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