Skip to content

Instantly share code, notes, and snippets.

@shravanasati
Last active March 29, 2023 18:32
Show Gist options
  • Save shravanasati/16c667381cc375de388b3ece371deeb7 to your computer and use it in GitHub Desktop.
Save shravanasati/16c667381cc375de388b3ece371deeb7 to your computer and use it in GitHub Desktop.
V updater/installer script written in python.
"""
Cross platform script for installing and updating V toolchain.
Requirements:
pip install requests tqdm userpath
"""
import os # to do a lot of things
import platform # to determine host os
import shutil # to find the V executable
import stat # to set file permissions
from datetime import datetime # file modification times
from zipfile import ZipFile # to extract v.zip
import requests # to download V from github releases
import userpath # for updating PATH variable
from tqdm import tqdm # for showing progress bar
def get_v_executable():
"""
Returns the path to the V installation folder.
"""
path = shutil.which("v")
if path is None:
return ""
folder = os.path.split(path)
return os.path.split(folder[0])[0] # excludes `/v` from .../vlang/v/
def get_download_url():
"""
Returns the GitHub download URL for V according to the OS.
"""
host_os = platform.system()
if host_os == "Windows":
return "https://github.com/vlang/v/releases/latest/download/v_windows.zip"
elif host_os == "Linux":
return "https://github.com/vlang/v/releases/latest/download/v_linux.zip"
elif host_os == "Darwin":
return "https://github.com/vlang/v/releases/latest/download/v_macos.zip"
else:
return ""
def download(max_retries: int = 5):
"""
Downloads V from GitHub releases.
"""
retry_counter = 0
while retry_counter < max_retries:
try:
retry_counter += 1
url = get_download_url()
if url == "":
print("Unable to find the download URL for your system.")
exit(1)
print(f"Downloading V from: {url}\n")
location = os.path.join(os.path.expanduser("~"), "Downloads")
os.makedirs(location, exist_ok=True)
location = os.path.join(location, "v_temp.zip")
headers = {}
initial_download_value = 0
with open(location, "ab") as f:
pos = f.tell()
if pos: # file already has some content
last_modification_time = os.path.getmtime(location)
last_modification_date = datetime.fromtimestamp(last_modification_time)
print(
f"Resuming download from previous failed iteration ({last_modification_date})...\n"
)
initial_download_value = pos
headers["Range"] = f"bytes={pos}-"
r = requests.get(
url, allow_redirects=True, stream=True, timeout=30, headers=headers
)
r.raise_for_status()
download_size = int(r.headers.get("content-length", 0))
with open(location, "ab") as file, tqdm(
desc="v_temp.zip",
total=download_size,
initial=initial_download_value,
unit="iB",
unit_scale=True,
unit_divisor=1024,
) as progess_bar:
for data in r.iter_content(chunk_size=1024):
size = file.write(data)
progess_bar.update(size)
print()
return # break the while loop
except Exception as e:
print("Unable to download V!")
print("Error:", e)
if retry_counter < max_retries:
print(f"Retrying again ({retry_counter+1}th attempt)...")
else:
print(
f"Tried downloading the file {max_retries} times, but failed. Stopping now."
)
cleanup(location)
exit(1)
def install():
"""
Installs V from the downloaded zip file.
"""
location = get_v_executable()
WINDOWS = platform.system() == "Windows"
if location == "":
proceed = input(
"Unable to find existing V installation. Would you like to newly install V? (y/n) "
)
if proceed.lower().strip() != "y":
exit(0)
location = os.path.join(os.path.expanduser("~"), "vlang")
download()
else:
proceed = input(
f"V is already installed at {location}. Would you like to update it? (y/n) "
)
if proceed.lower().strip() != "y":
exit(0)
download()
print(f"Removing existing installation at {location}...")
shutil.rmtree(location, ignore_errors=True)
print(f"Installing V at {location}...")
zip_file_location = os.path.join(os.path.expanduser("~"), "Downloads", "v_temp.zip")
with ZipFile(zip_file_location, "r") as zip_ref:
zip_ref.extractall(location)
path_location = os.path.join(location, "v")
present_in_path = userpath.in_current_path(path_location) or userpath.in_new_path(
path_location
)
executable_location = (
os.path.join(path_location, "v.exe")
if WINDOWS
else os.path.join(path_location, "v")
)
os.chmod(executable_location, stat.S_IRWXU)
cleanup(zip_file_location)
if not present_in_path:
print(
f"V installation was successfull, updating the PATH variable to use V at `{path_location}`."
)
success = userpath.append(path_location)
if success:
print(f"Successfully added {path_location} to PATH.")
if userpath.need_shell_restart(path_location):
print("You need to restart your shell to use V.")
else:
print(f"V installation was successfull at `{path_location}`.")
def cleanup(zip_file_location):
"""
Removes downloaded assets, if present.
"""
try:
print("Removing downloaded assets...")
os.remove(zip_file_location)
except FileNotFoundError:
pass
except Exception as e:
print(f"An unknown error occured: {e}")
if __name__ == "__main__":
install()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment