summaryrefslogtreecommitdiffstats
path: root/debian/generate_debconf_templates
diff options
context:
space:
mode:
Diffstat (limited to 'debian/generate_debconf_templates')
-rwxr-xr-xdebian/generate_debconf_templates239
1 files changed, 239 insertions, 0 deletions
diff --git a/debian/generate_debconf_templates b/debian/generate_debconf_templates
new file mode 100755
index 0000000..333c2b1
--- /dev/null
+++ b/debian/generate_debconf_templates
@@ -0,0 +1,239 @@
+#!/usr/bin/python3
+
+# Author: Benjamin Drung <bdrung@ubuntu.com>
+
+"""Generate tzdata debconf templates file."""
+
+import argparse
+import logging
+import os
+import pathlib
+import sys
+
+import natsort
+
+LOG_FORMAT = "%(name)s %(levelname)s: %(message)s"
+__script_name__ = os.path.basename(sys.argv[0]) if __name__ == "__main__" else __name__
+
+TEMPLATES_AREAS = [
+ "Africa",
+ "America",
+ "Antarctica",
+ "Arctic",
+ "Asia",
+ "Atlantic",
+ "Australia",
+ "Europe",
+ "Indian",
+ "Pacific",
+ "Etc",
+]
+
+# List of backward compatability symlinks that should not be selectable
+EXCLUDE_SYMLINKS = {
+ "Africa/Asmera",
+ "America/Argentina/ComodRivadavia",
+ "America/Buenos_Aires",
+ "America/Catamarca",
+ "America/Cordoba",
+ "America/Fort_Wayne",
+ "America/Indianapolis",
+ "America/Jujuy",
+ "America/Knox_IN",
+ "America/Louisville",
+ "America/Mendoza",
+ "America/Rosario",
+ "Antarctica/South_Pole",
+ "Asia/Ashkhabad",
+ "Asia/Calcutta",
+ "Asia/Chungking",
+ "Asia/Dacca",
+ "Asia/Katmandu",
+ "Asia/Macao",
+ "Asia/Rangoon",
+ "Asia/Saigon",
+ "Asia/Thimbu",
+ "Asia/Ujung_Pandang",
+ "Asia/Ulan_Bator",
+ "Atlantic/Faeroe",
+ "Australia/ACT",
+ "Australia/LHI",
+ "Australia/NSW",
+ "Australia/North",
+ "Australia/Queensland",
+ "Australia/South",
+ "Australia/Tasmania",
+ "Australia/Victoria",
+ "Australia/West",
+ "Europe/Kiev",
+ "Europe/Uzhgorod",
+ "Europe/Zaporozhye",
+ "Pacific/Enderbury",
+ "Pacific/Ponape",
+ "Pacific/Truk",
+ "US/Alaska",
+ "US/Aleutian",
+ "US/Arizona",
+ "US/Central",
+ "US/East-Indiana",
+ "US/Eastern",
+ "US/Hawaii",
+ "US/Indiana-Starke",
+ "US/Michigan",
+ "US/Mountain",
+ "US/Pacific",
+ "US/Samoa",
+}
+
+# List of symlinks that should be selectable
+INCLUDE_SYMLINKS = {
+ "Africa/Timbuktu",
+ "America/Atka",
+ "America/Coral_Harbour",
+ "America/Ensenada",
+ "America/Godthab",
+ "America/Kralendijk",
+ "America/Lower_Princes",
+ "America/Marigot",
+ "America/Montreal",
+ "America/Nipigon",
+ "America/Pangnirtung",
+ "America/Porto_Acre",
+ "America/Rainy_River",
+ "America/Santa_Isabel",
+ "America/Shiprock",
+ "America/St_Barthelemy",
+ "America/Thunder_Bay",
+ "America/Virgin",
+ "America/Yellowknife",
+ "Arctic/Longyearbyen",
+ "Asia/Chongqing",
+ "Asia/Harbin",
+ "Asia/Istanbul",
+ "Asia/Kashgar",
+ "Asia/Tel_Aviv",
+ "Atlantic/Jan_Mayen",
+ "Australia/Canberra",
+ "Australia/Currie",
+ "Australia/Yancowinna",
+ "Europe/Belfast",
+ "Europe/Bratislava",
+ "Europe/Busingen",
+ "Europe/Mariehamn",
+ "Europe/Nicosia",
+ "Europe/Podgorica",
+ "Europe/San_Marino",
+ "Europe/Tiraspol",
+ "Europe/Vatican",
+ "Pacific/Johnston",
+ "Pacific/Samoa",
+ "Pacific/Yap",
+ "Etc/GMT+0",
+ "Etc/GMT-0",
+ "Etc/GMT0",
+ "Etc/Greenwich",
+ "Etc/UCT",
+ "Etc/Universal",
+ "Etc/Zulu",
+}
+
+
+def get_timezones(base_dir: pathlib.Path, subdir: pathlib.Path) -> list[str]:
+ """Return list of timezone files relative to the base_dir."""
+ timezones = []
+ for path in natsort.natsorted(subdir.iterdir(), key=str):
+ if path.is_dir():
+ timezones += get_timezones(base_dir, path)
+ continue
+ timezone = str(path.relative_to(base_dir))
+ if path.is_symlink():
+ if timezone in EXCLUDE_SYMLINKS:
+ continue
+ if timezone not in INCLUDE_SYMLINKS:
+ logger = logging.getLogger(__script_name__)
+ logger.error(
+ "Timezone '%s' is a symlink, but neither in EXCLUDE_SYMLINKS"
+ " nor INCLUDE_SYMLINKS. Please add it explicitly.",
+ timezone,
+ )
+ sys.exit(1)
+ timezones.append(timezone)
+ return timezones
+
+
+def generate_debconf_templates_area(zoneinfo_dir: pathlib.Path, area: str) -> str:
+ """Generate tzdata debconf templates paragraph for given area."""
+ timezones = get_timezones(zoneinfo_dir, zoneinfo_dir / area)
+ choices = [timezone.split("/", maxsplit=1)[1] for timezone in timezones]
+ if area == "Etc":
+ choices_key = "Choices"
+ description = (
+ "Please select your time zone. Contrary to modern conventions, these"
+ " POSIX-compatible zones use positive values to refer to zones west of"
+ " Greenwich and negative values for those east of Greenwich"
+ " (e.g., 'Etc/GMT+6' refers to 6 hours west of Greenwich,"
+ " commonly called 'UTC-6')."
+ )
+ else:
+ choices_key = "__Choices"
+ description = (
+ "Please select the city or region corresponding to your time zone."
+ )
+ return f"""\
+Template: tzdata/Zones/{area}
+Type: select
+# Translators: This is a city name.
+# Do not translate underscores. You can use spaces instead.
+#flag:partial
+{choices_key}: {", ".join(choices)}
+_Description: Time zone:
+ {description}
+"""
+
+
+def generate_debconf_templates(zoneinfo_dir: pathlib.Path) -> str:
+ """Generate tzdata debconf templates file content."""
+ debconf_templates = f"""\
+# This file was generated by {pathlib.Path(__file__).relative_to(os.getcwd())}
+#
+Template: tzdata/Areas
+Type: select
+# Note to translators:
+# - This is a continent or ocean (except for "Etc")
+# - "Etc" will present users with a list of "GMT+xx" or "GMT-xx" timezones
+__Choices: {", ".join(TEMPLATES_AREAS)}
+_Description: Geographic area:
+ Please select the geographic area in which you live. Subsequent
+ configuration questions will narrow this down by presenting a list of
+ cities, representing the time zones in which they are located.
+"""
+ for area in TEMPLATES_AREAS:
+ debconf_templates += "\n" + generate_debconf_templates_area(zoneinfo_dir, area)
+ return debconf_templates
+
+
+def existing_dir_path(string: str) -> pathlib.Path:
+ """Convert string to existing dir path or raise ArgumentTypeError."""
+ path = pathlib.Path(string)
+ if not path.is_dir():
+ raise argparse.ArgumentTypeError(f"Directory {string} does not exist")
+ return path
+
+
+def main() -> None:
+ """Generate tzdata debconf templates file."""
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-d",
+ "--directory",
+ default=".",
+ type=existing_dir_path,
+ help="Directory containing the generated zoneinfo files",
+ )
+ args = parser.parse_args()
+ logging.basicConfig(format=LOG_FORMAT)
+ print(generate_debconf_templates(args.directory), end="")
+
+
+if __name__ == "__main__":
+ main()