Keep last update information so we can show it again (fix #639)

Now the last update information retrieved from the HTTP request, is saved
in the configuration file so we can reuse it when the program is restarted.
Changes:
* Add support to compare two semvers
* Add new_version/new_url options to preferences
* Remove convert_to for base::Version (now this class is constructed from
  strings only)
This commit is contained in:
David Capello 2015-04-24 12:45:01 -03:00
parent 7e52e6d882
commit c63ccf914f
10 changed files with 138 additions and 258 deletions

View File

@ -95,6 +95,8 @@
<option id="wait_days" type="double" default="0.0" migrate="Updater.WaitDays" />
<option id="last_check" type="int" default="0" migrate="Updater.LastCheck" />
<option id="uuid" type="std::string" migrate="Updater.Uuid" />
<option id="new_version" type="std::string" />
<option id="new_url" type="std::string" />
</section>
</global>

View File

@ -18,6 +18,7 @@
#include "base/bind.h"
#include "base/convert_to.h"
#include "base/launcher.h"
#include "base/version.h"
#include <ctime>
#include <sstream>
@ -130,8 +131,10 @@ void CheckUpdateThreadLauncher::launch()
{
// In this case we are in the "wait days" period, so we don't check
// for updates.
if (!m_doCheck)
if (!m_doCheck) {
showUI();
return;
}
if (m_uuid.empty())
m_uuid = m_preferences.updater.uuid();
@ -163,17 +166,20 @@ void CheckUpdateThreadLauncher::onMonitoringTick()
switch (m_response.getUpdateType()) {
case updater::CheckUpdateResponse::NoUpdate:
m_delegate->onUpToDate();
// Clear
m_preferences.updater.newVersion("");
m_preferences.updater.newUrl("");
break;
case updater::CheckUpdateResponse::Critical:
case updater::CheckUpdateResponse::Major:
m_delegate->onNewUpdate(
m_response.getUrl(),
base::convert_to<std::string>(m_response.getLatestVersion()));
m_preferences.updater.newVersion(m_response.getLatestVersion());
m_preferences.updater.newUrl(m_response.getUrl());
break;
}
showUI();
// Save the new UUID
if (!m_response.getUuid().empty()) {
m_uuid = m_response.getUuid();
@ -211,6 +217,25 @@ void CheckUpdateThreadLauncher::checkForUpdates()
}
}
void CheckUpdateThreadLauncher::showUI()
{
bool newVer = false;
if (!m_preferences.updater.newVersion().empty()) {
base::Version serverVersion(m_preferences.updater.newVersion());
base::Version localVersion(VERSION);
newVer = (localVersion < serverVersion);
}
if (newVer) {
m_delegate->onNewUpdate(m_preferences.updater.newUrl(),
m_preferences.updater.newVersion());
}
else {
m_delegate->onUpToDate();
}
}
}
#endif // ENABLE_UPDATER

View File

@ -39,6 +39,7 @@ namespace app {
private:
void onMonitoringTick();
void checkForUpdates();
void showUI();
CheckUpdateDelegate* m_delegate;
Preferences& m_preferences;

View File

@ -10,7 +10,6 @@
#include "base/convert_to.h"
#include "base/sha1.h"
#include "base/version.h"
#include <cstdio>
#include <cstdlib>
@ -80,33 +79,4 @@ template<> std::string convert_to(const Sha1& from)
return res;
}
template<> Version convert_to(const std::string& from)
{
Version result;
std::string::size_type i = 0;
std::string::size_type j = 0;
while (j != std::string::npos) {
j = from.find('.', i);
std::string digitString = from.substr(i, j - i);
int digit = convert_to<int>(digitString);
result.addDigit(digit);
i = j+1;
}
return result;
}
template<> std::string convert_to(const Version& from)
{
std::string result;
result.reserve(3*from.size());
for (size_t i=0; i<from.size(); ++i) {
result += convert_to<std::string>(from[i]);
if (i < from.size()-1)
result += ".";
}
return result;
}
} // namespace base

View File

@ -14,7 +14,6 @@
namespace base {
class Sha1;
class Version;
// Undefined convertion
template<typename To, typename From>
@ -34,9 +33,6 @@ namespace base {
template<> Sha1 convert_to(const std::string& from);
template<> std::string convert_to(const Sha1& from);
template<> Version convert_to(const std::string& from);
template<> std::string convert_to(const Version& from);
}
#endif

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -10,42 +10,49 @@
#include "base/version.h"
#include "base/convert_to.h"
#include <cctype>
namespace base {
Version::Version()
Version::Version(const std::string& from)
: m_prereleaseDigit(0)
{
}
std::string::size_type i = 0;
std::string::size_type j = 0;
std::string::size_type k = from.find('-', 0);
Version::Version(int major, int minor, int rev, int compilation)
{
if (major >= 0 || minor >= 0 || rev >= 0 || compilation >= 0)
addDigit(major);
while ((j != std::string::npos) &&
(k == std::string::npos || j < k)) {
j = from.find('.', i);
if (minor >= 0 || rev >= 0 || compilation >= 0)
addDigit(minor);
std::string digit;
if (j != std::string::npos) {
digit = from.substr(i, j - i);
i = j+1;
}
else
digit = from.substr(i);
if (rev >= 0 || compilation >= 0)
addDigit(rev);
if (compilation >= 0)
addDigit(compilation);
}
bool Version::operator==(const Version& other) const
{
Digits::const_iterator
it1 = m_digits.begin(), end1 = m_digits.end(),
it2 = other.m_digits.begin(), end2 = other.m_digits.end();
while (it1 != end1 || it2 != end2) {
int digit1 = (it1 != end1 ? *it1++: 0);
int digit2 = (it2 != end2 ? *it2++: 0);
if (digit1 != digit2)
return false;
m_digits.push_back(convert_to<int>(digit));
}
return true;
if (k != std::string::npos) {
auto k0 = ++k;
for (; k < from.size() && !std::isdigit(from[k]); ++k)
;
if (k < from.size()) {
m_prereleaseDigit = convert_to<int>(from.substr(k));
m_prerelease = from.substr(k0, k - k0);
}
else
m_prerelease = from.substr(k0);
}
while (!m_prerelease.empty() &&
m_prerelease[m_prerelease.size()-1] == '.')
m_prerelease.erase(m_prerelease.size()-1);
}
bool Version::operator<(const Version& other) const
@ -62,10 +69,42 @@ bool Version::operator<(const Version& other) const
return true;
else if (digit1 > digit2)
return false;
// else continue...
}
if (m_prerelease.empty()) {
return false;
}
else if (other.m_prerelease.empty()) {
return true;
}
else {
int res = m_prerelease.compare(other.m_prerelease);
if (res < 0)
return true;
else if (res > 0)
return false;
else
return (m_prereleaseDigit < other.m_prereleaseDigit);
}
return false;
}
std::string Version::str() const
{
std::string res;
for (auto digit : m_digits) {
if (!res.empty())
res.push_back('.');
res += base::convert_to<std::string>(digit);
}
if (!m_prerelease.empty()) {
res.push_back('-');
res += m_prerelease;
if (m_prereleaseDigit)
res += base::convert_to<std::string>(m_prereleaseDigit);
}
return res;
}
} // namespace base

View File

@ -11,78 +11,21 @@
#include <string>
#include <vector>
#ifdef major
#undef major
#endif
#ifdef minor
#undef minor
#endif
namespace base {
class Version {
public:
Version();
explicit Version(int major, int minor = -1, int revision = -1, int build = -1);
explicit Version(const std::string& from);
int major() const { return (*this)[0]; }
int minor() const { return (*this)[1]; }
int revision() const { return (*this)[2]; }
int build() const { return (*this)[3]; }
Version& major(int digit) { (*this)[0] = digit; return *this; }
Version& minor(int digit) { (*this)[1] = digit; return *this; }
Version& revision(int digit) { (*this)[2] = digit; return *this; }
Version& build(int digit) { (*this)[3] = digit; return *this; }
std::size_t size() const {
return m_digits.size();
}
// operator[] that can be used to set version digits.
int& operator[](std::size_t index) {
if (index >= m_digits.size())
m_digits.resize(index+1);
return m_digits[index];
}
// operator[] that can be used to get version digits.
int operator[](std::size_t index) const {
if (index < m_digits.size())
return m_digits[index];
else
return 0;
}
// Adds a new digit.
void addDigit(int digit) {
m_digits.push_back(digit);
}
// Comparison
bool operator==(const Version& other) const;
bool operator<(const Version& other) const;
bool operator!=(const Version& other) const {
return !operator==(other);
}
bool operator>(const Version& other) const {
return !operator<(other) && !operator==(other);
}
bool operator>=(const Version& other) const {
return !operator<(other);
}
bool operator<=(const Version& other) const {
return operator<(other) || operator==(other);
}
std::string str() const;
private:
typedef std::vector<int> Digits;
Digits m_digits;
std::string m_prerelease; // alpha, beta, dev, rc (empty if it's official release)
int m_prereleaseDigit;
};
}

View File

@ -1,5 +1,5 @@
// Aseprite Base Library
// Copyright (c) 2001-2013 David Capello
// Copyright (c) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -14,139 +14,42 @@ using namespace base;
namespace base {
std::ostream& operator<<(std::ostream& os, const Version& ver) {
return os << convert_to<std::string>(ver);
return os << ver.str();
}
}
TEST(Version, Ctor)
{
Version v0;
EXPECT_EQ(0, v0[0]);
EXPECT_EQ(0, v0[1]);
EXPECT_EQ(0, v0[2]);
EXPECT_EQ(0, v0[3]);
EXPECT_EQ(0, v0[4]);
Version v1(1);
EXPECT_EQ(1, v1[0]);
EXPECT_EQ(0, v1[1]);
Version v2(1, 2);
EXPECT_EQ(1, v2[0]);
EXPECT_EQ(2, v2[1]);
EXPECT_EQ(0, v2[2]);
Version v3(1, 2, 3);
EXPECT_EQ(1, v3[0]);
EXPECT_EQ(2, v3[1]);
EXPECT_EQ(3, v3[2]);
EXPECT_EQ(0, v3[3]);
Version v4(1, 2, 3, 4);
EXPECT_EQ(1, v4[0]);
EXPECT_EQ(2, v4[1]);
EXPECT_EQ(3, v4[2]);
EXPECT_EQ(4, v4[3]);
EXPECT_EQ(0, v4[4]);
}
TEST(Version, StringToVersion)
{
EXPECT_EQ(Version(), convert_to<Version>(std::string("")));
EXPECT_EQ(Version(1), convert_to<Version>(std::string("1")));
EXPECT_EQ(Version(1, 2), convert_to<Version>(std::string("1.2")));
EXPECT_EQ(Version(1, 2, 3), convert_to<Version>(std::string("1.2.3")));
EXPECT_EQ(Version(1, 2, 3, 4), convert_to<Version>(std::string("1.2.3.4")));
}
TEST(Version, VersionToString)
{
EXPECT_EQ("", convert_to<std::string>(Version()));
EXPECT_EQ("0", convert_to<std::string>(Version(0)));
EXPECT_EQ("1", convert_to<std::string>(Version(1)));
EXPECT_EQ("1.0", convert_to<std::string>(Version(1, 0)));
EXPECT_EQ("0.0", convert_to<std::string>(Version(0, 0)));
EXPECT_EQ("1.0.2", convert_to<std::string>(Version(1, 0, 2)));
}
TEST(Version, Equal)
{
EXPECT_EQ(Version(), Version());
EXPECT_EQ(Version(0), Version());
EXPECT_EQ(Version(1), Version(1));
EXPECT_EQ(Version(1), Version(1, 0));
EXPECT_EQ(Version(1, 0), Version(1));
EXPECT_EQ(Version(1, 2), Version(1, 2));
EXPECT_EQ(Version(1, 2, 3), Version(1, 2, 3));
EXPECT_EQ(Version(1, 0, 0), Version(1));
}
TEST(Version, NotEqual)
{
EXPECT_FALSE(Version() != Version());
EXPECT_TRUE(Version(1) != Version(1, 2));
EXPECT_TRUE(Version() != Version(0, 1));
EXPECT_TRUE(Version(1, 0) != Version(1, 0, 1));
EXPECT_TRUE(Version(1, 2) != Version(1, 3));
EXPECT_TRUE(Version(1, 2, 3) != Version(1, 2, 3, 4));
EXPECT_EQ("1", Version("1").str());
EXPECT_EQ("1.2", Version("1.2").str());
EXPECT_EQ("1.2-rc3", Version("1.2-rc3").str());
EXPECT_EQ("1.2-beta3", Version("1.2-beta3").str());
EXPECT_EQ("1.2-beta", Version("1.2-beta").str());
EXPECT_EQ("1.2-beta", Version("1.2-beta0").str());
}
TEST(Version, LessThan)
{
EXPECT_FALSE(Version() < Version(0));
EXPECT_TRUE(Version(0) < Version(1));
EXPECT_TRUE(Version(1, 2) < Version(1, 3));
EXPECT_TRUE(Version(1, 2, 3) < Version(1, 2, 4));
EXPECT_TRUE(Version(1, 2, 0, 4) < Version(1, 2, 3));
EXPECT_FALSE(Version(1, 3) < Version(1, 2));
}
EXPECT_TRUE(Version("0") < Version("1"));
EXPECT_TRUE(Version("1.2") < Version("1.3"));
EXPECT_TRUE(Version("1.2.3") < Version("1.2.4"));
EXPECT_TRUE(Version("1.2.0.4") < Version("1.2.3"));
EXPECT_TRUE(Version("1.3-dev") < Version("1.3"));
EXPECT_TRUE(Version("1.3-dev") < Version("1.4"));
EXPECT_TRUE(Version("1.1-beta") < Version("1.1-beta1"));
EXPECT_TRUE(Version("1.1-beta1") < Version("1.1-beta2"));
EXPECT_TRUE(Version("1.1-beta2") < Version("1.1-rc1"));
TEST(Version, AllComparisons)
{
EXPECT_TRUE(Version(1, 2, 3) == Version(1, 2, 3));
EXPECT_FALSE(Version(1, 2, 3) < Version(1, 2, 3));
EXPECT_FALSE(Version(1, 2, 3) > Version(1, 2, 3));
EXPECT_FALSE(Version(1, 2, 3) != Version(1, 2, 3));
EXPECT_TRUE(Version(1, 2, 3) <= Version(1, 2, 3));
EXPECT_TRUE(Version(1, 2, 3) >= Version(1, 2, 3));
EXPECT_FALSE(Version(1, 2, 3) == Version(2));
EXPECT_TRUE(Version(1, 2, 3) < Version(2));
EXPECT_FALSE(Version(1, 2, 3) > Version(2));
EXPECT_TRUE(Version(1, 2, 3) != Version(2));
EXPECT_TRUE(Version(1, 2, 3) <= Version(2));
EXPECT_FALSE(Version(1, 2, 3) >= Version(2));
}
TEST(Version, SimpleGetters)
{
Version v0;
EXPECT_EQ(0, v0.major());
EXPECT_EQ(0, v0.minor());
EXPECT_EQ(0, v0.revision());
EXPECT_EQ(0, v0.build());
Version v2(1, 2);
EXPECT_EQ(1, v2.major());
EXPECT_EQ(2, v2.minor());
EXPECT_EQ(0, v2.revision());
Version v4(1, 2, 3, 4);
EXPECT_EQ(1, v4.major());
EXPECT_EQ(2, v4.minor());
EXPECT_EQ(3, v4.revision());
EXPECT_EQ(4, v4.build());
}
TEST(Version, SimpleSetters)
{
EXPECT_EQ(Version(1), Version().major(1));
EXPECT_EQ(Version(1, 2), Version().major(1).minor(2));
EXPECT_EQ(Version(1, 2), Version().minor(2).major(1));
EXPECT_EQ(Version(1, 2, 3, 4), Version().major(1).minor(2).revision(3).build(4));
EXPECT_EQ(Version(1, 2, 3, 4), Version().build(4).revision(3).minor(2).major(1));
EXPECT_EQ(Version(0, 0, 0, 4), Version().build(4));
EXPECT_FALSE(Version("1") < Version("0"));
EXPECT_FALSE(Version("1.3") < Version("1.2"));
EXPECT_FALSE(Version("1.2.4") < Version("1.2.3"));
EXPECT_FALSE(Version("1.2.3") < Version("1.2.0.4"));
EXPECT_FALSE(Version("1.3") < Version("1.3-dev"));
EXPECT_FALSE(Version("1.4") < Version("1.3-dev"));
EXPECT_FALSE(Version("1.1-beta1") < Version("1.1-beta"));
EXPECT_FALSE(Version("1.1-beta2") < Version("1.1-beta1"));
EXPECT_FALSE(Version("1.1-rc1") < Version("1.1-beta2"));
}
int main(int argc, char** argv)

View File

@ -70,7 +70,7 @@ CheckUpdateResponse::CheckUpdateResponse(const std::string& responseBody)
}
if (version_attr)
m_version = base::convert_to<base::Version>(std::string(version_attr));
m_version = version_attr;
if (url_attr)
m_url = url_attr;

View File

@ -10,7 +10,8 @@
#pragma once
#include "base/disable_copying.h"
#include "base/version.h"
#include <string>
namespace updater {
@ -34,7 +35,7 @@ namespace updater {
Type getUpdateType() const { return m_type; }
// Returns the latest version available to be downloaded.
base::Version getLatestVersion() const { return m_version; }
std::string getLatestVersion() const { return m_version; }
// Returns the URL to download the new version.
std::string getUrl() const { return m_url; }
@ -50,7 +51,7 @@ namespace updater {
private:
Type m_type;
base::Version m_version;
std::string m_version;
std::string m_url;
Uuid m_uuid;
double m_waitDays;