SpecBackendBuilder SpecMountpointReader::readMountpointSpecification (KeySet const & cks) { ks = cks; mp = ks.head ().dup (); Key rmp (mp.dup ()); helper::removeNamespace (rmp); bb.setMountpoint (rmp, mountConf); processKey (mp); bb.nodes++; // count mp ks.lookup (mp, KDB_O_POP); ks.rewind (); // we need old fashioned loop, because it can handle ks.cut during iteration for (Key k = ks.next (); k; k = ks.next ()) { // search for mountpoint Key m = k.getMeta<const Key> ("mountpoint"); if (m) { SpecMountpointReader smr (backends, bbi); backends[k] = smr.readMountpointSpecification (ks.cut (k)); continue; } processKey (k); bb.nodes++; } bb.setBackendConfig (backendConfig); bb.useConfigFile (mp.getMeta<std::string> ("mountpoint")); return bb; }
void SpecReader::readSpecification (KeySet const & cks) { KeySet ks; Key mp; // only accept keys in 'spec' namespace for (Key k : cks) { if (k.isSpec ()) { ks.append (k); } } ks.rewind (); // we need old fashioned loop, because it can handle ks.cut during iteration for (Key k = ks.next (); k; k = ks.next ()) { // search for mountpoint Key m = k.getMeta<const Key> ("mountpoint"); if (m) { SpecMountpointReader smr (backends, bbi); backends[k] = smr.readMountpointSpecification (ks.cut (k)); } } }
int CpCommand::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); if (!sourceKey.isValid ()) { throw invalid_argument ("Source given is not a valid keyname"); } Key destKey = cl.createKey (1); if (!destKey.isValid ()) { throw invalid_argument ("Destination given is not a valid keyname"); } string newDirName = destKey.getName (); kdb.get (conf, sourceKey); kdb.get (conf, destKey); KeySet tmpConf = conf; KeySet oldConf; oldConf.append (tmpConf.cut (sourceKey)); KeySet newConf; oldConf.rewind (); std::string sourceName = sourceKey.getName (); if (cl.verbose) cout << "common name: " << sourceName << endl; if (cl.recursive) { // copy all keys with new name Key k; while ((k = oldConf.next ())) { Key rk = rename_key (k, sourceName, newDirName, cl.verbose); copySingleKey (cl, rk, tmpConf, newConf); } } else { // just copy one key Key k = oldConf.next (); Key rk = rename_key (k, sourceName, newDirName, cl.verbose); copySingleKey (cl, rk, tmpConf, newConf); } newConf.append (tmpConf); // these are unrelated keys newConf.append (oldConf); // these are the original keys newConf.rewind (); kdb.set (newConf, destKey); return 0; }
std::vector<PluginSpec> PluginVariantDatabase::getPluginVariantsFromSysconf (PluginSpec const & whichplugin, KeySet const & sysconf, KeySet const & genconfToIgnore) const { std::vector<PluginSpec> result; KeySet ksSysconf (sysconf); // first find possible variants Key kVariantBase ("system/elektra/plugins", KEY_END); kVariantBase.addBaseName (whichplugin.getName ()); kVariantBase.addBaseName ("variants"); KeySet ksPluginVariantSysconf (ksSysconf.cut (kVariantBase)); KeySet ksToIterate (ksPluginVariantSysconf); for (auto kCurrent : ksToIterate) { Key kCurrentTest (kVariantBase); kCurrentTest.addBaseName (kCurrent.getBaseName ()); if (kCurrentTest == kCurrent) { PluginSpec variant (whichplugin); KeySet ksVariantConfToAdd; // new base for plugin conf Key kVariantPluginConf ("system/", KEY_END); // add system conf for plugin variant Key kVariantSysconf (this->buildVariantSysconfKey (whichplugin, kCurrent.getBaseName (), "config")); this->addKeysBelowKeyToConf (kVariantSysconf, ksPluginVariantSysconf, kVariantPluginConf, ksVariantConfToAdd); // check if the variant was disabled : system/elektra/plugins/simpleini/variants/space/disable Key kDisable = sysconf.lookup (this->buildVariantSysconfKey (whichplugin, kCurrent.getBaseName (), "disable")); if (kDisable && kDisable.getString () == "1") { continue; // skip this variant } // check if the variant is in the genconfToIgnore list Key kGenconfVariant (kVariantPluginConf); kGenconfVariant.addBaseName (kCurrent.getBaseName ()); Key kIgnore = genconfToIgnore.lookup (kGenconfVariant); if (kIgnore) { continue; // this variant was added by genconf already } if (ksVariantConfToAdd.size () == 0) { continue; // no config means no variant } variant.appendConfig (ksVariantConfToAdd); result.push_back (variant); } } return result; }
void PluginVariantDatabase::addKeysBelowKeyToConf (Key const & below, KeySet const & conf, Key const & newbase, KeySet & targetconf) const { KeySet confCp (conf); KeySet ksVariantSysConf = confCp.cut (below); for (auto kVariantCurrent : ksVariantSysConf) { if (!kVariantCurrent.isBelow (below)) continue; targetconf.append (helper::rebaseKey (kVariantCurrent, below, newbase)); } }
/** * @brief Allows for updating of a database entry. * * Will renew the entry and all its subkeys (configuration). * * @param entry A custom Entry object holding current information. * @return true if the entry was updated, false if not * @throw kdbrest::exception::EntryNotFoundException in case the entry * to update does not exist. */ bool StorageEngine::updateEntry (model::Entry & entry) { using namespace kdb; // register exclusive access boost::unique_lock<boost::shared_mutex> lock (m_mutex_entryCache); bool found = false; std::vector<model::Entry> & entries = this->m_entryCache; unsigned int i = 0; while (i < entries.size ()) { if (entries[i].getName ().compare (entry.getName ()) == 0) { found = true; break; } i++; } if (!found) { throw exception::EntryNotFoundException (); } KDB kdb; KeySet ks; kdb.get (ks, entry.getName ()); Key k = ks.lookup (entry.getName ()); if (!k) { throw kdbrest::exception::EntryNotFoundException (); } ks.cut (entry); ks.append (entry); ks.append (entry.getSubkeys ()); if (kdb.set (ks, entry.getName ()) >= 1) { entries.erase (entries.begin () + i); entries.push_back (entry); return true; } else { return false; } }
/** * @brief Unmount a backend by given mountPath * * @param mountPath the given mountpoint * * Uses findBackend() to locate the backend. * * @retval true if something was done * @retval false if nothing was done (but also no error) */ bool Backends::umount (std::string const & mountPath, KeySet & mountConf) { BackendInfo bi = Backends::findBackend (mountPath, mountConf); if (!bi.name.empty ()) { Key x (Backends::mountpointsPath, KEY_END); ; x.addBaseName (bi.name); mountConf.cut (x); return true; } return false; }
/** * @brief Allows for deleting of an user entry. * * Will delete the entry iteself as well as all subkeys (additional user information). * * @param user A custom User object that should be deleted. * @return true if the user was deleted successfully, false otherwise * @throw kdbrest::exception::UserNotFoundException in case the user * to delete does not exist. */ bool StorageEngine::deleteUser (model::User & user) { using namespace kdb; // register exclusive access boost::unique_lock<boost::shared_mutex> lock (m_mutex_userCache); bool found = false; std::vector<model::User> & users = this->m_userCache; unsigned int i = 0; while (i < users.size ()) { if (users[i].getName ().compare (user.getName ()) == 0) { found = true; break; } i++; } if (!found) { throw exception::UserNotFoundException (); } KDB kdb; KeySet ks; kdb.get (ks, user.getName ()); Key k = ks.lookup (user.getName ()); if (!k) { throw kdbrest::exception::UserNotFoundException (); } ks.cut (user); if (kdb.set (ks, user.getName ()) >= 1) { users.erase (users.begin () + i); return true; } else { return false; } }
void test_kdbGetSet() { cout << "testing kdbSet() and kdbGet()" << endl; { KeySet ks_set (5, *Key ("user/tests/key3", KEY_DIR, KEY_END), *Key ("user/tests/key3/1", KEY_END), *Key ("user/tests/key3/2", KEY_END), *Key ("user/tests/key3/3", KEY_VALUE, "value", KEY_END), KS_END); KeySet ks; KDB kdb; kdb.get (ks, "user/tests/key3"); ks.append(ks_set); kdb.set (ks, "user/tests/key3"); } // check if they were written { KDB kdb; KeySet ks; kdb.get (ks, "user/tests/key3"); exit_if_fail(ks.lookup("user/tests/key3/3"), "could not find previously written key"); succeed_if(ks.lookup("user/tests/key3/3").get<std::string>() == "value", "could not get value"); succeed_if(!ks.lookup("user/tests/key3/3").needSync(), "should not need sync"); } // now remove keys (cleanup) { KeySet ks; KDB kdb; kdb.get (ks, "user/tests/key3"); ks.cut(Key("user/tests/key3", KEY_END)); kdb.set (ks, "user/tests/key3"); } // check if its gone now { KDB kdb; KeySet ks; kdb.get (ks, "user/tests/key3"); succeed_if(!ks.lookup("user/tests/key3/3"), "key was not removed"); } }
void SpecReader::readSpecification (KeySet const & cks) { KeySet ks (cks); Key mp; ks.rewind (); // we need old fashioned loop, because it can handle ks.cut during iteration for (Key k = ks.next (); k; k = ks.next ()) { // search for mountpoint Key m = k.getMeta<const Key> ("mountpoint"); if (m) { SpecMountpointReader smr (backends, bbi); backends[k] = smr.readMountpointSpecification (ks.cut (k)); } } }
void TreeViewModel::importConfiguration(const QString& name, const QString& format, QString& file, const QVariantList &mergeStrategies) { Key root(name.toStdString(), KEY_END); KeySet originalKeys = collectCurrentKeySet(); KeySet base = originalKeys.cut(root); printWarnings (cerr, root); KeySet importedKeys; string formatString = format.toStdString(); string fileString = file.remove("file://").toStdString(); Modules modules; PluginPtr plugin = modules.load(formatString); Key errorKey (root); errorKey.setString (fileString); plugin->get(importedKeys, errorKey); stringstream ws; stringstream es; QString warnings; QString errors; printWarnings(ws, errorKey); warnings = QString::fromStdString(ws.str()); printError(es, errorKey); errors = QString::fromStdString(es.str()); if(!errors.isEmpty()) { emit showMessage(tr("Error"), tr("Failed to import configuration from %1 to %2.").arg(file, QString::fromStdString(root.getName())), errors); return; } ThreeWayMerge merger; foreach(QVariant s, mergeStrategies) { MergeConflictStrategy* strategy = getMergeStrategy(s.toString()); if(strategy) merger.addConflictStrategy(strategy); }
int ExportCommand::execute (Cmdline const & cl) { size_t argc = cl.arguments.size (); if (argc != 1 && argc != 2 && argc != 3) { throw invalid_argument ("need 1 to 3 arguments"); } Key root = cl.createKey (0); kdb.get (ks, root); printWarnings (cerr, root); KeySet part (ks.cut (root)); if (cl.withoutElektra) { Key systemElektra ("system/elektra", KEY_END); part.cut (systemElektra); } string format = cl.format; if (argc > 1) format = cl.arguments[1]; #ifdef _WIN32 string file = "CON"; #else string file = "/dev/stdout"; #endif if (argc > 2 && cl.arguments[2] != "-") file = cl.arguments[2]; Modules modules; PluginPtr plugin = modules.load (format, cl.getPluginsConfig ()); Key errorKey (root); errorKey.setString (file); plugin->set (part, errorKey); printWarnings (cerr, errorKey); printError (cerr, errorKey); return 0; }
kdb::KeySet Plugin::getNeededConfig() { Key neededConfigKey ("system/elektra/modules", KEY_END); neededConfigKey.addName(pluginName); neededConfigKey.addName("config/needs"); KeySet d (info.dup()); KeySet config = d.cut(neededConfigKey); KeySet ret; Key oldParent = neededConfigKey; Key newParent("system", KEY_END); for (KeySet::iterator i = config.begin(); i != config.end(); ++i) { Key k(i->dup()); ret.append(kdb::tools::helper::rebaseKey(k, oldParent, newParent)); } return ret; }
int EditorCommand::execute(Cmdline const& cl) { #ifdef _WIN32 throw EditorNotAvailable(); #endif int argc = cl.arguments.size (); if (argc < 1) { throw invalid_argument ("wrong number of arguments, 1 needed"); } Key root = cl.createKey(0); KeySet ours; KDB kdb; kdb.get (ours, root); KeySet oursToEdit = ours.cut (root); // export it to file string format = cl.format; if (argc > 1) format = cl.arguments[1]; Modules modules; PluginPtr plugin = modules.load(format); tmpFile(); if (cl.verbose) std::cout << "filename set to " << filename << std::endl; Key errorKey(root); errorKey.setString(filename); if (plugin->set(oursToEdit, errorKey) == -1) { printWarnings(cerr, errorKey); printError(cerr, errorKey); return 11; } printWarnings(cerr, errorKey); // start editor if (cl.verbose) std::cout << "running editor with " << filename << std::endl; if (!cl.editor.empty()) { if (!runEditor (cl.editor, filename)) { std::cerr << "Could not run editor " << cl.editor << std::endl; return 12; } } else { if (!runAllEditors(filename)) { std::cerr << "Could not run any editor, please change /sw/elektra/kdb/#0/current/editor" << std::endl; return 12; } } // import from the file KeySet importedKeys; plugin->get(importedKeys, errorKey); importedKeys = importedKeys.cut(root); printWarnings (cerr, errorKey); printError (cerr, errorKey); ThreeWayMerge merger; MergeHelper helper; helper.configureMerger (cl, merger); MergeResult result = merger.mergeKeySet ( MergeTask (BaseMergeKeys (oursToEdit, root), OurMergeKeys (oursToEdit, root), TheirMergeKeys (importedKeys, root), root)); helper.reportResult (cl, result, cout, cerr); int ret = 13; if (!result.hasConflicts ()) { if (cl.verbose) { cout << "The merged keyset with strategy " << cl.strategy << " is:" << endl; cout << result.getMergedKeys(); } KeySet resultKeys = result.getMergedKeys(); if (cl.verbose) std::cout << "about to write result keys " << resultKeys << std::endl; ours.append(resultKeys); kdb.set (ours, root); if (cl.verbose) std::cout << "successful, cleaning up " << filename << std::endl; unlink(filename.c_str()); ret = 0; } else { std::cout << "Import not successful, please import and remove \"" << filename << '"' << std::endl; } return ret; }
int ImportCommand::execute (Cmdline const & cl) { size_t argc = cl.arguments.size (); if (argc != 1 && argc != 2 && argc != 3) { throw invalid_argument ("need 1 to 3 arguments"); } Key root = cl.createKey (0); if (!root.isValid ()) { throw invalid_argument ("root key \"" + cl.arguments[0] + "\" is not a valid key name"); } KeySet originalKeys; kdb.get (originalKeys, root); KeySet base = originalKeys.cut (root); printWarnings (cerr, root); string format = cl.format; if (argc > 1) format = cl.arguments[1]; string file = "/dev/stdin"; if (argc > 2 && cl.arguments[2] != "-") file = cl.arguments[2]; Modules modules; PluginPtr plugin = modules.load (format, cl.getPluginsConfig ()); Key errorKey (root); errorKey.setString (file); KeySet importedKeys; plugin->get (importedKeys, errorKey); importedKeys = importedKeys.cut (root); printWarnings (cerr, errorKey); printError (cerr, errorKey); ThreeWayMerge merger; MergeHelper helper; helper.configureMerger (cl, merger); MergeResult result = merger.mergeKeySet ( MergeTask (BaseMergeKeys (base, root), OurMergeKeys (base, root), TheirMergeKeys (importedKeys, root), root)); helper.reportResult (cl, result, cout, cerr); int ret = -1; if (!result.hasConflicts ()) { if (cl.verbose) { cout << "The merged keyset with strategy " << cl.strategy << " is:" << endl; cout << result.getMergedKeys (); } KeySet resultKeys = result.getMergedKeys (); originalKeys.append (resultKeys); kdb.set (originalKeys, root); ret = 0; } return ret; }
int main() { KeySet ours; KeySet theirs; KeySet base; // the root of the subtree containing our keys (i.e. our side of the merge) Key oursRoot ("user/ours", KEY_END); // the root of the subtree containing their keys (i.e. their side of the merge) Key theirsRoot ("user/theirs", KEY_END); // the root of the subtree containing the base keys (i.e. the common ancestor of the merge) Key baseRoot ("user/base", KEY_END); // the root of the subtree that will contain the merge result Key resultRoot ("user/result", KEY_END); // Step 1: retrieve clean KeySets containing only those // keys that should be merged. This is a bit trickier than // it seems at first. Have a look at the documentation of kdbGet // for detailed information // things to note: // * use blocks with local KDB instances so we don't have to worry about // writing the keys back // * remove the root key itself from the result KeySet because it usually // contains the mounted filename and cannot be merged anyway // Also have a look at the documentation of kdbSet() // (http://doc.libelektra.org/api/latest/html/group__kdb.html#ga11436b058408f83d303ca5e996832bcf). // The merging framework can also be used to resolve conflicts resulting from // concurrent calls to kdbSet() as described in the example of kdbSet(). { KDB lkdb; lkdb.get (ours, oursRoot); ours = ours.cut (oursRoot); ours.lookup(oursRoot, KDB_O_POP); lkdb.get (theirs, theirsRoot); theirs = theirs.cut (theirsRoot); theirs.lookup(theirsRoot, KDB_O_POP); lkdb.get (base, baseRoot); base = base.cut (baseRoot); base.lookup(baseRoot, KDB_O_POP); } // Step 2: Make sure that no keys reside below the intended merge result root // Usually the merge can be either aborted if this is the case or the existing // keys can be overwritten. KeySet resultKeys; kdb::KDB kdb; kdb.get (resultKeys, resultRoot); KeySet discard = resultKeys.cut (resultRoot); if (discard.size () != 0) { // handle existing keys below the result root return -1; } ThreeWayMerge merger; // Step 3: Decide which resolution strategies to use. The strategies are registered // with the merge and applied in order as soon as a conflict is detected. If a strategy // marks a conflict as resolved, no further strategies are consulted. Therefore the order // in which they are registered is absolutely crucial. With this chaining the strategies // remain simple, but can be combined to powerful resolution strategies. // Have a look at the strategy documentation for further details on what they do and how they work. // The unit tests also provide insight into how the strategies work. // In order to simplify the initialization, predefined merge configurations exist. // in this example we first resolve all the keys that can be automatically // resolved (e.g. only one side was modified). This is exactly the use case of the // AutoMergeConfiguration. AutoMergeConfiguration configuration; configuration.configureMerger(merger); // Step 4: Perform the actual merge MergeResult result = merger.mergeKeySet ( MergeTask (BaseMergeKeys (base, baseRoot), OurMergeKeys (ours, oursRoot), TheirMergeKeys (theirs, theirsRoot), resultRoot)); // Step 5: work with the result. The merger will return an object containing information // about the merge result. if (!result.hasConflicts ()) { // output some statistical information cout << result.getMergedKeys().size() << " keys in the result" << endl; cout << result.getNumberOfEqualKeys() << " keys were equal" << endl; cout << result.getNumberOfResolvedKeys() << " keys were resolved" << endl; // write the result resultKeys.append(result.getMergedKeys()); kdb.set (resultKeys, resultRoot); return 0; } else { KeySet conflicts = result.getConflictSet(); cerr << conflicts.size() << " conflicts were detected that could not be resolved automatically:" << endl; conflicts.rewind(); Key current; while ((current = conflicts.next())) { // For each unresolved conflict there is a conflict key in the merge result. // This conflict key contains meta information about the reason of the conflict. // In particular the metakeys conflict/operation/our and conflict/operation/their contain // the operations done on our version of the key and their version of the key relative to // the base version of the key. string ourConflict = current.getMeta<string> ("conflict/operation/our"); string theirConflict = current.getMeta<string> ("conflict/operation/their"); cerr << current << endl; cerr << "ours: " << ourConflict << ", theirs: " << theirConflict << endl; cerr << endl; } cerr << "Merge unsuccessful." << endl; return -1; } }
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; Key k; oldConf.rewind (); if (cl.recursive) { while ((k = oldConf.next ())) { newConf.append (rename_key (k, sourceName, newDirName, cl.verbose)); } } else { // just rename one key k = oldConf.next (); 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 newConf.rewind (); if (cl.verbose) { cout << "Will write out:" << endl; cout << newConf; } kdb.set (newConf, root); printWarnings (cerr, root); return 0; }
int MergeCommand::execute(Cmdline const& cl) { if (cl.arguments.size () < 4) { throw invalid_argument ("wrong number of arguments, 4 needed"); } Key oursRoot = cl.createKey(0); Key theirsRoot = cl.createKey(1); Key baseRoot = cl.createKey(2); Key resultRoot = cl.createKey(3); KeySet ours; KeySet theirs; KeySet base; { KDB lkdb; lkdb.get (ours, oursRoot); ours = ours.cut (oursRoot); ours.lookup(oursRoot, KDB_O_POP); if (cl.verbose) std::cout << "we got ours: " << oursRoot << " with keys " << ours << std::endl; } { KDB lkdb; lkdb.get (theirs, theirsRoot); theirs = theirs.cut (theirsRoot); ours.lookup(oursRoot, KDB_O_POP); if (cl.verbose) std::cout << "we got theirs: " << theirsRoot << " with keys " << theirs << std::endl; } { KDB lkdb; lkdb.get (base, baseRoot); base = base.cut (baseRoot); ours.lookup(oursRoot, KDB_O_POP); if (cl.verbose) std::cout << "we got base: " << baseRoot << " with keys " << base << std::endl; } KeySet resultKeys; kdb.get (resultKeys, resultRoot); KeySet discard = resultKeys.cut (resultRoot); if (discard.size () != 0) { if (cl.force) { if (cl.verbose) { std::cout << "will remove " << discard.size () << " keys, because -f was given" << std::endl; } } else { std::cerr << discard.size () << " keys exist in merge resultroot, will quit. Use -f to override the keys there." << std::endl; } } MergeHelper helper; ThreeWayMerge merger; helper.configureMerger (cl, merger); MergeResult result = merger.mergeKeySet ( MergeTask (BaseMergeKeys (base, baseRoot), OurMergeKeys (ours, oursRoot), TheirMergeKeys (theirs, theirsRoot), resultRoot)); helper.reportResult (cl, result, cout, cerr); int ret = 0; if (!result.hasConflicts ()) { resultKeys.append(result.getMergedKeys()); kdb.set (resultKeys, resultRoot); } else { ret = -1; } return ret; }