diff options
author | Binbin <binloveplay1314@qq.com> | 2022-05-27 17:58:00 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-27 12:58:00 +0300 |
commit | 2a099d49d457239201b38c3ec97054a167658b6e (patch) | |
tree | df5a74aff673143a9c093db5e9f06b778a4bb910 /utils/generate-command-code.py | |
parent | 6f7c1a8ce6861fb382f8313d07a6e2a13217a690 (diff) | |
download | redis-2a099d49d457239201b38c3ec97054a167658b6e.tar.gz |
Fix some commands key spec in json files (#10779)
There are some commands that has the wrong key specs.
This PR adds a key-spec related check in generate-command-code.py.
Check if the index is valid, or if there is an unused index.
The check result will look like:
```
[root]# python utils/generate-command-code.py
Processing json files...
Linking container command to subcommands...
Checking all commands...
command: RESTORE_ASKING may have unused key_spec
command: RENAME may have unused key_spec
command: PFDEBUG may have unused key_spec
command: WATCH key_specs missing flags
command: LCS arg: key2 key_spec_index error
command: RENAMENX may have unused key_spec
Error: There are errors in the commands check, please check the above logs.
```
The following commands have been fixed according to the check results:
- RESTORE ASKING: add missing arguments section (and history section)
- RENAME: newkey's key_spec_index should be 1
- PFDEBUG: add missing arguments (and change the arity from -3 to 3)
- WATCH: add missing key_specs flags: RO, like EXIST (it allow you to know the key exists, or is modified, but doesn't "leak" the data)
- LCS: key2 key_spec_index error, there is only one key-spec
- RENAMENX: newkey's key_spec_index should be 1
Diffstat (limited to 'utils/generate-command-code.py')
-rwxr-xr-x | utils/generate-command-code.py | 67 |
1 files changed, 64 insertions, 3 deletions
diff --git a/utils/generate-command-code.py b/utils/generate-command-code.py index c5c08e196..605bde40f 100755 --- a/utils/generate-command-code.py +++ b/utils/generate-command-code.py @@ -1,8 +1,7 @@ #!/usr/bin/env python3 - -import os import glob import json +import os ARG_TYPES = { "string": "ARG_TYPE_STRING", @@ -68,6 +67,55 @@ def get_optional_desc_string(desc, field, force_uppercase=False): return ret.replace("\n", "\\n") +def check_command_args_key_specs(args, command_key_specs_index_set, command_arg_key_specs_index_set): + if not args: + return True + + for arg in args: + if arg.key_spec_index is not None: + assert isinstance(arg.key_spec_index, int) + + if arg.key_spec_index not in command_key_specs_index_set: + print("command: %s arg: %s key_spec_index error" % (command.fullname(), arg.name)) + return False + + command_arg_key_specs_index_set.add(arg.key_spec_index) + + if not check_command_args_key_specs(arg.subargs, command_key_specs_index_set, command_arg_key_specs_index_set): + return False + + return True + +def check_command_key_specs(command): + if not command.key_specs: + return True + + assert isinstance(command.key_specs, list) + + for cmd_key_spec in command.key_specs: + if "flags" not in cmd_key_spec: + print("command: %s key_specs missing flags" % command.fullname()) + return False + + if "NOT_KEY" in cmd_key_spec["flags"]: + # Like SUNSUBSCRIBE / SPUBLISH / SSUBSCRIBE + return True + + command_key_specs_index_set = set(range(len(command.key_specs))) + command_arg_key_specs_index_set = set() + + # Collect key_spec used for each arg, including arg.subarg + if not check_command_args_key_specs(command.args, command_key_specs_index_set, command_arg_key_specs_index_set): + return False + + # Check if we have key_specs not used + if command_key_specs_index_set != command_arg_key_specs_index_set: + print("command: %s may have unused key_spec" % command.fullname()) + return False + + return True + + # Globals subcommands = {} # container_name -> dict(subcommand_name -> Subcommand) - Only subcommands commands = {} # command_name -> Command - Only commands @@ -132,6 +180,7 @@ class Argument(object): self.desc = desc self.name = self.desc["name"].lower() self.type = self.desc["type"] + self.key_spec_index = self.desc.get("key_spec_index", None) self.parent_name = parent_name self.subargs = [] self.subargs_name = None @@ -200,6 +249,7 @@ class Command(object): self.name = name.upper() self.desc = desc self.group = self.desc["group"] + self.key_specs = self.desc.get("key_specs", []) self.subcommands = [] self.args = [] for arg_desc in self.desc.get("arguments", []): @@ -271,7 +321,7 @@ class Command(object): def _key_specs_code(): s = "" - for spec in self.desc.get("key_specs", []): + for spec in self.key_specs: s += "{%s}," % KeySpec(spec).struct_code() return s[:-1] @@ -398,6 +448,17 @@ for command in commands.values(): subcommand.group = command.group command.subcommands.append(subcommand) +check_command_error_counter = 0 # An error counter is used to count errors in command checking. + +print("Checking all commands...") +for command in commands.values(): + if not check_command_key_specs(command): + check_command_error_counter += 1 + +if check_command_error_counter != 0: + print("Error: There are errors in the commands check, please check the above logs.") + exit(1) + print("Generating commands.c...") with open("%s/commands.c" % srcdir, "w") as f: f.write("/* Automatically generated by %s, do not edit. */\n\n" % os.path.basename(__file__)) |