CMS 3D CMS Logo

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