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\n";
601 filestr <<
"## SANS ISIS Command Interface\n";
602 filestr <<
"## Uncomment below line to allow usage of deprecated ISIS Command Interface\n";
603 filestr <<
"#sans.deprecated_command_interface=On\n\n";
606 }
catch (std::runtime_error &ex) {
623 }
catch (
const std::exception &) {
628 const bool append =
false;
629 const bool updateCaches =
true;
663 std::string updated_file;
665 std::ifstream reader(filename.c_str(), std::ios::in);
667 throw std::runtime_error(
"Error opening user properties file. Cannot save "
668 "updated configuration.");
671 std::string file_line, output;
672 bool line_continuing(
false);
673 while (std::getline(reader, file_line)) {
674 if (!file_line.empty()) {
675 char last = *(file_line.end() - 1);
679 if (!line_continuing)
681 line_continuing =
true;
682 output += file_line +
"\n";
684 }
else if (line_continuing) {
686 line_continuing =
false;
692 updated_file +=
"\n";
700 std::string::size_type pos = output.find(
'=');
701 if (pos == std::string::npos) {
704 key = output.substr(0, pos);
707 Poco::trimInPlace(key);
710 std::string::size_type comment = key.find(
'#');
715 updated_file += output;
723 Poco::replaceInPlace(
value,
"\\",
"\\\\");
724 updated_file.append(key).append(
"=").append(
value);
728 updated_file +=
"\n";
734 updated_file +=
"\n";
736 for (
auto key_itr =
m_changed_keys.begin(); key_itr != key_end;) {
742 updated_file += *key_itr +
"=";
744 Poco::replaceInPlace(
value,
"\\",
"\\\\");
745 updated_file +=
value;
746 if (++key_itr != key_end) {
747 updated_file +=
"\n";
754 std::ofstream writer(filename.c_str(), std::ios_base::trunc);
757 g_log.
error() <<
"Error writing new user properties file. Cannot save "
758 "current configuration.\n";
759 throw std::runtime_error(
"Error writing new user properties file. Cannot "
760 "save current configuration.");
763 writer.write(updated_file.c_str(), updated_file.size());
780 if (
m_pConf->hasProperty(keyName)) {
789 g_log.
debug() <<
"Unable to find " << keyName <<
" in the properties file" <<
'\n';
803 std::vector<std::string> rawKeys;
804 m_pConf->keys(keyName, rawKeys);
812 std::vector<std::string> rootKeys =
getKeys(root);
814 if (rootKeys.empty())
815 allKeys.emplace_back(root);
817 for (
auto &rootKey : rootKeys) {
818 std::string searchString;
820 searchString.append(rootKey);
822 searchString.append(root).append(
".").append(rootKey);
838 std::vector<std::string> allKeys;
867std::string expandEnvironmentInFilepath(
const std::string &target) {
868 std::string result = target;
873 while ((pos = result.find(
'%', pos)) != std::string::npos) {
874 size_t end = result.find(
'%', pos + 1);
875 if (end == std::string::npos)
878 std::string varName = result.substr(pos + 1, end - pos - 1);
879 const char *envValue = std::getenv(varName.c_str());
882 result.replace(pos, end - pos + 1, envValue);
883 pos += std::strlen(envValue);
891 while ((pos = result.find(
'$', pos)) != std::string::npos) {
896 if (pos + 1 < result.length() && result[pos + 1] ==
'{') {
898 end = result.find(
'}', pos + 2);
899 if (end == std::string::npos) {
903 varName = result.substr(pos + 2, end - pos - 2);
908 while (end < result.length() && (std::isalnum(result[end]) || result[end] ==
'_')) {
911 varName = result.substr(pos + 1, end - pos - 1);
914 if (!varName.empty()) {
915 const char *envValue = std::getenv(varName.c_str());
917 result.replace(start, end - start, envValue);
918 pos = start + std::strlen(envValue);
942 std::filesystem::path filepath(expandEnvironmentInFilepath(target));
944 if (std::filesystem::exists(filepath) && std::filesystem::is_regular_file(filepath)) {
950 std::string ext = filepath.extension().string();
951 std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
952 return (ext ==
".exe" || ext ==
".bat" || ext ==
".cmd" || ext ==
".com");
955 auto perms = std::filesystem::status(filepath).permissions();
956 return (perms & std::filesystem::perms::owner_exec) != std::filesystem::perms::none ||
957 (perms & std::filesystem::perms::group_exec) != std::filesystem::perms::none ||
958 (perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none;
962 }
catch (
const std::exception &) {
980 const std::vector<std::string> &programArguments)
const {
982 std::string expTarget = expandEnvironmentInFilepath(programFilePath);
983 Poco::Process::launch(expTarget, programArguments);
984 }
catch (Poco::SystemException &e) {
985 throw std::runtime_error(e.what());
1005 if (key ==
"datasearch.directories") {
1007 }
else if (key ==
"instrumentDefinition.directory") {
1009 }
else if (key ==
"defaultsave.directory") {
1011 }
else if (key ==
"logging.channels.consoleChannel.class") {
1014 }
else if (key == LOG_LEVEL_KEY) {
1030 std::string strValue =
getString(keyName);
1035 return std::nullopt;
1038 return std::optional<T>(output);
1049 auto returnedValue = getValue<std::string>(keyName);
1050 if (!returnedValue.has_value()) {
1051 return std::nullopt;
1054 auto &configVal = returnedValue.value();
1056 std::transform(configVal.begin(), configVal.end(), configVal.begin(), ::tolower);
1058 boost::trim(configVal);
1060 bool trueString = configVal ==
"true";
1061 bool valueOne = configVal ==
"1";
1062 bool onOffString = configVal ==
"on";
1065 return trueString || valueOne || onOffString;
1074 return "Mantid.local.properties";
1076 return "/etc/mantid.local.properties";
1094 return m_pSysConfig->getString(
"system.env." + keyName);
1108 auto osArch =
m_pSysConfig->getString(
"system.osArchitecture");
1110 if (osArch ==
"x86_64") {
1114 size_t size =
sizeof(ret);
1115 if (sysctlbyname(
"sysctl.proc_translated", &ret, &size,
nullptr, 0) != -1 && ret == 1) {
1116 osArch =
"arm64_(x86_64)";
1117 g_log.
warning(
"You are running an Intel build of Mantid on Apple silicon, which will be significantly slower and "
1118 "use more power. For best performance, install the Arm version of Mantid. This version is "
1119 "available here: https://downloads.mantidproject.org");
1122 g_log.
warning(
"Mantid v6.14 is the last version that will support Intel macOS.");
1144 if (!std::filesystem::exists(filename)) {
1149 std::ifstream file(filename);
1155 size_t start = orig.find(key);
1156 if (start == std::string::npos) {
1157 return std::string();
1159 start += key.size();
1161 size_t stop = orig.find(
'\n', start);
1162 if (stop == std::string::npos) {
1163 return std::string();
1175 std::string description;
1178 static const std::string OS_RELEASE(
"/etc/os-release");
1180 static const std::string PRETTY_NAME(
"PRETTY_NAME=");
1183 std::ifstream handle(OS_RELEASE.c_str(), std::ios::in);
1187 while (std::getline(handle, line)) {
1188 if (line.find(PRETTY_NAME) != std::string::npos) {
1189 if (line.length() > PRETTY_NAME.length() + 1) {
1190 size_t length = line.length() - PRETTY_NAME.length() - 2;
1191 description = line.substr(PRETTY_NAME.length() + 1, length);
1199 if (!description.empty()) {
1205 static const std::string REDHAT_RELEASE(
"/etc/redhat-release");
1206 if (
canRead(REDHAT_RELEASE)) {
1208 std::ifstream handle(REDHAT_RELEASE.c_str(), std::ios::in);
1212 while (std::getline(handle, line)) {
1213 if (!line.empty()) {
1214 description = std::move(line);
1221 if (!description.empty()) {
1228 std::vector<std::string> args;
1233 args.emplace_back(
"os");
1234 args.emplace_back(
"get");
1235 args.emplace_back(
"Caption");
1236 args.emplace_back(
"/value");
1239#if defined __APPLE__ || defined _WIN32
1241 Poco::Pipe outPipe, errorPipe;
1242 Poco::ProcessHandle ph = Poco::Process::launch(cmd, args,
nullptr, &outPipe, &errorPipe);
1243 const int rc = ph.wait();
1246 Poco::PipeInputStream pipeStream(outPipe);
1247 std::stringstream stringStream;
1248 Poco::StreamCopier::copyStream(pipeStream, stringStream);
1249 const std::string result = stringStream.str();
1254 description = product_name +
" " + product_vers;
1261 std::stringstream messageStream;
1262 messageStream <<
"command \"" << cmd <<
"\" failed with code: " << rc;
1265 }
catch (Poco::SystemException &e) {
1266 g_log.
debug(
"command \"" + cmd +
"\" failed");
1275 std::string username;
1280 if (!username.empty()) {
1283 }
catch (
const Poco::NotFoundException &e) {
1289 username =
m_pSysConfig->getString(
"system.env.USERNAME");
1290 if (!username.empty()) {
1293 }
catch (
const Poco::NotFoundException &e) {
1298 return std::string();
1325 const std::string applicationName =
"mantid";
1326#if POCO_OS == POCO_OS_WINDOWS_NT
1327 const std::string vendorName =
"mantidproject";
1328 wchar_t *w_appdata = _wgetenv(L
"APPDATA");
1329 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
1330 std::string appdata = converter.to_bytes(w_appdata);
1331 std::filesystem::path path(appdata);
1333 path /= applicationName;
1334 return path.string();
1336 const char *home = std::getenv(
"HOME");
1338 throw std::runtime_error(
"HOME environment variable not set - seen in ConfigService.getAppDataDir()");
1340 std::filesystem::path path(home);
1341 path /= (
"." + applicationName);
1342 return path.string();
1353 return execPath.parent_path().string() +
"/";
1362 std::string execpath;
1363 const size_t LEN(1024);
1367 unsigned int bytes = GetModuleFileName(NULL, pBuf, LEN);
1368#elif defined __linux__
1370 sprintf(szTmp,
"/proc/%d/exe", getpid());
1371 ssize_t bytes = readlink(szTmp, pBuf, LEN);
1372#elif defined __APPLE__
1375 _NSGetExecutablePath(pBuf, &bytes);
1376 const int success = _NSGetExecutablePath(pBuf, &bytes);
1381 if (bytes > 0 && bytes < 1024) {
1383 execpath = std::string(pBuf);
1396 char buff[MAX_PATH];
1397 GetFullPathName(path.c_str(), MAX_PATH, buff, NULL);
1398 std::string fullName(buff);
1399 size_t i = fullName.find(
':');
1402 if (i == std::string::npos)
1405 fullName.erase(i + 1);
1407 UINT type = GetDriveType(fullName.c_str());
1408 return DRIVE_REMOTE == type;
1409#elif defined __linux__
1423 std::ifstream mntfile(
"/proc/mounts");
1424 std::string txtread(
"");
1425 while (getline(mntfile, txtread)) {
1426 std::istringstream strm(txtread);
1427 std::string devname(
""), mntpoint(
""), fstype(
"");
1428 strm >> devname >> mntpoint >> fstype;
1432 std::transform(fstype.begin(), fstype.end(), fstype.begin(), toupper);
1434 if (fstype !=
"NFS" && fstype !=
"SMB")
1443 std::string::size_type idx = mntpoint.find(
"\\0");
1444 if (idx != std::string::npos) {
1445 std::string oct = mntpoint.substr(idx + 1, 3);
1448 strm.setf(std::ios::oct, std::ios::basefield);
1450 if (printch != -1) {
1451 mntpoint = mntpoint.substr(0, idx) +
static_cast<char>(printch) + mntpoint.substr(idx + 4);
1454 if (path.find(mntpoint) == 0)
1487 std::filesystem::path datadir(
m_pSysConfig->getString(
"system.homeDir"));
1488 datadir /=
".mantid";
1490 std::filesystem::create_directory(datadir);
1491 return datadir.string() +
"/";
1506 std::string searchPaths = boost::join(searchDirs,
";");
1516 setString(
"datasearch.directories", searchDirs);
1528 std::filesystem::path subDirPath;
1530 subDirPath = std::filesystem::path(subdir);
1531 }
catch (
const std::exception &) {
1536 if (!subDirPath.is_relative()) {
1542 std::filesystem::path newDirPath;
1544 newDirPath = std::filesystem::path(path) / subDirPath;
1546 if (std::find(newDataDirs.begin(), newDataDirs.end(), newDirPath.string()) == newDataDirs.end())
1547 newDataDirs.emplace_back(newDirPath.string());
1548 }
catch (
const std::exception &) {
1565 std::filesystem::path dirPath;
1567 dirPath = std::filesystem::path(path);
1569 std::string pathStr = dirPath.string();
1570 if (pathStr.back() !=
'/' && pathStr.back() !=
'\\') {
1575 newSearchString.append(
";" + path);
1576 setString(
"datasearch.directories", newSearchString);
1578 }
catch (
const std::exception &) {
1608 std::string directoryName =
getString(
"instrumentDefinition.vtp.directory");
1610 if (directoryName.empty()) {
1612 path /=
"instrument";
1613 path /=
"geometryCache";
1614 directoryName = path.string();
1616 return directoryName;
1632 path /=
"instrument";
1633 const std::string appdatadir = path.string();
1641 std::string directoryName =
getString(
"instrumentDefinition.directory",
true);
1642 if (directoryName.empty()) {
1647 directoryName = (basePath /
".." /
"instrument").lexically_normal().string();
1660 std::vector<std::string> &directoryList) {
1662 if (std::filesystem::is_directory(directoryName)) {
1663 directoryList.emplace_back(directoryName);
1669 }
catch (
const std::filesystem::filesystem_error &) {
1672 }
catch (
const std::exception &) {
1679 std::vector<std::string> returnPaths;
1682 if (!fName.empty()) {
1683 if (std::filesystem::exists(fName)) {
1684 returnPaths.emplace_back(fName);
1693 const std::string updateInstrStr = this->
getString(
"UpdateInstrumentDefinitions.OnStartup");
1695 auto instrDir = directoryNames.begin();
1701 if (!(updateInstrStr ==
"1" || updateInstrStr ==
"on" || updateInstrStr ==
"On") && directoryNames.size() > 1) {
1706 for (; instrDir != directoryNames.end(); ++instrDir) {
1707 std::filesystem::path p(*instrDir);
1708 p /=
"Facilities.xml";
1709 std::string filename = p.string();
1711 if (std::filesystem::exists(filename))
1712 returnPaths.emplace_back(filename);
1715 if (returnPaths.size() > 0) {
1720 std::string directoryNamesList = boost::algorithm::join(directoryNames,
", ");
1721 throw std::runtime_error(
"Failed to find \"Facilities.xml\". Searched in " + directoryNamesList);
1740 size_t attemptIndex = 0;
1741 bool success =
false;
1742 while ((!success) && (attemptIndex < fileNames.size())) {
1743 const auto &fileName = fileNames[attemptIndex];
1746 Poco::AutoPtr<Poco::XML::Document> pDoc;
1748 Poco::XML::DOMParser pParser;
1749 pDoc = pParser.parse(fileName);
1755 Poco::XML::Element *pRootElem = pDoc->documentElement();
1756 if (!pRootElem->hasChildNodes()) {
1757 throw std::runtime_error(
"No root element in Facilities.xml file");
1760 const Poco::AutoPtr<Poco::XML::NodeList> pNL_facility = pRootElem->getElementsByTagName(
"facility");
1761 const size_t n = pNL_facility->length();
1763 for (
unsigned long i = 0; i <
n; ++i) {
1764 const auto *elem =
dynamic_cast<Poco::XML::Element *
>(pNL_facility->item(i));
1771 throw std::runtime_error(
"The facility definition file " + fileName +
" defines no facilities");
1776 }
catch (std::runtime_error &ex) {
1778 g_log.
error() <<
"Failed to load the facilities.xml file at " << fileName <<
"\nIt might be corrupt. "
1779 << ex.what() <<
"\nWill try to load another version.\n";
1782 if (attemptIndex == fileNames.size()) {
1783 const std::string errorMessage =
"No more Facilities.xml files can be found, Mantid will not be "
1784 "able to start, Sorry. Try reinstalling Mantid.";
1790 throw std::runtime_error(errorMessage);
1818 if (!defaultFacility.empty()) {
1820 g_log.
debug() <<
"Looking for " << instrumentName <<
" at " << defaultFacility <<
".\n";
1831 g_log.
debug() <<
"Looking for " << instrumentName <<
" at " << (*facility).name() <<
".\n";
1832 return (*facility).instrument(instrumentName);
1839 const std::string errMsg =
"Failed to find an instrument with this name in any facility: '" + instrumentName +
"' -";
1840 g_log.
debug(
"Instrument " + instrumentName +
" not found");
1846 std::vector<std::string> names;
1849 const auto &insts = facility->instruments();
1850 for (
const auto &inst : insts) {
1851 names.emplace_back(inst.shortName());
1852 names.emplace_back(inst.name());
1856 std::sort(names.begin(), names.end());
1857 const auto last = std::unique(names.begin(), names.end());
1858 names.erase(last, names.end());
1863 std::string longestPrefix;
1868 auto it = std::prev(match);
1870 if (hint.starts_with(*it)) {
1871 longestPrefix = *it;
1874 if ((*it)[0] != hint[0]) {
1884 return longestPrefix;
1896 auto names = std::vector<std::string>(
m_facilities.size());
1898 [](
const FacilityInfo *facility) { return facility->name(); });
1907 std::string defFacility =
getString(
"default.facility");
1908 if (defFacility.empty()) {
1921 if (facilityName.empty())
1925 [&facilityName](
const auto f) { return f->name() == facilityName; });
1947 g_log.
error(
"Failed to set default facility to be " + facilityName +
". Facility not found");
1950 assert(foundFacility);
1951 setString(
"default.facility", facilityName);
1953 const auto &associatedInsts = foundFacility->
instruments();
1954 if (associatedInsts.empty()) {
1955 throw std::invalid_argument(
"The selected facility has no instruments associated with it");
1985 auto proxyHost = getValue<std::string>(
"proxy.host");
1986 auto proxyPort = getValue<int>(
"proxy.port");
1988 if (proxyHost.has_value() && proxyPort.has_value()) {
2003 const int options)
const {
2005 g_log.
debug() <<
"getFullPath(" << fName <<
")\n";
2007 std::filesystem::path filepath(fName);
2008 if (filepath.is_absolute())
2013 std::filesystem::path fullPath = std::filesystem::current_path() / fName;
2014 if (std::filesystem::exists(fullPath) && (!ignoreDirs || !std::filesystem::is_directory(fullPath)))
2015 return fullPath.string();
2016 }
catch (
const std::exception &) {
2021 directoryNames.insert(directoryNames.end(), instrDirectories.begin(), instrDirectories.end());
2022 for (
const auto &searchPath : directoryNames) {
2023 g_log.
debug() <<
"Searching for " << fName <<
" in " << searchPath <<
"\n";
2029 if (fName.find(
"*") != std::string::npos) {
2031 std::filesystem::path path = std::filesystem::path(searchPath) / fName;
2032 std::set<std::string> files;
2034 if (!files.empty()) {
2035 std::filesystem::path matchPath(*files.begin());
2036 if (ignoreDirs && std::filesystem::is_directory(matchPath)) {
2039 return *files.begin();
2043 std::filesystem::path path = std::filesystem::path(searchPath) / fName;
2044 if (std::filesystem::exists(path) && !(ignoreDirs && std::filesystem::is_directory(path))) {
2045 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.