149 auto instrumentDirs = Mantid::Kernel::ConfigService::Instance().getInstrumentDirectories();
150 std::filesystem::path installPath(instrumentDirs.back());
151 std::filesystem::create_directories(installPath);
152 std::filesystem::path localPath(instrumentDirs[0]);
153 std::filesystem::create_directories(localPath);
156 std::filesystem::path gitHubJsonFile = localPath /
"github.json";
157 Poco::DateTime gitHubJsonDate(1900, 1, 1);
158 bool forceUpdate = this->
getProperty(
"ForceUpdate");
159 if ((!forceUpdate) && std::filesystem::exists(gitHubJsonFile) && std::filesystem::is_regular_file(gitHubJsonFile)) {
160 auto ftime = std::filesystem::last_write_time(gitHubJsonFile);
161 auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
162 ftime - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());
163 std::time_t cftime = std::chrono::system_clock::to_time_t(sctp);
164 gitHubJsonDate = Poco::Timestamp::fromEpochTime(cftime);
169 headers.emplace(
"if-modified-since",
170 Poco::DateTimeFormatter::format(gitHubJsonDate, Poco::DateTimeFormat::HTTP_FORMAT));
171 std::string gitHubInstrumentRepoUrl = ConfigService::Instance().getString(
"UpdateInstrumentDefinitions.URL");
172 if (gitHubInstrumentRepoUrl.empty()) {
173 throw std::runtime_error(
"Property UpdateInstrumentDefinitions.URL is not defined, "
174 "this should point to the location of the instrument "
175 "directory in the github API "
177 "https://api.github.com/repos/mantidproject/mantid/contents/"
182 doDownloadFile(gitHubInstrumentRepoUrl, gitHubJsonFile.string(), headers);
193 std::filesystem::path installRepoFile = localPath /
"install.json";
195 std::filesystem::path localRepoFile = localPath /
"local.json";
199 if (std::filesystem::file_size(gitHubJsonFile) == 0) {
200 std::stringstream msg;
201 msg <<
"Encountered empty file \"" << gitHubJsonFile.string() <<
"\" while determining what to download";
202 throw std::runtime_error(msg.str());
206 ::Json::CharReaderBuilder readerBuilder;
207 Json::Value serverContents;
208 Poco::FileStream fileStream(gitHubJsonFile.string(), std::ios::in);
211 Json::parseFromStream(readerBuilder, fileStream, &serverContents, &errors);
212 if (errors.size() != 0) {
213 throw std::runtime_error(
"Unable to parse server JSON file \"" + gitHubJsonFile.string() +
"\"");
217 std::unordered_set<std::string> repoFilenames;
219 for (
auto &serverElement : serverContents) {
220 std::string elementName = serverElement.get(
"name",
"").asString();
221 repoFilenames.insert(elementName);
222 std::filesystem::path filePath = localPath / elementName;
223 if (filePath.extension().string() !=
".xml")
225 std::string sha = serverElement.get(
"sha",
"").asString();
226 std::string downloadUrl = getDownloadUrl(serverElement);
234 if ((sha != installSha) && (sha != localSha)) {
235 fileMap.emplace(downloadUrl,
237 }
else if ((!localSha.empty()) && (sha == installSha) && (sha != localSha))
239 fileMap.emplace(downloadUrl, filePath.string());
299 const std::unordered_set<std::string> &filenamesToKeep)
const {
302 std::vector<std::filesystem::path> filesToDelete;
305 for (
auto const &it : std::filesystem::directory_iterator{directoryPath}) {
306 auto const entryPath = it.path();
307 if (entryPath.extension().string() !=
".xml")
309 if (filenamesToKeep.find(entryPath.filename().string()) == filenamesToKeep.end()) {
310 g_log.
debug() <<
"File not found in remote instrument repository, will "
312 << entryPath.filename().string() <<
'\n';
313 filesToDelete.emplace_back(entryPath);
316 }
catch (Poco::Exception &ex) {
317 g_log.
error() <<
"DownloadInstrument: failed to list the directory: " << directoryPath <<
" : " << ex.className()
318 <<
" : " << ex.displayText() <<
'\n';
320 }
catch (std::exception &ex) {
321 std::stringstream ss;
322 ss <<
"unknown exception while checking local file system. " << ex.what() <<
". Input = " << directoryPath;
323 throw std::runtime_error(ss.str());
328 for (
const auto &filepath : filesToDelete) {
329 std::filesystem::remove(filepath);
331 }
catch (Poco::Exception &ex) {
332 g_log.
error() <<
"DownloadInstrument: failed to delete file: " << ex.className() <<
" : " << ex.displayText()
335 }
catch (std::exception &ex) {
336 std::stringstream ss;
337 ss <<
"unknown exception while deleting file: " << ex.what();
338 throw std::runtime_error(ss.str());
341 g_log.
debug() << filesToDelete.size() <<
" Files deleted.\n";
343 return filesToDelete.size();
360 const std::string &localFilePath,
362 std::filesystem::path localFile(localFilePath);
363 if (std::filesystem::exists(localFile)) {
364 auto perms = std::filesystem::status(localFile).permissions();
365 if ((perms & std::filesystem::perms::owner_write) == std::filesystem::perms::none) {
366 std::stringstream msg;
367 msg <<
"Cannot write file \"" << localFilePath <<
"\"";
368 throw std::runtime_error(msg.str());
371 localFile = std::filesystem::path(localFilePath).parent_path();
372 auto perms = std::filesystem::status(localFile).permissions();
373 if ((perms & std::filesystem::perms::owner_write) == std::filesystem::perms::none) {
374 std::stringstream msg;
375 msg <<
"Cannot write file \"" << localFilePath <<
"\"";
376 throw std::runtime_error(msg.str());
381 inetHelper.
headers().insert(headers.begin(), headers.end());
382 const auto retStatus = inetHelper.
downloadFile(urlFile, localFilePath);