Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
PathResolver.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
7 #ifndef XAOD_STANDALONE
8 #include "GaudiKernel/System.h"
9 #endif
10 
11 
12 #include <iostream>
13 
14 #include <vector>
15 #include <stdexcept>
16 #include <stdlib.h>
17 
18 #include <boost/algorithm/string/split.hpp>
19 #include <boost/algorithm/string.hpp>
20 #include <boost/algorithm/string/classification.hpp>
21 #include <boost/filesystem.hpp>
23 
24 
25 
26 #include "TFile.h"
27 #include "TSystem.h"
28 #include "TError.h" //needed to suppress errors when attempting file downloads
29 
30 namespace bf = boost::filesystem;
31 using namespace std;
32 
33 namespace {
34  enum class DevAreaResponse {
35  DEFAULT,
36  THROW,
37  SILENT,
38  INFO,
39  WARNING,
40  ERROR,
41  };
42  const std::string pathResolverEnvVar = "PATHRESOLVER_DEVAREARESPONSE";
43  DevAreaResponse getDevAreaResponse(
44  const std::string& varname = pathResolverEnvVar)
45  {
46  const char* env = std::getenv(varname.c_str());
47  if (env == nullptr) return DevAreaResponse::DEFAULT;
48  std::string envstr(env);
49 #define TRYSTR(string) if (envstr == #string) return DevAreaResponse::string
50  TRYSTR(THROW);
51  TRYSTR(SILENT);
52  TRYSTR(DEFAULT);
53  TRYSTR(INFO);
54  TRYSTR(WARNING);
55  TRYSTR(ERROR);
56 #undef TRYSTR
57  throw std::runtime_error(
58  varname + " set to '" + envstr + "', not sure what to do. "
59  "Option are DEFAULT, THROW, INFO, WARNING, ERROR, or SILENT");
60  }
61 
62  void checkForDev(asg::AsgMessaging& asgmsg,
63  const std::string& logical_file_name,
64  const std::string& envvar = pathResolverEnvVar) {
65  DevAreaResponse dev_area_response = getDevAreaResponse(envvar);
66  asgmsg.msg(MSG::DEBUG) << "Trying to locate " << logical_file_name << endmsg;
67  if(logical_file_name.compare(0, 4, "dev/")==0 &&
68  dev_area_response != DevAreaResponse::SILENT)
69  {
70  auto level = MSG::ERROR;
71 #ifdef XAOD_ANALYSIS
72  level = MSG::WARNING;
73 #endif
74  switch(dev_area_response) {
75  case DevAreaResponse::INFO: level = MSG::INFO; break;
76  case DevAreaResponse::WARNING: level = MSG::WARNING; break;
77  case DevAreaResponse::ERROR: level = MSG::ERROR; break;
78  default: /* do nothing use the cases above */ ;
79  }
80  asgmsg.msg(level) << "Locating dev file " << logical_file_name << ". Do not let this propagate to a release" << endmsg;
81  if (dev_area_response == DevAreaResponse::THROW) {
82  throw std::runtime_error(
83  "dev area file " + logical_file_name + " is not allowed! "
84  "to override this error set the environment variable " +
85  envvar + " to SILENT, DEFAULT, INFO, WARNING, or ERROR");
86  }
87  }
88  }
89 }
90 
91 static const char* const path_separator = ",:";
92 std::atomic<MSG::Level> PathResolver::m_level=MSG::INFO;
93 
95 
97 #ifdef XAOD_STANDALONE
98  static thread_local asg::AsgMessaging asgMsg("PathResolver");
99 #else
100  static asg::AsgMessaging asgMsg ATLAS_THREAD_SAFE ("PathResolver");
101 #endif
102 #ifndef XAOD_ANALYSIS
104  asgMsg.setLevel(m_level);
105 #else
106  asgMsg.msg().setLevel(m_level);
107 #endif
108  return asgMsg;
109 }
110 
111 //
113 //
114 
115 
116 
117 
118 
119 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
120 
121 bool
122 PathResolver::PR_find( const std::string& logical_file_name, const string& search_list,
123  PR_file_type file_type, PathResolver::SearchType search_type,
124  string& result ) {
125 
126  std::string trimmed_logical_file_name = logical_file_name;
127  boost::algorithm::trim(trimmed_logical_file_name); //trim again for extra safety
128 
129  bf::path file( trimmed_logical_file_name );
130 
131  bool found(false);
132 
133  // look for file as specified first
134 
135  try {
136  if ( ( file_type == PR_regular_file && is_regular_file( file ) ) ||
137  ( file_type == PR_directory && is_directory( file ) ) ) {
138  result = bf::system_complete(file).string();
139  return true;
140  }
141  } catch (const bf::filesystem_error& /*err*/) {
142  }
143 
144  // assume that "." is always part of the search path, so check locally first
145 
146  try {
147  bf::path local = bf::initial_path() / file;
148  if ( ( file_type == PR_regular_file && is_regular_file( local ) ) ||
149  ( file_type == PR_directory && is_directory( local ) ) ) {
150  result = bf::system_complete(file).string();
151  return true;
152  }
153  } catch (const bf::filesystem_error& /*err*/) {
154  }
155 
156  std::string locationToDownloadTo = "."; //will replace with first search location
157 
158  // iterate through search list
159  vector<string> spv;
160  split(spv, search_list, boost::is_any_of( path_separator), boost::token_compress_on);
161  for (vector<string>::const_iterator itr = spv.begin();
162  itr != spv.end(); ++itr ) {
163 
164  if( itr->find("http//")==0 && file_type==PR_regular_file && gSystem->Getenv("PATHRESOLVER_ALLOWHTTPDOWNLOAD") ) { //only http download files, not directories
165  //try to do an http download to the local location
166  //restore the proper http protocal (had to remove for sake of env var splitting)
167  std::string addr = "http://"; addr += itr->substr(6,itr->length());
168  bf::path lp = locationToDownloadTo/file;
169  bf::path lpd = lp; lpd.remove_filename();
170  msg(MSG::DEBUG) <<"Attempting http download of " << addr << "/" << file.string() << " to " << lp << endmsg;
171 
172  if(!is_directory(lpd)) {
173  msg(MSG::DEBUG) <<" Creating directory: " << lpd << endmsg;
174  if(!boost::filesystem::create_directories(lpd)) {
175  msg(MSG::DEBUG) <<"Unable to create directories to write file to : " << lp << endmsg;
176  continue;
177  //throw std::runtime_error("Unable to download calibration file");
178  }
179  }
180  std::string fileToDownload = addr + "/" + file.string();
181  std::string targetPath = locationToDownloadTo+"/"+file.string();
182  //disable error output from root while attempting to download
183  // FIXME: Disabling errors now commented out because it is not
184  // thread-safe. Needs changes in ROOT.
185  //long errLevel = gErrorIgnoreLevel;
186  //gErrorIgnoreLevel = kError+1;
187  if(!TFile::Cp(fileToDownload.c_str(),targetPath.c_str(), false)) {
188  msg(MSG::WARNING) <<"Unable to download file : " << fileToDownload << endmsg;
189  } else {
190  msg(MSG::DEBUG) <<"Successfully downloaded " << fileToDownload << endmsg;
191  result = (locationToDownloadTo+"/"+file.string()).c_str();
192  //gErrorIgnoreLevel=errLevel;
193  return true;
194  }
195  //gErrorIgnoreLevel=errLevel;
196  } else if(locationToDownloadTo=="." && itr->find("/afs/cern.ch/atlas/www/")==std::string::npos) { //don't let it ever download back to the www area!
197  //prefer first non-pwd location for downloading to. But must be fully accessible. This should be the local InstallArea in cmt
198  FILE *fp = std::fopen((*itr+"/._pathresolver_dummy").c_str(), "a+");
199  if(fp!=NULL) {
200  locationToDownloadTo=*itr;
201  std::fclose(fp);
202  (void)std::remove((*itr+"/._pathresolver_dummy").c_str());
203  }
204  }
205 
206  //std::cout << "searching path: " << *itr);
207 
208  bf::path fp = *itr / file;
209 
210  try {
211  if ( ( file_type == PR_regular_file && is_regular_file( fp ) ) ||
212  ( file_type == PR_directory && is_directory( fp ) ) ) {
213  result = bf::system_complete(fp).string();
214  return true;
215  }
216  } catch (const bf::filesystem_error& /*err*/) {
217  }
218 
219 
220  // if recursive searching requested, drill down
221  if (search_type == PathResolver::RecursiveSearch &&
222  is_directory( bf::path(*itr) ) ) {
223 
224  bf::recursive_directory_iterator end_itr;
225  try {
226  for ( bf::recursive_directory_iterator ritr( *itr );
227  ritr != end_itr; ++ritr) {
228 
229  // skip if not a directory
230  if (! is_directory( bf::path(*ritr) ) ) { continue; }
231 
232  bf::path fp2 = bf::path(*ritr) / file;
233  if ( ( file_type == PR_regular_file && is_regular_file( fp2 ) ) ||
234  ( file_type == PR_directory && is_directory( fp2 ) ) ) {
235  result = bf::system_complete( fp2 ).string();
236  return true;
237  }
238  }
239  } catch (const bf::filesystem_error& /*err*/) {
240  }
241  }
242 
243  }
244 
245  return found;
246 }
247 
248 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
249 
250 string
251 PathResolver::find_file(const std::string& logical_file_name,
252  const std::string& search_path,
253  SearchType search_type) {
254  //std::cout << "finding file: " <<logical_file_name << " in path=" << search_path);
255 
256  std::string path_list;
257 
258 #ifdef XAOD_STANDALONE
259  const char* envVarVal = gSystem->Getenv(search_path.c_str());
260  if(envVarVal == NULL) {
261  msg(MSG::WARNING) <<search_path.c_str() << " environment variable not defined!" << endmsg;
262  path_list = ""; //this will allow search in pwd ... maybe we should throw exception though!
263  }
264  else { path_list = envVarVal; }
265 #else
266  System::getEnv(search_path, path_list);
267 #endif
268 
269 #ifndef XAOD_ANALYSIS
270  if (!logical_file_name.empty() && logical_file_name[0]=='/') {
271  msg(MSG::ERROR) << "Use of an absolute file name: " << logical_file_name << endmsg;
272  }
273 #endif
274 
275  return (find_file_from_list (logical_file_name, path_list, search_type));
276 }
277 
278 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
279 
280 std::string
281 PathResolver::find_file_from_list (const std::string& logical_file_name,
282  const std::string& search_list,
283  SearchType search_type)
284 {
285  std::string result("");
286 
287 
288 
289  /* bool found = */
290  PR_find (logical_file_name, search_list, PR_regular_file, search_type, result);
291 
292  // The following functionality was in the original PathResolver, but I believe
293  // that it's WRONG. It extracts the filename of the requested item, and searches
294  // for that if the preceding search fails. i.e., if you're looking for "B/a.txt",
295  // and that fails, it will look for just "a.txt" in the search list.
296 
297  // if (! found && lfn.filename() != lfn ) {
298  // result = "";
299  // PR_find (lfn.filename(), search_list, PR_regular_file, search_type, result);
300  // }
301 
302  return (result);
303 }
304 
305 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
306 
307 string PathResolver::find_directory (const std::string& logical_file_name,
308  const std::string& search_path,
309  SearchType search_type)
310 {
311  std::string path_list;
312 
313 #ifdef XAOD_STANDALONE
314  const char* envVarVal = gSystem->Getenv(search_path.c_str());
315  if(envVarVal == NULL) {
316  msg(MSG::WARNING) <<search_path.c_str() << " environment variable not defined!" << endmsg;
317  path_list = ""; //this will allow search in pwd ... maybe we should throw exception though!
318  }
319  else { path_list = envVarVal; }
320 #else
321  System::getEnv(search_path, path_list);
322 #endif
323 
324  return (find_directory_from_list (logical_file_name, path_list, search_type));
325 }
326 
327 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
328 
329 string
330 PathResolver::find_directory_from_list (const std::string& logical_file_name,
331  const std::string& search_list,
332  SearchType search_type)
333 {
334  std::string result;
335 
336  if (!PR_find (logical_file_name, search_list, PR_directory, search_type, result))
337  {
338  result = "";
339  }
340 
341  return (result);
342 }
343 
344 
345 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
346 
348 PathResolver::check_search_path (const std::string& search_path)
349 {
350  std::string path_list = gSystem->Getenv(search_path.c_str());
351  if ( path_list.empty() )
352  return (EnvironmentVariableUndefined);
353 
354  vector<string> spv;
355  boost::split( spv, path_list, boost::is_any_of( path_separator ), boost::token_compress_on);
356  vector<string>::iterator itr=spv.begin();
357 
358  try {
359  for (; itr!= spv.end(); ++itr) {
360  bf::path pp(*itr);
361  if (!is_directory(pp)) {
362  return (UnknownDirectory);
363  }
364  }
365  } catch(const bf::filesystem_error& /*err*/) {
366  return (UnknownDirectory);
367  }
368 
369  return ( Ok );
370 }
371 
372 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
373 
374 std::string PathResolverFindXMLFile (const std::string& logical_file_name)
375 {
376  return PathResolver::find_file (logical_file_name, "XMLPATH");
377 }
378 
379 std::string PathResolverFindDataFile (const std::string& logical_file_name)
380 {
381  return PathResolver::find_file (logical_file_name, "DATAPATH");
382 }
383 
384 std::string PathResolver::find_calib_file (const std::string& logical_file_name)
385 {
386  checkForDev(asgMsg(), logical_file_name);
387  //expand filename before finding ..
388  TString tmpString(logical_file_name);
389  gSystem->ExpandPathName(tmpString);
390  if(tmpString.BeginsWith("root://")) {
391  //xrootd access .. try to open file ...
392  TFile* fTmp = TFile::Open(tmpString);
393  if(!fTmp || fTmp->IsZombie()) {
394  msg(MSG::WARNING) << "Could not open " << logical_file_name << endmsg;
395  tmpString = "";
396  }
397 
398  if(fTmp) {
399  fTmp->Close();
400  delete fTmp;
401  }
402 
403  return tmpString.Data();
404  }
405  std::string expandedFileName(tmpString.Data());
406  //strip any spaces off of the name
407  boost::algorithm::trim(expandedFileName);
408  std::string out = PathResolver::find_file (expandedFileName, "CALIBPATH");
409  if(out=="") msg(MSG::WARNING) <<"Could not locate " << logical_file_name << endmsg;
410  return out;
411 }
412 
413 std::string PathResolver::find_calib_directory (const std::string& logical_file_name)
414 {
415  checkForDev(asgMsg(), logical_file_name);
416  //expand filename before finding
417  TString tmpString(logical_file_name);
418  gSystem->ExpandPathName(tmpString);
419  std::string expandedFileName(tmpString.Data());
420  boost::algorithm::trim(expandedFileName);
421  std::string out = PathResolver::find_directory (expandedFileName, "CALIBPATH");
422  if(out=="") msg(MSG::WARNING) <<"Could not locate " << logical_file_name << endmsg;
423  return out;
424 }
425 
427  m_level = level;
428 }
429 
430 
431 std::string PathResolverFindCalibFile (const std::string& logical_file_name) { return PathResolver::find_calib_file(logical_file_name); }
432 std::string PathResolverFindCalibDirectory (const std::string& logical_file_name) { return PathResolver::find_calib_directory(logical_file_name); }
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
PathResolver::find_calib_file
static std::string find_calib_file(const std::string &logical_file_name)
Definition: PathResolver.cxx:384
PathResolver::asgMsg
static asg::AsgMessaging & asgMsg()
Definition: PathResolver.cxx:96
DEFAULT
@ DEFAULT
Definition: sTGCenumeration.h:15
PathResolver::SearchType
SearchType
Definition: PathResolver.h:26
PathResolver::RecursiveSearch
@ RecursiveSearch
Definition: PathResolver.h:28
get_generator_info.result
result
Definition: get_generator_info.py:21
athena.path
path
python interpreter configuration --------------------------------------—
Definition: athena.py:128
PathResolver::find_file
static std::string find_file(const std::string &logical_file_name, const std::string &search_path, SearchType search_type=LocalSearch)
Definition: PathResolver.cxx:251
CP::OutOfValidityAction::SILENT
@ SILENT
don't print anything and return success
PathResolver::find_calib_directory
static std::string find_calib_directory(const std::string &logical_file_name)
Definition: PathResolver.cxx:413
python.Constants.ERROR
int ERROR
Definition: Control/AthenaCommon/python/Constants.py:17
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:71
PathResolver::PathResolver
PathResolver()
Definition: PathResolver.cxx:94
PathResolver::m_level
static std::atomic< MSG::Level > m_level
Definition: PathResolver.h:117
PathResolver::find_directory
static std::string find_directory(const std::string &logical_file_name, const std::string &search_path, SearchType search_type=LocalSearch)
Definition: PathResolver.cxx:307
python.iconfTool.models.loaders.level
level
Definition: loaders.py:20
TRYSTR
#define TRYSTR(string)
PixelModuleFeMask_create_db.remove
string remove
Definition: PixelModuleFeMask_create_db.py:83
TrigConf::MSGTC::Level
Level
Definition: Trigger/TrigConfiguration/TrigConfBase/TrigConfBase/MsgStream.h:21
trigmenu_modify_prescale_json.fp
fp
Definition: trigmenu_modify_prescale_json.py:53
endmsg
#define endmsg
Definition: AnalysisConfig_Ntuple.cxx:63
PathResolverFindXMLFile
std::string PathResolverFindXMLFile(const std::string &logical_file_name)
Definition: PathResolver.cxx:374
PathResolver::check_search_path
static SearchPathStatus check_search_path(const std::string &search_path)
Definition: PathResolver.cxx:348
asg::AsgMessaging::msg
MsgStream & msg() const
The standard message stream.
Definition: AsgMessaging.cxx:49
file
TFile * file
Definition: tile_monitor.h:29
PathResolverFindDataFile
std::string PathResolverFindDataFile(const std::string &logical_file_name)
Definition: PathResolver.cxx:379
python.Constants.WARNING
int WARNING
Definition: Control/AthenaCommon/python/Constants.py:16
PathResolver::PR_find
static bool PR_find(const std::string &logical_file_name, const std::string &search_list, PR_file_type file_type, SearchType search_type, std::string &result)
Definition: PathResolver.cxx:122
PathResolver::find_file_from_list
static std::string find_file_from_list(const std::string &logical_file_name, const std::string &search_list, SearchType search_type=LocalSearch)
Definition: PathResolver.cxx:281
PathResolver::SearchPathStatus
SearchPathStatus
Definition: PathResolver.h:19
InDetDD::local
@ local
Definition: InDetDD_Defs.h:16
PathResolver.h
PathResolver::find_directory_from_list
static std::string find_directory_from_list(const std::string &logical_file_name, const std::string &search_list, SearchType search_type=LocalSearch)
Definition: PathResolver.cxx:330
asg::AsgMessaging
Class mimicking the AthMessaging class from the offline software.
Definition: AsgMessaging.h:40
PathResolver::PR_file_type
PR_file_type
Definition: PathResolver.h:31
PathResolverSetOutputLevel
void PathResolverSetOutputLevel(int lvl)
Definition: PathResolver.cxx:433
checkTriggerxAOD.found
found
Definition: checkTriggerxAOD.py:328
PathResolverFindCalibDirectory
std::string PathResolverFindCalibDirectory(const std::string &logical_file_name)
Definition: PathResolver.cxx:432
LArG4AODNtuplePlotter.varname
def varname(hname)
Definition: LArG4AODNtuplePlotter.py:37
SCT_ConditionsAlgorithms::CoveritySafe::getenv
std::string getenv(const std::string &variableName)
get an environment variable
Definition: SCT_ConditionsUtilities.cxx:17
python.Constants.INFO
int INFO
Definition: Control/AthenaCommon/python/Constants.py:15
athena.path_list
list path_list
Definition: athena.py:93
DEBUG
#define DEBUG
Definition: page_access.h:11
GRLStrUtil::trim
void trim(std::string &input)
Definition: StrUtil.cxx:12
PathResolverFindCalibFile
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
Definition: PathResolver.cxx:431
PathResolver::setOutputLevel
static void setOutputLevel(MSG::Level level)
Definition: PathResolver.cxx:426
ATLAS_THREAD_SAFE
#define ATLAS_THREAD_SAFE
Definition: checker_macros.h:211
python.DataFormatRates.env
env
Definition: DataFormatRates.py:32
checker_macros.h
Define macros for attributes used to control the static checker.
python.AutoConfigFlags.msg
msg
Definition: AutoConfigFlags.py:7
Trk::split
@ split
Definition: LayerMaterialProperties.h:38