rebuild.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import logging
  2. import os
  3. import tempfile
  4. import shutil
  5. import json
  6. from subprocess import check_call, check_output
  7. from tarfile import TarFile
  8. from dateutil.zoneinfo import METADATA_FN, ZONEFILENAME
  9. def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None):
  10. """Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar*
  11. filename is the timezone tarball from ``ftp.iana.org/tz``.
  12. """
  13. tmpdir = tempfile.mkdtemp()
  14. zonedir = os.path.join(tmpdir, "zoneinfo")
  15. moduledir = os.path.dirname(__file__)
  16. try:
  17. with TarFile.open(filename) as tf:
  18. for name in zonegroups:
  19. tf.extract(name, tmpdir)
  20. filepaths = [os.path.join(tmpdir, n) for n in zonegroups]
  21. _run_zic(zonedir, filepaths)
  22. # write metadata file
  23. with open(os.path.join(zonedir, METADATA_FN), 'w') as f:
  24. json.dump(metadata, f, indent=4, sort_keys=True)
  25. target = os.path.join(moduledir, ZONEFILENAME)
  26. with TarFile.open(target, "w:%s" % format) as tf:
  27. for entry in os.listdir(zonedir):
  28. entrypath = os.path.join(zonedir, entry)
  29. tf.add(entrypath, entry)
  30. finally:
  31. shutil.rmtree(tmpdir)
  32. def _run_zic(zonedir, filepaths):
  33. """Calls the ``zic`` compiler in a compatible way to get a "fat" binary.
  34. Recent versions of ``zic`` default to ``-b slim``, while older versions
  35. don't even have the ``-b`` option (but default to "fat" binaries). The
  36. current version of dateutil does not support Version 2+ TZif files, which
  37. causes problems when used in conjunction with "slim" binaries, so this
  38. function is used to ensure that we always get a "fat" binary.
  39. """
  40. try:
  41. help_text = check_output(["zic", "--help"])
  42. except OSError as e:
  43. _print_on_nosuchfile(e)
  44. raise
  45. if b"-b " in help_text:
  46. bloat_args = ["-b", "fat"]
  47. else:
  48. bloat_args = []
  49. check_call(["zic"] + bloat_args + ["-d", zonedir] + filepaths)
  50. def _print_on_nosuchfile(e):
  51. """Print helpful troubleshooting message
  52. e is an exception raised by subprocess.check_call()
  53. """
  54. if e.errno == 2:
  55. logging.error(
  56. "Could not find zic. Perhaps you need to install "
  57. "libc-bin or some other package that provides it, "
  58. "or it's not in your PATH?")