Merge branch 'feature/idf_py_depeprecation_parameter_flag' into 'master'
idf.py: Add support for deprecation of command/options See merge request espressif/esp-idf!5433
This commit is contained in:
commit
146a0f8e14
3 changed files with 164 additions and 2 deletions
|
@ -527,6 +527,18 @@ endmenu\n" >> ${IDF_PATH}/Kconfig;
|
||||||
rm -rf CMakeLists.txt
|
rm -rf CMakeLists.txt
|
||||||
mv CMakeLists.txt.bak CMakeLists.txt
|
mv CMakeLists.txt.bak CMakeLists.txt
|
||||||
rm -rf CMakeLists.txt.bak
|
rm -rf CMakeLists.txt.bak
|
||||||
|
|
||||||
|
print_status "Print all required argument deprecation warnings"
|
||||||
|
idf.py -C${IDF_PATH}/tools/test_idf_py --test-0=a --test-1=b --test-2=c --test-3=d test-0 --test-sub-0=sa --test-sub-1=sb ta test-1 > out.txt
|
||||||
|
! grep -e '"test-0" is deprecated' -e '"test_0" is deprecated' out.txt || failure "Deprecation warnings are displayed for non-deprecated option/command"
|
||||||
|
grep -e 'Warning: Option "test_sub_1" is deprecated and will be removed in future versions.' \
|
||||||
|
-e 'Warning: Command "test-1" is deprecated and will be removed in future versions. Please use alternative command.' \
|
||||||
|
-e 'Warning: Option "test_1" is deprecated and will be removed in future versions.' \
|
||||||
|
-e 'Warning: Option "test_2" is deprecated and will be removed in future versions. Please update your parameters.' \
|
||||||
|
-e 'Warning: Option "test_3" is deprecated and will be removed in future versions.' \
|
||||||
|
out.txt \
|
||||||
|
|| failure "Deprecation warnings are not displayed"
|
||||||
|
rm out.txt
|
||||||
|
|
||||||
print_status "All tests completed"
|
print_status "All tests completed"
|
||||||
if [ -n "${FAILURES}" ]; then
|
if [ -n "${FAILURES}" ]; then
|
||||||
|
|
84
tools/idf.py
84
tools/idf.py
|
@ -551,6 +551,46 @@ def init_cli():
|
||||||
# Click is imported here to run it after check_environment()
|
# Click is imported here to run it after check_environment()
|
||||||
import click
|
import click
|
||||||
|
|
||||||
|
class DeprecationMessage(object):
|
||||||
|
"""Construct deprecation notice for help messages"""
|
||||||
|
|
||||||
|
def __init__(self, deprecated=False):
|
||||||
|
self.deprecated = deprecated
|
||||||
|
self.since = None
|
||||||
|
self.removed = None
|
||||||
|
self.custom_message = ""
|
||||||
|
|
||||||
|
if isinstance(deprecated, dict):
|
||||||
|
self.custom_message = deprecated.get("message", "")
|
||||||
|
self.since = deprecated.get("since", None)
|
||||||
|
self.removed = deprecated.get("removed", None)
|
||||||
|
elif isinstance(deprecated, str):
|
||||||
|
self.custom_message = deprecated
|
||||||
|
|
||||||
|
def full_message(self, type="Option"):
|
||||||
|
return "%s is deprecated %sand will be removed in%s.%s" % (
|
||||||
|
type,
|
||||||
|
"since %s " % self.since if self.since else "",
|
||||||
|
" %s" % self.removed if self.removed else " future versions",
|
||||||
|
" %s" % self.custom_message if self.custom_message else ""
|
||||||
|
)
|
||||||
|
|
||||||
|
def help(self, text, type="Option", separator=" "):
|
||||||
|
text = text or ""
|
||||||
|
return self.full_message(type) + separator + text if self.deprecated else text
|
||||||
|
|
||||||
|
def short_help(self, text):
|
||||||
|
text = text or ""
|
||||||
|
return ("Deprecated! " + text) if self.deprecated else text
|
||||||
|
|
||||||
|
def print_deprecation_warning(ctx):
|
||||||
|
"""Prints deprectation warnings for arguments in given context"""
|
||||||
|
for option in ctx.command.params:
|
||||||
|
default = () if option.multiple else option.default
|
||||||
|
if isinstance(option, Option) and option.deprecated and ctx.params[option.name] != default:
|
||||||
|
print("Warning: %s" % DeprecationMessage(option.deprecated).
|
||||||
|
full_message('Option "%s"' % option.name))
|
||||||
|
|
||||||
class Task(object):
|
class Task(object):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, callback, name, aliases, dependencies, order_dependencies, action_args
|
self, callback, name, aliases, dependencies, order_dependencies, action_args
|
||||||
|
@ -573,6 +613,7 @@ def init_cli():
|
||||||
self,
|
self,
|
||||||
name=None,
|
name=None,
|
||||||
aliases=None,
|
aliases=None,
|
||||||
|
deprecated=False,
|
||||||
dependencies=None,
|
dependencies=None,
|
||||||
order_dependencies=None,
|
order_dependencies=None,
|
||||||
**kwargs
|
**kwargs
|
||||||
|
@ -580,6 +621,7 @@ def init_cli():
|
||||||
super(Action, self).__init__(name, **kwargs)
|
super(Action, self).__init__(name, **kwargs)
|
||||||
|
|
||||||
self.name = self.name or self.callback.__name__
|
self.name = self.name or self.callback.__name__
|
||||||
|
self.deprecated = deprecated
|
||||||
|
|
||||||
if aliases is None:
|
if aliases is None:
|
||||||
aliases = []
|
aliases = []
|
||||||
|
@ -598,6 +640,11 @@ def init_cli():
|
||||||
# Show first line of help if short help is missing
|
# Show first line of help if short help is missing
|
||||||
self.short_help = self.short_help or self.help.split("\n")[0]
|
self.short_help = self.short_help or self.help.split("\n")[0]
|
||||||
|
|
||||||
|
if deprecated:
|
||||||
|
deprecation = DeprecationMessage(deprecated)
|
||||||
|
self.short_help = deprecation.short_help(self.short_help)
|
||||||
|
self.help = deprecation.help(self.help, type="Command", separator="\n")
|
||||||
|
|
||||||
# Add aliases to help string
|
# Add aliases to help string
|
||||||
if aliases:
|
if aliases:
|
||||||
aliases_help = "Aliases: %s." % ", ".join(aliases)
|
aliases_help = "Aliases: %s." % ", ".join(aliases)
|
||||||
|
@ -620,8 +667,21 @@ def init_cli():
|
||||||
|
|
||||||
self.callback = wrapped_callback
|
self.callback = wrapped_callback
|
||||||
|
|
||||||
|
def invoke(self, ctx):
|
||||||
|
if self.deprecated:
|
||||||
|
print("Warning: %s" % DeprecationMessage(self.deprecated).full_message('Command "%s"' % self.name))
|
||||||
|
self.deprecated = False # disable Click's built-in deprecation handling
|
||||||
|
|
||||||
|
# Print warnings for options
|
||||||
|
print_deprecation_warning(ctx)
|
||||||
|
return super(Action, self).invoke(ctx)
|
||||||
|
|
||||||
class Argument(click.Argument):
|
class Argument(click.Argument):
|
||||||
"""Positional argument"""
|
"""
|
||||||
|
Positional argument
|
||||||
|
|
||||||
|
names - alias of 'param_decls'
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
names = kwargs.pop("names")
|
names = kwargs.pop("names")
|
||||||
|
@ -662,12 +722,28 @@ def init_cli():
|
||||||
class Option(click.Option):
|
class Option(click.Option):
|
||||||
"""Option that knows whether it should be global"""
|
"""Option that knows whether it should be global"""
|
||||||
|
|
||||||
def __init__(self, scope=None, **kwargs):
|
def __init__(self, scope=None, deprecated=False, **kwargs):
|
||||||
|
"""
|
||||||
|
Keyword arguments additional to Click's Option class:
|
||||||
|
|
||||||
|
names - alias of 'param_decls'
|
||||||
|
deprecated - marks option as deprecated. May be boolean, string (with custom deprecation message)
|
||||||
|
or dict with optional keys:
|
||||||
|
since: version of deprecation
|
||||||
|
removed: version when option will be removed
|
||||||
|
custom_message: Additional text to deprecation warning
|
||||||
|
"""
|
||||||
|
|
||||||
kwargs["param_decls"] = kwargs.pop("names")
|
kwargs["param_decls"] = kwargs.pop("names")
|
||||||
super(Option, self).__init__(**kwargs)
|
super(Option, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
self.deprecated = deprecated
|
||||||
self.scope = Scope(scope)
|
self.scope = Scope(scope)
|
||||||
|
|
||||||
|
if deprecated:
|
||||||
|
deprecation = DeprecationMessage(deprecated)
|
||||||
|
self.help = deprecation.help(self.help)
|
||||||
|
|
||||||
if self.scope.is_global:
|
if self.scope.is_global:
|
||||||
self.help += " This option can be used at most once either globally, or for one subcommand."
|
self.help += " This option can be used at most once either globally, or for one subcommand."
|
||||||
|
|
||||||
|
@ -829,6 +905,7 @@ def init_cli():
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
for key in list(task.action_args):
|
for key in list(task.action_args):
|
||||||
option = next((o for o in ctx.command.params if o.name == key), None)
|
option = next((o for o in ctx.command.params if o.name == key), None)
|
||||||
|
|
||||||
if option and (option.scope.is_global or option.scope.is_shared):
|
if option and (option.scope.is_global or option.scope.is_shared):
|
||||||
local_value = task.action_args.pop(key)
|
local_value = task.action_args.pop(key)
|
||||||
global_value = global_args[key]
|
global_value = global_args[key]
|
||||||
|
@ -842,6 +919,9 @@ def init_cli():
|
||||||
if local_value != default:
|
if local_value != default:
|
||||||
global_args[key] = local_value
|
global_args[key] = local_value
|
||||||
|
|
||||||
|
# Show warnings about global arguments
|
||||||
|
print_deprecation_warning(ctx)
|
||||||
|
|
||||||
# Validate global arguments
|
# Validate global arguments
|
||||||
for action_callback in ctx.command.global_action_callbacks:
|
for action_callback in ctx.command.global_action_callbacks:
|
||||||
action_callback(ctx, global_args, tasks)
|
action_callback(ctx, global_args, tasks)
|
||||||
|
|
70
tools/test_idf_py/idf_ext.py
Normal file
70
tools/test_idf_py/idf_ext.py
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
def action_extensions(base_actions, project_path=None):
|
||||||
|
def echo(name, *args, **kwargs):
|
||||||
|
print(name, args, kwargs)
|
||||||
|
|
||||||
|
# Add global options
|
||||||
|
extensions = {
|
||||||
|
"global_options": [
|
||||||
|
{
|
||||||
|
"names": ["--test-0"],
|
||||||
|
"help": "Non-deprecated option.",
|
||||||
|
"deprecated": False
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"names": ["--test-1"],
|
||||||
|
"help": "Deprecated option 1.",
|
||||||
|
"deprecated": True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"names": ["--test-2"],
|
||||||
|
"help": "Deprecated option 2.",
|
||||||
|
"deprecated": "Please update your parameters."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"names": ["--test-3"],
|
||||||
|
"help": "Deprecated option 3.",
|
||||||
|
"deprecated": {
|
||||||
|
"custom_message": "Please update your parameters."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"names": ["--test-4"],
|
||||||
|
"help": "Deprecated option 3.",
|
||||||
|
"deprecated": {
|
||||||
|
"since": "v4.0",
|
||||||
|
"removed": "v5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"actions": {
|
||||||
|
"test-0": {
|
||||||
|
"callback":
|
||||||
|
echo,
|
||||||
|
"help":
|
||||||
|
"Non-deprecated command 0",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"names": ["--test-sub-0"],
|
||||||
|
"help": "Non-deprecated subcommand option 0",
|
||||||
|
"default": None,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"names": ["--test-sub-1"],
|
||||||
|
"help": "Deprecated subcommand option 1",
|
||||||
|
"default": None,
|
||||||
|
"deprecated": True
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"arguments": [{
|
||||||
|
"names": ["test-arg-0"],
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
"test-1": {
|
||||||
|
"callback": echo,
|
||||||
|
"help": "Deprecated command 1",
|
||||||
|
"deprecated": "Please use alternative command."
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return extensions
|
Loading…
Reference in a new issue