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 :
16 : #include "libmesh/libmesh_common.h"
17 :
18 : #include <memory>
19 : #include <filesystem>
20 : #include <regex>
21 :
22 : Registry &
23 176893313 : Registry::getRegistry()
24 : {
25 : // We need a naked new here (_not_ a smart pointer or object instance) due to what seems like a
26 : // bug in clang's static object destruction when using dynamic library loading.
27 : static Registry * registry_singleton = nullptr;
28 176893313 : if (!registry_singleton)
29 51208 : registry_singleton = new Registry();
30 176893313 : return *registry_singleton;
31 : }
32 :
33 : void
34 125519 : Registry::registerObjectsTo(Factory & f, const std::set<std::string> & labels)
35 : {
36 125519 : auto & r = getRegistry();
37 :
38 251038 : for (const auto & label : labels)
39 : {
40 125519 : r._known_labels.insert(label);
41 125519 : if (r._per_label_objects.count(label) == 0)
42 5 : continue;
43 :
44 93713890 : for (const auto & obj : r._per_label_objects[label])
45 : {
46 93588376 : const auto name = obj->name();
47 93588376 : r._name_to_entry[name] = obj;
48 :
49 93588376 : f.reg(obj);
50 93588376 : if (!obj->_alias.empty())
51 4204397 : f.associateNameToClass(name, obj->_classname);
52 93588376 : }
53 : }
54 125519 : }
55 :
56 : const RegistryEntryBase &
57 0 : Registry::objData(const std::string & name)
58 : {
59 0 : auto & r = getRegistry();
60 :
61 0 : if (const auto it = r._name_to_entry.find(name); it != r._name_to_entry.end())
62 0 : return *it->second;
63 : else
64 0 : mooseError("Object ", name, " is not registered yet");
65 : }
66 :
67 : void
68 125330 : Registry::registerActionsTo(ActionFactory & f, const std::set<std::string> & labels)
69 : {
70 125330 : auto & r = getRegistry();
71 :
72 250660 : for (const auto & label : labels)
73 : {
74 125330 : r._known_labels.insert(label);
75 125330 : if (r._per_label_actions.count(label) == 0)
76 17 : continue;
77 :
78 13222837 : for (const auto & obj : r._per_label_actions[label])
79 13097524 : f.reg(obj);
80 : }
81 125330 : }
82 :
83 : char
84 62823 : Registry::addKnownLabel(const std::string & label)
85 : {
86 62823 : getRegistry()._known_labels.insert(label);
87 62823 : return 0;
88 : }
89 :
90 : void
91 62786 : Registry::addDataFilePath(const std::string & name, const std::string & in_tree_path)
92 : {
93 62786 : if (!std::regex_search(name, std::regex("\\w+")))
94 1 : mooseError("Unallowed characters in '", name, "'");
95 :
96 : // Enforce that the folder is called "data", because we rely on the installed path
97 : // to be within PREFIX/share/<name>/data (see determineDataFilePath())
98 62785 : const std::string folder = std::filesystem::path(in_tree_path).filename().c_str();
99 62785 : if (folder != "data")
100 1 : mooseError("While registering data file path '",
101 : in_tree_path,
102 : "' for '",
103 : name,
104 : "': The folder must be named 'data' and it is named '",
105 : folder,
106 : "'");
107 :
108 : // Find either the installed or in-tree path
109 62784 : const auto path = determineDataFilePath(name, in_tree_path);
110 :
111 62784 : auto & dfp = getRegistry()._data_file_paths;
112 62784 : const auto it = dfp.find(name);
113 : // Not registered yet
114 62784 : if (it == dfp.end())
115 51201 : dfp.emplace(name, path);
116 : // Registered, but with a different value
117 11583 : else if (it->second != path)
118 1 : mooseError("While registering data file path '",
119 : path,
120 : "' for '",
121 : name,
122 : "': the path '",
123 1 : it->second,
124 : "' is already registered");
125 62786 : }
126 :
127 : void
128 62758 : Registry::addAppDataFilePath(const std::string & app_name, const std::string & app_path)
129 : {
130 : // split the *App.C filename from its containing directory
131 62758 : const auto dir = MooseUtils::splitFileName(app_path).first;
132 : // This works for both build/unity_src/ and src/base/ as the *App.C file location,
133 : // in case __FILE__ doesn't get overriden in unity build
134 62758 : addDataFilePath(app_name, MooseUtils::pathjoin(dir, "../../data"));
135 62758 : }
136 :
137 : void
138 1 : Registry::addDeprecatedAppDataFilePath(const std::string & app_path)
139 : {
140 1 : const auto app_name = appNameFromAppPath(app_path);
141 1 : mooseDeprecated("In ",
142 : app_path,
143 : ":\nregisterDataFilePath() is deprecated. Use registerAppDataFilePath(\"",
144 : app_name,
145 : "\") instead.");
146 1 : addAppDataFilePath(app_name, app_path);
147 1 : }
148 :
149 : std::string
150 4 : Registry::getDataFilePath(const std::string & name)
151 : {
152 4 : const auto & dfps = getRegistry()._data_file_paths;
153 4 : const auto it = dfps.find(name);
154 4 : if (it == dfps.end())
155 1 : mooseError("Registry::getDataFilePath(): A data file path for '", name, "' is not registered");
156 6 : return it->second;
157 : }
158 :
159 : void
160 62756 : Registry::addRepository(const std::string & repo_name, const std::string & repo_url)
161 : {
162 62756 : auto & repos = getRegistry()._repos;
163 62756 : const auto [it, inserted] = repos.emplace(repo_name, repo_url);
164 62756 : if (!inserted && it->second != repo_url)
165 1 : mooseError("Registry::registerRepository(): The repository '",
166 : repo_name,
167 : "' is already registered with a different URL '",
168 1 : it->second,
169 : "'.");
170 62755 : }
171 :
172 : const std::string &
173 8 : Registry::getRepositoryURL(const std::string & repo_name)
174 : {
175 8 : const auto & repos = getRegistry()._repos;
176 8 : if (const auto it = repos.find(repo_name); it != repos.end())
177 7 : return it->second;
178 1 : mooseError("Registry::getRepositoryURL(): The repository '", repo_name, "' is not registered.");
179 : }
180 :
181 : std::string
182 62786 : Registry::determineDataFilePath(const std::string & name, const std::string & in_tree_path)
183 : {
184 : // TODO: Track whether or not the application is installed in a better way
185 : // than this, which will enable us to pick one or the other based on
186 : // the install state. This probably also won't work with dynamic loading, where
187 : // we can't necessarily get this information from the binary (as there could be
188 : // multiple binary paths)
189 :
190 : // Installed data
191 : const auto installed_path =
192 62786 : MooseUtils::pathjoin(Moose::getExecutablePath(), "..", "share", name, "data");
193 62786 : if (MooseUtils::checkFileReadable(installed_path, false, false, false))
194 0 : return MooseUtils::canonicalPath(installed_path);
195 :
196 : // In tree data
197 62786 : if (MooseUtils::checkFileReadable(in_tree_path, false, false, false))
198 62785 : return MooseUtils::canonicalPath(in_tree_path);
199 :
200 1 : mooseError("Failed to determine data file path for '",
201 : name,
202 : "'. Paths searched:\n\n installed: ",
203 : installed_path,
204 : "\n in-tree: ",
205 : in_tree_path);
206 62786 : }
207 :
208 : std::string
209 3 : Registry::appNameFromAppPath(const std::string & app_path)
210 : {
211 : // This is for deprecated use only. It assumes that the application name
212 : // (binary name) in the build follows our normal naming of FooBarApp -> foo_bar.
213 : // We need to convert the application source file to the above, for example:
214 : // /path/to/FooBarBazApp.C -> foo_bar_baz
215 : // Ideally, we would instead have the user specify this manually so that
216 : // there is no ambiguity.
217 3 : std::smatch match;
218 3 : if (std::regex_search(app_path, match, std::regex("\\/([a-zA-Z0-9_]+)App\\.C$")))
219 : {
220 2 : std::string name = match[1]; // FooBarBaz
221 2 : name = std::regex_replace(name, std::regex("(?!^)([A-Z])"), "_$1"); // Foo_Bar_Baz
222 2 : name = MooseUtils::toLower(name); // foo_bar_baz
223 4 : return name;
224 2 : }
225 :
226 1 : mooseError(
227 : "Registry::appNameFromAppPath(): Failed to parse application name from '", app_path, "'");
228 3 : }
|