lib: make cmd_element->attr a bitmask & clarify

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>
This commit is contained in:
David Lamparter 2022-10-04 13:30:04 +02:00
parent 53d8bf6d7a
commit 9eebf97e3d
10 changed files with 59 additions and 34 deletions

View 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);
@ -990,7 +988,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);
}
@ -1471,8 +1469,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, " ");
@ -1561,9 +1558,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);
}

View File

@ -358,9 +358,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)

View 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)

View 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 {

View 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);

View 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);

View 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);

View File

@ -17,8 +17,22 @@
# 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

View 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']])

View 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, " ");