Skip to content

Instantly share code, notes, and snippets.

@kkirsche
Last active December 16, 2022 15:53
Embed
What would you like to do?
ASDF Auto Updater
#!/usr/bin/env python
from shlex import split
from subprocess import CompletedProcess, run # noqa
from typing import cast
from packaging.version import InvalidVersion, parse
from requests import get
def run_cmd(
cmd: str, capture_output: bool = True, check: bool = True
) -> CompletedProcess[str]:
return run(
args=split(cmd), capture_output=capture_output, check=check, encoding="utf-8"
)
def list_plugins() -> tuple[str, ...]:
proc = run_cmd(cmd="asdf plugin list")
return tuple(proc.stdout.strip().split("\n"))
def list_versions(plugin_name: str) -> tuple[str, ...]:
proc = run_cmd(cmd=f"asdf list {plugin_name}")
return tuple(vers.strip("*").strip() for vers in proc.stdout.strip().split("\n"))
def latest_version(plugin_name: str, constraint: str | None = None) -> str:
cmd = f"asdf latest {plugin_name}"
if constraint is not None:
cmd = f"{cmd} {constraint}"
proc = run_cmd(cmd=cmd)
return proc.stdout.strip()
def latest_nodejs_lts_release() -> str | None:
resp = get(url="https://nodejs.org/download/release/index.json")
if not resp.ok:
print("Failed to retrieve latest NodeJS LTS release, skipping...")
return None
body = resp.json()
version_to_codename = {}
for version in body:
if version["lts"] is False:
continue
version_full = version["version"]
version_major = int(cast(str, version_full.split(".")[0]).removeprefix("v"))
version_codename = version["lts"]
if version_major not in version_to_codename:
version_to_codename[version_major] = version_codename
latest_lts_version = max(version_to_codename.keys())
return str(latest_lts_version)
def update_version(plugin_name: str, current_version: str, target_version: str) -> None:
print(f"Installling {plugin_name} version: {target_version}...")
run_cmd(cmd=f"asdf install {plugin_name} {target_version}")
print(f"Setting global version of {plugin_name}: {target_version}...")
run_cmd(cmd=f"asdf global {plugin_name} {target_version}")
print(f"Removing previous version of {plugin_name}: {current_version}...")
run_cmd(cmd=f"asdf uninstall {plugin_name} {current_version}")
if plugin_name == "python":
print(f"{plugin_name} was updated, but is currently in use by this script")
print("Please reshim the langauge manually")
else:
print(f"Reshimming {plugin_name}")
run_cmd(cmd=f"asdf reshim {plugin_name}")
def main() -> None:
plugins = list_plugins()
for plugin in plugins:
constraint = None
versions = list_versions(plugin_name=plugin)
if len(versions) > 1:
print(f"{plugin} has multiple versions installed, skipping...")
continue
elif len(versions) == 0:
print(f"{plugin} has no versions installed, skipping...")
continue
current = versions[0]
if plugin == "nodejs":
constraint = latest_nodejs_lts_release()
if constraint is None:
continue
latest = latest_version(plugin_name=plugin, constraint=constraint)
try:
if parse(latest) > parse(current):
update_version(
plugin_name=plugin, target_version=latest, current_version=current
)
print(f"asdf {plugin} language upgrade complete")
else:
print(f"No asdf {plugin} langauge updates")
except InvalidVersion as e:
print(f"Updating {plugin} failed with version error")
print(f"* {latest=}")
print(f"* {current=}")
print(f"* {e}")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment