Last active
March 29, 2023 18:32
-
-
Save shravanasati/16c667381cc375de388b3ece371deeb7 to your computer and use it in GitHub Desktop.
V updater/installer script written in python.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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