diff --git a/src/tools/kdb/factory.hpp b/src/tools/kdb/factory.hpp index 7109d6a9041..6830446df51 100644 --- a/src/tools/kdb/factory.hpp +++ b/src/tools/kdb/factory.hpp @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -82,7 +81,6 @@ class Factory 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> ())); - m_factory.insert (std::make_pair ("mv", std::make_shared> ())); m_factory.insert (std::make_pair ("mount", std::make_shared> ())); m_factory.insert (std::make_pair ("remount", std::make_shared> ())); m_factory.insert (std::make_pair ("shell", std::make_shared> ())); diff --git a/src/tools/kdb/main.c b/src/tools/kdb/main.c index e2b77113c47..3801b31eb7f 100644 --- a/src/tools/kdb/main.c +++ b/src/tools/kdb/main.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,7 @@ command subcommands[] = { { "ls", addLsSpec, execLs }, { "meta", addMetaSpec, execMeta }, { "mountpoint", addMountpointSpec, execMountpoint }, + { "mv", addMvSpec, execMv }, { "namespace", addNamespaceSpec, execNamespace }, { "set", addSetSpec, execSet }, }; diff --git a/src/tools/kdb/mv.c b/src/tools/kdb/mv.c new file mode 100644 index 00000000000..b3ae8448e70 --- /dev/null +++ b/src/tools/kdb/mv.c @@ -0,0 +1,162 @@ +/** + * @file + * + * @brief Implementation of kdb mv command + * + * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define COMMAND_NAME "mv" + +#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 addMvSpec (KeySet * spec) +{ + ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME), KEY_META, "description", + "Move a configuration within the key database.", 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) "/source", KEY_META, "description", "The source key", KEY_META, "args", + "indexed", KEY_META, "args/index", "0", KEY_END)); + ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME) "/destination", KEY_META, "description", "The destination key", KEY_META, + "args", "indexed", KEY_META, "args/index", "1", KEY_END)); + + ADD_BASIC_OPTIONS (spec, COMMAND_SPEC_KEY (COMMAND_NAME)) +} + +int execMv (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 * sourceName = getKeyNameFromOptions (options, GET_OPTION (options, "source"), errorKey, verbose); + if (sourceName == NULL) return 1; + + const char * destName = getKeyNameFromOptions (options, GET_OPTION (options, "destination"), errorKey, verbose); + if (destName == NULL) + { + elektraFree ((void *) sourceName); + return 1; + } + + CLI_PRINT (CLI_LOG_DEBUG, "%s", "create keys... "); + + Key * sourceKey = keyNew (sourceName, KEY_END); + Key * destKey = keyNew (destName, KEY_END); + + if (keyGetNamespace (sourceKey) == KEY_NS_NONE || keyGetNamespace (sourceKey) == KEY_NS_CASCADING) { + ret = 1; + ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, "source key does not specify a namespace"); + elektraFree ((void*) sourceName); + elektraFree ((void*) destName); + keyDel (sourceKey); + keyDel (destKey); + return ret; + } + if (keyGetNamespace (destKey) == KEY_NS_NONE || keyGetNamespace (destKey) == KEY_NS_CASCADING) { + ret = 1; + ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, "destination key does not specify a namespace"); + elektraFree ((void*) sourceName); + elektraFree ((void*) destName); + keyDel (sourceKey); + keyDel (destKey); + return ret; + } + + CLI_PRINT (CLI_LOG_DEBUG, "%s", "ok\n"); + + 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", sourceName, GET_ERR (root)); + ret = 1; + goto cleanup; + } + + Key * cur = NULL; + + + size_t sourceNameLen = elektraStrLen (keyName (sourceKey)); + size_t destNameLen = elektraStrLen (keyName (destKey)); + + CLI_PRINT (CLI_LOG_DEBUG, "source: %s [%ld]\n", keyName (sourceKey), sourceNameLen); + CLI_PRINT (CLI_LOG_DEBUG, "dest: %s [%ld]\n", keyName (destKey), destNameLen); + CLI_PRINT (CLI_LOG_DEBUG, "recursive: %d\n", recursive); + + 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 (sourceKey), sourceNameLen - 1); + bool equalsSrc = !elektraStrCmp (keyName (cur), keyName (sourceKey)); + CLI_PRINT (CLI_LOG_DEBUG, "checking if '%s' has to be moved\n", BOLD (keyName (cur))); + CLI_PRINT (CLI_LOG_DEBUG, " starts-with: %d; ", startsWithSrc); + CLI_PRINT (CLI_LOG_DEBUG, " equals: %d\n", equalsSrc); + + // starts-with if recursive, or equals if !recursive + if ((recursive && startsWithSrc) || equalsSrc) + { + size_t newNameLen = destNameLen + (equalsSrc ? 0 : 1 + elektraStrLen (keyName (cur)) - sourceNameLen); + char * newName = elektraMalloc (newNameLen); + strcpy (newName, keyName (destKey)); + if (!equalsSrc) + { + strcat (newName, "/"); + strcat (newName, &keyName (cur)[sourceNameLen]); + } + CLI_PRINT (CLI_LOG_VERBOSE, "-> moving '%s' to '%s'\n", BOLD(keyName (cur)), BOLD(newName)); + Key * tmpKey = keyDup (cur, KEY_CP_ALL); + keySetName (tmpKey, newName); + ksAppendKey (newConf, tmpKey); + elektraFree (newName); + count++; + } + else + { + 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, "\nmoved %ld keys", count); + + +cleanup: + if (!noNewLine) + { + printf ("\n"); + } + elektraFree ((void *) sourceName); + keyDel (root); + elektraFree ((void *) fmtBuffer); + ksDel (conf); + kdbClose (handle, errorKey); + return ret; +} diff --git a/src/tools/kdb/mv.cpp b/src/tools/kdb/mv.cpp deleted file mode 100644 index 331e153af3b..00000000000 --- a/src/tools/kdb/mv.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file - * - * @brief - * - * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) - */ - -#include - -#include -#include -#include -#include - -#include - -#include - -using namespace std; -using namespace kdb; - -MvCommand::MvCommand () -{ -} - -int MvCommand::execute (Cmdline const & cl) -{ - if (cl.arguments.size () != 2) - { - throw invalid_argument ("wrong number of arguments, 2 needed"); - } - - KeySet conf; - Key sourceKey = cl.createKey (0, false); - - Key destKey = cl.createKey (1, false); - string newDirName = destKey.getName (); - - Key root = tools::helper::commonKeyName (sourceKey, destKey); - if (cl.verbose) std::cout << "using common basename: " << root.getName () << std::endl; - kdb.get (conf, root); - KeySet tmpConf = conf; - KeySet oldConf; - - oldConf.append (tmpConf.cut (sourceKey)); - std::string sourceName = sourceKey.getName (); - - if (!oldConf.size ()) - { - std::cerr << "No key to copy found below '" << sourceName << "'" << std::endl; - return 11; - } - - KeySet newConf; - - if (cl.recursive) - { - for (Key k : oldConf) - { - newConf.append (rename_key (k, sourceName, newDirName, cl.verbose)); - } - } - else - { - // just rename one key - Key k = oldConf.at (0); - if (k != sourceKey) - { - cerr << "First key found " << k.getName () << " does not exactly match given key " << sourceKey.getName () - << ", aborting (use -r to move hierarchy)\n"; - return 11; - } - newConf.append (rename_key (k, sourceName, newDirName, cl.verbose)); - } - newConf.append (tmpConf); // these are unrelated keys - // drop the original configuration - - if (cl.verbose) - { - cout << "Will write out:" << endl; - cout << newConf; - } - - kdb.set (newConf, root); - printWarnings (cerr, root, cl.verbose, cl.debug); - - return 0; -} - -MvCommand::~MvCommand () -{ -} diff --git a/src/tools/kdb/mv.h b/src/tools/kdb/mv.h new file mode 100644 index 00000000000..3941ce5050f --- /dev/null +++ b/src/tools/kdb/mv.h @@ -0,0 +1,36 @@ +/** +* @file +* +* @brief Header for mv command +* +* @copyright BSD License (see LICENSE.md or https://www.libelektra.org) +*/ + +#ifndef ELEKTRA_KDB_MV_H +#define ELEKTRA_KDB_MV_H + +#include + +/** +* Adds options specification of mv command to @spec +* +* @param spec the base spec where the commands spec should be added +*/ +void addMvSpec (KeySet * spec); + +/** +* Executes the mv command +* +* @param options cli options and arguments as specified in addMvSpec() +* @param errorKey key where errors and warnings should be saved +* +* @retval 0 mv command ran without errors +* @retval 1 errors occurred, keyGetMeta (errorKey, "error/reason") for info +* +*/ +int execMv (KeySet * options, Key * errorKey); + +// helper functions +int getKeyNameDepth (const char * name); + +#endif // ELEKTRA_KDB_MV_H diff --git a/src/tools/kdb/mv.hpp b/src/tools/kdb/mv.hpp deleted file mode 100644 index 9ae2310a702..00000000000 --- a/src/tools/kdb/mv.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @file - * - * @brief - * - * @copyright BSD License (see LICENSE.md or https://www.libelektra.org) - */ - -#ifndef MV_HPP -#define MV_HPP - -#include "coloredkdbio.hpp" -#include -#include - -class MvCommand : public Command -{ - kdb::KDB kdb; - -public: - MvCommand (); - ~MvCommand (); - - virtual std::string getShortOptions () override - { - return "r"; - } - - virtual std::string getSynopsis () override - { - return " "; - } - - virtual std::string getShortHelpText () override - { - return "Move configuration within the key database."; - } - - virtual std::string getLongHelpText () override - { - return ""; - } - - virtual int execute (Cmdline const & cmdline) override; -}; - -#endif