Changeset 85:8938c2bb579a in finroc_plugins_parameters


Ignore:
Timestamp:
21.03.2020 16:20:12 (12 months ago)
Author:
Max Reichardt <mreichardt@…>
Branch:
17.03
Children:
86:b177bc25e9c4, 87:495d52531f18
Phase:
public
Message:

Adds concept of explicitly overriding values in config files: values and nodes can be marked with 'override="true"'. This will remove warnings w.r.t. multiple entries with the same name - and select the last entry marked with 'override'.

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • tConfigFile.cpp

    r81 r85  
    7575/*! Leaf name in XML */ 
    7676static const std::string cXML_LEAF_NAME("value"); 
     77 
     78/*! Override attribute name in config files */ 
     79static const std::string cXML_OVERRIDE_ATTRIBUTE_NAME("override"); 
     80 
    7781#endif 
    7882 
     
    159163} 
    160164 
    161  
    162 #endif 
    163  
    164 } 
    165  
    166 tConfigFile::tConfigFile() : 
    167 #ifdef _LIB_RRLIB_XML_PRESENT_ 
    168   wrapped(), 
    169 #endif 
    170   filename(), 
    171   active(true) 
    172 { 
    173 #ifdef _LIB_RRLIB_XML_PRESENT_ 
    174   wrapped.AddRootNode(cXML_BRANCH_NAME); 
    175 #endif 
    176 } 
    177  
    178 tConfigFile::tConfigFile(const std::string& filename, bool optional) : 
    179 #ifdef _LIB_RRLIB_XML_PRESENT_ 
    180   wrapped(), 
    181 #endif 
    182   filename(filename), 
    183   active(true) 
    184 { 
    185 #ifdef _LIB_RRLIB_XML_PRESENT_ 
    186   if (core::FinrocFileExists(filename)) 
    187   { 
    188     try 
    189     { 
    190       wrapped = LoadConfigFile(filename); 
    191       return; 
    192     } 
    193     catch (const std::exception& e) 
    194     { 
    195       FINROC_LOG_PRINT(ERROR, e); 
    196     } 
    197   } 
    198   else if (!optional) 
    199   { 
    200     FINROC_LOG_PRINT(WARNING, "Specified config file not found: ", filename); 
    201   } 
    202   wrapped = rrlib::xml::tDocument(); 
    203   wrapped.AddRootNode(cXML_BRANCH_NAME); 
    204 #endif 
    205 } 
    206  
    207 void tConfigFile::Append(const std::string& filename) 
    208 { 
    209 #ifdef _LIB_RRLIB_XML_PRESENT_ 
    210   if (core::FinrocFileExists(filename)) 
    211   { 
    212     // merge entries into first document 
    213     auto document = LoadConfigFile(filename); 
    214     auto& root_node = document.RootNode(); 
    215     for (auto it = root_node.ChildrenBegin(); it != root_node.ChildrenEnd(); ++it) 
    216     { 
    217       this->wrapped.RootNode().AddChildNode(*it, true); // not using copy resulted in erroneous behavior 
    218     } 
    219   } 
    220   else 
    221   { 
    222     throw std::runtime_error("Specified config file not found: " + filename); 
    223   } 
    224 #endif 
    225 } 
    226  
    227 #ifdef _LIB_RRLIB_XML_PRESENT_ 
    228 rrlib::xml::tNode& tConfigFile::CreateEntry(const std::string& entry, bool leaf) 
    229 { 
    230   if (!leaf) 
    231   { 
    232     std::vector<rrlib::xml::tNode*> result; 
    233     GetEntryImplementation(result, entry, wrapped.RootNode(), 0); 
    234     if (result.size() > 0) 
    235     { 
    236       // do we want to warn if node is a leaf node? - I currently do not think so 
    237       return *result[0]; 
    238     } 
    239   } 
    240  
    241   size_t slash_index = entry.rfind('/'); 
    242   tXMLNode& parent = (slash_index == std::string::npos || slash_index == 0) ? wrapped.RootNode() : CreateEntry(entry.substr(0, slash_index), false); 
    243   tXMLNode& created = parent.AddChildNode(leaf ? cXML_LEAF_NAME : cXML_BRANCH_NAME); 
    244   created.SetAttribute("name", (slash_index == std::string::npos) ? entry : entry.substr(slash_index + 1)); 
    245   return created; 
    246 } 
    247 #endif 
    248  
    249 tConfigFile* tConfigFile::Find(const core::tFrameworkElement& element) 
    250 { 
    251   tConfigFile* config_file = element.GetAnnotation<tConfigFile>(); 
    252   if (config_file && config_file->active == true) 
    253   { 
    254     return config_file; 
    255   } 
    256   core::tFrameworkElement* parent = element.GetParent(); 
    257   if (parent) 
    258   { 
    259     return Find(*parent); 
    260   } 
    261   return NULL; 
    262 } 
    263  
    264 #ifdef _LIB_RRLIB_XML_PRESENT_ 
    265 rrlib::xml::tNode& tConfigFile::GetEntry(const std::string& entry, bool create) 
    266 { 
    267   std::vector<rrlib::xml::tNode*> result; 
    268   GetEntryImplementation(result, entry, wrapped.RootNode(), 0); 
    269   if (result.size() > 1) 
    270   { 
    271     FINROC_LOG_PRINT(WARNING, "There are ", result.size(), " entries in config file with the qualified name '", entry, "'. Using the first one."); 
    272   } 
    273  
    274   if (!create) 
    275   { 
    276     if (result.size() == 0) 
    277     { 
    278       throw std::runtime_error("Config node not found: " + entry); 
    279     } 
    280     if (result[0]->Name() != cXML_LEAF_NAME) 
    281     { 
    282       throw std::runtime_error("Config node is no leaf: " + entry); 
    283     } 
    284     return *result[0]; 
    285   } 
    286  
    287   // create node... 
    288   if (result.size() > 0) 
    289   { 
    290     // recreate existing node 
    291     std::string name = result[0]->GetStringAttribute("name"); 
    292     tXMLNode& parent = result[0]->Parent(); 
    293     tXMLNode& new_node = result[0]->AddNextSibling(cXML_LEAF_NAME); 
    294     new_node.SetAttribute("name", name); 
    295     parent.RemoveChildNode(*result[0]); 
    296     return new_node; 
    297   } 
    298   else 
    299   { 
    300     return CreateEntry(entry, true); 
    301   } 
    302 } 
    303  
    304 std::vector<std::string> tConfigFile::GetChildrenNames(const std::string &entry) 
    305 { 
    306   std::vector<rrlib::xml::tNode *> nodes; 
    307   this->GetEntryImplementation(nodes, entry, wrapped.RootNode(), 0); 
    308   if (nodes.size() > 1) 
    309   { 
    310     FINROC_LOG_PRINT(WARNING, "There are ", nodes.size(), " entries in config file with the qualified name '", entry, "'. Using the first one."); 
    311   } 
    312  
    313   if (nodes.size() == 0) 
    314   { 
    315     throw std::runtime_error("Config node not found: " + entry); 
    316   } 
    317   if (nodes[0]->Name() == cXML_LEAF_NAME) 
    318   { 
    319     throw std::runtime_error("Config node is a leaf: " + entry); 
    320   } 
    321  
    322   std::vector<std::string> result; 
    323   for (auto it = nodes.front()->ChildrenBegin(); it != nodes.front()->ChildrenEnd(); ++it) 
    324   { 
    325     result.push_back(it->GetStringAttribute("name")); 
    326   } 
    327   return result; 
    328 } 
    329  
    330  
    331 void tConfigFile::GetEntryImplementation(std::vector<rrlib::xml::tNode*>& result, const std::string& entry, rrlib::xml::tNode& node, size_t entry_string_index) 
     165bool OverrideContext(rrlib::xml::tNode& node, bool in_override_context) 
     166{ 
     167  if (node.HasAttribute(cXML_OVERRIDE_ATTRIBUTE_NAME)) 
     168  { 
     169    return node.GetBoolAttribute(cXML_OVERRIDE_ATTRIBUTE_NAME); 
     170  } 
     171  return in_override_context; 
     172} 
     173 
     174/*! Result of GetEntryImplementation function */ 
     175struct GetEntryImplementationResult 
     176{ 
     177  struct tEntry 
     178  { 
     179    rrlib::xml::tNode* node; 
     180    bool overrides; 
     181  }; 
     182  tEntry first_entry, last_override_entry; 
     183  size_t entry_count = 0, override_entry_count = 0; 
     184}; 
     185 
     186/*! 
     187 * Implementation of GetEntry() - called recursively 
     188 * 
     189 * \param result Object that will contain the result(s) as additional entry/entries after the call 
     190 * \param entry Entry 
     191 * \param node Current node 
     192 * \param entry_string_index Current index in entry string 
     193 * \param override_context Whether override="true" has been set in any parent now 
     194 */ 
     195void GetEntryImplementation(GetEntryImplementationResult& result, const std::string& entry, rrlib::xml::tNode& node, size_t entry_string_index, bool override_context = false) 
    332196{ 
    333197  if (entry_string_index >= entry.length()) 
     
    341205    if (entry_string_index > 0) 
    342206    { 
    343       FINROC_LOG_PRINT(WARNING, "Entry '", entry, "' seems to be not clean (sequential slashes). Skipping one slash now, as this is typically intended. Please fix this!"); 
     207      FINROC_LOG_PRINT_STATIC(WARNING, "Entry '", entry, "' seems to be not clean (sequential slashes). Skipping one slash now, as this is typically intended. Please fix this!"); 
    344208    } 
    345209    entry_string_index++; 
     
    351215    if (child->Name() == cXML_BRANCH_NAME || child->Name() == cXML_LEAF_NAME) 
    352216    { 
     217      std::string name_attribute; 
    353218      try 
    354219      { 
    355         std::string name_attribute = child->GetStringAttribute("name"); 
     220        name_attribute = child->GetStringAttribute("name"); 
     221      } 
     222      catch (const std::exception& e) 
     223      { 
     224        FINROC_LOG_PRINT_STATIC(WARNING, "Encountered tree node without name"); 
     225      } 
     226 
     227      try 
     228      { 
    356229        if (entry.compare(entry_string_index, name_attribute.length(), name_attribute) == 0) // starts_with name attribute? 
    357230        { 
     
    362235            { 
    363236              new_entry_string_index++; 
    364               GetEntryImplementation(result, entry, *child, new_entry_string_index); 
     237              GetEntryImplementation(result, entry, *child, new_entry_string_index, OverrideContext(*child, override_context)); 
    365238            } 
    366239          } 
    367240          else 
    368241          { 
    369             result.push_back(&(*child)); 
     242            // Entry found - include in result 
     243            GetEntryImplementationResult::tEntry new_entry = { &(*child), OverrideContext(*child, override_context) }; 
     244            if (!result.entry_count) 
     245            { 
     246              result.first_entry = new_entry; 
     247              if (new_entry.overrides) 
     248              { 
     249                FINROC_LOG_PRINT_STATIC(WARNING, "First config entry with path '", entry, "' marked 'override', but does not override."); 
     250              } 
     251            } 
     252            if (new_entry.overrides) 
     253            { 
     254              result.last_override_entry = new_entry; 
     255            } 
     256            result.entry_count++; 
     257            result.override_entry_count += (new_entry.overrides ? 1 : 0); 
    370258          } 
    371259        } 
     
    373261      catch (const std::exception& e) 
    374262      { 
    375         FINROC_LOG_PRINT(WARNING, "Encountered tree node without name"); 
    376       } 
    377     } 
    378   } 
    379  
    380   // Okay, we did not find any more 
    381 } 
     263        FINROC_LOG_PRINT_STATIC(ERROR, "Error looking for config entry with path '", entry, "'. Reason: ", e.what()); 
     264      } 
     265    } 
     266  } 
     267} 
     268 
     269rrlib::xml::tNode* ChooseNodeFromResult(GetEntryImplementationResult& result, const std::string& path) 
     270{ 
     271  if (result.entry_count > 1) 
     272  { 
     273    assert(result.entry_count >= result.override_entry_count); 
     274    if (!result.override_entry_count) 
     275    { 
     276      FINROC_LOG_PRINT_STATIC(WARNING, "There are ", result.entry_count, " entries in config file with the path '", path, "'. Using the first one. Hint: Add attribute 'override=\"true\"' to nodes and values if the later entries are intended be used. This will also remove any warning messages."); 
     277    } 
     278    else if (result.entry_count - result.override_entry_count > 1) 
     279    { 
     280      FINROC_LOG_PRINT_STATIC(WARNING, "There are ", result.entry_count, " entries in config file with the path '", path, "'. Only ", result.override_entry_count, " are marked 'override'. Using the last one marked 'override'."); 
     281    } 
     282    return result.override_entry_count ? result.last_override_entry.node : result.first_entry.node; 
     283  } 
     284  return result.entry_count ? result.first_entry.node : nullptr; 
     285} 
     286 
     287#endif 
     288 
     289} 
     290 
     291tConfigFile::tConfigFile() : 
     292#ifdef _LIB_RRLIB_XML_PRESENT_ 
     293  wrapped(), 
     294#endif 
     295  filename(), 
     296  active(true) 
     297{ 
     298#ifdef _LIB_RRLIB_XML_PRESENT_ 
     299  wrapped.AddRootNode(cXML_BRANCH_NAME); 
     300#endif 
     301} 
     302 
     303tConfigFile::tConfigFile(const std::string& filename, bool optional) : 
     304#ifdef _LIB_RRLIB_XML_PRESENT_ 
     305  wrapped(), 
     306#endif 
     307  filename(filename), 
     308  active(true) 
     309{ 
     310#ifdef _LIB_RRLIB_XML_PRESENT_ 
     311  if (core::FinrocFileExists(filename)) 
     312  { 
     313    try 
     314    { 
     315      wrapped = LoadConfigFile(filename); 
     316      return; 
     317    } 
     318    catch (const std::exception& e) 
     319    { 
     320      FINROC_LOG_PRINT(ERROR, e); 
     321    } 
     322  } 
     323  else if (!optional) 
     324  { 
     325    FINROC_LOG_PRINT(WARNING, "Specified config file not found: ", filename); 
     326  } 
     327  wrapped = rrlib::xml::tDocument(); 
     328  wrapped.AddRootNode(cXML_BRANCH_NAME); 
     329#endif 
     330} 
     331 
     332void tConfigFile::Append(const std::string& filename) 
     333{ 
     334#ifdef _LIB_RRLIB_XML_PRESENT_ 
     335  if (core::FinrocFileExists(filename)) 
     336  { 
     337    // merge entries into first document 
     338    auto document = LoadConfigFile(filename); 
     339    auto& root_node = document.RootNode(); 
     340    for (auto it = root_node.ChildrenBegin(); it != root_node.ChildrenEnd(); ++it) 
     341    { 
     342      this->wrapped.RootNode().AddChildNode(*it, true); // not using copy resulted in erroneous behavior 
     343    } 
     344  } 
     345  else 
     346  { 
     347    throw std::runtime_error("Specified config file not found: " + filename); 
     348  } 
     349#endif 
     350} 
     351 
     352#ifdef _LIB_RRLIB_XML_PRESENT_ 
     353rrlib::xml::tNode& tConfigFile::CreateEntry(const std::string& entry, bool leaf) 
     354{ 
     355  if (!leaf) 
     356  { 
     357    GetEntryImplementationResult result; 
     358    GetEntryImplementation(result, entry, wrapped.RootNode(), 0); 
     359    rrlib::xml::tNode* result_node = ChooseNodeFromResult(result, entry); 
     360    if (result_node) 
     361    { 
     362      // do we want to warn if node is a leaf node? - I currently do not think so 
     363      return *result_node; 
     364    } 
     365  } 
     366 
     367  size_t slash_index = entry.rfind('/'); 
     368  tXMLNode& parent = (slash_index == std::string::npos || slash_index == 0) ? wrapped.RootNode() : CreateEntry(entry.substr(0, slash_index), false); 
     369  tXMLNode& created = parent.AddChildNode(leaf ? cXML_LEAF_NAME : cXML_BRANCH_NAME); 
     370  created.SetAttribute("name", (slash_index == std::string::npos) ? entry : entry.substr(slash_index + 1)); 
     371  return created; 
     372} 
     373#endif 
     374 
     375tConfigFile* tConfigFile::Find(const core::tFrameworkElement& element) 
     376{ 
     377  tConfigFile* config_file = element.GetAnnotation<tConfigFile>(); 
     378  if (config_file && config_file->active == true) 
     379  { 
     380    return config_file; 
     381  } 
     382  core::tFrameworkElement* parent = element.GetParent(); 
     383  if (parent) 
     384  { 
     385    return Find(*parent); 
     386  } 
     387  return NULL; 
     388} 
     389 
     390#ifdef _LIB_RRLIB_XML_PRESENT_ 
     391rrlib::xml::tNode& tConfigFile::GetEntry(const std::string& entry, bool create) 
     392{ 
     393  GetEntryImplementationResult result; 
     394  GetEntryImplementation(result, entry, wrapped.RootNode(), 0); 
     395  rrlib::xml::tNode* result_node = ChooseNodeFromResult(result, entry); 
     396 
     397  if (!create) 
     398  { 
     399    if (!result_node) 
     400    { 
     401      throw std::runtime_error("Config node not found: " + entry); 
     402    } 
     403    if (result_node->Name() != cXML_LEAF_NAME) 
     404    { 
     405      throw std::runtime_error("Config node is no leaf: " + entry); 
     406    } 
     407    return *result_node; 
     408  } 
     409 
     410  // create node... 
     411  if (result.entry_count > 0) 
     412  { 
     413    // recreate existing node 
     414    std::string name = result_node->GetStringAttribute("name"); 
     415    tXMLNode& parent = result_node->Parent(); 
     416    tXMLNode& new_node = result_node->AddNextSibling(cXML_LEAF_NAME); 
     417    new_node.SetAttribute("name", name); 
     418    parent.RemoveChildNode(*result_node); 
     419    return new_node; 
     420  } 
     421  else 
     422  { 
     423    return CreateEntry(entry, true); 
     424  } 
     425} 
     426 
     427std::vector<std::string> tConfigFile::GetChildrenNames(const std::string &entry) 
     428{ 
     429  GetEntryImplementationResult result; 
     430  GetEntryImplementation(result, entry, wrapped.RootNode(), 0); 
     431  rrlib::xml::tNode* result_node = ChooseNodeFromResult(result, entry); 
     432 
     433  if (!result_node) 
     434  { 
     435    throw std::runtime_error("Config node not found: " + entry); 
     436  } 
     437  if (result_node->Name() == cXML_LEAF_NAME) 
     438  { 
     439    throw std::runtime_error("Config node is a leaf: " + entry); 
     440  } 
     441 
     442  std::vector<std::string> children_names; 
     443  for (auto it = result_node->ChildrenBegin(); it != result_node->ChildrenEnd(); ++it) 
     444  { 
     445    children_names.push_back(it->GetStringAttribute("name")); 
     446  } 
     447  return children_names; 
     448} 
     449 
    382450#endif 
    383451 
  • tConfigFile.h

    r80 r85  
    206206  /*! (Wrapped) XML document */ 
    207207  rrlib::xml::tDocument wrapped; 
     208 
    208209#endif 
    209210 
     
    221222   */ 
    222223  rrlib::xml::tNode& CreateEntry(const std::string& entry, bool leaf); 
    223  
    224   /*! 
    225    * Implementation of GetEntry() - called recursively 
    226    * 
    227    * \param result List that will contain the result(s) as additional entry/entries after the call 
    228    * \param entry Entry 
    229    * \param node Current node 
    230    * \param entry_string_index Current index in entry string 
    231    */ 
    232   void GetEntryImplementation(std::vector<rrlib::xml::tNode*>& result, const std::string& entry, rrlib::xml::tNode& node, size_t entry_string_index); 
    233224#endif 
    234225 
Note: See TracChangeset for help on using the changeset viewer.