Skip to content

Commit d352844

Browse files
committed
Add initial script to update the database
1 parent b8ddb25 commit d352844

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

tox.ini

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[tox]
2+
minversion = 3.3.0
3+
isolated_build = True
4+
skip_missing_interpreters = true
5+
6+
[testenv:update]
7+
description = Update the tzdata contents
8+
skip_install = True
9+
deps =
10+
requests
11+
click
12+
commands =
13+
python update.py {posargs}
14+
15+
[testenv:build]
16+
description = Build a wheel and source distribution
17+
skip_install = True
18+
deps =
19+
pep517
20+
twine
21+
commands =
22+
python -m pep517.build -s -b {toxinidir} -o {envtmpdir}/dist
23+
twine check {envtmpdir}/dist/*

update.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import logging
2+
import os
3+
import pathlib
4+
import shutil
5+
import subprocess
6+
import tempfile
7+
import typing
8+
9+
import click
10+
import requests
11+
12+
SOURCE = "https://data.iana.org/time-zones/releases"
13+
WORKING_DIR = pathlib.Path("tmp")
14+
REPO_ROOT = pathlib.Path(__file__).parent
15+
PKG_BASE = REPO_ROOT / "src"
16+
TEMPLATES_DIR = REPO_ROOT / "templates"
17+
18+
19+
def download_tzdb_tarballs(
20+
version: str, base_url: str = SOURCE, working_dir: pathlib.Path = WORKING_DIR
21+
) -> typing.List[pathlib.Path]:
22+
"""Download the tzdata and tzcode tarballs."""
23+
tzdata_file = f"tzdata{version}.tar.gz"
24+
tzcode_file = f"tzcode{version}.tar.gz"
25+
26+
target_dir = working_dir / version / "download"
27+
# mkdir -p target_dir
28+
target_dir.mkdir(parents=True, exist_ok=True)
29+
30+
download_locations = []
31+
for filename in [tzdata_file, tzcode_file]:
32+
download_location = target_dir / filename
33+
download_locations.append(download_location)
34+
35+
if download_location.exists():
36+
logging.info("File %s already exists, skipping", download_location)
37+
continue
38+
39+
url = f"{base_url}/{filename}"
40+
logging.info("Downloading %s from %s", filename, url)
41+
42+
r = requests.get(url)
43+
with open(download_location, "wb") as f:
44+
f.write(r.content)
45+
46+
return download_locations
47+
48+
49+
def unpack_tzdb_tarballs(download_locations: typing.List[pathlib.Path]) -> pathlib.Path:
50+
assert len(download_locations) == 2
51+
assert download_locations[0].parent == download_locations[1].parent
52+
base_dir = download_locations[0].parent.parent
53+
target_dir = base_dir / "tzdb"
54+
55+
# Remove the directory and re-create it if it does not exist
56+
if target_dir.exists():
57+
shutil.rmtree(target_dir)
58+
59+
target_dir.mkdir()
60+
61+
for tarball in download_locations:
62+
logging.info("Unpacking %s to %s", tarball, target_dir)
63+
subprocess.run(
64+
["tar", "-xf", os.fspath(tarball.absolute())], cwd=target_dir, check=True,
65+
)
66+
67+
return target_dir
68+
69+
70+
def load_zonefiles(base_dir: pathlib.Path) -> pathlib.Path:
71+
target_dir = base_dir.parent / "zoneinfo"
72+
if target_dir.exists():
73+
shutil.rmtree(target_dir)
74+
75+
with tempfile.TemporaryDirectory() as td:
76+
td_path = pathlib.Path(td)
77+
78+
# First run the makefile, which does all kinds of other random stuff
79+
subprocess.run(
80+
["make", f"DESTDIR={td}", "ZFLAGS=-b slim", "install"], cwd=base_dir
81+
)
82+
83+
# Move the zoneinfo files into the target directory
84+
src_dir = td_path / "usr" / "share" / "zoneinfo"
85+
shutil.move(os.fspath(src_dir), os.fspath(target_dir))
86+
87+
return target_dir
88+
89+
90+
def create_package(version: str, zoneinfo_dir: pathlib.Path):
91+
"""Creates the tzdata package"""
92+
# First remove the existing package contents
93+
target_dir = PKG_BASE / "tzdata"
94+
if target_dir.exists():
95+
shutil.rmtree(target_dir)
96+
97+
# Next move the zoneinfo file to the target location
98+
shutil.move(os.fspath(zoneinfo_dir), target_dir)
99+
100+
# Generate the base __init__.py from a template
101+
with open(TEMPLATES_DIR / "__init__.py.in", "r") as f_in:
102+
contents = f_in.read()
103+
contents = contents.replace("%%IANA_VERSION%%", version)
104+
105+
with open(target_dir / "__init__.py", "w") as f_out:
106+
f_out.write(contents)
107+
108+
# Now recursively create __init__.py files in every directory we need to
109+
for dirpath, _, filenames in os.walk(target_dir):
110+
if "__init__.py" not in filenames:
111+
init_file = pathlib.Path(dirpath) / "__init__.py"
112+
init_file.touch()
113+
114+
115+
@click.command()
116+
@click.option(
117+
"--version", "-v", default=None, help="The version of the tzdata file to download"
118+
)
119+
def main(version: str):
120+
logging.basicConfig(level=logging.INFO)
121+
122+
download_locations = download_tzdb_tarballs(version)
123+
tzdb_location = unpack_tzdb_tarballs(download_locations)
124+
125+
zonefile_path = load_zonefiles(tzdb_location)
126+
127+
create_package(version, zonefile_path)
128+
129+
130+
if __name__ == "__main__":
131+
main()

0 commit comments

Comments
 (0)