diff --git a/doc/CONTRACT.ini b/doc/CONTRACT.ini index 9b090735cb3..ef3d543ad80 100644 --- a/doc/CONTRACT.ini +++ b/doc/CONTRACT.ini @@ -223,7 +223,7 @@ description = any non-empty string disables the stacking of plugins. type = list status = implemented usedby = plugin spec -example = binary code +example = binary description = Lists the requirements of the plugin. This can be a name of a plugin, but you should always prefer the name of providers. @@ -238,6 +238,9 @@ description = Lists the requirements of the plugin. that such a provider must be present anywhere in the backend. The name can also directly refer to another plugin’s name. + If your plugin does not has native support for serializing binary + data, make sure that `infos/needs` contains `binary`. + [infos/recommends] type = string status = implemented @@ -281,39 +284,7 @@ description = Load plugins as given (with arguments as in "kdb mount"). [infos/status] -type = vector - {"default", 64000}, ; will be added by the build system for KDB_DEFAULT_STORAGE and KDB_DEFAULT_RESOLVER - {"recommended", 32000}, ; in case of doubt, use this plugin - {"productive", 8000}, ; actively used in productive environments, not only by maintainer - {"maintained", 4000}, ; actively used and fixed by maintainer (infos/author) - {"reviewed", 4000}, ; actively reviewed on every change and not by maintainer - {"conformant", 2000}, ; to indicate that e.g. a storage plugin fulfils all requirements of a storage plugin - {"compatible", 2000}, ; to indicate it will be compatible with its later versions - {"coverage", 2000}, ; unittests have full code coverage - {"specific", 1000}, ; means that the plugin is non-portable in order to gain some specific advantages for the user - ; (i.e. in a positive sense specific/non-portable) - {"unittest", 1000}, ; substantial plugin unittests (testmod) - {"shelltest", 1000}, ; substantial unittests with shell - {"tested", 500}, ; extensively manually tested on every change - {"nodep", 250}, ; no external library dependencies, except the languages core deps, e.g. libstdc++ and other plugins in `needs` - {"libc", 250}, ; uses libc only, no deps of other language’s run-times, e.g., libstdc++ - {"configurable", 50}, ; options available to modify behavior - {"final", 50}, ; no further extensions, configure options or features are desirable - {"global", 1}, ; suitable as global plugin - {"readonly", 0}, ; can only read data from files (only kdbGet implemented) - {"writeonly", 0}, ; can only write data to files (only kdbSet implemented) - {"preview", -50}, ; plugin in technical preview state - {"memleak", -250}, ; memleak in plugin or one of the libraries the plugin uses - {"experimental", -500}, ; not much tested, plugin is in early stage, disabled in CMake by default - {"difficult", -500}, ; the plugin is (unnecessarily) difficult to use - {"limited", -750}, ; cannot represent arbitrary data (i.e. very specific format) - {"unfinished", -1000}, ; important functionality still missing - {"old", -1000}, ; code base is old and should be refactored/improved - {"nodoc", -1000}, ; documentation is minimal - {"concept", -2000}, ; the plugin only exists to demonstrate something - {"orphan", -4000}, ; author does not respond and also otherwise not much knowledge about plugin is present - {"obsolete", -4000}, ; another plugin fulfils a similar functionality in a better way - {"discouraged", -32000}, ; only use the plugin if you really know what you are doing +type = vector status = implemented usedby = plugin spec binding description = Tags about how well-established and well-working a plugin is. @@ -323,9 +294,8 @@ description = Tags about how well-established and well-working a plugin is. Numerical values are allowed, too. Please argue in the infos/description why numerical values are used. - When changing some value in the type, you need to copy the information to - src/libs/tools/src/plugindatabase.cpp - src/plugins/template/README.md + For individual values see: + src/libs/tools/include/plugincontract.h [infos/version] @@ -339,42 +309,55 @@ description = Exports the plugin version this plugin was compiled The version implies how the plugin interface must look like. -[config/needs] + +[infos/features/storage] +type = vector status = implemented -usedby = plugin spec -description = Exports a plugin configuration needed by another plugin. All keys - below `config/needs` will be propagated to the backend configuration. - Usually a provider in infos/needs then will use this configuration. - Alternatively, it can be provided if it avoids conflicts with some - other plugins. +usedby = plugin +description = Tags about how feature-full a storage plugin is. - It presents the plugin configuration needed so that - the plugin works properly. Typically the configuration is not for the - plugin itself, but for other needed plugins (in infos/needs). + Different features can be combined. + For individual features see: + src/libs/tools/include/pluginfeatures.h [infos/environment] type = string -status = PROPOSED +status = implemented usedby = plugin kdb-plugin-info example = HOME USER -description = List all environment variables the plugin - may access. +description = List all environment variables the plugin may access. - Note: Not listed environment variables do not mean that there - are none (the clause is only proposed, not yet implemented). - Grep for `getenv` to list all environment variables. + Space separated list of environment variables. + + An empty list means that no environment variables influences + the behavior of the plugin. [infos/dependencies/_] type = string -status = PROPOSED +status = implemented usedby = plugin kdb-plugin-info example = libyajl-dev description = The list of dependencies a plugin has for a specific package management system (like deb, rpm, arch, homebrew, ...). - Note: Not listed dependencies do not mean that there - are none (the clause is only proposed, not yet implemented). - See `infos/status` with `nodep` for up-to-date information. + Space separated list of dependencies. + + An empty list means that only language core deps are used, + e.g. libc or libstdc++. + + +[config/needs] +status = implemented +usedby = plugin spec +description = Exports a plugin configuration needed by another plugin. All keys + below `config/needs` will be propagated to the backend configuration. + Usually a provider in infos/needs then will use this configuration. + Alternatively, it can be provided if it avoids conflicts with some + other plugins. + + It presents the plugin configuration needed so that + the plugin works properly. Typically the configuration is not for the + plugin itself, but for other needed plugins (in infos/needs). diff --git a/doc/METADATA.ini b/doc/METADATA.ini index fa03a92cb02..eb91295c608 100644 --- a/doc/METADATA.ini +++ b/doc/METADATA.ini @@ -154,6 +154,11 @@ description="The spaces/tabs used between a comment and the beginning of the An error needs to be emitted if non-ignored spaces are present." example= +[indentation] +status=proposal +type= string +description= Preserves whitespace in front of the key used for indentation. + [internal//*] status= implemented diff --git a/doc/news/_preparation_next_release.md b/doc/news/_preparation_next_release.md index bd8b29f0ccd..14214a5dd64 100644 --- a/doc/news/_preparation_next_release.md +++ b/doc/news/_preparation_next_release.md @@ -80,6 +80,25 @@ Take a look at the [new docs](../dev/mountpoints.md), if you need to know detail ## Plugins The following text lists news about the [plugins](https://www.libelektra.org/plugins/readme) we updated in this release. +The following section lists news about the [plugins](https://www.libelektra.org/plugins/readme) we updated in this release. + +### Contract + +We simplified and extended the plugin's contract, mostly related to `infos/status`. +`infos/status` describes the development status of a plugin. +It is used for automatic selection of the best plugin during mounting. + +- many redundant tags were removed +- tags that are actually features (like `readonly`) were moved to `infos/features/storage` + (currently not used by any tools but we intend to use this for the test framework and advanced mounting features) +- tag `nodep` replaced by `infos/dependencies/_` +- introduced `infos/environment` to indicate if environment variables can influence the plugin (or mountpoint) +- tag `nodoc` renamed to `documented` +- to avoid duplication, the tags are now described in header files: + - src/libs/tools/include/plugincontract.h + - src/libs/tools/include/pluginfeatures.h + +Done in collaboration with _(Markus Raab, Klemens Böswirth, René Schwaiger, )_. ### list diff --git a/doc/tutorials/storage-plugins.md b/doc/tutorials/storage-plugins.md index e27c87850b4..5cf8bb31a1a 100644 --- a/doc/tutorials/storage-plugins.md +++ b/doc/tutorials/storage-plugins.md @@ -41,6 +41,8 @@ sudo kdb umount user:/tests/storage . For more information on why we allow “holes” in the hierarchy, please take a look [here](../decisions/5_implemented/holes.md). +Use the `directory/holes` tag in `infos/features/storage` to indicate that your storage plugin supports this feature. + [markdown shell recorder]: https://master.libelektra.org/tests/shell/shell_recorder/tutorial_wrapper ## Differentiate Between Empty Keys and Keys Containing an Empty String @@ -100,6 +102,8 @@ kdb rm -r user:/tests/storage sudo kdb umount user:/tests/storage ``` +Use the `type` tag in `infos/features/storage` to indicate that your storage plugin supports this feature. + ## Support Values Inside Non-Leaf Keys Sometimes the most “natural” mapping of key-value pairs to a file format might cause a storage plugin to not be able to store values in so-called directory (non-leaf) keys. @@ -158,6 +162,8 @@ sudo kdb umount user:/tests/storage . To make sure that your storage plugin works correctly, please just replace `yamlcpp` with the name of your plugin and verify that the test above still works. +Use the `directory/value` tag in `infos/features/storage` to indicate that your storage plugin supports this feature. + ## Support Array And Non-Array Data Properly You already learned about the array syntax and the mandatory `array` metakey in the [array tutorial](arrays.md). Now it is time to check, if your storage plugin supports array and non-array keys properly. Let us look at a concrete example. We use a key set that contains the following keys as example: @@ -303,6 +309,8 @@ sudo kdb umount user:/tests/hosts As you can see by setting the order metakey in the respective KDB entries, we can manipulate the order in which entries get written to the hosts file. Also when importing from the initial hosts file, the plugin stores the correct order in the meta KeySet. +Use the `array` tag in `infos/features/storage` to indicate that your storage plugin supports this feature. + diff --git a/src/libs/tools/include/plugincontract.h b/src/libs/tools/include/plugincontract.h new file mode 100644 index 00000000000..ff9a9628daf --- /dev/null +++ b/src/libs/tools/include/plugincontract.h @@ -0,0 +1,18 @@ +{"default", 64000}, //< to be used as default, will be added by the build system for KDB_DEFAULT_STORAGE and KDB_DEFAULT_RESOLVER +{"recommended", 32000}, //< in case of doubt, use this plugin +{"productive", 8000}, //< actively used in productive environments, not only by maintainer +{"maintained", 4000}, //< actively used and improved by maintainer (infos/author) +{"compatible", 2000}, //< will be compatible with its later versions +{"tested/unit", 1000}, //< substantial plugin unittests (testmod) +{"tested/shell", 1000}, //< substantial shell-recorder tests (README.md) +{"tested/fuzz", 1000}, //< tested using a fuzzer tool like AFL +{"documented", 1000}, //< all features are described in documentation (README.md) +{"configurable", 0}, //< plugin configuration available to modify behavior +{"global", 0}, //< suitable as global plugin +{"private", -250}, //< uses private header files from Elektra +{"memleak", -250}, //< memleak in plugin or one of the libraries the plugin uses +{"experimental", -4000}, //< plugin is in early stage, disabled in CMake by default +{"difficult", -8000}, //< the plugin is (unnecessarily) difficult to use +{"concept", -16000}, //< only a concept of how such a plugin could be done, needs proper rewrite +{"obsolete", -32000}, //< another plugin fulfils a similar functionality in a better way +{"discouraged", -64000}, //< only use the plugin if you really know what you are doing diff --git a/src/libs/tools/include/pluginfeatures.h b/src/libs/tools/include/pluginfeatures.h new file mode 100644 index 00000000000..0374419655e --- /dev/null +++ b/src/libs/tools/include/pluginfeatures.h @@ -0,0 +1,19 @@ +"read", //< Can read from configuration files +"write", //< Can write to configuration files +"spec/*/*", //< Supports the standard spec for the format, e.g. spec/toml/v1.0.0-rc.3 +"preserves/order", //< Preserves order of file structure (see order in doc/METADATA.ini) +"preserves/comment", //< Preserves comments (see comment/# in doc/METADATA.ini) +"preserves/comment/empty", //< Preserves empty lines in comments +"preserves/indentation", //< Preserves indentation around key and values (see indentation in doc/METADATA.ini) +"limited", //< Only specific structures of KeySets can be stored. This is for special purpose formats like hosts, fstab or passwd. +"arbitrary/keyset", //< Storage plugins should be able to read any (valid) config file and produce a KeySet. The few plugins marked with this tag, find also a config file for any KeySet. +"arbitrary/metadata", //< Also supports any other metadata (not listed in infos/metadata) +"directory/value", //< Supports non-leaf keys with value +"directory/holes", //< Support for holes within the hierarchy (not every directory needs to be present) +"type", //< Support for Elektra's types +"array", //< Support for arrays +"format/array", //< Has a specific serialization format for arrays (i.e. not #0=value) +"format/hierarchy", //< Has a specific serialization format for hierarchy (i.e. not dir/key=value) +"format/type", //< Has a specific serialization format for various types (i.e. not bool="0") +"format/human/read", //< The format is intended to be read by humans. +"format/human/write", //< The format is intended to be written by humans. diff --git a/src/libs/tools/src/plugindatabase.cpp b/src/libs/tools/src/plugindatabase.cpp index 33796a16fc1..40baa6fddbb 100644 --- a/src/libs/tools/src/plugindatabase.cpp +++ b/src/libs/tools/src/plugindatabase.cpp @@ -140,43 +140,8 @@ bool hasProvides (PluginDatabase const & pd, std::string which) } // namespace -// TODO: directly use data from CONTRACT.ini const std::map PluginDatabase::statusMap = { - // clang-format off - {"default", 64000}, - {"recommended", 32000}, - {"productive", 8000}, - {"maintained", 4000}, - {"reviewed", 4000}, - {"conformant", 2000}, - {"compatible", 2000}, - {"coverage", 2000}, - {"specific", 1000}, - - {"unittest", 1000}, - {"shelltest", 1000}, - {"tested", 500}, - {"nodep", 250}, - {"libc", 250}, - {"configurable", 50}, - {"final", 50}, - {"global", 1}, - {"readonly", 0}, - {"writeonly", 0}, - {"preview", -50}, - {"memleak", -250}, - {"experimental", -500}, - {"difficult", -500}, - {"limited", -750}, - {"unfinished", -1000}, - {"old", -1000}, - {"nodoc", -1000}, - {"concept", -2000}, - {"orphan", -4000}, - {"obsolete", -4000}, - {"discouraged", -32000}, - - // clang-format on +#include };