mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-04-23 14:19:52 +08:00
convert version from string to real number for comparison
Allow 2.3.10 to be > than 2.3.9 allow 1.1.1.1 and not only 1.1.1 supermerill/SuperSlicer#2301
This commit is contained in:
parent
56b2f2b483
commit
3a3627a2d9
@ -431,7 +431,7 @@ std::string AppConfig::load()
|
||||
// Make 1.40.0 alphas compare well
|
||||
ini_ver->set_metadata(boost::none);
|
||||
ini_ver->set_prerelease(boost::none);
|
||||
m_legacy_datadir = ini_ver < Semver(1, 40, 0);
|
||||
m_legacy_datadir = ini_ver < Semver(1, 40, 0, 0);
|
||||
}
|
||||
|
||||
// Legacy conversion
|
||||
|
@ -20,24 +20,30 @@ class Semver
|
||||
public:
|
||||
struct Major { const int i; Major(int i) : i(i) {} };
|
||||
struct Minor { const int i; Minor(int i) : i(i) {} };
|
||||
struct Counter { const int i; Counter(int i) : i(i) {} }; //for SuSi
|
||||
struct Patch { const int i; Patch(int i) : i(i) {} };
|
||||
|
||||
Semver() : ver(semver_zero()) {}
|
||||
|
||||
Semver(int major, int minor, int patch,
|
||||
Semver(int major, int minor, int counter, int patch,
|
||||
boost::optional<const std::string&> metadata = boost::none,
|
||||
boost::optional<const std::string&> prerelease = boost::none)
|
||||
: ver(semver_zero())
|
||||
{
|
||||
ver.major = major;
|
||||
ver.minor = minor;
|
||||
ver.patch = patch;
|
||||
semver_free(&ver);
|
||||
ver.counter_size = 4;
|
||||
ver.counters = new int[4];
|
||||
ver.counters[0] = major;
|
||||
ver.counters[1] = minor;
|
||||
ver.counters[2] = counter;
|
||||
ver.counters[3] = patch;
|
||||
set_metadata(metadata);
|
||||
set_prerelease(prerelease);
|
||||
}
|
||||
|
||||
Semver(const std::string &str) : ver(semver_zero())
|
||||
{
|
||||
|
||||
auto parsed = parse(str);
|
||||
if (! parsed) {
|
||||
throw Slic3r::RuntimeError(std::string("Could not parse version string: ") + str);
|
||||
@ -60,13 +66,16 @@ public:
|
||||
|
||||
static const Semver inf()
|
||||
{
|
||||
static semver_t ver = { std::numeric_limits<int>::max(), std::numeric_limits<int>::max(), std::numeric_limits<int>::max(), nullptr, nullptr };
|
||||
semver_t ver = { new int[4], 4, nullptr, nullptr };
|
||||
for (int i = 0; i < ver.counter_size; i++)
|
||||
ver.counters[i] = std::numeric_limits<int>::max();
|
||||
return Semver(ver);
|
||||
}
|
||||
|
||||
static const Semver invalid()
|
||||
{
|
||||
static semver_t ver = { -1, 0, 0, nullptr, nullptr };
|
||||
semver_t ver = { new int[1], 1, nullptr, nullptr };
|
||||
ver.counters[0] = -1;
|
||||
return Semver(ver);
|
||||
}
|
||||
|
||||
@ -91,16 +100,18 @@ public:
|
||||
~Semver() { ::semver_free(&ver); }
|
||||
|
||||
// const accessors
|
||||
int maj() const { return ver.major; }
|
||||
int min() const { return ver.minor; }
|
||||
int patch() const { return ver.patch; }
|
||||
//int maj() const { return ver.counter_size > 0 ? ver.counters[0] : 0; }
|
||||
//int min() const { return ver.counter_size > 1 ? ver.counters[1] : 0; }
|
||||
//int counter() const { return ver.counter_size > 2 ? ver.counters[2] : 0; }
|
||||
//int patch() const { return ver.counter_size > 3 ? ver.counters[3] : 0; }
|
||||
const char* prerelease() const { return ver.prerelease; }
|
||||
const char* metadata() const { return ver.metadata; }
|
||||
|
||||
// Setters
|
||||
void set_maj(int maj) { ver.major = maj; }
|
||||
void set_min(int min) { ver.minor = min; }
|
||||
void set_patch(int patch) { ver.patch = patch; }
|
||||
//void set_maj(int maj) { if(ver.counter_size > 0) ver.counters[0] = maj; }
|
||||
//void set_min(int min) { if (ver.counter_size > 1) ver.counters[1] = min; }
|
||||
//void set_counter(int count) { if (ver.counter_size > 2) ver.counters[2] = count; }
|
||||
//void set_patch(int patch) { if (ver.counter_size > 3) ver.counters[3] = patch; }
|
||||
void set_metadata(boost::optional<const std::string&> meta) { ver.metadata = meta ? strdup(*meta) : nullptr; }
|
||||
void set_prerelease(boost::optional<const std::string&> pre) { ver.prerelease = pre ? strdup(*pre) : nullptr; }
|
||||
|
||||
@ -120,25 +131,32 @@ public:
|
||||
|
||||
// Conversion
|
||||
std::string to_string() const {
|
||||
auto res = (boost::format("%1%.%2%.%3%") % ver.major % ver.minor % ver.patch).str();
|
||||
std::string res;
|
||||
for (int i = 0; i < ver.counter_size; i++) {
|
||||
res += ( (i==0 ? boost::format("%1%") : boost::format(".%1%")) % ver.counters[i]).str();
|
||||
}
|
||||
if (ver.prerelease != nullptr) { res += '-'; res += ver.prerelease; }
|
||||
if (ver.metadata != nullptr) { res += '+'; res += ver.metadata; }
|
||||
return res;
|
||||
}
|
||||
|
||||
// Arithmetics
|
||||
Semver& operator+=(const Major &b) { ver.major += b.i; return *this; }
|
||||
Semver& operator+=(const Minor &b) { ver.minor += b.i; return *this; }
|
||||
Semver& operator+=(const Patch &b) { ver.patch += b.i; return *this; }
|
||||
Semver& operator-=(const Major &b) { ver.major -= b.i; return *this; }
|
||||
Semver& operator-=(const Minor &b) { ver.minor -= b.i; return *this; }
|
||||
Semver& operator-=(const Patch &b) { ver.patch -= b.i; return *this; }
|
||||
Semver operator+(const Major &b) const { Semver res(*this); return res += b; }
|
||||
Semver operator+(const Minor &b) const { Semver res(*this); return res += b; }
|
||||
Semver operator+(const Patch &b) const { Semver res(*this); return res += b; }
|
||||
Semver operator-(const Major &b) const { Semver res(*this); return res -= b; }
|
||||
Semver operator-(const Minor &b) const { Semver res(*this); return res -= b; }
|
||||
Semver operator-(const Patch &b) const { Semver res(*this); return res -= b; }
|
||||
//Semver& operator+=(const Major &b) { set_maj(maj()+b.i); return *this; }
|
||||
//Semver& operator+=(const Minor &b) { set_min(min() + b.i); return *this; }
|
||||
//Semver& operator+=(const Counter& b) { set_counter(counter() + b.i); return *this; }
|
||||
//Semver& operator+=(const Patch &b) { set_patch(patch() + b.i); return *this; }
|
||||
//Semver& operator-=(const Major& b) { set_maj(maj() - b.i); return *this; }
|
||||
//Semver& operator-=(const Minor& b) { set_min(min() - b.i); return *this; }
|
||||
//Semver& operator-=(const Counter& b) { set_counter(counter() - b.i); return *this; }
|
||||
//Semver& operator-=(const Patch& b) { set_patch(patch() - b.i); return *this; }
|
||||
//Semver operator+(const Major &b) const { Semver res(*this); return res += b; }
|
||||
//Semver operator+(const Minor &b) const { Semver res(*this); return res += b; }
|
||||
//Semver operator+(const Counter& b) const { Semver res(*this); return res += b; }
|
||||
//Semver operator+(const Patch& b) const { Semver res(*this); return res += b; }
|
||||
//Semver operator-(const Major &b) const { Semver res(*this); return res -= b; }
|
||||
//Semver operator-(const Minor &b) const { Semver res(*this); return res -= b; }
|
||||
//Semver operator-(const Counter& b) const { Semver res(*this); return res -= b; }
|
||||
//Semver operator-(const Patch& b) const { Semver res(*this); return res -= b; }
|
||||
|
||||
// Stream output
|
||||
friend std::ostream& operator<<(std::ostream& os, const Semver &self) {
|
||||
@ -148,9 +166,10 @@ public:
|
||||
private:
|
||||
semver_t ver;
|
||||
|
||||
|
||||
Semver(semver_t ver) : ver(ver) {}
|
||||
|
||||
static semver_t semver_zero() { return { 0, 0, 0, nullptr, nullptr }; }
|
||||
static semver_t semver_zero() { return { nullptr, 0, nullptr, nullptr }; }
|
||||
static char * strdup(const std::string &str) { return ::semver_strdup(str.data()); }
|
||||
};
|
||||
|
||||
|
@ -162,6 +162,40 @@ semver_parse (const char *str, semver_t *ver) {
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* count he numbezr of int
|
||||
*/
|
||||
int
|
||||
semver_count_version(const char* str) {
|
||||
size_t len;
|
||||
int index, value;
|
||||
char* slice, * next, * endptr;
|
||||
slice = (char*)str;
|
||||
index = 0;
|
||||
|
||||
while (slice != NULL && index++ < 4) {
|
||||
next = strchr(slice, DELIMITER[0]);
|
||||
if (next == NULL)
|
||||
len = strlen(slice);
|
||||
else
|
||||
len = next - slice;
|
||||
if (len > SLICE_SIZE) return -1;
|
||||
|
||||
/* Cast to integer and store */
|
||||
value = strtol(slice, &endptr, 10);
|
||||
if (endptr != next && *endptr != '\0') return -1;
|
||||
|
||||
/* Continue with the next slice */
|
||||
if (next == NULL)
|
||||
slice = NULL;
|
||||
else
|
||||
slice = next + 1;
|
||||
}
|
||||
|
||||
// Major and minor versions are mandatory, patch version is not mandatory.
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a given string as semver expression.
|
||||
*
|
||||
@ -178,37 +212,37 @@ semver_parse_version (const char *str, semver_t *ver) {
|
||||
char *slice, *next, *endptr;
|
||||
slice = (char *) str;
|
||||
index = 0;
|
||||
|
||||
// non mandatory
|
||||
ver->patch = 0;
|
||||
|
||||
while (slice != NULL && index++ < 4) {
|
||||
next = strchr(slice, DELIMITER[0]);
|
||||
if (next == NULL)
|
||||
len = strlen(slice);
|
||||
else
|
||||
len = next - slice;
|
||||
if (len > SLICE_SIZE) return -1;
|
||||
|
||||
/* Cast to integer and store */
|
||||
value = strtol(slice, &endptr, 10);
|
||||
if (endptr != next && *endptr != '\0') return -1;
|
||||
|
||||
switch (index) {
|
||||
case 1: ver->major = value; break;
|
||||
case 2: ver->minor = value; break;
|
||||
case 3: ver->patch = value; break;
|
||||
}
|
||||
|
||||
/* Continue with the next slice */
|
||||
if (next == NULL)
|
||||
slice = NULL;
|
||||
else
|
||||
slice = next + 1;
|
||||
if (ver->counters) {
|
||||
free(ver->counters);
|
||||
ver->counters = NULL;
|
||||
}
|
||||
ver->counter_size = semver_count_version(str);
|
||||
if (ver->counter_size != 0) {
|
||||
ver->counters = malloc(ver->counter_size * sizeof(int));
|
||||
|
||||
while (slice != NULL && index++ < 4) {
|
||||
next = strchr(slice, DELIMITER[0]);
|
||||
if (next == NULL)
|
||||
len = strlen(slice);
|
||||
else
|
||||
len = next - slice;
|
||||
if (len > SLICE_SIZE) return -1;
|
||||
|
||||
/* Cast to integer and store */
|
||||
value = strtol(slice, &endptr, 10);
|
||||
if (endptr != next && *endptr != '\0') return -1;
|
||||
|
||||
ver->counters[index - 1] = value;
|
||||
|
||||
/* Continue with the next slice */
|
||||
if (next == NULL)
|
||||
slice = NULL;
|
||||
else
|
||||
slice = next + 1;
|
||||
}
|
||||
}
|
||||
// Major and minor versions are mandatory, patch version is not mandatory.
|
||||
return (index == 2 || index == 3) ? 0 : -1;
|
||||
return (index >= 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -280,12 +314,11 @@ semver_compare_prerelease (semver_t x, semver_t y) {
|
||||
|
||||
int
|
||||
semver_compare_version (semver_t x, semver_t y) {
|
||||
int res;
|
||||
int res = binary_comparison(x.counter_size, y.counter_size);
|
||||
|
||||
if ((res = binary_comparison(x.major, y.major)) == 0) {
|
||||
if ((res = binary_comparison(x.minor, y.minor)) == 0) {
|
||||
return binary_comparison(x.patch, y.patch);
|
||||
}
|
||||
for (int i = 0; i < x.counter_size && i < y.counter_size; i++) {
|
||||
if ((res = binary_comparison(x.counters[i], y.counters[i])) != 0)
|
||||
return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -379,9 +412,9 @@ semver_lte (semver_t x, semver_t y) {
|
||||
|
||||
int
|
||||
semver_satisfies_caret (semver_t x, semver_t y) {
|
||||
if (x.major == y.major) {
|
||||
if (x.major == 0) {
|
||||
return x.minor >= y.minor;
|
||||
if (x.counter_size > 0 && y.counter_size > 0 && x.counters[0] == y.counters[0]) {
|
||||
if (x.counters[0] == 0) {
|
||||
return x.counter_size > 1 && y.counter_size > 1 && x.counters[1] >= y.counters[1];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -402,8 +435,8 @@ semver_satisfies_caret (semver_t x, semver_t y) {
|
||||
|
||||
int
|
||||
semver_satisfies_patch (semver_t x, semver_t y) {
|
||||
return x.major == y.major
|
||||
&& x.minor == y.minor;
|
||||
return x.counter_size > 1 && y.counter_size > 1 && x.counters[0] == y.counters[0]
|
||||
&& x.counters[1] == y.counters[1];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -480,6 +513,11 @@ semver_free (semver_t *x) {
|
||||
free(x->prerelease);
|
||||
x->prerelease = NULL;
|
||||
}
|
||||
if (x->counters) {
|
||||
x->counter_size = 0;
|
||||
free(x->counters);
|
||||
x->counters = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -507,9 +545,9 @@ concat_char (char * str, char * x, char * sep) {
|
||||
|
||||
void
|
||||
semver_render (semver_t *x, char *dest) {
|
||||
if (x->major) concat_num(dest, x->major, NULL);
|
||||
if (x->minor) concat_num(dest, x->minor, DELIMITER);
|
||||
if (x->patch) concat_num(dest, x->patch, DELIMITER);
|
||||
for (int i = 0; i < x->counter_size; ++i) {
|
||||
concat_num(dest, x->counters[i], i==0 ? NULL : DELIMITER);
|
||||
}
|
||||
if (x->prerelease) concat_char(dest, x->prerelease, PR_DELIMITER);
|
||||
if (x->metadata) concat_char(dest, x->metadata, MT_DELIMITER);
|
||||
}
|
||||
@ -519,18 +557,21 @@ semver_render (semver_t *x, char *dest) {
|
||||
*/
|
||||
|
||||
void
|
||||
semver_bump (semver_t *x) {
|
||||
x->major++;
|
||||
semver_bump_major (semver_t *x) {
|
||||
if(x->counter_size > 0)
|
||||
x->counters[0]++;
|
||||
}
|
||||
|
||||
void
|
||||
semver_bump_minor (semver_t *x) {
|
||||
x->minor++;
|
||||
if (x->counter_size > 1)
|
||||
x->counters[1]++;
|
||||
}
|
||||
|
||||
void
|
||||
semver_bump_patch (semver_t *x) {
|
||||
x->patch++;
|
||||
semver_bump (semver_t *x, int idx) {
|
||||
if (x->counter_size > idx)
|
||||
x->counters[idx]++;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -612,9 +653,9 @@ semver_numeric (semver_t *x) {
|
||||
char buf[SLICE_SIZE * 3];
|
||||
memset(&buf, 0, SLICE_SIZE * 3);
|
||||
|
||||
if (x->major) concat_num(buf, x->major, NULL);
|
||||
if (x->minor) concat_num(buf, x->minor, NULL);
|
||||
if (x->patch) concat_num(buf, x->patch, NULL);
|
||||
for (int i = 0; i < x->counter_size; ++i) {
|
||||
concat_num(buf, x->counters[i], NULL);
|
||||
}
|
||||
|
||||
num = parse_int(buf);
|
||||
if(num == -1) return -1;
|
||||
@ -625,11 +666,17 @@ semver_numeric (semver_t *x) {
|
||||
return num;
|
||||
}
|
||||
|
||||
char *semver_strdup(const char *src) {
|
||||
if (src == NULL) return NULL;
|
||||
size_t len = strlen(src) + 1;
|
||||
char *res = malloc(len);
|
||||
return res != NULL ? (char *) memcpy(res, src, len) : NULL;
|
||||
char* semver_strdup(const char* src) {
|
||||
if (src == NULL) return NULL;
|
||||
size_t len = strlen(src) + 1;
|
||||
char* res = malloc(len);
|
||||
return res != NULL ? (char*)memcpy(res, src, len) : NULL;
|
||||
}
|
||||
|
||||
int* semver_intdup(const int* src, int len) {
|
||||
if (src == NULL) return NULL;
|
||||
int* res = malloc(len * sizeof(int));
|
||||
return res != NULL ? (int*)memcpy(res, src, len * sizeof(int)) : NULL;
|
||||
}
|
||||
|
||||
semver_t
|
||||
@ -639,7 +686,10 @@ semver_copy(const semver_t *ver) {
|
||||
res.metadata = strdup(ver->metadata);
|
||||
}
|
||||
if (ver->prerelease != NULL) {
|
||||
res.prerelease = strdup(ver->prerelease);
|
||||
res.prerelease = strdup(ver->prerelease);
|
||||
}
|
||||
if (ver->counters) {
|
||||
res.counters = semver_intdup(ver->counters, ver->counter_size);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -21,9 +21,8 @@ extern "C" {
|
||||
*/
|
||||
|
||||
typedef struct semver_version_s {
|
||||
int major;
|
||||
int minor;
|
||||
int patch;
|
||||
int * counters;
|
||||
int counter_size;
|
||||
char * metadata;
|
||||
char * prerelease;
|
||||
} semver_t;
|
||||
@ -72,7 +71,10 @@ int
|
||||
semver_parse (const char *str, semver_t *ver);
|
||||
|
||||
int
|
||||
semver_parse_version (const char *str, semver_t *ver);
|
||||
semver_count_version(const char* str);
|
||||
|
||||
int
|
||||
semver_parse_version(const char* str, semver_t* ver);
|
||||
|
||||
void
|
||||
semver_render (semver_t *x, char *dest);
|
||||
@ -81,13 +83,13 @@ int
|
||||
semver_numeric (semver_t *x);
|
||||
|
||||
void
|
||||
semver_bump (semver_t *x);
|
||||
semver_bump_major (semver_t *x);
|
||||
|
||||
void
|
||||
semver_bump_minor (semver_t *x);
|
||||
|
||||
void
|
||||
semver_bump_patch (semver_t *x);
|
||||
semver_bump (semver_t *x, int idx);
|
||||
|
||||
void
|
||||
semver_free (semver_t *x);
|
||||
|
@ -244,6 +244,19 @@ void PresetUpdater::priv::prune_tmps() const
|
||||
}
|
||||
}
|
||||
|
||||
//parse the string, if it doesn't contain a valid version string, return invalid version.
|
||||
Semver get_version(const std::string &str, const std::regex ®exp) {
|
||||
std::smatch match;
|
||||
if (std::regex_match(str, match, regexp)) {
|
||||
std::string version_cleaned = match[0];
|
||||
const boost::optional<Semver> version = Semver::parse(version_cleaned);
|
||||
if (version.has_value()) {
|
||||
return *version;
|
||||
}
|
||||
}
|
||||
return Semver::invalid();
|
||||
}
|
||||
|
||||
// Get Slic3rPE version available online, save in AppConfig.
|
||||
void PresetUpdater::priv::sync_version() const
|
||||
{
|
||||
@ -267,34 +280,48 @@ void PresetUpdater::priv::sync_version() const
|
||||
std::stringstream json_stream(body);
|
||||
boost::property_tree::read_json(json_stream, root);
|
||||
bool i_am_pre = false;
|
||||
std::string best_pre = "1";
|
||||
std::string best_release = "1";
|
||||
//at least two number, use '.' as separator. can be followed by -Az23 for prereleased and +Az42 for metadata
|
||||
std::regex matcher("[0-9]+\.[0-9]+(\.[0-9]+)*(-[A-Za-z0-9]+)?(\\+[A-Za-z0-9]+)?");
|
||||
|
||||
Semver current_version(SLIC3R_VERSION_FULL);
|
||||
Semver best_pre(1,0,0,0);
|
||||
Semver best_release(1, 0, 0, 0);
|
||||
std::string best_pre_url;
|
||||
std::string best_release_url;
|
||||
const std::regex reg_num("([0-9]+)");
|
||||
for (auto json_version : root) {
|
||||
std::string tag = json_version.second.get<std::string>("tag_name");
|
||||
if (SLIC3R_VERSION_FULL == tag)
|
||||
for (std::regex_iterator it = std::sregex_iterator(tag.begin(), tag.end(), reg_num); it != std::sregex_iterator(); ++it) {
|
||||
|
||||
}
|
||||
Semver tag_version = get_version(tag, matcher);
|
||||
if (current_version == tag_version)
|
||||
i_am_pre = json_version.second.get<bool>("prerelease");
|
||||
if (json_version.second.get<bool>("prerelease")) {
|
||||
if (best_pre < tag) {
|
||||
best_pre = tag;
|
||||
if (best_pre < tag_version) {
|
||||
best_pre = tag_version;
|
||||
best_pre_url = json_version.second.get<std::string>("html_url");
|
||||
}
|
||||
} else {
|
||||
if (best_release < tag) {
|
||||
best_release = tag;
|
||||
if (best_release < tag_version) {
|
||||
best_release = tag_version;
|
||||
best_release_url = json_version.second.get<std::string>("html_url");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((i_am_pre ? best_pre : best_release) <= SLIC3R_VERSION_FULL)
|
||||
//if release is more recent than beta, use release anyway
|
||||
if (best_pre < best_release) {
|
||||
best_pre = best_release;
|
||||
best_pre_url = best_release_url;
|
||||
}
|
||||
//if we're the most recent, don't do anything
|
||||
if ((i_am_pre ? best_pre : best_release) <= current_version)
|
||||
return;
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << format("Got %1% online version: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, i_am_pre? best_pre:best_release);
|
||||
BOOST_LOG_TRIVIAL(info) << format("Got %1% online version: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, i_am_pre ? best_pre : best_release);
|
||||
|
||||
wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_VERSION_ONLINE);
|
||||
evt->SetString(i_am_pre ? best_pre : best_release);
|
||||
evt->SetString((i_am_pre ? best_pre : best_release).to_string());
|
||||
GUI::wxGetApp().QueueEvent(evt);
|
||||
})
|
||||
.perform_sync();
|
||||
|
Loading…
x
Reference in New Issue
Block a user