Skip to content

Commit

Permalink
kdb-cli: rewrite set
Browse files Browse the repository at this point in the history
... and (partial) fix #3742, fix #4028, fix #1164
  • Loading branch information
hannes99 committed Jul 4, 2023
1 parent 00df54b commit 0616860
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 178 deletions.
35 changes: 4 additions & 31 deletions doc/tutorials/cascading.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,41 +91,14 @@ The **proc** namespace is not accessible by the command line tool **kdb**, as it

The **spec** namespace is used to store metadata about keys and therefore Elektra handles the **spec** namespace differently to other namespaces. The following part of the tutorial is dedicated to the impact of the **spec** namespace on cascading lookups.

## Write Operations and the cascading Namespace

If a value is to be written to a cascading key, i.e., a key starting with '/', only cascading keys that resolve to an existing key will be used.
## Cascading writes are not possible

For example,

```sh
kdb set /tests/tutorial/cascading/#0/current/cascading_write_test value
# STDERR: Aborting: A cascading write to a non-existent key is ambiguous.
# RET: 12

kdb meta-set /tests/tutorial/cascading/#0/current/cascading_write_test metakey metavalue
# STDERR: Aborting: A cascading write to a non-existent key is ambiguous.
# RET: 12
```

will both fail, as no matching key exists.
Since there are multiple hypothetical key names that would match the cascading name (keys of specific namespaces like user:, system:, ...) if they existed, it is not clear what the user intended and thus an error is produced.

To make the previous two operations meaningful, a matching key in the user: namespace is created:

```sh
kdb set user:/tests/tutorial/cascading/#0/current/cascading_write_test value
#> Create a new key user:/tests/tutorial/cascading/#0/current/cascading_write_test with string "value"
```

Now, the operations operate on a well-defined key and succeed this time:

```sh
kdb set /tests/tutorial/cascading/#0/current/cascading_write_test value
#> Set string to "value"
#> Using name user:/tests/tutorial/cascading/#0/current/cascading_write_test

kdb meta-set /tests/tutorial/cascading/#0/current/cascading_write_test metakey metavalue
#> Using name user:/tests/tutorial/cascading/#0/current/cascading_write_test
kdb set /tests/tutorial/cascading/key1 "hello world"
# RET: 2
# STDERR: .*key does not specify a namespace
```

## Override Links
Expand Down
4 changes: 2 additions & 2 deletions src/plugins/hosts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ kdb get /tests/hosts/ipv6/localhost
#> ::1

# Should both fail with error C03200 and return 5
kdb set /tests/hosts/ipv4/localhost ::1
kdb set user:/tests/hosts/ipv4/localhost ::1
# RET:5
# ERROR:C03200
kdb set /tests/hosts/ipv6/localhost 127.0.0.1
kdb set user:/tests/hosts/ipv6/localhost 127.0.0.1
# RET:5
# ERROR:C03200

Expand Down
2 changes: 1 addition & 1 deletion src/plugins/kconfig/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ kdb get /tests/kconfig/key
#> Value

# Set the value to Example
kdb set /tests/kconfig/key Example
kdb set user:/tests/kconfig/key Example

# Verify that the value has changed in the file too
cat `kdb file user:/tests/kconfig`
Expand Down
1 change: 1 addition & 0 deletions src/plugins/range/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ kdb set user:/tests/range/value 2
# RET:0

kdb rm -r user:/tests/range
kdb rm -r spec:/tests/range
sudo kdb umount /tests/range
```

Expand Down
2 changes: 0 additions & 2 deletions src/tools/kdb/factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
#include <recordstop.hpp>
#include <remount.hpp>
#include <rm.hpp>
#include <set.hpp>
#include <sget.hpp>
#include <shell.hpp>
#include <showmeta.hpp>
Expand Down Expand Up @@ -93,7 +92,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<Cnstancer<SetCommand>> ()));
m_factory.insert (std::make_pair ("rm", std::make_shared<Cnstancer<RemoveCommand>> ()));
m_factory.insert (std::make_pair ("ls", std::make_shared<Cnstancer<LsCommand>> ()));
m_factory.insert (std::make_pair ("cache", std::make_shared<Cnstancer<CacheCommand>> ()));
Expand Down
2 changes: 1 addition & 1 deletion src/tools/kdb/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ command subcommands[] = {
{ "get", addGetSpec, execGet },
{ "record-start", addRecordStartSpec, execRecordStart },
{ "record-undo", addRecordUndoSpec, execRecordUndo },
{ "set", addSetSpec, execSet },
};

cppCommand cppSubcommands[] = {
Expand All @@ -85,7 +86,6 @@ cppCommand cppSubcommands[] = {
{ "mv", addMvSpec, execCppMv },
{ "namespace", addNamespaceSpec, execCppNamespace },
{ "rm", addRmSpec, execCppRm },
{ "set", addSetSpec, execCppSet },
{ "sget", addSgetSpec, execCppSget },
{ "cache", addCacheSpec, execCppCache },
{ "complete", addCompleteSpec, execCppComplete },
Expand Down
87 changes: 83 additions & 4 deletions src/tools/kdb/set.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
* @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
*/

#include <colors.h>
#include <command.h>
#include <kdbassert.h>
#include <kdbease.h>
#include <kdberrors.h>
#include <set.h>

#include <cpp-main.h>
#include <stdio.h>
#include <string.h>

#define COMMAND_NAME "set"

Expand All @@ -31,7 +35,82 @@ void addSetSpec (KeySet * spec)
ADD_BASIC_OPTIONS (spec, COMMAND_SPEC_KEY (COMMAND_NAME))
}

int execCppSet (int argc, char ** argv)
int execSet (KeySet * options, Key * errorKey)
{
return cpp_main (argc, argv);
int ret = 0;
GET_BASIC_OPTIONS

bool force = false;
tmp = GET_OPTION_KEY (options, "force");
if (tmp != NULL)
{
elektraKeyToBoolean (GET_OPTION_KEY (options, "force"), &force);
}

Key * parentKey = getKeyFromOptions (GET_OPTION (options, "name"), errorKey, verbose);
if (parentKey == NULL)
{
RETURN (2)
}

const char * value = GET_OPTION (options, "value");

if (keyGetNamespace (parentKey) == KEY_NS_NONE || keyGetNamespace (parentKey) == KEY_NS_CASCADING)
{
ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, "key does not specify a namespace");
keyDel (parentKey);
RETURN (2)
}

Key * maybeCascadingParent = keyDup (parentKey, KEY_CP_NAME);
if (!force)
{
keySetNamespace (maybeCascadingParent, KEY_NS_CASCADING);
}
KeySet * conf = ksNew (0, KS_END);
KDB * handle = kdbOpen (NULL, errorKey);

if (kdbGet (handle, conf, maybeCascadingParent) == -1)
{
ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "could not load '%s': %s", keyName (parentKey),
GET_ERR (maybeCascadingParent));
ret = 5;
goto cleanup;
}
keyCopyAllMeta (errorKey, parentKey);

Key * key = ksLookup (conf, parentKey, KDB_O_NONE);
if (key == NULL)
{
key = keyNew (keyName (parentKey), KEY_END);
ksAppendKey (conf, key);
CLI_PRINT (CLI_LOG_NONE, "Create a new key %s with string \"%s\"", keyName (key), value);
}
else
{
CLI_PRINT (CLI_LOG_NONE, "Set string to \"%s\"", value);
}
keySetString (key, value); // can't fail, since neither value or key can be null

if (kdbSet (handle, conf, parentKey) == -1)
{
ret = 5;
ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "could not set value for '%s': %s", keyName (parentKey),
GET_ERR (parentKey));
}
keyCopyAllMeta (errorKey, parentKey);

keyDel (key);

cleanup:
if (!noNewLine)
{
printf ("\n");
}
keyDel (parentKey);
keyDel (maybeCascadingParent);
ksDel (conf);
kdbClose (handle, errorKey);

RETURN (ret)
}
86 changes: 0 additions & 86 deletions src/tools/kdb/set.cpp

This file was deleted.

4 changes: 2 additions & 2 deletions src/tools/kdb/set.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ void addSetSpec (KeySet * spec);
* @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
* @retval >0 errors occurred, keyGetMeta (errorKey, "error/reason") for info
*
*/
int execCppSet (int argc, char ** argv);
int execSet (KeySet * options, Key * errorKey);

#endif // ELEKTRA_KDB_SET_H
49 changes: 0 additions & 49 deletions src/tools/kdb/set.hpp

This file was deleted.

1 change: 1 addition & 0 deletions tests/shell/shell_recorder/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ if (ENABLE_KDB_TESTING)
"${CMAKE_CURRENT_BINARY_DIR}/tutorial_wrapper/markdown_shell_recorder.sh" @ONLY)

add_shell_recorder_test (cli/cli_get.esr)
add_shell_recorder_test (cli/cli_set.esr)
add_shell_recorder_test (db_changes.esr)
add_shell_recorder_test (hosts.esr REQUIRED_PLUGINS hosts)
# DISABLED add_shell_recorder_test (listtest.esr REQUIRED_PLUGINS dump list)
Expand Down

0 comments on commit 0616860

Please sign in to comment.