X-Git-Url: https://git.libre-soc.org/?p=utils.git;a=blobdiff_plain;f=src%2Fbudget_sync%2Fconfig.py;h=2f0e0f77254b558b8c794648cf2a7541923dd0c3;hp=56162ba717f164f59eaddad65927588ec8d48016;hb=c56e0aa1dc9759132c0bacbe5301ea36f3301eb2;hpb=77e86bf4a668209e49c290e4dc9ad12ccc584da2 diff --git a/src/budget_sync/config.py b/src/budget_sync/config.py index 56162ba..2f0e0f7 100644 --- a/src/budget_sync/config.py +++ b/src/budget_sync/config.py @@ -39,14 +39,30 @@ class Person: f"aliases={self.aliases!r}, email={self.email!r})" +class Milestone: + def __init__(self, config: "Config", + identifier: str, canonical_bug_id: int): + self.config = config + self.identifier = identifier + self.canonical_bug_id = canonical_bug_id + + def __repr__(self): + return f"Milestone(config=..., " \ + f"identifier={self.identifier!r}, " \ + f"canonical_bug_id={self.canonical_bug_id})" + + class Config: - def __init__(self, bugzilla_url: str, people: Dict[str, Person]): + def __init__(self, bugzilla_url: str, people: Dict[str, Person], + milestones: Dict[str, Milestone]): self.bugzilla_url = bugzilla_url self.people = people + self.milestones = milestones def __repr__(self): return f"Config(bugzilla_url={self.bugzilla_url!r}, " \ - f"people={self.people!r})" + f"people={self.people!r}, " \ + f"milestones={self.milestones!r})" @cached_property def all_names(self) -> Dict[str, Person]: @@ -73,6 +89,24 @@ class Config: retval[alias] = person return retval + @cached_property + def canonical_bug_ids(self) -> Dict[int, Milestone]: + # also checks for any bug id clashes and raises + # ConfigParseError if any are detected + retval = {} + for milestone in self.milestones.values(): + other_milestone = retval.get(milestone.canonical_bug_id) + if other_milestone is not None: + raise ConfigParseError( + f"canonical_bug_id is not allowed to be the same as " + f"another milestone's canonical_bug_id: in milestone " + f"entry for {milestone.identifier!r}: " + f"{milestone.canonical_bug_id} is also the " + f"canonical_bug_id for milestone " + f"{other_milestone.identifier!r}") + retval[milestone.canonical_bug_id] = milestone + return retval + def _parse_person(self, identifier: str, value: Any) -> Person: def raise_aliases_must_be_list_of_strings(): raise ConfigParseError( @@ -121,14 +155,52 @@ class Config: # if any are detected, so the following line is needed: self.all_names + def _parse_milestone(self, identifier: str, value: Any) -> Milestone: + if not isinstance(value, dict): + raise ConfigParseError( + f"milestones entry for {identifier!r} must be a table") + canonical_bug_id = None + for k, v in value.items(): + assert isinstance(k, str) + if k == "canonical_bug_id": + if not isinstance(v, int): + raise ConfigParseError( + f"`canonical_bug_id` field in milestones entry for " + f"{identifier!r} must be an integer") + canonical_bug_id = v + else: + raise ConfigParseError(f"unknown field in milestones entry " + f"for {identifier!r}: `{k}`") + if canonical_bug_id is None: + raise ConfigParseError(f"`canonical_bug_id` field is missing in " + f"milestones entry for {identifier!r}") + return Milestone(config=self, identifier=identifier, + canonical_bug_id=canonical_bug_id) + + def _parse_milestones(self, milestones: Any): + if not isinstance(milestones, dict): + raise ConfigParseError("`milestones` field must be a table") + for identifier, value in milestones.items(): + assert isinstance(identifier, str) + self.milestones[identifier] = \ + self._parse_milestone(identifier, value) + + # self.canonical_bug_ids checks for bug id clashes and raises + # ConfigParseError if any are detected, so the following line + # is needed: + self.canonical_bug_ids + @staticmethod def _from_toml(parsed_toml: Dict[str, Any]) -> "Config": people = None bugzilla_url = None + milestones = None for k, v in parsed_toml.items(): assert isinstance(k, str) if k == "people": people = v + elif k == "milestones": + milestones = v elif k == "bugzilla_url": if not isinstance(v, str): raise ConfigParseError("`bugzilla_url` must be a string") @@ -139,13 +211,18 @@ class Config: if bugzilla_url is None: raise ConfigParseError("`bugzilla_url` field is missing") - config = Config(bugzilla_url=bugzilla_url, people={}) + config = Config(bugzilla_url=bugzilla_url, people={}, milestones={}) if people is None: raise ConfigParseError("`people` table is missing") else: config._parse_people(people) + if milestones is None: + raise ConfigParseError("`milestones` table is missing") + else: + config._parse_milestones(milestones) + return config @staticmethod