Mantid
Loading...
Searching...
No Matches
FileFinder.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
17#include "MantidKernel/Glob.h"
20
22#include <Poco/Exception.h>
23#include <Poco/File.h>
24#include <Poco/Path.h>
25#include <boost/lexical_cast.hpp>
26#include <boost/regex.hpp>
27
28#include <algorithm>
29#include <cctype>
30
31#include <boost/algorithm/string.hpp>
32
33namespace {
35Mantid::Kernel::Logger g_log("FileFinder");
36
45bool containsWildCard(const std::string &ext) { return std::string::npos != ext.find('*'); }
46
47bool isASCII(const std::string &str) {
48 return !std::any_of(str.cbegin(), str.cend(), [](char c) { return static_cast<unsigned char>(c) > 127; });
49}
50
51} // namespace
52
53namespace Mantid::API {
54using std::string;
55
56// this allowed string could be made into an array of allowed, currently used
57// only by the ISIS SANS group
58const std::string FileFinderImpl::ALLOWED_SUFFIX = "-add";
59//----------------------------------------------------------------------
60// Public member functions
61//----------------------------------------------------------------------
66 // Make sure plugins are loaded
67 FrameworkManager::Instance().loadPlugins();
68
69// determine from Mantid property how sensitive Mantid should be
70#ifdef _WIN32
71 m_globOption = Poco::Glob::GLOB_DEFAULT;
72#else
73 setCaseSensitive(Kernel::ConfigService::Instance().getValue<bool>("filefinder.casesensitive").get_value_or(false));
74#endif
75}
76
82 if (cs)
83 m_globOption = Poco::Glob::GLOB_DEFAULT;
84 else
85 m_globOption = Poco::Glob::GLOB_CASELESS;
86}
87
93bool FileFinderImpl::getCaseSensitive() const { return (m_globOption == Poco::Glob::GLOB_DEFAULT); }
94
105std::string FileFinderImpl::getFullPath(const std::string &filename, const bool ignoreDirs) const {
106 return Kernel::ConfigService::Instance().getFullPath(filename, ignoreDirs, m_globOption);
107}
108
114std::string FileFinderImpl::extractAllowedSuffix(std::string &userString) const {
115 if (userString.find(ALLOWED_SUFFIX) == std::string::npos) {
116 // short cut processing as normally there is no suffix
117 return "";
118 }
119
120 // ignore any file extension in checking if a suffix is present
121 Poco::Path entry(userString);
122 std::string noExt(entry.getBaseName());
123 const size_t repNumChars = ALLOWED_SUFFIX.size();
124 if (noExt.find(ALLOWED_SUFFIX) == noExt.size() - repNumChars) {
125 userString.replace(userString.size() - repNumChars, repNumChars, "");
126 return ALLOWED_SUFFIX;
127 }
128 return "";
129}
130
138 if ((!hint.empty()) && (!isdigit(hint[0]))) {
139 string instrName(hint);
140 Poco::Path path(instrName);
141 instrName = path.getFileName();
142 if ((instrName.find("PG3") == 0) || (instrName.find("pg3") == 0)) {
143 instrName = "PG3";
144 }
145 // We're extending this nasty hack to accomodate data archive searching for
146 // SANS2D.
147 // While this certainly shouldn't be considered good practice, #7515 exists
148 // to
149 // completely redesign FileFinder -- this quick fix will have to do until
150 // all this
151 // code gets an overhaul as part of that ticket. Please think twice before
152 // adding
153 // any more instruments to this list.
154 else if ((instrName.find("SANS2D") == 0) || (instrName.find("sans2d") == 0)) {
155 instrName = "SANS2D";
156 } else {
157 // go forwards looking for the run number to start
158 {
159 const auto it = std::find_if(instrName.begin(), instrName.end(), isdigit);
160 const auto nChars = std::distance(instrName.begin(), it);
161 instrName = instrName.substr(0, nChars);
162 }
163
164 // go backwards looking for the instrument name to end - gets around
165 // delimiters
166 if (!instrName.empty()) {
167 const auto it = std::find_if(instrName.rbegin(), instrName.rend(), isalpha);
168 const auto nChars = std::distance(it, instrName.rend());
169 instrName = instrName.substr(0, nChars);
170 }
171 }
172 try {
173 const Kernel::InstrumentInfo instrument = Kernel::ConfigService::Instance().getInstrument(instrName);
174 return instrument;
176 g_log.debug() << e.what() << "\n";
177 }
178 }
179 return Kernel::ConfigService::Instance().getInstrument();
180}
181
187std::pair<std::string, std::string> FileFinderImpl::toInstrumentAndNumber(const std::string &hint) const {
188 // g_log.debug() << "toInstrumentAndNumber(" << hint << ")\n";
189 std::string instrPart;
190 std::string runPart;
191
192 if (isdigit(hint[0])) {
193 instrPart = Kernel::ConfigService::Instance().getInstrument().shortName();
194 runPart = hint;
195 } else {
197 std::string::const_reverse_iterator it = std::find_if(hint.rbegin(), hint.rend(), std::not_fn(isdigit));
198 // No non-digit or all non-digits
199 if (it == hint.rend() || it == hint.rbegin()) {
200 throw std::invalid_argument("Malformed hint to FileFinderImpl::makeFileName: " + hint);
201 }
202 std::string::size_type nChars = std::distance(it, hint.rend());
203
204 // Add in special test for PG3
205 if (boost::algorithm::istarts_with(hint, "PG3")) {
206 instrPart = "PG3";
207 nChars = instrPart.length();
208 }
209 // Another nasty check for SANS2D. Will do until FileFinder redesign.
210 else if (boost::algorithm::istarts_with(hint, "SANS2D")) {
211 instrPart = "SANS2D";
212 nChars = instrPart.length();
213 } else {
214 instrPart = hint.substr(0, nChars);
215 }
216
217 runPart = hint.substr(nChars);
218 }
219
220 unsigned int irunPart(0);
221 try {
222 irunPart = boost::lexical_cast<unsigned int>(runPart);
223 } catch (boost::bad_lexical_cast &) {
224 std::ostringstream os;
225 os << "Cannot convert '" << runPart << "' to run number.";
226 throw std::invalid_argument(os.str());
227 }
228 Kernel::InstrumentInfo instr = Kernel::ConfigService::Instance().getInstrument(instrPart);
229 size_t nZero = instr.zeroPadding(irunPart);
230 // remove any leading zeros in case there are too many of them
231 std::string::size_type i = runPart.find_first_not_of('0');
232 runPart.erase(0, i);
233 while (runPart.size() < nZero)
234 runPart.insert(0, "0");
235 if (runPart.size() > nZero && nZero != 0) {
236 throw std::invalid_argument("Run number does not match instrument's zero padding");
237 }
238
239 instrPart = instr.filePrefix(irunPart);
240
241 return std::make_pair(instrPart, runPart);
242}
243
256std::string FileFinderImpl::makeFileName(const std::string &hint, const Kernel::InstrumentInfo &instrument) const {
257 // g_log.debug() << "makeFileName(" << hint << ", " << instrument.shortName()
258 // << ")\n";
259 if (hint.empty())
260 return "";
261
262 std::string filename(hint);
263 const std::string suffix = extractAllowedSuffix(filename);
264 const std::string shortName = instrument.shortName();
265 std::string delimiter = instrument.delimiter();
266
267 // see if starts with the provided instrument name
268 if (filename.substr(0, shortName.size()) == shortName) {
269 filename = filename.substr(shortName.size());
270 if ((!delimiter.empty()) && (filename.substr(0, delimiter.size()) == delimiter))
271 filename = filename.substr(delimiter.size());
272
273 filename = shortName + filename;
274 }
275
276 std::pair<std::string, std::string> p = toInstrumentAndNumber(filename);
277
278 filename = p.first;
279 if (!delimiter.empty()) {
280 filename += delimiter;
281 }
282 filename += p.second;
283
284 if (!suffix.empty()) {
285 filename += suffix;
286 }
287
288 return filename;
289}
290
300std::string FileFinderImpl::getExtension(const std::string &filename, const std::vector<std::string> &exts) const {
301 g_log.debug() << "getExtension(" << filename << ", exts[" << exts.size() << "])\n";
302
303 // go through the list of supplied extensions
304 for (const auto &ext : exts) {
305 std::string extension = toUpper(ext);
306 if (extension.rfind('*') == extension.size() - 1) // there is a wildcard at play
307 {
308 extension = extension.substr(0, extension.rfind('*'));
309 }
310
311 std::size_t found = toUpper(filename).rfind(extension);
312 if (found != std::string::npos) {
313 g_log.debug() << "matched extension \"" << extension << "\" based on \"" << ext << "\"\n";
314 return filename.substr(found); // grab the actual extensions found
315 }
316 }
317
318 g_log.debug() << "Failed to find extension. Just using last \'.\'\n";
319 std::size_t pos = filename.find_last_of('.');
320 if (pos != std::string::npos) {
321 return filename.substr(pos);
322 }
323
324 // couldn't find an extension
325 return "";
326}
327
328std::vector<IArchiveSearch_sptr> FileFinderImpl::getArchiveSearch(const Kernel::FacilityInfo &facility) const {
329 std::vector<IArchiveSearch_sptr> archs;
330
331 // get the searchive option from config service and format it
332 std::string archiveOpt = Kernel::ConfigService::Instance().getString("datasearch.searcharchive");
333 std::transform(archiveOpt.begin(), archiveOpt.end(), archiveOpt.begin(), tolower);
334
335 // if it is turned off, not specified, or the facility doesn't have
336 // IArchiveSearch defined, return an empty vector
337 if (archiveOpt.empty() || archiveOpt == "off" || facility.archiveSearch().empty())
338 return archs;
339
340 // determine if the user wants archive search for this facility
341 auto createArchiveSearch = bool(archiveOpt == "all");
342
343 // then see if the facility name appears in the list or if we just want the
344 // default facility
345 if (!createArchiveSearch) {
346 std::string faciltyName = facility.name();
347 std::transform(faciltyName.begin(), faciltyName.end(), faciltyName.begin(), tolower);
348 if (archiveOpt == "on") { // only default facilty
349 std::string defaultFacility = Kernel::ConfigService::Instance().getString("default.facility");
350 std::transform(defaultFacility.begin(), defaultFacility.end(), defaultFacility.begin(), tolower);
351 createArchiveSearch = bool(faciltyName == defaultFacility);
352 } else { // everything in the list
353 createArchiveSearch = bool(archiveOpt.find(faciltyName) != std::string::npos);
354 }
355 }
356
357 // put together the list of IArchiveSearch to use
358 if (createArchiveSearch) {
359 for (const auto &facilityname : facility.archiveSearch()) {
360 g_log.debug() << "get archive search for the facility..." << facilityname << "\n";
361 archs.emplace_back(ArchiveSearchFactory::Instance().create(facilityname));
362 }
363 }
364 return archs;
365}
366
367std::string FileFinderImpl::findRun(const std::string &hintstr, const std::vector<std::string> &exts,
368 const bool useExtsOnly) const {
369 std::string hint = Kernel::Strings::strip(hintstr);
370 g_log.debug() << "vector findRun(\'" << hint << "\', exts[" << exts.size() << "])\n";
371
372 // if partial filename or run number is not supplied, return here
373 if (hint.empty())
374 return "";
375
376 // if it looks like a full filename just do a quick search for it
377 Poco::Path hintPath(hint);
378 if (!hintPath.getExtension().empty()) {
379 // check in normal search locations
380 g_log.debug() << "hintPath is not empty, check in normal search locations"
381 << "\n";
382 std::string path = getFullPath(hint);
383 if (!path.empty()) {
384 try {
385 if (Poco::File(path).exists()) {
386 g_log.information() << "found path = " << path << '\n';
387 return path;
388 }
389 } catch (Poco::Exception &) {
390 }
391 } else {
392 g_log.debug() << "Unable to find files via directory search with the "
393 "filename that looks like a full filename"
394 << "\n";
395 }
396 }
397
398 // get instrument and facility
399 const Kernel::InstrumentInfo instrument = this->getInstrument(hint);
400 const Kernel::FacilityInfo &facility = instrument.facility();
401 // get facility extensions
402 const std::vector<std::string> facility_extensions = facility.extensions();
403 // select allowed extensions
404 std::vector<std::string> extensions;
405
406 g_log.debug() << "Add facility extensions defined in the Facility.xml file"
407 << "\n";
408 extensions.assign(facility_extensions.begin(), facility_extensions.end());
409
410 // Do we need to try and form a filename from our preset rules
411 std::string filename(hint);
412 std::string extension = getExtension(hint, extensions);
413 if (!extensions.empty())
414 filename = hint.substr(0, hint.rfind(extension));
415 if (hintPath.depth() == 0) {
416 try {
417 if (!facility.noFilePrefix()) {
418 filename = makeFileName(filename, instrument);
419 }
420 } catch (std::invalid_argument &) {
421 if (filename.length() >= hint.length()) {
422 g_log.information() << "Could not form filename from standard rules '" << filename << "'\n";
423 }
424 }
425 }
426
427 if (filename.empty())
428 return "";
429
430 // Look first at the original filename then for case variations. This is
431 // important
432 // on platforms where file names ARE case sensitive.
433 // Sorry for the duplication, a last minute fix was required. Ticket #6419 is
434 // tasked with a redesign of
435 // the whole file finding concept.
436
437 std::set<std::string> filenames;
438 filenames.insert(filename);
439 if (!getCaseSensitive()) {
440 std::string transformed(filename);
441 std::transform(filename.begin(), filename.end(), transformed.begin(), toupper);
442 filenames.insert(transformed);
443 std::transform(filename.begin(), filename.end(), transformed.begin(), tolower);
444 filenames.insert(transformed);
445 }
446
447 // Merge the extensions & throw out duplicates
448 // On Windows throw out ones that only vary in case
449 std::vector<std::string> uniqueExts;
450 uniqueExts.reserve(1 + exts.size() + extensions.size());
451 if (!extension.empty())
452 uniqueExts.emplace_back(extension);
453
454 // If provided exts are empty, or useExtsOnly is false,
455 // we want to include facility exts as well
456 getUniqueExtensions(exts, uniqueExts);
457 if (exts.empty() || !useExtsOnly) {
458 getUniqueExtensions(extensions, uniqueExts);
459 }
460
461 // determine which archive search facilities to use
462 std::vector<IArchiveSearch_sptr> archs = getArchiveSearch(facility);
463
464 std::string path = getPath(archs, filenames, uniqueExts);
465 if (!path.empty()) {
466 g_log.information() << "found path = " << path << '\n';
467 return path;
468 } else {
469 g_log.information() << "Unable to find run with hint " << hint << "\n";
470 }
471
472 g_log.information() << "Unable to find file path for " << hint << "\n";
473
474 return "";
475}
476
485void FileFinderImpl::getUniqueExtensions(const std::vector<std::string> &extensionsToAdd,
486 std::vector<std::string> &uniqueExts) const {
487 const bool isCaseSensitive = getCaseSensitive();
488 for (const auto &cit : extensionsToAdd) {
489 std::string transformed(cit);
490 if (!isCaseSensitive) {
491 std::transform(cit.begin(), cit.end(), transformed.begin(), tolower);
492 }
493 const auto searchItr = std::find(uniqueExts.begin(), uniqueExts.end(), transformed);
494 if (searchItr == uniqueExts.end()) {
495 uniqueExts.emplace_back(transformed);
496 }
497 }
498}
499
506std::string FileFinderImpl::validateRuns(const std::string &searchText) const {
507 if (!isASCII(searchText))
508 return "An unsupported non-ASCII character was found in the search text.";
509 return "";
510}
511
527std::vector<std::string> FileFinderImpl::findRuns(const std::string &hintstr, const std::vector<std::string> &exts,
528 const bool useExtsOnly) const {
529 auto const error = validateRuns(hintstr);
530 if (!error.empty())
531 throw std::invalid_argument(error);
532
533 std::string hint = Kernel::Strings::strip(hintstr);
534 g_log.debug() << "findRuns hint = " << hint << "\n";
535 std::vector<std::string> res;
538 static const boost::regex digits("[0-9]+");
539 auto h = hints.begin();
540
541 std::string instrSName;
542 for (; h != hints.end(); ++h) {
543 // Quick check for a filename
544 bool fileSuspected = false;
545 // Assume if the hint contains either a "/" or "\" it is a filename..
546 if ((*h).find("\\") != std::string::npos) {
547 fileSuspected = true;
548 }
549 if ((*h).find("/") != std::string::npos) {
550 fileSuspected = true;
551 }
552 if ((*h).find(ALLOWED_SUFFIX) != std::string::npos) {
553 fileSuspected = true;
554 }
555
558 if ((range.count() > 2) && (!fileSuspected)) {
559 throw std::invalid_argument("Malformed range of runs: " + *h);
560 } else if ((range.count() == 2) && (!fileSuspected)) {
561 std::pair<std::string, std::string> p1 = toInstrumentAndNumber(range[0]);
562 if (boost::algorithm::istarts_with(hint, "PG3")) {
563 instrSName = "PG3";
564 }
565 std::string run = p1.second;
566 size_t nZero = run.size(); // zero padding
567 if (range[1].size() > nZero) {
568 throw std::invalid_argument("Malformed range of runs: " + *h +
569 ". The end of string value is longer than "
570 "the instrument's zero padding");
571 }
572 auto runNumber = boost::lexical_cast<int>(run);
573 std::string runEnd = run;
574 // Adds zero padding to end of range.
575 runEnd.replace(runEnd.end() - range[1].size(), runEnd.end(), range[1]);
576
577 // Throw if runEnd contains something else other than a digit.
578 if (!boost::regex_match(runEnd, digits))
579 throw std::invalid_argument("Malformed range of runs: Part of the run "
580 "has a non-digit character in it.");
581
582 auto runEndNumber = boost::lexical_cast<int>(runEnd);
583 if (runEndNumber < runNumber) {
584 throw std::invalid_argument("Malformed range of runs: " + *h);
585 }
586 std::string previousPath, previousExt;
587 for (int irun = runNumber; irun <= runEndNumber; ++irun) {
588 run = std::to_string(irun);
589 while (run.size() < nZero)
590 run.insert(0, "0");
591
592 // Quick check if file can be created from previous successfully found
593 // path/extension
594 if (!previousPath.empty() && !previousExt.empty()) {
595 try {
596 const Poco::File file(previousPath + p1.first + run + previousExt);
597 if (file.exists()) {
598 res.emplace_back(file.path());
599 continue;
600 }
601 } catch (...) {
602 // Clear cached path and extension
603 previousPath = previousExt = "";
604 }
605 }
606
607 std::string path;
608 if (boost::algorithm::istarts_with(hint, "PG3")) {
609 path = findRun(instrSName + run, exts, useExtsOnly);
610 } else {
611 path = findRun(p1.first + run, exts, useExtsOnly);
612 }
613
614 if (!path.empty()) {
615 // Cache successfully found path and extension
616 auto tempPath = Poco::Path(path);
617 previousExt = "." + tempPath.getExtension();
618 previousPath = tempPath.makeParent().toString();
619 res.emplace_back(path);
620 } else {
621 throw Kernel::Exception::NotFoundError("Unable to find file:", run);
622 }
623 }
624 } else {
625 std::string path;
626 // Special check for "PG3", to cope with situation like '48314,48316'.
627 if (boost::algorithm::istarts_with(hint, "PG3")) {
628 if (h == hints.begin()) {
629 instrSName = "PG3";
630 path = findRun(*h, exts, useExtsOnly);
631 } else {
632 path = findRun(instrSName + *h, exts, useExtsOnly);
633 }
634 } else {
635 path = findRun(*h, exts, useExtsOnly);
636 }
637 if (!path.empty()) {
638 res.emplace_back(path);
639 } else {
640 throw Kernel::Exception::NotFoundError("Unable to find file:", *h);
641 }
642 }
643 }
644
645 return res;
646}
647
658std::string FileFinderImpl::getArchivePath(const std::vector<IArchiveSearch_sptr> &archs,
659 const std::set<std::string> &filenames,
660 const std::vector<std::string> &exts) const {
661 g_log.debug() << "getArchivePath([IArchiveSearch_sptr], [ ";
662 for (const auto &iter : filenames)
663 g_log.debug() << iter << " ";
664 g_log.debug() << "], [ ";
665 for (const auto &iter : exts)
666 g_log.debug() << iter << " ";
667 g_log.debug() << "])\n";
668
669 std::string path;
670 for (const auto &arch : archs) {
671 try {
672 g_log.debug() << "Getting archive path for requested files\n";
673 path = arch->getArchivePath(filenames, exts);
674 if (!path.empty()) {
675 return path;
676 }
677 } catch (...) {
678 }
679 }
680 return path;
681}
682
694std::string FileFinderImpl::getPath(const std::vector<IArchiveSearch_sptr> &archs,
695 const std::set<std::string> &filenames,
696 const std::vector<std::string> &exts) const {
697 std::string path;
698
699 std::vector<std::string> extensions;
700 extensions.assign(exts.begin(), exts.end());
701
702 // Remove wild cards.
703 extensions.erase(std::remove_if(extensions.begin(), extensions.end(), containsWildCard), extensions.end());
704
705 const std::vector<std::string> &searchPaths = Kernel::ConfigService::Instance().getDataSearchDirs();
706
707 // Before we try any globbing, make sure we exhaust all reasonable attempts at
708 // constructing the possible filename.
709 // Avoiding the globbing of getFullPath() for as long as possible will help
710 // performance when calling findRuns()
711 // with a large range of files, especially when searchPaths consists of
712 // folders containing a large number of runs.
713 for (auto &extension : extensions) {
714 for (const auto &filename : filenames) {
715 for (const auto &searchPath : searchPaths) {
716 try {
717 const Poco::Path filePath(searchPath, filename + extension);
718 const Poco::File file(filePath);
719 if (file.exists())
720 return filePath.toString();
721
722 } catch (Poco::Exception &) { /* File does not exist, just carry on. */
723 }
724 }
725 }
726 }
727
728 for (const auto &extension : extensions) {
729 for (const auto &filename : filenames) {
730 path = getFullPath(filename + extension);
731 try {
732 if (!path.empty() && Poco::File(path).exists()) {
733 g_log.debug() << "path returned from getFullPath() = " << path << '\n';
734 return path;
735 }
736 } catch (std::exception &e) {
737 g_log.error() << "Cannot open file " << path << ": " << e.what() << '\n';
738 return "";
739 }
740 }
741 }
742
743 // Search the archive
744 if (!archs.empty()) {
745 g_log.debug() << "Search the archives\n";
746 const std::string archivePath = getArchivePath(archs, filenames, exts);
747 try {
748 if (!archivePath.empty() && Poco::File(archivePath).exists()) {
749 return archivePath;
750 }
751 } catch (std::exception &e) {
752 g_log.error() << "Cannot open file " << archivePath << ": " << e.what() << '\n';
753 return "";
754 }
755
756 } // archs
757
758 return "";
759}
760
761std::string FileFinderImpl::toUpper(const std::string &src) const {
762 std::string result = src;
763 std::transform(result.begin(), result.end(), result.begin(), toupper);
764 return result;
765}
766
767} // namespace Mantid::API
double error
Definition: IndexPeaks.cpp:133
std::string validateRuns(const std::string &searchText) const
A method that returns error messages if the provided runs are invalid.
Definition: FileFinder.cpp:506
std::pair< std::string, std::string > toInstrumentAndNumber(const std::string &hint) const
Extracts the instrument name and run number from a hint.
Definition: FileFinder.cpp:187
std::string makeFileName(const std::string &hint, const Kernel::InstrumentInfo &instrument) const
DO NOT USE! MADE PUBLIC FOR TESTING ONLY.
Definition: FileFinder.cpp:256
bool getCaseSensitive() const
Option to get if file finder should be case sensitive.
Definition: FileFinder.cpp:93
std::string getExtension(const std::string &filename, const std::vector< std::string > &exts) const
DO NOT USE! MADE PUBLIC FOR TESTING ONLY.
Definition: FileFinder.cpp:300
std::string findRun(const std::string &hintstr, const std::vector< std::string > &exts={}, const bool useExtsOnly=false) const
Definition: FileFinder.cpp:367
std::string getFullPath(const std::string &filename, const bool ignoreDirs=false) const
Return the full path to the file given its name.
Definition: FileFinder.cpp:105
int m_globOption
glob option - set to case sensitive or insensitive
Definition: FileFinder.h:75
std::string extractAllowedSuffix(std::string &userString) const
Run numbers can be followed by an allowed string.
Definition: FileFinder.cpp:114
std::vector< std::string > findRuns(const std::string &hintstr, const std::vector< std::string > &exts={}, const bool useExtsOnly=false) const
Find a list of files file given a hint.
Definition: FileFinder.cpp:527
std::vector< IArchiveSearch_sptr > getArchiveSearch(const Kernel::FacilityInfo &facility) const
Definition: FileFinder.cpp:328
static const std::string ALLOWED_SUFFIX
a string that is allowed at the end of any run number
Definition: FileFinder.h:60
std::string getPath(const std::vector< IArchiveSearch_sptr > &archs, const std::set< std::string > &filenames, const std::vector< std::string > &exts) const
Return the full path to the file given its name, checking local directories first.
Definition: FileFinder.cpp:694
FileFinderImpl()
Default constructor.
Definition: FileFinder.cpp:65
void getUniqueExtensions(const std::vector< std::string > &extensionsToAdd, std::vector< std::string > &uniqueExts) const
Given a set of already determined extensions and new extensions, create a set of all extensions.
Definition: FileFinder.cpp:485
std::string toUpper(const std::string &src) const
Definition: FileFinder.cpp:761
const Kernel::InstrumentInfo getInstrument(const std::string &hint) const
DO NOT USE! MADE PUBLIC FOR TESTING ONLY.
Definition: FileFinder.cpp:137
void setCaseSensitive(const bool cs)
Option to set if file finder should be case sensitive.
Definition: FileFinder.cpp:81
std::string getArchivePath(const std::vector< IArchiveSearch_sptr > &archs, const std::set< std::string > &filenames, const std::vector< std::string > &exts) const
Return the path to the file found in archive.
Definition: FileFinder.cpp:658
Exception for when an item is not found in a collection.
Definition: Exception.h:145
const char * what() const noexcept override
Writes out the range and limits.
Definition: Exception.cpp:105
A class that holds information about a facility.
Definition: FacilityInfo.h:36
const std::vector< std::string > extensions() const
Returns a list of file extensions.
Definition: FacilityInfo.h:48
const std::vector< std::string > & archiveSearch() const
Return the archive search interface names.
Definition: FacilityInfo.h:56
bool noFilePrefix() const
Returns a bool indicating whether prefix is required in file names.
Definition: FacilityInfo.h:68
const std::string & name() const
Return the name of the facility.
Definition: FacilityInfo.h:41
A class that holds information about an instrument.
std::string filePrefix(unsigned int runNumber) const
Returns file prefix for this instrument and a run number.
const FacilityInfo & facility() const
The facility to which this instrument belongs.
int zeroPadding(unsigned int runNumber) const
Returns zero padding for this instrument and a run number.
std::string delimiter() const
Returns the default delimiter between instrument name and run number.
const std::string shortName() const
Return the short name of the instrument.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Iterator begin()
Iterator referring to first element in the container.
@ TOK_IGNORE_EMPTY
ignore empty tokens
@ TOK_TRIM
remove leading and trailing whitespace from tokens
std::size_t size() const noexcept
Get the total number of tokens.
Iterator end()
Iterator referring to the past-the-end element in the container.
std::size_t count() const
Get the total number of tokens.
Kernel::Logger g_log("ExperimentInfo")
static logger object
bool exists(::NeXus::File &file, const std::string &name)
Based on the current group in the file, does the named sub-entry exist?
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
Definition: Strings.cpp:397
std::string to_string(const wide_integer< Bits, Signed > &n)