summaryrefslogtreecommitdiff
path: root/wheel/wininst2wheel.py
diff options
context:
space:
mode:
Diffstat (limited to 'wheel/wininst2wheel.py')
-rwxr-xr-xwheel/wininst2wheel.py216
1 files changed, 0 insertions, 216 deletions
diff --git a/wheel/wininst2wheel.py b/wheel/wininst2wheel.py
deleted file mode 100755
index 15f0cdf..0000000
--- a/wheel/wininst2wheel.py
+++ /dev/null
@@ -1,216 +0,0 @@
-#!/usr/bin/env python
-import os.path
-import re
-import sys
-import tempfile
-import zipfile
-import wheel.bdist_wheel
-import distutils.dist
-from distutils.archive_util import make_archive
-from shutil import rmtree
-from wheel.archive import archive_wheelfile
-from argparse import ArgumentParser
-from glob import iglob
-
-egg_info_re = re.compile(r'''(^|/)(?P<name>[^/]+?)-(?P<ver>.+?)
- (-(?P<pyver>.+?))?(-(?P<arch>.+?))?.egg-info(/|$)''', re.VERBOSE)
-
-def parse_info(wininfo_name, egginfo_name):
- """Extract metadata from filenames.
-
- Extracts the 4 metadataitems needed (name, version, pyversion, arch) from
- the installer filename and the name of the egg-info directory embedded in
- the zipfile (if any).
-
- The egginfo filename has the format::
-
- name-ver(-pyver)(-arch).egg-info
-
- The installer filename has the format::
-
- name-ver.arch(-pyver).exe
-
- Some things to note:
-
- 1. The installer filename is not definitive. An installer can be renamed
- and work perfectly well as an installer. So more reliable data should
- be used whenever possible.
- 2. The egg-info data should be preferred for the name and version, because
- these come straight from the distutils metadata, and are mandatory.
- 3. The pyver from the egg-info data should be ignored, as it is
- constructed from the version of Python used to build the installer,
- which is irrelevant - the installer filename is correct here (even to
- the point that when it's not there, any version is implied).
- 4. The architecture must be taken from the installer filename, as it is
- not included in the egg-info data.
- 5. Architecture-neutral installers still have an architecture because the
- installer format itself (being executable) is architecture-specific. We
- should therefore ignore the architecture if the content is pure-python.
- """
-
- egginfo = None
- if egginfo_name:
- egginfo = egg_info_re.search(egginfo_name)
- if not egginfo:
- raise ValueError("Egg info filename %s is not valid" %
- (egginfo_name,))
-
- # Parse the wininst filename
- # 1. Distribution name (up to the first '-')
- w_name, sep, rest = wininfo_name.partition('-')
- if not sep:
- raise ValueError("Installer filename %s is not valid" %
- (wininfo_name,))
- # Strip '.exe'
- rest = rest[:-4]
- # 2. Python version (from the last '-', must start with 'py')
- rest2, sep, w_pyver = rest.rpartition('-')
- if sep and w_pyver.startswith('py'):
- rest = rest2
- w_pyver = w_pyver.replace('.', '')
- else:
- # Not version specific - use py2.py3. While it is possible that
- # pure-Python code is not compatible with both Python 2 and 3, there
- # is no way of knowing from the wininst format, so we assume the best
- # here (the user can always manually rename the wheel to be more
- # restrictive if needed).
- w_pyver = 'py2.py3'
- # 3. Version and architecture
- w_ver, sep, w_arch = rest.rpartition('.')
- if not sep:
- raise ValueError("Installer filename %s is not valid" %
- (wininfo_name,))
-
- if egginfo:
- w_name = egginfo.group('name')
- w_ver = egginfo.group('ver')
-
- return dict(name=w_name, ver=w_ver, arch=w_arch, pyver=w_pyver)
-
-def bdist_wininst2wheel(path, dest_dir=os.path.curdir):
- bdw = zipfile.ZipFile(path)
-
- # Search for egg-info in the archive
- egginfo_name = None
- for filename in bdw.namelist():
- if '.egg-info' in filename:
- egginfo_name = filename
- break
-
- info = parse_info(os.path.basename(path), egginfo_name)
-
- root_is_purelib = True
- for zipinfo in bdw.infolist():
- if zipinfo.filename.startswith('PLATLIB'):
- root_is_purelib = False
- break
- if root_is_purelib:
- paths = {'purelib': ''}
- else:
- paths = {'platlib': ''}
-
- dist_info = "%(name)s-%(ver)s" % info
- datadir = "%s.data/" % dist_info
-
- # rewrite paths to trick ZipFile into extracting an egg
- # XXX grab wininst .ini - between .exe, padding, and first zip file.
- members = []
- egginfo_name = ''
- for zipinfo in bdw.infolist():
- key, basename = zipinfo.filename.split('/', 1)
- key = key.lower()
- basepath = paths.get(key, None)
- if basepath is None:
- basepath = datadir + key.lower() + '/'
- oldname = zipinfo.filename
- newname = basepath + basename
- zipinfo.filename = newname
- del bdw.NameToInfo[oldname]
- bdw.NameToInfo[newname] = zipinfo
- # Collect member names, but omit '' (from an entry like "PLATLIB/"
- if newname:
- members.append(newname)
- # Remember egg-info name for the egg2dist call below
- if not egginfo_name:
- if newname.endswith('.egg-info'):
- egginfo_name = newname
- elif '.egg-info/' in newname:
- egginfo_name, sep, _ = newname.rpartition('/')
- dir = tempfile.mkdtemp(suffix="_b2w")
- bdw.extractall(dir, members)
-
- # egg2wheel
- abi = 'none'
- pyver = info['pyver']
- arch = (info['arch'] or 'any').replace('.', '_').replace('-', '_')
- # Wininst installers always have arch even if they are not
- # architecture-specific (because the format itself is).
- # So, assume the content is architecture-neutral if root is purelib.
- if root_is_purelib:
- arch = 'any'
- # If the installer is architecture-specific, it's almost certainly also
- # CPython-specific.
- if arch != 'any':
- pyver = pyver.replace('py', 'cp')
- wheel_name = '-'.join((
- dist_info,
- pyver,
- abi,
- arch
- ))
- if root_is_purelib:
- bw = wheel.bdist_wheel.bdist_wheel(distutils.dist.Distribution())
- else:
- bw = _bdist_wheel_tag(distutils.dist.Distribution())
-
- bw.root_is_pure = root_is_purelib
- bw.python_tag = pyver
- bw.plat_name_supplied = True
- bw.plat_name = info['arch'] or 'any'
-
- if not root_is_purelib:
- bw.full_tag_supplied = True
- bw.full_tag = (pyver, abi, arch)
-
- dist_info_dir = os.path.join(dir, '%s.dist-info' % dist_info)
- bw.egg2dist(os.path.join(dir, egginfo_name), dist_info_dir)
- bw.write_wheelfile(dist_info_dir, generator='wininst2wheel')
- bw.write_record(dir, dist_info_dir)
-
- archive_wheelfile(os.path.join(dest_dir, wheel_name), dir)
- rmtree(dir)
-
-
-class _bdist_wheel_tag(wheel.bdist_wheel.bdist_wheel):
- # allow the client to override the default generated wheel tag
- # The default bdist_wheel implementation uses python and abi tags
- # of the running python process. This is not suitable for
- # generating/repackaging prebuild binaries.
-
- full_tag_supplied = False
- full_tag = None # None or a (pytag, soabitag, plattag) triple
-
- def get_tag(self):
- if self.full_tag_supplied and self.full_tag is not None:
- return self.full_tag
- else:
- return super(_bdist_wheel_tag, self).get_tag()
-
-
-def main():
- parser = ArgumentParser()
- parser.add_argument('installers', nargs='*', help="Installers to convert")
- parser.add_argument('--dest-dir', '-d', default=os.path.curdir,
- help="Directory to store wheels (default %(default)s)")
- parser.add_argument('--verbose', '-v', action='store_true')
- args = parser.parse_args()
- for pat in args.installers:
- for installer in iglob(pat):
- if args.verbose:
- sys.stdout.write("{0}... ".format(installer))
- bdist_wininst2wheel(installer, args.dest_dir)
- if args.verbose:
- sys.stdout.write("OK\n")
-
-if __name__ == "__main__":
- main()