Skip to content

Commit

Permalink
Register data per application and allow arbitrary registration
Browse files Browse the repository at this point in the history
  • Loading branch information
loganharbour committed Nov 26, 2024
1 parent 9446d5f commit a6f1f0d
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 41 deletions.
9 changes: 7 additions & 2 deletions framework/doc/content/source/interfaces/DataFileInterface.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ If the provided path is absolute, no searching will take place and the absolute
path will be used. Otherwise, `getDataFileName` will search (in this order)

- relative to the input file
- relative to the running binary in the shared directory (assuming the application is installed)
- relative to all registered data file directories (which are determined by the source file locations when compiling and registered using the `registerDataFilePath` macro in `Registry.h`)
- relative to all installed and registered data file directories (for an installed application)
- relative to all in-tree registered data file directories (for an in-tree build)

The "registered" data file directories are directories that are registered via:

- the `registerAppDataFilePath` macro in `Registry.h`, where an applications data in its root `data` directory is registered
- the `registerDataFilePath` macro in `Registry.h`, where a general data directory is registered

## `getDataFileNameByName`

Expand Down
31 changes: 26 additions & 5 deletions framework/include/base/Registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@
#define registerADMooseObjectRenamed(app, orig_class, time, new_class) \
registerMooseObjectRenamed(app, orig_class, time, new_class)

#define registerDataFilePath() Registry::addDataFilePath(__FILE__)
/// register a data file path (folder name must be data)
#define registerDataFilePath(name, path) Registry::addDataFilePath(app, path)
/// register a data file path for the given application name. uses the current file to register
/// ../../data as a path
#define registerAppDataFilePath(app) Registry::addAppDataFilePath(app, __FILE__)

#define registerRepository(repo_name, repo_url) Registry::addRepository(repo_name, repo_url);

Expand Down Expand Up @@ -198,8 +202,11 @@ class Registry
/// addKnownLabel whitelists a label as valid for purposes of the checkLabels function.
static char addKnownLabel(const std::string & label);

/// register search paths for built-in data files
static void addDataFilePath(const std::string & path);
/// register general search paths (folder name must be data)
static void addDataFilePath(const std::string & name, const std::string & path);
/// register search paths for an application (path determined relative to app_path);
/// app_path should be passed as __FILE__ from the application source file
static void addAppDataFilePath(const std::string & app_name, const std::string & app_path);

/// register a repository
static void addRepository(const std::string & repo_name, const std::string & repo_url);
Expand All @@ -226,11 +233,24 @@ class Registry
}

/// Returns a vector of all registered data file paths
static const std::vector<std::string> & getDataFilePaths()
static const std::map<std::string, std::string> & getDataFilePaths()
{
return getRegistry()._data_file_paths;
}

/**
* Attempt to get a data path for the registered name.
*
* Searches the installed path and the in-tree path.
*/
static std::optional<std::string> queryDataPath(const std::string & name);
/**
* Gets a data path for the registered name.
*
* Same as queryDataPath(), but errors if one is not found.
*/
static std::string getDataPath(const std::string & name);

/// Returns the repository URL associated with \p repo_name
static const std::string & getRepositoryURL(const std::string & repo_name);

Expand All @@ -253,7 +273,8 @@ class Registry
std::map<std::string, std::vector<std::shared_ptr<RegistryEntryBase>>> _per_label_objects;
std::map<std::string, std::vector<std::shared_ptr<RegistryEntryBase>>> _per_label_actions;
std::set<std::string> _known_labels;
std::vector<std::string> _data_file_paths;
/// Data file registry; name -> in-tree path
std::map<std::string, std::string> _data_file_paths;
/// Repository name -> repository URL; used for mooseDocumentedError
std::map<std::string, std::string> _repos;
std::map<std::string, std::string> _type_to_classname;
Expand Down
2 changes: 1 addition & 1 deletion framework/src/base/Moose.C
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ registerAll(Factory & f, ActionFactory & af, Syntax & s)
registerObjects(f, {"MooseApp"});
associateSyntaxInner(s, af);
registerActions(s, af, {"MooseApp"});
registerDataFilePath();
registerAppDataFilePath("MooseApp");
registerRepository("moose", "github.com/idaholab/moose");
}

Expand Down
69 changes: 61 additions & 8 deletions framework/src/base/Registry.C
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "libmesh/libmesh_common.h"

#include <memory>
#include <filesystem>

Registry &
Registry::getRegistry()
Expand Down Expand Up @@ -86,21 +87,73 @@ Registry::addKnownLabel(const std::string & label)
}

void
Registry::addDataFilePath(const std::string & fullpath)
Registry::addDataFilePath(const std::string & name, const std::string & path)
{
mooseAssert(std::filesystem::path(path).parent_path().filename() == "data", "Must end with data");

const std::string abs_path = std::filesystem::canonical(path).c_str();
if (!MooseUtils::pathIsDirectory(abs_path))
mooseError("While registering data file path '",
abs_path,
"' for '",
name,
"': the path was not found");

auto & dfp = getRegistry()._data_file_paths;
const auto it = dfp.find(name);
// Not registered yet
if (it == dfp.end())
dfp.emplace(name, abs_path);
// Registered, but with a different value
else if (it->second != abs_path)
mooseError("While registering data file path '",
abs_path,
"' for ",
name,
", the path '",
it->second,
"' is already registered");
}

void
Registry::addAppDataFilePath(const std::string & app_name, const std::string & app_path)
{
// split the *App.C filename from its containing directory
const auto path = MooseUtils::splitFileName(fullpath).first;

const auto dir = MooseUtils::splitFileName(app_path).first;
// This works for both build/unity_src/ and src/base/ as the *App.C file location,
// in case __FILE__ doesn't get overriden in unity build
const auto data_dir = MooseUtils::pathjoin(path, "../../data");
addDataFilePath(app_name, MooseUtils::pathjoin(dir, "../../data"));
}

std::optional<std::string>
Registry::queryDataPath(const std::string & name)
{
const auto & dfps = getRegistry()._data_file_paths;
const auto it = dfps.find(name);
if (it == dfps.end())
mooseError("Registry::getDataPath(): A data path for '", name, "' is not registered");

// Installed data
const auto installed_path =
MooseUtils::pathjoin(Moose::getExecutablePath(), "..", "share", name, "data");
if (MooseUtils::checkFileReadable(installed_path, false, false, false))
return std::filesystem::canonical(installed_path).c_str();

// In tree data
if (MooseUtils::checkFileReadable(it->second, false, false, false))
return std::filesystem::canonical(it->second).c_str();

// No success
return {};
}

// if the data directory exists and hasn't been added before, add it
if (MooseUtils::pathIsDirectory(data_dir) &&
std::find(dfp.begin(), dfp.end(), data_dir) == dfp.end())
dfp.push_back(data_dir);
std::string
Registry::getDataPath(const std::string & name)
{
const auto path = queryDataPath(name);
if (!path)
mooseError("Failed to determine data path for '", name, "'");
return *path;
}

void
Expand Down
34 changes: 10 additions & 24 deletions framework/src/interfaces/DataFileInterface.C
Original file line number Diff line number Diff line change
Expand Up @@ -48,40 +48,26 @@ std::string
DataFileInterface::getDataFileNameByName(const std::string & relative_path,
const std::string * param) const
{
/// - relative to the running binary (assuming the application is installed)
const auto share_dir = MooseUtils::pathjoin(Moose::getExecutablePath(), "..", "share");
if (MooseUtils::pathIsDirectory(share_dir))
// Search each registered data path for the relative path
for (const auto & name_dir_path : Registry::getRegistry().getDataFilePaths())
{
const auto dirs = MooseUtils::listDir(share_dir, false);
for (const auto & data_dir : dirs)
const auto & name = name_dir_path.first;
const auto data_path = Registry::getRegistry().queryDataPath(name);
if (data_path)
{
const auto path = MooseUtils::pathjoin(data_dir, "data", relative_path);
const auto path = MooseUtils::pathjoin(*data_path, relative_path);
if (MooseUtils::checkFileReadable(path, false, false, false))
{
const std::string abs_path = std::filesystem::canonical(path).c_str();
if (param)
_parent.paramInfo(
*param, "Data file '", path, "' found in an installed app distribution.");
_parent.paramInfo(*param, "Data file '", abs_path, "' found from ", name);
else
mooseInfo("Data file '", path, "' found in an installed app distribution.");
return path;
mooseInfo("Data file '", abs_path, "' found from ", name);
return abs_path;
}
}
}

/// - relative to all registered data file directories
for (const auto & data_dir : Registry::getRegistry().getDataFilePaths())
{
const auto path = MooseUtils::pathjoin(data_dir, relative_path);
if (MooseUtils::checkFileReadable(path, false, false, false))
{
if (param)
_parent.paramInfo(*param, "Data file '", path, "' found in a source repository.");
else
mooseInfo("Data file '", path, "' found in a source repository.");
return path;
}
}

mooseException(param ? _parent.parameters().inputLocation(*param) : _parent.name(),
": Unable to find data file '",
relative_path,
Expand Down
2 changes: 1 addition & 1 deletion modules/solid_mechanics/src/base/SolidMechanicsApp.C
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ SolidMechanicsApp::registerAll(Factory & f, ActionFactory & af, Syntax & s)
Registry::registerObjectsTo(f, {"SolidMechanicsApp"});
Registry::registerActionsTo(af, {"SolidMechanicsApp"});
associateSyntaxInner(s, af);
registerDataFilePath();
registerAppDataFilePath("SolidMechanicsApp");
}

void
Expand Down

0 comments on commit a6f1f0d

Please sign in to comment.