MARLEY (Model of Argon Reaction Low Energy Yields) v2.0.0
A Monte Carlo event generator for tens-of-MeV neutrino interactions
Loading...
Searching...
No Matches
FileManager.cc
1
4//
5// This file is part of MARLEY (Model of Argon Reaction Low Energy Yields)
6//
7// MARLEY is free software: you can redistribute it and/or modify it under the
8// terms of version 3 of the GNU General Public License as published by the
9// Free Software Foundation.
10//
11// For the full text of the license please see COPYING or
12// visit http://opensource.org/licenses/GPL-3.0
13//
14// Please respect the MCnet academic usage guidelines. See GUIDELINES
15// or visit https://www.montecarlonet.org/GUIDELINES for details.
16
17#include <cstdlib>
18#include <filesystem>
19
20#include "marley/Error.hh"
21#include "marley/FileManager.hh"
22#include "marley/Logger.hh"
23#include "marley/marley_utils.hh"
24
25namespace {
26 // Delimiter that separates directory names in search paths used by
27 // marley::FileManager
28 constexpr char SEARCH_PATH_DELIMITER = ':';
29
30 bool file_exists(const std::string& file_name) {
31 return std::filesystem::is_regular_file(file_name);
32 }
33
34 //bool file_is_readable(const std::string& file_name) {
35 // std::ifstream test_stream( file_name );
36 // return test_stream.good();
37 //}
38}
39
40// Define the static default search path member variable. Its value will be set
41// when the singleton instance of marley::FileManager is constructed.
43
45
46 // Check whether the MARLEY environment variable is set
47 char* mar = std::getenv("MARLEY");
48 if ( !mar ) throw marley::Error("The MARLEY environment variable is not set."
49 " Please set it (e.g., by sourcing the setup_marley.sh script) and"
50 " try again.");
51
52 marley_dir_ = std::string( mar );
53
54 // If the MARLEY_SEARCH_PATH environment variable is set, use that
55 // instead of the default search path
56 char* msp = std::getenv("MARLEY_SEARCH_PATH");
57 if ( msp ) default_search_path_ = std::string( msp );
58 else {
60 default_search_path_ += ':' + marley_dir_ + "/data/react";
61 default_search_path_ += ':' + marley_dir_ + "/data/optical_model";
62 default_search_path_ += ':' + marley_dir_ + "/data/structure";
63 }
64
65 MARLEY_LOG( DEBUG, "io" ) << "MARLEY search path set to \""
66 << default_search_path_ << '\"';
67}
68
70
71 // Create the mass table using a static variable. This ensures
72 // that the singleton instance is only created once.
73 static std::unique_ptr<marley::FileManager>
74 the_instance(new marley::FileManager());
75
76 // Return a reference to the singleton instance
77 return *the_instance;
78}
79
81 const std::string& search_path)
82{
83 std::vector<std::string> dir_names
84 = marley_utils::split_string(search_path, SEARCH_PATH_DELIMITER);
85 return dir_names;
86}
87
88std::string marley::FileManager::find_file(const std::string& base_name,
89 const std::string& search_path) const
90{
91 auto search_dirs = search_path_to_dir_vector( search_path );
92 return find_file(base_name, search_dirs);
93}
94
95std::string marley::FileManager::find_file(const std::string& base_name,
96 const std::vector<std::string>& search_dirs) const
97{
98 std::string full_path_to_file;
99
100 // First check if we can find the file just using base_name. We can
101 // avoid the search if it's already accessible (e.g., because the
102 // full path was supplied instead of the base name)
103 if ( file_exists(base_name) ) return base_name;
104
105 // If the file name contains directory separators, try resolving
106 // the relative path against each search directory
107 if ( base_name.find('/') != std::string::npos ) {
108 for (const auto& dir : search_dirs) {
109 std::string candidate = dir + '/' + base_name;
110 if ( file_exists(candidate) ) return candidate;
111 }
112 }
113
114 // Search the directories in the order listed. In each directory,
115 // compare all regular file names to the given base name. If a match
116 // is found, stop the search and store the result in full_path_to_file.
117 // If no match is found, full_path_to_file will remain empty.
118 for (const auto& dir : search_dirs) {
119 bool file_found = dir_iterate(dir,
120 [&full_path_to_file, &base_name](const std::string& other_full_path,
121 const std::string& other_base_name) -> bool
122 {
123 if ( base_name == other_base_name ) {
124 // We've found the desired file, so store its full path
125 full_path_to_file = other_full_path;
126 // Signal that we don't need to continue the search any longer
127 return true;
128 }
129 return false;
130 }
131 );
132
133 if ( file_found ) break;
134 }
135
136 return full_path_to_file;
137}
138
139std::vector<std::string> marley::FileManager::list_all_files(
140 const std::string& search_path) const
141{
142 auto search_dirs = search_path_to_dir_vector( search_path );
143 return list_all_files( search_dirs );
144}
145
146// Returns a vector of strings loaded with the full paths to all regular files
147// in the desired search path. The directories are scanned non-recursively.
148std::vector<std::string> marley::FileManager::list_all_files(
149 const std::vector<std::string>& search_dirs) const
150{
151 std::vector<std::string> result;
152
153 for (const auto& dir : search_dirs) {
154 dir_iterate(dir,
155 [&result](const std::string& full_path,
156 const std::string& /*base_name*/) -> bool
157 {
158 // Add the current file to the vector of full paths
159 result.push_back( full_path );
160 // Signal that the directory scan should continue
161 return false;
162 }
163 );
164 }
165
166 return result;
167}
168
169
170// Iterates non-recursively through all the regular files in a given
171// directory. Calls a std::function for each one that it finds.
172// If the function returns true, the iteration continues.
173// If it returns false, then the iteration will stop before the
174// next file is used.
175bool marley::FileManager::dir_iterate(const std::string& dir_name,
176 const std::function<bool(const std::string&, const std::string&)>& func)
177{
178 std::error_code ec;
179 std::filesystem::directory_iterator it(dir_name,
180 std::filesystem::directory_options::skip_permission_denied, ec);
181
182 if (ec) {
183 MARLEY_LOG(WARN, "io") << "Could not read from the directory \""
184 << dir_name << '\"';
185 return false;
186 }
187
188 std::filesystem::directory_iterator end;
189 bool stop_iterations = false;
190 while (!stop_iterations && it != end) {
191 const auto& entry = *it;
192 std::string full_file_name = entry.path().string();
193 std::string base_name = entry.path().filename().string();
194
195 MARLEY_LOG(TRACE, "io") << "marley::FileManager found file \""
196 << full_file_name << '\"';
197
198 if (entry.is_regular_file()) {
199 stop_iterations = func(full_file_name, base_name);
200 }
201
202 it.increment(ec);
203 if (ec) {
204 MARLEY_LOG(DEBUG, "io") << "Couldn't access a file in directory \""
205 << dir_name << '\"';
206 ec.clear();
207 }
208 }
209
210 return stop_iterations;
211}
Base class for all exceptions thrown by MARLEY functions.
Definition Error.hh:26
Singleton class that handles file searches.
std::string marley_dir_
Stores the value of the MARLEY environment variable (which points to the root folder of the source co...
FileManager()
Create the singleton FileManager object.
std::vector< std::string > list_all_files(const std::vector< std::string > &search_dirs) const
Get a vector of full paths for all regular files in the requested directories.
static std::string default_search_path_
By default, use this search path when looking for files.
static std::vector< std::string > search_path_to_dir_vector(const std::string &search_path=FileManager::default_search_path_)
Converts a ':'-delimited search path (given as a single string) into a vector of directory names.
static bool dir_iterate(const std::string &dir_name, const std::function< bool(const std::string &, const std::string &)> &func)
Helper function that executes a std::function on the name of each regular file found while scanning t...
static const FileManager & Instance()
Get a const reference to the singleton instance of the FileManager.
std::string find_file(const std::string &base_name, const std::vector< std::string > &search_dirs) const
Searches for a file in the given directories.