From d9a8478478b0009971a070d2990af0b310abfd7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemens=20B=C3=B6swirth?= Date: Thu, 12 Nov 2020 14:17:32 +0100 Subject: [PATCH] Keyname overhaul MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squashed (and fixed) commit of the following: commit 541e404e77da80866ffd7d5109b045bd0f98d269 Author: Klemens Böswirth Date: Fri Oct 23 17:50:26 2020 +0200 proposal and demo for new api commit 29fb355d99ebf00b4bdf20e817cf48858e247347 Author: Klemens Böswirth Date: Tue Oct 20 21:11:01 2020 +0200 add TODO commit b169534b4196e7c311283715d22cfd5397fff867 Author: Klemens Böswirth Date: Mon Oct 12 17:25:38 2020 +0200 fix footnote commit 60c508b0d479bf323c294526d23e253917ef626a Author: Klemens Böswirth Date: Sun Oct 11 16:55:20 2020 +0200 add TODO commit 7da783df31360334119fffee98cc24cff7134e8a Author: Klemens Böswirth Date: Sun Oct 11 16:44:46 2020 +0200 Remove keyIsInactive and plugin 'hidden' commit 2f167d56bd2eca77529c762302e8229ade8ef10b Author: Klemens Böswirth Date: Fri Oct 9 14:38:56 2020 +0200 Update release notes commit 14297658bee7181cfb59f08c542f2b6ccf0d02b8 Author: kodebach <23529132+kodebach@users.noreply.github.com> Date: Mon Oct 12 17:25:24 2020 +0200 Apply suggestions from code review Co-authored-by: markus2330 commit 2fdb2dc5cd8754369725e270abcc97b35eb029d5 Author: kodebach <23529132+kodebach@users.noreply.github.com> Date: Sun Oct 11 20:28:12 2020 +0200 Apply suggestions from code review Co-authored-by: markus2330 commit 3ae0fb7257536dc0251f710ff74ff036220d6e29 Author: Klemens Böswirth Date: Sat Oct 3 21:32:05 2020 +0200 fix spelling commit 6feba9c5725379fe2bc86a560bbec1edba4dad98 Author: Klemens Böswirth Date: Sat Oct 3 20:51:13 2020 +0200 Finish new documentation and extend release notes commit a026717a4c18f521c1e2d70f0eef6b860fd5ee89 Author: Klemens Böswirth Date: Sat Oct 3 14:08:19 2020 +0200 Add Key Name documentation - Add a Python reference implementation - Start documentation README commit 6120185b74a9fc6dafd07bd82b11a858accac397 Author: Klemens Böswirth Date: Sat Oct 3 00:57:21 2020 +0200 ccode: fix oclint issue commit 495410c450b4c46399c6cf5367f5ff513abbbd71 Author: Klemens Böswirth Date: Fri Oct 2 20:34:50 2020 +0200 fix bug in keyname validation commit 06162908dabdb6990a5297045b7a97c8436a00ee Author: Klemens Böswirth Date: Fri Oct 2 18:36:12 2020 +0200 ccode: fix en-/decoding bug commit abe9dd76b02acc041eb06725fc1d914d0906b2c4 Author: Klemens Böswirth Date: Fri Oct 2 15:41:35 2020 +0200 Update shell test data commit 8b471253b2f4cf721d881e49b1fc1092c9d824b3 Author: Klemens Böswirth Date: Tue Sep 29 20:21:29 2020 +0200 Update release notes commit f90ec817965b86402743583c0f7af9cd31338707 Author: Klemens Böswirth Date: Tue Sep 29 20:11:44 2020 +0200 fix swig compile flags commit 4403f12c5afa34f84fca3ac98f4cb4fb4251c995 Author: Klemens Böswirth Date: Mon Sep 28 20:13:22 2020 +0200 Update Keynames proposal commit 76c552950c5735a76052ed01a41fd6b47d90cb2b Author: Klemens Böswirth Date: Wed Sep 23 20:19:30 2020 +0200 update some bits of the C++ binding commit 6edcb87717110c7ebe938e4e34012dde44aa4ae1 Author: Klemens Böswirth Date: Wed Sep 23 18:53:56 2020 +0200 update TODOs commit f42102b7c7241fc7e0db5f534b939a531a6c76a1 Author: Klemens Böswirth Date: Wed Sep 23 18:29:12 2020 +0200 remove various deprecated things commit 3a63e42db6247d9cf05c3a12304c9fc03b9ffe82 Author: Klemens Böswirth Date: Wed Sep 23 18:12:56 2020 +0200 fix website build commit 151f7700b55e3844c812178249af4f9375443c19 Author: Klemens Böswirth Date: Wed Sep 23 00:53:18 2020 +0200 fix oclint errors commit bb90d375ecc887213e0baefe33ba43201e39272e Author: Klemens Böswirth Date: Tue Sep 22 23:38:20 2020 +0200 fix oclint errors commit e5a06110536b8fd059407a981bc67ab4bc4419d8 Author: Klemens Böswirth Date: Tue Sep 22 22:28:17 2020 +0200 fix oclint errors (again) commit b9a5021df3ddcdb0f15b633ecf8760cbbbd82f95 Author: Klemens Böswirth Date: Tue Sep 22 22:21:38 2020 +0200 Revert "Revert "adapt ruby code to work with ruby 2.3"" This reverts commit 2e8f936b31de5dd54342661e97390db5b9243347. commit 25a788e2910b85c003b9f95662465eea6da9e43f Author: Klemens Böswirth Date: Tue Sep 22 22:21:35 2020 +0200 Revert "fix oclint errors" This reverts commit 8703b056b1f48fd12bcbdfdec9b865ef8638b2cc. commit 5865fa60c6e27abb1f4b731fc3303d3d1bec22eb Author: Klemens Böswirth Date: Tue Sep 22 22:21:32 2020 +0200 Revert "fix ccode" This reverts commit ffebe183af9b1a3f8e28d5c6660f60678951f9de. commit 7e7de6897a9c4122af3415142b16cce213eb8b9f Author: Klemens Böswirth Date: Tue Sep 22 21:37:04 2020 +0200 Revert "adapt ruby code to work with ruby 2.3" This reverts commit eebd51a6342fecea0ac9b5d55909235525e4d444. commit 4703b86df808f2339942e9e58a4193ffffd1f292 Author: Klemens Böswirth Date: Tue Sep 22 21:02:52 2020 +0200 adapt ruby code to work with ruby 2.3 commit ca687a92fe52585a3d5dc68572e7ff1a43729f83 Author: Klemens Böswirth Date: Tue Sep 22 20:57:08 2020 +0200 fix ccode commit d54ed1acd10b4f9fc158d931eb19b53952cc6c41 Author: Klemens Böswirth Date: Tue Sep 22 20:54:09 2020 +0200 fix oclint errors commit 8eb97171c7ef6aaebb531c94712a8c0a38b7947a Author: Klemens Böswirth Date: Tue Sep 22 18:50:29 2020 +0200 fix JNA keyCmp commit 2c1850e42a8fc4690ea2f5e6af3781bc689ae976 Author: Klemens Böswirth Date: Tue Sep 22 18:09:55 2020 +0200 remove TODO commit b6894d4031d460e19ed77892661059bcf3ff9109 Author: Klemens Böswirth Date: Tue Sep 22 18:03:51 2020 +0200 fix disabled pythongen commit 291ddedb09370de5d01ee131e748475615377c78 Author: Klemens Böswirth Date: Tue Sep 22 18:01:29 2020 +0200 remove debian-stretch-full-ini Jenkins job commit e8e6d4bf2df8a38b44a5674abe0a1ff0d848014c Author: Klemens Böswirth Date: Tue Sep 22 18:00:05 2020 +0200 add ELEKTRA_NO_SANITIZE_ADDRESS for gcc commit 0e7890c0ce335e8b909d3d058e53a5e4f9ff63fd Author: Klemens Böswirth Date: Tue Sep 22 17:55:31 2020 +0200 fully disable pythongen commit 85d7224a74c2f1fd25075677694aac847d09609a Author: Klemens Böswirth Date: Tue Sep 22 17:50:12 2020 +0200 disable more santizers in opmphmHashfunction commit 63c29cafc0a76e42cce66d738581e837f286b0ff Author: Klemens Böswirth Date: Sun Sep 20 22:22:19 2020 +0200 fix kdb gen commit 1e47869c78ef80286208892584ab1d574b5eaa85 Author: Klemens Böswirth Date: Sun Sep 20 22:08:29 2020 +0200 update man page commit be60437930ab4f65d592a449726f4649f48c30f7 Author: Klemens Böswirth Date: Sun Sep 20 21:52:59 2020 +0200 fix more keynames commit 6d9be2358fff3f6b9a3ee8552c542e49f2f92345 Author: Klemens Böswirth Date: Sun Sep 20 21:22:40 2020 +0200 fix .gitignore and add missing files commit 74d72293d049399ed2845dee38eaf34ef8c6015f Author: Klemens Böswirth Date: Sun Sep 20 21:07:26 2020 +0200 fix javascript formatting commit e59e9a52818fb099a8a146960f9eff9be936346b Author: Klemens Böswirth Date: Sun Sep 20 20:50:02 2020 +0200 update some files missed in rebase commit d0102d7ecae7fbb915a1650062ddb4bdcb19f64a Author: Klemens Böswirth Date: Sun Sep 20 20:00:58 2020 +0200 remove some files commit c9f0b99301a0f879cd0982ef4627ad6dc4b26bd4 Author: Klemens Böswirth Date: Sun Sep 20 20:00:28 2020 +0200 Revert "undo changes to kdb-global-umount test" This reverts commit 371695931d2b5ad16c505f022ceab580adb0088c. commit 6521996a820ecaf6dca7100bfa6ff4e3e537af45 Author: Klemens Böswirth Date: Sun Sep 20 19:15:11 2020 +0200 fix testcpp_contextual_update commit 350ad2533479a8048837ad894d2c8589fb2a122e Author: Klemens Böswirth Date: Sun Sep 20 18:48:43 2020 +0200 undo changes to kdb-global-umount test commit 8390278048bfb0e2e9e2ae8f36a5f3bea706c100 Author: Klemens Böswirth Date: Sun Sep 20 18:21:55 2020 +0200 update TODOs commit 529c2ec7ae2bf23ec67b6d8ecc1a8165c6211995 Author: Klemens Böswirth Date: Sun Sep 20 18:02:11 2020 +0200 fix kdb-global-umount commit d93027f56ae97e3de815e9ceccef7eee2d278e68 Author: Klemens Böswirth Date: Sun Sep 20 17:27:35 2020 +0200 fix various memory problems commit 1bf60ee2af90e98bf805672f8f0139505b8fd633 Author: Klemens Böswirth Date: Sat Sep 5 16:57:55 2020 +0200 java: fix after keyname overhaul commit 33c2c536f65a6b400f9bcbc08be34ee8e4dc9eba Author: Klemens Böswirth Date: Sat Sep 5 16:35:51 2020 +0200 fix formatting commit 0486d043d70ada5ed7ff48cb2ff93619033282b3 Author: Klemens Böswirth Date: Sat May 30 14:34:43 2020 +0200 Keyname overhaul Squashed version of 22ff913..3645f79 --- .github/ISSUE_TEMPLATE.md | 12 +- .gitignore | 1 + Testing/Temporary/CTestCostData.txt | 1 + Testing/Temporary/LastTest.log | 3 + benchmarks/benchmarks.c | 2 +- benchmarks/benchmarks.h | 2 +- benchmarks/kdb.c | 4 +- benchmarks/memoryleak.c | 2 +- benchmarks/opmphm.c | 6 +- benchmarks/plugingetset.c | 4 +- benchmarks/storage.c | 4 +- doc/METADATA.ini | 2 +- doc/TESTING.md | 14 +- doc/VERSION.md | 10 +- doc/VISION.md | 28 +- doc/decisions/bootstrap.md | 13 +- doc/decisions/global_validation.md | 4 +- doc/decisions/plugin_variants.md | 72 +- doc/dev/algorithm.md | 44 +- doc/dev/architecture.md | 66 +- doc/dev/data-structures.md | 22 +- doc/dev/error-handling.md | 4 +- doc/dev/error-message.md | 2 +- doc/dev/plugins-framework.md | 16 +- doc/help/elektra-bootstrapping.md | 8 +- doc/help/elektra-cascading.md | 2 +- doc/help/elektra-granularity.md | 6 +- doc/help/elektra-hierarchy.md | 16 +- doc/help/elektra-key-names.md | 26 +- doc/help/elektra-spec.md | 4 +- doc/help/kdb-cache.md | 2 +- doc/help/kdb-cmerge.md | 16 +- doc/help/kdb-complete.md | 38 +- doc/help/kdb-cp.md | 38 +- doc/help/kdb-editor.md | 4 +- doc/help/kdb-export.md | 22 +- doc/help/kdb-file.md | 2 +- doc/help/kdb-find.md | 30 +- doc/help/kdb-get.md | 36 +- doc/help/kdb-global-mount.md | 2 +- doc/help/kdb-global-umount.md | 4 +- doc/help/kdb-help.md | 2 +- doc/help/kdb-import.md | 32 +- doc/help/kdb-install-config-file.md | 2 +- doc/help/kdb-ls.md | 56 +- doc/help/kdb-merge.md | 6 +- doc/help/kdb-meta-get.md | 8 +- doc/help/kdb-meta-rm.md | 2 +- doc/help/kdb-meta-set.md | 10 +- doc/help/kdb-meta-show.md | 18 +- doc/help/kdb-mount-list-all-files.md | 12 +- doc/help/kdb-mount.md | 10 +- doc/help/kdb-mountpoint-info.md | 6 +- doc/help/kdb-mv.md | 4 +- doc/help/kdb-plugin-info.md | 4 +- doc/help/kdb-remount.md | 4 +- doc/help/kdb-reset-elektra.md | 4 +- doc/help/kdb-rm.md | 10 +- doc/help/kdb-set.md | 10 +- doc/help/kdb-sget.md | 2 +- doc/help/kdb-spec-mount.md | 12 +- doc/help/kdb-stash.md | 28 +- doc/help/kdb-test.md | 6 +- doc/help/kdb.md | 12 +- doc/keynames/README.md | 473 +++++ doc/keynames/keynames.py | 470 +++++ doc/keynames/new_api.py | 1113 ++++++++++++ doc/keynames/tree.svg | 43 + doc/man/man1/kdb-backup.1 | 2 +- doc/man/man1/kdb-cache.1 | 4 +- doc/man/man1/kdb-change-resolver-symlink.1 | 2 +- doc/man/man1/kdb-change-storage-symlink.1 | 2 +- doc/man/man1/kdb-check-env-dep.1 | 2 +- doc/man/man1/kdb-cmerge.1 | 18 +- doc/man/man1/kdb-complete.1 | 40 +- doc/man/man1/kdb-convert.1 | 2 +- doc/man/man1/kdb-cp.1 | 40 +- doc/man/man1/kdb-editor.1 | 6 +- doc/man/man1/kdb-elektrify-getenv.1 | 50 +- doc/man/man1/kdb-export.1 | 22 +- doc/man/man1/kdb-file.1 | 4 +- doc/man/man1/kdb-find-tools.1 | 2 +- doc/man/man1/kdb-find.1 | 32 +- doc/man/man1/kdb-gen-highlevel.1 | 2 +- doc/man/man1/kdb-gen.1 | 2 +- doc/man/man1/kdb-get.1 | 38 +- doc/man/man1/kdb-global-mount.1 | 4 +- doc/man/man1/kdb-global-umount.1 | 6 +- doc/man/man1/kdb-help.1 | 4 +- doc/man/man1/kdb-import.1 | 34 +- doc/man/man1/kdb-install-config-file.1 | 4 +- doc/man/man1/kdb-list-commands.1 | 2 +- doc/man/man1/kdb-list-tools.1 | 2 +- doc/man/man1/kdb-ls.1 | 56 +- doc/man/man1/kdb-merge.1 | 8 +- doc/man/man1/kdb-meta-get.1 | 10 +- doc/man/man1/kdb-meta-ls.1 | 2 +- doc/man/man1/kdb-meta-rm.1 | 4 +- doc/man/man1/kdb-meta-set.1 | 12 +- doc/man/man1/kdb-meta-show.1 | 20 +- doc/man/man1/kdb-mount-list-all-files.1 | 14 +- doc/man/man1/kdb-mount.1 | 12 +- doc/man/man1/kdb-mountpoint-info.1 | 8 +- doc/man/man1/kdb-mv.1 | 6 +- doc/man/man1/kdb-plugin-check.1 | 2 +- doc/man/man1/kdb-plugin-info.1 | 6 +- doc/man/man1/kdb-plugin-list.1 | 2 +- doc/man/man1/kdb-remount.1 | 6 +- doc/man/man1/kdb-reset-elektra.1 | 6 +- doc/man/man1/kdb-reset.1 | 2 +- doc/man/man1/kdb-restore.1 | 2 +- doc/man/man1/kdb-rm.1 | 12 +- doc/man/man1/kdb-run-website.1 | 2 +- doc/man/man1/kdb-set.1 | 12 +- doc/man/man1/kdb-sget.1 | 4 +- doc/man/man1/kdb-shell.1 | 2 +- doc/man/man1/kdb-spec-mount.1 | 14 +- doc/man/man1/kdb-stash.1 | 30 +- doc/man/man1/kdb-test.1 | 8 +- doc/man/man1/kdb-umount-all.1 | 2 +- doc/man/man1/kdb-umount.1 | 2 +- doc/man/man1/kdb.1 | 14 +- doc/man/man7/elektra-backends.7 | 2 +- doc/man/man7/elektra-bootstrapping.7 | 8 +- doc/man/man7/elektra-cascading.7 | 4 +- doc/man/man7/elektra-cmerge-strategy.7 | 2 +- doc/man/man7/elektra-contracts.7 | 2 +- doc/man/man7/elektra-granularity.7 | 4 +- doc/man/man7/elektra-hierarchy.7 | 18 +- doc/man/man7/elektra-highlevel-gen.7 | 2 +- doc/man/man7/elektra-introduction.7 | 2 +- doc/man/man7/elektra-key-names.7 | 22 +- doc/man/man7/elektra-merge-strategy.7 | 2 +- doc/man/man7/elektra-metadata.7 | 2 +- doc/man/man7/elektra-mounting.7 | 2 +- doc/man/man7/elektra-related.7 | 2 +- doc/man/man7/elektra-semantics.7 | 2 +- doc/man/man7/elektra-spec.7 | 6 +- doc/man/man7/elektra-sync-flag.7 | 2 +- doc/man/man7/elektra-values.7 | 2 +- doc/news/_preparation_next_release.md | 22 +- doc/proposals/keynames.md | 649 +++++++ doc/todo/FUTURE | 3 - doc/todo/MARKETING | 30 +- doc/todo/PLUGINS | 8 +- doc/todo/PROPOSALS | 0 doc/todo/RELEASE | 18 +- doc/todo/TESTING | 8 +- doc/todo/TOOLS | 8 +- doc/tutorials/application-integration.md | 10 +- doc/tutorials/arrays.md | 70 +- doc/tutorials/cascading.md | 40 +- doc/tutorials/cmerge.md | 96 +- doc/tutorials/code-generator.md | 12 +- doc/tutorials/command-line-options.md | 24 +- doc/tutorials/crypto.md | 84 +- doc/tutorials/export.md | 16 +- doc/tutorials/hello-elektra.md | 2 +- doc/tutorials/highlevel.md | 2 +- doc/tutorials/import.md | 34 +- doc/tutorials/install-config-files.md | 30 +- doc/tutorials/install-webui.md | 14 +- doc/tutorials/java-kdb.md | 20 +- doc/tutorials/merge.md | 22 +- doc/tutorials/mount.md | 50 +- doc/tutorials/namespaces.md | 68 +- doc/tutorials/plugins.md | 28 +- doc/tutorials/python-kdb.md | 6 +- doc/tutorials/storage-plugins.md | 148 +- doc/tutorials/validation.md | 92 +- examples/cascading.c | 8 +- examples/codegen/econf/README.md | 4 +- examples/codegen/econf/cmake/CMakeLists.txt | 2 +- examples/codegen/econf/pkgconfig/Makefile | 2 +- examples/codegen/menu/README.md | 12 +- examples/codegen/menu/cmake/CMakeLists.txt | 2 +- examples/codegen/menu/pkgconfig/Makefile | 2 +- examples/codegen/tree/README.md | 4 +- examples/codegen/tree/cmake/CMakeLists.txt | 2 +- examples/codegen/tree/pkgconfig/Makefile | 2 +- examples/external/cmake/application.c | 4 +- .../src/main/java/org/libelektra/app/App.java | 2 +- examples/external/pkgconfig/application.c | 4 +- examples/functional.c | 20 +- examples/gopts.c | 6 +- examples/hello.c | 2 +- examples/helloElektra.c | 4 +- examples/hierarchy.xml | 14 +- examples/highlevel/README.md | 4 +- examples/iterate.c | 32 +- examples/kdbget_error.c | 38 +- examples/kdbset.c | 4 +- examples/keyBasename.c | 12 +- examples/keyCopy.c | 4 +- examples/keyMeta.c | 6 +- examples/keyMetaKeySet.c | 2 +- examples/keyName.c | 8 +- examples/keyNew.c | 20 +- examples/keyNewExample.c | 40 +- examples/keyset.c | 10 +- examples/keyset.xml | 30 +- examples/ksCut.c | 2 +- examples/ksIterate.c | 2 +- examples/ksNew.c | 16 +- examples/ksNewExample.c | 4 +- examples/meta.c | 4 +- examples/namespace.c | 8 +- examples/opts.c | 2 +- examples/reference.c | 8 +- examples/set_key.c | 26 +- examples/spec/openicc.ini | 2 +- scripts/admin/update-snippet-repository | 2 +- scripts/benchmark-createtree | 2 +- scripts/benchmark_augeas_hosts.sh | 8 +- scripts/cmake/Modules/LibAddMacros.cmake | 34 +- scripts/completion/kdb.fish | 2 +- scripts/configure-firefox.in | 4 +- scripts/docker/webui/elektrad-demo/Dockerfile | 22 +- .../docker/webui/elektrad-demo/realworld.ini | 12 +- scripts/docker/webui/webd-demo/Dockerfile | 2 +- scripts/kdb/backup.in | 6 +- scripts/kdb/cmerge-config-files | 8 +- scripts/kdb/install-config-file | 6 +- scripts/kdb/mount-augeas | 16 +- scripts/kdb/mount-info | 2 +- scripts/kdb/mount-kde | 2 +- scripts/kdb/mount-list-all-files | 4 +- scripts/kdb/mountpoint-info | 12 +- scripts/release/get-installed-version.sh | 2 +- scripts/release/release.sh | 16 +- scripts/reset | 6 +- scripts/reset-elektra | 2 +- scripts/sed | 4 +- scripts/start-ssh-agent | 4 +- scripts/umount-all | 4 +- scripts/upgrade-bootstrap | 16 +- .../cpp/benchmarks/benchmark_sync.cpp | 8 +- .../cpp/benchmarks/benchmark_thread.cpp | 32 +- src/bindings/cpp/examples/cpp_example_dup.cpp | 4 +- .../cpp/examples/cpp_example_hello.cpp | 2 +- .../cpp/examples/cpp_example_hierarchy.cpp | 20 +- src/bindings/cpp/examples/cpp_example_io.cpp | 2 +- .../cpp/examples/cpp_example_iter.cpp | 2 +- .../cpp/examples/cpp_example_iter_name.cpp | 2 +- src/bindings/cpp/examples/cpp_example_ks.cpp | 2 +- .../cpp/examples/cpp_example_ordering.cpp | 14 +- src/bindings/cpp/examples/cpp_example_set.cpp | 2 +- .../examples/cpp_example_userexception.cpp | 5 + .../cpp/examples/cpp_example_userio.cpp | 51 +- src/bindings/cpp/include/kdbio.hpp | 49 +- src/bindings/cpp/include/kdbvalue.hpp | 13 +- src/bindings/cpp/include/key.hpp | 99 +- src/bindings/cpp/include/keyexcept.hpp | 16 +- src/bindings/cpp/include/keysetget.hpp | 8 +- .../cpp/tests/testcpp_contextual_basic.cpp | 706 ++++---- .../cpp/tests/testcpp_contextual_policy.cpp | 16 +- .../cpp/tests/testcpp_contextual_thread.cpp | 60 +- .../cpp/tests/testcpp_contextual_update.cpp | 405 ++--- src/bindings/cpp/tests/testcpp_iter.cpp | 298 +-- src/bindings/cpp/tests/testcpp_iter_name.cpp | 136 +- src/bindings/cpp/tests/testcpp_kdb.cpp | 26 +- src/bindings/cpp/tests/testcpp_key.cpp | 435 ++--- src/bindings/cpp/tests/testcpp_keyio.cpp | 16 +- src/bindings/cpp/tests/testcpp_ks.cpp | 338 ++-- src/bindings/cpp/tests/testcpp_ksget.cpp | 32 +- src/bindings/cpp/tests/testcpp_meta.cpp | 8 +- src/bindings/cpp/tests/tests.hpp | 24 +- src/bindings/glib/gelektra-key.c | 34 +- src/bindings/glib/gelektra-key.h | 2 - src/bindings/glib/tests/testglib_kdb.c | 10 +- src/bindings/glib/tests/testglib_key.c | 56 +- src/bindings/glib/tests/testglib_keyset.c | 20 +- .../gsettings/elektrasettingsbackend.c | 4 +- src/bindings/intercept/env/README.md | 52 +- .../env/benchmarks/benchmark_getenv.cpp | 14 +- src/bindings/intercept/env/src/getenv.cpp | 20 +- .../intercept/env/tests/test_context.cpp | 104 +- .../intercept/env/tests/test_getenv.cpp | 22 +- src/bindings/intercept/fs/README.md | 4 +- src/bindings/jna/HelloElektra.java | 8 +- src/bindings/jna/README.md | 10 +- .../src/main/java/org/libelektra/Elektra.java | 6 - .../src/main/java/org/libelektra/Key.java | 12 +- .../mapper/ExceptionMapperService.java | 2 +- .../exception/model/WarningEntry.java | 8 +- .../org/libelektra/plugin/NativePlugin.java | 2 +- .../libelektra/plugin/PropertiesStorage.java | 2 +- .../org/libelektra/ExceptionMapperIT.java | 26 +- .../org/libelektra/ExceptionMapperTest.java | 2 +- .../java/org/libelektra/KDBExceptionTest.java | 6 +- .../src/test/java/org/libelektra/KDBTest.java | 6 +- .../src/test/java/org/libelektra/KeyTest.java | 12 +- .../exception/model/WarningEntryTest.java | 20 +- src/bindings/rust/README.md | 14 +- src/bindings/rust/elektra-sys/src/lib.rs | 6 +- src/bindings/rust/elektra/src/kdb.rs | 6 +- src/bindings/rust/elektra/src/key.rs | 71 +- src/bindings/rust/elektra/src/keybuilder.rs | 16 +- src/bindings/rust/elektra/src/keyset.rs | 92 +- src/bindings/rust/elektra/src/readable.rs | 67 +- src/bindings/rust/elektra/src/writeable.rs | 33 +- src/bindings/rust/example/src/bin/kdb.rs | 6 +- src/bindings/rust/example/src/bin/key.rs | 6 +- src/bindings/rust/example/src/bin/keyset.rs | 8 +- src/bindings/swig/CMakeLists.txt | 2 +- src/bindings/swig/common.i | 1 - .../swig/lua/examples/example_kdb.lua | 8 +- .../swig/lua/examples/example_key.lua | 4 +- .../swig/lua/examples/example_keyset.lua | 12 +- .../swig/lua/examples/example_loadstring.lua | 4 +- src/bindings/swig/lua/kdb.i | 2 - src/bindings/swig/lua/tests/test_kdb.lua | 6 +- src/bindings/swig/lua/tests/test_key.lua | 56 +- src/bindings/swig/lua/tests/test_keyset.lua | 34 +- .../swig/python/examples/example_gopts.py | 8 +- .../swig/python/examples/example_kdb.py | 8 +- .../swig/python/examples/example_key.py | 4 +- .../swig/python/examples/example_keyset.py | 12 +- src/bindings/swig/python/kdb.i | 3 - src/bindings/swig/python/tests/test_kdb.py | 10 +- src/bindings/swig/python/tests/test_key.py | 91 +- src/bindings/swig/python/tests/test_keyset.py | 92 +- .../tests_tools/test_tools_backendparser.py | 2 +- .../python/tests_tools/test_tools_modules.py | 2 +- .../tests_tools/test_tools_pluginspec.py | 4 +- .../tests_tools/test_tools_specreader.py | 2 +- .../swig/python2/tests/testpy2_kdb.py | 0 src/bindings/swig/ruby/README.md | 14 +- .../ruby/examples/ruby_example_application.rb | 2 +- .../swig/ruby/examples/ruby_example_keys.rb | 12 +- .../swig/ruby/examples/ruby_example_keyset.rb | 38 +- .../swig/ruby/examples/tools/kdb_simple.rb | 10 +- src/bindings/swig/ruby/kdb.i | 7 +- src/bindings/swig/ruby/kdb.rb | 2 +- src/bindings/swig/ruby/tests/testruby_kdb.rb | 10 +- src/bindings/swig/ruby/tests/testruby_key.rb | 145 +- .../swig/ruby/tests/testruby_keyset.rb | 216 +-- .../swig/ruby/tests/testruby_tools_modules.rb | 2 +- .../ruby/tests/testruby_tools_pluginspec.rb | 4 +- .../ruby/tests/testruby_tools_specreader.rb | 4 +- src/include/CMakeLists.txt | 4 +- src/include/kdb.h.in | 25 +- src/include/kdbconfig.h.in | 5 +- src/include/kdbextension.h | 1 - src/include/kdbhelper.h | 2 +- src/include/kdbinternal.h | 2 - src/include/kdbmeta.h | 2 +- src/include/kdbobsolete.h | 19 - src/include/kdbprivate.h | 54 +- src/include/kdbproposal.h | 3 - src/include/kdbversion.h.in | 24 +- src/libs/ease/array.c | 43 +- src/libs/ease/keyname.c | 8 +- src/libs/ease/reference.c | 2 +- src/libs/elektra/backend.c | 40 +- src/libs/elektra/errors.c | 69 +- src/libs/elektra/internal.c | 411 +---- src/libs/elektra/kdb.c | 106 +- src/libs/elektra/kdbenum.c | 24 +- src/libs/elektra/key.c | 262 +-- src/libs/elektra/keyhelpers.c | 157 -- src/libs/elektra/keymeta.c | 33 +- src/libs/elektra/keyname.c | 1613 ++++++++++++----- src/libs/elektra/keyset.c | 236 +-- src/libs/elektra/keytest.c | 164 +- src/libs/elektra/keyvalue.c | 6 +- src/libs/elektra/mount.c | 174 +- src/libs/elektra/opmphm.c | 2 + src/libs/elektra/owner.c | 17 +- src/libs/elektra/plugin.c | 6 +- src/libs/elektra/split.c | 95 +- src/libs/elektra/symbols.map | 24 +- src/libs/elektra/trie.c | 22 +- src/libs/highlevel/elektra.c | 30 +- src/libs/invoke/invoke.c | 6 +- src/libs/loader/dl.c | 8 +- src/libs/loader/doc.c | 4 +- src/libs/loader/static.c | 4 +- src/libs/merge/kdbmerge.c | 2 +- src/libs/meta/meta.c | 37 +- src/libs/notification/notification.c | 16 +- .../notification/tests/testlib_notification.c | 10 +- src/libs/opts/opts.c | 70 +- src/libs/plugin/plugin.c | 4 +- src/libs/pluginprocess/pluginprocess.c | 2 +- .../tests/testlib_pluginprocess.c | 54 +- .../tools/benchmarks/benchmark_plugins.cpp | 8 +- src/libs/tools/examples/merging.cpp | 8 +- src/libs/tools/include/backendbuilder.hpp | 2 +- src/libs/tools/include/backendparser.hpp | 2 +- src/libs/tools/include/plugindatabase.hpp | 34 +- src/libs/tools/include/toolexcept.hpp | 2 +- src/libs/tools/src/backend.cpp | 75 +- src/libs/tools/src/backendbuilder.cpp | 19 +- src/libs/tools/src/backends.cpp | 24 +- src/libs/tools/src/helper/keyhelper.cpp | 37 +- src/libs/tools/src/merging/mergeresult.cpp | 4 +- .../tools/src/merging/metamergestrategy.cpp | 6 +- src/libs/tools/src/merging/threewaymerge.cpp | 4 +- src/libs/tools/src/modules.cpp | 2 +- src/libs/tools/src/plugin.cpp | 14 +- src/libs/tools/src/plugindatabase.cpp | 35 +- src/libs/tools/src/plugins.cpp | 10 +- src/libs/tools/src/specreader.cpp | 13 +- src/libs/tools/tests/mergetestutils.cpp | 38 +- .../tests/testtool_automergestrategy.cpp | 18 +- src/libs/tools/tests/testtool_backend.cpp | 253 +-- .../tools/tests/testtool_backendbuilder.cpp | 38 +- .../tools/tests/testtool_backendparser.cpp | 70 +- src/libs/tools/tests/testtool_comparison.cpp | 32 +- src/libs/tools/tests/testtool_keyhelper.cpp | 80 +- src/libs/tools/tests/testtool_mergecases.cpp | 32 +- src/libs/tools/tests/testtool_mergeresult.cpp | 26 +- src/libs/tools/tests/testtool_mergingkdb.cpp | 26 +- .../tests/testtool_metamergestrategy.cpp | 6 +- .../tools/tests/testtool_newkeystrategy.cpp | 8 +- .../tools/tests/testtool_onesidestrategy.cpp | 42 +- .../tools/tests/testtool_plugindatabase.cpp | 4 +- src/libs/tools/tests/testtool_pluginspec.cpp | 108 +- .../tools/tests/testtool_samemountpoint.cpp | 203 +-- src/libs/tools/tests/testtool_specreader.cpp | 110 +- src/libs/tools/tests/testtool_umount.cpp | 73 +- src/plugins/augeas/README.md | 26 +- src/plugins/augeas/aug.h | 1 - src/plugins/augeas/augeas.c | 88 +- src/plugins/augeas/contract.h | 24 +- src/plugins/augeas/testmod_augeas.c | 115 +- src/plugins/base64/README.md | 26 +- src/plugins/base64/base64.c | 2 +- src/plugins/base64/contract.h | 14 +- src/plugins/base64/testmod_base64.c | 6 +- src/plugins/blockresolver/README.md | 42 +- src/plugins/blockresolver/blockresolver.c | 22 +- .../blockresolver/testmod_blockresolver.c | 16 +- src/plugins/c/README.md | 2 +- src/plugins/c/c.c | 20 +- src/plugins/cache/cache.c | 34 +- src/plugins/cache/shelltests.md | 184 +- src/plugins/cache/testmod_cache.c | 10 +- src/plugins/ccode/ccode.cpp | 16 +- src/plugins/ccode/coder.cpp | 23 +- src/plugins/ccode/testmod_ccode.cpp | 42 +- src/plugins/conditionals/README.md | 36 +- src/plugins/conditionals/conditionals.c | 13 +- .../conditionals/testmod_conditionals.c | 312 ++-- src/plugins/constants/README.md | 142 +- src/plugins/constants/constants.c.in | 15 +- src/plugins/counter/counter.c | 18 +- src/plugins/cpptemplate/README.md | 16 +- src/plugins/cpptemplate/cpptemplate.cpp | 20 +- .../cpptemplate/testmod_cpptemplate.cpp | 2 +- src/plugins/crypto/README.md | 18 +- src/plugins/crypto/common_gpg_tests.c | 2 +- src/plugins/crypto/contract.h | 29 +- src/plugins/crypto/crypto.c | 6 +- src/plugins/crypto/gcrypt_operations.c | 4 +- src/plugins/crypto/gpg.c | 10 +- src/plugins/crypto/testmod_crypto.c | 30 +- src/plugins/csvstorage/README.md | 82 +- src/plugins/csvstorage/csvstorage.c | 12 +- src/plugins/csvstorage/testmod_csvstorage.c | 86 +- src/plugins/curlget/README.md | 34 +- src/plugins/curlget/curlget.c | 23 +- src/plugins/date/date.c | 14 +- src/plugins/date/testmod_date.c | 12 +- src/plugins/dbus/README.md | 6 +- src/plugins/dbus/dbus.c | 16 +- src/plugins/dbus/testmod_dbus.c | 4 +- src/plugins/dbusrecv/dbusrecv.c | 20 +- src/plugins/dbusrecv/testmod_dbusrecv.c | 8 +- src/plugins/desktop/README.md | 4 +- src/plugins/desktop/desktop.c | 12 +- src/plugins/directoryvalue/README.md | 124 +- src/plugins/directoryvalue/directoryvalue.cpp | 16 +- .../directoryvalue_delegate.cpp | 4 +- .../directoryvalue/testmod_directoryvalue.cpp | 4 +- src/plugins/doc/doc.c | 26 +- src/plugins/doc/doc.h | 4 +- src/plugins/dpkg/README.md | 4 +- src/plugins/dpkg/dpkg.c | 12 +- src/plugins/dump/README.md | 6 +- src/plugins/dump/dump.cpp | 62 +- src/plugins/dump/dump/v2/fullnames.dump | 20 +- src/plugins/dump/testdata.h | 43 +- src/plugins/dump/testmod_dump.c | 98 +- src/plugins/error/README.md | 8 +- src/plugins/error/error.c | 14 +- src/plugins/fcrypt/README.md | 2 +- src/plugins/fcrypt/contract.h | 21 +- src/plugins/fcrypt/fcrypt.c | 2 +- src/plugins/fcrypt/testmod_fcrypt.c | 12 +- src/plugins/file/README.md | 12 +- src/plugins/file/file.c | 12 +- src/plugins/file/testmod_file.c | 18 +- src/plugins/filecheck/filecheck.c | 16 +- src/plugins/filecheck/testmod_filecheck.c | 24 +- src/plugins/fstab/README.md | 6 +- src/plugins/fstab/fstab.c | 30 +- src/plugins/fstab/testmod_fstab.c | 40 +- src/plugins/gitresolver/README.md | 2 +- src/plugins/gitresolver/gitresolver.c | 23 +- src/plugins/glob/README.md | 4 +- src/plugins/glob/contract.h | 16 +- src/plugins/glob/glob.c | 14 +- src/plugins/glob/testmod_glob.c | 103 +- src/plugins/gopts/README.md | 6 +- src/plugins/gopts/gopts.c | 18 +- src/plugins/gopts/testapp.c | 2 +- src/plugins/gopts/testdata.h | 19 +- src/plugins/gpgme/README.md | 12 +- src/plugins/gpgme/contract.h | 16 +- src/plugins/gpgme/gpgme.c | 2 +- src/plugins/gpgme/testmod_gpgme.c | 14 +- src/plugins/hexcode/hexcode.c | 16 +- src/plugins/hexcode/testmod_hexcode.c | 14 +- src/plugins/hexnumber/README.md | 30 +- src/plugins/hexnumber/hexnumber.c | 29 +- src/plugins/hexnumber/testmod_hexnumber.c | 26 +- src/plugins/hidden/CMakeLists.txt | 3 - src/plugins/hidden/README.md | 14 - src/plugins/hidden/hidden.c | 86 - src/plugins/hidden/hidden.h | 22 - src/plugins/hosts/README.md | 10 +- src/plugins/hosts/contract.h | 26 +- src/plugins/hosts/hosts-get.c | 3 +- src/plugins/hosts/hosts-set.c | 6 +- src/plugins/hosts/keymetaformatting.c | 6 +- src/plugins/hosts/testmod_hosts.c | 80 +- src/plugins/iconv/README.md | 14 +- src/plugins/iconv/data_latin1.c | 10 +- src/plugins/iconv/data_utf8.c | 10 +- src/plugins/iconv/iconv.c | 12 +- src/plugins/iconv/testmod_iconv.c | 12 +- src/plugins/internalnotification/README.md | 2 +- .../internalnotification.c | 24 +- .../internalnotification.h | 2 +- .../macros/create_type_tests.h | 4 +- .../testmod_internalnotification.c | 44 +- src/plugins/ipaddr/ipaddr.c | 12 +- src/plugins/ipaddr/test_ipaddr.h | 4 +- src/plugins/iterate/iterate.c | 18 +- src/plugins/iterate/testmod_iterate.c | 4 +- src/plugins/jni/jni.c | 18 +- src/plugins/jni/testmod_jni.c | 6 +- src/plugins/journald/journald.c | 14 +- src/plugins/kconfig/README.md | 7 +- src/plugins/kconfig/kconfig.cpp | 24 +- src/plugins/kconfig/kconfig_serializer.hpp | 4 +- src/plugins/kconfig/testmod_kconfig.cpp | 2 +- src/plugins/keytometa/README.md | 58 +- src/plugins/keytometa/contract.h | 14 +- src/plugins/keytometa/keytometa.c | 2 +- src/plugins/keytometa/keytometa.h | 1 - src/plugins/keytometa/testmod_keytometa.c | 130 +- src/plugins/line/README.md | 4 +- src/plugins/line/line.c | 13 +- src/plugins/line/testmod_line.c | 8 +- src/plugins/lineendings/lineendings.c | 12 +- src/plugins/lineendings/testmod_lineendings.c | 8 +- src/plugins/list/addPluginTest.c | 49 +- src/plugins/list/list.c | 55 +- src/plugins/list/testmod_list.c | 38 +- src/plugins/logchange/README.md | 2 +- src/plugins/logchange/logchange.c | 14 +- src/plugins/lua/lua.cpp | 2 +- src/plugins/lua/lua/batterytotracker.lua | 2 +- src/plugins/lua/lua/lua_filter.lua | 2 +- src/plugins/lua/lua/lua_plugin.lua | 4 +- src/plugins/lua/testmod_lua.c | 32 +- src/plugins/macaddr/README.md | 38 +- src/plugins/macaddr/macaddr.c | 12 +- src/plugins/macaddr/testmod_macaddr.c | 14 +- src/plugins/mathcheck/README.md | 42 +- src/plugins/mathcheck/mathcheck.c | 16 +- src/plugins/mathcheck/testmod_mathcheck.c | 26 +- src/plugins/mini/README.md | 82 +- src/plugins/mini/mini.c | 20 +- src/plugins/mini/testmod_mini.c | 6 +- src/plugins/mmapstorage/README.md | 38 +- src/plugins/mmapstorage/contract.h | 14 +- src/plugins/mmapstorage/mmapstorage.c | 35 +- src/plugins/mmapstorage/shelltests.md | 120 +- src/plugins/mmapstorage/testmod_mmapstorage.c | 33 +- .../mmapstorage/testmod_mmapstorage_crc.c | 2 +- src/plugins/mozprefs/README.md | 28 +- src/plugins/mozprefs/autoconfig/README.md | 28 +- src/plugins/mozprefs/mozprefs.c | 12 +- src/plugins/mozprefs/testmod_mozprefs.c | 20 +- src/plugins/multifile/README.md | 84 +- src/plugins/multifile/multifile.c | 27 +- src/plugins/network/README.md | 26 +- src/plugins/network/network.c | 14 +- src/plugins/network/testmod_network.c | 4 +- src/plugins/ni/README.md | 32 +- src/plugins/ni/ni.c | 12 +- src/plugins/noresolver/noresolver.c | 18 +- src/plugins/passwd/README.md | 4 +- src/plugins/passwd/passwd.c | 12 +- src/plugins/passwd/testmod_passwd.c | 30 +- src/plugins/path/README.md | 44 +- src/plugins/path/path.c | 12 +- src/plugins/process/README.md | 14 +- src/plugins/process/process.c | 20 +- src/plugins/process/testmod_process.c | 12 +- src/plugins/profile/README.md | 32 +- src/plugins/profile/profile.c | 34 +- src/plugins/python/python.cpp | 2 +- .../python/python/python_configparser.py | 2 +- src/plugins/python/python/python_filter.py | 2 +- src/plugins/python/python/python_plugin.py | 4 +- src/plugins/python/testmod_python.c | 42 +- src/plugins/quickdump/README.md | 44 +- src/plugins/quickdump/benchmarks.md | 2 +- src/plugins/quickdump/quickdump.c | 90 +- .../quickdump/quickdump/test.quickdump.h | 16 +- .../quickdump/quickdump/test.v1.quickdump | Bin 694 -> 0 bytes .../quickdump/quickdump/test.v2.quickdump | Bin 550 -> 0 bytes src/plugins/quickdump/readv1.c | 181 -- src/plugins/quickdump/readv2.c | 223 --- src/plugins/quickdump/testmod_quickdump.c | 130 +- src/plugins/range/range.c | 14 +- src/plugins/range/testmod_range.c | 28 +- src/plugins/reference/README.md | 28 +- .../reference/examples/alternative/README.md | 36 +- src/plugins/reference/reference.c | 12 +- src/plugins/reference/testmod_reference.c | 2 +- src/plugins/rename/README.md | 60 +- src/plugins/rename/contract.h | 12 +- src/plugins/rename/rename.c | 40 +- src/plugins/rename/testmod_rename.c | 152 +- src/plugins/resolver/README.md | 16 +- src/plugins/resolver/contract.h | 42 +- src/plugins/resolver/filename.c | 24 +- src/plugins/resolver/resolver.c | 18 +- src/plugins/resolver/testmod_resolver.c | 14 +- src/plugins/rgbcolor/README.md | 40 +- src/plugins/rgbcolor/rgbcolor.c | 12 +- src/plugins/rgbcolor/testmod_rgbcolor.c | 10 +- src/plugins/ruby/README.md | 4 +- src/plugins/ruby/ruby.cpp | 4 +- src/plugins/ruby/ruby/spec/shellvars_spec.rb | 4 +- src/plugins/ruby/testmod_ruby.c | 90 +- src/plugins/shell/README.md | 18 +- src/plugins/shell/shell.c | 14 +- src/plugins/simpleini/README.md | 6 +- src/plugins/simpleini/simpleini.c | 36 +- src/plugins/simpleini/testmod_simpleini.c | 10 +- src/plugins/spec/README.md | 12 +- src/plugins/spec/spec.c | 158 +- src/plugins/spec/testmod_spec.c | 166 +- src/plugins/specload/README.md | 24 +- src/plugins/specload/specload.c | 57 +- src/plugins/specload/testapp.c | 4 +- src/plugins/specload/testdata.h | 2 +- src/plugins/sync/README.md | 4 +- src/plugins/sync/sync.c | 12 +- src/plugins/syslog/syslog.c | 18 +- src/plugins/template/README.md | 6 +- src/plugins/template/template.c | 22 +- src/plugins/template/testmod_template.c | 2 +- src/plugins/timeofday/README.md | 6 +- src/plugins/timeofday/timeofday.c | 18 +- src/plugins/toml/README.md | 282 +-- src/plugins/toml/prepare.c | 4 +- src/plugins/toml/testmod_toml.c | 7 +- src/plugins/toml/toml.c | 12 +- src/plugins/toml/write.c | 2 +- src/plugins/tracer/README.md | 22 +- src/plugins/tracer/tracer.c | 18 +- src/plugins/type/README.md | 94 +- src/plugins/type/testmod_type.c | 298 +-- src/plugins/type/type.c | 22 +- src/plugins/type/types.c | 35 +- src/plugins/uname/README.md | 20 +- src/plugins/uname/testmod_uname.c | 14 +- src/plugins/uname/uname.c | 12 +- src/plugins/unit/testmod_unit.c | 16 +- src/plugins/unit/unit.c | 12 +- src/plugins/validation/lookupre.c | 12 +- src/plugins/validation/testmod_validation.c | 66 +- src/plugins/validation/validation.c | 14 +- src/plugins/wresolver/wresolver.c | 27 +- src/plugins/xerces/README.md | 32 +- src/plugins/xerces/deserializer.cpp | 17 +- src/plugins/xerces/serializer.cpp | 15 +- src/plugins/xerces/testmod_xerces.c | 16 +- src/plugins/xerces/xerces.cpp | 16 +- src/plugins/xmltool/README.md | 6 +- src/plugins/xmltool/kdbtools.c | 2 +- src/plugins/xmltool/kdbtools.h | 2 +- src/plugins/xmltool/kscompare.c | 164 +- src/plugins/xmltool/stream.c | 15 +- src/plugins/xmltool/testmod_xmltool.c | 76 +- src/plugins/xmltool/xmltool.c | 16 +- src/plugins/xmltool/xmltool.h | 2 +- src/plugins/xmltool/xmltool/dump.xml | 2 +- src/plugins/xmltool/xmltool/dump_keyset.xml | 2 +- src/plugins/xmltool/xmltool/filesys.xml | 2 +- src/plugins/xmltool/xmltool/fstab-cmp.xml | 14 +- src/plugins/xmltool/xmltool/fstab.xml | 2 +- src/plugins/xmltool/xmltool/hosts.xml | 2 +- src/plugins/xmltool/xmltool/key-cmp.xml | 18 +- src/plugins/xmltool/xmltool/key.xml | 2 +- src/plugins/xmltool/xmltool/keyset.xml | 2 +- src/plugins/xmltool/xmltool/passwd.xml | 2 +- src/plugins/yajl/README.md | 86 +- src/plugins/yajl/iterator.c | 50 +- src/plugins/yajl/name.c | 33 +- src/plugins/yajl/testmod_yajl.c | 290 +-- src/plugins/yajl/yajl_gen.c | 17 +- src/plugins/yajl/yajl_gen.h | 1 - src/plugins/yajl/yajl_gen_close.c | 68 +- src/plugins/yajl/yajl_gen_open.c | 86 +- src/plugins/yajl/yajl_parse.c | 20 +- src/plugins/yamlcpp/README.md | 330 ++-- src/plugins/yamlcpp/read.cpp | 8 +- src/plugins/yamlcpp/testmod_yamlcpp.cpp | 4 +- src/plugins/yamlcpp/write.cpp | 6 +- src/plugins/yamlcpp/yamlcpp.cpp | 18 +- src/plugins/yamlsmith/README.md | 44 +- src/plugins/yamlsmith/testmod_yamlsmith.c | 2 +- src/plugins/yamlsmith/yamlsmith.cpp | 16 +- src/plugins/yanlr/README.md | 126 +- src/plugins/yanlr/testmod_yanlr.cpp | 4 +- src/plugins/yanlr/yanlr.cpp | 10 +- src/plugins/zeromqrecv/testmod_zeromqrecv.c | 4 +- src/plugins/zeromqrecv/zeromqrecv.c | 21 +- src/plugins/zeromqsend/testmod_zeromqsend.c | 14 +- src/plugins/zeromqsend/zeromqsend.c | 16 +- src/tools/elektrad/benchmark_test.go | 2 +- src/tools/elektrad/find_handler_test.go | 4 +- src/tools/elektrad/kdb_handler_test.go | 8 +- src/tools/elektrad/meta_handler_test.go | 4 +- src/tools/elektrad/move_handler_test.go | 4 +- src/tools/kdb/cache.cpp | 4 +- src/tools/kdb/cmdline.cpp | 7 +- src/tools/kdb/cmdline.hpp | 4 +- src/tools/kdb/cmerge.cpp | 2 +- src/tools/kdb/coloredkdbio.hpp | 54 +- src/tools/kdb/complete.cpp | 38 +- src/tools/kdb/export.cpp | 2 +- src/tools/kdb/gen/highlevel/highlevel.cpp | 24 +- src/tools/kdb/gen/highlevel/structs.cpp | 2 +- .../kdb/gen/templates/highlevel.c.mustache | 4 +- .../gen/templates/highlevel.mount.sh.mustache | 8 +- src/tools/kdb/get.cpp | 8 +- src/tools/kdb/get.hpp | 2 +- src/tools/kdb/globalmount.cpp | 6 +- src/tools/kdb/globalumount.cpp | 2 +- src/tools/kdb/import.cpp | 2 +- src/tools/kdb/main.cpp | 6 +- src/tools/kdb/metals.cpp | 2 +- src/tools/kdb/metaset.cpp | 2 +- src/tools/kdb/mount.cpp | 4 +- src/tools/kdb/mountbase.cpp | 18 +- src/tools/kdb/plugincheck.cpp | 2 +- src/tools/kdb/plugininfo.cpp | 10 +- src/tools/kdb/pluginlist.cpp | 2 +- src/tools/kdb/rm.cpp | 2 +- src/tools/kdb/showmeta.cpp | 2 +- src/tools/kdb/specmount.cpp | 6 +- src/tools/kdb/test.cpp | 1 + src/tools/pythongen/CMakeLists.txt | 1 + src/tools/pythongen/README.md | 8 +- src/tools/pythongen/support/c.py | 10 +- src/tools/pythongen/support/c_elektra.py | 4 +- src/tools/pythongen/support/gen.py | 10 +- src/tools/pythongen/tests/editor_context.cpp | 13 +- src/tools/pythongen/tests/lift.c | 84 +- src/tools/pythongen/tests/lift.cpp | 28 +- src/tools/pythongen/tests/lift_context.cpp | 20 +- src/tools/pythongen/tests/lift_nested.cpp | 30 +- src/tools/pythongen/tests/location.cpp | 34 +- src/tools/pythongen/tests/visit_context.cpp | 82 +- src/tools/qt-gui/src/guibackend.cpp | 4 +- src/tools/qt-gui/src/treeviewmodel.cpp | 9 +- src/tools/qt-gui/unittest/treeviewtest.cpp | 6 +- src/tools/race/race.c | 4 +- src/tools/webd/CMakeLists.txt | 2 +- src/tools/webd/src/config.js | 2 +- src/tools/webd/src/kdb.js | 2 +- src/tools/website/README.md | 2 +- src/tools/website/mount-config.sh | 7 +- .../vendor/asciinema/asciinema-player.js | 20 +- tests/abi/testabi_key.c | 1484 +++++++-------- tests/abi/testabi_ks.c | 1313 +++++++------- tests/abi/testabi_meta.c | 74 +- tests/abi/testabi_rel.c | 276 ++- tests/cframework/tests.c | 64 +- tests/cframework/tests.h | 58 +- tests/cframework/tests_plugin.h | 2 +- tests/ctest/CMakeLists.txt | 2 +- tests/ctest/test_array.c | 106 +- tests/ctest/test_backend.c | 145 +- tests/ctest/test_cmerge.c | 101 +- tests/ctest/test_conversion.c | 14 +- tests/ctest/test_ease_keyname.c | 142 ++ tests/ctest/test_globbing.c | 10 +- tests/ctest/test_internal.c | 220 ++- tests/ctest/test_key.c | 1313 +++----------- tests/ctest/test_keyname.c | 928 ++++++++-- tests/ctest/test_ks.c | 55 +- tests/ctest/test_meta.c | 55 +- tests/ctest/test_mount.c | 611 +++---- tests/ctest/test_mountsplit.c | 299 ++- tests/ctest/test_namespace.c | 58 +- tests/ctest/test_operation.c | 58 +- tests/ctest/test_opts.c | 6 +- tests/ctest/test_order.c | 133 +- tests/ctest/test_plugin.c | 50 +- tests/ctest/test_size.c | 18 +- tests/ctest/test_spec.c | 146 +- tests/ctest/test_split.c | 22 +- tests/ctest/test_splitget.c | 237 ++- tests/ctest/test_splitset.c | 211 +-- tests/ctest/test_storage.c | 118 +- tests/ctest/test_trie.c | 544 +++--- tests/data/data_allns.c | 1328 +++++++------- tests/data/data_copy.c | 576 +++--- tests/data/data_cut.c | 64 +- tests/data/data_dbelow.c | 36 +- tests/data/data_escape.c | 4 +- tests/data/data_filesys.c | 18 +- tests/data/data_fstab-cmp.c | 14 +- tests/data/data_fstab.c | 14 +- tests/data/data_hosts.c | 36 +- tests/data/data_key.c | 18 +- tests/data/data_keyset.c | 204 +-- tests/data/data_noescape.c | 1 - tests/data/data_ns.c | 1020 +++++------ tests/data/data_nscut.c | 70 +- tests/data/data_one.c | 184 +- tests/data/data_others.c | 168 +- tests/data/data_passwd.c | 74 +- tests/gtest-framework/gtest/gtest-elektra.h | 10 +- tests/kdb/testkdb_conflict.cpp | 30 +- tests/kdb/testkdb_ensure.cpp | 16 +- tests/kdb/testkdb_error.cpp | 26 +- tests/kdb/testkdb_highlevel.cpp | 8 +- tests/kdb/testkdb_nested.cpp | 36 +- tests/kdb/testkdb_simple.cpp | 78 +- tests/shell/check_cmd_line_arguments.sh | 2 +- tests/shell/check_distribution.sh | 38 +- tests/shell/check_error.sh | 4 +- tests/shell/check_gen.sh | 4 +- tests/shell/check_get_set.sh | 4 +- tests/shell/check_import.sh | 16 +- tests/shell/check_kdb_internal_check.sh | 2 +- tests/shell/check_mount.sh | 22 +- tests/shell/check_race.sh | 4 +- tests/shell/check_real_world.sh | 50 +- tests/shell/check_resolver.sh | 2 +- tests/shell/check_spec.sh | 14 +- tests/shell/external/example.sh | 4 +- tests/shell/external/example_codegen_econf.sh | 4 +- tests/shell/external/example_codegen_menu.sh | 12 +- tests/shell/external/example_codegen_tree.sh | 4 +- tests/shell/external/example_highlevel.sh | 4 +- tests/shell/external/pythongen.sh | 15 +- tests/shell/gen/highlevel/commands.expected.c | 10 +- .../gen/highlevel/commands.expected.mount.sh | 16 +- tests/shell/gen/highlevel/empty.expected.c | 10 +- .../gen/highlevel/empty.expected.mount.sh | 16 +- tests/shell/gen/highlevel/enum.expected.c | 10 +- .../gen/highlevel/enum.expected.mount.sh | 16 +- .../shell/gen/highlevel/externalspec.check.sh | 6 +- .../gen/highlevel/externalspec.expected.c | 4 +- .../highlevel/externalspec.expected.mount.sh | 12 +- .../highlevel/externalwithdefaults.check.sh | 6 +- .../highlevel/externalwithdefaults.expected.c | 4 +- .../externalwithdefaults.expected.mount.sh | 12 +- tests/shell/gen/highlevel/nosetter.check.sh | 6 +- tests/shell/gen/highlevel/nosetter.expected.c | 10 +- .../gen/highlevel/nosetter.expected.mount.sh | 16 +- tests/shell/gen/highlevel/notype.expected.c | 10 +- .../gen/highlevel/notype.expected.mount.sh | 16 +- tests/shell/gen/highlevel/simple.check.sh | 6 +- tests/shell/gen/highlevel/simple.expected.c | 10 +- .../gen/highlevel/simple.expected.mount.sh | 16 +- tests/shell/gen/highlevel/struct.expected.c | 10 +- .../gen/highlevel/struct.expected.mount.sh | 16 +- tests/shell/include_common.sh.in | 40 +- tests/shell/shell/again_two_value.tcl | 4 +- tests/shell/shell/again_two_value.xmltool | 4 +- tests/shell/shell/one_value.tcl | 2 +- tests/shell/shell/one_value.xmltool | 2 +- tests/shell/shell/three_value.tcl | 6 +- tests/shell/shell/three_value.xmltool | 6 +- tests/shell/shell/two_value.tcl | 4 +- tests/shell/shell/two_value.xmltool | 4 +- tests/shell/shell_recorder/README.md | 62 +- tests/shell/shell_recorder/db_changes.esr | 4 +- tests/shell/shell_recorder/hosts.esr | 4 +- tests/shell/shell_recorder/listtest.esr | 2 +- tests/shell/shell_recorder/mathcheck.esr | 2 +- tests/shell/shell_recorder/profiletest.esr | 44 +- .../shell/shell_recorder/replay_tests/ls.epf | 36 +- .../shell/shell_recorder/replay_tests/ls.esr | 16 +- tests/shell/shell_recorder/script.esr | 2 +- tests/shell/shell_recorder/selftest.esr | 6 +- tests/shell/shell_recorder/shell_recorder.sh | 2 +- .../shell_recorder/tutorial_wrapper/README.md | 22 +- .../tutorial_wrapper/SyntaxCheck.md | 6 +- .../markdown_shell_recorder.sh | 4 +- 904 files changed, 20505 insertions(+), 18796 deletions(-) create mode 100644 Testing/Temporary/CTestCostData.txt create mode 100644 Testing/Temporary/LastTest.log create mode 100644 doc/keynames/README.md create mode 100755 doc/keynames/keynames.py create mode 100755 doc/keynames/new_api.py create mode 100644 doc/keynames/tree.svg create mode 100644 doc/proposals/keynames.md create mode 100644 doc/todo/PROPOSALS create mode 100644 src/bindings/swig/python2/tests/testpy2_kdb.py delete mode 100644 src/include/kdbobsolete.h delete mode 100644 src/plugins/hidden/CMakeLists.txt delete mode 100644 src/plugins/hidden/README.md delete mode 100644 src/plugins/hidden/hidden.c delete mode 100644 src/plugins/hidden/hidden.h delete mode 100644 src/plugins/quickdump/quickdump/test.v1.quickdump delete mode 100644 src/plugins/quickdump/quickdump/test.v2.quickdump delete mode 100644 src/plugins/quickdump/readv1.c delete mode 100644 src/plugins/quickdump/readv2.c create mode 100644 tests/ctest/test_ease_keyname.c diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index d36204cd17a..56cbb8c2b86 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -9,17 +9,17 @@ Please provide a step by step guide on how to reproduce the problem here. If pos syntax: ```sh -kdb set user/tests/hello world -#> Create a new key user/tests/hello with string "world" +kdb set user:/tests/hello world +#> Create a new key user:/tests/hello with string "world" -kdb get user/tests/hello +kdb get user:/tests/hello #> world -kdb get user/does/not/exist +kdb get user:/does/not/exist # RET: 11 -# STDERR: [Dd]id not find key 'user/does/not/exist' +# STDERR: [Dd]id not find key 'user:/does/not/exist' -kdb rm user/tests/hello +kdb rm user:/tests/hello ``` If your key database (KDB) might influence the outcome, please use `kdb stash` diff --git a/.gitignore b/.gitignore index 9f7c61d82dd..745733ca114 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ #ignore all build directories of cmake build*/ cmake-build*/ +!scripts/build/ #ignore ctags + gdb history files .ctags diff --git a/Testing/Temporary/CTestCostData.txt b/Testing/Temporary/CTestCostData.txt new file mode 100644 index 00000000000..ed97d539c09 --- /dev/null +++ b/Testing/Temporary/CTestCostData.txt @@ -0,0 +1 @@ +--- diff --git a/Testing/Temporary/LastTest.log b/Testing/Temporary/LastTest.log new file mode 100644 index 00000000000..72c3fc85e36 --- /dev/null +++ b/Testing/Temporary/LastTest.log @@ -0,0 +1,3 @@ +Start testing: Sep 05 13:14 CEST +---------------------------------------------------------- +End testing: Sep 05 13:14 CEST diff --git a/benchmarks/benchmarks.c b/benchmarks/benchmarks.c index b6fdb6fe9b8..8fadc2ac8f7 100644 --- a/benchmarks/benchmarks.c +++ b/benchmarks/benchmarks.c @@ -598,7 +598,7 @@ KeySet * generateKeySet (const size_t size, int32_t * seed, KeySetShape * shape) } for (size_t i = 0; i < root->numberofChildren; ++i) { - Key * key = keyNew ("", KEY_END); + Key * key = keyNew ("/", KEY_END); if (!key) { printExit ("generateKeySet: Can not create Key"); diff --git a/benchmarks/benchmarks.h b/benchmarks/benchmarks.h index ec76ba36479..433a41572ea 100644 --- a/benchmarks/benchmarks.h +++ b/benchmarks/benchmarks.h @@ -22,7 +22,7 @@ #include -#define KEY_ROOT "user/benchmark" +#define KEY_ROOT "user:/benchmark" #define KEY_NAME_LENGTH 1000 #define NUM_DIR 200 diff --git a/benchmarks/kdb.c b/benchmarks/kdb.c index f32a6eaa7b8..971f8f13ebe 100644 --- a/benchmarks/kdb.c +++ b/benchmarks/kdb.c @@ -29,7 +29,7 @@ int main (void) fprintf (stdout, "%s;%s;%s\n", "plugin", "operation", "microseconds"); { KeySet * returned = ksNew (0, KS_END); - Key * parentKey = keyNew ("user", KEY_END); + Key * parentKey = keyNew ("user:/", KEY_END); timeInit (); KDB * handle = kdbOpen (parentKey); @@ -49,7 +49,7 @@ int main (void) for (size_t i = 0; i < NUM_RUNS; ++i) { timeInit (); - Key * parentKey = keyNew ("user/benchmark", KEY_END); + Key * parentKey = keyNew ("user:/benchmark", KEY_END); KDB * handle = kdbOpen (parentKey); fprintf (stdout, CSV_STR_FMT, "core", "kdbOpen", timeGetDiffMicroseconds ()); diff --git a/benchmarks/memoryleak.c b/benchmarks/memoryleak.c index e1618f565c5..dfdbf57489d 100644 --- a/benchmarks/memoryleak.c +++ b/benchmarks/memoryleak.c @@ -19,7 +19,7 @@ int main (void) KDB * handles[NUM_RUNS]; KeySet * keysets[NUM_RUNS]; - Key * parentKey = keyNew ("user", KEY_END); + Key * parentKey = keyNew ("user:/", KEY_END); for (size_t i = 0; i < NUM_RUNS; ++i) { diff --git a/benchmarks/opmphm.c b/benchmarks/opmphm.c index 576af03c6a6..cf8f63580d0 100644 --- a/benchmarks/opmphm.c +++ b/benchmarks/opmphm.c @@ -2461,7 +2461,7 @@ static void shapefCommonStartEnd (const size_t initSize ELEKTRA_UNUSED, size_t s } } /** - * modules, level 1 keys same, one level 2 key stores the modules. Like system/elektra. + * modules, level 1 keys same, one level 2 key stores the modules. Like system:/elektra. */ static void * shapeModulesInit (void) { @@ -2496,13 +2496,13 @@ static void shapefModules (const size_t initSize, size_t size ELEKTRA_UNUSED, si uint8_t * assign = &d[3]; if (level == 1) { - // common start, simulates elektra in system/elektra + // common start, simulates elektra in system:/elektra ret->subKeys = 1; ret->label = 0; } else if (level == 2) { - // common name, simulates modules in system/elektra/modules + // common name, simulates modules in system:/elektra/modules // calculates how many modules have space ret->subKeys = 0; ssize_t remainingSize = initSize; diff --git a/benchmarks/plugingetset.c b/benchmarks/plugingetset.c index 2f8cfa559b4..ff761c1d496 100644 --- a/benchmarks/plugingetset.c +++ b/benchmarks/plugingetset.c @@ -45,7 +45,7 @@ int main (int argc, char ** argv) KeySet * conf = ksNew (0, KS_END); KeySet * modules = ksNew (0, KS_END); elektraModulesInit (modules, 0); - Key * errorKey = keyNew ("", KEY_END); + Key * errorKey = keyNew ("/", KEY_END); Plugin * plugin = elektraPluginOpen (pluginname, modules, conf, errorKey); keyDel (errorKey); @@ -69,7 +69,7 @@ int main (int argc, char ** argv) KeySet * conf = ksNew (0, KS_END); KeySet * modules = ksNew (0, KS_END); elektraModulesInit (modules, 0); - Key * errorKey = keyNew ("", KEY_END); + Key * errorKey = keyNew ("/", KEY_END); Plugin * plugin = elektraPluginOpen (pluginname, modules, conf, errorKey); keyDel (errorKey); plugin->kdbSet (plugin, ks, setKey); diff --git a/benchmarks/storage.c b/benchmarks/storage.c index 75f81ca1c69..b415e8311f5 100644 --- a/benchmarks/storage.c +++ b/benchmarks/storage.c @@ -33,7 +33,7 @@ static int benchmarkOpenPlugins (void) modules[i] = ksNew (0, KS_END); elektraModulesInit (modules[i], 0); KeySet * conf = ksNew (0, KS_END); - Key * errorKey = keyNew ("", KEY_END); + Key * errorKey = keyNew ("/", KEY_END); Plugin * plugin = elektraPluginOpen (pluginNames[i], modules[i], conf, errorKey); const Key * metaWarnings = keyGetMeta (errorKey, "warnings"); @@ -102,7 +102,7 @@ int main (int argc, char ** argv) init (argc, argv); Plugin * plugin = plugins[i]; - Key * parentKey = keyNew ("user/benchmarks/storage", KEY_VALUE, tmpfilename, KEY_END); + Key * parentKey = keyNew ("user:/benchmarks/storage", KEY_VALUE, tmpfilename, KEY_END); for (size_t run = 0; run < NUM_RUNS; ++run) { diff --git a/doc/METADATA.ini b/doc/METADATA.ini index 5085d36fa7a..71852fb5707 100644 --- a/doc/METADATA.ini +++ b/doc/METADATA.ini @@ -1077,7 +1077,7 @@ description= Internal metadata to be ignored by other plugins. status= idea description= states where a key comes from if it is not from an ordinary persistent configuration. E.g. hardware (queries) - e.g. system/sw/xorg/current/monitor might have "source" metadata if it + e.g. system:/sw/xorg/current/monitor might have "source" metadata if it is queried from hardware and not from configuration file. [dependency/control] diff --git a/doc/TESTING.md b/doc/TESTING.md index 44de542f91a..dc0880e6300 100644 --- a/doc/TESTING.md +++ b/doc/TESTING.md @@ -83,15 +83,15 @@ You have some options to avoid running them as root: ```sh kdb mount-info - echo `kdb sget system/info/elektra/constants/cmake/CMAKE_INSTALL_PREFIX .`/`kdb sget system/info/elektra/constants/cmake/KDB_DB_SPEC .` - echo `kdb sget system/info/elektra/constants/cmake/KDB_DB_SYSTEM .` + echo `kdb sget system:/info/elektra/constants/cmake/CMAKE_INSTALL_PREFIX .`/`kdb sget system:/info/elektra/constants/cmake/KDB_DB_SPEC .` + echo `kdb sget system:/info/elektra/constants/cmake/KDB_DB_SYSTEM .` ``` Then change the permissions: ```sh - chown -R `whoami` `kdb sget system/info/elektra/constants/cmake/CMAKE_INSTALL_PREFIX .`/`kdb sget system/info/elektra/constants/cmake/KDB_DB_SPEC .` - chown -R `whoami` `kdb sget system/info/elektra/constants/cmake/KDB_DB_SYSTEM .` + chown -R `whoami` `kdb sget system:/info/elektra/constants/cmake/CMAKE_INSTALL_PREFIX .`/`kdb sget system:/info/elektra/constants/cmake/KDB_DB_SPEC .` + chown -R `whoami` `kdb sget system:/info/elektra/constants/cmake/KDB_DB_SYSTEM .` ``` After that all test cases should run successfully as described above. @@ -195,7 +195,7 @@ are expected to be in the README.md of the plugin. - should not run, if `ENABLE_KDB_TESTING` is OFF. - should only write below - `/tests/` (e.g. `/tests/ruby`) and - - `system/elektra` (e.g. for mounts or globalplugins). + - `system:/elektra` (e.g. for mounts or globalplugins). - Before executing tests, no keys must be present below `/tests`. The test cases need to clean up everything they wrote. (Including temporary files) @@ -324,13 +324,13 @@ cp ~e/src/plugins/toml/toml/* testcase_dir Fewer files is better. Then run, for example: ```sh -LD_LIBRARY_PATH=`pwd`/lib /usr/src/afl/AFL-2.57b/afl-fuzz -i testcase_dir -o findings_dir bin/kdb import user/tests toml +LD_LIBRARY_PATH=`pwd`/lib /usr/src/afl/AFL-2.57b/afl-fuzz -i testcase_dir -o findings_dir bin/kdb import user:/tests toml ``` Check if something is happening with: ```sh -watch kdb export user/tests +watch kdb export user:/tests ``` ### ASAN diff --git a/doc/VERSION.md b/doc/VERSION.md index 2d600b2f434..535df48de3b 100644 --- a/doc/VERSION.md +++ b/doc/VERSION.md @@ -8,10 +8,10 @@ numbers for the publicly announced versions. The version can also be retrieved at run-time from KDB: ``` -system/elektra/version/constants/KDB_VERSION -system/elektra/version/constants/KDB_VERSION_MAJOR -system/elektra/version/constants/KDB_VERSION_MINOR -system/elektra/version/constants/KDB_VERSION_PATCH +system:/elektra/version/constants/KDB_VERSION +system:/elektra/version/constants/KDB_VERSION_MAJOR +system:/elektra/version/constants/KDB_VERSION_MICRO +system:/elektra/version/constants/KDB_VERSION_MINOR ``` ## Scope @@ -136,7 +136,7 @@ know about which bug fixes are included. The patch level might also be used to fix bugs within bindings. This means that applications can only introspect the patch -level of Elektra by getting `system/elektra/version/constants/KDB_VERSION_PATCH` +level of Elektra by getting `system:/elektra/version/constants/KDB_VERSION_PATCH` but not by static patch levels the binding might provide. This should be no problem, as the patch level is supposed to not change the behavior. diff --git a/doc/VISION.md b/doc/VISION.md index 7bb9c2da7f8..d8d96fedc6c 100644 --- a/doc/VISION.md +++ b/doc/VISION.md @@ -27,13 +27,13 @@ as desired. Either by either invoking [command-line tools](/doc/help/kdb.md): ```sh -kdb set system/sw/samba/#0/current/global/workgroup MYGROUP +kdb set system:/sw/samba/#0/current/global/workgroup MYGROUP ``` Also by importing an INI file with the information: ```ini -kdb import system/sw/samba/#0/current ini << HERE +kdb import system:/sw/samba/#0/current ini << HERE [global] workgroup=MYGROUP HERE @@ -49,7 +49,7 @@ with neither code generation nor error handling): int main () { ElektraError* error; - Elektra * elektra = elektraOpen ("system/sw/samba/#0/current", 0, &error); + Elektra * elektra = elektraOpen ("system:/sw/samba/#0/current", 0, &error); elektraSetString (elektra, "global/workgroup", "MYGROUP", &error); elektraClose (elektra); } @@ -62,7 +62,7 @@ Or using some interpreted language like Python import kdb k = kdb.KDB() ks = kdb.KeySet() -s = "system/sw/samba/#0/current" +s = "system:/sw/samba/#0/current" k.get (ks, s) ks.append(kdb.Key(s+"/global/workgroup", kdb.KEY_VALUE, "MYGROUP")) k.set (ks, s) @@ -75,7 +75,7 @@ change a configuration value. Key-value access in [puppet-libelektra](https://puppet.libelektra.org): ``` -kdbkey {'system/sw/samba/#0/current/global/workgroup': +kdbkey {'system:/sw/samba/#0/current/global/workgroup': ensure => 'present', value => 'MYGROUP' } @@ -84,7 +84,7 @@ kdbkey {'system/sw/samba/#0/current/global/workgroup': Key-value access in Chef: ``` -kdbset 'system/sw/samba/#0/current/global/workgroup' do +kdbset 'system:/sw/samba/#0/current/global/workgroup' do value 'MYGROUP' action :create end @@ -99,12 +99,12 @@ Key-value access in Ansible: tasks: - name: set workgroup elektra: - key: "system/sw/samba/#0/current/global/workgroup" + key: "system:/sw/samba/#0/current/global/workgroup" value: "MYGROUP" ``` In all these examples, we have set -`system/sw/samba/#0/current/global/workgroup` to `MYGROUP`. +`system:/sw/samba/#0/current/global/workgroup` to `MYGROUP`. ## Application Integration @@ -148,7 +148,7 @@ shown above can be used. To make mounting more simple, we introduced an extra tool: ```sh -kdb mount /etc/samba/smb.conf system/sw/samba/#0/current ini +kdb mount /etc/samba/smb.conf system:/sw/samba/#0/current ini ``` Mounting can also be done via configuration management @@ -157,12 +157,12 @@ tools. Mounting in puppet-libelektra: ``` -kdbmount {'system/sw/samba/#0/current': +kdbmount {'system:/sw/samba/#0/current': ensure => 'present', file => '/etc/samba/smb.conf', plugins => 'ini' } -kdbkey {'system/sw/samba/global/log level': +kdbkey {'system:/sw/samba/global/log level': ensure => 'absent' } ``` @@ -176,7 +176,7 @@ Mounting in Ansible: tasks: - name: set workgroup elektra: - mountpoint: system/sw/samba + mountpoint: system:/sw/samba file: /etc/samba/smb.conf plugins: ini ``` @@ -209,7 +209,7 @@ kdb set-meta /sw/samba/#0/current/global/workgroup description "This controls wh Key-value specifications in [puppet-libelektra](https://puppet.libelektra.org): ``` -kdbkey {'system/sw/samba/#0/current/global/workgroup': +kdbkey {'system:/sw/samba/#0/current/global/workgroup': ensure => 'present', check => { 'type' => 'string', @@ -224,7 +224,7 @@ kdbkey {'system/sw/samba/#0/current/global/workgroup': ``` Note, that the specification (in both examples above) actually lands up in -`spec/sw/samba/#0/current/global/workgroup`. The unique path to the +`spec:/sw/samba/#0/current/global/workgroup`. The unique path to the configuration setting is `/sw/samba/#0/current/global/workgroup`, but the specification gets written to the [namespace](/doc/tutorials/namespaces.md) `spec`, while the system-configuration gets written to the namespace `system`. diff --git a/doc/decisions/bootstrap.md b/doc/decisions/bootstrap.md index bac3fcdbeac..df0c057911d 100644 --- a/doc/decisions/bootstrap.md +++ b/doc/decisions/bootstrap.md @@ -4,7 +4,7 @@ Currently the default backend (default.ecf) will also be used for bootstrapping. There are two problems with this approach: -1. Thus the default backend first will be read with parentKey `system/elektra` and later with parentKey `system`, it needs to store absolute paths and thus won't work with the current INI plugin +1. Thus the default backend first will be read with parentKey `system:/elektra` and later with parentKey `system:/`, it needs to store absolute paths and thus won't work with most of the plugins (except dump). 2. When `system` is large without mount points, everything is reread twice during bootstrapping. ## Constraints @@ -19,7 +19,7 @@ Currently the default backend (default.ecf) will also be used for bootstrapping. ## Considered Alternatives -- Implement a hack so that `system/elektra` is actually read as `system`. (Will not solve problem 2.) +- Implement a hack so that `system:/elektra` is actually read as `system:/`. (Will not solve problem 2.) - Its a hack. - Its confusing and does not play well with persistent data with relative key names. - Split up without compatibility mode: would need to migrate all mount points by exporting (with old version!) and then importing (with new version!) @@ -33,10 +33,8 @@ The default backend reading `default.ecf` is only relevant as long as no root ba Algorithm: -1. try to get system/elektra using the file elektra.ecf (KDB_DB_INIT) -2. if it works, mount the init backend to system/elektra (non-fallback mode) -3. if it fails (== 0 or == -1), try default.ecf as fallback -4. if the fallback works (i.e. keys are present in system/elektra), mount the default backend to system/elektra (fallback mode) +1. try to get system:/elektra using the file elektra.ecf (KDB_DB_INIT) +2. if it works, mount the init backend to system:/elektra ## Rationale @@ -46,7 +44,6 @@ Algorithm: ## Implications -- Fallback mode should be removed with 1.0 - added scripts/upgrade-bootstrap ## Related Decisions @@ -56,4 +53,4 @@ Algorithm: to upgrade to new system, either: - touch /etc/kdb/elektra.ecf (loses old mount points) -- or do kdb export system/elektra/mountpoints, kdb rm -r system/elektra/mountpoints, kdb import system/elektra/mountpoints +- or do kdb export system:/elektra/mountpoints, kdb rm -r system:/elektra/mountpoints, kdb import system:/elektra/mountpoints diff --git a/doc/decisions/global_validation.md b/doc/decisions/global_validation.md index 251ea66307d..698fc580d7a 100644 --- a/doc/decisions/global_validation.md +++ b/doc/decisions/global_validation.md @@ -15,8 +15,8 @@ with the respective `kdbGet`. - global plugin can register additional backends to load - split `kdbGet` into multiple steps: - 1. do `kdbGet` on `system/elektra` to update mount points - 2. first do `kdbGet` on the `spec/`-namespace + 1. do `kdbGet` on `system:/elektra` to update mount points + 2. first do `kdbGet` on the `spec:/`-namespace 3. then calculate which backends are needed 4. then fetch all backends as needed - split loops in `kdbGet` not only according placements diff --git a/doc/decisions/plugin_variants.md b/doc/decisions/plugin_variants.md index aa937a81e2c..0ce6a52ed02 100644 --- a/doc/decisions/plugin_variants.md +++ b/doc/decisions/plugin_variants.md @@ -57,9 +57,9 @@ Best implementation candidate was: 1. Provide a function `int genconf (KeySet * ks, Key * errorKey)` where `ks` is filled with a list of all variants with the essential configuration (subkeys `config`) and the changed parts of the contract (subkeys `infos`). -2. Keys defined in `system/elektra/plugins//variants/` have the same content, +2. Keys defined in `system:/elektra/plugins//variants/` have the same content, but take precedence. If a variant with the same name is defined, only `config` or `infos` - from `genconf` are considered if they are not mentioned in `system/elektra/plugins/variants`. + from `genconf` are considered if they are not mentioned in `system:/elektra/plugins/variants`. 3. If the bool key `override` (for a plugin or a variant) is true, it will be overwritten (content of `genconf` ignored, but instead a plugin or variant as given is created). 4. If the bool key `disable` (for a plugin or a variant) is true the plugin or a variant of the @@ -75,38 +75,38 @@ Best implementation candidate was: `genconf` for augeas yields: ``` -system/access -system/access/config -system/access/config/lens = Access.lns -system/access/infos -system/access/infos/provides = storage/access -system/aliases -system/aliases/config -system/aliases/config/lens = Aliases.lns -system/aliases/infos -system/aliases/infos/provides = storage/aliases +system:/access +system:/access/config +system:/access/config/lens = Access.lns +system:/access/infos +system:/access/infos/provides = storage/access +system:/aliases +system:/aliases/config +system:/aliases/config/lens = Aliases.lns +system:/aliases/infos +system:/aliases/infos/provides = storage/aliases ``` `genconf` for python might yield: ``` -user/configparser/config -user/configparser/config/script = python_configparser.py +user:/configparser/config +user:/configparser/config/script = python_configparser.py ``` -The user/admin specifies: +The user:/admin specifies: ``` -system/elektra/plugins/jni/disable = 1 -system/elektra/plugins/augeas/variants/access -system/elektra/plugins/augeas/variants/access/disable = 1 -system/elektra/plugins/augeas/variants/aliases -system/elektra/plugins/augeas/variants/aliases/infos -system/elektra/plugins/augeas/variants/aliases/infos/status = 10000 -system/elektra/plugins/python/variants/configparser -system/elektra/plugins/python/variants/configparser/override = 1 -system/elektra/plugins/python/variants/configparser/config -system/elektra/plugins/python/variants/configparser/config/script = mybetter_configparser.py +system:/elektra/plugins/jni/disable = 1 +system:/elektra/plugins/augeas/variants/access +system:/elektra/plugins/augeas/variants/access/disable = 1 +system:/elektra/plugins/augeas/variants/aliases +system:/elektra/plugins/augeas/variants/aliases/infos +system:/elektra/plugins/augeas/variants/aliases/infos/status = 10000 +system:/elektra/plugins/python/variants/configparser +system:/elektra/plugins/python/variants/configparser/override = 1 +system:/elektra/plugins/python/variants/configparser/config +system:/elektra/plugins/python/variants/configparser/config/script = mybetter_configparser.py ``` As result we get: @@ -120,9 +120,9 @@ As result we get: To have a space-separated simpleini one would use: ``` -system/elektra/plugins/simpleini/variants/spacesep -system/elektra/plugins/simpleini/variants/spacesep/config -system/elektra/plugins/simpleini/variants/spacesep/config/format = "% %" +system:/elektra/plugins/simpleini/variants/spacesep +system:/elektra/plugins/simpleini/variants/spacesep/config +system:/elektra/plugins/simpleini/variants/spacesep/config/format = "% %" ``` ## Rationale @@ -154,19 +154,19 @@ It is also not possible to add additional information to a variant, only overrides work. E.g. ``` -system/elektra/plugins/augeas/variants/aliases -system/elektra/plugins/augeas/variants/aliases/override = 1 -system/elektra/plugins/augeas/variants/aliases/config -system/elektra/plugins/augeas/variants/aliases/config/lens = Aliases.lns -system/elektra/plugins/augeas/variants/aliases/config/otherparam = 0 +system:/elektra/plugins/augeas/variants/aliases +system:/elektra/plugins/augeas/variants/aliases/override = 1 +system:/elektra/plugins/augeas/variants/aliases/config +system:/elektra/plugins/augeas/variants/aliases/config/lens = Aliases.lns +system:/elektra/plugins/augeas/variants/aliases/config/otherparam = 0 ``` works, while ``` -system/elektra/plugins/augeas/variants/aliases -system/elektra/plugins/augeas/variants/aliases/config -system/elektra/plugins/augeas/variants/aliases/config/otherparam = 0 +system:/elektra/plugins/augeas/variants/aliases +system:/elektra/plugins/augeas/variants/aliases/config +system:/elektra/plugins/augeas/variants/aliases/config/otherparam = 0 ``` gets ignored. diff --git a/doc/dev/algorithm.md b/doc/dev/algorithm.md index a6d5c7c8638..c4d52c783c7 100644 --- a/doc/dev/algorithm.md +++ b/doc/dev/algorithm.md @@ -147,39 +147,39 @@ following keys. (A) and (B) indicate from which backend the key comes from. ``` -user/sw/generator/akey (A) -user/sw/generator/dir (A) -user/sw/generator/dir/outside1 (A) -user/sw/generator/dir/outside2 (A) +user:/sw/generator/akey (A) +user:/sw/generator/dir (A) +user:/sw/generator/dir/outside1 (A) +user:/sw/generator/dir/outside2 (A) ``` It will still return these keys even if the plugin is not responsible for some of them anymore. This can happen if another backend B is mounted -to `user/sw/generator/dir`. In the example it yields the +to `user:/sw/generator/dir`. In the example it yields the following keys: ``` -user/sw/generator/dir (B) -user/sw/generator/dir/new (B) -user/sw/generator/dir/outside1 (B) -user/sw/generator/outside (B) +user:/sw/generator/dir (B) +user:/sw/generator/dir/new (B) +user:/sw/generator/dir/outside1 (B) +user:/sw/generator/outside (B) ``` In this situation `kdbGet()` is responsible to pop all three keys at, -and below, `user/sw/generator/dir` of backend (A) and the key -`user/sw/generator/outside` of backend (B). The user will get the +and below, `user:/sw/generator/dir` of backend (A) and the key +`user:/sw/generator/outside` of backend (B). The user will get the resulting key set: ``` -user/sw/generator/akey (A) -user/sw/generator/dir (B) -user/sw/generator/dir/new (B) -user/sw/generator/dir/outside1 (B) +user:/sw/generator/akey (A) +user:/sw/generator/dir (B) +user:/sw/generator/dir/new (B) +user:/sw/generator/dir/outside1 (B) ``` Note that the key exactly at the mount point comes from the backend mounted -at `user/sw/generator/dir`. +at `user:/sw/generator/dir`. ### Sequence @@ -187,8 +187,8 @@ at `user/sw/generator/dir`. tree. In this object, `kdbOpen()` will append a list of all backends available. A specific `kdbGet()` request usually includes only a part of the configuration. For example, the user is only interested in -keys below `user/sw/apps/userapp`. All backends that cannot -contribute to configuration below `user/sw/apps/userapp` will be +keys below `user:/sw/apps/userapp`. All backends that cannot +contribute to configuration below `user:/sw/apps/userapp` will be omitted for that request. To achieve this, parts of the `Split` object are filtered out. After this step we know the list of backends involved. The `Split` object allocates a key set for each of these backends. @@ -259,11 +259,11 @@ work is done. Because Elektra provides self-contained configuration, `kdbOpen()` has to retrieve settings in the _bootstrapping_ process below -`system/elektra` as explained in `bootstrapping`. +`system:/elektra` as explained in `bootstrapping`. Because of the new way to keep track of removed keys, the internally executed `kdbGet()` creates a problem. Without countermeasures even the first `kdbGet()` of a user requesting the configuration below -`system/elektra` fails, because the resolver finds out that the +`system:/elektra` fails, because the resolver finds out that the configuration is already up to date. The configuration delivered by the user is empty at this point. As a result, the empty configuration will be appointed and returned to the user. @@ -303,8 +303,8 @@ int kdbSet(KDB *handle, KeySet *returned, Key * parentKey); The user passes the configuration using the `KeySet` `returned`. The key set will not be changed by `kdbSet()`. The `parentKey` provides a way to limit which part of the configuration is written out. For example, -the `parentKey` `user/sw/org/app/#0/current` will induce `kdbSet()` to -only modify the key databases below `user/sw/org/app` even +the `parentKey` `user:/sw/org/app/#0/current` will induce `kdbSet()` to +only modify the key databases below `user:/sw/org/app` even if the `KeySet` `returned` also contains more configuration. Note that all backends with no keys in `returned` but that are below `parentKey` will completely wipe out their key database. The `KDB` handle contains diff --git a/doc/dev/architecture.md b/doc/dev/architecture.md index 263c8ea5f10..468a964896c 100644 --- a/doc/dev/architecture.md +++ b/doc/dev/architecture.md @@ -181,37 +181,37 @@ within the mount point configuration provided by the administrator. Example for a mount point configuration: ``` -system/elektra/mountpoints -system/elektra/mountpoints/fstab -system/elektra/mountpoints/fstab/config -system/elektra/mountpoints/fstab/config/path=fstab -system/elektra/mountpoints/fstab/config/struct=list FStab -system/elektra/mountpoints/fstab/config/struct/FStab -system/elektra/mountpoints/fstab/config/struct/FStab/device -system/elektra/mountpoints/fstab/config/struct/FStab/dumpfreq -system/elektra/mountpoints/fstab/config/struct/FStab/mpoint -system/elektra/mountpoints/fstab/config/struct/FStab/options -system/elektra/mountpoints/fstab/config/struct/FStab/passno -system/elektra/mountpoints/fstab/config/struct/FStab/type -system/elektra/mountpoints/fstab/errorplugins -system/elektra/mountpoints/fstab/errorplugins/#5#resolver#resolver# -system/elektra/mountpoints/fstab/getplugins -system/elektra/mountpoints/fstab/getplugins/#0#resolver -system/elektra/mountpoints/fstab/getplugins/#5#fstab#fstab# -system/elektra/mountpoints/fstab/mountpoint /fstab -system/elektra/mountpoints/fstab/setplugins -system/elektra/mountpoints/fstab/setplugins/#0#resolver -system/elektra/mountpoints/fstab/setplugins/#1#struct#struct# -system/elektra/mountpoints/fstab/setplugins/#2#type#type# -system/elektra/mountpoints/fstab/setplugins/#3#path#path# -system/elektra/mountpoints/fstab/setplugins/#3#path#path#/config -system/elektra/mountpoints/fstab/setplugins/#3#path#path#/config/path/allow=proc tmpfs none -system/elektra/mountpoints/fstab/setplugins/#5#fstab -system/elektra/mountpoints/fstab/setplugins/#7#resolver +system:/elektra/mountpoints +system:/elektra/mountpoints/fstab +system:/elektra/mountpoints/fstab/config +system:/elektra/mountpoints/fstab/config/path=fstab +system:/elektra/mountpoints/fstab/config/struct=list FStab +system:/elektra/mountpoints/fstab/config/struct/FStab +system:/elektra/mountpoints/fstab/config/struct/FStab/device +system:/elektra/mountpoints/fstab/config/struct/FStab/dumpfreq +system:/elektra/mountpoints/fstab/config/struct/FStab/mpoint +system:/elektra/mountpoints/fstab/config/struct/FStab/options +system:/elektra/mountpoints/fstab/config/struct/FStab/passno +system:/elektra/mountpoints/fstab/config/struct/FStab/type +system:/elektra/mountpoints/fstab/errorplugins +system:/elektra/mountpoints/fstab/errorplugins/#5#resolver#resolver# +system:/elektra/mountpoints/fstab/getplugins +system:/elektra/mountpoints/fstab/getplugins/#0#resolver +system:/elektra/mountpoints/fstab/getplugins/#5#fstab#fstab# +system:/elektra/mountpoints/fstab/mountpoint /fstab +system:/elektra/mountpoints/fstab/setplugins +system:/elektra/mountpoints/fstab/setplugins/#0#resolver +system:/elektra/mountpoints/fstab/setplugins/#1#struct#struct# +system:/elektra/mountpoints/fstab/setplugins/#2#type#type# +system:/elektra/mountpoints/fstab/setplugins/#3#path#path# +system:/elektra/mountpoints/fstab/setplugins/#3#path#path#/config +system:/elektra/mountpoints/fstab/setplugins/#3#path#path#/config/path/allow=proc tmpfs none +system:/elektra/mountpoints/fstab/setplugins/#5#fstab +system:/elektra/mountpoints/fstab/setplugins/#7#resolver ``` Let us look at the subkeys below the key -`system/elektra/mountpoints/fstab`: +`system:/elektra/mountpoints/fstab`: - **config**: Everything below `config` is the system's @@ -220,13 +220,13 @@ Let us look at the subkeys below the key **plugin configuration**. For example, ``` - system/elektra/mountpoints/fstab/config/struct/FStab/mpoint + system:/elektra/mountpoints/fstab/config/struct/FStab/mpoint ``` will be translated to ``` - system/struct/FStab/mpoint + system:/struct/FStab/mpoint ``` and inserted into the plugin configuration for all plugins in the @@ -253,7 +253,7 @@ the one in this example. **cascading mount point**. A cascading mount point differs from two separate mount points because internally only one backend is created. In the example, the mount point `/fstab` means that the backend handles both - `user/fstab` and `system/fstab`. If the mount point + `user:/fstab` and `system:/fstab`. If the mount point is `/`, the backend will be mounted to all namespaces except `spec`, including both `user` and `system`. @@ -276,13 +276,13 @@ configuration. This configuration appears in the user's configuration of the plugin. Configuration is renamed properly. For example, the key ``` -system/elektra/mountpoints/fstab/setplugins/#3#path#path#/config/path/allow +system:/elektra/mountpoints/fstab/setplugins/#3#path#path#/config/path/allow ``` is transformed to ``` -user/path/allow +user:/path/allow ``` and appears in the plugin configuration of the path plugin diff --git a/doc/dev/data-structures.md b/doc/dev/data-structures.md index a309e58cc80..b879d355f90 100644 --- a/doc/dev/data-structures.md +++ b/doc/dev/data-structures.md @@ -121,15 +121,15 @@ can append a key to a key set. For example, the key set with the keys ``` -system -system/elektra -system/elektra/mountpoints +system:/ +system:/elektra +system:/elektra/mountpoints ``` would allow the -key `system/elektra/mountpoints/tcl` to be added, +key `system:/elektra/mountpoints/tcl` to be added, but not the key -`system/apps/abc` because `system/apps` is missing. +`system:/apps/abc` because `system:/apps` is missing. File systems enforce this kind of consistency. These semantics are however not useful for configurations. @@ -157,19 +157,19 @@ without a parent key. For example, with the keys ``` -user/sw/apps/abc/current/bindings -user/sw/apps/abc/current/bindings/key1 -user/sw/apps/abc/current/bindings/key2 +user:/sw/apps/abc/current/bindings +user:/sw/apps/abc/current/bindings/key1 +user:/sw/apps/abc/current/bindings/key2 ``` the weak consistency would allow inserting -`user/sw/apps/abc/current/bindings/key3` +`user:/sw/apps/abc/current/bindings/key3` because it is directly below an existing key. It would also allow adding -`user/sw/apps/xyz/current` +`user:/sw/apps/xyz/current` because it does not have any parent key. But it would not allow -`user/sw/apps/abc/current/bindings/dir/key1` +`user:/sw/apps/abc/current/bindings/dir/key1` to add. The worst-case complexity was found to be too expensive, and hence `KeySet` has diff --git a/doc/dev/error-handling.md b/doc/dev/error-handling.md index d4d7b2ac986..340ce3a843c 100644 --- a/doc/dev/error-handling.md +++ b/doc/dev/error-handling.md @@ -152,13 +152,13 @@ Additional metakeys yield all the details. - [error/line] represents the exact line of that source file. Beside errors, Elektra can also emit warnings metadata. While only a single error can be set -on a specific error key, warnings can be up to 100 entries (#00 - #99): +on a specific error key, warnings can be up to 100 entries (#0 - #\_99): - [warnings] indicate that at least one warning is present. The value of the metakey contains the number of warnings which can be accessed. Additional metakeys yield all the details. The warnings are stored in a special array format -which range from 00 to 99. E.g., the first warning number can be accessed by getting the key `warnings/#00/number`. +which range from 0 to \_99. E.g., the first warning number can be accessed by getting the key `warnings/#0/number`. The following metadatas are available and have the same semantics as the error metadata: `[warnings//number]`, `[warnings//description]`, `[warnings//reason]`, `[warnings//module]`, diff --git a/doc/dev/error-message.md b/doc/dev/error-message.md index b987c78b03d..0533b5f45db 100644 --- a/doc/dev/error-message.md +++ b/doc/dev/error-message.md @@ -29,4 +29,4 @@ Actual reason might be in errno or an exception - `"Could not rename file %s. Reason: %s" file.path(), e.what()` Result: `Could not rename file /etc/conf/file.yml. Reason: File is not existent` - `"The key %s contained the value '%s', but only 'unmounted' is supported for non-global clauses at the moment", keyName(key), keyString(key)` - Result: `The key user/my/key contained the value 'mounted', but only 'unmounted' is supported for non-global clauses at the moment` + Result: `The key user:/my/key contained the value 'mounted', but only 'unmounted' is supported for non-global clauses at the moment` diff --git a/doc/dev/plugins-framework.md b/doc/dev/plugins-framework.md index 641d958e9c8..8bf9c88f025 100644 --- a/doc/dev/plugins-framework.md +++ b/doc/dev/plugins-framework.md @@ -71,10 +71,10 @@ and placement information makes the system reliable and robust. With that information, plugins can be placed into a backend in an automatic and secure way. -`system/elektra/modules` provides for every module the information +`system:/elektra/modules` provides for every module the information described above. The entry exists once a plugin of that module is loaded. For each module a special _module backend_ is generated and mounted at -`system/elektra/modules/`. The `elektraPluginGet()` function +`system:/elektra/modules/`. The `elektraPluginGet()` function generates this described contract on requests. For example, the ccode plugin, implements: @@ -82,12 +82,12 @@ For example, the ccode plugin, implements: ```c int elektraCcodeGet(Plugin *handle, KeySet *returned, Key *parentKey) { - if (!strcmp (keyName(parentKey), "system/elektra/modules/ccode")) + if (!strcmp (keyName(parentKey), "system:/elektra/modules/ccode")) { KeySet *contract = ksNew (30, - keyNew ("system/elektra/modules/ccode", + keyNew ("system:/elektra/modules/ccode", KEY_END), - keyNew ("system/elektra/modules/ccode/exports", + keyNew ("system:/elektra/modules/ccode/exports", KEY_END), //... KS_END); @@ -101,8 +101,8 @@ int elektraCcodeGet(Plugin *handle, KeySet *returned, Key *parentKey) We see in the listing above that the plugin generates and returns the contract if, and only if, the name of the `parentKey` is -`system/elektra/modules/ccode`. The user and the contract checker can -access the contract of ccode below the key `system/elektra/modules/ccode` +`system:/elektra/modules/ccode`. The user and the contract checker can +access the contract of ccode below the key `system:/elektra/modules/ccode` in the same way other configuration is accessed. Note that we also have to `return 1` at the end of the contract to not execute the regular functionality of the plugin. @@ -114,7 +114,7 @@ To export it, simply add another `exports` symbol to the contract: ```c -keyNew ("system/elektra/modules/dump/exports/checkconf", KEY_FUNC, +keyNew ("system:/elektra/modules/dump/exports/checkconf", KEY_FUNC, elektraCcodeCheckConf, KEY_END); ``` diff --git a/doc/help/elektra-bootstrapping.md b/doc/help/elektra-bootstrapping.md index c5a0bb31c84..bccc46fff0f 100644 --- a/doc/help/elektra-bootstrapping.md +++ b/doc/help/elektra-bootstrapping.md @@ -18,7 +18,7 @@ usage of the default backend by simple mounting another backend to `/`. The mounting configuration (the configuration how to mount the mount points) also needs to be stored somewhere. The so called **init backend** is responsible for fetching configuration -from `system/elektra`, where the mount points are stored. +from `system:/elektra`, where the mount points are stored. Again `KDB_STORAGE` and `KDB_RESOLVER` is used, but now they write into the configuration file `KDB_DB_INIT` (`elektra.ecf` by default). @@ -28,9 +28,9 @@ symbolic links (`libelektra-resolver.so` and `libelektra-storage.so`) to concret and thus can be changed without recompilation. The **init backend** is guaranteed to stay mounted at -`system/elektra` where the configuration for Elektra +`system:/elektra` where the configuration for Elektra itself is stored. After mounting all backends, Elektra checks if -`system/elektra` still resides at the default backend. If not, +`system:/elektra` still resides at the default backend. If not, the init backend will be mounted there. ## SUMMARY @@ -38,7 +38,7 @@ the init backend will be mounted there. To summarize, this approach delivers a good out-of-the-box experience capable of storing configuration. For special use cases, applications and administrators can mount specific backends anywhere except at, and -below, `system/elektra`. On `kdbOpen()`, the system +below, `system:/elektra`. On `kdbOpen()`, the system bootstraps itself starting with the init backend. The default backend consists of a default storage plugin and default diff --git a/doc/help/elektra-cascading.md b/doc/help/elektra-cascading.md index 2543e149ff6..8b3fa278f82 100644 --- a/doc/help/elektra-cascading.md +++ b/doc/help/elektra-cascading.md @@ -35,7 +35,7 @@ They can be used like this: ```sh kdb set /overrides/test "example override" -sudo kdb meta-set spec/test override/#0 /overrides/test +sudo kdb meta-set spec:/test override/#0 /overrides/test ``` ## CASCADING diff --git a/doc/help/elektra-granularity.md b/doc/help/elektra-granularity.md index e908a7e5bdc..6d32bdb8d26 100644 --- a/doc/help/elektra-granularity.md +++ b/doc/help/elektra-granularity.md @@ -18,10 +18,10 @@ different backends. Splitting up key sets makes sense if any application requests only a part of the configuration. No benefits arise if every application requests all keys anyway. -Let us assume that many keys reside in `user/sw` and an -application only needs the keys in `user/sw/org/app`. To save memory +Let us assume that many keys reside in `user:/sw` and an +application only needs the keys in `user:/sw/org/app`. To save memory and get better startup-times for the application, a new backend can be -mounted at `user/sw/org/app`. On the other hand, every mounted backend +mounted at `user:/sw/org/app`. On the other hand, every mounted backend causes a small run-time overhead in the overall configuration system. The solution in Elektra is flexible, because the user decides the diff --git a/doc/help/elektra-hierarchy.md b/doc/help/elektra-hierarchy.md index 4597ef0c4e2..6aa63d1cd13 100644 --- a/doc/help/elektra-hierarchy.md +++ b/doc/help/elektra-hierarchy.md @@ -4,15 +4,15 @@ These mount points are always available. -## system/elektra/modules +## system:/elektra/modules Information about currently loaded modules. -## system/elektra/mountpoints +## system:/elektra/mountpoints The mount points present in the system. -## system/elektra/version +## system:/elektra/version Version information. @@ -20,26 +20,26 @@ Version information. Use `kdb mount-info` to mount these mount points. -## system/info/elektra/constants +## system:/info/elektra/constants Gives information about how Elektra was build. -## system/info/elektra/uname +## system:/info/elektra/uname System Information given with `uname`. -## system/info/elektra/desktop +## system:/info/elektra/desktop System Information about currently running desktop. -## system/info/elektra/metadata +## system:/info/elektra/metadata Gives information about which metadata is currently understood by Elektra. `METADATA.ini` needs to be mounted there. -## system/info/elektra/contract +## system:/info/elektra/contract Gives information about clauses in plugin's contract that is currently understood. diff --git a/doc/help/elektra-key-names.md b/doc/help/elektra-key-names.md index 1b8b3cf6f7c..21d1e2d45ff 100644 --- a/doc/help/elektra-key-names.md +++ b/doc/help/elektra-key-names.md @@ -18,10 +18,10 @@ Only the administrator can change system configuration. Examples of valid system key names: ``` -system -system/hosts/hostname -system/sw/apache/httpd/#0/current/num_processes -system/sw/apps/abc/#0/current/default-setting +system:/ +system:/hosts/hostname +system:/sw/apache/httpd/#0/current/num_processes +system:/sw/apps/abc/#0/current/default-setting ``` user configuration is empty until the user changes some preferences. @@ -32,18 +32,18 @@ and anything not useful for the rest of the system. Examples of valid user key names: ``` -user -user/env/#1/LD_LIBRARY_PATH -user/sw/apps/abc/#0/current/default-setting -user/sw/kde/kicker/#0/current/preferred_applications/#0 +user:/ +user:/env/#1/LD_LIBRARY_PATH +user:/sw/apps/abc/#0/current/default-setting +user:/sw/kde/kicker/#0/current/preferred_applications/#0 ``` The slash (`/`) separates key names and structures them hierarchically. If two keys start with the same key names, but one key name continues after a slash, this key is **below** the other and is called a -_subkey_. For example `user/sw/apps/abc/current` is a subkey of the -key `user/sw/apps`. The key is not directly below but, for example, -`user/sw/apps/abc` is. Various functions in `keytest` implement +_subkey_. For example `user:/sw/apps/abc/current` is a subkey of the +key `user:/sw/apps`. The key is not directly below but, for example, +`user:/sw/apps/abc` is. Various functions in `keytest` implement ways to determine the relationship between two keys. ## Conventions @@ -100,8 +100,8 @@ the key names of software-applications should always start with: `/sw/org/myapp/#/%/` where `#` is a major version number, e.g. `#3` for the 4th version and `%` is a profile (`%` for default profile). This way, from a sysadmin perspective, it will be possible to copy the - `system/sw/myapp/#3/%/` tree to something like - `system/sw/myapp/#3/old/` and keep system clean and organized. + `system:/sw/myapp/#3/%/` tree to something like + `system:/sw/myapp/#3/old/` and keep system clean and organized. ## SEE ALSO diff --git a/doc/help/elektra-spec.md b/doc/help/elektra-spec.md index 10d389bb104..b57bea6fbbf 100644 --- a/doc/help/elektra-spec.md +++ b/doc/help/elektra-spec.md @@ -55,13 +55,13 @@ fallback/#0=/somewhere/else namespace/#0=user ``` -1. When this file is mounted to `spec/sw/app/#0` we specify, that +1. When this file is mounted to `spec:/sw/app/#0` we specify, that for the key `/sw/app/#0/promise` only the namespace `user` should be used. 2. If this key was not found, but `/somewhere/else` is present, we will use this key instead. The `fallback` technique is very powerful: it allows us to have (recursive) links between applications. In the example above, - the application is tricked in receiving e.g. the key `user/somewhere/else` + the application is tricked in receiving e.g. the key `user:/somewhere/else` when `promise` was not available. 3. The value `20` will be used as default, even if no configuration file is found. diff --git a/doc/help/kdb-cache.md b/doc/help/kdb-cache.md index fc7be58dcc3..880588f5988 100644 --- a/doc/help/kdb-cache.md +++ b/doc/help/kdb-cache.md @@ -34,7 +34,7 @@ subcommand can only remove a user's cache files (i.e. not system wide). ## EXAMPLES ```sh -# Backup-and-Restore: system/elektra/cache +# Backup-and-Restore: system:/elektra/cache # Enable the cache kdb cache enable diff --git a/doc/help/kdb-cmerge.md b/doc/help/kdb-cmerge.md index dedf958144b..de347124813 100644 --- a/doc/help/kdb-cmerge.md +++ b/doc/help/kdb-cmerge.md @@ -80,14 +80,14 @@ Conflicts occur when a key has a different value in all three key sets or when o To complete a simple merge of three KeySets:
````sh -kdb set user/base "A" -#> Create a new key user/base with string "A" -kdb set user/their "A" -#> Create a new key user/their with string "A" -kdb set user/our "B" -#> Create a new key user/our with string "B" -kdb cmerge user/our user/their user/base user/result -kdb get user/result +kdb set user:/base "A" +#> Create a new key user:/base with string "A" +kdb set user:/their "A" +#> Create a new key user:/their with string "A" +kdb set user:/our "B" +#> Create a new key user:/our with string "B" +kdb cmerge user:/our user:/their user:/base user:/result +kdb get user:/result #>B ```
diff --git a/doc/help/kdb-complete.md b/doc/help/kdb-complete.md index 4c8daa7ef0e..46fbafb7054 100644 --- a/doc/help/kdb-complete.md +++ b/doc/help/kdb-complete.md @@ -45,27 +45,27 @@ originates from. ## EXAMPLES ```sh -# Backup-and-Restore: user/tests/complete/examples +# Backup-and-Restore: user:/tests/complete/examples # Create the keys we use for the examples -kdb set user/tests/complete/examples/kdb-complete/level1 foo -kdb set user/tests/complete/examples/kdb-complete/lvl1/lvl2 bar -kdb set user/tests/complete/examples/kdb-complete/lvl1/lvl2/lvl3/lvl4/lvl5 fizz -kdb set user/tests/complete/examples/kdb-complete/buzz fizzBuzz -kdb set user/tests/complete/examples/kdb-complete/#array_1 asdf -kdb set user/tests/complete/examples/kdb-complete/% nothing +kdb set user:/tests/complete/examples/kdb-complete/level1 foo +kdb set user:/tests/complete/examples/kdb-complete/lvl1/lvl2 bar +kdb set user:/tests/complete/examples/kdb-complete/lvl1/lvl2/lvl3/lvl4/lvl5 fizz +kdb set user:/tests/complete/examples/kdb-complete/buzz fizzBuzz +kdb set user:/tests/complete/examples/kdb-complete/#1 asdf +kdb set user:/tests/complete/examples/kdb-complete/% nothing # list suggestions for namespaces starting with us, only the current level kdb complete us --max-depth=1 -#> user/ +#> user:/ # list suggestions for namespaces starting with user, only the current level kdb complete user --max-depth=1 -#> user/ +#> user:/ # list suggestions for the namespace user, only the next level as it ends with / # note the difference to the previous example, which uses no trailing / -kdb complete user/ --max-depth=1 +kdb complete user:/ --max-depth=1 # STDOUT-REGEX: .+ # list all possible namespaces or mount points, only the current level @@ -74,24 +74,24 @@ kdb complete --max-depth=1 # list suggestions for /tests/complete/examples/kdb-complete, only the current level kdb complete /tests/complete/examples/kdb-complete --max-depth=1 -#> user/tests/complete/examples/kdb-complete/ +#> user:/tests/complete/examples/kdb-complete/ # list suggestions for /tests/complete/examples/kdb-complete/, only the next level # again, note the difference to the previous example which has no trailing / kdb complete /tests/complete/examples/kdb-complete/ --max-depth=1 -#> user/tests/complete/examples/kdb-complete/% -#> user/tests/complete/examples/kdb-complete/#array_1 -#> user/tests/complete/examples/kdb-complete/buzz -#> user/tests/complete/examples/kdb-complete/level1 -#> user/tests/complete/examples/kdb-complete/lvl1/ +#> user:/tests/complete/examples/kdb-complete/% +#> user:/tests/complete/examples/kdb-complete/#1 +#> user:/tests/complete/examples/kdb-complete/buzz +#> user:/tests/complete/examples/kdb-complete/level1 +#> user:/tests/complete/examples/kdb-complete/lvl1/ # list suggestions for /tests/complete/examples/kdb-complete which are minimum 2 levels # away from that key, and maximum 4 levels away kdb complete /tests/complete/examples/kdb-complete/ --min-depth=2 --max-depth=4 -#> user/tests/complete/examples/kdb-complete/lvl1/lvl2/lvl3/ -#> user/tests/complete/examples/kdb-complete/lvl1/lvl2/lvl3/lvl4/ +#> user:/tests/complete/examples/kdb-complete/lvl1/lvl2/lvl3/ +#> user:/tests/complete/examples/kdb-complete/lvl1/lvl2/lvl3/lvl4/ -kdb rm -r user/tests/complete/examples/kdb-complete +kdb rm -r user:/tests/complete/examples/kdb-complete ``` ## SEE ALSO diff --git a/doc/help/kdb-cp.md b/doc/help/kdb-cp.md index a70337d8b61..52f8f42ae63 100644 --- a/doc/help/kdb-cp.md +++ b/doc/help/kdb-cp.md @@ -52,49 +52,49 @@ This command will return the following values as an exit status: ## EXAMPLES ```sh -# Backup-and-Restore: user/tests/cp/examples +# Backup-and-Restore: user:/tests/cp/examples # Create the keys we use for the examples -kdb set user/tests/cp/examples/kdb-cp/key key1 -kdb set user/tests/cp/examples/kdb-cp/key/first key -kdb set user/tests/cp/examples/kdb-cp/key/second key -kdb set user/tests/cp/examples/kdb-cp/cpkey key1 -kdb set user/tests/cp/examples/kdb-cp/cpkey/first key -kdb set user/tests/cp/examples/kdb-cp/cpkey/second key -kdb set user/tests/cp/examples/kdb-cp/cpkeyerror/first key -kdb set user/tests/cp/examples/kdb-cp/cpkeyerror/second anotherValue -kdb set user/tests/cp/examples/kdb-cp/another/key one -kdb set user/tests/cp/examples/kdb-cp/another/value two +kdb set user:/tests/cp/examples/kdb-cp/key key1 +kdb set user:/tests/cp/examples/kdb-cp/key/first key +kdb set user:/tests/cp/examples/kdb-cp/key/second key +kdb set user:/tests/cp/examples/kdb-cp/cpkey key1 +kdb set user:/tests/cp/examples/kdb-cp/cpkey/first key +kdb set user:/tests/cp/examples/kdb-cp/cpkey/second key +kdb set user:/tests/cp/examples/kdb-cp/cpkeyerror/first key +kdb set user:/tests/cp/examples/kdb-cp/cpkeyerror/second anotherValue +kdb set user:/tests/cp/examples/kdb-cp/another/key one +kdb set user:/tests/cp/examples/kdb-cp/another/value two # To copy a single key: -kdb cp user/tests/cp/examples/kdb-cp/key user/tests/cp/examples/kdb-cp/key2 +kdb cp user:/tests/cp/examples/kdb-cp/key user:/tests/cp/examples/kdb-cp/key2 #> # To copy multiple keys: -kdb cp -r user/tests/cp/examples/kdb-cp/key user/tests/cp/examples/kdb-cp/copied +kdb cp -r user:/tests/cp/examples/kdb-cp/key user:/tests/cp/examples/kdb-cp/copied #> # If the target-key already exists and has a different value, cp fails: -kdb cp -r user/tests/cp/examples/kdb-cp/key user/tests/cp/examples/kdb-cp/cpkeyerror +kdb cp -r user:/tests/cp/examples/kdb-cp/key user:/tests/cp/examples/kdb-cp/cpkeyerror # RET: 11 # If the target-key already exists and has the same value as the source, everything is fine: -kdb cp -r user/tests/cp/examples/kdb-cp/key user/tests/cp/examples/kdb-cp/cpkey +kdb cp -r user:/tests/cp/examples/kdb-cp/key user:/tests/cp/examples/kdb-cp/cpkey #> # To force the copy of keys: -kdb cp -rf user/tests/cp/examples/kdb-cp/key user/tests/cp/examples/kdb-cp/cpkeyerror +kdb cp -rf user:/tests/cp/examples/kdb-cp/key user:/tests/cp/examples/kdb-cp/cpkeyerror #> # Now the key-values of /cpkeyerror are overwritten: -kdb export user/tests/cp/examples/kdb-cp/cpkeyerror mini +kdb export user:/tests/cp/examples/kdb-cp/cpkeyerror mini #> =key1 #> first=key #> second=key # To copy keys below an existing key: -kdb cp -r user/tests/cp/examples/kdb-cp/another user/tests/cp/examples/kdb-cp/another/key +kdb cp -r user:/tests/cp/examples/kdb-cp/another user:/tests/cp/examples/kdb-cp/another/key #> -kdb rm -r user/tests/cp/examples/kdb-cp/ +kdb rm -r user:/tests/cp/examples/kdb-cp/ ``` diff --git a/doc/help/kdb-editor.md b/doc/help/kdb-editor.md index 746b0bfb9a1..615a0ce2abb 100644 --- a/doc/help/kdb-editor.md +++ b/doc/help/kdb-editor.md @@ -80,8 +80,8 @@ The other strategies are implemented by the merge framework and are documented i ## EXAMPLES -To change the configuration in KDB below `user/ini` with `/usr/bin/vim`, you would use:
-`kdb editor -e /usr/bin/vim user/ini` +To change the configuration in KDB below `user:/ini` with `/usr/bin/vim`, you would use:
+`kdb editor -e /usr/bin/vim user:/ini` Or set a new editor as default using:
`kdb set /sw/elektra/kdb/#0/current/editor /usr/bin/nano` diff --git a/doc/help/kdb-export.md b/doc/help/kdb-export.md index 134d0501208..7f755b1bf15 100644 --- a/doc/help/kdb-export.md +++ b/doc/help/kdb-export.md @@ -28,7 +28,7 @@ The `storage` plugin can be configured at compile-time or changed by the link `l - `-C`, `--color `: Print never/auto(default)/always colored output. - `-E`, `--without-elektra`: - Omit the `system/elektra` directory. + Omit the `system:/elektra` directory. - `-c`, `--plugins-config `: Add a configuration to the format plugin. - `-v`, `--verbose`: @@ -49,8 +49,8 @@ To view your full key database in Elektra’s `storage` format:
To backup your full key database in Elektra’s `storage` format to a file called `full-backup.ecf`:
`kdb export / > full-backup.ecf`
-To backup a keyset stored in `user/keyset` in the `ini` format to a file called `keyset.ini`:
-`kdb export user/keyset ini > keyset.ini`
+To backup a keyset stored in `user:/keyset` in the `ini` format to a file called `keyset.ini`:
+`kdb export user:/keyset ini > keyset.ini`
Change default format to `simpleini`:
`kdb set /sw/elektra/kdb/#0/current/format simpleini` @@ -58,10 +58,10 @@ Change default format to `simpleini`:
Create two key values and export them as `xml`: ```sh -kdb set user/tests/kdb-export/one one -kdb set user/tests/kdb-export/two two +kdb set user:/tests/kdb-export/one one +kdb set user:/tests/kdb-export/two two -kdb export user/tests/kdb-export/ xml +kdb export user:/tests/kdb-export/ xml #> #> #> @@ -72,17 +72,17 @@ kdb export user/tests/kdb-export/ xml #> -kdb rm -r user/tests +kdb rm -r user:/tests # cleanup ``` Create two key values and export them with the `xerces` plugin: ```sh -kdb set user/tests/kdb-export/one one -kdb set user/tests/kdb-export/two two +kdb set user:/tests/kdb-export/one one +kdb set user:/tests/kdb-export/two two -kdb export user/tests/kdb-export/ xerces +kdb export user:/tests/kdb-export/ xerces #> #> #> @@ -92,7 +92,7 @@ kdb export user/tests/kdb-export/ xerces #> #> -kdb rm -r user/tests +kdb rm -r user:/tests # cleanup ``` diff --git a/doc/help/kdb-file.md b/doc/help/kdb-file.md index f7087453eed..c93de7c6a16 100644 --- a/doc/help/kdb-file.md +++ b/doc/help/kdb-file.md @@ -41,7 +41,7 @@ This command makes use of Elektra’s `resolver` plugin which the uer can learn ## EXAMPLES To find which file a key is stored in:
-`kdb file user/example/key`
+`kdb file user:/example/key`
## SEE ALSO diff --git a/doc/help/kdb-find.md b/doc/help/kdb-find.md index b71dc30262d..306a4012ebe 100644 --- a/doc/help/kdb-find.md +++ b/doc/help/kdb-find.md @@ -30,34 +30,34 @@ This command will list the name of all keys that contain `regex`. ## EXAMPLES ```sh -# Backup-and-Restore: user/tests/find +# Backup-and-Restore: user:/tests/find # We use the `dump` plugin, since some storage plugins, e.g. INI, -# create intermediate keys, such as `user/tests/find/tests/foo` +# create intermediate keys, such as `user:/tests/find/tests/foo` # for the following test. -sudo kdb mount find.ecf user/tests/find dump +sudo kdb mount find.ecf user:/tests/find dump # Create the keys we use for the examples -kdb set user/tests/find/tests val1 -kdb set user/tests/find/tests/foo/bar val2 -kdb set user/tests/find/tests/fizz/buzz fizzbuzz -kdb set user/tests/find/tostfizz val3 -kdb set user/tests/find/tust/level lvl +kdb set user:/tests/find/tests val1 +kdb set user:/tests/find/tests/foo/bar val2 +kdb set user:/tests/find/tests/fizz/buzz fizzbuzz +kdb set user:/tests/find/tostfizz val3 +kdb set user:/tests/find/tust/level lvl # list all keys containing /tests/find/t[eo] kdb find '/tests/find/t[eo]' -#> user/tests/find/tests -#> user/tests/find/tests/fizz/buzz -#> user/tests/find/tests/foo/bar -#> user/tests/find/tostfizz +#> user:/tests/find/tests +#> user:/tests/find/tests/fizz/buzz +#> user:/tests/find/tests/foo/bar +#> user:/tests/find/tostfizz # list all keys containing fizz kdb find 'fizz' -#> user/tests/find/tests/fizz/buzz -#> user/tests/find/tostfizz +#> user:/tests/find/tests/fizz/buzz +#> user:/tests/find/tostfizz kdb rm -r /tests/find -sudo kdb umount user/tests/find +sudo kdb umount user:/tests/find ``` ## SEE ALSO diff --git a/doc/help/kdb-get.md b/doc/help/kdb-get.md index 55edcb7774d..be6eb8875d2 100644 --- a/doc/help/kdb-get.md +++ b/doc/help/kdb-get.md @@ -54,19 +54,19 @@ This command will return the following values as an exit status: ## EXAMPLES ```sh -# Backup-and-Restore: user/tests/get/examples +# Backup-and-Restore: user:/tests/get/examples # We use the `dump` plugin, since some storage plugins, e.g. INI, # create intermediate keys. -sudo kdb mount get.ecf user/tests/get/examples/kdb-get dump -sudo kdb mount get.ecf spec/tests/get/examples/kdb-get dump +sudo kdb mount get.ecf user:/tests/get/examples/kdb-get dump +sudo kdb mount get.ecf spec:/tests/get/examples/kdb-get dump # Create the keys we use for the examples -kdb set user/tests/get/examples/kdb-get/key myKey +kdb set user:/tests/get/examples/kdb-get/key myKey kdb meta-set /tests/get/examples/kdb-get/anotherKey default defaultValue # To get the value of a key: -kdb get user/tests/get/examples/kdb-get/key +kdb get user:/tests/get/examples/kdb-get/key #> myKey # To get the value of a key using a cascading lookup: @@ -80,33 +80,33 @@ kdb get -n /tests/get/examples/kdb-get/key # To explain why a specific key was used (for cascading keys): kdb get -v /tests/get/examples/kdb-get/key #> got 3 keys -#> searching spec/tests/get/examples/kdb-get/key, found: , options: KDB_O_CALLBACK -#> searching proc/tests/get/examples/kdb-get/key, found: -#> searching dir/tests/get/examples/kdb-get/key, found: -#> searching user/tests/get/examples/kdb-get/key, found: user/tests/get/examples/kdb-get/key -#> The resulting keyname is user/tests/get/examples/kdb-get/key +#> searching spec:/tests/get/examples/kdb-get/key, found: , options: KDB_O_CALLBACK +#> searching proc:/tests/get/examples/kdb-get/key, found: +#> searching dir:/tests/get/examples/kdb-get/key, found: +#> searching user:/tests/get/examples/kdb-get/key, found: user:/tests/get/examples/kdb-get/key +#> The resulting keyname is user:/tests/get/examples/kdb-get/key #> The resulting value size is 6 #> myKey # Output if only a default value is set for a key: kdb get -v /tests/get/examples/kdb-get/anotherKey #> got 3 keys -#> searching spec/tests/get/examples/kdb-get/anotherKey, found: spec/tests/get/examples/kdb-get/anotherKey, options: KDB_O_CALLBACK -#> The key was not found in any other namespace, taking the default from the metadata -#> The resulting keyname is /tests/get/examples/kdb-get/anotherKey +#> searching spec:/tests/get/examples/kdb-get/anotherKey, found: spec:/tests/get/examples/kdb-get/anotherKey, options: KDB_O_CALLBACK +#> The key was not found in any other namespace, taking the default +#> The resulting keyname is default:/tests/get/examples/kdb-get/anotherKey #> The resulting value size is 13 #> defaultValue -kdb rm user/tests/get/examples/kdb-get/key -kdb rm spec/tests/get/examples/kdb-get/anotherKey -sudo kdb umount user/tests/get/examples/kdb-get -sudo kdb umount spec/tests/get/examples/kdb-get +kdb rm user:/tests/get/examples/kdb-get/key +kdb rm spec:/tests/get/examples/kdb-get/anotherKey +sudo kdb umount user:/tests/get/examples/kdb-get +sudo kdb umount spec:/tests/get/examples/kdb-get ``` To use bookmarks:
`kdb get +kdb/format` -This command will actually get `user/sw/elektra/kdb/#0/current/format` if the bookmarks commands from +This command will actually get `user:/sw/elektra/kdb/#0/current/format` if the bookmarks commands from [kdb-set(1)](kdb-set.md) man pages are executed before. ## SEE ALSO diff --git a/doc/help/kdb-global-mount.md b/doc/help/kdb-global-mount.md index 66ea7b8edbc..51a6d31e651 100644 --- a/doc/help/kdb-global-mount.md +++ b/doc/help/kdb-global-mount.md @@ -16,7 +16,7 @@ This command allows a user to globally mount some plugins that will be part of e ## IMPORTANT This command writes into the `/etc` directory and as such it requires root permissions. -Use `kdb file system/elektra/globalplugins` to find out where exactly it will write to. +Use `kdb file system:/elektra/globalplugins` to find out where exactly it will write to. ## OPTIONS diff --git a/doc/help/kdb-global-umount.md b/doc/help/kdb-global-umount.md index a102bc18b66..da938532441 100644 --- a/doc/help/kdb-global-umount.md +++ b/doc/help/kdb-global-umount.md @@ -22,7 +22,7 @@ Unmount a global plugin from the key database. ## EXAMPLES ```sh -# Backup-and-Restore: system/elektra/globalplugins +if [ -f "$(kdb file system:/elektra/globalplugins)" ]; then mv "$(kdb file system:/elektra/globalplugins)" "globalplugins.bak"; else touch "globalplugins.rm"; fi sudo kdb global-mount tracer @@ -39,6 +39,8 @@ sudo kdb global-umount spec sudo kdb global-mount #> + +if [ -f "globalplugins.rm" ]; then rm "$(kdb file system:/elektra/globalplugins)" "globalplugins.rm"; else mv "globalplugins.bak" "$(kdb file system:/elektra/globalplugins)"; fi ``` ## SEE ALSO diff --git a/doc/help/kdb-help.md b/doc/help/kdb-help.md index 2c1b4d89500..93789dd8751 100644 --- a/doc/help/kdb-help.md +++ b/doc/help/kdb-help.md @@ -28,4 +28,4 @@ Show how to set keys: `kdb help set` Use the info program as man page viewer for the current user: -`kdb set user/sw/elektra/kdb/#0/current/man /usr/bin/info` +`kdb set user:/sw/elektra/kdb/#0/current/man /usr/bin/info` diff --git a/doc/help/kdb-import.md b/doc/help/kdb-import.md index 00e3fc3f8d5..0fbc2a22246 100644 --- a/doc/help/kdb-import.md +++ b/doc/help/kdb-import.md @@ -70,45 +70,45 @@ The other strategies are implemented by the merge framework and are documented i ## EXAMPLES -To import a configuration stored in the XML format in a file called `example.xml` below `user/keyset`:
-`kdb import user/keyset xmltool < example.xml` +To import a configuration stored in the XML format in a file called `example.xml` below `user:/keyset`:
+`kdb import user:/keyset xmltool < example.xml` -To import a configuration stored in the `ini` format in a file called `example.ini` below `user/keyset` replacing any previous keys stored there:
-`cat example.ini | kdb import -s cut user/keyset ini` +To import a configuration stored in the `ini` format in a file called `example.ini` below `user:/keyset` replacing any previous keys stored there:
+`cat example.ini | kdb import -s cut user:/keyset ini` -To import a configuration stored in the `ini` format in a file called `example.ini` below `user/keyset` keeping any previous keys stored there that aren't present in the newly imported configuration:
-`cat example.ini | kdb import -s import user/keyset ini` +To import a configuration stored in the `ini` format in a file called `example.ini` below `user:/keyset` keeping any previous keys stored there that aren't present in the newly imported configuration:
+`cat example.ini | kdb import -s import user:/keyset ini` -To restore a backup (stored as `sw.ecf`) of a user's configuration below `system/sw`:
-`cat sw.ecf | kdb import system/sw` +To restore a backup (stored as `sw.ecf`) of a user's configuration below `system:/sw`:
+`cat sw.ecf | kdb import system:/sw` To import a sample `xml` content with the `xerces` plugin: ```sh # import two keys from a xml string -kdb import user/tests/kdb-import/ xerces <<< "onetwo" +kdb import user:/tests/kdb-import/ xerces <<< "onetwo" # get the values and verify they got imported correctly -kdb get user/tests/kdb-import/one +kdb get user:/tests/kdb-import/one #> one -kdb get user/tests/kdb-import/two +kdb get user:/tests/kdb-import/two #> two -kdb rm -r user/tests/kdb-import +kdb rm -r user:/tests/kdb-import ``` To import a sample `xml` content via specifying the file format directly: ```sh # import two keys from a xml string -kdb import user/tests/kdb-import/ xml <<< "onetwo" +kdb import user:/tests/kdb-import/ xml <<< "onetwo" # get the values and verify they got imported correctly -kdb get user/tests/kdb-import/one +kdb get user:/tests/kdb-import/one #> one -kdb get user/tests/kdb-import/two +kdb get user:/tests/kdb-import/two #> two -kdb rm -r user/tests/kdb-import +kdb rm -r user:/tests/kdb-import ``` ## SEE ALSO diff --git a/doc/help/kdb-install-config-file.md b/doc/help/kdb-install-config-file.md index 2a85f2032e7..b462d2be862 100644 --- a/doc/help/kdb-install-config-file.md +++ b/doc/help/kdb-install-config-file.md @@ -29,4 +29,4 @@ Elektra. There are two possible scenarios: To install the config file at `~/.config/installing.ini` we can use the following command -`kdb install-config-file user/tests/installing installing.ini ini` +`kdb install-config-file user:/tests/installing installing.ini ini` diff --git a/doc/help/kdb-ls.md b/doc/help/kdb-ls.md index ca30eaf303f..113c21af49c 100644 --- a/doc/help/kdb-ls.md +++ b/doc/help/kdb-ls.md @@ -36,32 +36,32 @@ This command will list the name of all keys below a given path. ## EXAMPLES ```sh -# Backup-and-Restore: user/tests/examples +# Backup-and-Restore: user:/tests/examples # We use `dump` as storage format here, since storage plugins such as INI -# automatically add keys between levels (e.g. `user/tests/examples/kdb-ls/test/foo`). -sudo kdb mount ls.ecf user/tests/examples dump +# automatically add keys between levels (e.g. `user:/tests/examples/kdb-ls/test/foo`). +sudo kdb mount ls.ecf user:/tests/examples dump # Create the keys we use for the examples -kdb set user/tests/examples/kdb-ls/test val1 -kdb set user/tests/examples/kdb-ls/test/foo/bar val2 -kdb set user/tests/examples/kdb-ls/test/fizz/buzz fizzbuzz -kdb set user/tests/examples/kdb-ls/tost val3 -kdb set user/tests/examples/kdb-ls/tost/level lvl +kdb set user:/tests/examples/kdb-ls/test val1 +kdb set user:/tests/examples/kdb-ls/test/foo/bar val2 +kdb set user:/tests/examples/kdb-ls/test/fizz/buzz fizzbuzz +kdb set user:/tests/examples/kdb-ls/tost val3 +kdb set user:/tests/examples/kdb-ls/tost/level lvl # list all keys below /tests/examples/kdb-ls kdb ls /tests/examples/kdb-ls -#> user/tests/examples/kdb-ls/test -#> user/tests/examples/kdb-ls/test/fizz/buzz -#> user/tests/examples/kdb-ls/test/foo/bar -#> user/tests/examples/kdb-ls/tost -#> user/tests/examples/kdb-ls/tost/level +#> user:/tests/examples/kdb-ls/test +#> user:/tests/examples/kdb-ls/test/fizz/buzz +#> user:/tests/examples/kdb-ls/test/foo/bar +#> user:/tests/examples/kdb-ls/tost +#> user:/tests/examples/kdb-ls/tost/level # list the next level of keys below /tests/examples/kdb-ls # note that if the search key ends with a /, it lists the next level kdb ls /tests/examples/kdb-ls/ --max-depth=1 -#> user/tests/examples/kdb-ls/test -#> user/tests/examples/kdb-ls/tost +#> user:/tests/examples/kdb-ls/test +#> user:/tests/examples/kdb-ls/tost # list the current level of keys below /tests/examples/kdb-ls # note the difference to the previous example @@ -71,27 +71,27 @@ kdb ls /tests/examples/kdb-ls --max-depth=1 # list all keys below /tests/examples/kdb-ls with are minimum 1 level (inclusive) away from that key # and maximum 2 levels away (exclusive) kdb ls /tests/examples/kdb-ls --min-depth=1 --max-depth=2 -#> user/tests/examples/kdb-ls/test -#> user/tests/examples/kdb-ls/tost +#> user:/tests/examples/kdb-ls/test +#> user:/tests/examples/kdb-ls/tost # list all keys below /tests/examples/kdb-ls/test kdb ls /tests/examples/kdb-ls/test -#> user/tests/examples/kdb-ls/test -#> user/tests/examples/kdb-ls/test/fizz/buzz -#> user/tests/examples/kdb-ls/test/foo/bar +#> user:/tests/examples/kdb-ls/test +#> user:/tests/examples/kdb-ls/test/fizz/buzz +#> user:/tests/examples/kdb-ls/test/foo/bar # list all keys under /tests/examples/kdb-ls in verbose mode kdb ls /tests/examples/kdb-ls/ -v #> size of all keys in mount point: 5 #> size of requested keys: 5 -#> user/tests/examples/kdb-ls/test -#> user/tests/examples/kdb-ls/test/fizz/buzz -#> user/tests/examples/kdb-ls/test/foo/bar -#> user/tests/examples/kdb-ls/tost -#> user/tests/examples/kdb-ls/tost/level - -kdb rm -r user/tests/examples -sudo kdb umount user/tests/examples +#> user:/tests/examples/kdb-ls/test +#> user:/tests/examples/kdb-ls/test/fizz/buzz +#> user:/tests/examples/kdb-ls/test/foo/bar +#> user:/tests/examples/kdb-ls/tost +#> user:/tests/examples/kdb-ls/tost/level + +kdb rm -r user:/tests/examples +sudo kdb umount user:/tests/examples ``` ## SEE ALSO diff --git a/doc/help/kdb-merge.md b/doc/help/kdb-merge.md index 89e6879aeaf..e998674798f 100644 --- a/doc/help/kdb-merge.md +++ b/doc/help/kdb-merge.md @@ -71,13 +71,13 @@ To interactively resolve conflicts, use the `-i` option. ## EXAMPLES To complete a simple merge of three KeySets:
-`kdb merge user/ours user/theirs user/base user/result`
+`kdb merge user:/ours user:/theirs user:/base user:/result`
To complete a merge whilst using the `ours` version of the KeySet to resolve conflicts:
-`kdb merge -s ours user/ours user/theirs user/base user/result`
+`kdb merge -s ours user:/ours user:/theirs user:/base user:/result`
To complete a three-way merge and overwrite all current keys in the `resultpath`:
-`kdb merge -s cut user/ours user/theirs user/base user/result`
+`kdb merge -s cut user:/ours user:/theirs user:/base user:/result`
## SEE ALSO diff --git a/doc/help/kdb-meta-get.md b/doc/help/kdb-meta-get.md index 63f70626332..bc214e1628c 100644 --- a/doc/help/kdb-meta-get.md +++ b/doc/help/kdb-meta-get.md @@ -45,11 +45,11 @@ This command will return the following values as an exit status:
## EXAMPLES -To get the value of a metakey called `description` stored in the key `spec/example/key`:
-`kdb meta-get spec/example/key description` +To get the value of a metakey called `description` stored in the key `spec:/example/key`:
+`kdb meta-get spec:/example/key description` -To get the value of metakey called `override/#0` stored in the key `spec/example/dir/key`:
-`kdb meta-get spec/example/dir/key "override/#0"` +To get the value of metakey called `override/#0` stored in the key `spec:/example/dir/key`:
+`kdb meta-get spec:/example/dir/key "override/#0"` ## SEE ALSO diff --git a/doc/help/kdb-meta-rm.md b/doc/help/kdb-meta-rm.md index 2ca62e64f6a..03a7a08ba05 100644 --- a/doc/help/kdb-meta-rm.md +++ b/doc/help/kdb-meta-rm.md @@ -28,7 +28,7 @@ This command removes a metakey of a key from the Key database. ## EXAMPLES To remove metakey `metakey` of a key:
-`kdb meta-rm user/example metakey` +`kdb meta-rm user:/example metakey` ## SEE ALSO diff --git a/doc/help/kdb-meta-set.md b/doc/help/kdb-meta-set.md index 0410d116033..6fdf4a0b8aa 100644 --- a/doc/help/kdb-meta-set.md +++ b/doc/help/kdb-meta-set.md @@ -50,10 +50,10 @@ that is the place where you usually want to set metadata. ## EXAMPLES -To set a metakey called `description` associated with the key `user/example/key` to the value `Hello World!`:
-`kdb meta-set spec/example/key description "Hello World!"` +To set a metakey called `description` associated with the key `user:/example/key` to the value `Hello World!`:
+`kdb meta-set spec:/example/key description "Hello World!"` -To create a new key `spec/example/newkey` with a null value (if it did not exist before) +To create a new key `spec:/example/newkey` with a null value (if it did not exist before) and a metakey `namespace/#0` associated with it to the value `system`:
`kdb meta-set /example/newkey "namespace/#0" system` @@ -61,13 +61,13 @@ To create an override link for a `/test` key: ```sh kdb set /overrides/test "example override" -sudo kdb meta-set spec/test override/#0 /overrides/test +sudo kdb meta-set spec:/test override/#0 /overrides/test ``` To remove it: ```sh -sudo kdb meta-set spec/test override/#0 +sudo kdb meta-set spec:/test override/#0 ``` ## SEE ALSO diff --git a/doc/help/kdb-meta-show.md b/doc/help/kdb-meta-show.md index 285a4adae04..25c10cdb863 100644 --- a/doc/help/kdb-meta-show.md +++ b/doc/help/kdb-meta-show.md @@ -41,17 +41,17 @@ This command will return the following values as an exit status:
## EXAMPLES ```sh -# Backup-and-Restore: user/tests/examples +# Backup-and-Restore: user:/tests/examples # We use `dump` as storage format here, since storage plugins such as INI -sudo kdb mount ls.ecf user/tests/examples dump +sudo kdb mount ls.ecf user:/tests/examples dump # Create the keys we use for the examples -kdb set user/tests/examples/kdb-meta-show test -kdb meta-set user/tests/examples/kdb-meta-show meta1 val1 -kdb meta-set user/tests/examples/kdb-meta-show meta2 val2 -kdb meta-set user/tests/examples/kdb-meta-show meta3 val3 -kdb meta-set user/tests/examples/kdb-meta-show meta4 val4 +kdb set user:/tests/examples/kdb-meta-show test +kdb meta-set user:/tests/examples/kdb-meta-show meta1 val1 +kdb meta-set user:/tests/examples/kdb-meta-show meta2 val2 +kdb meta-set user:/tests/examples/kdb-meta-show meta3 val3 +kdb meta-set user:/tests/examples/kdb-meta-show meta4 val4 # list all meta keys for /tests/examples/kdb-meta-show kdb meta-show /tests/examples/kdb-meta-show @@ -60,8 +60,8 @@ kdb meta-show /tests/examples/kdb-meta-show #> meta3: val3 #> meta4: val4 -kdb rm -r user/tests/examples -sudo kdb umount user/tests/examples +kdb rm -r user:/tests/examples +sudo kdb umount user:/tests/examples ``` ## SEE ALSO diff --git a/doc/help/kdb-mount-list-all-files.md b/doc/help/kdb-mount-list-all-files.md index f9976961221..b848d93ace7 100644 --- a/doc/help/kdb-mount-list-all-files.md +++ b/doc/help/kdb-mount-list-all-files.md @@ -12,12 +12,12 @@ This command prints a sorted list of all files under the control of Elektra ``` kdb mount -#> none on system/info/elektra/constants with name system/info/elektra/constants -#> /usr/local/share/doc/elektra/CONTRACT.ini on system/info/elektra/contract/#0 with name system/info/elektra/contract/#0 -#> none on system/info/elektra/desktop with name system/info/elektra/desktop -#> /usr/local/share/doc/elektra/METADATA.ini on system/info/elektra/metadata/#0 with name system/info/elektra/metadata/#0 -#> none on system/info/elektra/uname with name system/info/elektra/uname -#> /tmp/test.ini on system/test with name system/test +#> none on system:/info/elektra/constants with name system:/info/elektra/constants +#> /usr/local/share/doc/elektra/CONTRACT.ini on system:/info/elektra/contract/#0 with name system:/info/elektra/contract/#0 +#> none on system:/info/elektra/desktop with name system:/info/elektra/desktop +#> /usr/local/share/doc/elektra/METADATA.ini on system:/info/elektra/metadata/#0 with name system:/info/elektra/metadata/#0 +#> none on system:/info/elektra/uname with name system:/info/elektra/uname +#> /tmp/test.ini on system:/test with name system:/test kdb mount-list-all-files #> none diff --git a/doc/help/kdb-mount.md b/doc/help/kdb-mount.md index 004538ddb01..f7c0497731d 100644 --- a/doc/help/kdb-mount.md +++ b/doc/help/kdb-mount.md @@ -30,7 +30,7 @@ More about mounting is explained in [elektra-mounting(7)](elektra-mounting.md). This command writes into the `/etc` directory to make the mounting persistent. As such it requires root permissions. -Use `kdb file system/elektra/mountpoints` to find out where exactly it will write to. +Use `kdb file system:/elektra/mountpoints` to find out where exactly it will write to. Absolute paths are still relative to their namespace (see `kdb plugin-info resolver`). Only system+spec mount points are actually absolute. @@ -103,19 +103,19 @@ To list the currently mounted backends:
`kdb mount` To mount a system configuration file using the ini format:
-`kdb mount /etc/configuration.ini system/example ini` +`kdb mount /etc/configuration.ini system:/example ini` Print a null-terminated output of paths and backend names:
`kdb mount -02 | xargs -0n 2 echo` To mount the /etc/file system file with two plugins with a respective configuration option each:
-`kdb mount /etc/file system/file plugin1 plugin1config=config1 plugin2 plugin2config=config2` +`kdb mount /etc/file system:/file plugin1 plugin1config=config1 plugin2 plugin2config=config2` To mount the /etc/file system file with two plugins and setting both to be verbose:
-`kdb mount -c verbose=1 /etc/file system/file plugin1 plugin2` +`kdb mount -c verbose=1 /etc/file system:/file plugin1 plugin2` To recode and rename a configuration file using Elektra:
-`kdb mount recode.txt dir/recode ni rename cut=path iconv to=utf8,from=latin1` +`kdb mount recode.txt dir:/recode ni rename cut=path iconv to=utf8,from=latin1` ## SEE ALSO diff --git a/doc/help/kdb-mountpoint-info.md b/doc/help/kdb-mountpoint-info.md index d5bba0a3f55..1cdcedd133a 100644 --- a/doc/help/kdb-mountpoint-info.md +++ b/doc/help/kdb-mountpoint-info.md @@ -16,13 +16,13 @@ kdb mountpoint-info #> Default resolver: resolver_fm_hpu_b #> Default storage: ini -kdb mount /tmp/test.ini system/test ini hello=ini -c hello=world +kdb mount /tmp/test.ini system:/test ini hello=ini -c hello=world -kdb mountpoint-info system/test +kdb mountpoint-info system:/test #> Version: 0.8.19 #> Default resolver: resolver_fm_hpu_b #> Default storage: ini -#> Mountpoint: system/test +#> Mountpoint: system:/test #> File: /tmp/test.ini #> config: #> hello = world diff --git a/doc/help/kdb-mv.md b/doc/help/kdb-mv.md index 48e68948d5a..c368f02d7ec 100644 --- a/doc/help/kdb-mv.md +++ b/doc/help/kdb-mv.md @@ -49,7 +49,7 @@ This command will return the following values as an exit status: ## EXAMPLES To move multiple keys:
-`kdb mv -r user/example1 user/example2` +`kdb mv -r user:/example1 user:/example2` To move a single key:
-`kdb mv user/example/key1 user/example/key2` +`kdb mv user:/example/key1 user:/example/key2` diff --git a/doc/help/kdb-plugin-info.md b/doc/help/kdb-plugin-info.md index 15feea14407..8cce29b202f 100644 --- a/doc/help/kdb-plugin-info.md +++ b/doc/help/kdb-plugin-info.md @@ -11,7 +11,7 @@ The optional `clause name` argument can be used to just print information from a This command will print out all the information about an Elektra plugin except it's configuration.
This command will also print out any functions that are exported by the plugin.
-Information about a plugin will be read from `system/elektra/modules/`. If the information could not be located there, such as when a plugin is not mounted, the module will be loaded dynamically and then the information will be requested directly from the plugin.
+Information about a plugin will be read from `system:/elektra/modules/`. If the information could not be located there, such as when a plugin is not mounted, the module will be loaded dynamically and then the information will be requested directly from the plugin.
If a user wishes to load the information directly from the plugin, they can force that by using the `-l` option.
## RETURN VALUES @@ -35,7 +35,7 @@ This command returns the following exit statuses:
- `-C`, `--color `: Print never/auto(default)/always colored output. - `-l`, `--load`: - Load plugin even if system/elektra is available. + Load plugin even if system:/elektra is available. - `-c`, `--plugins-config `: Add a plugin configuration. diff --git a/doc/help/kdb-remount.md b/doc/help/kdb-remount.md index 400ab0b1843..e4e6f7e7bb5 100644 --- a/doc/help/kdb-remount.md +++ b/doc/help/kdb-remount.md @@ -32,5 +32,5 @@ This command allows a user to use an existing backend (such as one from a previo ## EXAMPLES -To mount a new file using an existing backend that is mounted to `system/example`:
-`kdb remount /etc/configuration2.ini system/example2 system/example`
+To mount a new file using an existing backend that is mounted to `system:/example`:
+`kdb remount /etc/configuration2.ini system:/example2 system:/example`
diff --git a/doc/help/kdb-reset-elektra.md b/doc/help/kdb-reset-elektra.md index 31291a363a1..9ab98f27ef5 100644 --- a/doc/help/kdb-reset-elektra.md +++ b/doc/help/kdb-reset-elektra.md @@ -1,4 +1,4 @@ -# kdb-reset-elektra(1) - Resets system/elektra +# kdb-reset-elektra(1) - Resets system:/elektra ## SYNOPSIS @@ -7,7 +7,7 @@ ## DESCRIPTION Resets all configuration changes that influence Elektra's core, i.e., -keys in `system/elektra`. +keys in `system:/elektra`. ## WARNING diff --git a/doc/help/kdb-rm.md b/doc/help/kdb-rm.md index 65b1861bd95..b5b70eb4f3b 100644 --- a/doc/help/kdb-rm.md +++ b/doc/help/kdb-rm.md @@ -35,7 +35,7 @@ This command will return the following values as an exit status: - `-r`, `--recursive`: Work in a recursive mode. - `-E`, `--without-elektra`: - Omit the `system/elektra` directory. + Omit the `system:/elektra` directory. - `-f`, `--force`: Do not fail on missing key, nor print if there was a key (-v to still print). - `-v`, `--verbose`: @@ -46,16 +46,16 @@ This command will return the following values as an exit status: ## EXAMPLES To remove a single key:
-`kdb rm user/example/key1` +`kdb rm user:/example/key1` To remove multiple keys:
-`kdb rm -r user/example` +`kdb rm -r user:/example` -To remove all keys in `system` except `system/elektra`:
+To remove all keys in `system` except `system:/elektra`:
`sudo kdb rm -rE system` To not fail when key is missing:
-`kdb rm -f user/maybe/missing` +`kdb rm -f user:/maybe/missing` ## SEE ALSO diff --git a/doc/help/kdb-set.md b/doc/help/kdb-set.md index b7cf6e6365c..48aea074dc6 100644 --- a/doc/help/kdb-set.md +++ b/doc/help/kdb-set.md @@ -57,22 +57,22 @@ To set a key to a negative value, `--` has to be used to stop option processing. ## EXAMPLES To set a Key to the value `Hello World!`:
-`kdb set user/example/key "Hello World!"` +`kdb set user:/example/key "Hello World!"` To create a new key with a null value:
-`kdb set user/example/key` +`kdb set user:/example/key` To set a key to an empty value:
-`kdb set user/example/key ""` +`kdb set user:/example/key ""` To set a key to a negative value:
`kdb set -- /tests/neg -3` To create bookmarks:
-`kdb set user/sw/elektra/kdb/#0/current/bookmarks` +`kdb set user:/sw/elektra/kdb/#0/current/bookmarks` Followed by:
-`kdb set user/sw/elektra/kdb/#0/current/bookmarks/kdb user/sw/elektra/kdb/#0/current` +`kdb set user:/sw/elektra/kdb/#0/current/bookmarks/kdb user:/sw/elektra/kdb/#0/current` ## SEE ALSO diff --git a/doc/help/kdb-sget.md b/doc/help/kdb-sget.md index ef429a7106a..f9d5d980143 100644 --- a/doc/help/kdb-sget.md +++ b/doc/help/kdb-sget.md @@ -28,7 +28,7 @@ This command will either print the value of the key it retrieves or a default va ## EXAMPLES To get the value of a key from a script or return the value `0`:
-`kdb sget user/example/key 0` +`kdb sget user:/example/key 0` To get the value of a key using a cascading lookup or return the value `notfound`:
`kdb sget /example/key "notfound"` diff --git a/doc/help/kdb-spec-mount.md b/doc/help/kdb-spec-mount.md index 21201a420bf..9ec1e8a53f8 100644 --- a/doc/help/kdb-spec-mount.md +++ b/doc/help/kdb-spec-mount.md @@ -6,7 +6,7 @@ - `mountpoint` is where in the key database the new backend should be mounted to. It must be a cascading mount point, i.e., `mountpoint` must start with `/`. -- `plugin` are extra Elektra plugins to be used (next to the one specified in `spec/`). +- `plugin` are extra Elektra plugins to be used (next to the one specified in `spec:/`). - Plugins may be followed by a `,` separated list of `keys=values` pairs which will be used as plugin configuration. `kdb smount` is an alias and can be used in the same way as `kdb spec-mount`. @@ -17,7 +17,7 @@ This command allows a user to mount a new _backend_ described by a previously mo To mount a specification file to `spec`-[namespace](elektra-namespaces.md) first use [kdb-mount(7)](kdb-mount.md): ```sh -sudo kdb mount /path/to/some-spec-file.ini spec/example/mountpoint ni +sudo kdb mount /path/to/some-spec-file.ini spec:/example/mountpoint ni ``` The idea of mounting is explained [in elektra-mounting(7)](elektra-mounting.md). @@ -34,16 +34,16 @@ During `spec-mount` the `spec` keys are searched for relevant metadata: For example: ```sh -kdb meta-get spec/example/mountpoint mountpoint # verify that we have a mountpoint here +kdb meta-get spec:/example/mountpoint mountpoint # verify that we have a mountpoint here sudo kdb spec-mount /example/mountpoint # mounts /example/mountpoint according to # the specification as found at - # spec/example/mountpoint + # spec:/example/mountpoint ``` ## IMPORTANT This command writes into the `/etc` directory and as such it requires root permissions. -Use `kdb file system/elektra/mountpoints` to find out where exactly it will write to. +Use `kdb file system:/elektra/mountpoints` to find out where exactly it will write to. Note that many specifications have globs like `_` and `#`. They will only work if the `spec` plugin is present: @@ -94,7 +94,7 @@ kdb global-mount ## EXAMPLES -To mount /example as described in `spec/example`:
+To mount /example as described in `spec:/example`:
`sudo kdb spec-mount /example` Additionally, add `ini` plugin (instead of some default resolver) with a config for INI:
diff --git a/doc/help/kdb-stash.md b/doc/help/kdb-stash.md index e43f118d77d..9c7bf5f7a15 100644 --- a/doc/help/kdb-stash.md +++ b/doc/help/kdb-stash.md @@ -14,39 +14,39 @@ The backup will be done in the `/var/tmp` directory, so make sure the backup is ## EXAMPLES ``` -kdb set user/x foo +kdb set user:/x foo #> -#> Create a new key user/x with string "foo" +#> Create a new key user:/x with string "foo" kdb mount a.ini /a kdb mount #> a.ini on /a with name /a -#> none on system/info/elektra/constants with name system/info/elektra/constants -#> /usr/local/share/doc/elektra/CONTRACT.ini on system/info/elektra/contract/#0 with name system/info/elektra/contract/#0 -#> none on system/info/elektra/desktop with name system/info/elektra/desktop -#> /usr/local/share/doc/elektra/METADATA.ini on system/info/elektra/metadata/#0 with name system/info/elektra/metadata/#0 -#> none on system/info/elektra/uname with name system/info/elektra/uname +#> none on system:/info/elektra/constants with name system:/info/elektra/constants +#> /usr/local/share/doc/elektra/CONTRACT.ini on system:/info/elektra/contract/#0 with name system:/info/elektra/contract/#0 +#> none on system:/info/elektra/desktop with name system:/info/elektra/desktop +#> /usr/local/share/doc/elektra/METADATA.ini on system:/info/elektra/metadata/#0 with name system:/info/elektra/metadata/#0 +#> none on system:/info/elektra/uname with name system:/info/elektra/uname kdb backup #> kdb restore 1500000000 -kdb get user/x +kdb get user:/x #> Did not find key kdb mount kdb restore 1500000000 -kdb get user/x +kdb get user:/x #> foo kdb mount #> a.ini on /a with name /a -#> none on system/info/elektra/constants with name system/info/elektra/constants -#> /usr/local/share/doc/elektra/CONTRACT.ini on system/info/elektra/contract/#0 with name system/info/elektra/contract/#0 -#> none on system/info/elektra/desktop with name system/info/elektra/desktop -#> /usr/local/share/doc/elektra/METADATA.ini on system/info/elektra/metadata/#0 with name system/info/elektra/metadata/#0 -#> none on system/info/elektra/uname with name system/info/elektra/uname +#> none on system:/info/elektra/constants with name system:/info/elektra/constants +#> /usr/local/share/doc/elektra/CONTRACT.ini on system:/info/elektra/contract/#0 with name system:/info/elektra/contract/#0 +#> none on system:/info/elektra/desktop with name system:/info/elektra/desktop +#> /usr/local/share/doc/elektra/METADATA.ini on system:/info/elektra/metadata/#0 with name system:/info/elektra/metadata/#0 +#> none on system:/info/elektra/uname with name system:/info/elektra/uname ``` ## SEE ALSO diff --git a/doc/help/kdb-test.md b/doc/help/kdb-test.md index 1fb38a37254..8c9899c89ea 100644 --- a/doc/help/kdb-test.md +++ b/doc/help/kdb-test.md @@ -28,11 +28,11 @@ The following tests are available: basic string umlauts binary naming meta
## EXAMPLES -To run all tests below the `user/example/tests` key:
-`kdb test user/example/tests`
+To run all tests below the `user:/example/tests` key:
+`kdb test user:/example/tests`
To run the `binary` and `naming` tests:
-`kdb test user/example/tests binary naming`
+`kdb test user:/example/tests binary naming`
## SEE ALSO diff --git a/doc/help/kdb.md b/doc/help/kdb.md index 8fb61b2d47c..3cae981676f 100644 --- a/doc/help/kdb.md +++ b/doc/help/kdb.md @@ -31,13 +31,13 @@ External commands can be listed via:
Only a few commands are enough for daily use. We can retrieve a key by:
-`kdb get user/key` +`kdb get user:/key` We store a key permanently with a value given by:
-`kdb set user/key value` +`kdb set user:/key value` We list all available keys arranged below a key by:
-`kdb ls user/key` +`kdb ls user:/key` Documentation of plugins is available using the [kdb-plugin-info(1)](kdb-plugin-info.md) tool:
@@ -126,7 +126,7 @@ Sometimes it is useful to start with default options, for example it is not possible to invert the `-q` option. In such situations one can simply select a non-existing profile, then `-q` works as usual:
-`kdb mount -p nonexist -q /abc dir/abc` +`kdb mount -p nonexist -q /abc dir:/abc` If `%` is used as profile name for `-p`, the `kdb` tools disables reading from `KDB` for their own configuration settings. Then, they only use command-line arguments. @@ -164,8 +164,8 @@ The string until the first `/` will be considered as bookmark. For example, if you set the bookmark kdb: ```sh -kdb set user/sw/elektra/kdb/#0/current/bookmarks -kdb set user/sw/elektra/kdb/#0/current/bookmarks/kdb user/sw/elektra/kdb/#0/current +kdb set user:/sw/elektra/kdb/#0/current/bookmarks +kdb set user:/sw/elektra/kdb/#0/current/bookmarks/kdb user:/sw/elektra/kdb/#0/current ``` You are able to use: diff --git a/doc/keynames/README.md b/doc/keynames/README.md new file mode 100644 index 00000000000..a93b9aca7f1 --- /dev/null +++ b/doc/keynames/README.md @@ -0,0 +1,473 @@ +# Key Names in Elektra + +## Preface + +This document is a full explanation of how Key Names work in Elektra. +In addition to this document, a reference Python implementation can be found in [keynames.py](keynames.py). +The goal this Python implementation is not to be fast, or to be used in any way other than as a reference. +If there are any discrepancies between this document, the Python implementation and the actual C implementation in [src/libs/elektra/keyname.c](../../src/libs/elektra/keyname.c), you should consider them as follows: + +1. The C implementation is optimized for speed and much harder to maintain. + It is mostly likely to be incorrect. +2. In most cases, this document outranks the Python implementation. + There may, however, be cases where the language in this document was too vague and the Python implementation is actually correct. +3. If two of the sources agree, the third one is probably incorrect. + Although again, if one of the agreeing sources is the C implementation it could still be the case that there is a mistake. + +In any case: If you find a discrepancy, please file a bug report at https://issues.libelektra.org/new. + +> _Note:_ Mistakes happen. +> So there is no 100% always correct specification for Elektra's Key Names. +> The goal is only to provide a reference that has a very high likelihood of being correct. + +_To Elektra Developers:_ Feel free to add any unclear or previous incorrect examples to the test cases in [tests/ctest/test_keyname.c](../../tests/ctest/test_keyname.c). +These tests are very fast (1000+ test cases per second) and the more tests the better. + +## 1. Key Name Parts and Namespaces + +Before we get to Key Names proper, we need to talk about Key Name Parts and Namespaces. + +Each Key is part of one of these _Namespaces_: + +- Cascading +- Meta +- Spec +- Proc +- Dir +- User +- System +- Default + +Each of these Namespaces has a very specific meaning, explained in [another section below](#12-namespaces-and-root-keys). + +Apart from the Namespace, a Key Name is just a series of zero or more _Key Name Parts_. +Each Key Name Part is just an arbitrary (possibly empty) sequence of non-zero bytes. + +So without knowing anything about how Key Names are written, we could say that there is a Key in the Namespace "System" with the Key Name Parts "elektra", "version" and "info". + +> _Note:_ Not every such sequence, is a valid Key Name. +> For more information see [section 4](#4-valid-and-invalid-key-names) + +### 1.1. Key Hierarchy + +You may have already seen elsewhere, that in Elektra Keys commonly look like Unix paths: + +``` +/elektra/version/info +``` + +> _Note:_ How this representation works exactly and how namespaces come into play, will be explained in the next section. +> For now, we only care that there is some similarity to Unix paths. + +This is no mistake. +Elektra's _Key Database (KDB)_ is designed to resemble a Unix filesystem. +In particular, the KDB has a similar hierarchy. +More generally, all Key Names exhibit this hierarchy. +By going back to thinking about a Key Name as a Namespace and a series of Key Name Parts, we can define this _Key Hierarchy_. + +Each Namespace has a separate hierarchy. +The relation between these, will be explored in the next section. +For now, we just look at a single Namespace. + +In a Unix filesystems, we commonly talk about files and directories. +We also say a file is located within a directory. +But you might also know that in Unix "everything is a file". +This applies to directories as well, but "a file is located within a file" is a bit clunky, so you might say "file `A` is located below file `B`", if `B` is a file within the directory `A`. +What makes `A` a directory is just the fact that there can be other files below `A` [[1]](#footnote-1). + + +#### 1.1.1. The "is below" Relation + +This relation of "is below" is also what defines Elektra's Key Hierarchy. +Based on a Key `K` with `n` Key Name Parts, we say: + +- A Key `Km` is _below_ `K`, if `Km` has `n+m` Key Name Parts and the first `n` Key Name Parts of `Km` are equal to the Key Name Parts of `K` (in the same order). +- A Key `K1` is _directly below_ `K`, if `K1` is below `K` and `K1` has `n+1` Key Name Parts. + +Here are a few examples to show how this works in practice (using the Unix-path-like representation teased above): + +| Key 1 | Key 2 | Relation | +| ----------------------- | ----------------------- | --------------------------------- | +| `/elektra/version/info` | `/elektra/version` | "Key 1" is directly below "Key 2" | +| `/elektra/version/info` | `/elektra` | "Key 1" is below "Key 2" | +| `/elektra` | `/elektra/version/info` | "Key 2" is below "Key 1" | +| `/elektra/version/info` | `/elektra/version/info` | "Key 1" and "Key 2" are equal | +| `/elektra/version/info` | `/elektra/data` | no relation | +| `/elektra/data` | `/elektra/version` | "Key 1" and "Key 2" are siblings | + +You can think of the Key Hierarchy (within a single Namespace) as a big tree of Keys. +Each node in the tree is a single key `K` and the children of the nodes are the keys that are directly below `K`. + +![Tree structure of a Key Hierarchy](tree.svg) + +The diagram above shows the Key Hierarchy of the Keys in the table above (`A` -> `B` denotes `A` is directly below `B`). + +> _Note:_ While we could use the directory vs. file terminology for Elektra as well, it is recommended to avoid it. +> This is because in Elektra, every Key may have an associated value. +> In particular a Key may have a value, even if there are other Keys below it. +> This value is **not**, as a beginner might suspect, the set of Keys below it, like you could say the value of a directory is the set of files (and directories) within. +> The value is just another value, like any other key would have. +> +> Instead, we recommend the terms _leaf Key_ and _non-leaf Key_, as these are commonly used for tree-like structures and their definitions fit perfectly. + +#### 1.1.2. The "parent" confusion + +As an inverse to "is below" we sometimes use "parent". +For example: + +- `/elektra/version` is directly below `/elektra`, so `/elektra` is the (direct) parent of `/elektra/version` +- `/elektra/version/info` is below `/elektra`, so `/elektra` is a parent of `/elektra/version` +- `/elektra/version/info` and `/elektra/version` are below `/elektra`, so `/elektra` is the common parent. + +This terminology can be easy to confuse, as "parent" is used for multiple different things. +If the context doesn't make it clear what "parent" means, you might consider more clear terms, e.g. other common terms for tree-like structures. +For example, you could use "ancestor" and "direct parent" as a clear differentiation. + +There is also the term "(the) Parent Key". +In many cases, this is refers to a very specific Key in the given context that is a "common parent" to a certain set of Keys. +If you are working within such a context, be careful about "a parent Key" vs. "the Parent Key". + +### 1.2. Namespaces and Root Keys + +We mentioned above that there are different Namespaces in Elektra. +Now we will explain their meaning. + +To recap, Elektra knows these Namespaces: + +- Cascading +- Meta +- Spec +- Proc +- Dir +- User +- System +- Default + +We mentioned above that there are Key Names with zero Key Name Parts, i.e. just Namespace. +These are called _Root Keys_ (based on Unix's filesystem root, as well as the root of a tree). + +Lets explore them one by one: + +- The simplest Namespace is the **"Meta"**. + The Namespace "Meta" is used exclusively for Meta Keys, i.e. Keys that are attached to another Key as metadata. + The Key Hierarchy of the Namespace "Meta" is entirely separate from the Key Hierarchies in the other Namespaces. + Without external information, you cannot determine from a Key Name with Namespace "Meta", which Key this Meta Key is attached to. +- Keys with Namespace **"Proc"** only exist in memory and are scoped to the current Process. +- Keys with Namespace **"Dir"** are scoped to a single filesystem Directory. + They will (normally) be stored somewhere within this directory. + Currently, there is no way of knowing which filesystem directory a Key with Namespace "Dir" is scoped to. + Elektra only uses Keys scoped to the Current Working Directory. +- Similarly, Keys with Namespace **"User"** are scoped to a single **User**. + They will (normally) be stored somewhere within the User's home directory. + Again, there is no way of knowing which user a Key is scoped to and Elektra only uses Keys scoped to the current user, i.e. the one that executed the application. +- The Namespace **"System"** is what makes Elektra global. + Keys with Namespace "System" are the same for all users of the system, independent of context. + They are stored in system level directory. +- Keys with Namespace **"Default"** are special. + While you could create them manually, you normally don't want to. + It is used for Keys with default values for Namespace Resolution (explained below). + Keys with this Namespace are also in-memory only. +- Then there is **"Spec"**. + This Namespace, like "Meta", is separate from the rest. + We use it for Keys that are part of a specification used to describe other Keys. + The Metadata of every Key with Namespace "Spec" describes a specification for the Keys that have the same Key Name Part but a different Namespace (except "Meta"). + So the Namespace "Spec" has a closer relation to the others than "Meta". +- Now just the Namespace **"Cascading"** remains. + This Namespace is used for Namespace Resolution (see below). + It is the one that applications and end-users will use most commonly when interacting with Elektra. + Keys with Namespace "Cascading" are never stored. + Not on disk and normally also not in a `KeySet`. + +There is also a certain ranking between the Namespaces "Proc", "Dir", "User", "System" and "Default". +Namely, that they override each other in exactly this order. +Given two Key Names with identical Key Name Parts, but one with Namespace "Dir" and one with Namespace "User", the one with Namespace "Dir" should be considered more specific and should be preferred. + +A special feature of Elektra is _Namespace Resolution_ (sometimes just Name Resolution, or Key Name Resolution). +Namespace Resolution is the process of finding an appropriate Namespace for a Key based on a Key Name with Namespace "Cascading". +It is most commonly used, when you to find which Key in the KDB should be used, based on a series of Key Name Parts. + +To resolve the namespace, we just look at each of the Namespaces in the ranking defined above. +We then use the first Namespace where the Key actually exists. +Namespace Resolution is performed, when `ksLookup`/`ksLookupByName` is called with a Key Name with Namespace "Cascading" [[2]](#footnote-2). + +This is also done, if you call `kdb get` or `kdb set` with a Key Name with Namespace "Cascading". + +## 2. Escaped Names + +The standard way to represent a Key Name in Elektra is this: + +``` +system:/elektra/version/info +``` + +This can be deconstructed into: + +- The Namespace: `system` +- The Namespace Separator: `:` +- A Part Separator: `/` +- A Key Name Part: `elektra` +- A Part Separator: `/` +- A Key Name Part: `version` +- A Part Separator: `/` +- A Key Name Part: `info` +- The invisible null terminator + +> _Note:_ It might seem strange, that there is a part **separator** before the first part. +> This makes sense, because then the Part Separator always introduces a new part. +> A better fitting description would be "part introducer". +> But since we commonly call `/` a separator, we will stick to this terminology. + +For Keys in the Namespace "Cascading", we omit both the Namespace itself and as well as the Namespace separator: + +``` +/elektra/version/info +``` + +We also have a special rule for the Root Keys, i.e. the Key Names with zero Key Name Parts and just a Namespace. +According to above rules `system:` would be the Escaped Name of the Root Key for the Namespace "System" and the Escaped Name for the Root Key of the Namespace "Cascading" would be an empty string. +But this is not the case. +We use `system:/` and `/` instead. +The exact details will be explored later, but for now just remember, that an (Escaped) Key Name **always** contains at least one Part Separator (`/`). + +But there is a problem. +We said a Key Name part is "an arbitrary sequence of non-zero bytes". +This means "elektra/version" is a Key Name Part as well. +Since the slash `/` would conflict with the Part Separator, we can escape it with a backslash `\` (and `\` can be escaped with another `\`): + +``` +/elektra\/version\\/info +``` + +This can be deconstructed into: + +- A Part Separator: `/` +- A Key Name Part: `elektra/version\` +- A Part Separator: `/` +- A Key Name Part: `info` +- An invisible null terminator + +> _Note:_ When talking about a single Key Name Part `/` and `\` are never escaped. + +Because of this escaping mechanism, we call this the _Escaped Name_ of a Key. + +Elektra's Key Names are designed to mimic Unix paths to some extent. +To this end we support the commonly used `/.` and `/..`. +This is one reason, why we need to differentiate between _Canonical_ Key Names and _Non-Canonical_ Key Names. + +### 2.1. (Non-)Canonical (Escaped) Key Names + +Following the syntax of Unix paths, in Elektra both `/elektra/./version` and `/elektra/version` refer to the same Key. +Similarly, `/elektra/../version` and `/version` refer to the same Key. + +To give each Key a unique Key Name, we need to introduce a _Canonical (Escaped) Key Name_. +For Unix paths, we could say that the canonical path is the shortest possible path that refers to a file. +In Elektra this doesn't quite work, but will use this definition for now. + +> _Note:_ Only Escaped Key Names can be Canonical or Non-Canonical, so we normally omit the "Escaped" specifier. + +Let's look at a few examples to get a feeling for Canonical and Non-Canonical Key Names. + +| Non-Canonical | Canonical | +| ----------------------- | ------------------ | +| `/elektra/./version` | `/elektra/version` | +| `/elektra/../version` | `/version` | +| `/elektra/.././version` | `/version` | +| `/elektra///version` | `/elektra/version` | +| `/elektra//../version` | `/version` | +| `/elektra/./../version` | `/elektra/version` | +| `/elektra/version/` | `/elektra/version` | + +So far this mostly follows, what we know from Unix paths. +However, the last two examples are somewhat different. + +First, in Unix `/elektra/./../version` would be the same as `/version`, because `.` is just skipped and `..` removes `elektra`. +But in Elektra, we evaluate `..` first and only then skip `.`. +`/elektra/./../version` is the same as `/elektra/version`, because `..` remove `.`. + + + +The last example is not as different, in Unix such paths would also refer to the same file. +However, in some Unix tools, a trailing slash alters the behavior of the tool. +In Elektra this is never the case. +`/elektra/version/` and `/elektra/version` refer to the same Key and are always treated as the same Key Name. +The only exception are the Root Keys. +The Canonical Key Names for the Root Keys always end with a `/`. +In fact, we will see [later](#4-valid-and-invalid-key-names), that removing the `/` makes the Key Name invalid. + +There also is a completely new addition in Elektra. +Elektra has a notion of _Array Parts_. +These are Key Name Parts that denote an array index. +How exactly these work, will be explored [later](#4-valid-and-invalid-key-names). +For now, we only need to know that they start with an `#` and their canonical form has `n` underscores followed by `n+1` digits. + +A few examples for Array Parts: + +| Non-Canonical | Canonical | +| ---------------- | ------------------- | +| `/elektra/#10` | `/elektra/#_10` | +| `/elektra/#1234` | `/elektra/#___1234` | + +### 2.2. Other Escape Sequences + +We already know, that `/` and `\` have to be escaped in an Escaped Key Name. +In addition two these to, there are a few more characters that have to be escaped. +However, these additional characters may **only** be escaped at the start of a Key Name Part. + +The characters in question are: `.`, `#`, `%`, `@`. +For example the Canonical Escaped Key Name for the Key with Namespace "Cascading" and Key Name Parts `elektra`, `.` and `version` is: `/elektra/\./version`. +The `\.` is the escaped form of `.`. +Using just `.` would make it a Non-Canonical Key Name, whose Canonical counterpart is `/elektra/version`, which does not have the wanted Key Name Part `.`. +Similarly, `#10` would make a Key Name Non-Canonical, but `\#10` won't. +Therefore, if you want a Canonical Key Name with a Key Name Part `#10` and not actually `#_10`, +must use e.g. `/elektra/\#10/version`. + + + +## 3. Unescaped Names + +While the Escaped Name of a Key is nice for humans, it is not very well suited for machines. +The escaping of path separators makes it hard to find the Key Name Parts of a given Key Name. +The Escaped Name is also not well suited for sorting [[3]](#footnote-3). + + +Both of these flaws are solved by the _Unescaped Name_. +In Unescaped Names we use a zero-byte as the Part Separator. +Since a Key Name Part cannot contain a zero-byte, we do not need an escaping mechanism for the path separator. + +However, these zero-bytes mean that the Unescaped Name is not a printable string and therefore not human-readable. +This why we will only describe the Unescaped Name in the deconstructed form. + +The Escaped Names from above correspond to the following Unescaped Names: + +1. `system:/elektra/version/info` + - The byte representing the Namespace "System": `0x07` + - A Part Separator: `0x00` + - A Key Name Part: `elektra` + - A Part Separator: `0x00` + - A Key Name Part: `version` + - A Part Separator: `0x00` + - A Key Name Part: `info` + - The terminator byte: `0x00` +2. `/elektra/version/info` + - The byte representing the Namespace "Cascading": `0x01` + - A Part Separator: `0x00` + - A Key Name Part: `elektra` + - A Part Separator: `0x00` + - A Key Name Part: `version` + - A Part Separator: `0x00` + - A Key Name Part: `info` + - The terminator byte: `0x00` +3. `/elektra\/version\\/info` + - The byte representing the Namespace "Cascading": `0x01` + - A Part Separator: `0x00` + - A Key Name Part: `elektra/version\` + - A Part Separator: `0x00` + - A Key Name Part: `info` + - The terminator byte: `0x00` +4. `/`: + - The byte representing the Namespace "Cascading": `0x01` + - A Part Separator: `0x00` + - The terminator byte: `0x00` + +> _Note:_ We use 0xZZ to represent a single byte in hexadecimal. +> This form is only used when the context makes it clear that it represents a single byte and not a four character string. + +The process of turning an Escaped Name into the corresponding Unescaped Name is called _unescaping_. +Turning an Unescaped Name back into an Escaped Name is called _escaping_. + +Unescaping works, by simply removing the backslashes `\` that are used as escapes. +This applies both to `\/` and `\\` anywhere in Key Name Parts, as well as to the escape sequences that are only used at the start of Key Name Parts, e.g. `\#`. + +## 4. Valid and Invalid Key Names + +Not all of the Key Names described by the above sections are valid under all circumstances. +You might also say, that a Key Name as defined above does not necessarily refer to a Key in the KDB. +So while it might be a Key Name, there is no Key that actually uses this name. +Only _Valid Key Names_ refer to a Key in the KDB and may be used by a Key as its name. +The remaining Key Names are referred to as _Invalid Key Names_. + +For Unescaped Key Names, it is pretty simple: +Unescaped Key Names are Valid Key Names, if all of the following are true: + +- The first byte is a valid Namespace Byte, i.e. `0x01` - `0x08`. +- The second byte is a zero-byte `0x00`. +- The last byte is a zero-byte `0x00`. + +For this reason Unescaped Names for Root Keys are 3 bytes long, with the last two bytes being zero-byte. +Between the second and the last byte, we find the Key Name Parts separated by a zero-byte `0x00`. + +For Escaped Key Names it is easier to define, what makes an Invalid Key Name, than what makes a Valid Key Name, so we will go this route. +An Escaped Key Name is considered an Invalid Key Name, if any of the following are true: + +- It is an empty string. +- The last character before the invisible null terminator is a backslash `\`. + This is a dangling escape as we expect another character after the escape character `\`. +- It contains a Namespace (i.e. the Namespace is not "Cascading"), but the Namespace Separator `:` is not followed by a `/`. + (This mainly applies to Root Keys.) +- It contains a Namespace Separator `:`, but the substring before the first `:` is not one of: `meta`, `spec`, `proc`, `dir`, `user`, `system` and `default`. +- One of the Key Name Parts starts with an unescaped `@`. + For example `/elektra/@version` is an invalid Escaped Key Name. + Only `/elektra/\@version` would be valid. +- It contains an Illegal Escape Sequence (see below). +- It contains an Invalid Array Part (see below). +- Going from left to right one Key Name Part at a time, at any point, the number of Key Name Parts that are `..` is bigger than the number of other Key Name Parts. + In Non-Canonical Key Names, the `.` Key Name Parts contribute to the number of other Key Name Parts. + +An Escape Sequence is illegal, if (one of): + +- It appears at the start of a Key Name Part and the escaped character is not one of: `/`, `\`, `.`, `#`, `%` or `@`. +- It appears anywhere else and the escaped character is not one of: `/` or `\`. + +An Array Part is valid, if (one of): + +- The whole Key Name Part is `#` or `#0`. +- The Key Name Part is `#` followed by 1-19 digits, the first digit is not `0`, and the digits form a number less than or equal to `9223372036854775807` (= `2^64 - 1`). +- The Key Name Part is `#` followed by `n` underscores, followed by `n+1` digits, where `n <= 18`, the first digit is not `0`, and the digits form a number less than or equal to `9223372036854775807` (= `2^64 - 1`). + +Otherwise, Array Parts (i.e. Key Name Parts starting with `#`) are invalid. + +> _Note:_ The C-API does not allow you to construct a `Key` with an Invalid Key Name; for example `keyNew` (and `keyVNew`) will return `NULL`. + +## 4.1. Special Key Names + +Apart from Invalid Key Names, which cannot be constructed via the C-API, there are also _Reserved Key Names_. +These can be used with the C-API (`keyNew` returns a valid `Key *`), but there might be situations, in which `Key`s with such Key Names are treated differently. + +A simple example is `/somewhere/_/below`. +If used with the globbing functionality, the Key Name Part `_` will be interpreted as "match anything that is not an array element". + +If any of the following is true, a Key Name is a _Reserved Key Name_: + +- A Key Name Part starts with `_`. +- A Key Name Part starts with `@`. +- A Key Name Part starts with `%` and the Key Name Part is more than one byte long. + +> _Note:_ This rules apply to all Key Names. +> An Unescaped Key Name with a Key Name Part `@part`, the Escaped Key Name `/elektra/@part` and the Escaped Key Name Part `/elektra/%abc` are **all** Reserved Key Names. + +--- + +[1]: +This explanation of Unix paths and Unix filesystems, is not entirely accurate. +But it is good enough for our purposes, so we will just ignore some details. +[↑](#ref-footnote-1) + +[2]: +The actual process of resolution process that happens in `ksLookupByName` and `ksLookup` is a bit more complicated. +It may involve some Keys with Namespace "Spec" as well. +[↑](#ref-footnote-2) + +[3]: +For performance reasons, we want to make the comparison between to Key Names as fast as possible. +A good solution is a single `memcmp`. +But this doesn't account for the fact that Key Names represent a hierarchy and that `/` has a special meaning: +`/key/sub` should always be sorted after `/key` and before `/key.1`. +With `memcmp`, `/key` is first, because it is the shortest and otherwise equal. +But then we would get `/key.1` not `/key/sub`, because `/ < .` in ASCII. +This cannot happen with zero-bytes as the separator, because there is no byte with a smaller value. +[↑](#ref-footnote-3) diff --git a/doc/keynames/keynames.py b/doc/keynames/keynames.py new file mode 100755 index 00000000000..e0a618ae8b7 --- /dev/null +++ b/doc/keynames/keynames.py @@ -0,0 +1,470 @@ +#!/bin/python3 + +""" +This file contains a reference implementation of Elektra's Key Name processing. + +It contains commented functions for: + - Checking, wether a string is a valid Key Name and if so turning it into its canonical form. + - Splitting (canonical) Key Names into a Namespace and a list of (unescaped) Key Name Parts. + +In addition, we provide a command line interface to experiment with the implementation. +Execute the file with the argument '--help' to find out more about the CLI. +""" + +import re +import sys + +from itertools import takewhile + +from typing import List, Tuple, Match, Optional, Iterator +from enum import Enum + +import argparse + +# Enum for Elektra's Namespaces. Values are used as the first byte in Unescaped Names. + + +class Namespace(Enum): + CASCADING = 1 + META = 2 + SPEC = 3 + PROC = 4 + DIR = 5 + USER = 6 + SYSTEM = 7 + DEFAULT = 8 + + +# String names for the Namespaces +NAMESPACES = set(["meta", "spec", "proc", "dir", "user", "system", "default"]) + +# Map between string Namespaces and enum values +NAMESPACES_MAP = { + "meta": Namespace.META, + "spec": Namespace.SPEC, + "proc": Namespace.PROC, + "dir": Namespace.DIR, + "user": Namespace.USER, + "system": Namespace.SYSTEM, + "default": Namespace.DEFAULT, +} + +# Characters that can be escaped anywhere in a Key Name Part +ESCAPES = set(["/", "\\"]) + +# Characters that can ONLY be escaped at at the start of a Key Name Part +ESCAPES_START = set(list(ESCAPES) + [".", "#", "%", "@"]) + + +# This RegEx defines what a Key Name Part can be. +# A string must match this RegEx to be a Key Name Part, but not all matching strings necessarily are valid Key Name Parts. +# +# The RegEx looks for a leading slash `/`, optionally followed by more slashes `/`. +# All of these slashes will be treated as a single separator. +# After that comes the actual content of the Key Name Part, a series of +# - characters other than slash `/` and backslash `\` +# - OR backslash `\` followed by any other character (an escape sequence). +PART_REGEX = re.compile(r"/(?P/*)(?P(?:[^\\/]|\\.)*)") + +# This RegEx is used to find escape sequences within a Key Name Part. +ESCAPE_REGEX = re.compile(r"\\(.)") + + +class KeyNameException(Exception): + pass + + +def canonicalize(name: str, prefix: str = "", verbose: bool = False) -> str: + """ + Returns the canonical version of the Key Name `name`. + If `name` is not a valid Key Name, a `KeyNameException` will be raised. + + If `prefix` is not empty, `name` is canonicalized under the assumption that it is being appended to the existing Key Name `prefix`. + It is similar to (but not necessarily the same as) calling `canonicalize (name + "/" + prefix)`. + + If `verbose` is set to `True`, additional information about the procedure is printed to `sys.stderr`. + """ + + # First check for an empty Key Name + if len(name) == 0: + if len(prefix) == 0: + raise KeyNameException("Empty name is invalid") + + return prefix + + # Then find and validate the Namespace + namespace = None + namespace_offset = 0 + + # This will contain the Key Name without the Namespace (and Namespace separator `:`) + fullname = None + + # Namespace is everything before the first colon `:`, or empty if there is no colon `:` + if len(prefix) == 0: + # No prefix, so we look in name + colon_index = name.find(":") + if colon_index > 0: + namespace = name[:colon_index] + namespace_offset = len(namespace) + + if namespace not in NAMESPACES: + raise KeyNameException( + f"Illegal namespace '{namespace}'. " + + f"Allowed namespaces: {NAMESPACES}" + ) + + fullname = name[colon_index + 1:] + else: + fullname = name + else: + # We have a prefix, so we extract the Namespace from there + colon_index = prefix.find(":") + if colon_index > 0: + namespace = prefix[:colon_index] + namespace_offset = len(namespace) + + if namespace not in NAMESPACES: + raise KeyNameException( + f"Illegal namespace '{namespace}'. " + + f"Allowed namespaces: {NAMESPACES}" + ) + + fullname = prefix[colon_index + 1:] + "/" + name + else: + fullname = prefix + "/" + name + + # Check if Key Name starts correctly after Namespace + if len(fullname) == 0 or fullname[0] != "/": + raise KeyNameException( + f"Key must start with ':/' or just '/'. " + + f"Allowed values for : {NAMESPACES}" + ) + + # Check if for dangling escapes + if sum(1 for _ in takewhile(lambda x: x == "\\", reversed(fullname))) % 2 != 0: + raise KeyNameException( + f"The key must not end with an unescaped backslash '\\'." + ) + + # Split Key Name into Key Name Parts and process separately + parts = list(PART_REGEX.finditer(fullname)) + part_count = len(parts) + + # Will contain a Tuple for each Key Name Part in the canonical Key Name. + # The first element of the Tuple is the RegEx Mach object. This is used for processing `..` parts. + # The second element is either None, meaning this part will be skipped when creating the final Key Name or a str, i.e. a canonical Key Name Part. + key_parts: List[Tuple[Match[str], Optional[str]]] = [] + + for (index, part) in enumerate(parts): + full_part = part.group(0) + leading_slashes = len(part.group('leadingSlashes')) + actual_part = part.group('content') + + part_start = part.start(0) + namespace_offset + part_end = part.end(0) + namespace_offset + + # Report leading slashes in verbose mode. + if verbose and leading_slashes > 0: + print( + f"[DEBUG] removing {leading_slashes} leading slashes " + + f"from part '{full_part}' ({part_start}:{part_end})", + file=sys.stderr + ) + + # If this is the last part and we have no content, we are done. A trailing slashes are explicitly allowed. + if index == part_count - 1: + if len(actual_part) == 0: + if verbose: + print( + f"[DEBUG] removing empty last part ({part_start}:{part_end})", + file=sys.stderr + ) + break + + # Validate escape sequences + for esc in ESCAPE_REGEX.finditer(actual_part): + escape = esc.group(1) + + # At the start of the Key Name Part, different characters can be escaped. + if esc.start(0) == 0: + if escape not in ESCAPES_START: + raise KeyNameException( + f"Illegal escape sequence '{escape}' at start of part. " + + f"Invalid part '{full_part}' ({part_start}:{part_end})." + ) + elif escape not in ESCAPES: + raise KeyNameException( + f"Illegal escape sequence '{escape}' (inside part). " + + f"Invalid part '{full_part}' ({part_start}:{part_end})." + ) + + if actual_part == ".": + # A `.` is skipped for the canonical Key Name. + if verbose: + print( + f"[DEBUG] skipping part '.' ({part_start}:{part_end})", + file=sys.stderr + ) + + # But we need to keep it for know, because `..` parts can remove `.` as well. + key_parts.append((part, None)) + elif actual_part == "..": + # A `..` removes a part from the canonical Key Name, so we need to check if there is a part left. + if len(key_parts) == 0: + raise KeyNameException( + "Found part '..' but no more parts left to remove." + ) + + if verbose: + (previous_part, _) = key_parts[-1] + full_previous_part = previous_part.group(0) + previous_start = previous_part.start(0) + namespace_offset + previous_end = previous_part.end(0) + namespace_offset + print( + f"[DEBUG] found part '..' ({part_start}:{part_end}) " + + f"removing previous part '{full_previous_part}' ({previous_start}:{previous_end})", + file=sys.stderr + ) + + key_parts.pop() + elif actual_part[0] == "@": + # Key Name Parts starting with `@` are reserved and make Key Names invalid. + raise KeyNameException( + f"Parts starting with '@' are reserved and makes the name invalid. " + + f"Invalid part: '{full_part}' ({part_start}:{part_end})" + ) + elif actual_part[0] == "#": + # This is an Array part, so we need to validate the structure. + # For more details, look at the KeyNameException messages. + underscores = sum(1 for _ in takewhile( + lambda x: x == "_", actual_part[1:])) + digits = actual_part[underscores + 1:] + + if any(not x.isdigit() for x in digits): + raise KeyNameException( + f"Array parts (starting with '#') may only contain underscores ('_') and digits ('0'-'9'). " + + f"Invalid part: '{full_part}' ({part_start}:{part_end})" + ) + + if underscores > 0 and underscores != len(digits) - 1: + raise KeyNameException( + f"Array parts (starting with '#') must consist of either only digits ('0'-'9') or " + + f"exactly N underscores ('_') followed by exactly N-1 digits ('0'-'9'). " + + f"Invalid part: '{full_part}' ({part_start}:{part_end})" + ) + + if len(digits) > 19 or (len(digits) == 19 and digits > "9223372036854775807"): + raise KeyNameException( + f"The maximum array index is 9223372036854775807 (2^64 - 1). " + + f"Invalid part: '{full_part}' ({part_start}:{part_end})" + ) + + if len(digits) > 1 and digits[0] == "0": + raise KeyNameException( + f"Array indices cannot start with a '0'. " + + f"Invalid part: '{full_part}' ({part_start}:{part_end})" + ) + + # The canonical version of an Array Part always has the underscores. + key_parts.append((part, f"#{'_' * (len(digits) - 1)}{digits}")) + elif actual_part[0] == "_": + # Parts starting with `_` are reserved, ... + if verbose: + print( + f"[DEBUG] part starting with '_' is reserved for special use. " + + f"The part may have unintended meaning '{full_previous_part}' ({part_start}:{part_end})", + file=sys.stderr + ) + + # ... but do not make Key Names invalid. + key_parts.append((part, actual_part)) + elif actual_part[0] == "%": + # Parts starting with `%` are reserved, ... + if verbose: + if len(actual_part) == 1: + print( + f"[DEBUG] part '%' represents empty part ({part_start}:{part_end})", + file=sys.stderr + ) + else: + print( + f"[DEBUG] part starting with '%' is reserved for special use. " + + f"The part may have unintended meaning '{full_previous_part}' ({part_start}:{part_end})", + file=sys.stderr + ) + + # ... but do not make Key Names invalid. + key_parts.append((part, actual_part)) + else: + # Basic Key Name Part, just append to list + key_parts.append((part, actual_part)) + + # Create the Key Name without the namespace + key = "/".join(p for (_, p) in key_parts if p is not None) + + # Add the Namespace, if this is not a cascading Key Name + if namespace is not None: + fullkey = f"{namespace}:/{key}" + else: + fullkey = f"/{key}" + + return fullkey + + +def unescape(canonical: str, verbose: bool = False) -> Tuple[Namespace, Iterator[str]]: + """ + Returns the Namespace enum value and list of Key Name Parts for a given canonical Key Name. + + `canonical` MUST be a canonical Key Name. If you are not sure about this, call `canonicalize` first. + """ + + # Extract the Namespace string value and convert it into an enum value. + colon_index = canonical.find(":") + if colon_index > 0: + namespace = NAMESPACES_MAP[canonical[:colon_index]] + else: + namespace = Namespace.CASCADING + + def unescape_part(part: Match[str]) -> str: + """ + Returns the unescaped version of a single Key Name Part. + + `part` MUST NOT contain unescaped slashes `/` for this function to be correct. + """ + + actual_part = part.group("content") + + if actual_part == "%": + # Found an empty part, replace with empty string + if verbose: + part_start = part.start(0) + part_end = part.end(0) + print( + f"[DEBUG] '%' represents an empty part. ({part_start}:{part_end})", + file=sys.stderr + ) + + return "" + else: + # Simple remove the backslashes `\` from the escape sequences + return ESCAPE_REGEX.sub("\\1", actual_part) + + # Use the RegEx to separate the parts and then unescape each one individually + unescaped = ( + unescape_part(part) for part in PART_REGEX.finditer(canonical) + ) + + return (namespace, unescaped) + + +""" +START OF MAIN FUNCTION +""" + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Check an convert Elektra Key Names." + ) + parser.add_argument( + "--verbose", "-v", + help="Show more info about what is happening.", + action="store_true" + ) + + subparsers = parser.add_subparsers( + title="commands", + dest="command" + ) + + p_canonicalize = subparsers.add_parser( + "canonicalize", + description="canonicalize Key Name and print result" + ) + p_canonicalize.add_argument( + "--prefix", "-p", + nargs="?", + default="", + help="existing Key Name to which 'name' should be added" + ) + p_canonicalize.add_argument( + "name", + help="the Key Name to canonicalize" + ) + + p_unescape = subparsers.add_parser( + "unescape", + description="unescape Key Name and print one part per line" + ) + p_unescape.add_argument( + "--raw", "-r", + action="store_true", + help="print the raw unescaped Key Name instead of one part per line" + ) + p_unescape.add_argument( + "--python-bytes", "-b", + action="store_true", + help="print the raw unescaped Key Name as a python bytes object" + ) + p_unescape.add_argument( + "name", + help="the Key Name to unescape" + ) + + args = parser.parse_args() + + if args.command == "canonicalize": + try: + if "prefix" in args: + key_canonical = canonicalize( + args.name, + args.prefix, + verbose=args.verbose + ) + else: + key_canonical = canonicalize( + args.name, + verbose=args.verbose + ) + + print(key_canonical) + except KeyNameException as e: + print("ERROR:", e, file=sys.stderr) + exit(1) + elif args.command == "unescape": + try: + if "prefix" in args: + key_canonical = canonicalize(args.name, args.prefix) + else: + key_canonical = canonicalize(args.name) + + if args.verbose: + print(f"[DEBUG] canonical version of name: {key_canonical}") + + (namespace, unescaped) = unescape( + key_canonical, + verbose=args.verbose + ) + + if args.raw: + sys.stdout.buffer.write( + bytes(namespace.value) + + b"\0" + + b"\0".join(bytes(p, encoding="utf-8") for p in unescaped) + + b"\0" + ) + elif args.python_bytes: + print( + bytes(namespace.value) + + b"\0" + + b"\0".join(bytes(p, encoding="utf-8") for p in unescaped) + + b"\0" + ) + else: + print(str(namespace)) + for part in unescaped: + print(part) + except KeyNameException as e: + print("ERROR:", e, file=sys.stderr) + exit(1) + else: + parser.print_usage() diff --git a/doc/keynames/new_api.py b/doc/keynames/new_api.py new file mode 100755 index 00000000000..c8d252b1e3c --- /dev/null +++ b/doc/keynames/new_api.py @@ -0,0 +1,1113 @@ +#!/bin/python3 + +from keynames import Namespace, NAMESPACES_MAP, NAMESPACES, PART_REGEX, ESCAPE_REGEX, ESCAPES, KeyNameException + +import re +import sys +import json +from typing import List, Optional, Union, Dict, Tuple, Iterator, Match +from itertools import takewhile + +import argparse + +NAMESPACES_MAP_INVERSE = { + Namespace.META: "meta", + Namespace.SPEC: "spec", + Namespace.PROC: "proc", + Namespace.DIR: "dir", + Namespace.USER: "user", + Namespace.SYSTEM: "system", + Namespace.DEFAULT: "default", +} + +ESCAPES_FULL = set([".", "..", "%"]) + +# Demo of new key name API +# reuses keynames.py for convience only. +# +# Changes compared to to keynames.py: +# - '®elektra' is a reserved part, assuming UTF-8 encoding. The UTF-8 encoding of '®' is '\xc2\xae'. +# - part starting with '#' is an array, unless it starts with '##' +# - part starting with '##' is pseudo-array part; it wants to look like an array part but not be an array part; first '#' should be ignored for field names +# - part starting with '%' is not reserved, but '/%/' and '/%' is still empty part in escaped name, can be escaped as '\%' +# - part starting with '_' is not reserved +# - part starting with '@' is not reserved +# - canonicalization of '.' and '..' works like with Unix Paths, but can be escaped as '\.' and '\..' +# - '/' and '\' still have to be escaped in escaped name, the other valid escape sequences are '/\%/', '/\./' and '/\../' +# - unescaping rules are unchanged (apart from a bugfix); parts starting with '##' are NOT unescaped +# +# The CLI also has the new commands 'demo' and 'repl' +# - 'demo' runs a short demo and a few tests +# - 'repl' loads this file and drops into a REPL; best way to explore the new API +# + + +class Key(object): + # contains relevant key manipulation methods + + namespace: Namespace + __parts: List[bytes] + value: Optional[Union[str, int, bool, float]] + + def __init__(self, key: str, value: Optional[Union[str, int, float, bool]] = None): + self.namespace, parts = Key.unescape(Key.canonicalize(key)) + self.__parts = list(bytes(part, encoding="utf-8") for part in parts) + if value is None or isinstance(value, bool) or isinstance(value, float) or isinstance(value, int): + self.value = value + else: + self.value = str(value) + + def parts(self) -> List[bytes]: + return list(self.__parts) + + def name(self) -> str: + if self.namespace == Namespace.CASCADING: + prefix = "/" + else: + prefix = NAMESPACES_MAP_INVERSE[self.namespace] + ":/" + + return prefix + "/".join(Key.escape_part(part) for part in self.__parts) + + def last_part(self) -> bytes: + return self.__parts[-1] + + def del_last_part(self): + del self.__parts[-1] + + @staticmethod + def base_name(name: bytes) -> bytes: + if name == bytes("®elektra", encoding="utf-8"): + raise KeyNameException("'®elektra' is reserved") + + if len(name) > 1 and name[0:1] == b"#": + return b"#" + name + else: + return name + + def add_base_name(self, name: bytes): + self.__parts.append(Key.base_name(name)) + + def set_base_name(self, name: bytes): + self.del_last_part() + self.add_base_name(name) + + @staticmethod + def array_index(index: int) -> bytes: + str_index = bytes(str(index), encoding="utf-8") + return b"#" + (b'_' * (len(str_index) - 1)) + str_index + + def add_array_index(self, index: int): + self.__parts.append(Key.array_index(index)) + + def set_array_index(self, index: int): + self.del_last_part() + self.add_array_index(index) + + def relative_name(self, parent: 'Key') -> Optional[List[bytes]]: + parent_len = len(parent.__parts) + + if self.__parts[0:parent_len] != parent.__parts: + return None + + return self.__parts[parent_len:] + + @staticmethod + def escape_part(part: bytes) -> str: + if len(part) == 0: + return "%" + + return re.sub(f"([\\\\/])", "\\\\\\1", part.decode("utf-8")) + + @staticmethod + def read_array_index(part: bytes) -> Optional[int]: + if part[0:1] == b"#": + underscores = list(takewhile(lambda x: x == b"_", + (part[i:i+1] for i in range(1, len(part))))) + digits = part[1+len(underscores):] + + if len(underscores) == len(digits) - 1 and re.match(b"[0-9]", digits) is not None: + return int(digits) + + return None + + @staticmethod + def canonicalize(name: str, prefix: str = "") -> str: + if len(name) == 0: + if len(prefix) == 0: + raise KeyNameException("Empty name is invalid") + + return prefix + + namespace = None + namespace_offset = 0 + + fullname = None + + if len(prefix) == 0: + colon_index = name.find(":") + if colon_index > 0: + namespace = name[:colon_index] + namespace_offset = len(namespace) + + if namespace not in NAMESPACES: + raise KeyNameException( + f"Illegal namespace '{namespace}'. " + + f"Allowed namespaces: {NAMESPACES}" + ) + + fullname = name[colon_index + 1:] + else: + fullname = name + else: + colon_index = prefix.find(":") + if colon_index > 0: + namespace = prefix[:colon_index] + namespace_offset = len(namespace) + + if namespace not in NAMESPACES: + raise KeyNameException( + f"Illegal namespace '{namespace}'. " + + f"Allowed namespaces: {NAMESPACES}" + ) + + fullname = prefix[colon_index + 1:] + "/" + name + else: + fullname = prefix + "/" + name + + if len(fullname) == 0 or fullname[0] != "/": + raise KeyNameException( + f"Key must start with ':/' or just '/'. " + + f"Allowed values for : {NAMESPACES}" + ) + + if sum(1 for _ in takewhile(lambda x: x == "\\", reversed(fullname))) % 2 != 0: + raise KeyNameException( + f"The key must not end with an unescaped backslash '\\'." + ) + + parts = list(PART_REGEX.finditer(fullname)) + part_count = len(parts) + key_parts: List[Tuple[Match[str], Optional[str]]] = [] + + for (index, part) in enumerate(parts): + full_part = part.group(0) + actual_part = part.group('content') + + part_start = part.start(0) + namespace_offset + part_end = part.end(0) + namespace_offset + + if index == part_count - 1: + if len(actual_part) == 0: + break + + # CHANGED: reserved part + if actual_part == "®elektra": + raise KeyNameException( + f"'®elektra' is a reserved name. " + + f"Invalid part '{full_part}' ({part_start}:{part_end})." + ) + + for esc in ESCAPE_REGEX.finditer(actual_part): + escape = esc.group(1) + + # CHANGED: only escaping full parts ., .., % or / \ anywhere allowed + if esc.start(0) == 0: + if actual_part[1:] not in ESCAPES_FULL and escape not in ESCAPES: + raise KeyNameException( + f"Illegal escape sequence '{escape}' at start of part. " + + f"Invalid part '{full_part}' ({part_start}:{part_end})." + ) + elif escape not in ESCAPES: + raise KeyNameException( + f"Illegal escape sequence '{escape}' (inside part). " + + f"Invalid part '{full_part}' ({part_start}:{part_end})." + ) + + if actual_part == ".": + # CHANGED: like in Unix Paths .. cannot remove ., instead . is ignored right away + continue + elif actual_part == "..": + if len(key_parts) == 0: + # CHANGED: line in Unix Paths, there cannot be to many .. + continue + + key_parts.pop() + elif actual_part[0] == "#" and (len(actual_part) == 1 or actual_part[1] != "#"): + # CHANGED: parts starting with ## are not invalid array parts, but new pseudo-array parts + + underscores = sum(1 for _ in takewhile( + lambda x: x == "_", actual_part[1:])) + digits = actual_part[underscores + 1:] + + if any(not x.isdigit() for x in digits): + raise KeyNameException( + f"Array parts (starting with '#') may only contain underscores ('_') and digits ('0'-'9'). " + + f"Invalid part: '{full_part}' ({part_start}:{part_end})" + ) + + if underscores > 0 and underscores != len(digits) - 1: + raise KeyNameException( + f"Array parts (starting with '#') must consist of either only digits ('0'-'9') or " + + f"exactly N underscores ('_') followed by exactly N-1 digits ('0'-'9'). " + + f"Invalid part: '{full_part}' ({part_start}:{part_end})" + ) + + if len(digits) > 19 or (len(digits) == 19 and digits > "9223372036854775807"): + raise KeyNameException( + f"The maximum array index is 9223372036854775807 (2^64 - 1). " + + f"Invalid part: '{full_part}' ({part_start}:{part_end})" + ) + + if len(digits) > 1 and digits[0] == "0": + raise KeyNameException( + f"Array indices cannot start with a '0'. " + + f"Invalid part: '{full_part}' ({part_start}:{part_end})" + ) + + key_parts.append((part, f"#{'_' * (len(digits) - 1)}{digits}")) + else: + # CHANGED: parts starting with _, @, % have no restrictions + key_parts.append((part, actual_part)) + + key = "/".join(p for (_, p) in key_parts if p is not None) + + if namespace is not None: + fullkey = f"{namespace}:/{key}" + else: + fullkey = f"/{key}" + + return fullkey + + @staticmethod + def unescape(canonical: str) -> Tuple[Namespace, Iterator[str]]: + colon_index = canonical.find(":") + if colon_index > 0: + namespace = NAMESPACES_MAP[canonical[:colon_index]] + else: + namespace = Namespace.CASCADING + + def unescape_part(part: Match[str]) -> str: + actual_part = part.group("content") + + if actual_part == "%": + return "" + else: + return ESCAPE_REGEX.sub("\\1", actual_part) + + # CHANGED, BUGFIX: ignore empty escaped parts; user:/ produced [b''], but should be [] + unescaped = ( + unescape_part(part) for part in PART_REGEX.finditer(canonical) if len(part.group('content')) > 0 + ) + + return (namespace, unescaped) + + def __repr__(self): + return f"Key({repr(self.name())}, {repr(self.value)})" + + +class KeyHierarchy(object): + # New struct to be created in C + # + # struct _KeyHierarchy { + # Key * root; // <- root key of this sub hierarchy, name cascading and relative to parent key + # Key * value; // <- same as Key * as root, if it was present it the original KeySet, NULL otherwise + # kdb_long_long_t arraySize; + # Key ** array; // <- list of array children, array[0] is .../#0, etc. + # KeySet * map; // <- non-array children, all keys have single part cascading names relative to root, key values are KeyHierarachy * + # }; + # + # typedef struct _KeyHierarchy KeyHierarchy; + # + # + # Created by a helper function: + # KeyHierarchy * elektraKeyHierarchy (Key * parentKey, KeySet * ks); + # + # Additional helper functions for access: + # Key * elektraKHRoot (KeyHierarchy * kh); + # Key * elektraKHValue (KeyHierarchy * kh); + # kdb_long_long_t elektraKHArraySize (KeyHierarchy * kh); + # Key ** elektraKHArray (KeyHierarchy * kh); + # KeySet * elektraKHMap (KeyHierarchy * kh); + # + # And/or traversal function: + # typedef void (*elektraKHTraversal) (Key * current, Key * value, kdb_long_long_t arraySize, Key ** array, KeySet * map); + # void elektraKHTraverse (KeyHierarchy * kh, elektraKHTraversal traversalFn); + # + # Should be used by storage plugins with hierarchical format + + path: List[Union[str, int]] + value: Optional[Key] + array_children: List['KeyHierarchy'] + map_children: Dict[str, 'KeyHierarchy'] + + @staticmethod + def create(parent: Key, keys: List[Key]) -> 'KeyHierarchy': + hierarchy = KeyHierarchy([], None, [], {}) + + def convert(part: bytes) -> str: + if len(part) > 1 and part[0:1] == b"#": + if part[1:2] == b"#": + return part[1:].decode("utf-8") + else: + return Key.read_array_index(part) + else: + return part.decode("utf-8") + + for key in keys: + parts = [convert(part) for part in key.relative_name(parent)] + KeyHierarchy.__insert(hierarchy, parts, key) + + return hierarchy + + def __init__(self, path: List[Union[str, int]], value: Optional[Key], array_children: List['KeyHierarchy'], map_children: Dict[bytes, 'KeyHierarchy']): + self.path = list(path) + self.value = value + self.array_children = list(array_children) + self.map_children = dict(map_children) + + def __insert(self, path: List[Union[str, int]], value: Key): + if len(path) == 0: + self.value = value + return + + field = path[0] + if isinstance(field, str): + if field not in self.map_children: + self.map_children[field] = KeyHierarchy( + self.path + path, None, [], {}) + + self.map_children[field].__insert(path[1:], value) + elif isinstance(field, int): + if field < len(self.array_children): + if self.array_children[field] is None: + self.array_children[field] = KeyHierarchy( + self.path + path, None, [], {}) + else: + for _ in range(len(self.array_children), field): + self.array_children.append(None) + self.array_children.append( + KeyHierarchy(self.path + path, None, [], {})) + + self.array_children[field].__insert(path[1:], value) + else: + raise Exception(f"invalid path part {field}") + + +class DumpPlugin(): + @staticmethod + def read_key_name(parent: Key, pkey: str) -> Key: + return Key(parent.name() + "/" + pkey) + + @staticmethod + def write_key_name(parent: Key, key: Key) -> str: + return key.name()[len(parent.name()):] + + +class PropertiesPlugin(): + # basic plugin using linear list of differently encoded full names + + @staticmethod + def read_key_name(parent: Key, pkey: str) -> Key: + name = "" + + escaped = False + part_start = True + for c in pkey: + if escaped: + escaped = False + + if c == "\\": + name += "\\\\" + elif c in [":", ".", "="]: + name += c + elif c == "n": + name += "\n" + else: + raise Exception(f"Illegal escape '\\{c}'") + elif c == "\\": + escaped = True + elif c == "/": + name += "\\/" + elif c == ".": + if part_start: + name += "%/" + else: + name += "/" + else: + name += c + + part_start = c == "." + + if part_start and len(pkey) > 0: + name += "%" + + return Key(parent.name() + "/" + name) + + @staticmethod + def write_key_name(parent: Key, key: Key) -> str: + return ".".join(re.sub(f"([\\\\.:=])", "\\\\\\1", part.decode("utf-8")).replace("\n", "\\n") for part in key.relative_name(parent)) + + @staticmethod + def read(parent: Key, properties_str: str) -> List[Key]: + keys = [] + + for line in properties_str.split("\n"): + matches = list(re.finditer(r"(^|[^\\\\])=", line)) + + if len(matches) == 0: + continue + + sep = matches[0] + name = line[:0 if sep.start(0) == 0 else sep.start(0)+1] + value = line[sep.end(0):] + key = PropertiesPlugin.read_key_name(parent, name) + key.value = value + keys.append(key) + + return keys + + @staticmethod + def write(parent: Key, keys: List[Key]) -> str: + result = "" + + for key in keys: + result += PropertiesPlugin.write_key_name(parent, key) + result += "=" + result += str(key.value) + result += "\n" + + return result + + +class JsonPlugin(): + # hierachical plugin with arrays, syntax = JSON + # + # arrays are encoded as proper JSON arrays + # the field name "#0" is never an array element + # + # holes in arrays need special handling, a missing array element is encoded as { "®elektra": null } + # The array [ { "®elektra": null }, "b" ] only has a second element, in Elektra that means .../#1=b and .../#0 doesn't exist + # + # mixing array and map children also supported + # The keys .../abc/#0=a .../abc/def=b are encoded as: + # "abc": { "®elektra": { "array": [ "a" ] }, "def": "b" } + # + # non-leaf keys also need special encoding + # The keys .../abc=a and .../abc/def=b are encoded as + # "abc": { "®elektra": { "value": "a" }, "def": "b" } + # + # metadata is not used here, but could similarly be encoded like this + # "abc": { "®elektra": { "value": "a", "meta": { "type": "string", "othermeta": 2 } }, "def": "b" } + # + + # example of direct logic + @staticmethod + def key_from_field_path(parent: Key, fields: List[Union[str, int]]) -> Key: + key = Key(parent.name()) + + for field in fields: + if isinstance(field, int): + key.add_array_index(field) + else: + key.add_base_name(bytes(field, encoding="utf-8")) + + return key + + # example of direct logic + @staticmethod + def field_path_from_key(parent: Key, key: Key) -> List[Union[str, int]]: + def json_field(part: bytes) -> str: + if len(part) > 1 and part[0:1] == b"#": + if part[1:2] == b"#": + return part[1:].decode("utf-8") + else: + return Key.read_array_index(part) + else: + return part.decode("utf-8") + + return list(json_field(part) for part in key.relative_name(parent)) + + @staticmethod + def read(parent: Key, json_str: str) -> List[Key]: + keys = [] + JsonPlugin.load_json_like(json.loads(json_str), parent, keys, []) + return keys + + @staticmethod + def write(parent: Key, keys: List[Key]) -> str: + return json.dumps(JsonPlugin.create_json_like(parent, keys), indent=2, ensure_ascii=False) + + # helper function + # in C this should be done directly, by traversing KeyHierarchy and immediately writing to the file + @staticmethod + def create_json_like(parent: Key, keys: List[Key]): + def convert(hierarchy: KeyHierarchy): + def convert_map(): + return dict((k, convert(v)) for (k, v) in hierarchy.map_children.items()) + + def array_data(): + return [{"®elektra": None} if v is None else convert(v) for v in hierarchy.array_children] + + def convert_array(): + return {} if len(hierarchy.array_children) == 0 else {"array": array_data()} + + def convert_value(): + return {} if hierarchy.value.value is None else {"value": hierarchy.value.value} + + if len(hierarchy.map_children) == 0: + if len(hierarchy.array_children) == 0: + if hierarchy.value == None: + raise Exception("empty hierarchy") + + return hierarchy.value.value + elif hierarchy.value == None: + return array_data() + + return {"®elektra": {**convert_value(), **convert_array()}, **convert_map()} + + return convert(KeyHierarchy.create(parent, keys)) + + # helper function for Json and Hier + # in C this should be done directly, by creating Keys while reading to the file + @staticmethod + def load_json_like(json_data, parent: Key, keys: List[Key], path: List[Union[str, int]]): + if isinstance(json_data, list): + for i, element in enumerate(json_data): + JsonPlugin.load_json_like(element, parent, keys, path + [i]) + elif isinstance(json_data, dict): + for k, data in json_data.items(): + if k == "®elektra": + if data is None: + continue + + if "value" in data: + key = JsonPlugin.key_from_field_path(parent, path) + key.value = data["value"] + keys.append(key) + + if "array" in data: + for i, element in enumerate(data["array"]): + JsonPlugin.load_json_like( + element, parent, keys, path + [i] + ) + else: + JsonPlugin.load_json_like(data, parent, keys, path + [k]) + else: + key = JsonPlugin.key_from_field_path(parent, path) + key.value = json_data + keys.append(key) + + +class HierPlugin(): + # hierachical plugin without arrays, syntax = JSON minus arrays + # + # arrays are encoded likes in Elektra key names + # the field name "#0" is always an array element, if "##0" is used for 'should be "#0" but not an array element' + # every key name part is used directly as a JSON field + # + # mixed array and map children are supported without special handling, everything is encoded as objects + # holes in arrays don't need special handling, since arrays encoded as objects + # + # non-leaf keys with value are handled like in JsonPlugin + # metadata would also be handled like in JsonPlugin + # + + # example of direct logic + @staticmethod + def key_from_field_path(parent: Key, fields: List[str]) -> Key: + key = Key(parent.name()) + + for field in fields: + field_bytes = bytes(field, encoding="utf-8") + + if len(field_bytes) > 1 and field_bytes[0:1] == b"#": + if field_bytes[1:2] == b"#": + key.add_base_name(field_bytes[1:]) + else: + key.add_array_index(Key.read_array_index(field_bytes)) + else: + key.add_base_name(field_bytes) + + return key + + # example of direct logic + @staticmethod + def field_path_from_key(parent: Key, key: Key) -> List[Union[str, int]]: + return list(part.decode("utf-8") for part in key.relative_name(parent)) + + @staticmethod + def read(parent: Key, hier_str: str) -> List[Key]: + keys = [] + HierPlugin.load_json_like(json.loads(hier_str), parent, keys, []) + return keys + + @staticmethod + def write(parent: Key, keys: List[Key]) -> str: + return json.dumps(HierPlugin.create_json_like(parent, keys), indent=2, ensure_ascii=False) + + # helper function + # in C this should be done directly, by traversing KeyHierarchy and immediately writing to the file + @staticmethod + def create_json_like(parent: Key, keys: List[Key]): + def convert(hierarchy: KeyHierarchy): + def convert_map(): + return dict((Key.base_name(bytes(k, encoding="utf-8")).decode("utf-8"), convert(v)) for (k, v) in hierarchy.map_children.items()) + + def convert_array(): + return {} if len(hierarchy.array_children) == 0 else dict((Key.array_index(i).decode("utf-8"), convert(v)) for i, v in enumerate(hierarchy.array_children) if (v is not None)) + + def convert_value(): + return {} if hierarchy.value.value is None else {"value": hierarchy.value.value} + + if len(hierarchy.map_children) == 0: + if len(hierarchy.array_children) == 0: + if hierarchy.value == None: + raise Exception("empty hierarchy") + + return hierarchy.value.value + elif hierarchy.value == None: + return convert_array() + + return {"®elektra": {**convert_value()}, **convert_array(), **convert_map()} + + return convert(KeyHierarchy.create(parent, keys)) + + # helper function for Json and Hier + # in C this should be done directly, by creating Keys while reading to the file + @staticmethod + def load_json_like(json_data, parent: Key, keys: List[Key], path: List[Union[str, int]]): + if isinstance(json_data, list): + for i, element in enumerate(json_data): + HierPlugin.load_json_like(element, parent, keys, path + [i]) + elif isinstance(json_data, dict): + for k, data in json_data.items(): + if k == "®elektra": + if data is None: + continue + + if "value" in data: + key = HierPlugin.key_from_field_path(parent, path) + key.value = data["value"] + keys.append(key) + else: + HierPlugin.load_json_like(data, parent, keys, path + [k]) + else: + key = HierPlugin.key_from_field_path(parent, path) + key.value = json_data + keys.append(key) + + +class Hier2Plugin(): + # hierachical plugin without arrays, syntax = JSON minus arrays, different encoding of arrays + # + # arrays are encoded as { "®elektra": { "array": { "#0": 1, "#1": 2 } } } + # the field name "#0" is an array element, if and only if it is a child of "array" and that in turn is a child of "®elektra" + # + # mixed array and map children are supported without special handling, everything is encoded as objects + # holes in arrays don't need special handling, since arrays encoded as objects + # + # non-leaf keys with value are handled like in JsonPlugin + # metadata would also be handled like in JsonPlugin + # + + # example of direct logic + @staticmethod + def key_from_field_path(parent: Key, fields: List[str]) -> Key: + key = Key(parent.name()) + + special = False + array = False + for field in fields: + field_bytes = bytes(field, encoding="utf-8") + + if array: + array = False + key.add_array_index(Key.read_array_index(field_bytes)) + elif special: + special = False + if field == "value": + break + elif field == "array": + array = True + elif field == "®elektra": + special = True + else: + key.add_base_name(field_bytes) + + return key + + # example of direct logic + @staticmethod + def field_path_from_key(parent: Key, key: Key) -> List[Union[str, int]]: + def hier2_field(part: bytes) -> List[str]: + if len(part) > 1 and part[0:1] == b"#": + if part[1:2] == b"#": + return [part[1:].decode("utf-8")] + else: + return ["®elektra", "array", part.decode("utf-8")] + else: + return [part.decode("utf-8")] + + fields = [] + for part in key.relative_name(parent): + fields.extend(hier2_field(part)) + return fields + + @staticmethod + def read(parent: Key, hier2_str: str) -> List[Key]: + keys = [] + Hier2Plugin.load_json_like(json.loads(hier2_str), parent, keys, []) + return keys + + @staticmethod + def write(parent: Key, keys: List[Key]) -> str: + return json.dumps(Hier2Plugin.create_json_like(parent, keys), indent=2, ensure_ascii=False) + + # helper function + # in C this should be done directly, by traversing KeyHierarchy and immediately writing to the file + @staticmethod + def create_json_like(parent: Key, keys: List[Key]): + def convert(hierarchy: KeyHierarchy): + def convert_map(): + return dict((k, convert(v)) for (k, v) in hierarchy.map_children.items()) + + def array_data(): + return dict((Key.array_index(i).decode("utf-8"), convert(v)) for i, v in enumerate(hierarchy.array_children) if (v is not None)) + + def convert_array(): + return {} if len(hierarchy.array_children) == 0 else {"array": array_data()} + + def convert_value(): + return {} if hierarchy.value.value is None else {"value": hierarchy.value.value} + + if len(hierarchy.map_children) == 0: + if len(hierarchy.array_children) == 0: + if hierarchy.value == None: + raise Exception("empty hierarchy") + + return hierarchy.value.value + + return {"®elektra": {**convert_value(), **convert_array()}, **convert_map()} + + return convert(KeyHierarchy.create(parent, keys)) + + # helper function for Json and Hier + # in C this should be done directly, by creating Keys while reading to the file + @staticmethod + def load_json_like(json_data, parent: Key, keys: List[Key], path: List[Union[str, int]]): + if isinstance(json_data, list): + for i, element in enumerate(json_data): + Hier2Plugin.load_json_like(element, parent, keys, path + [i]) + elif isinstance(json_data, dict): + for k, data in json_data.items(): + if k == "®elektra": + if data is None: + continue + + if "value" in data: + key = Hier2Plugin.key_from_field_path(parent, path) + key.value = data["value"] + keys.append(key) + + if "array" in data: + for i, element in data["array"].items(): + Hier2Plugin.load_json_like( + element, parent, keys, path + [k, "array", i] + ) + else: + Hier2Plugin.load_json_like(data, parent, keys, path + [k]) + else: + key = Hier2Plugin.key_from_field_path(parent, path) + key.value = json_data + keys.append(key) + + +def demo_test(): + print("Constructing key: ") + + print(" - start with 'user:/test/abc'") + key = Key("user:/test/abc") + + print(" - add base name 'xyz'") + key.add_base_name(b"xyz") + + print(" - delete last part") + key.del_last_part() + + print(" - add base name 'd.ef'") + key.add_base_name(b"d.ef") + + print(" - add base name '#0'") + key.add_base_name(b"#0") + + print(" - add base name 'xyz'") + key.add_base_name(b"xyz") + + print(" - set to base name 'ghi'") + key.set_base_name(b"ghi") + + print(" - add array index 1") + key.add_array_index(1) + + print(" - add base name 'xyz'") + key.add_base_name(b"xyz") + + print(" - set to array index 10") + key.set_array_index(10) + + print(" - add base name '' (empty)") + key.add_base_name(b"") + + print(" - add base name 'j/k\\l' (slash, backslash)") + key.add_base_name(b"j/k\\l") + + print(" - add base name '#' (hash)") + key.add_base_name(b"#") + + print() + + print("Resulting key: ", "namespace=", + key.namespace, ", parts=", key.parts(), sep="") + print("Resulting name: ", key.name(), sep="") + print() + + try: + key.add_base_name(b"\xc2\xaeelektra") + except KeyNameException: + print("'®elektra' is reserved") + else: + print("'®elektra' is not reserved") + print() + + print("Convert the key 'user:/test/abc/d.ef/##0/ghi/#1/#_10/%/j\\/k\\\\l/#' with parent 'user:/test/abc'") + + parent = Key("user:/test/abc") + print( + "- dump:", + "\n <-", DumpPlugin.write_key_name(parent, key), + "\n ->", DumpPlugin.read_key_name( + parent, + "d.ef/##0/ghi/#1/#_10/%/j\\/k\\\\l/#" + ).name() + ) + print( + "- properties:", + "\n <-", PropertiesPlugin.write_key_name(parent, key), + "\n ->", PropertiesPlugin.read_key_name( + parent, + "d\\.ef.##0.ghi.#1.#_10..j/k\\\\l.#" + ).name() + ) + print( + "- json:", + "\n <-", JsonPlugin.field_path_from_key(parent, key), + "\n ->", JsonPlugin.key_from_field_path( + parent, + ['d.ef', '#0', 'ghi', 1, 10, '', 'j/k\\l', '#'] + ).name() + ) + + # hier == "json without arrays" + print( + "- hier (json w/o arrays):", + "\n <-", HierPlugin.field_path_from_key(parent, key), + "\n ->", HierPlugin.key_from_field_path( + parent, + ['d.ef', '##0', 'ghi', '#1', '#_10', '', 'j/k\\l', '#'] + ).name() + ) + print() + + # hier2 == "json without arrays", different array encoding + print( + "- hier2 (json w/o arrays, different):", + "\n <-", Hier2Plugin.field_path_from_key(parent, key), + "\n ->", Hier2Plugin.key_from_field_path( + parent, + ['d.ef', '#0', 'ghi', '®elektra', 'array', '#1', + '®elektra', 'array', '#_10', '', 'j/k\\l', '#'] + ).name() + ) + print() + + print("Convert keys with parent 'user:/test/abc'") + print("Keys") + keys = [ + Key("user:/test/abc", 1), + Key("user:/test/abc/d.ef", 2), + Key("user:/test/abc/d.ef/##0", 3), + Key("user:/test/abc/d.ef/##0/ghi", 4), + Key("user:/test/abc/d.ef/##0/ghi/#0", 5), + Key("user:/test/abc/d.ef/##0/ghi/#1", 6), + Key("user:/test/abc/d.ef/##0/ghi/#1/#_10", 7), + Key("user:/test/abc/d.ef/##0/ghi/#1/#_10/%", 8), + Key("user:/test/abc/d.ef/##0/ghi/#1/#_10/%/j\\/k\\\\l", 9), + Key("user:/test/abc/d.ef/##0/ghi/#1/#_10/%/j\\/k\\\\l/#", 10), + Key("user:/test/abc/d.ef/##0/ghi/#2", 11), + Key("user:/test/abc/d.ef/##0/xyz", 12), + Key("user:/test/abc/d.ef/##0/xyz/#0", 13), + Key("user:/test/abc/d.ef/##0/xyz/#1", 14), + Key("user:/test/abc/d.ef/##0/xyz/#1/#0", 15), + Key("user:/test/abc/d.ef/##0/xyz/#1/#1", 16), + Key("user:/test/abc/d.ef/##0/xyz/#2/a", 18), + Key("user:/test/abc/d.ef/##0/xyz/#2", 17), + Key("user:/test/abc/str=ing", "str"), + Key("user:/test/abc/nu:ll", None), + ] + print("[", *(k for k in keys), sep="\n ") + print("]") + print() + + properties_data = PropertiesPlugin.write(parent, keys) + print("Properties") + print(properties_data) + + json_data = JsonPlugin.write(parent, keys) + print("JSON") + print(json_data) + print() + + hier_data = HierPlugin.write(parent, keys) + print("Hier") + print(hier_data) + print() + + hier2_data = Hier2Plugin.write(parent, keys) + print("Hier2") + print(hier2_data) + print() + + print("Reading data back") + + def find(key: Key) -> bool: + return any((k.name() == key.name() and str(k.value) == str(key.value)) for k in keys) + + properties_keys = PropertiesPlugin.read(parent, properties_data) + print("Properties", "matches" if len(keys) == len(properties_keys) + and all(find(k) for k in properties_keys) else "doesn't match") + + json_keys = JsonPlugin.read(parent, json_data) + print("Json", "matches" if len(keys) == len(json_keys) and all(find(k) + for k in json_keys) else "doesn't match") + + hier_keys = HierPlugin.read(parent, hier_data) + print("Hier", "matches" if len(keys) == len(hier_keys) and all(find(k) + for k in hier_keys) else "doesn't match") + + hier2_keys = Hier2Plugin.read(parent, hier2_data) + print("Hier2", "matches" if len(keys) == len(hier2_keys) and all(find(k) + for k in hier2_keys) else "doesn't match") + + +""" +START OF MAIN FUNCTION +""" + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Check an convert Elektra Key Names." + ) + + subparsers = parser.add_subparsers( + title="commands", + dest="command" + ) + + p_canonicalize = subparsers.add_parser( + "canonicalize", + description="canonicalize Key Name and print result" + ) + p_canonicalize.add_argument( + "--prefix", "-p", + nargs="?", + default="", + help="existing Key Name to which 'name' should be added" + ) + p_canonicalize.add_argument( + "name", + help="the Key Name to canonicalize" + ) + + p_unescape = subparsers.add_parser( + "unescape", + description="unescape Key Name and print one part per line" + ) + p_unescape.add_argument( + "--raw", "-r", + action="store_true", + help="print the raw unescaped Key Name instead of one part per line" + ) + p_unescape.add_argument( + "--python-bytes", "-b", + action="store_true", + help="print the raw unescaped Key Name as a python bytes object" + ) + p_unescape.add_argument( + "name", + help="the Key Name to unescape" + ) + + p_unescape = subparsers.add_parser( + "demo", + description="run demo tests" + ) + + # CHANGED: added repl + p_unescape = subparsers.add_parser( + "repl", + description="open repl" + ) + + args = parser.parse_args() + + if args.command == "demo": + demo_test() + elif args.command == "repl": + import code + code.InteractiveConsole(locals=globals()).interact() + elif args.command == "canonicalize": + try: + if "prefix" in args: + key_canonical = Key.canonicalize(args.name, args.prefix) + else: + key_canonical = Key.canonicalize(args.name) + + print(key_canonical) + except KeyNameException as e: + print("ERROR:", e, file=sys.stderr) + exit(1) + elif args.command == "unescape": + try: + if "prefix" in args: + key_canonical = Key.canonicalize(args.name, args.prefix) + else: + key_canonical = Key.canonicalize(args.name) + + if args.verbose: + print(f"[DEBUG] canonical version of name: {key_canonical}") + + (namespace, unescaped) = Key.unescape(key_canonical) + + if args.raw: + sys.stdout.buffer.write( + bytes(namespace.value) + + b"\0" + + b"\0".join(bytes(p, encoding="utf-8") for p in unescaped) + + b"\0" + ) + elif args.python_bytes: + print( + bytes(namespace.value) + + b"\0" + + b"\0".join(bytes(p, encoding="utf-8") for p in unescaped) + + b"\0" + ) + else: + print(str(namespace)) + for part in unescaped: + print(part) + except KeyNameException as e: + print("ERROR:", e, file=sys.stderr) + exit(1) + else: + parser.print_usage() diff --git a/doc/keynames/tree.svg b/doc/keynames/tree.svg new file mode 100644 index 00000000000..e0822c79a84 --- /dev/null +++ b/doc/keynames/tree.svg @@ -0,0 +1,43 @@ + + + + + + elektra + + + + version + + + + + + + + data + + + + + + + + info + + + + + + + \ No newline at end of file diff --git a/doc/man/man1/kdb-backup.1 b/doc/man/man1/kdb-backup.1 index 82a0c2be996..d9361ffb026 100644 --- a/doc/man/man1/kdb-backup.1 +++ b/doc/man/man1/kdb-backup.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-BACKUP" "" "August 2019" "" "" +.TH "KDB\-BACKUP" "" "May 2020" "" "" . .SH "NAME" \fBkdb\-backup\fR \- Make a backup of current KDB diff --git a/doc/man/man1/kdb-cache.1 b/doc/man/man1/kdb-cache.1 index 7d5ca35c6ce..f40f794aff7 100644 --- a/doc/man/man1/kdb-cache.1 +++ b/doc/man/man1/kdb-cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-CACHE" "1" "August 2019" "" "" +.TH "KDB\-CACHE" "1" "September 2020" "" "" . .SH "NAME" \fBkdb\-cache\fR \- Enable, disable or clear the cache @@ -45,7 +45,7 @@ Give debug information\. Prints additional debug information in case of errors/w . .nf -# Backup\-and\-Restore: system/elektra/cache +# Backup\-and\-Restore: system:/elektra/cache # Enable the cache kdb cache enable diff --git a/doc/man/man1/kdb-change-resolver-symlink.1 b/doc/man/man1/kdb-change-resolver-symlink.1 index d464b91e6dd..fbc218cdd9b 100644 --- a/doc/man/man1/kdb-change-resolver-symlink.1 +++ b/doc/man/man1/kdb-change-resolver-symlink.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-CHANGE\-RESOLVER\-SYMLINK" "" "August 2019" "" "" +.TH "KDB\-CHANGE\-RESOLVER\-SYMLINK" "" "May 2020" "" "" . .SH "NAME" \fBkdb\-change\-resolver\-symlink\fR \- Changes the default resolver symlink diff --git a/doc/man/man1/kdb-change-storage-symlink.1 b/doc/man/man1/kdb-change-storage-symlink.1 index 97f4a524631..1dd1492c6f1 100644 --- a/doc/man/man1/kdb-change-storage-symlink.1 +++ b/doc/man/man1/kdb-change-storage-symlink.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-CHANGE\-STORAGE\-SYMLINK" "" "August 2019" "" "" +.TH "KDB\-CHANGE\-STORAGE\-SYMLINK" "" "May 2020" "" "" . .SH "NAME" \fBkdb\-change\-storage\-symlink\fR \- Changes the default storage symlink diff --git a/doc/man/man1/kdb-check-env-dep.1 b/doc/man/man1/kdb-check-env-dep.1 index 52c963bf31e..96f971a3678 100644 --- a/doc/man/man1/kdb-check-env-dep.1 +++ b/doc/man/man1/kdb-check-env-dep.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-PLUGIN\-CHECK\-ENV\-DEP" "" "October 2019" "" "" +.TH "KDB\-PLUGIN\-CHECK\-ENV\-DEP" "" "May 2020" "" "" . .SH "NAME" \fBkdb\-plugin\-check\-env\-dep\fR \- Checks which mount points are influenced by environment variables diff --git a/doc/man/man1/kdb-cmerge.1 b/doc/man/man1/kdb-cmerge.1 index b84b815e106..ccce06f4f64 100644 --- a/doc/man/man1/kdb-cmerge.1 +++ b/doc/man/man1/kdb-cmerge.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-CMERGE" "1" "November 2019" "" "" +.TH "KDB\-CMERGE" "1" "September 2020" "" "" . .SH "NAME" \fBkdb\-cmerge\fR \- Three\-way merge of KeySets @@ -142,14 +142,14 @@ To complete a simple merge of three KeySets: . .nf -kdb set user/base "A" -#> Create a new key user/base with string "A" -kdb set user/their "A" -#> Create a new key user/their with string "A" -kdb set user/our "B" -#> Create a new key user/our with string "B" -kdb cmerge user/our user/their user/base user/result -kdb get user/result +kdb set user:/base "A" +#> Create a new key user:/base with string "A" +kdb set user:/their "A" +#> Create a new key user:/their with string "A" +kdb set user:/our "B" +#> Create a new key user:/our with string "B" +kdb cmerge user:/our user:/their user:/base user:/result +kdb get user:/result #>B ```
diff --git a/doc/man/man1/kdb-complete.1 b/doc/man/man1/kdb-complete.1 index eec7ad220d0..b137afb9486 100644 --- a/doc/man/man1/kdb-complete.1 +++ b/doc/man/man1/kdb-complete.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-COMPLETE" "1" "August 2019" "" "" +.TH "KDB\-COMPLETE" "1" "September 2020" "" "" . .SH "NAME" \fBkdb\-complete\fR \- Show suggestions how to complete a given path @@ -57,27 +57,27 @@ Give debug information\. Prints additional debug information in case of errors/w . .nf -# Backup\-and\-Restore: user/tests/complete/examples +# Backup\-and\-Restore: user:/tests/complete/examples # Create the keys we use for the examples -kdb set user/tests/complete/examples/kdb\-complete/level1 foo -kdb set user/tests/complete/examples/kdb\-complete/lvl1/lvl2 bar -kdb set user/tests/complete/examples/kdb\-complete/lvl1/lvl2/lvl3/lvl4/lvl5 fizz -kdb set user/tests/complete/examples/kdb\-complete/buzz fizzBuzz -kdb set user/tests/complete/examples/kdb\-complete/#array_1 asdf -kdb set user/tests/complete/examples/kdb\-complete/% nothing +kdb set user:/tests/complete/examples/kdb\-complete/level1 foo +kdb set user:/tests/complete/examples/kdb\-complete/lvl1/lvl2 bar +kdb set user:/tests/complete/examples/kdb\-complete/lvl1/lvl2/lvl3/lvl4/lvl5 fizz +kdb set user:/tests/complete/examples/kdb\-complete/buzz fizzBuzz +kdb set user:/tests/complete/examples/kdb\-complete/#1 asdf +kdb set user:/tests/complete/examples/kdb\-complete/% nothing # list suggestions for namespaces starting with us, only the current level kdb complete us \-\-max\-depth=1 -#> user/ +#> user:/ # list suggestions for namespaces starting with user, only the current level kdb complete user \-\-max\-depth=1 -#> user/ +#> user:/ # list suggestions for the namespace user, only the next level as it ends with / # note the difference to the previous example, which uses no trailing / -kdb complete user/ \-\-max\-depth=1 +kdb complete user:/ \-\-max\-depth=1 # STDOUT\-REGEX: \.+ # list all possible namespaces or mount points, only the current level @@ -86,24 +86,24 @@ kdb complete \-\-max\-depth=1 # list suggestions for /tests/complete/examples/kdb\-complete, only the current level kdb complete /tests/complete/examples/kdb\-complete \-\-max\-depth=1 -#> user/tests/complete/examples/kdb\-complete/ +#> user:/tests/complete/examples/kdb\-complete/ # list suggestions for /tests/complete/examples/kdb\-complete/, only the next level # again, note the difference to the previous example which has no trailing / kdb complete /tests/complete/examples/kdb\-complete/ \-\-max\-depth=1 -#> user/tests/complete/examples/kdb\-complete/% -#> user/tests/complete/examples/kdb\-complete/#array_1 -#> user/tests/complete/examples/kdb\-complete/buzz -#> user/tests/complete/examples/kdb\-complete/level1 -#> user/tests/complete/examples/kdb\-complete/lvl1/ +#> user:/tests/complete/examples/kdb\-complete/% +#> user:/tests/complete/examples/kdb\-complete/#1 +#> user:/tests/complete/examples/kdb\-complete/buzz +#> user:/tests/complete/examples/kdb\-complete/level1 +#> user:/tests/complete/examples/kdb\-complete/lvl1/ # list suggestions for /tests/complete/examples/kdb\-complete which are minimum 2 levels # away from that key, and maximum 4 levels away kdb complete /tests/complete/examples/kdb\-complete/ \-\-min\-depth=2 \-\-max\-depth=4 -#> user/tests/complete/examples/kdb\-complete/lvl1/lvl2/lvl3/ -#> user/tests/complete/examples/kdb\-complete/lvl1/lvl2/lvl3/lvl4/ +#> user:/tests/complete/examples/kdb\-complete/lvl1/lvl2/lvl3/ +#> user:/tests/complete/examples/kdb\-complete/lvl1/lvl2/lvl3/lvl4/ -kdb rm \-r user/tests/complete/examples/kdb\-complete +kdb rm \-r user:/tests/complete/examples/kdb\-complete . .fi . diff --git a/doc/man/man1/kdb-convert.1 b/doc/man/man1/kdb-convert.1 index e9cf9aa8754..a0e2da3e58c 100644 --- a/doc/man/man1/kdb-convert.1 +++ b/doc/man/man1/kdb-convert.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-CONVERT" "1" "August 2019" "" "" +.TH "KDB\-CONVERT" "1" "May 2020" "" "" . .SH "NAME" \fBkdb\-convert\fR \- Convert configuration files using elektra diff --git a/doc/man/man1/kdb-cp.1 b/doc/man/man1/kdb-cp.1 index c7c59808275..5ecb02b61a1 100644 --- a/doc/man/man1/kdb-cp.1 +++ b/doc/man/man1/kdb-cp.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-CP" "1" "August 2019" "" "" +.TH "KDB\-CP" "1" "September 2020" "" "" . .SH "NAME" \fBkdb\-cp\fR \- Copy keys within the key database @@ -71,51 +71,51 @@ Force overwriting the keys\. . .nf -# Backup\-and\-Restore: user/tests/cp/examples +# Backup\-and\-Restore: user:/tests/cp/examples # Create the keys we use for the examples -kdb set user/tests/cp/examples/kdb\-cp/key key1 -kdb set user/tests/cp/examples/kdb\-cp/key/first key -kdb set user/tests/cp/examples/kdb\-cp/key/second key -kdb set user/tests/cp/examples/kdb\-cp/cpkey key1 -kdb set user/tests/cp/examples/kdb\-cp/cpkey/first key -kdb set user/tests/cp/examples/kdb\-cp/cpkey/second key -kdb set user/tests/cp/examples/kdb\-cp/cpkeyerror/first key -kdb set user/tests/cp/examples/kdb\-cp/cpkeyerror/second anotherValue -kdb set user/tests/cp/examples/kdb\-cp/another/key one -kdb set user/tests/cp/examples/kdb\-cp/another/value two +kdb set user:/tests/cp/examples/kdb\-cp/key key1 +kdb set user:/tests/cp/examples/kdb\-cp/key/first key +kdb set user:/tests/cp/examples/kdb\-cp/key/second key +kdb set user:/tests/cp/examples/kdb\-cp/cpkey key1 +kdb set user:/tests/cp/examples/kdb\-cp/cpkey/first key +kdb set user:/tests/cp/examples/kdb\-cp/cpkey/second key +kdb set user:/tests/cp/examples/kdb\-cp/cpkeyerror/first key +kdb set user:/tests/cp/examples/kdb\-cp/cpkeyerror/second anotherValue +kdb set user:/tests/cp/examples/kdb\-cp/another/key one +kdb set user:/tests/cp/examples/kdb\-cp/another/value two # To copy a single key: -kdb cp user/tests/cp/examples/kdb\-cp/key user/tests/cp/examples/kdb\-cp/key2 +kdb cp user:/tests/cp/examples/kdb\-cp/key user:/tests/cp/examples/kdb\-cp/key2 #> # To copy multiple keys: -kdb cp \-r user/tests/cp/examples/kdb\-cp/key user/tests/cp/examples/kdb\-cp/copied +kdb cp \-r user:/tests/cp/examples/kdb\-cp/key user:/tests/cp/examples/kdb\-cp/copied #> # If the target\-key already exists and has a different value, cp fails: -kdb cp \-r user/tests/cp/examples/kdb\-cp/key user/tests/cp/examples/kdb\-cp/cpkeyerror +kdb cp \-r user:/tests/cp/examples/kdb\-cp/key user:/tests/cp/examples/kdb\-cp/cpkeyerror # RET: 11 # If the target\-key already exists and has the same value as the source, everything is fine: -kdb cp \-r user/tests/cp/examples/kdb\-cp/key user/tests/cp/examples/kdb\-cp/cpkey +kdb cp \-r user:/tests/cp/examples/kdb\-cp/key user:/tests/cp/examples/kdb\-cp/cpkey #> # To force the copy of keys: -kdb cp \-rf user/tests/cp/examples/kdb\-cp/key user/tests/cp/examples/kdb\-cp/cpkeyerror +kdb cp \-rf user:/tests/cp/examples/kdb\-cp/key user:/tests/cp/examples/kdb\-cp/cpkeyerror #> # Now the key\-values of /cpkeyerror are overwritten: -kdb export user/tests/cp/examples/kdb\-cp/cpkeyerror mini +kdb export user:/tests/cp/examples/kdb\-cp/cpkeyerror mini #> =key1 #> first=key #> second=key # To copy keys below an existing key: -kdb cp \-r user/tests/cp/examples/kdb\-cp/another user/tests/cp/examples/kdb\-cp/another/key +kdb cp \-r user:/tests/cp/examples/kdb\-cp/another user:/tests/cp/examples/kdb\-cp/another/key #> -kdb rm \-r user/tests/cp/examples/kdb\-cp/ +kdb rm \-r user:/tests/cp/examples/kdb\-cp/ . .fi diff --git a/doc/man/man1/kdb-editor.1 b/doc/man/man1/kdb-editor.1 index 1196f366e6b..d3c800db1a5 100644 --- a/doc/man/man1/kdb-editor.1 +++ b/doc/man/man1/kdb-editor.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-EDITOR" "1" "November 2019" "" "" +.TH "KDB\-EDITOR" "1" "September 2020" "" "" . .SH "NAME" \fBkdb\-editor\fR \- Use your editor for editing KDB @@ -103,10 +103,10 @@ The default editor, if no \fB\-e\fR option is given\. Defaults to \fB/usr/bin/se Specifies which default namespace should be used when setting a cascading name\. By default the namespace is user, except \fBkdb\fR is used as root, then \fBsystem\fR is the default (\fBvalidate\fR strategy only)\. . .SH "EXAMPLES" -To change the configuration in KDB below \fBuser/ini\fR with \fB/usr/bin/vim\fR, you would use: +To change the configuration in KDB below \fBuser:/ini\fR with \fB/usr/bin/vim\fR, you would use: . .br -\fBkdb editor \-e /usr/bin/vim user/ini\fR +\fBkdb editor \-e /usr/bin/vim user:/ini\fR . .P Or set a new editor as default using: diff --git a/doc/man/man1/kdb-elektrify-getenv.1 b/doc/man/man1/kdb-elektrify-getenv.1 index 9d22ed066e7..81cfb0e766a 100644 --- a/doc/man/man1/kdb-elektrify-getenv.1 +++ b/doc/man/man1/kdb-elektrify-getenv.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "KDB\-ELEKTRIFY\-GETENV" "1" "October 2019" "" "" +.TH "KDB\-ELEKTRIFY\-GETENV" "1" "September 2020" "" "" . .SH "NAME" \fBkdb\-elektrify\-getenv\fR \- elektrify the environment of applications @@ -20,7 +20,7 @@ kdb elektrify\-getenv kdb elektrify\-getenv curl \-\-elektra\-version kdb elektrify\-getenv curl https://www\.libelektra\.org -kdb set system/elektra/intercept/getenv/override/http_proxy http://www\.example\.com/ +kdb set system:/elektra/intercept/getenv/override/http_proxy http://www\.example\.com/ kdb elektrify\-getenv curl https://www\.libelektra\.org . .fi @@ -33,7 +33,7 @@ By using \fBkdb elektrify\-getenv\fR the last curl invocation will use a differe .nf ELEKTRA_RELOAD_TIMEOUT=100 kdb elektrify\-getenv firefox -kdb set system/elektra/intercept/getenv/override/http_proxy http://www\.example\.com +kdb set system:/elektra/intercept/getenv/override/http_proxy http://www\.example\.com . .fi . @@ -84,7 +84,7 @@ E\.g\. \fBkdb elektrify\-getenv \-\-elektra:HOME=/path/to/home\fR Then \fB/elektra/intercept/getenv/override/\fR will be looked up, where \fIkey\fR is the parameter to \fBgetenv\fR\. If found, the key will be returned, if it is a null keys, \fBgetenv\fR will return \fBNULL\fR\. . .IP -E\.g\. \fBkdb set user/elektra/intercept/getenv/override/HOME /path/to/home\fR +E\.g\. \fBkdb set user:/elektra/intercept/getenv/override/HOME /path/to/home\fR . .IP "3." 4 Then environment will be requested\. @@ -96,7 +96,7 @@ E\.g\. \fBHOME=/path/to/home kdb elektrify\-getenv \fR Then \fB/elektra/intercept/getenv/fallback/\fR will be looked up\. If found, the key will be returned, if it is a null keys, \fBgetenv\fR will return \fBNULL\fR\. . .IP -E\.g\. \fBkdb set user/elektra/intercept/getenv/fallback/HOME /path/to/home\fR +E\.g\. \fBkdb set user:/elektra/intercept/getenv/fallback/HOME /path/to/home\fR . .IP "" 0 . @@ -115,7 +115,7 @@ Gives version information\. . .TP \fB\-\-elektra\-debug=file\fR, \fBELEKTRA_DEBUG\fR or \fB/elektra/intercept/getenv/option/debug\fR -Trace all getenv(3) calls to a file\. stderr if no file is given, e\.g\. \fBkdb set user/elektra/intercept/getenv/option/debug ""\fR\. Note that null values (no forth argument), will disable debug messages\. See examples below\. +Trace all getenv(3) calls to a file\. stderr if no file is given, e\.g\. \fBkdb set user:/elektra/intercept/getenv/option/debug ""\fR\. Note that null values (no forth argument), will disable debug messages\. See examples below\. . .TP \fB\-\-elektra\-clearenv\fR, \fBELEKTRA_CLEARENV\fR or \fB/elektra/intercept/getenv/option/clearenv\fR @@ -138,10 +138,10 @@ as environment variable: \fBELEKTRA_