PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Lib/site-packages/wheel/wininst2wheel.py

https://gitlab.com/areema/myproject
Python | 187 lines | 179 code | 1 blank | 7 comment | 1 complexity | 6706ba7ae445271784a5370a3eafc2f3 MD5 | raw file
  1. #!/usr/bin/env python
  2. import os.path
  3. import re
  4. import sys
  5. import tempfile
  6. import zipfile
  7. import wheel.bdist_wheel
  8. import distutils.dist
  9. from distutils.archive_util import make_archive
  10. from shutil import rmtree
  11. from wheel.archive import archive_wheelfile
  12. from argparse import ArgumentParser
  13. from glob import iglob
  14. egg_info_re = re.compile(r'''(^|/)(?P<name>[^/]+?)-(?P<ver>.+?)
  15. (-(?P<pyver>.+?))?(-(?P<arch>.+?))?.egg-info(/|$)''', re.VERBOSE)
  16. def parse_info(wininfo_name, egginfo_name):
  17. """Extract metadata from filenames.
  18. Extracts the 4 metadataitems needed (name, version, pyversion, arch) from
  19. the installer filename and the name of the egg-info directory embedded in
  20. the zipfile (if any).
  21. The egginfo filename has the format::
  22. name-ver(-pyver)(-arch).egg-info
  23. The installer filename has the format::
  24. name-ver.arch(-pyver).exe
  25. Some things to note:
  26. 1. The installer filename is not definitive. An installer can be renamed
  27. and work perfectly well as an installer. So more reliable data should
  28. be used whenever possible.
  29. 2. The egg-info data should be preferred for the name and version, because
  30. these come straight from the distutils metadata, and are mandatory.
  31. 3. The pyver from the egg-info data should be ignored, as it is
  32. constructed from the version of Python used to build the installer,
  33. which is irrelevant - the installer filename is correct here (even to
  34. the point that when it's not there, any version is implied).
  35. 4. The architecture must be taken from the installer filename, as it is
  36. not included in the egg-info data.
  37. 5. Architecture-neutral installers still have an architecture because the
  38. installer format itself (being executable) is architecture-specific. We
  39. should therefore ignore the architecture if the content is pure-python.
  40. """
  41. egginfo = None
  42. if egginfo_name:
  43. egginfo = egg_info_re.search(egginfo_name)
  44. if not egginfo:
  45. raise ValueError("Egg info filename %s is not valid" %
  46. (egginfo_name,))
  47. # Parse the wininst filename
  48. # 1. Distribution name (up to the first '-')
  49. w_name, sep, rest = wininfo_name.partition('-')
  50. if not sep:
  51. raise ValueError("Installer filename %s is not valid" %
  52. (wininfo_name,))
  53. # Strip '.exe'
  54. rest = rest[:-4]
  55. # 2. Python version (from the last '-', must start with 'py')
  56. rest2, sep, w_pyver = rest.rpartition('-')
  57. if sep and w_pyver.startswith('py'):
  58. rest = rest2
  59. w_pyver = w_pyver.replace('.', '')
  60. else:
  61. # Not version specific - use py2.py3. While it is possible that
  62. # pure-Python code is not compatible with both Python 2 and 3, there
  63. # is no way of knowing from the wininst format, so we assume the best
  64. # here (the user can always manually rename the wheel to be more
  65. # restrictive if needed).
  66. w_pyver = 'py2.py3'
  67. # 3. Version and architecture
  68. w_ver, sep, w_arch = rest.rpartition('.')
  69. if not sep:
  70. raise ValueError("Installer filename %s is not valid" %
  71. (wininfo_name,))
  72. if egginfo:
  73. w_name = egginfo.group('name')
  74. w_ver = egginfo.group('ver')
  75. return dict(name=w_name, ver=w_ver, arch=w_arch, pyver=w_pyver)
  76. def bdist_wininst2wheel(path, dest_dir=os.path.curdir):
  77. bdw = zipfile.ZipFile(path)
  78. # Search for egg-info in the archive
  79. egginfo_name = None
  80. for filename in bdw.namelist():
  81. if '.egg-info' in filename:
  82. egginfo_name = filename
  83. break
  84. info = parse_info(os.path.basename(path), egginfo_name)
  85. root_is_purelib = True
  86. for zipinfo in bdw.infolist():
  87. if zipinfo.filename.startswith('PLATLIB'):
  88. root_is_purelib = False
  89. break
  90. if root_is_purelib:
  91. paths = {'purelib': ''}
  92. else:
  93. paths = {'platlib': ''}
  94. dist_info = "%(name)s-%(ver)s" % info
  95. datadir = "%s.data/" % dist_info
  96. # rewrite paths to trick ZipFile into extracting an egg
  97. # XXX grab wininst .ini - between .exe, padding, and first zip file.
  98. members = []
  99. egginfo_name = ''
  100. for zipinfo in bdw.infolist():
  101. key, basename = zipinfo.filename.split('/', 1)
  102. key = key.lower()
  103. basepath = paths.get(key, None)
  104. if basepath is None:
  105. basepath = datadir + key.lower() + '/'
  106. oldname = zipinfo.filename
  107. newname = basepath + basename
  108. zipinfo.filename = newname
  109. del bdw.NameToInfo[oldname]
  110. bdw.NameToInfo[newname] = zipinfo
  111. # Collect member names, but omit '' (from an entry like "PLATLIB/"
  112. if newname:
  113. members.append(newname)
  114. # Remember egg-info name for the egg2dist call below
  115. if not egginfo_name:
  116. if newname.endswith('.egg-info'):
  117. egginfo_name = newname
  118. elif '.egg-info/' in newname:
  119. egginfo_name, sep, _ = newname.rpartition('/')
  120. dir = tempfile.mkdtemp(suffix="_b2w")
  121. bdw.extractall(dir, members)
  122. # egg2wheel
  123. abi = 'none'
  124. pyver = info['pyver']
  125. arch = (info['arch'] or 'any').replace('.', '_').replace('-', '_')
  126. # Wininst installers always have arch even if they are not
  127. # architecture-specific (because the format itself is).
  128. # So, assume the content is architecture-neutral if root is purelib.
  129. if root_is_purelib:
  130. arch = 'any'
  131. # If the installer is architecture-specific, it's almost certainly also
  132. # CPython-specific.
  133. if arch != 'any':
  134. pyver = pyver.replace('py', 'cp')
  135. wheel_name = '-'.join((
  136. dist_info,
  137. pyver,
  138. abi,
  139. arch
  140. ))
  141. bw = wheel.bdist_wheel.bdist_wheel(distutils.dist.Distribution())
  142. bw.root_is_purelib = root_is_purelib
  143. dist_info_dir = os.path.join(dir, '%s.dist-info' % dist_info)
  144. bw.egg2dist(os.path.join(dir, egginfo_name), dist_info_dir)
  145. bw.write_wheelfile(dist_info_dir, generator='wininst2wheel')
  146. bw.write_record(dir, dist_info_dir)
  147. archive_wheelfile(os.path.join(dest_dir, wheel_name), dir)
  148. rmtree(dir)
  149. def main():
  150. parser = ArgumentParser()
  151. parser.add_argument('installers', nargs='*', help="Installers to convert")
  152. parser.add_argument('--dest-dir', '-d', default=os.path.curdir,
  153. help="Directory to store wheels (default %(default)s)")
  154. parser.add_argument('--verbose', '-v', action='store_true')
  155. args = parser.parse_args()
  156. for pat in args.installers:
  157. for installer in iglob(pat):
  158. if args.verbose:
  159. sys.stdout.write("{0}... ".format(installer))
  160. bdist_wininst2wheel(installer, args.dest_dir)
  161. if args.verbose:
  162. sys.stdout.write("OK\n")
  163. if __name__ == "__main__":
  164. main()