egg2wheel.py 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #!/usr/bin/env python
  2. import distutils.dist
  3. import os.path
  4. import re
  5. import shutil
  6. import sys
  7. import tempfile
  8. import zipfile
  9. from argparse import ArgumentParser
  10. from distutils.archive_util import make_archive
  11. from glob import iglob
  12. import wheel.bdist_wheel
  13. from wheel.tool import WheelError
  14. from wheel.wininst2wheel import _bdist_wheel_tag
  15. egg_info_re = re.compile(r'''
  16. (?P<name>.+?)-(?P<ver>.+?)
  17. (-(?P<pyver>py\d\.\d)
  18. (-(?P<arch>.+?))?
  19. )?.egg$''', re.VERBOSE)
  20. def egg2wheel(egg_path, dest_dir):
  21. filename = os.path.basename(egg_path)
  22. match = egg_info_re.match(filename)
  23. if not match:
  24. raise WheelError('Invalid egg file name: {}'.format(filename))
  25. egg_info = match.groupdict()
  26. dir = tempfile.mkdtemp(suffix="_e2w")
  27. if os.path.isfile(egg_path):
  28. # assume we have a bdist_egg otherwise
  29. egg = zipfile.ZipFile(egg_path)
  30. egg.extractall(dir)
  31. else:
  32. # support buildout-style installed eggs directories
  33. for pth in os.listdir(egg_path):
  34. src = os.path.join(egg_path, pth)
  35. if os.path.isfile(src):
  36. shutil.copy2(src, dir)
  37. else:
  38. shutil.copytree(src, os.path.join(dir, pth))
  39. pyver = egg_info['pyver']
  40. if pyver:
  41. pyver = pyver.replace('.', '')
  42. arch = (egg_info['arch'] or 'any').replace('.', '_').replace('-', '_')
  43. # assume all binary eggs are for CPython
  44. abi = 'cp' + pyver[2:] if arch != 'any' else 'none'
  45. root_is_purelib = egg_info['arch'] is None
  46. if root_is_purelib:
  47. bw = wheel.bdist_wheel.bdist_wheel(distutils.dist.Distribution())
  48. else:
  49. bw = _bdist_wheel_tag(distutils.dist.Distribution())
  50. bw.root_is_pure = root_is_purelib
  51. bw.python_tag = pyver
  52. bw.plat_name_supplied = True
  53. bw.plat_name = egg_info['arch'] or 'any'
  54. if not root_is_purelib:
  55. bw.full_tag_supplied = True
  56. bw.full_tag = (pyver, abi, arch)
  57. dist_info_dir = os.path.join(dir, '{name}-{ver}.dist-info'.format(**egg_info))
  58. bw.egg2dist(os.path.join(dir, 'EGG-INFO'), dist_info_dir)
  59. bw.write_wheelfile(dist_info_dir, generator='egg2wheel')
  60. bw.write_record(dir, dist_info_dir)
  61. wheel_name = '{name}-{ver}-{pyver}-{}-{arch}'.format(abi, **egg_info)
  62. filename = make_archive(os.path.join(dest_dir, wheel_name), 'zip', root_dir=dir)
  63. os.rename(filename, filename[:-3] + 'whl')
  64. shutil.rmtree(dir)
  65. def main():
  66. parser = ArgumentParser()
  67. parser.add_argument('eggs', nargs='*', help="Eggs to convert")
  68. parser.add_argument('--dest-dir', '-d', default=os.path.curdir,
  69. help="Directory to store wheels (default %(default)s)")
  70. parser.add_argument('--verbose', '-v', action='store_true')
  71. args = parser.parse_args()
  72. for pat in args.eggs:
  73. for egg in iglob(pat):
  74. if args.verbose:
  75. print("{}... ".format(egg))
  76. sys.stdout.flush()
  77. egg2wheel(egg, args.dest_dir)
  78. if args.verbose:
  79. print("OK")
  80. if __name__ == "__main__":
  81. main()