77import shutil
88import subprocess
99import sys
10- from collections import OrderedDict , defaultdict
10+ from collections import defaultdict
11+ from concurrent .futures import as_completed
12+ from concurrent .futures .thread import ThreadPoolExecutor
1113from pathlib import Path
1214from tempfile import TemporaryDirectory
1315from textwrap import dedent
14- from threading import Thread
16+ from typing import Dict
1517
1618STRICT = "UPGRADE_ADVISORY" not in os .environ
1719
2022DEST = Path (__file__ ).resolve ().parents [1 ] / "src" / "virtualenv" / "seed" / "wheels" / "embed"
2123
2224
23- def download (ver , dest , package ):
24- subprocess .call (
25- [
26- sys .executable ,
27- "-m" ,
28- "pip" ,
29- "--disable-pip-version-check" ,
30- "download" ,
31- "--only-binary=:all:" ,
32- "--python-version" ,
33- ver ,
34- "-d" ,
35- dest ,
36- package ,
37- ],
38- )
25+ def download (ver : str , into : Path ):
26+ dest = into / ver
27+ dest .mkdir ()
28+ cmd = [
29+ sys .executable ,
30+ "-m" ,
31+ "pip" ,
32+ "--disable-pip-version-check" ,
33+ "download" ,
34+ "--only-binary=:all:" ,
35+ "--python-version" ,
36+ ver ,
37+ ]
38+ subprocess .check_call (cmd + ["-d" , str (dest ), * BUNDLED ])
39+ deps = {}
40+ for pkg in BUNDLED :
41+ to_folder = dest / pkg
42+ to_folder .mkdir ()
43+ try :
44+ subprocess .check_call (cmd + ["-d" , str (to_folder ), pkg ])
45+ found = sorted (list (wheel .name .split ("-" )[0 ] for wheel in to_folder .iterdir ()))
46+ found .remove (pkg )
47+ deps [pkg ] = found
48+ finally :
49+ shutil .rmtree (to_folder )
50+ return ver , dest , deps
3951
4052
4153def run ():
54+ if sys .version_info < (3 , 7 ):
55+ raise RuntimeError ("requires python 3.7 or later" )
4256 old_batch = {i .name for i in DEST .iterdir () if i .suffix == ".whl" }
4357 with TemporaryDirectory () as temp :
44- temp_path = Path (temp )
45- folders = {}
46- targets = []
47- for support in SUPPORT :
48- support_ver = "." .join (str (i ) for i in support )
49- into = temp_path / support_ver
50- into .mkdir ()
51- folders [into ] = support_ver
52- for package in BUNDLED :
53- thread = Thread (target = download , args = (support_ver , str (into ), package ))
54- targets .append (thread )
55- thread .start ()
56- for thread in targets :
57- thread .join ()
58- new_batch = {i .name : i for f in folders .keys () for i in Path (f ).iterdir ()}
59-
58+ temp = Path (temp )
59+ bundle_support : Dict [str , Dict [str , str ]] = {}
60+ version_deps = {}
61+ new_batch = {}
62+ with ThreadPoolExecutor (max_workers = 4 ) as executor :
63+ for future in as_completed ({executor .submit (download , "." .join (str (i ) for i in s ), temp ) for s in SUPPORT }):
64+ try :
65+ version , dest , deps = future .result ()
66+ except Exception as exc :
67+ raise exc
68+ else :
69+ bundle = {}
70+ for wheel in dest .iterdir ():
71+ name = wheel .name .split ("-" )[0 ]
72+ bundle [name ] = wheel .name
73+ new_batch [wheel .name ] = wheel
74+ wheels = {wheel .name .split ("-" )[0 ]: wheel .name for wheel in dest .iterdir ()}
75+ wheels = {k : v for k , v in sorted (wheels .items ())}
76+ bundle_support [version ] = wheels
77+ version_deps [version ] = deps
78+ sort_by_version = lambda i : tuple (int (j ) for j in i [0 ].split ("." )) # noqa
79+ bundle_support = {k : v for k , v in sorted (bundle_support .items (), key = sort_by_version , reverse = True )}
80+ version_deps = {k : v for k , v in sorted (version_deps .items (), key = sort_by_version , reverse = True )}
6081 new_packages = new_batch .keys () - old_batch
6182 remove_packages = old_batch - new_batch .keys ()
6283
@@ -78,13 +99,6 @@ def run():
7899 for key , versions in removed .items ():
79100 print ("* removed embedded {} of {}" .format (key , fmt_version (versions )))
80101
81- support_table = OrderedDict (("." .join (str (j ) for j in i ), list ()) for i in SUPPORT )
82- for package in sorted (new_batch .keys ()):
83- for folder , version in sorted (folders .items ()):
84- if (folder / package ).exists ():
85- support_table [version ].append (package )
86- support_table = {k : OrderedDict ((i .split ("-" )[0 ], i ) for i in v ) for k , v in support_table .items ()}
87-
88102 msg = dedent (
89103 """
90104 from __future__ import absolute_import, unicode_literals
@@ -93,8 +107,9 @@ def run():
93107 from virtualenv.util.path import Path
94108
95109 BUNDLE_FOLDER = Path(__file__).absolute().parent
96- BUNDLE_SUPPORT = {{ {0} } }
110+ BUNDLE_SUPPORT = {0 }
97111 MAX = {1}
112+ VERSION_DEPS = {2}
98113
99114
100115 def get_embed_wheel(distribution, for_py_version):
@@ -105,16 +120,13 @@ def get_embed_wheel(distribution, for_py_version):
105120 __all__ = (
106121 "get_embed_wheel",
107122 "BUNDLE_SUPPORT",
123+ "VERSION_DEPS",
108124 "MAX",
109125 "BUNDLE_FOLDER",
110126 )
111127
112128 """ .format (
113- "," .join (
114- "{!r}: {{ {} }}" .format (v , "," .join ("{!r}: {!r}" .format (p , f ) for p , f in l .items ()))
115- for v , l in support_table .items ()
116- ),
117- repr (next (iter (support_table .keys ()))),
129+ repr (bundle_support ), repr (next (iter (bundle_support .keys ()))), repr (version_deps ),
118130 ),
119131 )
120132 dest_target = DEST / "__init__.py"
0 commit comments