From e915900bfec8d24276afb73599c94ab93f3c24ee Mon Sep 17 00:00:00 2001
From: John Estabrook <jestabro@vyos.io>
Date: Wed, 20 Mar 2024 10:54:23 -0500
Subject: xml: T6146: add utils and helper to provide priority data

---
 python/vyos/priority.py               | 75 +++++++++++++++++++++++++++++++++++
 python/vyos/xml_ref/generate_cache.py |  3 +-
 src/helpers/priority.py               | 42 ++++++++++++++++++++
 3 files changed, 119 insertions(+), 1 deletion(-)
 create mode 100644 python/vyos/priority.py
 create mode 100755 src/helpers/priority.py

diff --git a/python/vyos/priority.py b/python/vyos/priority.py
new file mode 100644
index 000000000..ab4e6d411
--- /dev/null
+++ b/python/vyos/priority.py
@@ -0,0 +1,75 @@
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library.  If not, see <http://www.gnu.org/licenses/>.
+
+from pathlib import Path
+from typing import List
+
+from vyos.xml_ref import load_reference
+from vyos.base import Warning as Warn
+
+def priority_data(d: dict) -> list:
+    def func(d, path, res, hier):
+        for k,v in d.items():
+            if not 'node_data' in v:
+                continue
+            subpath = path + [k]
+            hier_prio = hier
+            data = v.get('node_data')
+            o = data.get('owner')
+            p = data.get('priority')
+            # a few interface-definitions have priority preceding owner
+            # attribute, instead of within properties; pass in descent
+            if p is not None and o is None:
+                hier_prio = p
+            if o is not None and p is None:
+                p = hier_prio
+            if o is not None and p is not None:
+                o = Path(o.split()[0]).name
+                p = int(p)
+                res.append((subpath, o, p))
+            if isinstance(v, dict):
+                func(v, subpath, res, hier_prio)
+        return res
+    ret = func(d, [], [], 0)
+    ret = sorted(ret, key=lambda x: x[0])
+    ret = sorted(ret, key=lambda x: x[2])
+    return ret
+
+def get_priority_data() -> list:
+    xml = load_reference()
+    return priority_data(xml.ref)
+
+def priority_sort(sections: List[list[str]] = None,
+                  owners: List[str] = None,
+                  reverse=False) -> List:
+    if sections is not None:
+        index = 0
+        collection: List = sections
+    elif owners is not None:
+        index = 1
+        collection = owners
+    else:
+        raise ValueError('one of sections or owners is required')
+
+    l = get_priority_data()
+    m = [item for item in l if item[index] in collection]
+    n = sorted(m, key=lambda x: x[2], reverse=reverse)
+    o = [item[index] for item in n]
+    # sections are unhashable; use comprehension
+    missed = [j for j in collection if j not in o]
+    if missed:
+        Warn(f'No priority available for elements {missed}')
+
+    return o
diff --git a/python/vyos/xml_ref/generate_cache.py b/python/vyos/xml_ref/generate_cache.py
index 6a05d4608..d1ccb0f81 100755
--- a/python/vyos/xml_ref/generate_cache.py
+++ b/python/vyos/xml_ref/generate_cache.py
@@ -38,7 +38,8 @@ xml_tmp = join('/tmp', xml_cache_json)
 pkg_cache = abspath(join(_here, 'pkg_cache'))
 ref_cache = abspath(join(_here, 'cache.py'))
 
-node_data_fields = ("node_type", "multi", "valueless", "default_value")
+node_data_fields = ("node_type", "multi", "valueless", "default_value",
+                    "owner", "priority")
 
 def trim_node_data(cache: dict):
     for k in list(cache):
diff --git a/src/helpers/priority.py b/src/helpers/priority.py
new file mode 100755
index 000000000..04186104c
--- /dev/null
+++ b/src/helpers/priority.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+#
+
+import sys
+from argparse import ArgumentParser
+from tabulate import tabulate
+
+from vyos.priority import get_priority_data
+
+if __name__ == '__main__':
+    parser = ArgumentParser()
+    parser.add_argument('--legacy-format', action='store_true',
+                        help="format output for comparison with legacy 'priority.pl'")
+    args = parser.parse_args()
+
+    prio_list = get_priority_data()
+    if args.legacy_format:
+        for p in prio_list:
+            print(f'{p[2]} {"/".join(p[0])}')
+        sys.exit(0)
+
+    l = []
+    for p in prio_list:
+        l.append((p[2], p[1], p[0]))
+    headers = ['priority', 'owner', 'path']
+    out = tabulate(l, headers, numalign='right')
+    print(out)
-- 
cgit v1.2.3