Skip to content

Commit

Permalink
kdb-cli: rewrite get command
Browse files Browse the repository at this point in the history
... and remove cpp implementation
  • Loading branch information
hannes99 committed May 27, 2023
1 parent 410ae04 commit 026b455
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 261 deletions.
6 changes: 3 additions & 3 deletions doc/help/kdb-get.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ kdb get -n /tests/get/examples/kdb-get/key
kdb get -v /tests/get/examples/kdb-get/key
#> got 3 keys
#> searching spec:/tests/get/examples/kdb-get/key, found: <nothing>, options: KDB_O_CALLBACK
#> searching proc:/tests/get/examples/kdb-get/key, found: <nothing>
#> searching dir:/tests/get/examples/kdb-get/key, found: <nothing>
#> searching user:/tests/get/examples/kdb-get/key, found: user:/tests/get/examples/kdb-get/key
#> searching proc:/tests/get/examples/kdb-get/key, found: <nothing>, options: KDB_O_CALLBACK
#> searching dir:/tests/get/examples/kdb-get/key, found: <nothing>, options: KDB_O_CALLBACK
#> searching user:/tests/get/examples/kdb-get/key, found: user:/tests/get/examples/kdb-get/key, options: KDB_O_CALLBACK
#> The resulting keyname is user:/tests/get/examples/kdb-get/key
#> The resulting value size is 6
#> myKey
Expand Down
8 changes: 4 additions & 4 deletions doc/man/man1/kdb-get.1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.\" generated with Ronn-NG/v0.10.1
.\" http://github.com/apjanke/ronn-ng/tree/0.10.1.pre3
.TH "KDB\-GET" "1" "August 2021" ""
.TH "KDB\-GET" "1" "September 2022" ""
.SH "NAME"
\fBkdb\-get\fR \- Get the value of a key stored in the key database
.SH "SYNOPSIS"
Expand Down Expand Up @@ -78,9 +78,9 @@ kdb get \-n /tests/get/examples/kdb\-get/key
kdb get \-v /tests/get/examples/kdb\-get/key
#> got 3 keys
#> searching spec:/tests/get/examples/kdb\-get/key, found: <nothing>, options: KDB_O_CALLBACK
#> searching proc:/tests/get/examples/kdb\-get/key, found: <nothing>
#> searching dir:/tests/get/examples/kdb\-get/key, found: <nothing>
#> searching user:/tests/get/examples/kdb\-get/key, found: user:/tests/get/examples/kdb\-get/key
#> searching proc:/tests/get/examples/kdb\-get/key, found: <nothing>, options: KDB_O_CALLBACK
#> searching dir:/tests/get/examples/kdb\-get/key, found: <nothing>, options: KDB_O_CALLBACK
#> searching user:/tests/get/examples/kdb\-get/key, found: user:/tests/get/examples/kdb\-get/key, options: KDB_O_CALLBACK
#> The resulting keyname is user:/tests/get/examples/kdb\-get/key
#> The resulting value size is 6
#> myKey
Expand Down
4 changes: 2 additions & 2 deletions doc/news/_preparation_next_release.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,9 @@ This section keeps you up-to-date with the multi-language support provided by El

## Tools

### <<Tool>>
### KDB

- <<TODO>>
- add basic C framework, helper functions and new `get` implementation _(@hannes99)_
- <<TODO>>
- <<TODO>>

Expand Down
2 changes: 1 addition & 1 deletion doc/tutorials/namespaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Another question you may ask yourself now is, what happens if we look up a key w

```sh
kdb get -v /tests/b/c
# STDOUT-REGEX: got [[:digit:]]+ keys⏎searching spec:/tests/b/c, found: <nothing>, options: KDB_O_CALLBACK⏎ searching proc:/tests/b/c, found: <nothing>⏎ searching dir:/tests/b/c, found: <nothing>⏎ searching user:/tests/b/c, found: user:/tests/b/c⏎The resulting keyname is user:/tests/b/c⏎The resulting value size is 8⏎Value 2
# STDOUT-REGEX: got [[:digit:]]+ keys⏎searching spec:/tests/b/c, found: <nothing>, options: KDB_O_CALLBACK⏎ searching proc:/tests/b/c, found: <nothing>, options: KDB_O_CALLBACK⏎ searching dir:/tests/b/c, found: <nothing>, options: KDB_O_CALLBACK⏎ searching user:/tests/b/c, found: user:/tests/b/c, options: KDB_O_CALLBACK⏎The resulting keyname is user:/tests/b/c⏎The resulting value size is 8⏎Value 2
```

Here you see how Elektra searches all namespaces for matching keys in this order:
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/base64/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ kdb meta-set user:/tests/base64/encoded type binary

# Receive key data (the `\x0` at the end marks the end of the string)
kdb get user:/tests/base64/encoded
#> \x76\x61\x6c\x75\x65\x0
#> \x76\x61\x6c\x75\x65\x00

# Undo modifications
kdb rm -r user:/tests/base64
Expand Down
7 changes: 6 additions & 1 deletion src/tools/kdb/complete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,12 @@ void CompleteCommand::addMountpoints (KeySet & ks, Key const & root, Cmdline con
{
if (mountpoint.isDirectBelow (mountpointPath))
{
const string actualName = mountpoints.lookup (mountpoint.getName () + "/mountpoint").getString ();
Key const k = mountpoints.lookup (mountpoint.getName () + "/mountpoint");
if (!k)
{
continue;
}
const string actualName = k.getString ();
Key mountpointKey (actualName, KEY_END);
// If the mountpoint already has some contents, its expanded with a namespace, so leave it out then
if (mountpointKey.isBelow (root) && !KeySet (ks).cut (mountpointKey).size ())
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 @@ -35,7 +35,6 @@
#include <file.hpp>
#include <find.hpp>
#include <gen.hpp>
#include <get.hpp>
#include <import.hpp>
#include <listcommands.hpp>
#include <ls.hpp>
Expand Down Expand Up @@ -88,7 +87,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 ("get", std::make_shared<Cnstancer<GetCommand>> ()));
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>> ()));
Expand Down
224 changes: 224 additions & 0 deletions src/tools/kdb/get.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
/**
* @file
*
* @brief KDB get subcommand
*
* @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
*/

#include <colors.h>
#include <command.h>
#include <get.h>
#include <kdbassert.h>
#include <kdbease.h>
#include <kdberrors.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define COMMAND_NAME "get"

#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)

typedef Key * (*lookup_fn) (KeySet * s, Key * key, Key * found, elektraLookupFlags flags);

void addGetSpec (KeySet * spec)
{
ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME), KEY_META, "description", "Get the value of an individual key.",
KEY_META, "command", COMMAND_NAME, KEY_END));
ksAppendKey (spec, keyNew (COMMAND_SPEC_KEY (COMMAND_NAME) "/all", KEY_META, "description", "Consider all of the keys", KEY_META,
"opt", "a", KEY_META, "opt/long", "all", 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));

ADD_BASIC_OPTIONS (spec, COMMAND_SPEC_KEY (COMMAND_NAME))
}

static void printOptions (elektraLookupFlags options)
{
if (options & KDB_O_SPEC) printf ("KDB_O_SPEC ");
if (options & KDB_O_CREATE) printf ("KDB_O_CREATE ");
if (options & KDB_O_NOCASCADING) printf ("KDB_O_NOCASCADING ");
if (options & KDB_O_NOSPEC) printf ("KDB_O_NOSPEC ");
if (options & KDB_O_NODEFAULT) printf ("KDB_O_NODEFAULT ");
if (options & KDB_O_CALLBACK) printf ("KDB_O_CALLBACK");
}

static const char * getCascadingName (const char * str)
{
if (str == NULL) return "/";
const char * r = strchr (str, '/');
return r == NULL ? "/" : r;
}

static Key * warnOnMeta (ELEKTRA_UNUSED KeySet * ks, ELEKTRA_UNUSED Key * key, Key * found, elektraLookupFlags options)
{
if (found != NULL && strncmp (keyName (found), "spec:/", 6) == 0 && options == KDB_O_CALLBACK)
{
const Key * meta = keyGetMeta (found, "context");
if (meta != NULL)
{
ELEKTRA_ADD_RESOURCE_WARNINGF (
key, "%s is context dependent, shown result might be wrong, -v shows you the trace to the key\n",
keyName (found));
}
}
return found;
}


static Key * printTrace (ELEKTRA_UNUSED KeySet * ks, Key * key, Key * found, elektraLookupFlags options)
{
warnOnMeta (ks, key, found, options);
const char * lastKeyName = keyValue (keyGetMeta (key, "callback/print_trace/last_key_name"));
const char * name = keyName (key);
const char * rawDepth = keyValue (keyGetMeta (key, "callback/print_trace/depth"));

int depth = rawDepth == NULL ? 0 : atoi (rawDepth);
for (int i = 0; i < depth; ++i)
{
printf (" ");
}

printf ("searching %s%s", (name[0] == '/' ? "default of spec" : ""), name);
printf (", found: %s", (found != NULL ? keyName (found) : "<nothing>"));
if (options)
{
printf (", options: ");
printOptions (options);
}
printf ("\n");

int newDepth = depth;
if (elektraStrNCmp (name, "spec:/", 6) == 0 && (options & KDB_O_CALLBACK))
{
newDepth += 4;
}
else if (elektraStrCmp (getCascadingName (lastKeyName), getCascadingName (name)) != 0)
{
newDepth = depth != 0 ? depth - 2 : depth;
}
if (newDepth != depth)
{
char buff[11];
snprintf (buff, 11, "%d", newDepth);
keySetMeta (key, "callback/print_trace/depth", buff);
}
keySetMeta (key, "callback/print_trace/last_key_name", name);
return found;
}

static void setCallback (Key * key, lookup_fn f)
{
union
{
lookup_fn f;
void * v;
} conversation;

conversation.f = f;
keySetBinary (key, &conversation.v, sizeof (conversation));
keySetMeta (key, "callback", "");
}


int execGet (KeySet * options, Key * errorKey)
{
int ret = 0;
GET_BASIC_OPTIONS

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

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

KeySet * searchIn = ksNew (0, KS_END);
KDB * handle = kdbOpen (NULL, errorKey);

Key * parentKey = keyDup (toLookUp, KEY_CP_NAME);
if (all)
{
// we change the pointer, so we have to free old memory before
keyDel (parentKey);
parentKey = keyNew ("/", KEY_END);
}
if (kdbGet (handle, searchIn, parentKey) == -1)
{ // could not load keys from kdb
ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (errorKey, "could not load '%s': %s", keyName (toLookUp), GET_ERR (parentKey));
keyDel (toLookUp);
keyDel (parentKey);
ksDel (searchIn);
kdbClose (handle, errorKey);
RETURN (5)
}
keyCopyAllMeta (errorKey, parentKey);
kdbClose (handle, errorKey);

setCallback (toLookUp, warnOnMeta);
if (verbose)
{
CLI_PRINT (CLI_LOG_VERBOSE, "got %ld keys\n", ksGetSize (searchIn));
setCallback (toLookUp, printTrace);
}

Key * found = ksLookup (searchIn, toLookUp, KDB_O_CALLBACK);

if (keyCopyAllMeta (errorKey, toLookUp) == -1)
{ // we have to copy the meta keys so the CLI can print the errors
ELEKTRA_SET_INTERNAL_ERROR (errorKey, "could not copy key meta to errorKey");
keyDel (toLookUp);
ksDel (searchIn);
RETURN (3)
}

if (found == NULL)
{
CLI_ERROR_PRINT (CLI_LOG_NONE, "Did not find key '%s'", RED (keyName (toLookUp)));
ret = 11;
goto cleanup;
}

if (keyGetNamespace (found) == KEY_NS_DEFAULT)
{
CLI_PRINT (CLI_LOG_VERBOSE, "The key was not found in any other namespace, taking the %s\n", BOLD ("default"));
}
CLI_PRINT (CLI_LOG_VERBOSE, "The resulting keyname is %s\n", keyName (found));
CLI_PRINT (CLI_LOG_VERBOSE, "The resulting value size is %ld\n", keyGetValueSize (found));

if (keyIsBinary (found))
{ // for binary data in keys
ssize_t binSize = keyGetValueSize (found);
CLI_PRINT (CLI_LOG_VERBOSE, "The key is %s.\n", BOLD (binSize == 0 ? "null" : "binary"));
const uint8_t * data = (const uint8_t *) keyValue (found);
for (int position = 0; position < keyGetValueSize (found); position++)
{
CLI_PRINT (CLI_LOG_NONE, "\\x%02x", data[position]);
}
}
else
{
CLI_PRINT (CLI_LOG_NONE, "%s", keyString (found));
}

cleanup:
if (!noNewLine)
{
printf ("\n");
}
keyDel (parentKey);
keyDel (toLookUp);
ksDel (searchIn);

RETURN (ret)
}

0 comments on commit 026b455

Please sign in to comment.