diff --git a/plugins/libplugin.c b/plugins/libplugin.c index e0982ab92..d0cb66607 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -593,6 +593,7 @@ handle_getmanifest(struct command *getmanifest_cmd, json_add_string(params, "name", p->opts[i].name); json_add_string(params, "type", p->opts[i].type); json_add_string(params, "description", p->opts[i].description); + json_add_bool(params, "deprecated", p->opts[i].deprecated); json_object_end(params); } json_array_end(params); @@ -607,6 +608,7 @@ handle_getmanifest(struct command *getmanifest_cmd, if (p->commands[i].long_description) json_add_string(params, "long_description", p->commands[i].long_description); + json_add_bool(params, "deprecated", p->commands[i].deprecated); json_object_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.handle = va_arg(ap, char *(*)(const char *str, void *arg)); o.arg = va_arg(ap, void *); + o.deprecated = va_arg(ap, int); /* bool gets promoted! */ tal_arr_expand(&p->opts, o); } diff --git a/plugins/libplugin.h b/plugins/libplugin.h index 87ec13e1c..cada4de4b 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -64,6 +64,8 @@ struct plugin_command { struct command_result *(*handle)(struct command *cmd, const char *buf, 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. */ @@ -73,6 +75,8 @@ struct plugin_option { const char *description; char *(*handle)(const char *str, 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. */ @@ -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); /* Macro to define arguments */ -#define plugin_option(name, type, description, set, arg) \ +#define plugin_option_(name, type, description, set, arg, deprecated) \ (name), \ (type), \ (description), \ 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 */ char *u64_option(const char *arg, u64 *i); diff --git a/tests/plugins/test_libplugin.c b/tests/plugins/test_libplugin.c index 66dcb7c18..51a32d3d7 100644 --- a/tests/plugins/test_libplugin.c +++ b/tests/plugins/test_libplugin.c @@ -106,6 +106,14 @@ static const struct plugin_command commands[] = { { "Makes a simple getinfo call, to test rpc socket.", "", 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", "Who to say hello to.", charp_option, &name_option), + plugin_option_deprecated("name-deprecated", + "string", + "Who to say hello to.", + charp_option, &name_option), NULL); } diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 5415f6671..e9c49f678 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -967,7 +967,8 @@ def test_rpc_command_hook(node_factory): def test_libplugin(node_factory): """Sanity checks for plugins made with 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 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 ? 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( not DEVELOPER or DEPRECATED_APIS, "needs LIGHTNINGD_DEV_LOG_IO and new API"