blob: 66b6af60ee22b44a3ae9ffc9c23577664be37599 [file] [edit]
#!/usr/bin/env python3
# Copyright 2018 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import json
import os
import re
import ssl
import subprocess
import sys
import urllib.request
import certifi
import packaging.version
# TODO: Find these files dynamically.
# List of files to download for installation.
_FILES = (
'core.msi',
'core_d.msi',
'core_pdb.msi',
'dev.msi',
'dev_d.msi',
'doc.msi',
'exe.msi',
'exe_d.msi',
'exe_pdb.msi',
'lib.msi',
'lib_d.msi',
'lib_pdb.msi',
'path.msi',
'pip.msi',
'tcltk.msi',
'tcltk_d.msi',
'tcltk_pdb.msi',
'test.msi',
'test_d.msi',
'test_pdb.msi',
'tools.msi',
'ucrt.msi',
)
# Make sure up-to-date root certificates are used.
urllib.request.install_opener(
urllib.request.build_opener(
urllib.request.HTTPSHandler(
context=ssl.create_default_context(cafile=certifi.where()))))
def get_installer_suffix(platform):
if platform == 'windows-386':
return '.exe'
# Package windows-amd64 to run in emulated mode on windows-arm64.
if platform in ['windows-amd64', 'windows-arm64']:
return '-amd64.exe'
raise ValueError('fetch.py is only supported for windows-(386|amd64|arm64)')
# Only look at versions in 3.11.x for now.
_VERSION_LIMIT = packaging.version.parse("3.11.10")
def do_latest(platform):
"""This is pretty janky, but the apache generic Index page hasn't changed
since forever. It contains links (a tags with href's) to the different
version folders."""
suf = get_installer_suffix(platform)
# Find the highest version e.g. 3.8.0.
page_data = urllib.request.urlopen('https://www.python.org/ftp/python/')
highest = None
href_re = re.compile(r'href="(\d+\.\d+\.\d+)/"')
for m in href_re.finditer(page_data.read().decode('utf-8')):
v = packaging.version.parse(m.group(1))
if v < _VERSION_LIMIT:
if not highest or v > highest:
highest = v
page_data = urllib.request.urlopen('https://www.python.org/ftp/python/%s/' %
highest)
# Find the highest release e.g. 3.8.0a4.
highest = None
href_re = re.compile(r'href="python-(\d+\.\d+\.\d+((a|b|rc)\d+)?)%s"' % suf)
for m in href_re.finditer(page_data.read().decode('utf-8')):
v = packaging.version.parse(m.group(1))
if v < _VERSION_LIMIT:
if not highest or v > highest:
highest = v
print(highest)
def get_download_url(version, platform):
# e.g. 3.8.0a4 -> 3.8.0
short = version
short_re = re.compile(r'(\d+\.\d+\.\d+)')
m = short_re.match(version)
if m:
short = m.group(0)
path = 'amd64' if platform in ['windows-amd64', 'windows-arm64'] else 'win32'
base_download_url = (
'https://www.python.org/ftp/python/%(short)s/%(path)s/'
% {'short': short, 'path': path}
)
download_urls, artifact_names = [], []
for filename in _FILES:
download_urls.append(base_download_url + filename)
artifact_names.append(filename)
partial_manifest = {
'url': download_urls,
'name': artifact_names,
'ext': '.msi',
}
print(json.dumps(partial_manifest))
def main():
ap = argparse.ArgumentParser()
sub = ap.add_subparsers(dest='action', required=True)
latest = sub.add_parser("latest")
latest.set_defaults(func=lambda _opts: do_latest(os.environ['_3PP_PLATFORM']))
download = sub.add_parser("get_url")
download.set_defaults(
func=lambda opts: get_download_url(
os.environ['_3PP_VERSION'], os.environ['_3PP_PLATFORM']))
opts = ap.parse_args()
return opts.func(opts)
if __name__ == '__main__':
sys.exit(main())