|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import tempfile
|
|
|
|
import shutil
|
|
|
|
import json
|
|
|
|
from subprocess import check_call, check_output
|
|
|
|
from tarfile import TarFile
|
|
|
|
|
|
|
|
from dateutil.zoneinfo import METADATA_FN, ZONEFILENAME
|
|
|
|
|
|
|
|
|
|
|
|
def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None):
|
|
|
|
"""Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar*
|
|
|
|
|
|
|
|
filename is the timezone tarball from ``ftp.iana.org/tz``.
|
|
|
|
|
|
|
|
"""
|
|
|
|
tmpdir = tempfile.mkdtemp()
|
|
|
|
zonedir = os.path.join(tmpdir, "zoneinfo")
|
|
|
|
moduledir = os.path.dirname(__file__)
|
|
|
|
try:
|
|
|
|
with TarFile.open(filename) as tf:
|
|
|
|
for name in zonegroups:
|
|
|
|
tf.extract(name, tmpdir)
|
|
|
|
filepaths = [os.path.join(tmpdir, n) for n in zonegroups]
|
|
|
|
|
|
|
|
_run_zic(zonedir, filepaths)
|
|
|
|
|
|
|
|
# write metadata file
|
|
|
|
with open(os.path.join(zonedir, METADATA_FN), 'w') as f:
|
|
|
|
json.dump(metadata, f, indent=4, sort_keys=True)
|
|
|
|
target = os.path.join(moduledir, ZONEFILENAME)
|
|
|
|
with TarFile.open(target, "w:%s" % format) as tf:
|
|
|
|
for entry in os.listdir(zonedir):
|
|
|
|
entrypath = os.path.join(zonedir, entry)
|
|
|
|
tf.add(entrypath, entry)
|
|
|
|
finally:
|
|
|
|
shutil.rmtree(tmpdir)
|
|
|
|
|
|
|
|
|
|
|
|
def _run_zic(zonedir, filepaths):
|
|
|
|
"""Calls the ``zic`` compiler in a compatible way to get a "fat" binary.
|
|
|
|
|
|
|
|
Recent versions of ``zic`` default to ``-b slim``, while older versions
|
|
|
|
don't even have the ``-b`` option (but default to "fat" binaries). The
|
|
|
|
current version of dateutil does not support Version 2+ TZif files, which
|
|
|
|
causes problems when used in conjunction with "slim" binaries, so this
|
|
|
|
function is used to ensure that we always get a "fat" binary.
|
|
|
|
"""
|
|
|
|
|
|
|
|
try:
|
|
|
|
help_text = check_output(["zic", "--help"])
|
|
|
|
except OSError as e:
|
|
|
|
_print_on_nosuchfile(e)
|
|
|
|
raise
|
|
|
|
|
|
|
|
if b"-b " in help_text:
|
|
|
|
bloat_args = ["-b", "fat"]
|
|
|
|
else:
|
|
|
|
bloat_args = []
|
|
|
|
|
|
|
|
check_call(["zic"] + bloat_args + ["-d", zonedir] + filepaths)
|
|
|
|
|
|
|
|
|
|
|
|
def _print_on_nosuchfile(e):
|
|
|
|
"""Print helpful troubleshooting message
|
|
|
|
|
|
|
|
e is an exception raised by subprocess.check_call()
|
|
|
|
|
|
|
|
"""
|
|
|
|
if e.errno == 2:
|
|
|
|
logging.error(
|
|
|
|
"Could not find zic. Perhaps you need to install "
|
|
|
|
"libc-bin or some other package that provides it, "
|
|
|
|
"or it's not in your PATH?")
|