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  std::atomic<bool> s_fileLookupDisabled{false};
20 
24 
25  const std::string PathVariableName("CMSSW_SEARCH_PATH");
26  // Environment variables for local and release areas:
27  const std::string LOCALTOP("CMSSW_BASE");
28  const std::string RELEASETOP("CMSSW_RELEASE_BASE");
29  const std::string DATATOP("CMSSW_DATA_PATH");
30 
31 #if 1
32  // Needed for backward compatibility prior to CMSSW_1_5_0_pre3.
33  // String to serve as placeholder for release top.
34  // Do not change this value.
35  const std::string BASE("BASE");
36 #endif
37  const std::string version("V001");
38 
39  // Remove symlinks from path
40  std::string removeSymLinks(std::string const& envName) {
41  char const* const var = std::getenv(envName.c_str());
42  if (var == nullptr) {
43  return std::string();
44  }
47  return path;
48  }
49 
50  std::string removeSymLinksSrc(std::string const& envName) {
51  char const* const var = std::getenv(envName.c_str());
52  if (var == nullptr) {
53  return std::string();
54  }
55  std::string const src = "/src";
56  std::string path = var + src;
58  size_t actualSize = path.size() - src.size();
59  assert(path.substr(actualSize, src.size()) == src);
60  return path.substr(0, actualSize);
61  }
62 
63  std::string removeSymLinksTokens(std::string const& envName) {
64  char const* const var = std::getenv(envName.c_str());
65  if (var == nullptr) {
66  return std::string();
67  }
68  std::string theSearchPath;
69  typedef std::vector<std::string> stringvec_t;
70  stringvec_t pathElements = edm::tokenize(std::string(var), ":");
71  for (auto& element : pathElements) {
73  if (!theSearchPath.empty())
74  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, std::string const& relative) {
87  p /= relative;
88 
89  if (!bf::exists(p))
90  return false;
91 
92  if (bf::is_directory(p)) {
93  throw edm::Exception(edm::errors::FileInPathError) << "Path " << p.string() << " is a directory, not a file\n";
94  }
95 
96  if (bf::is_symlink(bf::symlink_status(p))) {
98  << "Path " << p.string() << " is a symbolic link, not a file\n";
99  }
100  return true;
101  }
102 } // namespace
103 
104 namespace edm {
105 
106  FileInPath::FileInPath() : relativePath_(), canonicalFilename_(), location_(Unknown) {
107  if (s_fileLookupDisabled) {
108  return;
109  }
110  getEnvironment();
111  }
112 
114  if (s_fileLookupDisabled) {
115  return;
116  }
117  getEnvironment();
118  initialize_();
119  }
120 
122  if (s_fileLookupDisabled) {
123  return;
124  }
125  if (r == nullptr) {
126  throw edm::Exception(edm::errors::FileInPathError) << "Relative path must not be null\n";
127  }
128  getEnvironment();
129  initialize_();
130  }
131 
133  : relativePath_(other.relativePath_),
135  location_(other.location_),
136  localTop_(other.localTop_),
137  releaseTop_(other.releaseTop_),
138  dataTop_(other.dataTop_),
139  searchPath_(other.searchPath_) {}
140 
142 
144  FileInPath temp(other);
145  this->swap(temp);
146  return *this;
147  }
148 
150  relativePath_.swap(other.relativePath_);
152  std::swap(location_, other.location_);
153  localTop_.swap(other.localTop_);
154  releaseTop_.swap(other.releaseTop_);
155  dataTop_.swap(other.dataTop_);
156  searchPath_.swap(other.searchPath_);
157  }
158 
160 
162 
164 
165  void FileInPath::write(std::ostream& os) const {
166  if (location_ == Unknown) {
167  os << version << ' ' << relativePath_ << ' ' << location_;
168  } else if (location_ == Local) {
169  // Guarantee a site independent value by stripping $LOCALTOP.
170  if (localTop_.empty()) {
171  throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << LOCALTOP << " is not set.\n";
172  }
174  if (pos != 0) {
176  << "Path " << canonicalFilename_ << " is not in the local release area " << localTop_ << "\n";
177  }
178  os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(localTop_.size());
179  } else if (location_ == Release) {
180  // Guarantee a site independent value by stripping $RELEASETOP.
181  if (releaseTop_.empty()) {
182  throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << RELEASETOP << " is not set.\n";
183  }
185  if (pos != 0) {
187  << "Path " << canonicalFilename_ << " is not in the base release area " << releaseTop_ << "\n";
188  }
189  os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(releaseTop_.size());
190  } else if (location_ == Data) {
191  // Guarantee a site independent value by stripping $DATATOP.
192  if (dataTop_.empty()) {
193  throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << DATATOP << " is not set.\n";
194  }
196  if (pos != 0) {
198  << "Path " << canonicalFilename_ << " is not in the data area " << dataTop_ << "\n";
199  }
200  os << version << ' ' << relativePath_ << ' ' << location_ << ' ' << canonicalFilename_.substr(dataTop_.size());
201  }
202  }
203 
204  void FileInPath::read(std::istream& is) {
205  std::string vsn;
206  std::string relname;
207  std::string canFilename;
208 #if 1
209  // This #if needed for backward compatibility
210  // for files written before CMSSW_1_5_0_pre3.
211  is >> vsn;
212  if (!is)
213  return;
214  bool oldFormat = (version != vsn);
215  if (oldFormat) {
216  relname = vsn;
217  bool local;
218  is >> local;
219  location_ = (local ? Local : Release);
220  is >> canFilename;
221  } else {
222  // Current format
223  int loc;
224  is >> relname >> loc;
225  location_ = static_cast<FileInPath::LocationCode>(loc);
226  if (location_ != Unknown)
227  is >> canFilename;
228  }
229 #else
230  is >> vsn >> relname >> loc >> canFilename;
231 #endif
232  if (!is)
233  return;
234  relativePath_ = relname;
235  if (location_ == Local) {
236  if (localTop_.empty()) {
237  throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << LOCALTOP << " is not set.\n"
238  << "Trying to read Local file: " << canFilename << ".\n";
239  }
240 #if 1
241  // This #if needed for backward compatibility
242  // for files written before CMSSW_1_5_0_pre3.
243  if (oldFormat) {
244  canonicalFilename_ = canFilename;
245  } else
246 #endif
247  canonicalFilename_ = localTop_ + canFilename;
248  } else if (location_ == Release) {
249  if (releaseTop_.empty()) {
250  throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << RELEASETOP << " is not set.\n";
251  }
252 #if 1
253  // This #if needed for backward compatibility
254  // for files written before CMSSW_1_5_0_pre3.
255  if (oldFormat) {
256  std::string::size_type pos = canFilename.find(BASE);
257  if (pos == 0) {
258  // Replace the placehoder with the path to the base release (site dependent).
259  canonicalFilename_ = releaseTop_ + canFilename.substr(BASE.size());
260  } else {
261  // Needed for files written before CMSSW_1_2_0_pre2.
262  canonicalFilename_ = canFilename;
263  }
264  } else
265 #endif
266  canonicalFilename_ = releaseTop_ + canFilename;
267  } else if (location_ == Data) {
268  if (dataTop_.empty()) {
269  throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << DATATOP << " is not set.\n";
270  }
271  canonicalFilename_ = dataTop_ + canFilename;
272  }
273  }
274 
275  void FileInPath::readFromParameterSetBlob(std::istream& is) {
276  std::string vsn;
277  std::string relname;
278  std::string canFilename;
279  is >> vsn;
280  if (!is)
281  return;
282  bool oldFormat = (version != vsn);
283  if (oldFormat) {
284  relname = vsn;
285  bool local;
286  is >> local;
287  location_ = (local ? Local : Release);
288  is >> canFilename;
289  } else {
290  // Current format
291  int loc;
292  is >> relname >> loc;
293  location_ = static_cast<FileInPath::LocationCode>(loc);
294  if (location_ != Unknown)
295  is >> canFilename;
296  }
297  if (!is)
298  return;
299  relativePath_ = relname;
300  if (location_ == Local) {
301  if (localTop_.empty()) {
302  localTop_ = "@LOCAL";
303  }
304  if (oldFormat) {
305  canonicalFilename_ = canFilename;
306  } else
307  canonicalFilename_ = localTop_ + canFilename;
308  } else if (location_ == Release) {
309  if (releaseTop_.empty()) {
310  releaseTop_ = "@RELEASE";
311  }
312  if (oldFormat) {
313  std::string::size_type pos = canFilename.find(BASE);
314  if (pos == 0) {
315  // Replace the placehoder with the path to the base release (site dependent).
316  canonicalFilename_ = releaseTop_ + canFilename.substr(BASE.size());
317  } else {
318  // Needed for files written before CMSSW_1_2_0_pre2.
319  canonicalFilename_ = canFilename;
320  }
321  } else
322  canonicalFilename_ = releaseTop_ + canFilename;
323  } else if (location_ == Data) {
324  if (dataTop_.empty()) {
325  throw edm::Exception(edm::errors::FileInPathError) << "Environment Variable " << DATATOP << " is not set.\n";
326  }
327  canonicalFilename_ = dataTop_ + canFilename;
328  }
329  }
330 
331  //------------------------------------------------------------
332 
334  static std::string const searchPath = removeSymLinksTokens(PathVariableName);
335  if (searchPath.empty()) {
336  throw edm::Exception(edm::errors::FileInPathError) << PathVariableName << " must be defined\n";
337  }
338  searchPath_ = searchPath;
339 
340  static std::string const releaseTop = removeSymLinksSrc(RELEASETOP);
341  releaseTop_ = releaseTop;
342 
343  static std::string const localTop = removeSymLinksSrc(LOCALTOP);
344  localTop_ = localTop;
345 
346  static std::string const dataTop = removeSymLinks(DATATOP);
347  dataTop_ = dataTop;
348 
349  if (releaseTop_.empty()) {
350  // RELEASETOP was not set. This means that the environment is set
351  // for the base release itself. So LOCALTOP actually contains the
352  // location of the base release.
354  localTop_.clear();
355  }
356  if (releaseTop_ == localTop_) {
357  // RELEASETOP is the same as LOCALTOP. This means that the environment is set
358  // for the base release itself. So LOCALTOP actually contains the
359  // location of the base release.
360  localTop_.clear();
361  }
362  }
363 
365  if (relativePath_.empty()) {
366  throw edm::Exception(edm::errors::FileInPathError) << "Relative path must not be empty\n";
367  }
368 
369  // Find the file, based on the value of path variable.
370  typedef std::vector<std::string> stringvec_t;
371  stringvec_t pathElements = tokenize(searchPath_, ":");
372  for (auto const& element : pathElements) {
373  // Set the boost::fs path to the current element of
374  // CMSSW_SEARCH_PATH:
375  bf::path pathPrefix(element);
376 
377  // Does the a file exist? locateFile throws is it finds
378  // something goofy.
379  if (locateFile(pathPrefix, relativePath_)) {
380  // Convert relative path to canonical form, and save it.
381  relativePath_ = bf::path(relativePath_).normalize().string();
382 
383  // Save the absolute path.
384  canonicalFilename_ = bf::absolute(relativePath_, pathPrefix).string();
385  if (canonicalFilename_.empty()) {
387  << "fullPath is empty"
388  << "\nrelativePath() is: " << relativePath_ << "\npath prefix is: " << pathPrefix.string() << '\n';
389  }
390 
391  // From the current path element, find the branch path (basically the path minus the
392  // last directory, e.g. /src or /share):
393  for (bf::path br = pathPrefix.branch_path(); !br.normalize().string().empty(); br = br.branch_path()) {
394  if (!localTop_.empty()) {
395  // Create a path object for our local path LOCALTOP:
396  bf::path local_(localTop_);
397  // If the branch path matches the local path, the file was found locally:
398  if (br == local_) {
399  location_ = Local;
400  return;
401  }
402  }
403 
404  if (!releaseTop_.empty()) {
405  // Create a path object for our release path RELEASETOP:
406  bf::path release_(releaseTop_);
407  // If the branch path matches the release path, the file was found in the release:
408  if (br == release_) {
409  location_ = Release;
410  return;
411  }
412  }
413 
414  if (!dataTop_.empty()) {
415  // Create a path object for our data path DATATOP:
416  bf::path data_(dataTop_);
417  // If the branch path matches the data path, the file was found in the data area:
418  if (br == data_) {
419  location_ = Data;
420  return;
421  }
422  }
423  }
424  }
425  }
426 
427  // If we got here, we ran out of path elements without finding
428  // what we're looking found.
430  << "edm::FileInPath unable to find file " << relativePath_ << " anywhere in the search path."
431  << "\nThe search path is defined by: " << PathVariableName << "\n${" << PathVariableName
432  << "} is: " << std::getenv(PathVariableName.c_str())
433  << "\nCurrent directory is: " << bf::initial_path().string() << "\n";
434  }
435 
436  void FileInPath::disableFileLookup() { s_fileLookupDisabled = true; }
437 
438 } // namespace edm
std::string canonicalFilename_
Definition: FileInPath.h:114
void write(std::ostream &os) const
Definition: FileInPath.cc:165
void swap(FileInPath &other)
Definition: FileInPath.cc:149
static void disableFileLookup()
Should only be called while the edmWriteConfigs executable runs.
Definition: FileInPath.cc:436
std::string dataTop_
Definition: FileInPath.h:118
void getEnvironment()
Definition: FileInPath.cc:333
std::string searchPath_
Definition: FileInPath.h:119
uint16_t size_type
std::string releaseTop_
Definition: FileInPath.h:117
LocationCode location_
Definition: FileInPath.h:115
void read(std::istream &is)
Definition: FileInPath.cc:204
void swap(edm::DataFrameContainer &lhs, edm::DataFrameContainer &rhs)
LocationCode location() const
Where was the file found?
Definition: FileInPath.cc:161
void initialize_()
Definition: FileInPath.cc:364
std::string relativePath_
Definition: FileInPath.h:113
HLT enums.
FileInPath & operator=(FileInPath const &other)
Definition: FileInPath.cc:143
std::string fullPath() const
Definition: FileInPath.cc:163
void readFromParameterSetBlob(std::istream &is)
Definition: FileInPath.cc:275
std::string relativePath() const
Definition: FileInPath.cc:159
void resolveSymbolicLinks(std::string &fullPath)
std::string localTop_
Definition: FileInPath.h:116
std::vector< std::string > tokenize(std::string const &input, std::string const &separator)
breaks the input string into tokens, delimited by the separator