CMS 3D CMS Logo

FileInPath.cc
Go to the documentation of this file.
1 // ----------------------------------------------------------------------
2 // ----------------------------------------------------------------------
3 
4 #include <atomic>
5 #include <cstdlib>
6 #include <vector>
7 #include "boost/filesystem/path.hpp"
8 #include "boost/filesystem/operations.hpp"
9 
14 
15 namespace bf = boost::filesystem;
16 
17 namespace
18 {
19 
20  std::atomic<bool> s_fileLookupDisabled{false};
21 
25 
26  const std::string PathVariableName("CMSSW_SEARCH_PATH");
27  // Environment variables for local and release areas:
28  const std::string LOCALTOP("CMSSW_BASE");
29  const std::string RELEASETOP("CMSSW_RELEASE_BASE");
30  const std::string DATATOP("CMSSW_DATA_PATH");
31 
32 #if 1
33  // Needed for backward compatibility prior to CMSSW_1_5_0_pre3.
34  // String to serve as placeholder for release top.
35  // Do not change this value.
36  const std::string BASE("BASE");
37 #endif
38  const std::string version("V001");
39 
40  // Remove symlinks from path
41  std::string removeSymLinks(std::string const& envName) {
42  char const* const var = getenv(envName.c_str());
43  if(var == nullptr) {
44  return std::string();
45  }
48  return path;
49  }
50 
51  std::string removeSymLinksSrc(std::string const& envName) {
52  char const* const var = getenv(envName.c_str());
53  if(var == nullptr) {
54  return std::string();
55  }
56  std::string const src = "/src";
57  std::string path = var + src;
59  size_t actualSize = path.size() - src.size();
60  assert(path.substr(actualSize, src.size()) == src);
61  return path.substr(0, actualSize);
62  }
63 
64  std::string removeSymLinksTokens(std::string const& envName) {
65  char const* const var = getenv(envName.c_str());
66  if(var == nullptr) {
67  return std::string();
68  }
69  std::string theSearchPath;
70  typedef std::vector<std::string> stringvec_t;
71  stringvec_t pathElements = edm::tokenize(std::string(var), ":");
72  for(auto& element : pathElements) {
74  if(!theSearchPath.empty()) theSearchPath += ":";
75  theSearchPath += element;
76  }
77  return theSearchPath;
78  }
79 
80  // Check for existence of a file for the given relative path and
81  // 'prefix'.
82  // Return true if a file (not directory or symbolic link) is found
83  // Return false is *nothing* is found
84  // Throw an exception if either a directory or symbolic link is found.
85  // If true is returned, then put the
86  bool locateFile(bf::path p,
87  std::string const& relative)
88  {
89  p /= relative;
90 
91  if (!bf::exists(p)) return false;
92 
93  if (bf::is_directory(p)) {
95  << "Path "
96  << p.string()
97  << " is a directory, not a file\n";
98  }
99 
100  if (bf::is_symlink(bf::symlink_status(p))) {
102  << "Path "
103  << p.string()
104  << " is a symbolic link, not a file\n";
105  }
106  return true;
107  }
108 }
109 
110 namespace edm
111 {
112 
114  relativePath_(),
115  canonicalFilename_(),
116  location_(Unknown)
117  {
118  if (s_fileLookupDisabled) {
119  return;
120  }
121  getEnvironment();
122  }
123 
125  relativePath_(r),
128  {
129  if (s_fileLookupDisabled) {
130  return;
131  }
132  getEnvironment();
133  initialize_();
134  }
135 
136  FileInPath::FileInPath(char const* r) :
137  relativePath_(r ? r : ""),
140  {
141  if (s_fileLookupDisabled) {
142  return;
143  }
144  if(r == nullptr) {
145  throw edm::Exception(edm::errors::FileInPathError) << "Relative path must not be null\n";
146  }
147  getEnvironment();
148  initialize_();
149  }
150 
154  location_(other.location_),
155  localTop_(other.localTop_),
156  releaseTop_(other.releaseTop_),
157  dataTop_(other.dataTop_),
158  searchPath_(other.searchPath_)
159  {}
160 
162 
163  FileInPath&
165  {
166  FileInPath temp(other);
167  this->swap(temp);
168  return *this;
169  }
170 
171  void
173  {
174  relativePath_.swap(other.relativePath_);
176  std::swap(location_, other.location_);
177  localTop_.swap(other.localTop_);
178  releaseTop_.swap(other.releaseTop_);
179  dataTop_.swap(other.dataTop_);
180  searchPath_.swap(other.searchPath_);
181  }
182 
185  {
186  return relativePath_;
187  }
188 
189 
192  {
193  return location_;
194  }
195 
198  {
199  return canonicalFilename_;
200  }
201 
202  void
203  FileInPath::write(std::ostream& os) const
204  {
205  if (location_ == Unknown) {
206  os << version << ' ' << relativePath_ << ' ' << location_;
207  } else if (location_ == Local) {
208  // Guarantee a site independent value by stripping $LOCALTOP.
209  if (localTop_.empty()) {
211  << "Environment Variable "
212  << LOCALTOP
213  << " is not set.\n";
214  }
216  if (pos != 0) {
218  << "Path "
220  << " is not in the local release area "
221  << localTop_
222  << "\n";
223  }
224  os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(localTop_.size());
225  } else if (location_ == Release) {
226  // Guarantee a site independent value by stripping $RELEASETOP.
227  if (releaseTop_.empty()) {
229  << "Environment Variable "
230  << RELEASETOP
231  << " is not set.\n";
232  }
234  if (pos != 0) {
236  << "Path "
238  << " is not in the base release area "
239  << releaseTop_
240  << "\n";
241  }
242  os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(releaseTop_.size());
243  } else if (location_ == Data) {
244  // Guarantee a site independent value by stripping $DATATOP.
245  if (dataTop_.empty()) {
247  << "Environment Variable "
248  << DATATOP
249  << " is not set.\n";
250  }
252  if (pos != 0) {
254  << "Path "
256  << " is not in the data area "
257  << dataTop_
258  << "\n";
259  }
260  os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(dataTop_.size());
261  }
262  }
263 
264 
265  void
266  FileInPath::read(std::istream& is)
267  {
268  std::string vsn;
269  std::string relname;
270  std::string canFilename;
271 #if 1
272  // This #if needed for backward compatibility
273  // for files written before CMSSW_1_5_0_pre3.
274  is >> vsn;
275  if (!is) return;
276  bool oldFormat = (version != vsn);
277  if (oldFormat) {
278  relname = vsn;
279  bool local;
280  is >> local;
281  location_ = (local ? Local : Release);
282  is >> canFilename;
283  } else {
284  // Current format
285  int loc;
286  is >> relname >> loc;
287  location_ = static_cast<FileInPath::LocationCode>(loc);
288  if (location_ != Unknown) is >> canFilename;
289  }
290 #else
291  is >> vsn >> relname >> loc >> canFilename;
292 #endif
293  if (!is) return;
294  relativePath_ = relname;
295  if (location_ == Local) {
296  if (localTop_.empty()) {
298  << "Environment Variable "
299  << LOCALTOP
300  << " is not set.\n"
301  << "Trying to read Local file: " << canFilename << ".\n";
302  }
303 #if 1
304  // This #if needed for backward compatibility
305  // for files written before CMSSW_1_5_0_pre3.
306  if (oldFormat) {
307  canonicalFilename_ = canFilename;
308  } else
309 #endif
310  canonicalFilename_ = localTop_ + canFilename;
311  } else if (location_ == Release) {
312  if (releaseTop_.empty()) {
314  << "Environment Variable "
315  << RELEASETOP
316  << " is not set.\n";
317  }
318 #if 1
319  // This #if needed for backward compatibility
320  // for files written before CMSSW_1_5_0_pre3.
321  if (oldFormat) {
322  std::string::size_type pos = canFilename.find(BASE);
323  if (pos == 0) {
324  // Replace the placehoder with the path to the base release (site dependent).
325  canonicalFilename_ = releaseTop_ + canFilename.substr(BASE.size());
326  } else {
327  // Needed for files written before CMSSW_1_2_0_pre2.
328  canonicalFilename_ = canFilename;
329  }
330  } else
331 #endif
332  canonicalFilename_ = releaseTop_ + canFilename;
333  } else if (location_ == Data) {
334  if (dataTop_.empty()) {
336  << "Environment Variable "
337  << DATATOP
338  << " is not set.\n";
339  }
340  canonicalFilename_ = dataTop_ + canFilename;
341  }
342  }
343 
344  void
346  {
347  std::string vsn;
348  std::string relname;
349  std::string canFilename;
350  is >> vsn;
351  if (!is) return;
352  bool oldFormat = (version != vsn);
353  if (oldFormat) {
354  relname = vsn;
355  bool local;
356  is >> local;
357  location_ = (local ? Local : Release);
358  is >> canFilename;
359  } else {
360  // Current format
361  int loc;
362  is >> relname >> loc;
363  location_ = static_cast<FileInPath::LocationCode>(loc);
364  if (location_ != Unknown) is >> canFilename;
365  }
366  if (!is) return;
367  relativePath_ = relname;
368  if (location_ == Local) {
369  if (localTop_.empty()) {
370  localTop_ = "@LOCAL";
371  }
372  if (oldFormat) {
373  canonicalFilename_ = canFilename;
374  } else
375  canonicalFilename_ = localTop_ + canFilename;
376  } else if (location_ == Release) {
377  if (releaseTop_.empty()) {
378  releaseTop_="@RELEASE";
379  }
380  if (oldFormat) {
381  std::string::size_type pos = canFilename.find(BASE);
382  if (pos == 0) {
383  // Replace the placehoder with the path to the base release (site dependent).
384  canonicalFilename_ = releaseTop_ + canFilename.substr(BASE.size());
385  } else {
386  // Needed for files written before CMSSW_1_2_0_pre2.
387  canonicalFilename_ = canFilename;
388  }
389  } else
390  canonicalFilename_ = releaseTop_ + canFilename;
391  } else if (location_ == Data) {
392  if (dataTop_.empty()) {
394  << "Environment Variable "
395  << DATATOP
396  << " is not set.\n";
397  }
398  canonicalFilename_ = dataTop_ + canFilename;
399  }
400  }
401 
402  //------------------------------------------------------------
403 
404 
405  void
407  static std::string const searchPath = removeSymLinksTokens(PathVariableName);
408  if (searchPath.empty()) {
410  << PathVariableName
411  << " must be defined\n";
412  }
413  searchPath_ = searchPath;
414 
415  static std::string const releaseTop = removeSymLinksSrc(RELEASETOP);
416  releaseTop_ = releaseTop;
417 
418  static std::string const localTop = removeSymLinksSrc(LOCALTOP);
419  localTop_ = localTop;
420 
421  static std::string const dataTop = removeSymLinks(DATATOP);
422  dataTop_ = dataTop;
423 
424  if (releaseTop_.empty()) {
425  // RELEASETOP was not set. This means that the environment is set
426  // for the base release itself. So LOCALTOP actually contains the
427  // location of the base release.
429  localTop_.clear();
430  }
431  if (releaseTop_ == localTop_) {
432  // RELEASETOP is the same as LOCALTOP. This means that the environment is set
433  // for the base release itself. So LOCALTOP actually contains the
434  // location of the base release.
435  localTop_.clear();
436  }
437  }
438 
439  void
441  if (relativePath_.empty()) {
443  << "Relative path must not be empty\n";
444  }
445 
446  // Find the file, based on the value of path variable.
447  typedef std::vector<std::string> stringvec_t;
448  stringvec_t pathElements = tokenize(searchPath_, ":");
449  for(auto const& element : pathElements) {
450  // Set the boost::fs path to the current element of
451  // CMSSW_SEARCH_PATH:
452  bf::path pathPrefix(element);
453 
454  // Does the a file exist? locateFile throws is it finds
455  // something goofy.
456  if (locateFile(pathPrefix, relativePath_)) {
457  // Convert relative path to canonical form, and save it.
458  relativePath_ = bf::path(relativePath_).normalize().string();
459 
460  // Save the absolute path.
461  canonicalFilename_ = bf::absolute(relativePath_, pathPrefix).string();
462  if (canonicalFilename_.empty()) {
464  << "fullPath is empty"
465  << "\nrelativePath() is: " << relativePath_
466  << "\npath prefix is: " << pathPrefix.string()
467  << '\n';
468  }
469 
470  // From the current path element, find the branch path (basically the path minus the
471  // last directory, e.g. /src or /share):
472  for (bf::path br = pathPrefix.branch_path(); !br.normalize().string().empty(); br = br.branch_path()) {
473 
474  if (!localTop_.empty()) {
475  // Create a path object for our local path LOCALTOP:
476  bf::path local_(localTop_);
477  // If the branch path matches the local path, the file was found locally:
478  if (br == local_) {
479  location_ = Local;
480  return;
481  }
482  }
483 
484  if (!releaseTop_.empty()) {
485  // Create a path object for our release path RELEASETOP:
486  bf::path release_(releaseTop_);
487  // If the branch path matches the release path, the file was found in the release:
488  if (br == release_) {
489  location_ = Release;
490  return;
491  }
492  }
493 
494  if (!dataTop_.empty()) {
495  // Create a path object for our data path DATATOP:
496  bf::path data_(dataTop_);
497  // If the branch path matches the data path, the file was found in the data area:
498  if (br == data_) {
499  location_ = Data;
500  return;
501  }
502  }
503  }
504  }
505  }
506 
507  // If we got here, we ran out of path elements without finding
508  // what we're looking found.
510  << "edm::FileInPath unable to find file "
511  << relativePath_
512  << " anywhere in the search path."
513  << "\nThe search path is defined by: "
514  << PathVariableName
515  << "\n${"
516  << PathVariableName
517  << "} is: "
518  << getenv(PathVariableName.c_str())
519  << "\nCurrent directory is: "
520  << bf::initial_path().string()
521  << "\n";
522  }
523 
525  s_fileLookupDisabled = true;
526  }
527 
528 }
529 
std::string canonicalFilename_
Definition: FileInPath.h:125
void write(std::ostream &os) const
Definition: FileInPath.cc:203
void swap(FileInPath &other)
Definition: FileInPath.cc:172
static void disableFileLookup()
Should only be called while the edmWriteConfigs executable runs.
Definition: FileInPath.cc:524
std::string dataTop_
Definition: FileInPath.h:129
void getEnvironment()
Definition: FileInPath.cc:406
std::string searchPath_
Definition: FileInPath.h:130
uint16_t size_type
std::string releaseTop_
Definition: FileInPath.h:128
LocationCode location_
Definition: FileInPath.h:126
void read(std::istream &is)
Definition: FileInPath.cc:266
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
LocationCode location() const
Where was the file found?
Definition: FileInPath.cc:191
void initialize_()
Definition: FileInPath.cc:440
std::string relativePath_
Definition: FileInPath.h:124
HLT enums.
FileInPath & operator=(FileInPath const &other)
Definition: FileInPath.cc:164
std::string fullPath() const
Definition: FileInPath.cc:197
void readFromParameterSetBlob(std::istream &is)
Definition: FileInPath.cc:345
std::string relativePath() const
Definition: FileInPath.cc:184
void resolveSymbolicLinks(std::string &fullPath)
std::string localTop_
Definition: FileInPath.h:127
std::vector< std::string > tokenize(std::string const &input, std::string const &separator)
breaks the input string into tokens, delimited by the separator