libplugin: allow commands and options to mark themselves deprecated.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2020-08-06 10:00:51 +09:30
parent 7a7a849fc2
commit fc097b8b48
4 changed files with 63 additions and 3 deletions

View File

@ -593,6 +593,7 @@ handle_getmanifest(struct command *getmanifest_cmd,
json_add_string(params, "name", p->opts[i].name); json_add_string(params, "name", p->opts[i].name);
json_add_string(params, "type", p->opts[i].type); json_add_string(params, "type", p->opts[i].type);
json_add_string(params, "description", p->opts[i].description); json_add_string(params, "description", p->opts[i].description);
json_add_bool(params, "deprecated", p->opts[i].deprecated);
json_object_end(params); json_object_end(params);
} }
json_array_end(params); json_array_end(params);
@ -607,6 +608,7 @@ handle_getmanifest(struct command *getmanifest_cmd,
if (p->commands[i].long_description) if (p->commands[i].long_description)
json_add_string(params, "long_description", json_add_string(params, "long_description",
p->commands[i].long_description); p->commands[i].long_description);
json_add_bool(params, "deprecated", p->commands[i].deprecated);
json_object_end(params); json_object_end(params);
} }
json_array_end(params); json_array_end(params);
@ -1260,6 +1262,7 @@ static struct plugin *new_plugin(const tal_t *ctx,
o.description = va_arg(ap, const char *); o.description = va_arg(ap, const char *);
o.handle = va_arg(ap, char *(*)(const char *str, void *arg)); o.handle = va_arg(ap, char *(*)(const char *str, void *arg));
o.arg = va_arg(ap, void *); o.arg = va_arg(ap, void *);
o.deprecated = va_arg(ap, int); /* bool gets promoted! */
tal_arr_expand(&p->opts, o); tal_arr_expand(&p->opts, o);
} }

View File

@ -64,6 +64,8 @@ struct plugin_command {
struct command_result *(*handle)(struct command *cmd, struct command_result *(*handle)(struct command *cmd,
const char *buf, const char *buf,
const jsmntok_t *params); const jsmntok_t *params);
/* If true, this command *disabled* if allow-deprecated-apis = false */
bool deprecated;
}; };
/* Create an array of these, one for each --option you support. */ /* Create an array of these, one for each --option you support. */
@ -73,6 +75,8 @@ struct plugin_option {
const char *description; const char *description;
char *(*handle)(const char *str, void *arg); char *(*handle)(const char *str, void *arg);
void *arg; void *arg;
/* If true, this options *disabled* if allow-deprecated-apis = false */
bool deprecated;
}; };
/* Create an array of these, one for each notification you subscribe to. */ /* Create an array of these, one for each notification you subscribe to. */
@ -229,12 +233,19 @@ struct plugin_timer *plugin_timer_(struct plugin *p,
void plugin_log(struct plugin *p, enum log_level l, const char *fmt, ...) PRINTF_FMT(3, 4); void plugin_log(struct plugin *p, enum log_level l, const char *fmt, ...) PRINTF_FMT(3, 4);
/* Macro to define arguments */ /* Macro to define arguments */
#define plugin_option(name, type, description, set, arg) \ #define plugin_option_(name, type, description, set, arg, deprecated) \
(name), \ (name), \
(type), \ (type), \
(description), \ (description), \
typesafe_cb_preargs(char *, void *, (set), (arg), const char *), \ typesafe_cb_preargs(char *, void *, (set), (arg), const char *), \
(arg) (arg), \
(deprecated)
#define plugin_option(name, type, description, set, arg) \
plugin_option_((name), (type), (description), (set), (arg), false)
#define plugin_option_deprecated(name, type, description, set, arg) \
plugin_option_((name), (type), (description), (set), (arg), true)
/* Standard helpers */ /* Standard helpers */
char *u64_option(const char *arg, u64 *i); char *u64_option(const char *arg, u64 *i);

View File

@ -106,6 +106,14 @@ static const struct plugin_command commands[] = { {
"Makes a simple getinfo call, to test rpc socket.", "Makes a simple getinfo call, to test rpc socket.",
"", "",
json_testrpc, json_testrpc,
},
{
"testrpc-deprecated",
"utils",
"Makes a simple getinfo call, to test rpc socket.",
"",
json_testrpc,
true,
} }
}; };
@ -131,5 +139,9 @@ int main(int argc, char *argv[])
"string", "string",
"Who to say hello to.", "Who to say hello to.",
charp_option, &name_option), charp_option, &name_option),
plugin_option_deprecated("name-deprecated",
"string",
"Who to say hello to.",
charp_option, &name_option),
NULL); NULL);
} }

View File

@ -967,7 +967,8 @@ def test_rpc_command_hook(node_factory):
def test_libplugin(node_factory): def test_libplugin(node_factory):
"""Sanity checks for plugins made with libplugin""" """Sanity checks for plugins made with libplugin"""
plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin") plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin")
l1 = node_factory.get_node(options={"plugin": plugin}) l1 = node_factory.get_node(options={"plugin": plugin,
'allow-deprecated-apis': False})
# Test startup # Test startup
assert l1.daemon.is_in_log("test_libplugin initialised!") assert l1.daemon.is_in_log("test_libplugin initialised!")
@ -996,6 +997,39 @@ def test_libplugin(node_factory):
# Test RPC calls FIXME: test concurrent ones ? # Test RPC calls FIXME: test concurrent ones ?
assert l1.rpc.call("testrpc") == l1.rpc.getinfo() assert l1.rpc.call("testrpc") == l1.rpc.getinfo()
# Make sure deprecated options nor commands are mentioned.
with pytest.raises(RpcError, match=r'Command "testrpc-deprecated" is deprecated'):
l1.rpc.call('testrpc-deprecated')
assert not any([h['command'] == 'testrpc-deprecated'
for h in l1.rpc.help()['help']])
with pytest.raises(RpcError, match=r"Deprecated command.*testrpc-deprecated"):
l1.rpc.help('testrpc-deprecated')
assert 'name-deprecated' not in str(l1.rpc.listconfigs())
l1.stop()
l1.daemon.opts["name-deprecated"] = "test_opt"
# This actually dies while waiting for the logs.
with pytest.raises(ValueError):
l1.start()
del l1.daemon.opts["name-deprecated"]
l1.start()
def test_libplugin_deprecated(node_factory):
"""Sanity checks for plugins made with libplugin using deprecated args"""
plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin")
l1 = node_factory.get_node(options={"plugin": plugin,
'name-deprecated': 'test_opt depr',
'allow-deprecated-apis': True})
assert l1.rpc.call("helloworld") == "hello test_opt depr"
l1.rpc.help('testrpc-deprecated')
assert l1.rpc.call("testrpc-deprecated") == l1.rpc.getinfo()
@unittest.skipIf( @unittest.skipIf(
not DEVELOPER or DEPRECATED_APIS, "needs LIGHTNINGD_DEV_LOG_IO and new API" not DEVELOPER or DEPRECATED_APIS, "needs LIGHTNINGD_DEV_LOG_IO and new API"