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
152std::vector<int> CheckMantidVersion::splitVersionString(const std::string &versionString) const {
153 std::vector<int> retVal;
157 auto h = tokenizer.begin();
158
159 for (; h != tokenizer.end(); ++h) {
160 try {
161 auto part = boost::lexical_cast<int>(*h);
162 retVal.emplace_back(part);
163 } catch (const boost::bad_lexical_cast &) {
164 g_log.error("Failed to convert the following string to an integer '" + *h +
165 "' as part of CheckMantidVersion::splitVersionString");
166 retVal.emplace_back(0);
167 }
168 }
169 return retVal;
170}
171
177bool CheckMantidVersion::isVersionMoreRecent(const std::string &localVersion, const std::string &gitHubVersion) const {
178 auto localVersionParts = splitVersionString(localVersion);
179 auto gitHubVersionParts = splitVersionString(gitHubVersion);
180
181 for (size_t i = 0; i < gitHubVersionParts.size(); i++) {
182 // sanity check
183 if (i >= localVersionParts.size()) {
184 // ran out of items to compare
185 break;
186 }
187
188 // the revision number needs to be handled separately
189 if (i == 2) {
190 if (localVersionParts[i] > 2000) {
191 // this is a date string, nightly build
192 // state that the local version is up to date
193 return false;
194 }
195 }
196 if (gitHubVersionParts[i] > localVersionParts[i]) {
197 return true;
198 }
199 if (gitHubVersionParts[i] < localVersionParts[i]) {
200 return false;
201 }
202 }
203 return false;
204}
205
212std::string CheckMantidVersion::getVersionsFromGitHub(const std::string &url) {
213
214 Kernel::GitHubApiHelper inetHelper;
215 std::ostringstream os;
216 int tzd = 0;
217
218 inetHelper.addHeader("if-modified-since",
219 Poco::DateTimeFormatter::format(Poco::DateTimeParser::parse(MantidVersion::releaseDate(), tzd),
220 Poco::DateTimeFormat::HTTP_FORMAT));
221 inetHelper.sendRequest(url, os);
222 std::string retVal = os.str();
223
224 return retVal;
225}
230
231} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
Kernel::Logger & g_log
Definition: Algorithm.h:451
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.
Definition: Exception.cpp:311
const int & errorCode() const
Writes out the range and limits.
Definition: Exception.cpp:317
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:114
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
static const char * version()
The full version number.
static const char * releaseDate()
The date of the last commit.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
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
Definition: Expression.cpp:17
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
Definition: Strings.cpp:397
MANTID_KERNEL_DLL std::string replaceAll(const std::string &input, const std::string &charStr, const std::string &substitute)
Return a string with all occurrences of the characters in the input replaced by the replace string.
Definition: Strings.cpp:94
STL namespace.
@ Output
An output workspace.
Definition: Property.h:54