Mercurial > repos > guerler > hhblits
comparison lib/python3.8/site-packages/wheel/cli/convert.py @ 1:64071f2a4cf0 draft default tip
Deleted selected files
| author | guerler |
|---|---|
| date | Mon, 27 Jul 2020 03:55:49 -0400 |
| parents | 9e54283cc701 |
| children |
comparison
equal
deleted
inserted
replaced
| 0:9e54283cc701 | 1:64071f2a4cf0 |
|---|---|
| 1 import os.path | |
| 2 import re | |
| 3 import shutil | |
| 4 import sys | |
| 5 import tempfile | |
| 6 import zipfile | |
| 7 from distutils import dist | |
| 8 from glob import iglob | |
| 9 | |
| 10 from ..bdist_wheel import bdist_wheel | |
| 11 from ..wheelfile import WheelFile | |
| 12 from . import WheelError, require_pkgresources | |
| 13 | |
| 14 egg_info_re = re.compile(r''' | |
| 15 (?P<name>.+?)-(?P<ver>.+?) | |
| 16 (-(?P<pyver>py\d\.\d+) | |
| 17 (-(?P<arch>.+?))? | |
| 18 )?.egg$''', re.VERBOSE) | |
| 19 | |
| 20 | |
| 21 class _bdist_wheel_tag(bdist_wheel): | |
| 22 # allow the client to override the default generated wheel tag | |
| 23 # The default bdist_wheel implementation uses python and abi tags | |
| 24 # of the running python process. This is not suitable for | |
| 25 # generating/repackaging prebuild binaries. | |
| 26 | |
| 27 full_tag_supplied = False | |
| 28 full_tag = None # None or a (pytag, soabitag, plattag) triple | |
| 29 | |
| 30 def get_tag(self): | |
| 31 if self.full_tag_supplied and self.full_tag is not None: | |
| 32 return self.full_tag | |
| 33 else: | |
| 34 return bdist_wheel.get_tag(self) | |
| 35 | |
| 36 | |
| 37 def egg2wheel(egg_path, dest_dir): | |
| 38 filename = os.path.basename(egg_path) | |
| 39 match = egg_info_re.match(filename) | |
| 40 if not match: | |
| 41 raise WheelError('Invalid egg file name: {}'.format(filename)) | |
| 42 | |
| 43 egg_info = match.groupdict() | |
| 44 dir = tempfile.mkdtemp(suffix="_e2w") | |
| 45 if os.path.isfile(egg_path): | |
| 46 # assume we have a bdist_egg otherwise | |
| 47 with zipfile.ZipFile(egg_path) as egg: | |
| 48 egg.extractall(dir) | |
| 49 else: | |
| 50 # support buildout-style installed eggs directories | |
| 51 for pth in os.listdir(egg_path): | |
| 52 src = os.path.join(egg_path, pth) | |
| 53 if os.path.isfile(src): | |
| 54 shutil.copy2(src, dir) | |
| 55 else: | |
| 56 shutil.copytree(src, os.path.join(dir, pth)) | |
| 57 | |
| 58 pyver = egg_info['pyver'] | |
| 59 if pyver: | |
| 60 pyver = egg_info['pyver'] = pyver.replace('.', '') | |
| 61 | |
| 62 arch = (egg_info['arch'] or 'any').replace('.', '_').replace('-', '_') | |
| 63 | |
| 64 # assume all binary eggs are for CPython | |
| 65 abi = 'cp' + pyver[2:] if arch != 'any' else 'none' | |
| 66 | |
| 67 root_is_purelib = egg_info['arch'] is None | |
| 68 if root_is_purelib: | |
| 69 bw = bdist_wheel(dist.Distribution()) | |
| 70 else: | |
| 71 bw = _bdist_wheel_tag(dist.Distribution()) | |
| 72 | |
| 73 bw.root_is_pure = root_is_purelib | |
| 74 bw.python_tag = pyver | |
| 75 bw.plat_name_supplied = True | |
| 76 bw.plat_name = egg_info['arch'] or 'any' | |
| 77 if not root_is_purelib: | |
| 78 bw.full_tag_supplied = True | |
| 79 bw.full_tag = (pyver, abi, arch) | |
| 80 | |
| 81 dist_info_dir = os.path.join(dir, '{name}-{ver}.dist-info'.format(**egg_info)) | |
| 82 bw.egg2dist(os.path.join(dir, 'EGG-INFO'), dist_info_dir) | |
| 83 bw.write_wheelfile(dist_info_dir, generator='egg2wheel') | |
| 84 wheel_name = '{name}-{ver}-{pyver}-{}-{}.whl'.format(abi, arch, **egg_info) | |
| 85 with WheelFile(os.path.join(dest_dir, wheel_name), 'w') as wf: | |
| 86 wf.write_files(dir) | |
| 87 | |
| 88 shutil.rmtree(dir) | |
| 89 | |
| 90 | |
| 91 def parse_wininst_info(wininfo_name, egginfo_name): | |
| 92 """Extract metadata from filenames. | |
| 93 | |
| 94 Extracts the 4 metadataitems needed (name, version, pyversion, arch) from | |
| 95 the installer filename and the name of the egg-info directory embedded in | |
| 96 the zipfile (if any). | |
| 97 | |
| 98 The egginfo filename has the format:: | |
| 99 | |
| 100 name-ver(-pyver)(-arch).egg-info | |
| 101 | |
| 102 The installer filename has the format:: | |
| 103 | |
| 104 name-ver.arch(-pyver).exe | |
| 105 | |
| 106 Some things to note: | |
| 107 | |
| 108 1. The installer filename is not definitive. An installer can be renamed | |
| 109 and work perfectly well as an installer. So more reliable data should | |
| 110 be used whenever possible. | |
| 111 2. The egg-info data should be preferred for the name and version, because | |
| 112 these come straight from the distutils metadata, and are mandatory. | |
| 113 3. The pyver from the egg-info data should be ignored, as it is | |
| 114 constructed from the version of Python used to build the installer, | |
| 115 which is irrelevant - the installer filename is correct here (even to | |
| 116 the point that when it's not there, any version is implied). | |
| 117 4. The architecture must be taken from the installer filename, as it is | |
| 118 not included in the egg-info data. | |
| 119 5. Architecture-neutral installers still have an architecture because the | |
| 120 installer format itself (being executable) is architecture-specific. We | |
| 121 should therefore ignore the architecture if the content is pure-python. | |
| 122 """ | |
| 123 | |
| 124 egginfo = None | |
| 125 if egginfo_name: | |
| 126 egginfo = egg_info_re.search(egginfo_name) | |
| 127 if not egginfo: | |
| 128 raise ValueError("Egg info filename %s is not valid" % (egginfo_name,)) | |
| 129 | |
| 130 # Parse the wininst filename | |
| 131 # 1. Distribution name (up to the first '-') | |
| 132 w_name, sep, rest = wininfo_name.partition('-') | |
| 133 if not sep: | |
| 134 raise ValueError("Installer filename %s is not valid" % (wininfo_name,)) | |
| 135 | |
| 136 # Strip '.exe' | |
| 137 rest = rest[:-4] | |
| 138 # 2. Python version (from the last '-', must start with 'py') | |
| 139 rest2, sep, w_pyver = rest.rpartition('-') | |
| 140 if sep and w_pyver.startswith('py'): | |
| 141 rest = rest2 | |
| 142 w_pyver = w_pyver.replace('.', '') | |
| 143 else: | |
| 144 # Not version specific - use py2.py3. While it is possible that | |
| 145 # pure-Python code is not compatible with both Python 2 and 3, there | |
| 146 # is no way of knowing from the wininst format, so we assume the best | |
| 147 # here (the user can always manually rename the wheel to be more | |
| 148 # restrictive if needed). | |
| 149 w_pyver = 'py2.py3' | |
| 150 # 3. Version and architecture | |
| 151 w_ver, sep, w_arch = rest.rpartition('.') | |
| 152 if not sep: | |
| 153 raise ValueError("Installer filename %s is not valid" % (wininfo_name,)) | |
| 154 | |
| 155 if egginfo: | |
| 156 w_name = egginfo.group('name') | |
| 157 w_ver = egginfo.group('ver') | |
| 158 | |
| 159 return {'name': w_name, 'ver': w_ver, 'arch': w_arch, 'pyver': w_pyver} | |
| 160 | |
| 161 | |
| 162 def wininst2wheel(path, dest_dir): | |
| 163 with zipfile.ZipFile(path) as bdw: | |
| 164 # Search for egg-info in the archive | |
| 165 egginfo_name = None | |
| 166 for filename in bdw.namelist(): | |
| 167 if '.egg-info' in filename: | |
| 168 egginfo_name = filename | |
| 169 break | |
| 170 | |
| 171 info = parse_wininst_info(os.path.basename(path), egginfo_name) | |
| 172 | |
| 173 root_is_purelib = True | |
| 174 for zipinfo in bdw.infolist(): | |
| 175 if zipinfo.filename.startswith('PLATLIB'): | |
| 176 root_is_purelib = False | |
| 177 break | |
| 178 if root_is_purelib: | |
| 179 paths = {'purelib': ''} | |
| 180 else: | |
| 181 paths = {'platlib': ''} | |
| 182 | |
| 183 dist_info = "%(name)s-%(ver)s" % info | |
| 184 datadir = "%s.data/" % dist_info | |
| 185 | |
| 186 # rewrite paths to trick ZipFile into extracting an egg | |
| 187 # XXX grab wininst .ini - between .exe, padding, and first zip file. | |
| 188 members = [] | |
| 189 egginfo_name = '' | |
| 190 for zipinfo in bdw.infolist(): | |
| 191 key, basename = zipinfo.filename.split('/', 1) | |
| 192 key = key.lower() | |
| 193 basepath = paths.get(key, None) | |
| 194 if basepath is None: | |
| 195 basepath = datadir + key.lower() + '/' | |
| 196 oldname = zipinfo.filename | |
| 197 newname = basepath + basename | |
| 198 zipinfo.filename = newname | |
| 199 del bdw.NameToInfo[oldname] | |
| 200 bdw.NameToInfo[newname] = zipinfo | |
| 201 # Collect member names, but omit '' (from an entry like "PLATLIB/" | |
| 202 if newname: | |
| 203 members.append(newname) | |
| 204 # Remember egg-info name for the egg2dist call below | |
| 205 if not egginfo_name: | |
| 206 if newname.endswith('.egg-info'): | |
| 207 egginfo_name = newname | |
| 208 elif '.egg-info/' in newname: | |
| 209 egginfo_name, sep, _ = newname.rpartition('/') | |
| 210 dir = tempfile.mkdtemp(suffix="_b2w") | |
| 211 bdw.extractall(dir, members) | |
| 212 | |
| 213 # egg2wheel | |
| 214 abi = 'none' | |
| 215 pyver = info['pyver'] | |
| 216 arch = (info['arch'] or 'any').replace('.', '_').replace('-', '_') | |
| 217 # Wininst installers always have arch even if they are not | |
| 218 # architecture-specific (because the format itself is). | |
| 219 # So, assume the content is architecture-neutral if root is purelib. | |
| 220 if root_is_purelib: | |
| 221 arch = 'any' | |
| 222 # If the installer is architecture-specific, it's almost certainly also | |
| 223 # CPython-specific. | |
| 224 if arch != 'any': | |
| 225 pyver = pyver.replace('py', 'cp') | |
| 226 wheel_name = '-'.join((dist_info, pyver, abi, arch)) | |
| 227 if root_is_purelib: | |
| 228 bw = bdist_wheel(dist.Distribution()) | |
| 229 else: | |
| 230 bw = _bdist_wheel_tag(dist.Distribution()) | |
| 231 | |
| 232 bw.root_is_pure = root_is_purelib | |
| 233 bw.python_tag = pyver | |
| 234 bw.plat_name_supplied = True | |
| 235 bw.plat_name = info['arch'] or 'any' | |
| 236 | |
| 237 if not root_is_purelib: | |
| 238 bw.full_tag_supplied = True | |
| 239 bw.full_tag = (pyver, abi, arch) | |
| 240 | |
| 241 dist_info_dir = os.path.join(dir, '%s.dist-info' % dist_info) | |
| 242 bw.egg2dist(os.path.join(dir, egginfo_name), dist_info_dir) | |
| 243 bw.write_wheelfile(dist_info_dir, generator='wininst2wheel') | |
| 244 | |
| 245 wheel_path = os.path.join(dest_dir, wheel_name) | |
| 246 with WheelFile(wheel_path, 'w') as wf: | |
| 247 wf.write_files(dir) | |
| 248 | |
| 249 shutil.rmtree(dir) | |
| 250 | |
| 251 | |
| 252 def convert(files, dest_dir, verbose): | |
| 253 # Only support wheel convert if pkg_resources is present | |
| 254 require_pkgresources('wheel convert') | |
| 255 | |
| 256 for pat in files: | |
| 257 for installer in iglob(pat): | |
| 258 if os.path.splitext(installer)[1] == '.egg': | |
| 259 conv = egg2wheel | |
| 260 else: | |
| 261 conv = wininst2wheel | |
| 262 | |
| 263 if verbose: | |
| 264 print("{}... ".format(installer)) | |
| 265 sys.stdout.flush() | |
| 266 | |
| 267 conv(installer, dest_dir) | |
| 268 if verbose: | |
| 269 print("OK") |
