Skip to content

Instantly share code, notes, and snippets.

@jedie
Last active August 15, 2024 11:16
Show Gist options
  • Save jedie/919ce4490e563b67ebec3a88d8b9f076 to your computer and use it in GitHub Desktop.
Save jedie/919ce4490e563b67ebec3a88d8b9f076 to your computer and use it in GitHub Desktop.
Python script to install https://github.com/eGenix/egenix-pyrun into '~/.local'
#!/bin/python3
"""
Download and setup missing Python versions using eGenix PyRun
https://github.com/eGenix/egenix-pyrun
"""
import dataclasses
import json
import shutil
import subprocess
import tarfile
import urllib.request
from pathlib import Path
from pprint import pprint
from urllib3.util import parse_url
PYRUN_VERSIONS = ('3.8', '3.9', '3.10', '3.11', '3.12')
LOCAL_BIN_PATH = Path('~/.local').expanduser()
@dataclasses.dataclass
class ReleaseInfo:
version: str
urls: list[str]
def get(self, *, version):
for url in self.urls:
if f'-py{version}_' in url:
return url
def get_pyrun_release_info() -> ReleaseInfo:
api_url = "https://api.github.com/repos/eGenix/egenix-pyrun/releases"
print(f'Fetch {api_url}...')
with urllib.request.urlopen(api_url) as response:
data = response.read().decode()
releases = json.loads(data)
latest_release = releases[0]
# pprint(latest_release)
print(latest_release['html_url'])
print(latest_release['tag_name'])
print(latest_release['name'])
urls = []
for asset in latest_release['assets']:
urls.append(asset['browser_download_url'])
return ReleaseInfo(version=latest_release['name'], urls=urls)
def pyrun_filter(member, dest_path):
if member.name in ('./bin/pyrun', './bin/python3'):
# Don't overwrite existing pyrun or python3
return None
print(f'Extract {member.name}')
return member
def setup_pyrun():
release_info = get_pyrun_release_info()
pprint(release_info)
for pyrun_version in PYRUN_VERSIONS:
python_bin_name = f'python{pyrun_version}'
path = shutil.which(python_bin_name)
if path:
path = Path(path).resolve()
print(f'Found {python_bin_name} at {path}')
print(path.name)
if path.name.startswith('pyrun'):
print(f'{python_bin_name} is pyrun -> update')
else:
continue
print('_' * 100)
print(f'Setup pyrun for Python {pyrun_version}')
if url := release_info.get(version=pyrun_version):
print(f'Download {url}')
download_path = Path('~/bin').expanduser()
subprocess.check_call(
['wget', '--timestamp', url],
cwd=download_path,
)
filename = Path(parse_url(url).path).name
print(f'{filename=}')
tgz_path = download_path / filename
assert tgz_path.is_file(), f'{tgz_path=}'
print(f'Extract {tgz_path} to {LOCAL_BIN_PATH}...')
with tarfile.open(tgz_path, "r:gz") as tgz_file:
tgz_file.extractall(path=LOCAL_BIN_PATH, filter=pyrun_filter)
print('\n')
def print_python_versions():
for pyrun_version in PYRUN_VERSIONS:
python_bin_name = f'python{pyrun_version}'
print(f'{python_bin_name}...', end=' ')
if path := shutil.which(python_bin_name):
path = Path(path).resolve()
print(f'Found at {path}:')
subprocess.run([python_bin_name, '-V'])
print()
else:
print('Not found.\n')
if __name__ == '__main__':
setup_pyrun()
print()
print_python_versions()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment