]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Preserve de-duplicated tag order in documentation
authorJames Addison <jay@jp-hosting.net>
Sun, 25 Feb 2024 21:10:36 +0000 (21:10 +0000)
committerPetr Špaček <pspacek@isc.org>
Fri, 23 Aug 2024 13:34:00 +0000 (15:34 +0200)
The 'set' datatype in Python does not provide iteration-order
guarantees related to insertion-order.  That means that its
usage in the 'split_csv' helper function during documentation
build can produce nondeterministic results.

That is non-desirable for two reasons: it means that the
documentation output may appear to vary unnecessarily between
builds, and secondly there could be loss-of-information in cases
where tag order in the source documentation is significant.

This patch implements order-preserving de-duplication of tags,
allowing authors to specify tags using intentional priority
ordering, while also removing tags that appear more than once.

doc/arm/_ext/iscconf.py

index b5bd966e2a95811053740e9be128aaa75ee92faf..32bbec2bf22b99c55d126028232ef8a2e613fc90 100644 (file)
@@ -41,12 +41,18 @@ logger = logging.getLogger(__name__)
 
 def split_csv(argument, required):
     argument = argument or ""
-    outlist = list(filter(len, (s.strip() for s in argument.split(","))))
-    if required and not outlist:
+    values = list(filter(len, (s.strip() for s in argument.split(","))))
+    if required and not values:
         raise ValueError(
             "a non-empty list required; provide at least one value or remove"
             " this option"
         )
+    # Order-preserving de-duplication
+    outlist, seen = list(), set()  # pylint: disable=use-list-literal
+    for value in values:
+        if value not in seen:
+            seen.add(value)
+            outlist.append(value)
     return outlist
 
 
@@ -73,10 +79,8 @@ def domain_factory(domainname, domainlabel, todolist, grammar):
 
         def run(self):
             placeholder = todolist("")
-            placeholder["isc_filter_tags"] = set(self.options.get("filter_tags", []))
-            placeholder["isc_filter_blocks"] = set(
-                self.options.get("filter_blocks", [])
-            )
+            placeholder["isc_filter_tags"] = self.options.get("filter_tags", [])
+            placeholder["isc_filter_blocks"] = self.options.get("filter_blocks", [])
             return [placeholder]
 
     class ISCConfDomain(Domain):
@@ -127,7 +131,7 @@ def domain_factory(domainname, domainlabel, todolist, grammar):
 
             @property
             def isc_tags(self):
-                return set(self.options.get("tags", []))
+                return self.options.get("tags", [])
 
             @property
             def isc_short(self):
@@ -475,11 +479,11 @@ def domain_factory(domainname, domainlabel, todolist, grammar):
                             lambda item: (
                                 (
                                     not acceptable_tags
-                                    or item["tags"].intersection(acceptable_tags)
+                                    or set(item["tags"]).intersection(acceptable_tags)
                                 )
                                 and (
                                     not acceptable_blocks
-                                    or item["block_names"].intersection(
+                                    or set(item["block_names"]).intersection(
                                         acceptable_blocks
                                     )
                                 )