diff --git a/src/tools/kdb/factory.hpp b/src/tools/kdb/factory.hpp index 9e59c8b73ee..04876157e03 100644 --- a/src/tools/kdb/factory.hpp +++ b/src/tools/kdb/factory.hpp @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -84,7 +83,6 @@ class Factory Factory () : m_factory () { // TODO: to add a new command, 2.) add a line here -> and you are done - m_factory.insert (std::make_pair ("set", std::make_shared> ())); m_factory.insert (std::make_pair ("rm", std::make_shared> ())); m_factory.insert (std::make_pair ("cache", std::make_shared> ())); m_factory.insert (std::make_pair ("complete", std::make_shared> ())); diff --git a/src/tools/kdb/main.c b/src/tools/kdb/main.c index 8815a05a6c2..63d908f37a1 100644 --- a/src/tools/kdb/main.c +++ b/src/tools/kdb/main.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,7 @@ command subcommands[] = { { "ls", addLsSpec, execLs }, { "mountpoint", addMountpointSpec, execMountpoint }, { "namespace", addNamespaceSpec, execNamespace }, + { "set", addSetSpec, execSet }, }; void printWarnings (Key * errorKey) diff --git a/src/tools/kdb/set.c b/src/tools/kdb/set.c new file mode 100644 index 00000000000..641d89542b6 --- /dev/null +++ b/src/tools/kdb/set.c @@ -0,0 +1,103 @@ +/** + * @file + * + * @brief KDB set subcommand + * + * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define COMMAND_NAME "set" + +#define GET_OPTION_KEY(options, name) GET_OPT_KEY (options, COMMAND_BASE_KEY (COMMAND_NAME) "/" name) +#define GET_OPTION(options, name) GET_OPT (options, COMMAND_BASE_KEY (COMMAND_NAME) "/" name) + +void addSetSpec (KeySet * spec) +{ + ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME), KEY_META, "description", "Set the value of an individual key.", + KEY_META, "command", COMMAND_NAME, KEY_END)); + ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME) "/force", KEY_META, "description", "Force setting the value", KEY_META, + "opt", "f", KEY_META, "opt/long", "force", KEY_META, "opt/arg", "none", KEY_END)); + ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME) "/name", KEY_META, "description", "The name of the key", KEY_META, + "args", "indexed", KEY_META, "args/index", "0", KEY_END)); + + ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME) "/value", KEY_META, "description", "The value that should be set", + KEY_META, "args", "indexed", KEY_META, "args/index", "1", KEY_END)); + + ADD_BASIC_OPTIONS (spec, COMMAND_SPEC_KEY (COMMAND_NAME)) +} + +int execSet (KeySet * options, Key * errorKey) +{ + int ret = 0; + GET_BASIC_OPTIONS + + bool force = false; + tmp = GET_OPTION_KEY (options, "force"); + if (tmp != NULL) + { + elektraKeyToBoolean (GET_OPTION_KEY (options, "all"), &force); + } + + const char * name = getKeyNameFromOptions (options, GET_OPTION (options, "name"), errorKey, verbose); + if (name == NULL) return 1; + + const char * value = GET_OPTION (options, "value"); + + Key * parentKey = keyNew (name, KEY_END); + + if (keyGetNamespace (parentKey) == KEY_NS_NONE || keyGetNamespace (parentKey) == KEY_NS_CASCADING) { + ret = 1; + ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, "key does not specify a namespace"); + elektraFree ((void*) name); + keyDel (parentKey); + return ret; + } + + keySetNamespace (parentKey, KEY_NS_CASCADING); + KeySet * conf = ksNew (0, KS_END); + KDB * handle = kdbOpen (NULL, errorKey); + + if (kdbGet (handle, conf, parentKey) == -1) + { + ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "could not load '%s': %s", name, GET_ERR (parentKey)); + ret = 1; + goto cleanup; + } + + Key * key = ksLookup (conf, parentKey, KDB_O_NONE); + if (key == NULL) + { + ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "could not load '%s': %s", name, GET_ERR (parentKey)); + ret = 1; + goto cleanup; + } + keySetString (key, value); // can't fail, since neither value or key can be null + + if (kdbSet (handle, conf, parentKey) == -1) + { + ret = 1; + ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "could not set value for '%s': %s", name, GET_ERR (parentKey)); + } + + keyDel (key); + +cleanup: + if (!noNewLine) + { + printf ("\n"); + } + elektraFree ((void*) name); + keyDel (parentKey); + ksDel (conf); + kdbClose (handle, errorKey); + return ret; +} diff --git a/src/tools/kdb/set.cpp b/src/tools/kdb/set.cpp deleted file mode 100644 index b6c69259a09..00000000000 --- a/src/tools/kdb/set.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file - * - * @brief - * - * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) - */ - -#include - -#include -#include -#include - -#include - -using namespace std; -using namespace kdb; - -SetCommand::SetCommand () -{ -} - -int SetCommand::execute (Cmdline const & cl) -{ - int argc = cl.arguments.size (); - if (argc != 2) - { - throw invalid_argument ("2 arguments needed"); - } - - std::string value = cl.arguments[1]; - - KeySet conf; - Key k = cl.createKey (0); - std::string name = k.getName (); - Key parentKey = cl.getParentKey (k); - - // do not resume on any get errors - // otherwise the user might break - // the config - kdb.get (conf, parentKey); - - bool cascadingWrite = name[0] == '/'; - - Key key = conf.lookup (name); - - std::ostringstream toprint; - - if (!key && cascadingWrite) - { - cerr << "Aborting: A cascading write to a non-existent key is ambiguous." << endl; - return 2; - } - if (!key) - { - toprint << "Create a new key " << name; - key = Key (name, KEY_END); - toprint << " with string \"" << value << '"' << endl; - key.setString (value); - - if (!key.isValid ()) - { - cerr << "no valid name supplied" << endl; - return 1; - } - conf.append (key); - } - else - { - toprint << "Set string to \"" << value << '"' << endl; - key.setString (value); - } - kdb.set (conf, parentKey); - printWarnings (cerr, parentKey, cl.verbose, cl.debug); - printError (cerr, parentKey, cl.verbose, cl.debug); - - if (cascadingWrite) toprint << "Using name " << key.getName () << std::endl; - if (!cl.quiet) cout << toprint.str (); - - return 0; -} - -SetCommand::~SetCommand () -{ -} diff --git a/src/tools/kdb/set.h b/src/tools/kdb/set.h new file mode 100644 index 00000000000..92912c2b238 --- /dev/null +++ b/src/tools/kdb/set.h @@ -0,0 +1,33 @@ +/** +* @file +* +* @brief KDB set subcommand header +* +* @copyright BSD License (see LICENSE.md or https://www.libelektra.org) +*/ + +#ifndef ELEKTRA_KDB_SET_H +#define ELEKTRA_KDB_SET_H + +#include + +/** +* Adds options specification of set command to keySet +* +* @param spec the base spec where the commands spec should be added +*/ +void addSetSpec (KeySet * spec); + +/** +* Runs the set command +* +* @param options cli options and arguments as specified in addSetSpec() +* @param errorKey key where errors and warnings should be saved +* +* @retval 0 set command ran without errors +* @retval 1 errors occurred, keySetMeta (errorKey, "error/reason") for info +* +*/ +int execSet (KeySet * options, Key * errorKey); + +#endif // ELEKTRA_KDB_SET_H diff --git a/src/tools/kdb/set.hpp b/src/tools/kdb/set.hpp deleted file mode 100644 index c64a909e59d..00000000000 --- a/src/tools/kdb/set.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @file - * - * @brief - * - * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) - */ - -#ifndef SET_HPP -#define SET_HPP - -#include "coloredkdbio.hpp" -#include -#include - -class SetCommand : public Command -{ - kdb::KDB kdb; - -public: - SetCommand (); - ~SetCommand (); - - virtual std::string getShortOptions () override - { - return "qf"; - } - - virtual std::string getSynopsis () override - { - return " "; - } - - virtual std::string getShortHelpText () override - { - return "Set the value of an individual key."; - } - - virtual std::string getLongHelpText () override - { - return "To set an empty value you need to quote like \"\" (depending on shell)\n" - "To set a negative value you need to use '--' to stop option processing.\n" - "(e.g. 'kdb set -- /tests/neg -3')\n"; - } - - virtual int execute (Cmdline const & cmdline) override; -}; - -#endif