Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Elektra High Level API #1412

Closed
wants to merge 124 commits into from
Closed

Conversation

domhof
Copy link
Contributor

@domhof domhof commented Mar 13, 2017

Purpose

First draft of Elektra High Level API.

Checklist

Please only check relevant points.
For docu fixes, spell checking and similar nothing
needs to be checked.

  • commit messages are fine (with references to issues)
  • I ran all tests and everything went fine
  • I added unit tests
  • affected documentation is fixed
  • I added code comments, logging, and assertions
  • meta data is updated (e.g. README.md of plugins)

@markus2330 please review my pull request

@markus2330 markus2330 requested a review from tom-wa March 13, 2017 16:29
@markus2330
Copy link
Contributor

Thank you!

Can you put elektra.c into a separate library? It won't compile (and does not make sense) to put it into the core.

@tom-wa Can you do a review, too?

Copy link
Contributor

@markus2330 markus2330 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

#include "kdbhelper.h"
#include "kdbtypes.h"

struct _ElektraError
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Structs should be hidden!


struct _ElektraError
{
int errorNr;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? Do you want to change elektraHasError to return a kdb_long_t?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we could do something like that (maybe with another function). The idea is that the developer can identify an error-type without parsing the string. Maybe it is not needed, I would say we will see which error-types we will have and can then decide upon that if we keep it or remove it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is that the developer can identify an error-type without parsing the string.

Yes, sounds useful. For the code generator option we could even provide an enum.

I would say we will see which error-types we will have

They are already defined in src/error/specification.

struct _ElektraError
{
int errorNr;
const char * msg;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be an array if you can hold errorNr errors?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

errorNr just identifies the error-type. msg is a readable string that describes it.

void elektraClearError (Elektra * elektra)
{
elektraFree (elektra->error);
elektra->error = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice and simple!


keyDel (nameKey);

const kdb_long_long_t value = ELEKTRA_LONG_LONG_S (string, NULL, 10);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use keyGetLongLong here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know we only have getString and getValue in the layer below. (we decided to remove all typed getters)

#include <stdlib.h>
#include <memory.h>

Elektra * elektraOpen (const char * application)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add error handling here!

It is important to understand which guarantees we can give to libraries.

markus2330 pushed a commit that referenced this pull request Mar 17, 2017
Copy link
Contributor

@markus2330 markus2330 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely done!

READ_KEY

kdb_boolean_t value = 0;
if (!strcmp(string, "true") || !strcmp(string, "1") || !strcmp(string, "on")) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you introduce the same issue as discussed with hex values in #1388

We already have defined booleans to be 0 or 1.

Furthermore, you need to check here if check/type isn't something else other than boolean.

typedef struct _ElektraError ElektraError;
typedef struct _Elektra Elektra;

Elektra * elektraOpen (const char * application);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error parameter missing

Elektra * elektraOpen (const char * application);
void elektraClose (Elektra * elektra);

kdb_boolean_t elektraHasError (const Elektra * elektra);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

old API

KeySet * config;
Key * parentKey;

struct _ElektraError * error;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed

@@ -15,3 +15,5 @@ add_subdirectory (plugin)
add_subdirectory (elektra)

generate_manpage (elektra-libs FILENAME ${CMAKE_CURRENT_SOURCE_DIR}/README.md SECTION 7)

add_subdirectory (highlevel)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add newline

keyDel (nameKey); \

#define RELEASE_KEY_AND_RETURN_VALUE \
keyDel (resultKey); \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this macro really needed?

#include "elektraprivate.h"

#define READ_KEY \
Key * const nameKey = keyDup (elektra->parentKey); \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why duplicate? What about having a searchKey in Elektra and only modify its name?

{
READ_KEY

char * value = elektraMalloc (keyGetValueSize(resultKey));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not return allocated memory to the user.

@@ -13,13 +13,13 @@ def funcname(self, key):
raise Exception("invalid keyname " + key)

def getfuncname(self, key):
return "get_"+self.funcname(key)
return "elektraGet"+self.funcname(key)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change would need a fix in the tests. It might be better to have a new py file which inherits from c.py.

Please cut off basename here, or fix specification of your user study example to not contain Sw.

@markus2330
Copy link
Contributor

Thanks for working on it!

Seems you need to rebase (conflicing file .gitignore)

Please remove "work in progress" when I should do a review.

Copy link
Contributor

@markus2330 markus2330 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seem to be some serious issues in the tests, unrelated to the resolver.

* @copyright BSD License (see doc/LICENSE.md or http://www.libelektra.org)
*/

#include <tests_internal.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, tests should do.

ksAppendKey(config, key);

// Check
Key *checkKey = ksLookupByName (config, name, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are searching for the wrong key here: name != parentKeyName+name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was never meant to be added to git, I tried different things until I found out that the KDB could not be loaded in the first place. I'm aware of the inconsistencies, please ignore them, the code will get removed anyway after we have found out why the resolver cannot be loaded (or about the real cause).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, for me it worked except of this.

KDB * handle = kdbOpen (parentKey);
kdbGet (handle, config, parentKey);

printf ("Error occurred: %s\n", keyString (keyGetMeta (parentKey, "error/description")));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you know it failed? You need to check the return value of kdbGet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lldb tells me that the handle is NULL ;-)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, something seems to be very broken, then.

But in this case the error 37 with the description handle or ks null pointer should be set?


int main (int argc, char ** argv)
{
printf ("KEY TESTS\n");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong test name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above. I initially copied test_key.c. This is just a leftover.

kdbGet (handle, config, parentKey);

// Check
Key *checkKey = ksLookupByName (config, name, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also wrong lookup here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment above


// Close
kdbClose (handle, parentKey);
keyDel (parentKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not everything cleaned up, e.g. config

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment above


static void test_development ()
{
const char * parentKey = "user/sw/elektra/kdb/#0/current";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only write in /test for test cases, e.g. user/test/...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw. the test cases redirect user to /tmp, so you cannot use kdb get to check the key afterwards.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I didn't know about user being redirected to tmp. Is there a documentation for writing tests etc.?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only doc/TESTING.md. For non-ABI tests it is okay to use gtest, which is much more comfortable and better documented. (And according to @fberlakovich CLion has support for it.)

We can also consider to write ABI tests with gtest. Until now nobody checked what would happen in the case of gtest upgrades. Maybe it will work without issues anyway. (Because gtest is compiled in after all.)

We can also consider a gtest upgrade, we still have 1.7.0 but 1.8.0 was already released.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improvements of doc/TESTING.md and how we use gtest is of course very welcomed!

@@ -113,7 +113,29 @@ ostream & operator<< (ostream & os, parse_t & p)
os << p[i]["macro"] << " " << i << endl;
}

os << endl << endl;

/* Temporarily disable enum generation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert that change, there is little use of passing all enums to the user.

Copy link
Contributor

@markus2330 markus2330 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, looks much better now!

Issues should be easy to fix, would be great to have the fixes soon so that we can merge this.

init (argc, argv);

test_primitiveGetters ();
test_arrayGetters ();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please reformat. (clang-format, see scripts/reformat-source)


succeed_if (elektraArraySize(elektra, "longDoubleArrayKey") == 2, "Wrong array size");
succeed_if (elektraGetLongDoubleArrayElement(elektra, "longDoubleArrayKey", 0) == 1.1L, "Wrong key value.");
succeed_if (elektraGetLongDoubleArrayElement(elektra, "longDoubleArrayKey", 1) == 2.1L, "Wrong key value.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens on out-of-array access?

elektraSetBooleanArrayElement(elektra, "booleanArrayKey", 0, 0);
elektraSetBooleanArrayElement(elektra, "booleanArrayKey", 1, 1);

elektraSetCharArrayElement(elektra, "charArrayKey", 'c', 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do boundary tests (smallest and largest char, long,...)


int main(int argc, char ** argv)
{
ElektraError * error = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also format examples nicely.

int main(int argc, char ** argv)
{
ElektraError * error = NULL;
Elektra * elektra = elektraOpen ("/sw/yourApplication", &error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use only correct examples (org+version missing)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it to "/sw/org/myapp/#0/current".


if (kdb == NULL)
{
*error = elektraErrorCreateFromKey(parentKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error fatal?

Key * problemKey = ksCurrent (elektra->config);
if (problemKey != NULL)
{
// ELEKTRA_LOG_DEBUG("problemKey: %s\n", keyName (problemKey));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why comment out?


kdbGet (elektra->kdb, elektra->config, elektra->parentKey);
}
} while (ret == -1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might not terminate.

// ELEKTRA_LOG_DEBUG("problemKey: %s\n", keyName (problemKey));
}

kdbGet (elektra->kdb, elektra->config, elektra->parentKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary kdbGet if kdbSet was successful.

Please take a look at examples/kdbset.c or qt-gui for how to do this correctly. You also need to do a 3-way merge considering who changed the value (for the one key to set).

Key * problemKey = ksCurrent (elektra->config);
if (problemKey != NULL)
{
// ELEKTRA_LOG_DEBUG("problemKey: %s\n", keyName (problemKey));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why comment out? Seems to be duplication of code here?

@@ -67,8 +67,9 @@ class Environment : public ThreadBoolean
: ThreadBoolean (ks, context_, Key ("/test/%layer1%", KEY_CASCADING_NAME, KEY_META, "default", "1", KEY_END)),
nested (ks, context_), person (ks, context_),
profile (ks, context_, Key ("/%layer1%/profile", KEY_CASCADING_NAME, KEY_META, "default", "default", KEY_END)),
bm (ks, context_, Key ("/%layer1%/%layer2%/%layer3%/%layer4%/%layer5%/%layer6%/%layer7%/%layer8%/%layer9%/", KEY_CASCADING_NAME,
Copy link
Contributor

@markus2330 markus2330 May 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you use clang-format-3.8? Maybe @sanssecours can give you a tip how to get it (on Mac).

If we would use different versions of clang-format we would keep reverting our changes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you use clang-format-3.8? Maybe @sanssecours can give you a tip how to get it (on Mac).

You can install clang-3.8 via brew install clang-format@3.8.

If we would use different versions of clang-format we would keep reverting our changes.

We could also just use the current version (5.0.0) of the software.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for giving the tip!

We could also just use the current version (5.0.0) of the software.

Installing clang on all build agents take some time, so I would prefer to wait for @BernhardDenner's build server case study. Furthermore, it needs to be coordinated with all developers. We can discuss it in the next meeting, but for now @domhof please use 3.8.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I used the current version (5.0.0). Reverted back to 3.8 for now.

@markus2330
Copy link
Contributor

Btw. before merging please rebase. And it would be great if you can put the module you are working on as short message before the commit messages. (kdbhl or similar)

And as long term perspective we should get rid of the python dep for the simple parts of the code generator (generating the key names and default config).

@markus2330
Copy link
Contributor

What is the status of this PR? Still seems to have a lot of wrong reformatting? Please check the PR at github.

@markus2330
Copy link
Contributor

Btw. last time we discussed you will start a new PR. What is the status? Please also make sure to work in all feedback you got so far and self-review what you have done.

@domhof domhof closed this Aug 2, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants