1
0
mirror of https://github.com/pyenv/pyenv.git synced 2025-11-08 11:33:49 -05:00
Files
pyenv/plugins/python-build/scripts/add_miniforge.py

143 lines
5.2 KiB
Python
Executable File

#!/usr/bin/env python3
'Adds the latest miniforge and mambaforge releases.'
from pathlib import Path
import logging
import os
import string
import requests
logger = logging.getLogger(__name__)
logging.basicConfig(level=os.environ.get('LOGLEVEL', 'INFO'))
MINIFORGE_REPO = 'conda-forge/miniforge'
DISTRIBUTIONS = ['miniforge']
DISTRIBUTIONS_PRE25 = ['miniforge', 'mambaforge']
SKIPPED_RELEASES = [
'4.13.0-0', #has no Mambaforge. We already generated scripts for Miniforge
'22.11.1-0', #MacOS packages are broken (have broken dep tarballs, downloading them fails with 403)
'22.11.1-1', #MacOS packages are broken (have broken dep tarballs, downloading them fails with 403)
'22.11.1-2', #MacOS packages are broken (have broken dep tarballs, downloading them fails with 403)
'25.3.0-0', #marked as prerelease, no Linux version
]
install_script_fmt = """
case "$(anaconda_architecture 2>/dev/null || true)" in
{install_lines}
* )
{{ echo
colorize 1 "ERROR"
echo ": The binary distribution of {flavor} is not available for $(anaconda_architecture 2>/dev/null || true)."
echo
}} >&2
exit 1
;;
esac
""".lstrip()
install_line_fmt = """
"{os}-{arch}" )
install_script "{filename}" "{url}#{sha}" "miniconda" verify_py{py_version}
;;
""".strip()
here = Path(__file__).resolve()
out_dir: Path = here.parent.parent / "share" / "python-build"
def download_sha(url):
logger.info('Downloading SHA file %(url)s', locals())
tup = tuple(reversed(requests.get(url).text.replace('./', '').rstrip().split()))
logger.debug('Got %(tup)s', locals())
return tup
def create_spec(filename, sha, url):
flavor_with_suffix, version, subversion, os, arch = filename.replace('.sh', '').split('-')
suffix = flavor_with_suffix[-1]
if suffix in string.digits:
flavor = flavor_with_suffix[:-1]
else:
flavor = flavor_with_suffix
spec = {
'filename': filename,
'sha': sha,
'url': url,
'py_version': py_version(version),
'flavor': flavor,
'os': os,
'arch': arch,
'installer_filename': f'{flavor_with_suffix.lower()}-{version}-{subversion}',
}
logger.debug('Created spec %(spec)s', locals())
return spec
def version_tuple(version):
return tuple(int(part) for part in version.split('-')[0].split("."))
def py_version(version):
"""Suffix for `verify_pyXXX` to call in the generated build script"""
version_tuple_ = version_tuple(version)
# current version: mentioned under https://github.com/conda-forge/miniforge?tab=readme-ov-file#requirements-and-installers
# transition points:
# https://github.com/conda-forge/miniforge/blame/main/Miniforge3/construct.yaml
# look for "- python <version>" in non-pypy branch and which tag the commit is first in
if version_tuple_ >= (24,5):
# yes, they jumped from 3.10 directly to 3.12
# https://github.com/conda-forge/miniforge/commit/bddad0baf22b37cfe079e47fd1680fdfb2183590
return "312"
if version_tuple_ >= (4,14):
return "310"
raise ValueError("Bundled Python version unknown for release `%s'"%version)
def supported(filename):
return ('pypy' not in filename) and ('Windows' not in filename)
def add_version(release, distributions):
tag_name = release['tag_name']
download_urls = { f['name']: f['browser_download_url'] for f in release['assets'] }
# can assume that sha files are named similar to release files so can also check supported(on their names)
shas = dict([download_sha(url) for (name, url) in download_urls.items() if name.endswith('.sha256') and supported(os.path.basename(name)) and tag_name in name])
specs = [create_spec(filename, sha, download_urls[filename]) for (filename, sha) in shas.items() if supported(filename)]
for distribution in distributions:
distribution_specs = [spec for spec in specs if distribution in spec['flavor'].lower()]
count = len(distribution_specs)
if count > 0:
output_file = out_dir / distribution_specs[0]['installer_filename']
logger.info('Writing %(count)d specs for %(distribution)s to %(output_file)s', locals())
script_str = install_script_fmt.format(
install_lines="\n".join([install_line_fmt.format_map(s) for s in distribution_specs]),
flavor=distribution_specs[0]['flavor'],
)
with open(output_file, 'w') as f:
f.write(script_str)
else:
logger.info('Did not find specs for %(distribution)s', locals())
for release in requests.get(f'https://api.github.com/repos/{MINIFORGE_REPO}/releases').json():
version = release['tag_name']
if version in SKIPPED_RELEASES:
continue
logger.info('Looking for %(version)s in %(out_dir)s', locals())
# mambaforge is retired https://github.com/conda-forge/miniforge/releases/tag/24.11.2-0
if version_tuple(version) >= (24,11,2):
distributions = DISTRIBUTIONS
else:
distributions = DISTRIBUTIONS_PRE25
if any(not list(out_dir.glob(f'{distribution}*-{version}')) for distribution in distributions):
logger.info('Downloading %(version)s', locals())
add_version(release, distributions)