https://mooseframework.inl.gov
DataFileUtils.C
Go to the documentation of this file.
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 "DataFileUtils.h"
11 #include "Moose.h"
12 #include "MooseError.h"
13 #include "MooseUtils.h"
14 #include "Registry.h"
15 
16 #include <filesystem>
17 #include <regex>
18 
19 namespace Moose::DataFileUtils
20 {
22 getPath(std::string path, const std::optional<std::string> & base)
23 {
24  const auto & data_paths = Registry::getRegistry().getDataFilePaths();
25 
26  // Search for "<name>:" prefix which is a data name to limit the search to
27  std::optional<std::string> data_name;
28  std::smatch match;
29  if (std::regex_search(path, match, std::regex("(?:(\\w+):)?(.*)")))
30  {
31  if (match[1].matched)
32  {
33  data_name = match[1];
34  if (!data_paths.count(*data_name))
35  mooseError("Data from '", *data_name, "' is not registered to be searched");
36  }
37  path = match[2];
38  }
39  else
40  mooseError("Failed to parse path '", path, "'");
41 
42  const std::filesystem::path value_path = std::filesystem::path(path);
43 
44  // File is absolute, no need to search
45  if (std::filesystem::path(path).is_absolute())
46  {
47  if (data_name)
48  mooseError("Should not specify an absolute path along with a data name to search (requested "
49  "to search in '",
50  *data_name,
51  "')");
52  if (MooseUtils::checkFileReadable(path, false, false, false))
54  mooseError("The absolute path '", path, "' does not exist or is not readable.");
55  }
56 
57  // Keep track of what was was searched for error context
58  std::map<std::string, std::string> not_found;
59 
60  // Relative to the base, if provided
61  if (base)
62  {
63  const auto relative_to_base = MooseUtils::pathjoin(*base, path);
64  if (MooseUtils::checkFileReadable(relative_to_base, false, false, false))
65  return {MooseUtils::canonicalPath(relative_to_base), Context::RELATIVE};
66  not_found.emplace("working directory", MooseUtils::canonicalPath(*base));
67  }
68 
69  // See if we should skip searching data
70  std::optional<std::string> skip_data_reason;
71  // Path starts with ./ so don't search data
72  if (path.size() > 1 && path.substr(0, 2) == "./")
73  {
74  skip_data_reason = "begins with './'";
75  }
76  else
77  {
78  // Path resolves outside of . so don't search data
79  const std::string proximate = std::filesystem::proximate(path).c_str();
80  if (proximate.size() > 1 && proximate.substr(0, 2) == "..")
81  {
82  skip_data_reason = "resolves behind '.'";
83  }
84  }
85 
86  // Search data if we don't have a reason not to
87  std::map<std::string, std::string> found;
88  if (!skip_data_reason)
89  for (const auto & [name, data_path] : data_paths)
90  {
91  // Explicit search, name doesn't match requested name
92  if (data_name && name != *data_name) // explicit search
93  continue;
94  const auto file_path = MooseUtils::pathjoin(data_path, path);
95  if (MooseUtils::checkFileReadable(file_path, false, false, false))
96  found.emplace(name, MooseUtils::canonicalPath(file_path));
97  else
98  not_found.emplace(name + " data", data_path);
99  }
100 
101  // Found exactly one
102  if (found.size() == 1)
103  {
104  const auto & [name, data_path] = *found.begin();
105  return {MooseUtils::canonicalPath(data_path), Context::DATA, name};
106  }
107 
108  std::stringstream oss;
109  // Found multiple
110  if (found.size() > 1)
111  {
112  oss << "Multiple files were found when searching for the data file '" << path << "':\n\n";
113  for (const auto & [name, data_path] : found)
114  oss << " " << name << ": " << data_path << "\n";
115  const auto & first_name = found.begin()->first;
116  oss << "\nYou can resolve this ambiguity by appending a prefix with the desired data name, for "
117  "example:\n\n "
118  << first_name << ":" << path;
119  }
120  // Found none
121  else
122  {
123  oss << "Unable to find the data file '" << path << "' anywhere.\n";
124  if (not_found.size())
125  {
126  oss << "\nPaths searched:\n";
127  for (const auto & [name, data_path] : not_found)
128  oss << " " << name << ": " << data_path << "\n";
129  }
130  if (skip_data_reason)
131  oss << "\nData path(s) were not searched because search path " << *skip_data_reason << ".\n";
132  }
133 
134  mooseError(oss.str());
135 }
136 
138 getPathExplicit(const std::string & data_name,
139  const std::string & path,
140  const std::optional<std::string> & base)
141 {
142  return getPath(data_name + ":" + path, base);
143 }
144 }
std::string name(const ElemQuality q)
Path getPathExplicit(const std::string &data_name, const std::string &path, const std::optional< std::string > &base=std::optional< std::string >())
Get the data path for a given path, searching the registered data given an explicit data search path...
static Registry & getRegistry()
Get the global Registry singleton.
Definition: Registry.C:23
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
std::string canonicalPath(const std::string &path)
Gets the canonical path of the given path.
Definition: MooseUtils.C:1266
bool checkFileReadable(const std::string &filename, bool check_line_endings=false, bool throw_on_unreadable=true, bool check_for_git_lfs_pointer=true)
Checks to see if a file is readable (exists and permissions)
Definition: MooseUtils.C:250
Representation of a data file path.
Definition: DataFileUtils.h:36
std::filesystem::path pathjoin(const std::filesystem::path &p)
Definition: MooseUtils.C:59
Path getPath(std::string path, const std::optional< std::string > &base=std::optional< std::string >())
Get the data path for a given path, searching the registered data.
Definition: DataFileUtils.C:22
static const std::map< std::string, std::string > & getDataFilePaths()
Returns a map of all registered data file paths (name -> path)
Definition: Registry.h:243