23namespace fs = std::filesystem;
26 const char path_separator =
':';
27 const char*
const pathResolverEnvVar =
"PATHRESOLVER_DEVAREARESPONSE";
30 size_t write_data(
void* ptr,
size_t size,
size_t nmemb,
void* userdata) {
31 std::ostream*
stream =
static_cast<std::ostream*
>(userdata);
32 size_t total_size = size * nmemb;
33 stream->write(
static_cast<char*
>(ptr), total_size);
36 bool download_file(
const std::string& url,
const std::string& output_path,
37 asg::AsgMessaging& asgmsg)
43 static std::once_flag curl_setup;
44 std::call_once(curl_setup, curl_global_init, CURL_GLOBAL_DEFAULT);
46 using owner_t = std::unique_ptr<CURL,
decltype(&curl_easy_cleanup)>;
47 owner_t curl_owner(curl_easy_init(), curl_easy_cleanup);
49 auto* curl = curl_owner.get();
52 asgmsg.
msg(MSG::WARNING) <<
"unable to setup curl" <<
endmsg;
56 std::ofstream
file(output_path, std::ios::binary);
57 if (!
file.is_open()) {
58 asgmsg.
msg(MSG::WARNING) <<
"unable to open " << output_path <<
endmsg;
61 auto setCurlOption =[curl](
auto option,
const auto &
value)->
bool{
62 CURLcode ret = curl_easy_setopt(curl, option, value);
63 return (ret == CURLE_OK);
65 bool setupOk = setCurlOption(CURLOPT_TIMEOUT, 60L);
66 setupOk &= setCurlOption(CURLOPT_URL,
url.c_str());
67 setupOk &= setCurlOption(CURLOPT_WRITEFUNCTION, write_data);
68 setupOk &= setCurlOption(CURLOPT_WRITEDATA, &
file);
70 setupOk &= setCurlOption(CURLOPT_FOLLOWLOCATION, 1L);
72 asgmsg.
msg(MSG::WARNING) <<
"curl setup failed in PathResolver." <<
endmsg;
75 CURLcode
res = curl_easy_perform(curl);
76 if (
res != CURLE_OK) {
77 asgmsg.
msg(MSG::WARNING) <<
"error downloading file: "
78 << curl_easy_strerror(
res)
87 void checkForDev(asg::AsgMessaging& asgmsg,
88 const std::string& logical_file_name) {
90 if (asgmsg.
msgLvl(MSG::DEBUG)) asgmsg.
msg(MSG::DEBUG) <<
"Trying to locate " << logical_file_name <<
endmsg;
92 if (logical_file_name.starts_with(
"dev/")) {
93 const char*
env = std::getenv(pathResolverEnvVar);
94 const std::string dev_area_response =
env ?
env :
"DEFAULT";
97 if (dev_area_response ==
"SILENT") {
100 else if (dev_area_response ==
"THROW") {
101 throw std::runtime_error(
102 "Loading dev area file " + logical_file_name +
" is not allowed! "
103 "To override this error set the environment variable " +
104 pathResolverEnvVar +
" to SILENT, DEFAULT, INFO, WARNING or ERROR");
106 else if (dev_area_response ==
"DEFAULT") {
108 level = MSG::WARNING;
113 else if (dev_area_response ==
"INFO")
level = MSG::INFO;
114 else if (dev_area_response ==
"WARNING")
level = MSG::WARNING;
115 else if (dev_area_response ==
"ERROR")
level = MSG::ERROR;
117 throw std::runtime_error(std::format(
"{} set to '{}', not sure what to do. "
118 "Options are DEFAULT, THROW, INFO, WARNING, ERROR or SILENT",
119 pathResolverEnvVar, dev_area_response));
123 asgmsg.
msg(level) <<
"Locating dev file " << logical_file_name <<
". Do not let this propagate to a release!" <<
endmsg;
131#ifdef XAOD_STANDALONE
148 fs::file_type file_type, std::string&
result ) {
151 TString tmpString(logical_file_name);
152 gSystem->ExpandPathName(tmpString);
154 fs::path
file(tmpString.Data());
155 fs::path locationToDownloadTo =
".";
158 const std::string searchPath = std::format(
"./{}{}", path_separator, search_list);
161 for (
const auto r : searchPath | std::views::split(path_separator)) {
162 std::string_view path(
r.begin(),
r.end());
163 const bool is_http = path.starts_with(
"http//");
164 if( (is_http || path.starts_with(
"https//")) &&
165 file_type==fs::file_type::regular && std::getenv(
"PATHRESOLVER_ALLOWHTTPDOWNLOAD") ) {
169 const std::string fileToDownload = std::format(
"{}://{}/{}", is_http ?
"http" :
"https",
170 path.substr(6),
file.string());
172 const fs::path targetPath = locationToDownloadTo /
file;
173 fs::path targetDir = targetPath;
174 targetDir.remove_filename();
175 if (
msgLvl(MSG::DEBUG))
msg(MSG::DEBUG) <<
"Attempting http download of " << fileToDownload <<
" to " << targetDir <<
endmsg;
177 if (!is_directory(targetDir)) {
178 if (
msgLvl(MSG::DEBUG))
msg(MSG::DEBUG) <<
"Creating directory " << targetDir <<
endmsg;
179 if(!fs::create_directories(targetDir)) {
180 msg(MSG::ERROR) <<
"Unable to create directories to write file to " << targetDir <<
endmsg;
185 if (!download_file(fileToDownload, targetPath,
asgMsg())) {
186 msg(MSG::WARNING) <<
"Unable to download file " << fileToDownload <<
endmsg;
188 if (
msgLvl(MSG::DEBUG))
msg(MSG::DEBUG) <<
"Successfully downloaded " << fileToDownload <<
endmsg;
193 }
else if (locationToDownloadTo==
".") {
195 fs::path dummyFile = fs::path(path) /
"._pathresolver_dummy";
196 std::ofstream ofs(dummyFile);
198 locationToDownloadTo = path;
200 fs::remove(dummyFile);
204 fs::path fp = path /
file;
206 if (fs::status(fp).
type() == file_type) {
207 result = fs::absolute(fp).string();
210 }
catch (
const fs::filesystem_error&) {
221 const std::string& search_path) {
224 if (logical_file_name.starts_with(
'/')) {
225 msg(MSG::ERROR) <<
"Use of an absolute file name: " << logical_file_name <<
endmsg;
229 const char* path_list = std::getenv(search_path.c_str());
230 if (path_list ==
nullptr) {
231 msg(MSG::ERROR) << search_path <<
" environment variable not defined!" <<
endmsg;
240 const std::string& search_list)
243 PR_find (logical_file_name, search_list, fs::file_type::regular,
result);
250 const std::string& search_path)
252 const char* path_list = std::getenv(search_path.c_str());
253 if(path_list ==
nullptr) {
254 msg(MSG::ERROR) << search_path <<
" environment variable not defined!" <<
endmsg;
263 const std::string& search_list)
266 PR_find(logical_file_name, search_list, fs::file_type::directory,
result);
274 checkForDev(
asgMsg(), logical_file_name);
276 if (logical_file_name.starts_with(
"root://")) {
278 std::unique_ptr<TFile> fTmp{TFile::Open(logical_file_name.c_str())};
279 if (!fTmp || fTmp->IsZombie()) {
280 msg(MSG::WARNING) <<
"Could not open " << logical_file_name <<
endmsg;
283 return logical_file_name;
288 msg(MSG::WARNING) <<
"Could not locate " << logical_file_name <<
endmsg;
296 checkForDev(
asgMsg(), logical_file_name);
300 msg(MSG::WARNING) <<
"Could not locate " << logical_file_name <<
endmsg;
std::pair< std::vector< unsigned int >, bool > res
std::string PathResolverFindXMLFile(const std::string &logical_file_name)
std::string PathResolverFindCalibDirectory(const std::string &logical_file_name)
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
std::string PathResolverFindDataFile(const std::string &logical_file_name)
void PathResolverSetOutputLevel(int lvl)
Define macros for attributes used to control the static checker.
#define ATLAS_THREAD_SAFE
void setLevel(MSG::Level lvl)
Change the current logging level.
static std::string find_directory_from_list(const std::string &logical_file_name, const std::string &search_list)
static void setOutputLevel(MSG::Level level)
static bool msgLvl(const MSG::Level lvl)
static bool PR_find(const std::string &logical_file_name, const std::string &search_list, std::filesystem::file_type file_type, std::string &result)
Main private search method used by all public methods.
static std::atomic< MSG::Level > m_level
static std::string find_calib_file(const std::string &logical_file_name)
static std::string find_directory(const std::string &logical_file_name, const std::string &search_path)
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)
static std::string find_file_from_list(const std::string &logical_file_name, const std::string &search_list)
static std::string find_calib_directory(const std::string &logical_file_name)
static asg::AsgMessaging & asgMsg()
Class mimicking the AthMessaging class from the offline software.
MsgStream & msg() const
The standard message stream.
bool msgLvl(const MSG::Level lvl) const
Test the output level of the object.