LCOV - code coverage report
Current view: top level - src/plugins/yamlcpp - read.cpp (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 60 65 92.3 %
Date: 2019-09-12 12:28:41 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Read key sets using yaml-cpp
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #include "read.hpp"
      10             : #include "yaml-cpp/yaml.h"
      11             : 
      12             : #include <kdb.hpp>
      13             : #include <kdblogger.h>
      14             : #include <kdbplugin.h>
      15             : 
      16             : #include <sstream>
      17             : 
      18             : using namespace std;
      19             : using namespace kdb;
      20             : 
      21             : namespace
      22             : {
      23             : /**
      24             :  * @brief This function converts a given number to an array base name.
      25             :  *
      26             :  * @param index This number specifies the index of the array entry.
      27             :  *
      28             :  * @return A string representing the given indices as Elektra array name.
      29             :  */
      30         273 : string indexToArrayBaseName (uintmax_t const index)
      31             : {
      32         273 :         size_t digits = 1;
      33             : 
      34         284 :         for (uintmax_t value = index; value > 9; digits++)
      35             :         {
      36          11 :                 value /= 10;
      37             :         }
      38             : 
      39        1911 :         return "#" + string (digits - 1, '_') + to_string (index);
      40             : }
      41             : 
      42             : /**
      43             :  * @brief This function creates a new key from the given parameters.
      44             :  *
      45             :  * @param name This string specifies the postfix of the name of the key produced by this function.
      46             :  * @param parent This key specifies the prefix of the name of the key produced by this function.
      47             :  *
      48             :  * @returns The function returns a new key that combines the name of the parent key and `name`.
      49             :  */
      50         396 : Key newKey (string const & name, Key const & parent)
      51             : {
      52             :         ELEKTRA_LOG_DEBUG ("Add new key with base name “%s”", name.c_str ());
      53             : 
      54         792 :         Key key{ parent.getFullName (), KEY_BINARY, KEY_END };
      55         396 :         key.addBaseName (name);
      56             : 
      57         396 :         return key;
      58             : }
      59             : 
      60             : /**
      61             :  * @brief This function creates a new array key from the given parameters.
      62             :  *
      63             :  * @param arrayKey This argument specifies the key that represents the root of the array.
      64             :  * @param index This parameter specifies the index of the array key this function creates.
      65             :  *
      66             :  * @returns The function returns a new key that is part of the array represented by `arrayKey`.
      67             :  */
      68         273 : Key newArrayKey (Key & arrayKey, uintmax_t const index)
      69             : {
      70             :         ELEKTRA_LOG_DEBUG ("Add new array element to array parent “%s”", arrayKey.getName ().c_str ());
      71             : 
      72         546 :         Key newKey{ arrayKey.getName (), KEY_BINARY, KEY_END };
      73         546 :         newKey.addBaseName (indexToArrayBaseName (index));
      74        1365 :         arrayKey.setMeta ("array", newKey.getBaseName ());
      75             : 
      76         273 :         return newKey;
      77             : }
      78             : 
      79             : /**
      80             :  * @brief Add metadata saved in a YAML map to the specified key
      81             :  *
      82             :  * @param key This parameter saves the key to which this function should add the metadata stored in `node`.
      83             :  * @param node This YAML node stores a map containing metadata.
      84             :  */
      85          36 : void addMetadata (Key & key, YAML::Node const & node)
      86             : {
      87         222 :         for (auto & element : node)
      88             :         {
      89          78 :                 auto metakey = element.first.as<string> ();
      90         117 :                 auto metavalue = element.second.IsNull () ? "" : element.second.as<string> ();
      91             :                 ELEKTRA_LOG_DEBUG ("Add metakey “%s: %s”", metakey.c_str (), metavalue.c_str ());
      92          78 :                 key.setMeta (metakey, metavalue);
      93             :         }
      94          36 : }
      95             : 
      96             : /**
      97             :  * @brief Create a key containing a (possibly empty) value.
      98             :  *
      99             :  * @param node This YAML node stores the data that should be converted to a new `Key`.
     100             :  * @param name This text specifies the name of the key this function creates.
     101             :  *
     102             :  * @return A new key containing the data specified in `node`
     103             :  */
     104         435 : Key createLeafKey (YAML::Node const & node, string const & name)
     105             : {
     106         870 :         Key key{ name, KEY_BINARY, KEY_END };
     107         435 :         if (!node.IsNull ())
     108             :         {
     109         692 :                 auto value = node.as<string> ();
     110         686 :                 if (value == "true" || value == "false")
     111             :                 {
     112             :                         try
     113             :                         {
     114           8 :                                 key.set<bool> (node.as<bool> ());
     115             :                         }
     116           0 :                         catch (YAML::BadConversion const &)
     117             :                         {
     118           0 :                                 key.set<string> (value); // Save value as string, if `node` is a quoted scalar
     119             :                         }
     120             :                 }
     121             :                 else
     122             :                 {
     123         676 :                         key.set<string> (value);
     124             :                 }
     125             :         }
     126         870 :         if (node.Tag () == "tag:yaml.org,2002:binary")
     127             :         {
     128             :                 ELEKTRA_LOG_DEBUG ("Set metadata type of key to binary");
     129          20 :                 key.setMeta ("type", "binary");
     130             :         }
     131             :         ELEKTRA_LOG_DEBUG ("Add key “%s: %s”", key.getName ().c_str (),
     132             :                            key.getBinarySize () == 0 ? "NULL" : key.isBinary () ? "binary value!" : key.get<string> ().c_str ());
     133         435 :         return key;
     134             : }
     135             : 
     136             : /**
     137             :  * @brief Convert the key value of a YAML meta node to a key
     138             :  *
     139             :  * @param node This YAML meta node stores the data this function stores in the returned key
     140             :  * @param parent This key stores the prefix for the key name
     141             :  *
     142             :  * @return A key representing the key value stored in `node`
     143             :  */
     144          36 : Key convertMetaNodeToKey (YAML::Node const & node, Key & parent)
     145             : {
     146         160 :         auto key = node[0].IsNull () ? Key{ parent.getFullName (), KEY_BINARY, KEY_END } :
     147         156 :                                        Key{ parent.getFullName (), KEY_VALUE, node[0].as<string> ().c_str (), KEY_END };
     148             :         ELEKTRA_LOG_DEBUG ("Add key “%s”: “%s”", key.getName ().c_str (),
     149             :                            key.getBinarySize () == 0 ? "NULL" : key.isString () ? key.getString ().c_str () : "binary value!");
     150          36 :         return key;
     151             : }
     152             : 
     153             : /**
     154             :  * @brief Convert a YAML node to a key set
     155             :  *
     156             :  * @param node This YAML node stores the data that should be added to the keyset `mappings`
     157             :  * @param mappings The key set where the YAML data will be stored
     158             :  * @param parent This key stores the prefix for the key name
     159             :  */
     160         812 : void convertNodeToKeySet (YAML::Node const & node, KeySet & mappings, Key & parent)
     161             : {
     162        1624 :         if (node.Tag () == "!elektra/meta")
     163             :         {
     164          72 :                 auto key = convertMetaNodeToKey (node, parent);
     165          36 :                 mappings.append (key);
     166          72 :                 addMetadata (key, node[1]);
     167             :         }
     168        1206 :         else if (node.IsScalar () || node.IsNull ())
     169             :         {
     170        1305 :                 auto key = createLeafKey (node, parent.getFullName ());
     171         435 :                 mappings.append (key);
     172             :         }
     173         341 :         else if (node.IsMap ())
     174             :         {
     175        1796 :                 for (auto element : node)
     176             :                 {
     177        1188 :                         Key key = newKey (element.first.as<string> (), parent);
     178         396 :                         convertNodeToKeySet (element.second, mappings, key);
     179             :                 }
     180             :         }
     181          90 :         else if (node.IsSequence ())
     182             :         {
     183          90 :                 uintmax_t index = 0;
     184          90 :                 uintmax_t lastIndex = 0;
     185         906 :                 for (auto element : node)
     186             :                 {
     187         273 :                         if (lastIndex == UINTMAX_MAX)
     188             :                         {
     189           0 :                                 Key key = newArrayKey (parent, lastIndex);
     190           0 :                                 throw std::overflow_error ("Unable to add element after “" + key.getName () + "”" + "in array “" +
     191           0 :                                                            parent.getName () + "”");
     192             :                         }
     193         546 :                         Key key = newArrayKey (parent, index);
     194         273 :                         mappings.append (parent); // Update array metadata
     195         273 :                         convertNodeToKeySet (element, mappings, key);
     196         273 :                         lastIndex = index++;
     197             :                 }
     198             :         }
     199         812 : }
     200             : } // end namespace
     201             : 
     202             : /**
     203             :  * @brief Read a YAML file and add the resulting data to a given key set
     204             :  *
     205             :  * @param mappings The key set where the YAML data will be stored
     206             :  * @param parent This key stores the path to the YAML data file that should be read
     207             :  */
     208         145 : void yamlcpp::yamlRead (KeySet & mappings, Key & parent)
     209             : {
     210         433 :         YAML::Node config = YAML::LoadFile (parent.getString ());
     211             : 
     212             :         ELEKTRA_LOG_DEBUG ("Read file “%s”", parent.getString ().c_str ());
     213             : 
     214             : #ifdef HAVE_LOGGER
     215             :         ostringstream data;
     216             :         data << config;
     217             : 
     218             :         ELEKTRA_LOG_DEBUG ("Read Data:");
     219             :         ELEKTRA_LOG_DEBUG ("——————————");
     220             : 
     221             :         istringstream stream (data.str ());
     222             :         for (string line; std::getline (stream, line);)
     223             :         {
     224             :                 ELEKTRA_LOG_DEBUG ("%s", line.c_str ());
     225             :         }
     226             : 
     227             :         ELEKTRA_LOG_DEBUG ("——————————");
     228             : #endif
     229             : 
     230         143 :         convertNodeToKeySet (config, mappings, parent);
     231             :         ELEKTRA_LOG_DEBUG ("Added %zd key%s", mappings.size (), mappings.size () == 1 ? "" : "s");
     232         143 : }

Generated by: LCOV version 1.13