]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: make cmd_element->attr a bitmask & clarify
authorDavid Lamparter <equinox@opensourcerouting.org>
Tue, 4 Oct 2022 11:30:04 +0000 (13:30 +0200)
committerDonatas Abraitis <donatas@opensourcerouting.org>
Sat, 8 Jul 2023 07:58:42 +0000 (10:58 +0300)
It already "looks" like a bitmask, but we currently can't flag a command
both YANG and HIDDEN at the same time.  It really should be a bitmask.

Also clarify DEPRECATED behaviour (or the absence thereof.)

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
lib/command.c
lib/command.h
lib/command_graph.c
lib/command_graph.h
lib/command_match.c
lib/command_py.c
lib/grammar_sandbox.c
python/clippy/__init__.py
python/xrelfo.py
tools/permutations.c

index ca05cd6d2fa20d0890bd913aafc704804c7f215f..389674afb19d365e220c0e998b5adc2294b47b07 100644 (file)
@@ -264,8 +264,7 @@ void install_node(struct cmd_node *node)
        node->cmdgraph = graph_new();
        node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
        // add start node
-       struct cmd_token *token =
-               cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+       struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL);
        graph_new_node(node->cmdgraph, token,
                       (void (*)(void *)) & cmd_token_del);
 
@@ -325,7 +324,7 @@ void _install_element(enum node_type ntype, const struct cmd_element *cmd)
        if (cnode->graph_built || !defer_cli_tree) {
                struct graph *graph = graph_new();
                struct cmd_token *token =
-                       cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+                       cmd_token_new(START_TKN, 0, NULL, NULL);
                graph_new_node(graph, token,
                               (void (*)(void *)) & cmd_token_del);
 
@@ -348,8 +347,7 @@ static void cmd_finalize_iter(struct hash_bucket *hb, void *arg)
        struct cmd_node *cnode = arg;
        const struct cmd_element *cmd = hb->data;
        struct graph *graph = graph_new();
-       struct cmd_token *token =
-               cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+       struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL);
 
        graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
 
@@ -404,7 +402,7 @@ void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
        if (cnode->graph_built) {
                struct graph *graph = graph_new();
                struct cmd_token *token =
-                       cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+                       cmd_token_new(START_TKN, 0, NULL, NULL);
                graph_new_node(graph, token,
                               (void (*)(void *)) & cmd_token_del);
 
@@ -994,7 +992,7 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
                         * Perform pending commit (if any) before executing
                         * non-YANG command.
                         */
-                       if (matched_element->attr != CMD_ATTR_YANG)
+                       if (!(matched_element->attr & CMD_ATTR_YANG))
                                (void)nb_cli_pending_commit_check(vty);
                }
 
@@ -1475,8 +1473,7 @@ static void permute(struct graph_node *start, struct vty *vty)
        for (unsigned int i = 0; i < vector_active(start->to); i++) {
                struct graph_node *gn = vector_slot(start->to, i);
                struct cmd_token *tok = gn->data;
-               if (tok->attr == CMD_ATTR_HIDDEN
-                   || tok->attr == CMD_ATTR_DEPRECATED)
+               if (tok->attr & CMD_ATTR_HIDDEN)
                        continue;
                else if (tok->type == END_TKN || gn == start) {
                        vty_out(vty, " ");
@@ -1565,9 +1562,8 @@ int cmd_list_cmds(struct vty *vty, int do_permute)
                const struct cmd_element *element = NULL;
                for (unsigned int i = 0; i < vector_active(node->cmd_vector);
                     i++)
-                       if ((element = vector_slot(node->cmd_vector, i))
-                           && element->attr != CMD_ATTR_DEPRECATED
-                           && element->attr != CMD_ATTR_HIDDEN) {
+                       if ((element = vector_slot(node->cmd_vector, i)) &&
+                           !(element->attr & CMD_ATTR_HIDDEN)) {
                                vty_out(vty, "    ");
                                print_cmd(vty, element->string);
                        }
index 70e52708a741ee0ac5def20e7d8d94af64fe1f12..06f2bfd589f7f383e26d6f1b9a68e6111de92f09 100644 (file)
@@ -368,9 +368,13 @@ struct cmd_node {
        DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, \
                          0)
 
+/* note: DEPRECATED implies HIDDEN, and other than that there is currently no
+ * difference.  It's purely for expressing intent in the source code - a
+ * DEPRECATED command is supposed to go away, a HIDDEN one is likely to stay.
+ */
 #define ALIAS_DEPRECATED(funcname, cmdname, cmdstr, helpstr)                   \
        DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr,                  \
-                         CMD_ATTR_DEPRECATED, 0)
+                         CMD_ATTR_DEPRECATED | CMD_ATTR_HIDDEN, 0)
 
 #define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr)                         \
        DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG, 0)
index 09d802e796705b4e1003b0b804559148d68cbdc0..e940685250fad5343f9a670646913dfcaa963ca8 100644 (file)
@@ -494,9 +494,10 @@ void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf)
        snprintf(nbuf, sizeof(nbuf), "<b>%s</b>",
                 lookup_msg(tokennames, tok->type, NULL));
        buffer_putstr(buf, nbuf);
-       if (tok->attr == CMD_ATTR_DEPRECATED)
+       if (tok->attr & CMD_ATTR_DEPRECATED)
                buffer_putstr(buf, " (d)");
-       else if (tok->attr == CMD_ATTR_HIDDEN)
+       /* DEPRECATED implies HIDDEN, don't print both */
+       else if (tok->attr & CMD_ATTR_HIDDEN)
                buffer_putstr(buf, " (h)");
        if (tok->text) {
                if (tok->type == WORD_TKN)
index ed4da6aa4c8942de03634eaa86111155793d3c1b..57a70a8186b40d7e7674d61d6423e66f6aa8e530 100644 (file)
@@ -73,10 +73,10 @@ enum cmd_token_type {
 #define IS_VARYING_TOKEN(x) ((x) >= VARIABLE_TKN && (x) < FORK_TKN)
 
 /* Command attributes */
-enum { CMD_ATTR_NORMAL,
-       CMD_ATTR_DEPRECATED,
-       CMD_ATTR_HIDDEN,
-       CMD_ATTR_YANG,
+enum {
+       CMD_ATTR_YANG = (1 << 0),
+       CMD_ATTR_HIDDEN = (1 << 1),
+       CMD_ATTR_DEPRECATED = (1 << 2),
 };
 
 enum varname_src {
index f221e0a02ce7ebfc846d93b81dab1a5a0d0de85d..ce2dbc9528997ad5997146baaaebd77ee429896b 100644 (file)
@@ -395,8 +395,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
                for (ALL_LIST_ELEMENTS_RO(current, node, gstack)) {
                        struct cmd_token *token = gstack[0]->data;
 
-                       if (token->attr == CMD_ATTR_HIDDEN
-                           || token->attr == CMD_ATTR_DEPRECATED)
+                       if (token->attr & CMD_ATTR_HIDDEN)
                                continue;
 
                        enum match_type minmatch = min_match_level(token->type);
index 6301eec5e8ee1c6ee2604125bdccc79e222fc962..ff7b2d18a5d12df3a95dbd31a52c6cc45b48780f 100644 (file)
@@ -226,8 +226,8 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph,
                        wrap->type = "???";
                }
 
-               wrap->deprecated = (tok->attr == CMD_ATTR_DEPRECATED);
-               wrap->hidden = (tok->attr == CMD_ATTR_HIDDEN);
+               wrap->deprecated = !!(tok->attr & CMD_ATTR_DEPRECATED);
+               wrap->hidden = !!(tok->attr & CMD_ATTR_HIDDEN);
                wrap->text = tok->text;
                wrap->desc = tok->desc;
                wrap->varname = tok->varname;
@@ -353,6 +353,11 @@ PyMODINIT_FUNC command_py_init(void)
        if (!pymod)
                initret(NULL);
 
+       if (PyModule_AddIntMacro(pymod, CMD_ATTR_YANG)
+           || PyModule_AddIntMacro(pymod, CMD_ATTR_HIDDEN)
+           || PyModule_AddIntMacro(pymod, CMD_ATTR_DEPRECATED))
+               initret(NULL);
+
        Py_INCREF(&typeobj_graph_node);
        PyModule_AddObject(pymod, "GraphNode", (PyObject *)&typeobj_graph_node);
        Py_INCREF(&typeobj_graph);
index f9778c5d4c460f068099f4c545e3a6ac9970772a..8fa47c053bcfaaa7d82ea9590b59c2291c9bf5fd 100644 (file)
@@ -76,8 +76,7 @@ DEFUN (grammar_test,
 
        // parse the command and install it into the command graph
        struct graph *graph = graph_new();
-       struct cmd_token *token =
-               cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+       struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL);
        graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
 
        cmd_graph_parse(graph, cmd);
index 344a1c91eec29f7c658c557276e3125f98640761..c356a29d3f2c572902ee9007bc29a21329c7c24c 100644 (file)
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 
 import os, stat
+
+try:
+    from enum import IntFlag as _IntFlag
+except ImportError:
+    # python <3.6
+    from enum import IntEnum as _IntFlag  # type: ignore
+
 import _clippy
-from _clippy import parse, Graph, GraphNode
+from _clippy import (
+    parse,
+    Graph,
+    GraphNode,
+    CMD_ATTR_YANG,
+    CMD_ATTR_HIDDEN,
+    CMD_ATTR_DEPRECATED,
+)
 
 
 frr_top_src = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
@@ -78,3 +92,9 @@ def wrdiff(filename, buf, reffiles=[]):
     with open(newname, "w") as out:
         out.write(buf)
     os.rename(newname, filename)
+
+
+class CmdAttr(_IntFlag):
+    YANG = CMD_ATTR_YANG
+    HIDDEN = CMD_ATTR_HIDDEN
+    DEPRECATED = CMD_ATTR_DEPRECATED
index 17262da8d98c60a5ff4c0821ecede551aa7448a9..3bfe9950d774ea023718a36b73f705bcfc77bbe0 100644 (file)
@@ -26,7 +26,7 @@ import argparse
 
 from clippy.uidhash import uidhash
 from clippy.elf import *
-from clippy import frr_top_src
+from clippy import frr_top_src, CmdAttr
 from tiabwarfo import FieldApplicator
 
 try:
@@ -196,8 +196,6 @@ Xref.containers[XREFT_LOGMSG] = XrefLogmsg
 class CmdElement(ELFDissectStruct, XrelfoJson):
     struct = 'cmd_element'
 
-    cmd_attrs = { 0: None, 1: 'deprecated', 2: 'hidden'}
-
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
@@ -207,10 +205,14 @@ class CmdElement(ELFDissectStruct, XrelfoJson):
         jsobj.update({
             'string': self.string,
             'doc': self.doc,
-            'attr': self.cmd_attrs.get(self.attr, self.attr),
         })
-        if jsobj['attr'] is None:
-            del jsobj['attr']
+        if self.attr:
+            jsobj['attr'] = attr = self.attr
+            for attrname in CmdAttr.__members__:
+                val = CmdAttr[attrname]
+                if attr & val:
+                    jsobj.setdefault('attrs', []).append(attrname.lower())
+                    attr &= ~val
 
         jsobj['defun'] = dict([(i, getattr(self.xref, i)) for i in ['file', 'line', 'func']])
 
index b280cc15b105748b015571a6fdb6036e100fbe65..a0b041f2f2fbd88e030db22871bfb102c4742407 100644 (file)
@@ -80,8 +80,7 @@ void permute(struct graph_node *start)
        for (unsigned int i = 0; i < vector_active(start->to); i++) {
                struct graph_node *gn = vector_slot(start->to, i);
                struct cmd_token *tok = gn->data;
-               if (tok->attr == CMD_ATTR_HIDDEN
-                   || tok->attr == CMD_ATTR_DEPRECATED)
+               if (tok->attr & CMD_ATTR_HIDDEN)
                        continue;
                else if (tok->type == END_TKN || gn == start) {
                        fprintf(stdout, " ");