diff options
Diffstat (limited to 'debian/generate_debconf_templates')
-rwxr-xr-x | debian/generate_debconf_templates | 239 |
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() |