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(),
129 m_isProxySet(false) {
131 Poco::LoggingFactory::defaultFactory().registerChannelClass(
132 "StdoutChannel",
new Poco::Instantiator<Poco::StdoutChannel, Poco::Channel>);
155 std::string propertiesFilesList;
165 if (Poco::Environment::has(
"MANTIDPROPERTIES")) {
170 updateConfig(Poco::Environment::get(
"MANTIDPROPERTIES"),
true,
true);
171 propertiesFilesList +=
", " + Poco::Environment::get(
"MANTIDPROPERTIES");
183 << Types::Core::DateAndTime::getCurrentTime().toFormattedString(
"%Y-%m-%dT%H:%MZ") <<
"\n";
184 g_log.
information() <<
"Properties file(s) loaded: " << propertiesFilesList <<
'\n';
188 std::filesystem::path path = std::filesystem::path(appDataDir) /
"instrument";
192 std::filesystem::create_directories(path);
193 }
catch (
const std::filesystem::filesystem_error &fe) {
194 g_log.
error() <<
"Cannot create the local instrument cache directory [" << path.string()
195 <<
"]. Mantid will not be able to update instrument definitions.\n"
196 << fe.what() <<
'\n';
200 std::filesystem::create_directories(vtpDir);
201 }
catch (
const std::filesystem::filesystem_error &fe) {
202 g_log.
error() <<
"Cannot create the local instrument geometry cache directory [" << vtpDir.string()
203 <<
"]. Mantid will be slower at viewing complex instruments.\n"
204 << fe.what() <<
'\n';
240 std::filesystem::path filepath;
243 m_strBaseDir = std::filesystem::current_path().string() +
"/";
245 if (std::filesystem::exists(filepath))
252 if (std::filesystem::exists(filepath))
256 if (Poco::Environment::has(
"MANTIDPATH")) {
264 m_strBaseDir = Poco::Environment::get(
"MANTIDPATH") +
"\\";
266 m_strBaseDir = Poco::Environment::get(
"MANTIDPATH") +
"/";
269 if (std::filesystem::exists(filepath))
277 m_strBaseDir = execPath.parent_path().parent_path().parent_path().string() +
"/";
283std::string checkForBadConfigOptions(
const std::string &filename,
const std::string &propertiesString) {
284 std::stringstream stream(propertiesString);
285 std::stringstream resultPropertiesString;
288 while (std::getline(stream, line)) {
297 }
else if (line.find(
"FilterChannel") != std::string::npos) {
303 const auto end = line.find(
"=");
305 if (end != std::string::npos) {
310 g_log.
warning() <<
"\" in " << filename <<
" on line " << line_num << std::endl;
313 resultPropertiesString <<
'#';
316 resultPropertiesString << line <<
'\n';
318 return resultPropertiesString.str();
342 bool good =
readFile(filename, temp);
345 if ((!good) || (temp.empty())) {
355 temp = checkForBadConfigOptions(filename, temp);
363 }
catch (std::exception &e) {
365 g_log.
error() <<
"Problem loading the configuration file " << filename <<
" " << e.what() <<
'\n';
366 g_log.
error() <<
"Mantid is unable to start.\n" << std::endl;
372 m_pConf =
new Poco::Util::PropertyFileConfiguration(istr);
382 std::ifstream propFile(filename.c_str(), std::ios::in);
383 bool good = propFile.good();
393 getline(propFile, contents,
'`');
404 Poco::Util::LoggingConfigurator configurator;
405#if POCO_VERSION > 0x01090400
406 configurator.configure(
m_pConf);
408 configurator.configure(
m_pConf.get());
410 }
catch (std::exception &e) {
411 std::cerr <<
"Trouble configuring the logging framework " << e.what() <<
'\n';
427 std::string converted;
429 if (dir.find_first_of(PATH_DELIMITERS) != std::string::npos) {
430 auto splitted = splitPath(dir);
431 auto iend = splitted.cend();
432 for (
auto itr = splitted.begin(); itr != iend;) {
434 if (absolute.empty()) {
437 converted += absolute;
455 bool is_relative(
false);
457 std::filesystem::path testPath(dir);
458 is_relative = testPath.is_relative();
464 if (is_relative && !dir.empty() && (dir[0] ==
'/' || dir[0] ==
'\\')) {
468 }
catch (
const std::exception &) {
469 g_log.
warning() <<
"Malformed path detected in the \"" << key <<
"\" variable, skipping \"" << dir <<
"\"\n";
474 std::filesystem::path basePath(propFileDir);
475 std::filesystem::path fullPath = basePath / dir;
476 converted = fullPath.string();
480 std::filesystem::path convertedPath(converted);
481 if (!convertedPath.extension().empty()) {
482 converted = convertedPath.string();
485 converted = convertedPath.string();
486 if (converted.back() !=
'/' && converted.back() !=
'\\') {
493 boost::replace_all(converted,
"\\",
"/");
503 std::string paths =
getString(
"datasearch.directories",
true);
520 std::string correctedPath = path;
521 replace(correctedPath.begin(), correctedPath.end(),
'\\',
'/');
523 using std::placeholders::_1;
525 std::bind(std::equal_to<std::string>(), _1, correctedPath));
537 filestr <<
"# This file can be used to override any properties for this "
539 filestr <<
"# Any properties found in this file will override any that are "
540 "found in the Mantid.Properties file\n";
541 filestr <<
"# As this file will not be replaced with further installations "
542 "of Mantid it is a safe place to put \n";
543 filestr <<
"# properties that suit your particular installation.\n";
545 filestr <<
"# See here for a list of possible options:\n";
547 "http://docs.mantidproject.org/nightly/concepts/PropertiesFile.html"
550 filestr <<
"## GENERAL\n";
552 filestr <<
"## Set the maximum number of cores used to run algorithms over\n";
553 filestr <<
"#MultiThreaded.MaxCores=4\n\n";
555 filestr <<
"## FACILITY AND INSTRUMENT\n";
557 filestr <<
"## Sets the default facility\n";
558 filestr <<
"## e.g.: ISIS, SNS, ILL\n";
559 filestr <<
"default.facility=\n\n";
560 filestr <<
"## Sets the default instrument\n";
561 filestr <<
"## e.g. IRIS, HET, NIMROD\n";
562 filestr <<
"default.instrument=\n\n";
564 filestr <<
"## Sets the Q.convention\n";
565 filestr <<
"## Set to Crystallography for kf-ki instead of default "
566 "Inelastic which is ki-kf\n";
567 filestr <<
"#Q.convention=Crystallography\n";
569 filestr <<
"## DIRECTORIES\n";
571 filestr <<
"## Sets a list of directories (separated by semi colons) to "
573 filestr <<
"#datasearch.directories=../data;../isis/data\n\n";
574 filestr <<
"## Set a list (separated by semi colons) of directories to "
575 "look for additional Python scripts\n";
576 filestr <<
"#pythonscripts.directories=../scripts;../docs/MyScripts\n\n";
577 filestr <<
"## Uncomment to enable archive search - ICat and Orbiter\n";
578 filestr <<
"#datasearch.searcharchive=On\n\n";
579 filestr <<
"## Sets default save directory\n";
580 filestr <<
"#defaultsave.directory=../data\n\n";
582 filestr <<
"## LOGGING\n";
584 filestr <<
"## Uncomment to change logging level\n";
585 filestr <<
"## Default is information\n";
586 filestr <<
"## Valid values are: error, warning, notice, information, debug\n";
587 filestr <<
"#logging.loggers.root.level=information\n\n";
589 filestr <<
"## MantidWorkbench\n";
591 filestr <<
"## Hides categories from the algorithm list in MantidWorkbench\n";
592 filestr <<
"#algorithms.catagories.hidden=Muons,Inelastic\n\n";
593 filestr <<
"## Show invisible workspaces\n";
594 filestr <<
"#MantidOptions.InvisibleWorkspaces=0\n";
595 filestr <<
"## Re-use plot instances for different plot types\n";
596 filestr <<
"#MantidOptions.ReusePlotInstances=Off\n\n";
597 filestr <<
"## Uncomment to disable use of OpenGL to render unwrapped "
598 "instrument views\n";
599 filestr <<
"#MantidOptions.InstrumentView.UseOpenGL=Off\n\n";
600 filestr <<
"## Muon GUI settings\n";
601 filestr <<
"#muon.GUI = \n";
604 }
catch (std::runtime_error &ex) {
621 }
catch (
const std::exception &) {
626 const bool append =
false;
627 const bool updateCaches =
true;
661 std::string updated_file;
663 std::ifstream reader(filename.c_str(), std::ios::in);
665 throw std::runtime_error(
"Error opening user properties file. Cannot save "
666 "updated configuration.");
669 std::string file_line, output;
670 bool line_continuing(
false);
671 while (std::getline(reader, file_line)) {
672 if (!file_line.empty()) {
673 char last = *(file_line.end() - 1);
677 if (!line_continuing)
679 line_continuing =
true;
680 output += file_line +
"\n";
682 }
else if (line_continuing) {
684 line_continuing =
false;
690 updated_file +=
"\n";
698 std::string::size_type pos = output.find(
'=');
699 if (pos == std::string::npos) {
702 key = output.substr(0, pos);
705 Poco::trimInPlace(key);
708 std::string::size_type comment = key.find(
'#');
713 updated_file += output;
721 Poco::replaceInPlace(
value,
"\\",
"\\\\");
722 updated_file.append(key).append(
"=").append(
value);
726 updated_file +=
"\n";
732 updated_file +=
"\n";
734 for (
auto key_itr =
m_changed_keys.begin(); key_itr != key_end;) {
740 updated_file += *key_itr +
"=";
742 Poco::replaceInPlace(
value,
"\\",
"\\\\");
743 updated_file +=
value;
744 if (++key_itr != key_end) {
745 updated_file +=
"\n";
752 std::ofstream writer(filename.c_str(), std::ios_base::trunc);
755 g_log.
error() <<
"Error writing new user properties file. Cannot save "
756 "current configuration.\n";
757 throw std::runtime_error(
"Error writing new user properties file. Cannot "
758 "save current configuration.");
761 writer.write(updated_file.c_str(), updated_file.size());
778 if (
m_pConf->hasProperty(keyName)) {
787 g_log.
debug() <<
"Unable to find " << keyName <<
" in the properties file" <<
'\n';
801 std::vector<std::string> rawKeys;
802 m_pConf->keys(keyName, rawKeys);
810 std::vector<std::string> rootKeys =
getKeys(root);
812 if (rootKeys.empty())
813 allKeys.emplace_back(root);
815 for (
auto &rootKey : rootKeys) {
816 std::string searchString;
818 searchString.append(rootKey);
820 searchString.append(root).append(
".").append(rootKey);
836 std::vector<std::string> allKeys;
865std::string expandEnvironmentInFilepath(
const std::string &target) {
866 std::string result = target;
871 while ((pos = result.find(
'%', pos)) != std::string::npos) {
872 size_t end = result.find(
'%', pos + 1);
873 if (end == std::string::npos)
876 std::string varName = result.substr(pos + 1, end - pos - 1);
877 const char *envValue = std::getenv(varName.c_str());
880 result.replace(pos, end - pos + 1, envValue);
881 pos += std::strlen(envValue);
889 while ((pos = result.find(
'$', pos)) != std::string::npos) {
894 if (pos + 1 < result.length() && result[pos + 1] ==
'{') {
896 end = result.find(
'}', pos + 2);
897 if (end == std::string::npos) {
901 varName = result.substr(pos + 2, end - pos - 2);
906 while (end < result.length() && (std::isalnum(result[end]) || result[end] ==
'_')) {
909 varName = result.substr(pos + 1, end - pos - 1);
912 if (!varName.empty()) {
913 const char *envValue = std::getenv(varName.c_str());
915 result.replace(start, end - start, envValue);
916 pos = start + std::strlen(envValue);
940 std::filesystem::path filepath(expandEnvironmentInFilepath(target));
942 if (std::filesystem::exists(filepath) && std::filesystem::is_regular_file(filepath)) {
948 std::string ext = filepath.extension().string();
949 std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
950 return (ext ==
".exe" || ext ==
".bat" || ext ==
".cmd" || ext ==
".com");
953 auto perms = std::filesystem::status(filepath).permissions();
954 return (perms & std::filesystem::perms::owner_exec) != std::filesystem::perms::none ||
955 (perms & std::filesystem::perms::group_exec) != std::filesystem::perms::none ||
956 (perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none;
960 }
catch (
const std::exception &) {
978 const std::vector<std::string> &programArguments)
const {
980 std::string expTarget = expandEnvironmentInFilepath(programFilePath);
981 Poco::Process::launch(expTarget, programArguments);
982 }
catch (Poco::SystemException &e) {
983 throw std::runtime_error(e.what());
1003 if (key ==
"datasearch.directories") {
1005 }
else if (key ==
"instrumentDefinition.directory") {
1007 }
else if (key ==
"defaultsave.directory") {
1009 }
else if (key ==
"logging.channels.consoleChannel.class") {
1012 }
else if (key == LOG_LEVEL_KEY) {
1028 std::string strValue =
getString(keyName);
1033 return std::nullopt;
1036 return std::optional<T>(output);
1047 auto returnedValue = getValue<std::string>(keyName);
1048 if (!returnedValue.has_value()) {
1049 return std::nullopt;
1052 auto &configVal = returnedValue.value();
1054 std::transform(configVal.begin(), configVal.end(), configVal.begin(), ::tolower);
1056 boost::trim(configVal);
1058 bool trueString = configVal ==
"true";
1059 bool valueOne = configVal ==
"1";
1060 bool onOffString = configVal ==
"on";
1063 return trueString || valueOne || onOffString;
1072 return "Mantid.local.properties";
1074 return "/etc/mantid.local.properties";
1092 return m_pSysConfig->getString(
"system.env." + keyName);
1106 auto osArch =
m_pSysConfig->getString(
"system.osArchitecture");
1108 if (osArch ==
"x86_64") {
1112 size_t size =
sizeof(ret);
1113 if (sysctlbyname(
"sysctl.proc_translated", &ret, &size,
nullptr, 0) != -1 && ret == 1) {
1114 osArch =
"arm64_(x86_64)";
1115 g_log.
warning(
"You are running an Intel build of Mantid on Apple silicon, which will be significantly slower and "
1116 "use more power. For best performance, install the Arm version of Mantid. This version is "
1117 "available here: https://downloads.mantidproject.org");
1120 g_log.
warning(
"Mantid v6.14 is the last version that will support Intel macOS.");
1142 if (!std::filesystem::exists(filename)) {
1147 std::ifstream file(filename);
1153 size_t start = orig.find(key);
1154 if (start == std::string::npos) {
1155 return std::string();
1157 start += key.size();
1159 size_t stop = orig.find(
'\n', start);
1160 if (stop == std::string::npos) {
1161 return std::string();
1173 std::string description;
1176 static const std::string OS_RELEASE(
"/etc/os-release");
1178 static const std::string PRETTY_NAME(
"PRETTY_NAME=");
1181 std::ifstream handle(OS_RELEASE.c_str(), std::ios::in);
1185 while (std::getline(handle, line)) {
1186 if (line.find(PRETTY_NAME) != std::string::npos) {
1187 if (line.length() > PRETTY_NAME.length() + 1) {
1188 size_t length = line.length() - PRETTY_NAME.length() - 2;
1189 description = line.substr(PRETTY_NAME.length() + 1, length);
1197 if (!description.empty()) {
1203 static const std::string REDHAT_RELEASE(
"/etc/redhat-release");
1204 if (
canRead(REDHAT_RELEASE)) {
1206 std::ifstream handle(REDHAT_RELEASE.c_str(), std::ios::in);
1210 while (std::getline(handle, line)) {
1211 if (!line.empty()) {
1212 description = std::move(line);
1219 if (!description.empty()) {
1226 std::vector<std::string> args;
1231 args.emplace_back(
"os");
1232 args.emplace_back(
"get");
1233 args.emplace_back(
"Caption");
1234 args.emplace_back(
"/value");
1237#if defined __APPLE__ || defined _WIN32
1239 Poco::Pipe outPipe, errorPipe;
1240 Poco::ProcessHandle ph = Poco::Process::launch(cmd, args,
nullptr, &outPipe, &errorPipe);
1241 const int rc = ph.wait();
1244 Poco::PipeInputStream pipeStream(outPipe);
1245 std::stringstream stringStream;
1246 Poco::StreamCopier::copyStream(pipeStream, stringStream);
1247 const std::string result = stringStream.str();
1252 description = product_name +
" " + product_vers;
1259 std::stringstream messageStream;
1260 messageStream <<
"command \"" << cmd <<
"\" failed with code: " << rc;
1263 }
catch (Poco::SystemException &e) {
1264 g_log.
debug(
"command \"" + cmd +
"\" failed");
1273 std::string username;
1278 if (!username.empty()) {
1281 }
catch (
const Poco::NotFoundException &e) {
1287 username =
m_pSysConfig->getString(
"system.env.USERNAME");
1288 if (!username.empty()) {
1291 }
catch (
const Poco::NotFoundException &e) {
1296 return std::string();
1323 const std::string applicationName =
"mantid";
1324#if POCO_OS == POCO_OS_WINDOWS_NT
1325 const std::string vendorName =
"mantidproject";
1326 wchar_t *w_appdata = _wgetenv(L
"APPDATA");
1327 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
1328 std::string appdata = converter.to_bytes(w_appdata);
1329 std::filesystem::path path(appdata);
1331 path /= applicationName;
1332 return path.string();
1334 const char *home = std::getenv(
"HOME");
1336 throw std::runtime_error(
"HOME environment variable not set - seen in ConfigService.getAppDataDir()");
1338 std::filesystem::path path(home);
1339 path /= (
"." + applicationName);
1340 return path.string();
1351 return execPath.parent_path().string() +
"/";
1360 std::string execpath;
1361 const size_t LEN(1024);
1365 unsigned int bytes = GetModuleFileName(NULL, pBuf, LEN);
1366#elif defined __linux__
1368 sprintf(szTmp,
"/proc/%d/exe", getpid());
1369 ssize_t bytes = readlink(szTmp, pBuf, LEN);
1370#elif defined __APPLE__
1373 _NSGetExecutablePath(pBuf, &bytes);
1374 const int success = _NSGetExecutablePath(pBuf, &bytes);
1379 if (bytes > 0 && bytes < 1024) {
1381 execpath = std::string(pBuf);
1394 char buff[MAX_PATH];
1395 GetFullPathName(path.c_str(), MAX_PATH, buff, NULL);
1396 std::string fullName(buff);
1397 size_t i = fullName.find(
':');
1400 if (i == std::string::npos)
1403 fullName.erase(i + 1);
1405 UINT type = GetDriveType(fullName.c_str());
1406 return DRIVE_REMOTE == type;
1407#elif defined __linux__
1421 std::ifstream mntfile(
"/proc/mounts");
1422 std::string txtread(
"");
1423 while (getline(mntfile, txtread)) {
1424 std::istringstream strm(txtread);
1425 std::string devname(
""), mntpoint(
""), fstype(
"");
1426 strm >> devname >> mntpoint >> fstype;
1430 std::transform(fstype.begin(), fstype.end(), fstype.begin(), toupper);
1432 if (fstype !=
"NFS" && fstype !=
"SMB")
1441 std::string::size_type idx = mntpoint.find(
"\\0");
1442 if (idx != std::string::npos) {
1443 std::string oct = mntpoint.substr(idx + 1, 3);
1446 strm.setf(std::ios::oct, std::ios::basefield);
1448 if (printch != -1) {
1449 mntpoint = mntpoint.substr(0, idx) +
static_cast<char>(printch) + mntpoint.substr(idx + 4);
1452 if (path.find(mntpoint) == 0)
1485 std::filesystem::path datadir(
m_pSysConfig->getString(
"system.homeDir"));
1486 datadir /=
".mantid";
1488 std::filesystem::create_directory(datadir);
1489 return datadir.string() +
"/";
1504 std::string searchPaths = boost::join(searchDirs,
";");
1514 setString(
"datasearch.directories", searchDirs);
1526 std::filesystem::path subDirPath;
1528 subDirPath = std::filesystem::path(subdir);
1529 }
catch (
const std::exception &) {
1534 if (!subDirPath.is_relative()) {
1540 std::filesystem::path newDirPath;
1542 newDirPath = std::filesystem::path(path) / subDirPath;
1544 if (std::find(newDataDirs.begin(), newDataDirs.end(), newDirPath.string()) == newDataDirs.end())
1545 newDataDirs.emplace_back(newDirPath.string());
1546 }
catch (
const std::exception &) {
1563 std::filesystem::path dirPath;
1565 dirPath = std::filesystem::path(path);
1567 std::string pathStr = dirPath.string();
1568 if (pathStr.back() !=
'/' && pathStr.back() !=
'\\') {
1573 newSearchString.append(
";" + path);
1574 setString(
"datasearch.directories", newSearchString);
1576 }
catch (
const std::exception &) {
1606 std::string directoryName =
getString(
"instrumentDefinition.vtp.directory");
1608 if (directoryName.empty()) {
1610 path /=
"instrument";
1611 path /=
"geometryCache";
1612 directoryName = path.string();
1614 return directoryName;
1630 path /=
"instrument";
1631 const std::string appdatadir = path.string();
1639 std::string directoryName =
getString(
"instrumentDefinition.directory",
true);
1640 if (directoryName.empty()) {
1645 directoryName = (basePath /
".." /
"instrument").lexically_normal().string();
1658 std::vector<std::string> &directoryList) {
1660 if (std::filesystem::is_directory(directoryName)) {
1661 directoryList.emplace_back(directoryName);
1667 }
catch (
const std::filesystem::filesystem_error &) {
1670 }
catch (
const std::exception &) {
1677 std::vector<std::string> returnPaths;
1680 if (!fName.empty()) {
1681 if (std::filesystem::exists(fName)) {
1682 returnPaths.emplace_back(fName);
1691 const std::string updateInstrStr = this->
getString(
"UpdateInstrumentDefinitions.OnStartup");
1693 auto instrDir = directoryNames.begin();
1699 if (!(updateInstrStr ==
"1" || updateInstrStr ==
"on" || updateInstrStr ==
"On") && directoryNames.size() > 1) {
1704 for (; instrDir != directoryNames.end(); ++instrDir) {
1705 std::filesystem::path p(*instrDir);
1706 p /=
"Facilities.xml";
1707 std::string filename = p.string();
1709 if (std::filesystem::exists(filename))
1710 returnPaths.emplace_back(filename);
1713 if (returnPaths.size() > 0) {
1718 std::string directoryNamesList = boost::algorithm::join(directoryNames,
", ");
1719 throw std::runtime_error(
"Failed to find \"Facilities.xml\". Searched in " + directoryNamesList);
1738 size_t attemptIndex = 0;
1739 bool success =
false;
1740 while ((!success) && (attemptIndex < fileNames.size())) {
1741 const auto &fileName = fileNames[attemptIndex];
1744 Poco::AutoPtr<Poco::XML::Document> pDoc;
1746 Poco::XML::DOMParser pParser;
1747 pDoc = pParser.parse(fileName);
1753 Poco::XML::Element *pRootElem = pDoc->documentElement();
1754 if (!pRootElem->hasChildNodes()) {
1755 throw std::runtime_error(
"No root element in Facilities.xml file");
1758 const Poco::AutoPtr<Poco::XML::NodeList> pNL_facility = pRootElem->getElementsByTagName(
"facility");
1759 const size_t n = pNL_facility->length();
1761 for (
unsigned long i = 0; i <
n; ++i) {
1762 const auto *elem =
dynamic_cast<Poco::XML::Element *
>(pNL_facility->item(i));
1769 throw std::runtime_error(
"The facility definition file " + fileName +
" defines no facilities");
1774 }
catch (std::runtime_error &ex) {
1776 g_log.
error() <<
"Failed to load the facilities.xml file at " << fileName <<
"\nIt might be corrupt. "
1777 << ex.what() <<
"\nWill try to load another version.\n";
1780 if (attemptIndex == fileNames.size()) {
1781 const std::string errorMessage =
"No more Facilities.xml files can be found, Mantid will not be "
1782 "able to start, Sorry. Try reinstalling Mantid.";
1788 throw std::runtime_error(errorMessage);
1814 if (!defaultFacility.empty()) {
1816 g_log.
debug() <<
"Looking for " << instrumentName <<
" at " << defaultFacility <<
".\n";
1827 g_log.
debug() <<
"Looking for " << instrumentName <<
" at " << (*facility).name() <<
".\n";
1828 return (*facility).instrument(instrumentName);
1835 const std::string errMsg =
"Failed to find an instrument with this name in any facility: '" + instrumentName +
"' -";
1836 g_log.
debug(
"Instrument " + instrumentName +
" not found");
1849 auto names = std::vector<std::string>(
m_facilities.size());
1851 [](
const FacilityInfo *facility) { return facility->name(); });
1860 std::string defFacility =
getString(
"default.facility");
1861 if (defFacility.empty()) {
1874 if (facilityName.empty())
1878 [&facilityName](
const auto f) { return f->name() == facilityName; });
1900 g_log.
error(
"Failed to set default facility to be " + facilityName +
". Facility not found");
1903 assert(foundFacility);
1904 setString(
"default.facility", facilityName);
1906 const auto &associatedInsts = foundFacility->
instruments();
1907 if (associatedInsts.empty()) {
1908 throw std::invalid_argument(
"The selected facility has no instruments associated with it");
1938 auto proxyHost = getValue<std::string>(
"proxy.host");
1939 auto proxyPort = getValue<int>(
"proxy.port");
1941 if (proxyHost.has_value() && proxyPort.has_value()) {
1956 const int options)
const {
1958 g_log.
debug() <<
"getFullPath(" << fName <<
")\n";
1960 std::filesystem::path filepath(fName);
1961 if (filepath.is_absolute())
1966 std::filesystem::path fullPath = std::filesystem::current_path() / fName;
1967 if (std::filesystem::exists(fullPath) && (!ignoreDirs || !std::filesystem::is_directory(fullPath)))
1968 return fullPath.string();
1969 }
catch (
const std::exception &) {
1974 directoryNames.insert(directoryNames.end(), instrDirectories.begin(), instrDirectories.end());
1975 for (
const auto &searchPath : directoryNames) {
1976 g_log.
debug() <<
"Searching for " << fName <<
" in " << searchPath <<
"\n";
1982 if (fName.find(
"*") != std::string::npos) {
1984 std::filesystem::path path = std::filesystem::path(searchPath) / fName;
1985 std::set<std::string> files;
1987 if (!files.empty()) {
1988 std::filesystem::path matchPath(*files.begin());
1989 if (ignoreDirs && std::filesystem::is_directory(matchPath)) {
1992 return *files.begin();
1996 std::filesystem::path path = std::filesystem::path(searchPath) / fName;
1997 if (std::filesystem::exists(path) && !(ignoreDirs && std::filesystem::is_directory(path))) {
1998 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 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.
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::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.