13#include "MantidKernel/DllConfig.h"
24#include <Poco/AutoPtr.h>
25#include <Poco/Channel.h>
26#include <Poco/DOM/DOMParser.h>
27#include <Poco/DOM/Document.h>
28#include <Poco/DOM/Element.h>
29#include <Poco/DOM/Node.h>
30#include <Poco/DOM/NodeList.h>
31#include <Poco/Environment.h>
32#include <Poco/Exception.h>
33#include <Poco/Instantiator.h>
34#include <Poco/Logger.h>
35#include <Poco/LoggingFactory.h>
36#include <Poco/LoggingRegistry.h>
39#include <Poco/PipeStream.h>
40#include <Poco/Platform.h>
41#include <Poco/Process.h>
42#include <Poco/StreamCopier.h>
43#include <Poco/String.h>
45#include <Poco/Util/LoggingConfigurator.h>
46#include <Poco/Util/PropertyFileConfiguration.h>
47#include <Poco/Util/SystemConfiguration.h>
48#include <Poco/Version.h>
50#include <boost/algorithm/string/join.hpp>
51#include <boost/algorithm/string/trim.hpp>
69#include <mach-o/dyld.h>
70#include <sys/sysctl.h>
89Logger
g_log(
"ConfigService");
91const std::string PATH_DELIMITERS =
";,";
99std::vector<std::string> splitPath(
const std::string &path) {
100 std::vector<std::string> splitted;
102 if (path.find_first_of(PATH_DELIMITERS) == std::string::npos) {
103 splitted.emplace_back(path);
110 splitted.emplace_back(*itr);
117const std::string LOG_LEVEL_KEY(
"logging.loggers.root.level");
127 : m_pConf(nullptr), m_pSysConfig(new
Poco::Util::SystemConfiguration()), m_changed_keys(), m_strBaseDir(
""),
128 m_propertyString(
""), m_properties_file_name(
"Mantid.properties"),
129 m_user_properties_file_name(
"Mantid.user.properties"), m_dataSearchDirs(), m_instrumentDirs(), m_proxyInfo() {
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\n";
602 filestr <<
"## SANS ISIS Command Interface\n";
603 filestr <<
"## Uncomment below line to allow usage of deprecated ISIS Command Interface\n";
604 filestr <<
"#sans.deprecated_command_interface=On\n\n";
607 }
catch (std::runtime_error &ex) {
624 }
catch (
const std::exception &) {
629 const bool append =
false;
630 const bool updateCaches =
true;
664 std::string updated_file;
666 std::ifstream reader(filename.c_str(), std::ios::in);
668 throw std::runtime_error(
"Error opening user properties file. Cannot save "
669 "updated configuration.");
672 std::string file_line, output;
673 bool line_continuing(
false);
674 while (std::getline(reader, file_line)) {
675 if (!file_line.empty()) {
676 char last = *(file_line.end() - 1);
680 if (!line_continuing)
682 line_continuing =
true;
683 output += file_line +
"\n";
685 }
else if (line_continuing) {
687 line_continuing =
false;
693 updated_file +=
"\n";
701 std::string::size_type pos = output.find(
'=');
702 if (pos == std::string::npos) {
705 key = output.substr(0, pos);
708 Poco::trimInPlace(key);
711 std::string::size_type comment = key.find(
'#');
716 updated_file += output;
724 Poco::replaceInPlace(
value,
"\\",
"\\\\");
725 updated_file.append(key).append(
"=").append(
value);
729 updated_file +=
"\n";
735 updated_file +=
"\n";
737 for (
auto key_itr =
m_changed_keys.begin(); key_itr != key_end;) {
743 updated_file += *key_itr +
"=";
745 Poco::replaceInPlace(
value,
"\\",
"\\\\");
746 updated_file +=
value;
747 if (++key_itr != key_end) {
748 updated_file +=
"\n";
755 std::ofstream writer(filename.c_str(), std::ios_base::trunc);
758 g_log.
error() <<
"Error writing new user properties file. Cannot save "
759 "current configuration.\n";
760 throw std::runtime_error(
"Error writing new user properties file. Cannot "
761 "save current configuration.");
764 writer.write(updated_file.c_str(), updated_file.size());
781 if (
m_pConf->hasProperty(keyName)) {
790 g_log.
debug() <<
"Unable to find " << keyName <<
" in the properties file" <<
'\n';
804 std::vector<std::string> rawKeys;
805 m_pConf->keys(keyName, rawKeys);
813 std::vector<std::string> rootKeys =
getKeys(root);
815 if (rootKeys.empty())
816 allKeys.emplace_back(root);
818 for (
auto &rootKey : rootKeys) {
819 std::string searchString;
821 searchString.append(rootKey);
823 searchString.append(root).append(
".").append(rootKey);
839 std::vector<std::string> allKeys;
868std::string expandEnvironmentInFilepath(
const std::string &target) {
869 std::string result = target;
874 while ((pos = result.find(
'%', pos)) != std::string::npos) {
875 size_t end = result.find(
'%', pos + 1);
876 if (end == std::string::npos)
879 std::string varName = result.substr(pos + 1, end - pos - 1);
880 const char *envValue = std::getenv(varName.c_str());
883 result.replace(pos, end - pos + 1, envValue);
884 pos += std::strlen(envValue);
892 while ((pos = result.find(
'$', pos)) != std::string::npos) {
897 if (pos + 1 < result.length() && result[pos + 1] ==
'{') {
899 end = result.find(
'}', pos + 2);
900 if (end == std::string::npos) {
904 varName = result.substr(pos + 2, end - pos - 2);
909 while (end < result.length() && (std::isalnum(result[end]) || result[end] ==
'_')) {
912 varName = result.substr(pos + 1, end - pos - 1);
915 if (!varName.empty()) {
916 const char *envValue = std::getenv(varName.c_str());
918 result.replace(start, end - start, envValue);
919 pos = start + std::strlen(envValue);
943 std::filesystem::path filepath(expandEnvironmentInFilepath(target));
945 if (std::filesystem::exists(filepath) && std::filesystem::is_regular_file(filepath)) {
951 std::string ext = filepath.extension().string();
952 std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
953 return (ext ==
".exe" || ext ==
".bat" || ext ==
".cmd" || ext ==
".com");
956 auto perms = std::filesystem::status(filepath).permissions();
957 return (perms & std::filesystem::perms::owner_exec) != std::filesystem::perms::none ||
958 (perms & std::filesystem::perms::group_exec) != std::filesystem::perms::none ||
959 (perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none;
963 }
catch (
const std::exception &) {
981 const std::vector<std::string> &programArguments)
const {
983 std::string expTarget = expandEnvironmentInFilepath(programFilePath);
984 Poco::Process::launch(expTarget, programArguments);
985 }
catch (Poco::SystemException &e) {
986 throw std::runtime_error(e.what());
1006 if (key ==
"datasearch.directories") {
1008 }
else if (key ==
"instrumentDefinition.directory") {
1010 }
else if (key ==
"defaultsave.directory") {
1012 }
else if (key ==
"logging.channels.consoleChannel.class") {
1015 }
else if (key == LOG_LEVEL_KEY) {
1031 std::string strValue =
getString(keyName);
1036 return std::nullopt;
1039 return std::optional<T>(output);
1050 auto returnedValue = getValue<std::string>(keyName);
1051 if (!returnedValue.has_value()) {
1052 return std::nullopt;
1055 auto &configVal = returnedValue.value();
1057 std::transform(configVal.begin(), configVal.end(), configVal.begin(), ::tolower);
1059 boost::trim(configVal);
1061 bool trueString = configVal ==
"true";
1062 bool valueOne = configVal ==
"1";
1063 bool onOffString = configVal ==
"on";
1066 return trueString || valueOne || onOffString;
1075 return "Mantid.local.properties";
1077 return "/etc/mantid.local.properties";
1095 return m_pSysConfig->getString(
"system.env." + keyName);
1109 auto osArch =
m_pSysConfig->getString(
"system.osArchitecture");
1111 if (osArch ==
"x86_64") {
1115 size_t size =
sizeof(ret);
1116 if (sysctlbyname(
"sysctl.proc_translated", &ret, &size,
nullptr, 0) != -1 && ret == 1) {
1117 osArch =
"arm64_(x86_64)";
1118 g_log.
warning(
"You are running an Intel build of Mantid on Apple silicon, which will be significantly slower and "
1119 "use more power. For best performance, install the Arm version of Mantid. This version is "
1120 "available here: https://downloads.mantidproject.org");
1123 g_log.
warning(
"Mantid v6.14 is the last version that will support Intel macOS.");
1145 if (!std::filesystem::exists(filename)) {
1150 std::ifstream file(filename);
1156 size_t start = orig.find(key);
1157 if (start == std::string::npos) {
1158 return std::string();
1160 start += key.size();
1162 size_t stop = orig.find(
'\n', start);
1163 if (stop == std::string::npos) {
1164 return std::string();
1176 std::string description;
1179 static const std::string OS_RELEASE(
"/etc/os-release");
1181 static const std::string PRETTY_NAME(
"PRETTY_NAME=");
1184 std::ifstream handle(OS_RELEASE.c_str(), std::ios::in);
1188 while (std::getline(handle, line)) {
1189 if (line.find(PRETTY_NAME) != std::string::npos) {
1190 if (line.length() > PRETTY_NAME.length() + 1) {
1191 size_t length = line.length() - PRETTY_NAME.length() - 2;
1192 description = line.substr(PRETTY_NAME.length() + 1, length);
1200 if (!description.empty()) {
1206 static const std::string REDHAT_RELEASE(
"/etc/redhat-release");
1207 if (
canRead(REDHAT_RELEASE)) {
1209 std::ifstream handle(REDHAT_RELEASE.c_str(), std::ios::in);
1213 while (std::getline(handle, line)) {
1214 if (!line.empty()) {
1215 description = std::move(line);
1222 if (!description.empty()) {
1229 std::vector<std::string> args;
1234 args.emplace_back(
"os");
1235 args.emplace_back(
"get");
1236 args.emplace_back(
"Caption");
1237 args.emplace_back(
"/value");
1240#if defined __APPLE__ || defined _WIN32
1242 Poco::Pipe outPipe, errorPipe;
1243 Poco::ProcessHandle ph = Poco::Process::launch(cmd, args,
nullptr, &outPipe, &errorPipe);
1244 const int rc = ph.wait();
1247 Poco::PipeInputStream pipeStream(outPipe);
1248 std::stringstream stringStream;
1249 Poco::StreamCopier::copyStream(pipeStream, stringStream);
1250 const std::string result = stringStream.str();
1255 description = product_name +
" " + product_vers;
1262 std::stringstream messageStream;
1263 messageStream <<
"command \"" << cmd <<
"\" failed with code: " << rc;
1266 }
catch (Poco::SystemException &e) {
1267 g_log.
debug(
"command \"" + cmd +
"\" failed");
1276 std::string username;
1281 if (!username.empty()) {
1284 }
catch (
const Poco::NotFoundException &e) {
1290 username =
m_pSysConfig->getString(
"system.env.USERNAME");
1291 if (!username.empty()) {
1294 }
catch (
const Poco::NotFoundException &e) {
1299 return std::string();
1326 const std::string applicationName =
"mantid";
1327#if POCO_OS == POCO_OS_WINDOWS_NT
1328 const std::string vendorName =
"mantidproject";
1329 wchar_t *w_appdata = _wgetenv(L
"APPDATA");
1330 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
1331 std::string appdata = converter.to_bytes(w_appdata);
1332 std::filesystem::path path(appdata);
1334 path /= applicationName;
1335 return path.string();
1337 const char *home = std::getenv(
"HOME");
1339 throw std::runtime_error(
"HOME environment variable not set - seen in ConfigService.getAppDataDir()");
1341 std::filesystem::path path(home);
1342 path /= (
"." + applicationName);
1343 return path.string();
1354 return execPath.parent_path().string() +
"/";
1363 std::string execpath;
1364 const size_t LEN(1024);
1368 unsigned int bytes = GetModuleFileName(NULL, pBuf, LEN);
1369#elif defined __linux__
1371 sprintf(szTmp,
"/proc/%d/exe", getpid());
1372 ssize_t bytes = readlink(szTmp, pBuf, LEN);
1373#elif defined __APPLE__
1376 _NSGetExecutablePath(pBuf, &bytes);
1377 const int success = _NSGetExecutablePath(pBuf, &bytes);
1382 if (bytes > 0 && bytes < 1024) {
1384 execpath = std::string(pBuf);
1397 char buff[MAX_PATH];
1398 GetFullPathName(path.c_str(), MAX_PATH, buff, NULL);
1399 std::string fullName(buff);
1400 size_t i = fullName.find(
':');
1403 if (i == std::string::npos)
1406 fullName.erase(i + 1);
1408 UINT type = GetDriveType(fullName.c_str());
1409 return DRIVE_REMOTE == type;
1410#elif defined __linux__
1424 std::ifstream mntfile(
"/proc/mounts");
1425 std::string txtread(
"");
1426 while (getline(mntfile, txtread)) {
1427 std::istringstream strm(txtread);
1428 std::string devname(
""), mntpoint(
""), fstype(
"");
1429 strm >> devname >> mntpoint >> fstype;
1433 std::transform(fstype.begin(), fstype.end(), fstype.begin(), toupper);
1435 if (fstype !=
"NFS" && fstype !=
"SMB")
1444 std::string::size_type idx = mntpoint.find(
"\\0");
1445 if (idx != std::string::npos) {
1446 std::string oct = mntpoint.substr(idx + 1, 3);
1449 strm.setf(std::ios::oct, std::ios::basefield);
1451 if (printch != -1) {
1452 mntpoint = mntpoint.substr(0, idx) +
static_cast<char>(printch) + mntpoint.substr(idx + 4);
1455 if (path.find(mntpoint) == 0)
1488 std::filesystem::path datadir(
m_pSysConfig->getString(
"system.homeDir"));
1489 datadir /=
".mantid";
1491 std::filesystem::create_directory(datadir);
1492 return datadir.string() +
"/";
1507 std::string searchPaths = boost::join(searchDirs,
";");
1517 setString(
"datasearch.directories", searchDirs);
1529 std::filesystem::path subDirPath;
1531 subDirPath = std::filesystem::path(subdir);
1532 }
catch (
const std::exception &) {
1537 if (!subDirPath.is_relative()) {
1543 std::filesystem::path newDirPath;
1545 newDirPath = std::filesystem::path(path) / subDirPath;
1547 if (std::find(newDataDirs.begin(), newDataDirs.end(), newDirPath.string()) == newDataDirs.end())
1548 newDataDirs.emplace_back(newDirPath.string());
1549 }
catch (
const std::exception &) {
1566 std::filesystem::path dirPath;
1568 dirPath = std::filesystem::path(path);
1570 std::string pathStr = dirPath.string();
1571 if (pathStr.back() !=
'/' && pathStr.back() !=
'\\') {
1576 newSearchString.append(
";" + path);
1577 setString(
"datasearch.directories", newSearchString);
1579 }
catch (
const std::exception &) {
1609 std::string directoryName =
getString(
"instrumentDefinition.vtp.directory");
1611 if (directoryName.empty()) {
1613 path /=
"instrument";
1614 path /=
"geometryCache";
1615 directoryName = path.string();
1617 return directoryName;
1633 path /=
"instrument";
1634 const std::string appdatadir = path.string();
1642 std::string directoryName =
getString(
"instrumentDefinition.directory",
true);
1643 if (directoryName.empty()) {
1648 directoryName = (basePath /
".." /
"instrument").lexically_normal().string();
1661 std::vector<std::string> &directoryList) {
1663 if (std::filesystem::is_directory(directoryName)) {
1664 directoryList.emplace_back(directoryName);
1670 }
catch (
const std::filesystem::filesystem_error &) {
1673 }
catch (
const std::exception &) {
1680 std::vector<std::string> returnPaths;
1683 if (!fName.empty()) {
1684 if (std::filesystem::exists(fName)) {
1685 returnPaths.emplace_back(fName);
1694 const std::string updateInstrStr = this->
getString(
"UpdateInstrumentDefinitions.OnStartup");
1696 auto instrDir = directoryNames.begin();
1702 if (!(updateInstrStr ==
"1" || updateInstrStr ==
"on" || updateInstrStr ==
"On") && directoryNames.size() > 1) {
1707 for (; instrDir != directoryNames.end(); ++instrDir) {
1708 std::filesystem::path p(*instrDir);
1709 p /=
"Facilities.xml";
1710 std::string filename = p.string();
1712 if (std::filesystem::exists(filename))
1713 returnPaths.emplace_back(filename);
1716 if (returnPaths.size() > 0) {
1721 std::string directoryNamesList = boost::algorithm::join(directoryNames,
", ");
1722 throw std::runtime_error(
"Failed to find \"Facilities.xml\". Searched in " + directoryNamesList);
1741 size_t attemptIndex = 0;
1742 bool success =
false;
1743 while ((!success) && (attemptIndex < fileNames.size())) {
1744 const auto &fileName = fileNames[attemptIndex];
1747 Poco::AutoPtr<Poco::XML::Document> pDoc;
1749 Poco::XML::DOMParser pParser;
1750 pDoc = pParser.parse(fileName);
1756 Poco::XML::Element *pRootElem = pDoc->documentElement();
1757 if (!pRootElem->hasChildNodes()) {
1758 throw std::runtime_error(
"No root element in Facilities.xml file");
1761 const Poco::AutoPtr<Poco::XML::NodeList> pNL_facility = pRootElem->getElementsByTagName(
"facility");
1762 const size_t n = pNL_facility->length();
1764 for (
unsigned long i = 0; i <
n; ++i) {
1765 const auto *elem =
dynamic_cast<Poco::XML::Element *
>(pNL_facility->item(i));
1772 throw std::runtime_error(
"The facility definition file " + fileName +
" defines no facilities");
1777 }
catch (std::runtime_error &ex) {
1779 g_log.
error() <<
"Failed to load the facilities.xml file at " << fileName <<
"\nIt might be corrupt. "
1780 << ex.what() <<
"\nWill try to load another version.\n";
1783 if (attemptIndex == fileNames.size()) {
1784 const std::string errorMessage =
"No more Facilities.xml files can be found, Mantid will not be "
1785 "able to start, Sorry. Try reinstalling Mantid.";
1791 throw std::runtime_error(errorMessage);
1819 if (!defaultFacility.empty()) {
1821 g_log.
debug() <<
"Looking for " << instrumentName <<
" at " << defaultFacility <<
".\n";
1832 g_log.
debug() <<
"Looking for " << instrumentName <<
" at " << (*facility).name() <<
".\n";
1833 return (*facility).instrument(instrumentName);
1840 const std::string errMsg =
"Failed to find an instrument with this name in any facility: '" + instrumentName +
"' -";
1841 g_log.
debug(
"Instrument " + instrumentName +
" not found");
1847 std::vector<std::string> names;
1850 const auto &insts = facility->instruments();
1851 for (
const auto &inst : insts) {
1852 names.emplace_back(inst.shortName());
1853 names.emplace_back(inst.name());
1857 std::sort(names.begin(), names.end());
1858 const auto last = std::unique(names.begin(), names.end());
1859 names.erase(last, names.end());
1864 std::string longestPrefix;
1869 auto it = std::prev(match);
1871 if (hint.starts_with(*it)) {
1872 longestPrefix = *it;
1875 if ((*it)[0] != hint[0]) {
1885 return longestPrefix;
1897 auto names = std::vector<std::string>(
m_facilities.size());
1899 [](
const FacilityInfo *facility) { return facility->name(); });
1908 std::string defFacility =
getString(
"default.facility");
1909 if (defFacility.empty()) {
1922 if (facilityName.empty())
1926 [&facilityName](
const auto f) { return f->name() == facilityName; });
1948 g_log.
error(
"Failed to set default facility to be " + facilityName +
". Facility not found");
1951 assert(foundFacility);
1952 setString(
"default.facility", facilityName);
1954 const auto &associatedInsts = foundFacility->
instruments();
1955 if (associatedInsts.empty()) {
1956 throw std::invalid_argument(
"The selected facility has no instruments associated with it");
1986 auto proxyHost = getValue<std::string>(
"proxy.host");
1987 auto proxyPort = getValue<int>(
"proxy.port");
1989 if (proxyHost.has_value() && proxyPort.has_value()) {
2004 const int options)
const {
2006 g_log.
debug() <<
"getFullPath(" << fName <<
")\n";
2008 std::filesystem::path filepath(fName);
2009 if (filepath.is_absolute())
2014 std::filesystem::path fullPath = std::filesystem::current_path() / fName;
2015 if (std::filesystem::exists(fullPath) && (!ignoreDirs || !std::filesystem::is_directory(fullPath)))
2016 return fullPath.string();
2017 }
catch (
const std::exception &) {
2022 directoryNames.insert(directoryNames.end(), instrDirectories.begin(), instrDirectories.end());
2023 for (
const auto &searchPath : directoryNames) {
2024 g_log.
debug() <<
"Searching for " << fName <<
" in " << searchPath <<
"\n";
2030 if (fName.find(
"*") != std::string::npos) {
2032 std::filesystem::path path = std::filesystem::path(searchPath) / fName;
2033 std::set<std::string> files;
2035 if (!files.empty()) {
2036 std::filesystem::path matchPath(*files.begin());
2037 if (ignoreDirs && std::filesystem::is_directory(matchPath)) {
2040 return *files.begin();
2044 std::filesystem::path path = std::filesystem::path(searchPath) / fName;
2045 if (std::filesystem::exists(path) && !(ignoreDirs && std::filesystem::is_directory(path))) {
2046 return path.string();
double value
The value of the point.
#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
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.