archive.py 2.3 KB

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