Mantid
Loading...
Searching...
No Matches
CheckMantidVersion.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8#include "MantidJson/Json.h"
13
15#include <Poco/DateTimeFormat.h>
16#include <Poco/DateTimeFormatter.h>
17#include <Poco/DateTimeParser.h>
18
19// jsoncpp
20#include <json/json.h>
21
22#include <boost/lexical_cast.hpp>
23
24namespace Mantid::DataHandling {
25
26using namespace Mantid::Kernel;
27
28// Register the algorithm into the AlgorithmFactory
30
31
32const std::string CheckMantidVersion::name() const { return "CheckMantidVersion"; }
33
35int CheckMantidVersion::version() const { return 1; }
36
38const std::string CheckMantidVersion::category() const { return "Utility\\Development"; }
39
41const std::string CheckMantidVersion::summary() const {
42 return "Checks if there is a more recent version of Mantid available using "
43 "the Github API";
44}
45
49 declareProperty("CurrentVersion", "", Direction::Output);
50 declareProperty("MostRecentVersion", "", Direction::Output);
51 declareProperty("IsNewVersionAvailable", false, "True if a newer version is available, otherwise false",
53}
54
58 std::string currentVersion = getCurrentVersion();
59 setProperty("CurrentVersion", currentVersion);
60 std::string mostRecentVersion;
61
62 std::string gitHubReleaseUrl = ConfigService::Instance().getString("CheckMantidVersion.GitHubReleaseURL");
63 if (gitHubReleaseUrl.empty()) {
64 gitHubReleaseUrl = "https://api.github.com/repos/mantidproject/mantid/releases/latest";
65 }
66 std::string downloadUrl = ConfigService::Instance().getString("CheckMantidVersion.DownloadURL");
67 if (downloadUrl.empty()) {
68 downloadUrl = "http://download.mantidproject.org";
69 }
70
71 std::string json;
72 try {
73 json = getVersionsFromGitHub(gitHubReleaseUrl);
74 } catch (Exception::InternetError &ex) {
75 if (ex.errorCode() == static_cast<int>(InternetHelper::HTTPStatus::NOT_MODIFIED)) {
76 // No changes since last release
77 // mostRecentVersion = getCurrentVersion();
78 mostRecentVersion = "No new versions since " + std::string(MantidVersion::releaseDate());
79 } else {
80 // any other exception just log quietly and return
81 g_log.debug("Cannot get latest version details from " + gitHubReleaseUrl);
82 g_log.debug("The address can be changed using the property "
83 "CheckMantidVersion.GitHubReleaseURL");
84 g_log.debug(ex.what());
85 return;
86 }
87 }
88
89 bool isNewVersionAvailable = false;
90 if (!json.empty()) {
91 Json::Value root;
92 std::string jsonErrors;
93 bool parseOK = Mantid::JsonHelpers::parse(json, &root, &jsonErrors);
94 if (!parseOK) {
95 // just warning. The parser is able to get relevant info even if there are
96 // formatting issues like missing quotes or brackets.
97 g_log.warning() << "Error found when parsing version information "
98 "retrieved from GitHub as a JSON string. "
99 "Error trying to parse this JSON string: "
100 << json << "\n. Parsing error details: " << jsonErrors << '\n';
101 }
102
103 std::string gitHubVersionTag;
104 try {
105 gitHubVersionTag = root["tag_name"].asString();
106 } catch (std::runtime_error &re) {
107 g_log.error() << "Error while trying to get the field 'tag_name' from "
108 "the version information retrieved from GitHub. This "
109 "algorithm cannot continue and will stop now. Error details: "
110 << re.what() << '\n';
111
112 mostRecentVersion = "Could not get information from GitHub";
113 setProperty("MostRecentVersion", mostRecentVersion);
114 setProperty("IsNewVersionAvailable", isNewVersionAvailable);
115 return;
116 }
117
118 mostRecentVersion = cleanVersionTag(gitHubVersionTag);
119 isNewVersionAvailable = isVersionMoreRecent(currentVersion, mostRecentVersion);
120 if (isNewVersionAvailable) {
121 // output a notice level log
122 g_log.notice("A new version of Mantid(" + mostRecentVersion + ") is available for download from " + downloadUrl);
123 }
124 }
125
126 g_log.information("Current Mantid Version: " + currentVersion);
127 g_log.information("Most Recent Mantid Version: " + mostRecentVersion);
128
129 setProperty("MostRecentVersion", mostRecentVersion);
130 setProperty("IsNewVersionAvailable", isNewVersionAvailable);
131}
132
138std::string CheckMantidVersion::cleanVersionTag(const std::string &versionTag) const {
139 std::string retVal = versionTag;
140
141 retVal = Strings::replaceAll(retVal, "v", "");
142 retVal = Strings::replaceAll(retVal, "V", "");
143 retVal = Strings::strip(retVal);
144
145 return retVal;
146}
147
160std::vector<int> CheckMantidVersion::splitVersionString(const std::string &versionString) const {
161 std::vector<int> versionNumbers;
162 // Discard suffix from release candidate version numbers.
163 const std::string versionStringBeforeRC = versionString.substr(0, versionString.find("rc"));
164 // Discard suffix from development builds.
165 const std::string versionStringBeforeDev = versionStringBeforeRC.substr(0, versionStringBeforeRC.find(".dev"));
166 // Discard suffix from local release versions.
167 const std::string versionStringBeforePlus = versionStringBeforeDev.substr(0, versionStringBeforeDev.find("+"));
168
169 Mantid::Kernel::StringTokenizer tokenizer(versionStringBeforePlus, ".",
172
173 for (auto h = tokenizer.begin(); h != tokenizer.end(); ++h) {
174 try {
175 auto part = boost::lexical_cast<int>(*h);
176 versionNumbers.emplace_back(part);
177 } catch (const boost::bad_lexical_cast &) {
178 g_log.error("Failed to convert the following string to an integer '" + *h +
179 "' as part of CheckMantidVersion::splitVersionString");
180 versionNumbers.emplace_back(0);
181 }
182 }
183 return versionNumbers;
184}
185
191bool CheckMantidVersion::isVersionMoreRecent(const std::string &localVersion, const std::string &gitHubVersion) const {
192 auto localVersionParts = splitVersionString(localVersion);
193 auto gitHubVersionParts = splitVersionString(gitHubVersion);
194
195 for (size_t i = 0; i < gitHubVersionParts.size(); i++) {
196 // sanity check
197 if (i >= localVersionParts.size()) {
198 // ran out of items to compare
199 break;
200 }
201
202 // the revision number needs to be handled separately
203 if (i == 2) {
204 if (localVersionParts[i] > 2000) {
205 // this is a date string, nightly build
206 // state that the local version is up to date
207 return false;
208 }
209 }
210 if (gitHubVersionParts[i] > localVersionParts[i]) {
211 return true;
212 }
213 if (gitHubVersionParts[i] < localVersionParts[i]) {
214 return false;
215 }
216 }
217 return false;
218}
219
226std::string CheckMantidVersion::getVersionsFromGitHub(const std::string &url) {
227
228 Kernel::GitHubApiHelper inetHelper;
229 std::ostringstream os;
230 int tzd = 0;
231
232 inetHelper.addHeader("if-modified-since",
233 Poco::DateTimeFormatter::format(Poco::DateTimeParser::parse(MantidVersion::releaseDate(), tzd),
234 Poco::DateTimeFormat::HTTP_FORMAT));
235 inetHelper.sendRequest(url, os);
236 std::string retVal = os.str();
237
238 return retVal;
239}
244
245} // namespace Mantid::DataHandling
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Kernel::Logger & g_log
Definition Algorithm.h:422
CheckMantidVersion : Checks if the current version of Mantid is the most recent.
virtual std::string getCurrentVersion() const
Gets the version of this Mantid.
void exec() override
Execute the algorithm.
virtual std::string getVersionsFromGitHub(const std::string &url)
Gets the version json for the most recent release from gitHub.
int version() const override
Algorithm's version for identification.
std::vector< int > splitVersionString(const std::string &versionString) const
Splits a .
bool isVersionMoreRecent(const std::string &localVersion, const std::string &gitHubVersion) const
Compare two version strings, tests if the gitHubVersion is more recent.
void init() override
Initialize the algorithm's properties.
std::string cleanVersionTag(const std::string &versionTag) const
Cleans the tag name from github to make it similar to that from MantidVersion.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
const std::string category() const override
Algorithm's category for identification.
Exception thrown when error occurs accessing an internet resource.
Definition Exception.h:321
const char * what() const noexcept override
Overloaded reporting method.
const int & errorCode() const
Writes out the range and limits.
GitHubApiHelper : A helper class for supporting access to the github api through HTTP and HTTPS,...
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void addHeader(const std::string &key, const std::string &value)
Adds a header.
virtual HTTPStatus sendRequest(const std::string &url, std::ostream &responseStream)
Performs a request using http or https depending on the url.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
static const char * version()
The full version number.
static const char * releaseDate()
The date of the last commit.
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.
Mantid::Kernel::StringTokenizer tokenizer
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
Definition Strings.cpp:419
MANTID_KERNEL_DLL std::string replaceAll(std::string const &input, char const to_replace, char const substitute)
Return a string with all occurrences of indicated character replaced by the new character.
Definition Strings.cpp:90
STL namespace.
@ Output
An output workspace.
Definition Property.h:54