From fcda2aba7b4fa5cfcf45ae1b02dbfc4876c17b96 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 15:54:48 +0200 Subject: Merging debian version 2024a-2. Signed-off-by: Daniel Baumann --- debian/test_timezone_conversions | 50 +++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) (limited to 'debian/test_timezone_conversions') diff --git a/debian/test_timezone_conversions b/debian/test_timezone_conversions index 768e6fd..ac009a8 100755 --- a/debian/test_timezone_conversions +++ b/debian/test_timezone_conversions @@ -5,6 +5,7 @@ """Check convert_timezone from tzdata.config for consistency.""" import argparse +import functools import logging import pathlib import re @@ -40,13 +41,14 @@ EXCLUDE_UNSELECTABLE = { class ConvertTimezone: """Wrap convert_timezone from tzdata.config.""" - def __init__(self, tzdata_config: pathlib.Path): + def __init__(self, tzdata_config: pathlib.Path) -> None: self.tzdata_config = tzdata_config content = tzdata_config.read_text(encoding="utf-8") match = re.search(r"convert_timezone\(\).*\n}", content, flags=re.DOTALL) assert match, f"convert_timezone function not found in {tzdata_config}" self.convert_timezone = match.group(0) + @functools.lru_cache(maxsize=8192) def __call__(self, timezone: str) -> str: shell_script = f"{self.convert_timezone}\nconvert_timezone '{timezone}'\n" shell = subprocess.run( @@ -57,17 +59,18 @@ class ConvertTimezone: ) return shell.stdout.strip() - def filter_converted_timezones(self, timezones: set[str]) -> set[str]: - """Return set of timezones that will be converted by convert_timezone.""" - converted = set() + def filter_converted_timezones(self, timezones: set[str]) -> dict[str, str]: + """Return dict of timezones that will be converted by convert_timezone.""" + converted = {} for timezone in timezones: - if self(timezone) != timezone: - converted.add(timezone) + conversion = self(timezone) + if conversion != timezone: + converted[timezone] = conversion return converted def filter_unconverted_timezones(self, timezones: set[str]) -> set[str]: """Return set of timezones that will not be converted by convert_timezone.""" - return timezones - self.filter_converted_timezones(timezones) + return timezones - set(self.filter_converted_timezones(timezones)) def get_targets(self) -> set[str]: """Return set of conversion targets.""" @@ -115,6 +118,27 @@ def get_debconf_choices(template_filename: pathlib.Path) -> set[str]: return debconf_choices +def _check_symlink(source: str, target: str) -> bool: + """Check if the given timezone source symlinks to the given target.""" + for tzpath in zoneinfo.TZPATH: + timezone = pathlib.Path(tzpath) / source + if timezone.exists(): + expected_target = pathlib.Path(tzpath) / target + return timezone.resolve() == expected_target.resolve() + return True + + +def check_symlinks(timezones: dict[str, str]) -> set[str]: + """Check timezone replacements are identical to the symlinks on disk.""" + mismatch = set() + for source, target in timezones.items(): + if source.startswith("right/"): + continue + if not _check_symlink(source, target): + mismatch.add(source) + return mismatch + + def existing_dir_path(string: str) -> pathlib.Path: """Convert string to existing dir path or raise ArgumentTypeError.""" path = pathlib.Path(string) @@ -160,7 +184,7 @@ def main() -> int: conversion_targets = convert_timezone.get_targets() failures = 0 - converted = convert_timezone.filter_converted_timezones(selectable) + converted = set(convert_timezone.filter_converted_timezones(selectable)) if converted: logger.error( "Following %i timezones can be selected, but will be converted:\n%s", @@ -206,6 +230,16 @@ def main() -> int: ) failures += 1 + mismatch = check_symlinks(convert_timezone.filter_converted_timezones(available)) + if mismatch: + logger.error( + "Following %i timezones are converted," + " but they do not match their symlink targets:\n%s", + len(mismatch), + "\n".join(sorted(mismatch)), + ) + failures += 1 + return failures -- cgit v1.2.3