archive.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. """
  2. Archive tools for wheel.
  3. """
  4. import os
  5. import os.path
  6. import time
  7. import zipfile
  8. from distutils import log
  9. def archive_wheelfile(base_name, base_dir):
  10. """Archive all files under `base_dir` in a whl file and name it like
  11. `base_name`.
  12. """
  13. olddir = os.path.abspath(os.curdir)
  14. base_name = os.path.abspath(base_name)
  15. try:
  16. os.chdir(base_dir)
  17. return make_wheelfile_inner(base_name)
  18. finally:
  19. os.chdir(olddir)
  20. def make_wheelfile_inner(base_name, base_dir='.'):
  21. """Create a whl file from all the files under 'base_dir'.
  22. Places .dist-info at the end of the archive."""
  23. zip_filename = base_name + ".whl"
  24. log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
  25. # Some applications need reproducible .whl files, but they can't do this
  26. # without forcing the timestamp of the individual ZipInfo objects. See
  27. # issue #143.
  28. timestamp = os.environ.get('SOURCE_DATE_EPOCH')
  29. if timestamp is None:
  30. date_time = None
  31. else:
  32. date_time = time.gmtime(int(timestamp))[0:6]
  33. score = {'WHEEL': 1, 'METADATA': 2, 'RECORD': 3}
  34. def writefile(path, date_time):
  35. st = os.stat(path)
  36. if date_time is None:
  37. mtime = time.gmtime(st.st_mtime)
  38. date_time = mtime[0:6]
  39. zinfo = zipfile.ZipInfo(path, date_time)
  40. zinfo.external_attr = st.st_mode << 16
  41. zinfo.compress_type = zipfile.ZIP_DEFLATED
  42. with open(path, 'rb') as fp:
  43. zip.writestr(zinfo, fp.read())
  44. log.info("adding '%s'" % path)
  45. with zipfile.ZipFile(zip_filename, "w", compression=zipfile.ZIP_DEFLATED,
  46. allowZip64=True) as zip:
  47. deferred = []
  48. for dirpath, dirnames, filenames in os.walk(base_dir):
  49. # Sort the directory names so that `os.walk` will walk them in a
  50. # defined order on the next iteration.
  51. dirnames.sort()
  52. for name in sorted(filenames):
  53. path = os.path.normpath(os.path.join(dirpath, name))
  54. if os.path.isfile(path):
  55. if dirpath.endswith('.dist-info'):
  56. deferred.append((score.get(name, 0), path))
  57. else:
  58. writefile(path, date_time)
  59. deferred.sort()
  60. for score, path in deferred:
  61. writefile(path, date_time)
  62. return zip_filename