LCOV - code coverage report
Current view: top level - src/base - Registry.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 110 116 94.8 %
Date: 2026-05-29 20:35:17 Functions: 15 16 93.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "InputParameters.h"
      11             : #include "Registry.h"
      12             : #include "Factory.h"
      13             : #include "ActionFactory.h"
      14             : #include "MooseUtils.h"
      15             : #include "Capabilities.h"
      16             : 
      17             : #include "libmesh/libmesh_common.h"
      18             : 
      19             : #include <memory>
      20             : #include <filesystem>
      21             : #include <regex>
      22             : 
      23             : Registry &
      24   209666113 : Registry::getRegistry()
      25             : {
      26             :   // We need a naked new here (_not_ a smart pointer or object instance) due to what seems like a
      27             :   // bug in clang's static object destruction when using dynamic library loading.
      28             :   static Registry * registry_singleton = nullptr;
      29   209666113 :   if (!registry_singleton)
      30       54389 :     registry_singleton = new Registry();
      31   209666113 :   return *registry_singleton;
      32             : }
      33             : 
      34             : void
      35      133997 : Registry::registerObjectsTo(Factory & f, const std::set<std::string> & labels)
      36             : {
      37      133997 :   auto & r = getRegistry();
      38             : 
      39      267994 :   for (const auto & label : labels)
      40             :   {
      41      133997 :     r._known_labels.insert(label);
      42      133997 :     if (r._per_label_objects.count(label) == 0)
      43          10 :       continue;
      44             : 
      45   112381446 :     for (const auto & obj : r._per_label_objects[label])
      46             :     {
      47   112247459 :       const auto name = obj->name();
      48   112247459 :       r._name_to_entry[name] = obj;
      49             : 
      50   112247459 :       f.reg(obj);
      51   112247459 :       if (!obj->_alias.empty())
      52     4689035 :         f.associateNameToClass(name, obj->_classname);
      53   112247459 :     }
      54             :   }
      55      133997 : }
      56             : 
      57             : const RegistryEntryBase &
      58           0 : Registry::objData(const std::string & name)
      59             : {
      60           0 :   auto & r = getRegistry();
      61             : 
      62           0 :   if (const auto it = r._name_to_entry.find(name); it != r._name_to_entry.end())
      63           0 :     return *it->second;
      64             :   else
      65           0 :     mooseError("Object ", name, " is not registered yet");
      66             : }
      67             : 
      68             : void
      69      133451 : Registry::registerActionsTo(ActionFactory & f, const std::set<std::string> & labels)
      70             : {
      71      133451 :   auto & r = getRegistry();
      72             : 
      73      266902 :   for (const auto & label : labels)
      74             :   {
      75      133451 :     r._known_labels.insert(label);
      76      133451 :     if (r._per_label_actions.count(label) == 0)
      77          17 :       continue;
      78             : 
      79    15008879 :     for (const auto & obj : r._per_label_actions[label])
      80    14875445 :       f.reg(obj);
      81             :   }
      82      133451 : }
      83             : 
      84             : char
      85       67062 : Registry::addKnownLabel(const std::string & label)
      86             : {
      87       67062 :   getRegistry()._known_labels.insert(label);
      88       67062 :   return 0;
      89             : }
      90             : 
      91             : void
      92      133494 : Registry::addDataFilePath(const std::string & name,
      93             :                           const std::string & in_tree_path,
      94             :                           const bool is_app /* = true */,
      95             :                           const std::optional<std::string> & info /* = {} */)
      96             : {
      97      133494 :   checkDataFilePathName(name);
      98             : 
      99             :   // Enforce that the folder is called "data", because we rely on the installed path
     100             :   // to be within PREFIX/share/<name>/data (see determineDataFilePath())
     101      133492 :   if (is_app)
     102             :   {
     103      133490 :     const std::string folder = std::filesystem::path(in_tree_path).filename().c_str();
     104      133490 :     if (folder != "data")
     105           2 :       mooseError("While registering data file path '",
     106             :                  in_tree_path,
     107             :                  "' for '",
     108             :                  name,
     109             :                  "': The folder must be named 'data' and it is named '",
     110             :                  folder,
     111             :                  "'");
     112      133490 :   }
     113             : 
     114             :   // Find either the installed or in-tree path
     115      133490 :   const auto path = determineDataFilePath(name, in_tree_path);
     116             : 
     117      133490 :   auto & dfp = getRegistry()._data_file_paths;
     118      133490 :   const auto it = dfp.find(name);
     119             :   // Not registered yet
     120      133490 :   if (it == dfp.end())
     121             :   {
     122      108756 :     dfp.emplace(name, path);
     123      108756 :     addDataFilePathCapability(name, path, info);
     124             :   }
     125             :   // Registered, but with a different value
     126       24734 :   else if (it->second != path)
     127           2 :     mooseError("While registering data file path '",
     128             :                path,
     129             :                "' for '",
     130             :                name,
     131             :                "': the path '",
     132           2 :                it->second,
     133             :                "' is already registered");
     134      133490 : }
     135             : 
     136             : void
     137           4 : Registry::addMissingDataFilePath(const std::string & name, const std::string & info)
     138             : {
     139           4 :   checkDataFilePathName(name);
     140           2 :   addDataFilePathCapability(name, {}, info);
     141           2 : }
     142             : 
     143             : void
     144      133416 : Registry::addAppDataFilePath(const std::string & app_name, const std::string & app_path)
     145             : {
     146             :   // split the *App.C filename from its containing directory
     147      133416 :   const auto dir = MooseUtils::splitFileName(app_path).first;
     148             :   // This works for both build/unity_src/ and src/base/ as the *App.C file location,
     149             :   // in case __FILE__ doesn't get overriden in unity build
     150      133416 :   addDataFilePath(app_name, MooseUtils::pathjoin(dir, "../../data"));
     151      133416 : }
     152             : 
     153             : void
     154           2 : Registry::addDeprecatedAppDataFilePath(const std::string & app_path)
     155             : {
     156           2 :   const auto app_name = appNameFromAppPath(app_path);
     157           2 :   mooseDeprecated("In ",
     158             :                   app_path,
     159             :                   ":\nregisterDataFilePath() is deprecated. Use registerAppDataFilePath(\"",
     160             :                   app_name,
     161             :                   "\") instead.");
     162           2 :   addAppDataFilePath(app_name, app_path);
     163           2 : }
     164             : 
     165             : std::string
     166           8 : Registry::getDataFilePath(const std::string & name)
     167             : {
     168           8 :   const auto & dfps = getRegistry()._data_file_paths;
     169           8 :   const auto it = dfps.find(name);
     170           8 :   if (it == dfps.end())
     171           2 :     mooseError("Registry::getDataFilePath(): A data file path for '", name, "' is not registered");
     172          12 :   return it->second;
     173             : }
     174             : 
     175             : void
     176       66997 : Registry::addRepository(const std::string & repo_name, const std::string & repo_url)
     177             : {
     178       66997 :   auto & repos = getRegistry()._repos;
     179       66997 :   const auto [it, inserted] = repos.emplace(repo_name, repo_url);
     180       66997 :   if (!inserted && it->second != repo_url)
     181           2 :     mooseError("Registry::registerRepository(): The repository '",
     182             :                repo_name,
     183             :                "' is already registered with a different URL '",
     184           2 :                it->second,
     185             :                "'.");
     186       66995 : }
     187             : 
     188             : const std::string &
     189          11 : Registry::getRepositoryURL(const std::string & repo_name)
     190             : {
     191          11 :   const auto & repos = getRegistry()._repos;
     192          11 :   if (const auto it = repos.find(repo_name); it != repos.end())
     193           9 :     return it->second;
     194           2 :   mooseError("Registry::getRepositoryURL(): The repository '", repo_name, "' is not registered.");
     195             : }
     196             : 
     197             : std::string
     198      133494 : Registry::determineDataFilePath(const std::string & name, const std::string & in_tree_path)
     199             : {
     200             :   // TODO: Track whether or not the application is installed in a better way
     201             :   // than this, which will enable us to pick one or the other based on
     202             :   // the install state. This probably also won't work with dynamic loading, where
     203             :   // we can't necessarily get this information from the binary (as there could be
     204             :   // multiple binary paths)
     205             : 
     206             :   // Installed data
     207             :   const auto installed_path =
     208      133494 :       MooseUtils::pathjoin(Moose::getExecutablePath(), "..", "share", name, "data");
     209      133494 :   if (MooseUtils::checkFileReadable(installed_path, false, false, false))
     210           0 :     return MooseUtils::canonicalPath(installed_path);
     211             : 
     212             :   // In tree data
     213      133494 :   if (MooseUtils::checkFileReadable(in_tree_path, false, false, false))
     214      133492 :     return MooseUtils::canonicalPath(in_tree_path);
     215             : 
     216           2 :   mooseError("Failed to determine data file path for '",
     217             :              name,
     218             :              "'. Paths searched:\n\n  installed: ",
     219             :              installed_path,
     220             :              "\n  in-tree: ",
     221             :              in_tree_path);
     222      133494 : }
     223             : 
     224             : std::string
     225           6 : Registry::appNameFromAppPath(const std::string & app_path)
     226             : {
     227             :   // This is for deprecated use only. It assumes that the application name
     228             :   // (binary name) in the build follows our normal naming of FooBarApp -> foo_bar.
     229             :   // We need to convert the application source file to the above, for example:
     230             :   //   /path/to/FooBarBazApp.C -> foo_bar_baz
     231             :   // Ideally, we would instead have the user specify this manually so that
     232             :   // there is no ambiguity.
     233           6 :   std::smatch match;
     234           6 :   if (std::regex_search(app_path, match, std::regex("\\/([a-zA-Z0-9_]+)App\\.C$")))
     235             :   {
     236           4 :     std::string name = match[1];                                        // FooBarBaz
     237           4 :     name = std::regex_replace(name, std::regex("(?!^)([A-Z])"), "_$1"); // Foo_Bar_Baz
     238           4 :     name = MooseUtils::toLower(name);                                   // foo_bar_baz
     239           8 :     return name;
     240           4 :   }
     241             : 
     242           2 :   mooseError(
     243             :       "Registry::appNameFromAppPath(): Failed to parse application name from '", app_path, "'");
     244           6 : }
     245             : 
     246             : void
     247      133498 : Registry::checkDataFilePathName(const std::string & name)
     248             : {
     249      133498 :   if (!std::regex_search(name, std::regex("[a-z0-9_]+")))
     250           4 :     mooseError("Unallowed characters in data file path name '",
     251             :                name,
     252             :                "'; allowed characters = a-z, 0-9, _");
     253      133494 : }
     254             : 
     255             : void
     256      108758 : Registry::addDataFilePathCapability(const std::string & name,
     257             :                                     const std::optional<std::string> & path /* = {} */,
     258             :                                     const std::optional<std::string> & extra_info /* = {}*/)
     259             : {
     260      108758 :   std::string doc = "Named data path '" + name + "' is ";
     261      108758 :   if (path)
     262      108756 :     doc += "available at '" + *path + "'";
     263             :   else
     264           2 :     doc += "not available";
     265      108758 :   if (extra_info)
     266           4 :     doc += "; " + *extra_info;
     267      108758 :   doc += ".";
     268             : 
     269      108758 :   auto & capabilities = Moose::internal::Capabilities::getCapabilities({});
     270      108758 :   capabilities.add("data_" + name, bool(path), doc);
     271      108758 : }

Generated by: LCOV version 1.14