23#include <Poco/AutoPtr.h>
24#include <Poco/Channel.h>
25#include <Poco/DOM/DOMParser.h>
26#include <Poco/DOM/Document.h>
27#include <Poco/DOM/Element.h>
28#include <Poco/DOM/Node.h>
29#include <Poco/DOM/NodeList.h>
30#include <Poco/Environment.h>
31#include <Poco/Exception.h>
32#include <Poco/Instantiator.h>
33#include <Poco/Logger.h>
34#include <Poco/LoggingFactory.h>
35#include <Poco/LoggingRegistry.h>
38#include <Poco/PipeStream.h>
39#include <Poco/Platform.h>
40#include <Poco/Process.h>
41#include <Poco/StreamCopier.h>
42#include <Poco/String.h>
44#include <Poco/Util/LoggingConfigurator.h>
45#include <Poco/Util/PropertyFileConfiguration.h>
46#include <Poco/Util/SystemConfiguration.h>
47#include <Poco/Version.h>
49#include <boost/algorithm/string/join.hpp>
50#include <boost/algorithm/string/trim.hpp>
68#include <mach-o/dyld.h>
69#include <sys/sysctl.h>
88Logger
g_log(
"ConfigService");
90const std::string PATH_DELIMITERS =
";,";
98std::vector<std::string> splitPath(
const std::string &path) {
99 std::vector<std::string> splitted;
101 if (path.find_first_of(PATH_DELIMITERS) == std::string::npos) {
102 splitted.emplace_back(path);
109 splitted.emplace_back(*itr);
116const std::string LOG_LEVEL_KEY(
"logging.loggers.root.level");
126 : m_pConf(nullptr), m_pSysConfig(new
Poco::Util::SystemConfiguration()), m_changed_keys(), m_strBaseDir(
""),
127 m_propertyString(
""), m_properties_file_name(
"Mantid.properties"),
128 m_user_properties_file_name(
"Mantid.user.properties"), m_dataSearchDirs(), m_instrumentDirs(), m_proxyInfo() {
130 Poco::LoggingFactory::defaultFactory().registerChannelClass(
131 "StdoutChannel",
new Poco::Instantiator<Poco::StdoutChannel, Poco::Channel>);
154 std::string propertiesFilesList;
164 if (Poco::Environment::has(
"MANTIDPROPERTIES")) {
169 updateConfig(Poco::Environment::get(
"MANTIDPROPERTIES"),
true,
true);
170 propertiesFilesList +=
", " + Poco::Environment::get(
"MANTIDPROPERTIES");
182 << Types::Core::DateAndTime::getCurrentTime().toFormattedString(
"%Y-%m-%dT%H:%MZ") <<
"\n";
183 g_log.
information() <<
"Properties file(s) loaded: " << propertiesFilesList <<
'\n';
187 std::filesystem::path path = std::filesystem::path(appDataDir) /
"instrument";
191 std::filesystem::create_directories(path);
192 }
catch (
const std::filesystem::filesystem_error &fe) {
193 g_log.
error() <<
"Cannot create the local instrument cache directory [" << path.string()
194 <<
"]. Mantid will not be able to update instrument definitions.\n"
195 << fe.what() <<
'\n';
199 std::filesystem::create_directories(vtpDir);
200 }
catch (
const std::filesystem::filesystem_error &fe) {
201 g_log.
error() <<
"Cannot create the local instrument geometry cache directory [" << vtpDir.string()
202 <<
"]. Mantid will be slower at viewing complex instruments.\n"
203 << fe.what() <<
'\n';
239 std::filesystem::path filepath;
242 m_strBaseDir = std::filesystem::current_path().string() +
"/";
244 if (std::filesystem::exists(filepath))
251 if (std::filesystem::exists(filepath))
255 if (Poco::Environment::has(
"MANTIDPATH")) {
263 m_strBaseDir = Poco::Environment::get(
"MANTIDPATH") +
"\\";
265 m_strBaseDir = Poco::Environment::get(
"MANTIDPATH") +
"/";
268 if (std::filesystem::exists(filepath))
276 m_strBaseDir = execPath.parent_path().parent_path().parent_path().string() +
"/";
282std::string checkForBadConfigOptions(
const std::string &filename,
const std::string &propertiesString) {
283 std::stringstream stream(propertiesString);
284 std::stringstream resultPropertiesString;
287 while (std::getline(stream, line)) {
296 }
else if (line.find(
"FilterChannel") != std::string::npos) {
302 const auto end = line.find(
"=");
304 if (end != std::string::npos) {
309 g_log.
warning() <<
"\" in " << filename <<
" on line " << line_num << std::endl;
312 resultPropertiesString <<
'#';
315 resultPropertiesString << line <<
'\n';
317 return resultPropertiesString.str();
341 bool good =
readFile(filename, temp);
344 if ((!good) || (temp.empty())) {
354 temp = checkForBadConfigOptions(filename, temp);
362 }
catch (std::exception &e) {
364 g_log.
error() <<
"Problem loading the configuration file " << filename <<
" " << e.what() <<
'\n';
365 g_log.
error() <<
"Mantid is unable to start.\n" << std::endl;
371 m_pConf =
new Poco::Util::PropertyFileConfiguration(istr);
381 std::ifstream propFile(filename.c_str(), std::ios::in);
382 bool good = propFile.good();
392 getline(propFile, contents,
'`');
403 Poco::Util::LoggingConfigurator configurator;
404#if POCO_VERSION > 0x01090400
405 configurator.configure(
m_pConf);
407 configurator.configure(
m_pConf.get());
409 }
catch (std::exception &e) {
410 std::cerr <<
"Trouble configuring the logging framework " << e.what() <<
'\n';
426 std::string converted;
428 if (dir.find_first_of(PATH_DELIMITERS) != std::string::npos) {
429 auto splitted = splitPath(dir);
430 auto iend = splitted.cend();
431 for (
auto itr = splitted.begin(); itr != iend;) {
433 if (absolute.empty()) {
436 converted += absolute;
454 bool is_relative(
false);
456 std::filesystem::path testPath(dir);
457 is_relative = testPath.is_relative();
463 if (is_relative && !dir.empty() && (dir[0] ==
'/' || dir[0] ==
'\\')) {
467 }
catch (
const std::exception &) {
468 g_log.
warning() <<
"Malformed path detected in the \"" << key <<
"\" variable, skipping \"" << dir <<
"\"\n";
473 std::filesystem::path basePath(propFileDir);
474 std::filesystem::path fullPath = basePath / dir;
475 converted = fullPath.string();
479 std::filesystem::path convertedPath(converted);
480 if (!convertedPath.extension().empty()) {
481 converted = convertedPath.string();
484 converted = convertedPath.string();
485 if (converted.back() !=
'/' && converted.back() !=
'\\') {
492 boost::replace_all(converted,
"\\",
"/");
502 std::string paths =
getString(
"datasearch.directories",
true);
519 std::string correctedPath = path;
520 replace(correctedPath.begin(), correctedPath.end(),
'\\',
'/');
522 using std::placeholders::_1;
524 std::bind(std::equal_to<std::string>(), _1, correctedPath));
536 filestr <<
"# This file can be used to override any properties for this "
538 filestr <<
"# Any properties found in this file will override any that are "
539 "found in the Mantid.Properties file\n";
540 filestr <<
"# As this file will not be replaced with further installations "
541 "of Mantid it is a safe place to put \n";
542 filestr <<
"# properties that suit your particular installation.\n";
544 filestr <<
"# See here for a list of possible options:\n";
546 "http://docs.mantidproject.org/nightly/concepts/PropertiesFile.html"
549 filestr <<
"## GENERAL\n";
551 filestr <<
"## Set the maximum number of cores used to run algorithms over\n";
552 filestr <<
"#MultiThreaded.MaxCores=4\n\n";
554 filestr <<
"## FACILITY AND INSTRUMENT\n";
556 filestr <<
"## Sets the default facility\n";
557 filestr <<
"## e.g.: ISIS, SNS, ILL\n";
558 filestr <<
"default.facility=\n\n";
559 filestr <<
"## Sets the default instrument\n";
560 filestr <<
"## e.g. IRIS, HET, NIMROD\n";
561 filestr <<
"default.instrument=\n\n";
563 filestr <<
"## Sets the Q.convention\n";
564 filestr <<
"## Set to Crystallography for kf-ki instead of default "
565 "Inelastic which is ki-kf\n";
566 filestr <<
"#Q.convention=Crystallography\n";
568 filestr <<
"## DIRECTORIES\n";
570 filestr <<
"## Sets a list of directories (separated by semi colons) to "
572 filestr <<
"#datasearch.directories=../data;../isis/data\n\n";
573 filestr <<
"## Set a list (separated by semi colons) of directories to "
574 "look for additional Python scripts\n";
575 filestr <<
"#pythonscripts.directories=../scripts;../docs/MyScripts\n\n";
576 filestr <<
"## Uncomment to enable archive search - ICat and Orbiter\n";
577 filestr <<
"#datasearch.searcharchive=On\n\n";
578 filestr <<
"## Sets default save directory\n";
579 filestr <<
"#defaultsave.directory=../data\n\n";
581 filestr <<
"## LOGGING\n";
583 filestr <<
"## Uncomment to change logging level\n";
584 filestr <<
"## Default is information\n";
585 filestr <<
"## Valid values are: error, warning, notice, information, debug\n";
586 filestr <<
"#logging.loggers.root.level=information\n\n";
588 filestr <<
"## MantidWorkbench\n";
590 filestr <<
"## Hides categories from the algorithm list in MantidWorkbench\n";
591 filestr <<
"#algorithms.catagories.hidden=Muons,Inelastic\n\n";
592 filestr <<
"## Show invisible workspaces\n";
593 filestr <<
"#MantidOptions.InvisibleWorkspaces=0\n";
594 filestr <<
"## Re-use plot instances for different plot types\n";
595 filestr <<
"#MantidOptions.ReusePlotInstances=Off\n\n";
596 filestr <<
"## Uncomment to disable use of OpenGL to render unwrapped "
597 "instrument views\n";
598 filestr <<
"#MantidOptions.InstrumentView.UseOpenGL=Off\n\n";
599 filestr <<
"## Muon GUI settings\n";
600 filestr <<
"#muon.GUI = \n";
603 }
catch (std::runtime_error &ex) {
620 }
catch (
const std::exception &) {
625 const bool append =
false;
626 const bool updateCaches =
true;
660 std::string updated_file;
662 std::ifstream reader(filename.c_str(), std::ios::in);
664 throw std::runtime_error(
"Error opening user properties file. Cannot save "
665 "updated configuration.");
668 std::string file_line, output;
669 bool line_continuing(
false);
670 while (std::getline(reader, file_line)) {
671 if (!file_line.empty()) {
672 char last = *(file_line.end() - 1);
676 if (!line_continuing)
678 line_continuing =
true;
679 output += file_line +
"\n";
681 }
else if (line_continuing) {
683 line_continuing =
false;
689 updated_file +=
"\n";
697 std::string::size_type pos = output.find(
'=');
698 if (pos == std::string::npos) {
701 key = output.substr(0, pos);
704 Poco::trimInPlace(key);
707 std::string::size_type comment = key.find(
'#');
712 updated_file += output;
720 Poco::replaceInPlace(
value,
"\\",
"\\\\");
721 updated_file.append(key).append(
"=").append(
value);
725 updated_file +=
"\n";
731 updated_file +=
"\n";
733 for (
auto key_itr =
m_changed_keys.begin(); key_itr != key_end;) {
739 updated_file += *key_itr +
"=";
741 Poco::replaceInPlace(
value,
"\\",
"\\\\");
742 updated_file +=
value;
743 if (++key_itr != key_end) {
744 updated_file +=
"\n";
751 std::ofstream writer(filename.c_str(), std::ios_base::trunc);
754 g_log.
error() <<
"Error writing new user properties file. Cannot save "
755 "current configuration.\n";
756 throw std::runtime_error(
"Error writing new user properties file. Cannot "
757 "save current configuration.");
760 writer.write(updated_file.c_str(), updated_file.size());
777 if (
m_pConf->hasProperty(keyName)) {
786 g_log.
debug() <<
"Unable to find " << keyName <<
" in the properties file" <<
'\n';
800 std::vector<std::string> rawKeys;
801 m_pConf->keys(keyName, rawKeys);
809 std::vector<std::string> rootKeys =
getKeys(root);
811 if (rootKeys.empty())
812 allKeys.emplace_back(root);
814 for (
auto &rootKey : rootKeys) {
815 std::string searchString;
817 searchString.append(rootKey);
819 searchString.append(root).append(
".").append(rootKey);
835 std::vector<std::string> allKeys;
864std::string expandEnvironmentInFilepath(
const std::string &target) {
865 std::string result = target;
870 while ((pos = result.find(
'%', pos)) != std::string::npos) {
871 size_t end = result.find(
'%', pos + 1);
872 if (end == std::string::npos)
875 std::string varName = result.substr(pos + 1, end - pos - 1);
876 const char *envValue = std::getenv(varName.c_str());
879 result.replace(pos, end - pos + 1, envValue);
880 pos += std::strlen(envValue);
888 while ((pos = result.find(
'$', pos)) != std::string::npos) {
893 if (pos + 1 < result.length() && result[pos + 1] ==
'{') {
895 end = result.find(
'}', pos + 2);
896 if (end == std::string::npos) {
900 varName = result.substr(pos + 2, end - pos - 2);
905 while (end < result.length() && (std::isalnum(result[end]) || result[end] ==
'_')) {
908 varName = result.substr(pos + 1, end - pos - 1);
911 if (!varName.empty()) {
912 const char *envValue = std::getenv(varName.c_str());
914 result.replace(start, end - start, envValue);
915 pos = start + std::strlen(envValue);
939 std::filesystem::path filepath(expandEnvironmentInFilepath(target));
941 if (std::filesystem::exists(filepath) && std::filesystem::is_regular_file(filepath)) {
947 std::string ext = filepath.extension().string();
948 std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
949 return (ext ==
".exe" || ext ==
".bat" || ext ==
".cmd" || ext ==
".com");
952 auto perms = std::filesystem::status(filepath).permissions();
953 return (perms & std::filesystem::perms::owner_exec) != std::filesystem::perms::none ||
954 (perms & std::filesystem::perms::group_exec) != std::filesystem::perms::none ||
955 (perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none;
959 }
catch (
const std::exception &) {
977 const std::vector<std::string> &programArguments)
const {
979 std::string expTarget = expandEnvironmentInFilepath(programFilePath);
980 Poco::Process::launch(expTarget, programArguments);
981 }
catch (Poco::SystemException &e) {
982 throw std::runtime_error(e.what());
1002 if (key ==
"datasearch.directories") {
1004 }
else if (key ==
"instrumentDefinition.directory") {
1006 }
else if (key ==
"defaultsave.directory") {
1008 }
else if (key ==
"logging.channels.consoleChannel.class") {
1011 }
else if (key == LOG_LEVEL_KEY) {
1027 std::string strValue =
getString(keyName);
1032 return std::nullopt;
1035 return std::optional<T>(output);
1046 auto returnedValue = getValue<std::string>(keyName);
1047 if (!returnedValue.has_value()) {
1048 return std::nullopt;
1051 auto &configVal = returnedValue.value();
1053 std::transform(configVal.begin(), configVal.end(), configVal.begin(), ::tolower);
1055 boost::trim(configVal);
1057 bool trueString = configVal ==
"true";
1058 bool valueOne = configVal ==
"1";
1059 bool onOffString = configVal ==
"on";
1062 return trueString || valueOne || onOffString;
1071 return "Mantid.local.properties";
1073 return "/etc/mantid.local.properties";
1091 return m_pSysConfig->getString(
"system.env." + keyName);
1105 auto osArch =
m_pSysConfig->getString(
"system.osArchitecture");
1107 if (osArch ==
"x86_64") {
1111 size_t size =
sizeof(ret);
1112 if (sysctlbyname(
"sysctl.proc_translated", &ret, &size,
nullptr, 0) != -1 && ret == 1) {
1113 osArch =
"arm64_(x86_64)";
1114 g_log.
warning(
"You are running an Intel build of Mantid on Apple silicon, which will be significantly slower and "
1115 "use more power. For best performance, install the Arm version of Mantid. This version is "
1116 "available here: https://downloads.mantidproject.org");
1119 g_log.
warning(
"Mantid v6.14 is the last version that will support Intel macOS.");
1141 if (!std::filesystem::exists(filename)) {
1146 std::ifstream file(filename);
1152 size_t start = orig.find(key);
1153 if (start == std::string::npos) {
1154 return std::string();
1156 start += key.size();
1158 size_t stop = orig.find(
'\n', start);
1159 if (stop == std::string::npos) {
1160 return std::string();
1172 std::string description;
1175 static const std::string OS_RELEASE(
"/etc/os-release");
1177 static const std::string PRETTY_NAME(
"PRETTY_NAME=");
1180 std::ifstream handle(OS_RELEASE.c_str(), std::ios::in);
1184 while (std::getline(handle, line)) {
1185 if (line.find(PRETTY_NAME) != std::string::npos) {
1186 if (line.length() > PRETTY_NAME.length() + 1) {
1187 size_t length = line.length() - PRETTY_NAME.length() - 2;
1188 description = line.substr(PRETTY_NAME.length() + 1, length);
1196 if (!description.empty()) {
1202 static const std::string REDHAT_RELEASE(
"/etc/redhat-release");
1203 if (
canRead(REDHAT_RELEASE)) {
1205 std::ifstream handle(REDHAT_RELEASE.c_str(), std::ios::in);
1209 while (std::getline(handle, line)) {
1210 if (!line.empty()) {
1211 description = std::move(line);
1218 if (!description.empty()) {
1225 std::vector<std::string> args;
1230 args.emplace_back(
"os");
1231 args.emplace_back(
"get");
1232 args.emplace_back(
"Caption");
1233 args.emplace_back(
"/value");
1236#if defined __APPLE__ || defined _WIN32
1238 Poco::Pipe outPipe, errorPipe;
1239 Poco::ProcessHandle ph = Poco::Process::launch(cmd, args,
nullptr, &outPipe, &errorPipe);
1240 const int rc = ph.wait();
1243 Poco::PipeInputStream pipeStream(outPipe);
1244 std::stringstream stringStream;
1245 Poco::StreamCopier::copyStream(pipeStream, stringStream);
1246 const std::string result = stringStream.str();
1251 description = product_name +
" " + product_vers;
1258 std::stringstream messageStream;
1259 messageStream <<
"command \"" << cmd <<
"\" failed with code: " << rc;
1262 }
catch (Poco::SystemException &e) {
1263 g_log.
debug(
"command \"" + cmd +
"\" failed");
1272 std::string username;
1277 if (!username.empty()) {
1280 }
catch (
const Poco::NotFoundException &e) {
1286 username =
m_pSysConfig->getString(
"system.env.USERNAME");
1287 if (!username.empty()) {
1290 }
catch (
const Poco::NotFoundException &e) {
1295 return std::string();
1322 const std::string applicationName =
"mantid";
1323#if POCO_OS == POCO_OS_WINDOWS_NT
1324 const std::string vendorName =
"mantidproject";
1325 wchar_t *w_appdata = _wgetenv(L
"APPDATA");
1326 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
1327 std::string appdata = converter.to_bytes(w_appdata);
1328 std::filesystem::path path(appdata);
1330 path /= applicationName;
1331 return path.string();
1333 const char *home = std::getenv(
"HOME");
1335 throw std::runtime_error(
"HOME environment variable not set - seen in ConfigService.getAppDataDir()");
1337 std::filesystem::path path(home);
1338 path /= (
"." + applicationName);
1339 return path.string();
1350 return execPath.parent_path().string() +
"/";
1359 std::string execpath;
1360 const size_t LEN(1024);
1364 unsigned int bytes = GetModuleFileName(NULL, pBuf, LEN);
1365#elif defined __linux__
1367 sprintf(szTmp,
"/proc/%d/exe", getpid());
1368 ssize_t bytes = readlink(szTmp, pBuf, LEN);
1369#elif defined __APPLE__
1372 _NSGetExecutablePath(pBuf, &bytes);
1373 const int success = _NSGetExecutablePath(pBuf, &bytes);
1378 if (bytes > 0 && bytes < 1024) {
1380 execpath = std::string(pBuf);
1393 char buff[MAX_PATH];
1394 GetFullPathName(path.c_str(), MAX_PATH, buff, NULL);
1395 std::string fullName(buff);
1396 size_t i = fullName.find(
':');
1399 if (i == std::string::npos)
1402 fullName.erase(i + 1);
1404 UINT type = GetDriveType(fullName.c_str());
1405 return DRIVE_REMOTE == type;
1406#elif defined __linux__
1420 std::ifstream mntfile(
"/proc/mounts");
1421 std::string txtread(
"");
1422 while (getline(mntfile, txtread)) {
1423 std::istringstream strm(txtread);
1424 std::string devname(
""), mntpoint(
""), fstype(
"");
1425 strm >> devname >> mntpoint >> fstype;
1429 std::transform(fstype.begin(), fstype.end(), fstype.begin(), toupper);
1431 if (fstype !=
"NFS" && fstype !=
"SMB")
1440 std::string::size_type idx = mntpoint.find(
"\\0");
1441 if (idx != std::string::npos) {
1442 std::string oct = mntpoint.substr(idx + 1, 3);
1445 strm.setf(std::ios::oct, std::ios::basefield);
1447 if (printch != -1) {
1448 mntpoint = mntpoint.substr(0, idx) +
static_cast<char>(printch) + mntpoint.substr(idx + 4);
1451 if (path.find(mntpoint) == 0)
1484 std::filesystem::path datadir(
m_pSysConfig->getString(
"system.homeDir"));
1485 datadir /=
".mantid";
1487 std::filesystem::create_directory(datadir);
1488 return datadir.string() +
"/";
1503 std::string searchPaths = boost::join(searchDirs,
";");
1513 setString(
"datasearch.directories", searchDirs);
1525 std::filesystem::path subDirPath;
1527 subDirPath = std::filesystem::path(subdir);
1528 }
catch (
const std::exception &) {
1533 if (!subDirPath.is_relative()) {
1539 std::filesystem::path newDirPath;
1541 newDirPath = std::filesystem::path(path) / subDirPath;
1543 if (std::find(newDataDirs.begin(), newDataDirs.end(), newDirPath.string()) == newDataDirs.end())
1544 newDataDirs.emplace_back(newDirPath.string());
1545 }
catch (
const std::exception &) {
1562 std::filesystem::path dirPath;
1564 dirPath = std::filesystem::path(path);
1566 std::string pathStr = dirPath.string();
1567 if (pathStr.back() !=
'/' && pathStr.back() !=
'\\') {
1572 newSearchString.append(
";" + path);
1573 setString(
"datasearch.directories", newSearchString);
1575 }
catch (
const std::exception &) {
1605 std::string directoryName =
getString(
"instrumentDefinition.vtp.directory");
1607 if (directoryName.empty()) {
1609 path /=
"instrument";
1610 path /=
"geometryCache";
1611 directoryName = path.string();
1613 return directoryName;
1629 path /=
"instrument";
1630 const std::string appdatadir = path.string();
1638 std::string directoryName =
getString(
"instrumentDefinition.directory",
true);
1639 if (directoryName.empty()) {
1644 directoryName = (basePath /
".." /
"instrument").lexically_normal().string();
1657 std::vector<std::string> &directoryList) {
1659 if (std::filesystem::is_directory(directoryName)) {
1660 directoryList.emplace_back(directoryName);
1666 }
catch (
const std::filesystem::filesystem_error &) {
1669 }
catch (
const std::exception &) {
1676 std::vector<std::string> returnPaths;
1679 if (!fName.empty()) {
1680 if (std::filesystem::exists(fName)) {
1681 returnPaths.emplace_back(fName);
1690 const std::string updateInstrStr = this->
getString(
"UpdateInstrumentDefinitions.OnStartup");
1692 auto instrDir = directoryNames.begin();
1698 if (!(updateInstrStr ==
"1" || updateInstrStr ==
"on" || updateInstrStr ==
"On") && directoryNames.size() > 1) {
1703 for (; instrDir != directoryNames.end(); ++instrDir) {
1704 std::filesystem::path p(*instrDir);
1705 p /=
"Facilities.xml";
1706 std::string filename = p.string();
1708 if (std::filesystem::exists(filename))
1709 returnPaths.emplace_back(filename);
1712 if (returnPaths.size() > 0) {
1717 std::string directoryNamesList = boost::algorithm::join(directoryNames,
", ");
1718 throw std::runtime_error(
"Failed to find \"Facilities.xml\". Searched in " + directoryNamesList);
1737 size_t attemptIndex = 0;
1738 bool success =
false;
1739 while ((!success) && (attemptIndex < fileNames.size())) {
1740 const auto &fileName = fileNames[attemptIndex];
1743 Poco::AutoPtr<Poco::XML::Document> pDoc;
1745 Poco::XML::DOMParser pParser;
1746 pDoc = pParser.parse(fileName);
1752 Poco::XML::Element *pRootElem = pDoc->documentElement();
1753 if (!pRootElem->hasChildNodes()) {
1754 throw std::runtime_error(
"No root element in Facilities.xml file");
1757 const Poco::AutoPtr<Poco::XML::NodeList> pNL_facility = pRootElem->getElementsByTagName(
"facility");
1758 const size_t n = pNL_facility->length();
1760 for (
unsigned long i = 0; i <
n; ++i) {
1761 const auto *elem =
dynamic_cast<Poco::XML::Element *
>(pNL_facility->item(i));
1768 throw std::runtime_error(
"The facility definition file " + fileName +
" defines no facilities");
1773 }
catch (std::runtime_error &ex) {
1775 g_log.
error() <<
"Failed to load the facilities.xml file at " << fileName <<
"\nIt might be corrupt. "
1776 << ex.what() <<
"\nWill try to load another version.\n";
1779 if (attemptIndex == fileNames.size()) {
1780 const std::string errorMessage =
"No more Facilities.xml files can be found, Mantid will not be "
1781 "able to start, Sorry. Try reinstalling Mantid.";
1787 throw std::runtime_error(errorMessage);
1815 if (!defaultFacility.empty()) {
1817 g_log.
debug() <<
"Looking for " << instrumentName <<
" at " << defaultFacility <<
".\n";
1828 g_log.
debug() <<
"Looking for " << instrumentName <<
" at " << (*facility).name() <<
".\n";
1829 return (*facility).instrument(instrumentName);
1836 const std::string errMsg =
"Failed to find an instrument with this name in any facility: '" + instrumentName +
"' -";
1837 g_log.
debug(
"Instrument " + instrumentName +
" not found");
1843 std::vector<std::string> names;
1846 const auto &insts = facility->instruments();
1847 for (
const auto &inst : insts) {
1848 names.emplace_back(inst.shortName());
1849 names.emplace_back(inst.name());
1853 std::sort(names.begin(), names.end());
1854 const auto last = std::unique(names.begin(), names.end());
1855 names.erase(last, names.end());
1860 std::string longestPrefix;
1865 auto it = std::prev(match);
1867 if (hint.starts_with(*it)) {
1868 longestPrefix = *it;
1871 if ((*it)[0] != hint[0]) {
1881 return longestPrefix;
1893 auto names = std::vector<std::string>(
m_facilities.size());
1895 [](
const FacilityInfo *facility) { return facility->name(); });
1904 std::string defFacility =
getString(
"default.facility");
1905 if (defFacility.empty()) {
1918 if (facilityName.empty())
1922 [&facilityName](
const auto f) { return f->name() == facilityName; });
1944 g_log.
error(
"Failed to set default facility to be " + facilityName +
". Facility not found");
1947 assert(foundFacility);
1948 setString(
"default.facility", facilityName);
1950 const auto &associatedInsts = foundFacility->
instruments();
1951 if (associatedInsts.empty()) {
1952 throw std::invalid_argument(
"The selected facility has no instruments associated with it");
1982 auto proxyHost = getValue<std::string>(
"proxy.host");
1983 auto proxyPort = getValue<int>(
"proxy.port");
1985 if (proxyHost.has_value() && proxyPort.has_value()) {
2000 const int options)
const {
2002 g_log.
debug() <<
"getFullPath(" << fName <<
")\n";
2004 std::filesystem::path filepath(fName);
2005 if (filepath.is_absolute())
2010 std::filesystem::path fullPath = std::filesystem::current_path() / fName;
2011 if (std::filesystem::exists(fullPath) && (!ignoreDirs || !std::filesystem::is_directory(fullPath)))
2012 return fullPath.string();
2013 }
catch (
const std::exception &) {
2018 directoryNames.insert(directoryNames.end(), instrDirectories.begin(), instrDirectories.end());
2019 for (
const auto &searchPath : directoryNames) {
2020 g_log.
debug() <<
"Searching for " << fName <<
" in " << searchPath <<
"\n";
2026 if (fName.find(
"*") != std::string::npos) {
2028 std::filesystem::path path = std::filesystem::path(searchPath) / fName;
2029 std::set<std::string> files;
2031 if (!files.empty()) {
2032 std::filesystem::path matchPath(*files.begin());
2033 if (ignoreDirs && std::filesystem::is_directory(matchPath)) {
2036 return *files.begin();
2040 std::filesystem::path path = std::filesystem::path(searchPath) / fName;
2041 if (std::filesystem::exists(path) && !(ignoreDirs && std::filesystem::is_directory(path))) {
2042 return path.string();
double value
The value of the point.
#define DLLExport
Definitions of the DLLImport compiler directives for MSVC.
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
This is the class for the notification that is to be sent when a value has been changed in config ser...
const std::vector< std::string > & getInstrumentDirectories() const
Get instrument search directories.
std::string m_propertyString
The configuration properties in string format.
void setBaseDirectory()
Setup the base directory.
const std::string getVTPFileDirectory()
get the vtp file directory
const std::string findLongestInstrumentPrefix(const std::string &hint) const
const std::string m_properties_file_name
The filename of the Mantid properties file.
std::set< std::string > m_configPaths
List of config paths that may be relative.
void setInstrumentDirectories(const std::vector< std::string > &directories)
Sets instrument directories.
ConfigServiceImpl()
Private constructor for singleton class.
const FacilityInfo & getFacility() const
Get the default facility.
std::string getDirectoryOfExecutable() const
Get the directory containing the program executable.
bool addDirectoryifExists(const std::string &directoryName, std::vector< std::string > &directoryList)
Verifies the directory exists and add it to the back of the directory list if valid.
void cacheInstrumentPaths()
Create the storage of the instrument directories.
void reset()
Reset to "factory" settings. Removes current user properties.
std::string getLocalFilename() const
Return the local properties filename.
std::string getAppDataDir()
Returns the system's appdata directory.
std::string getPropertiesDir() const
Returns the directory where the Mantid.properties file is found.
bool m_isInstrumentPrefixesCached
std::string getOSVersion()
Returns the OS version.
std::string getOSVersionReadable()
Returns a human readable version of the OS version.
virtual ~ConfigServiceImpl()
Private Destructor Prevents client from calling 'delete' on the pointer handed out by Instance.
std::string getFullPath(const std::string &filename, const bool ignoreDirs, const int options) const
std::string getPathToExecutable() const
Get the full path to the executing program (i.e.
void loadConfig(const std::string &filename, const bool append=false)
Loads a config file.
void configureLogging()
Configures the Poco logging and starts it up.
std::string getUserPropertiesDir() const
Returns a directory to use to write out Mantid information.
bool isExecutable(const std::string &target) const
Checks to see whether the target passed is an executable file.
void saveConfig(const std::string &filename) const
Save the configuration to the user file.
std::string getLogLevel()
const std::vector< std::string > & getDataSearchDirs() const
Get the list of search paths.
bool isInDataSearchList(const std::string &path) const
Returns true if the path is in the data search list.
const std::vector< std::string > getFacilityFilenames(const std::string &fName)
Determine the name of the facilities file to use.
void removeObserver(const Poco::AbstractObserver &observer) const
Remove an observer.
std::string m_strBaseDir
The directory that is considered to be the base directory.
Kernel::ProxyInfo & getProxy(const std::string &url)
Gets the proxy for the system.
std::string makeAbsolute(const std::string &dir, const std::string &key) const
Make a relative path or a list of relative paths into an absolute one.
const InstrumentInfo & getInstrument(const std::string &instrumentName="") const
Look for an instrument.
std::set< std::string > m_changed_keys
A set of property keys that have been changed.
void updateConfig(const std::string &filename, const bool append=false, const bool update_caches=true)
Wipe out the current configuration and load a new one.
void createUserPropertiesFile() const
Writes out a fresh user properties file.
std::vector< std::string > m_dataSearchDirs
Store a list of data search paths.
void updateFacilities(const std::string &fName="")
Load facility information from instrumentDir/Facilities.xml file.
const std::vector< FacilityInfo * > getFacilities() const
Get the list of facilities.
std::string getEnvironment(const std::string &keyName)
Searches for the given environment variable and returns it as a string.
void appendDataSearchDir(const std::string &path)
Adds the passed path to the end of the list of data search paths.
std::string getCurrentDir()
Returns the current directory.
void getKeysRecursive(const std::string &root, std::vector< std::string > &allKeys) const
Returns a list of all keys under a given root key.
void setLogLevel(int logLevel, bool quiet=false)
Sets the log level priority for all log channels.
std::optional< T > getValue(const std::string &keyName)
Searches for a string within the currently loaded configuration values and attempts to convert the va...
void setDataSearchDirs(const std::vector< std::string > &searchDirs)
Set a list of search paths via a vector.
std::string getString(const std::string &keyName, bool pathAbsolute=true) const
Searches for a configuration property.
const std::string getInstrumentDirectory() const
Get instrument search directory.
void addObserver(const Poco::AbstractObserver &observer) const
Add an observer for a notification.
std::string getUsername()
Returns the username.
std::string getOSName()
Returns the OS name.
void setString(const std::string &key, const std::string &value)
Sets a configuration property.
void clearFacilities()
Empty the list of facilities, deleting the FacilityInfo objects in the process.
std::string getComputerName()
Returns the computer name.
std::string getOSArchitecture()
Returns the architecture.
std::vector< std::string > m_instrumentPrefixesCache
std::string getUserFilename() const
Return the user properties filename.
Poco::AutoPtr< Poco::Util::SystemConfiguration > m_pSysConfig
the POCO system Config Object
bool m_isProxySet
whether the proxy has been populated yet
bool isNetworkDrive(const std::string &path)
Check if the path is on a network drive.
bool readFile(const std::string &filename, std::string &contents) const
Read a file and place its contents into the given string.
Poco::NotificationCenter m_notificationCenter
Handles distribution of Poco signals.
Kernel::ProxyInfo m_proxyInfo
local cache of proxy details
void setFacility(const std::string &facilityName)
Set the default facility.
void remove(const std::string &rootName)
Removes the value from a selected keyName.
void cacheDataSearchPaths()
Create the storage of the data search directories.
std::string getTempDir()
Returns the system's temp directory.
const std::string m_user_properties_file_name
The filename of the Mantid user properties file.
void appendDataSearchSubDir(const std::string &subdir)
Appends subdirectory to each of the specified data search directories.
std::vector< std::string > keys() const
Returns a list of all full keys in the config.
Poco::AutoPtr< Poco::Util::PropertyFileConfiguration > m_pConf
the POCO file config object
const std::vector< std::string > getFacilityNames() const
Get the list of facility names.
std::vector< FacilityInfo * > m_facilities
The list of available facilities.
void launchProcess(const std::string &programFilePath, const std::vector< std::string > &programArguments) const
Launches a process i.e opening a program.
std::vector< std::string > getKeys(const std::string &keyName) const
Searches for a key in the configuration property.
std::vector< std::string > m_instrumentDirs
Store a list of instrument directory paths.
bool hasProperty(const std::string &rootName) const
Checks to see whether a key has a value assigned to it.
Records the filename and the description of failure.
Exception for when an item is not found in a collection.
A class that holds information about a facility.
const std::vector< InstrumentInfo > & instruments() const
Returns a list of instruments of this facility.
const std::string & name() const
Return the name of the facility.
const InstrumentInfo & instrument(std::string iName="") const
Returns instruments with given name.
static void glob(const std::string &pathPattern, std::set< std::string > &files, int options=0)
Creates a set of files that match the given pathPattern.
A class that holds information about an instrument.
void debug(const std::string &msg)
Logs at debug level.
static void setLevelForAll(const int level)
Sets the log level for all Loggers created so far, including the root logger.
static void shutdown()
Shuts down the logging framework and releases all Loggers.
void error(const std::string &msg)
Logs at error level.
std::string getLevelName() const
void warning(const std::string &msg)
Logs at warning level.
Poco::Message::Priority Priority
void log(const std::string &message, const Priority &priority)
Log a message at a given priority.
int getLevel() const
Returns the Logger's log level.
void information(const std::string &msg)
Logs at information level.
static const std::array< std::string, 9 > PriorityNames
static const std::string & revision()
The abbreviated SHA-1 of the last commit.
static const std::string & version()
The full version number.
static std::string doi()
The DOI for this release of Mantid.
static const std::string & paperCitation()
The citation for the Mantid paper.
NetworkProxy : Network proxy utility for getting network proxy information.
ProxyInfo getHttpProxy(const std::string &targetURLString)
Get http proxy information.
ProxyInfo : Container for carrying around network proxy information.
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
Iterator end()
Iterator referring to the past-the-end element in the container.
Logger g_log("DateAndTime")
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
DLLExport std::string join(ITERATOR_TYPE begin, ITERATOR_TYPE end, const std::string &separator, typename std::enable_if<!(std::is_same< typename std::iterator_traits< ITERATOR_TYPE >::iterator_category, std::random_access_iterator_tag >::value)>::type *=nullptr)
Join a set or vector of (something that turns into a string) together into one string,...
int convert(const std::string &A, T &out)
Convert a string into a number.
std::string getValueFromStdOut(const std::string &orig, const std::string &key)
bool canRead(const std::string &filename)
Mantid::Kernel::StringTokenizer tokenizer
Helper class which provides the Collimation Length for SANS instruments.
MANTID_KERNEL_DLL std::string welcomeMessage()
Returns the welcome message for Mantid.