From ca3616142d99f7afc8d0a4f05118ddfb2037513b Mon Sep 17 00:00:00 2001 From: Hannes Laimer Date: Thu, 2 Mar 2023 17:12:26 +0100 Subject: [PATCH] kdb-cli: rewrite rm ... and fix #3742 --- src/tools/kdb/factory.hpp | 2 - src/tools/kdb/main.c | 2 + src/tools/kdb/rm.c | 115 ++++++++++++++++++++++++++++++++++++++ src/tools/kdb/rm.cpp | 79 -------------------------- src/tools/kdb/rm.h | 36 ++++++++++++ src/tools/kdb/rm.hpp | 47 ---------------- 6 files changed, 153 insertions(+), 128 deletions(-) create mode 100644 src/tools/kdb/rm.c delete mode 100644 src/tools/kdb/rm.cpp create mode 100644 src/tools/kdb/rm.h delete mode 100644 src/tools/kdb/rm.hpp diff --git a/src/tools/kdb/factory.hpp b/src/tools/kdb/factory.hpp index 6830446df51..31d2b107285 100644 --- a/src/tools/kdb/factory.hpp +++ b/src/tools/kdb/factory.hpp @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -77,7 +76,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 ("rm", std::make_shared> ())); m_factory.insert (std::make_pair ("cache", std::make_shared> ())); m_factory.insert (std::make_pair ("complete", std::make_shared> ())); m_factory.insert (std::make_pair ("cp", std::make_shared> ())); diff --git a/src/tools/kdb/main.c b/src/tools/kdb/main.c index 3801b31eb7f..30e0109fa5f 100644 --- a/src/tools/kdb/main.c +++ b/src/tools/kdb/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ command subcommands[] = { { "mountpoint", addMountpointSpec, execMountpoint }, { "mv", addMvSpec, execMv }, { "namespace", addNamespaceSpec, execNamespace }, + { "rm", addRmSpec, execRm }, { "set", addSetSpec, execSet }, }; diff --git a/src/tools/kdb/rm.c b/src/tools/kdb/rm.c new file mode 100644 index 00000000000..b59b7c86a20 --- /dev/null +++ b/src/tools/kdb/rm.c @@ -0,0 +1,115 @@ +/** + * @file + * + * @brief Implementation of kdb rm command + * + * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define COMMAND_NAME "rm" + +#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 addRmSpec (KeySet * spec) +{ + ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME), KEY_META, "description", "Remove a key.", KEY_META, "command", + COMMAND_NAME, KEY_END)); + ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME) "/recursive", KEY_META, "description", "Work in recursive mode.", + KEY_META, "opt", "r", KEY_META, "opt/long", "recursive", KEY_META, "opt/arg", "none", KEY_END)); + ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME) "/name", KEY_META, "description", "The key name", KEY_META, "args", + "indexed", KEY_META, "args/index", "0", KEY_END)); + + ADD_BASIC_OPTIONS (spec, COMMAND_SPEC_KEY (COMMAND_NAME)) +} + +int execRm (KeySet * options, Key * errorKey) +{ + int ret = 0; + GET_BASIC_OPTIONS + + bool recursive = false; + tmp = GET_OPTION_KEY (options, "recursive"); + if (tmp != NULL) + { + elektraKeyToBoolean (GET_OPTION_KEY (options, "recursive"), &recursive); + } + + const char * name = getKeyNameFromOptions (options, GET_OPTION (options, "name"), errorKey, verbose); + if (name == NULL) return 1; + + Key * key = keyNew (name, KEY_END); + + if (keyGetNamespace (key) == KEY_NS_NONE || keyGetNamespace (key) == KEY_NS_CASCADING) + { + ret = 1; + ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, "source key does not specify a namespace"); + elektraFree ((void *) name); + keyDel (key); + return ret; + } + + Key * root = keyNew ("/", KEY_END); + + KeySet * conf = ksNew (0, KS_END); + KDB * handle = kdbOpen (NULL, errorKey); + if (kdbGet (handle, conf, root) == -1) + { + ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "could not load '%s': %s", name, GET_ERR (root)); + ret = 1; + goto cleanup; + } + + Key * cur = NULL; + + size_t keyNameLen = elektraStrLen (keyName (key)); + + long count = 0; + KeySet * newConf = ksNew (ksGetSize (conf), KS_END); + for (elektraCursor it = 0; it < ksGetSize (conf); ++it) + { + cur = ksAtCursor (conf, it); + + bool startsWithSrc = !elektraStrNCmp (keyName (cur), keyName (key), keyNameLen - 1); + bool equalsSrc = !elektraStrCmp (keyName (cur), keyName (key)); + + // starts-with if recursive, or equals if !recursive + if ((recursive && startsWithSrc) || equalsSrc) + { + count++; + CLI_PRINT (CLI_LOG_VERBOSE, "removing '%s\n", BOLD(keyName (cur))); + continue; + } + ksAppendKey (newConf, cur); + } + + if (kdbSet (handle, newConf, root) == -1) + { + ret = 1; + ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "could not save keyset after moving: %s", GET_ERR (root)); + } + CLI_PRINT (CLI_LOG_VERBOSE, "\nremoved %ld keys", count); + + +cleanup: + if (!noNewLine) + { + printf ("\n"); + } + elektraFree ((void *) name); + keyDel (root); + elektraFree ((void *) fmtBuffer); + ksDel (conf); + kdbClose (handle, errorKey); + return ret; +} diff --git a/src/tools/kdb/rm.cpp b/src/tools/kdb/rm.cpp deleted file mode 100644 index 7f18c04e9c8..00000000000 --- a/src/tools/kdb/rm.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file - * - * @brief - * - * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) - */ - -#include - -#include -#include - -#include - -using namespace std; -using namespace kdb; - -RemoveCommand::RemoveCommand () -{ -} - -static int noKeyFound (bool verbose, bool force, std::string article) -{ - if (verbose || !force) - { - cerr << "Did not find " << article << " key" << endl; - } - return force ? 0 : 11; -} - -int RemoveCommand::execute (Cmdline const & cl) -{ - if (cl.arguments.size () != 1) throw invalid_argument ("1 argument required"); - - KeySet conf; - Key x = cl.createKey (0); - Key parentKey = cl.getParentKey (x); - - kdb.get (conf, parentKey); - - KeySet savedKeys; - - if (cl.withoutElektra) - { - Key systemElektra ("system:/elektra", KEY_END); - savedKeys = conf.cut (systemElektra); - } - - if (!cl.recursive) - { - Key f = conf.lookup (x, KDB_O_POP); - - if (!f) - { - return noKeyFound (cl.verbose, cl.force, "the"); - } - } - else - { - // do recursive removing - KeySet ks = conf.cut (x); - - if (ks.size () == 0) - { - return noKeyFound (cl.verbose, cl.force, "any"); - } - } - - conf.append (savedKeys); - - kdb.set (conf, parentKey); - - return 0; -} - -RemoveCommand::~RemoveCommand () -{ -} diff --git a/src/tools/kdb/rm.h b/src/tools/kdb/rm.h new file mode 100644 index 00000000000..a3bcb258a2b --- /dev/null +++ b/src/tools/kdb/rm.h @@ -0,0 +1,36 @@ +/** +* @file +* +* @brief Header for rm command +* +* @copyright BSD License (see LICENSE.md or https://www.libelektra.org) + */ + +#ifndef ELEKTRA_KDB_RM_H +#define ELEKTRA_KDB_RM_H + +#include + +/** +* Adds options specification of rm command to @spec +* +* @param spec the base spec where the commands spec should be added + */ +void addRmSpec (KeySet * spec); + +/** +* Executes the rm command +* +* @param options cli options and arguments as specified in addRmSpec() +* @param errorKey key where errors and warnings should be saved +* +* @retval 0 rm command ran without errors +* @retval 1 errors occurred, keyGetMeta (errorKey, "error/reason") for info +* + */ +int execRm (KeySet * options, Key * errorKey); + +// helper functions +int getKeyNameDepth (const char * name); + +#endif // ELEKTRA_KDB_RM_H diff --git a/src/tools/kdb/rm.hpp b/src/tools/kdb/rm.hpp deleted file mode 100644 index 97483c3e4a2..00000000000 --- a/src/tools/kdb/rm.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @file - * - * @brief - * - * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) - */ - -#ifndef REMOVE_HPP -#define REMOVE_HPP - -#include - -#include - -class RemoveCommand : public Command -{ - kdb::KDB kdb; - -public: - RemoveCommand (); - ~RemoveCommand (); - - virtual std::string getShortOptions () override - { - return "rfE"; - } - - virtual std::string getSynopsis () override - { - return ""; - } - - virtual std::string getShortHelpText () override - { - return "Remove key(s) from key database."; - } - - virtual std::string getLongHelpText () override - { - return ""; - } - - virtual int execute (Cmdline const & cmdline) override; -}; - -#endif