dependency version operators
а также сделал и вынес Version в ContentPackVersion ну и подправил луа скрипты. требуются тесты
This commit is contained in:
parent
5b18639d94
commit
7aa4c33721
@ -176,6 +176,81 @@ function place_pack(panel, packinfo, callback, position_func)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local Version = {};
|
||||||
|
|
||||||
|
function Version.matches_pattern(version)
|
||||||
|
for _, letter in string.gmatch(version, "%s+") do
|
||||||
|
if type(letter) ~= "number" or letter ~= "." then
|
||||||
|
return false;
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = string.split(version, ".");
|
||||||
|
|
||||||
|
return #t == 2 or #t == 3;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Version.__equal(ver1, ver2)
|
||||||
|
return ver1[1] == ver2[1] and ver1[2] == ver2[2] and ver1[3] == ver2[3];
|
||||||
|
end
|
||||||
|
|
||||||
|
function Version.__more(ver1, ver2)
|
||||||
|
if ver1[1] ~= ver2[1] then return ver1[1] > ver2[1] end;
|
||||||
|
if ver1[2] ~= ver2[2] then return ver1[2] > ver2[2] end;
|
||||||
|
return ver1[3] > ver2[3];
|
||||||
|
end
|
||||||
|
|
||||||
|
function Version.__less(ver1, ver2)
|
||||||
|
return Version.__more(ver2, ver1);
|
||||||
|
end
|
||||||
|
|
||||||
|
function Version.__more_or_equal(ver1, ver2)
|
||||||
|
return not Version.__less(ver1, ver2);
|
||||||
|
end
|
||||||
|
|
||||||
|
function Version.__less_or_equal(ver1, ver2)
|
||||||
|
return not Version.__more(ver1, ver2);
|
||||||
|
end
|
||||||
|
|
||||||
|
function Version.compare(op, ver1, ver2)
|
||||||
|
ver1 = string.split(ver1, ".");
|
||||||
|
ver2 = string.split(ver2, ".");
|
||||||
|
|
||||||
|
if op == "=" then return Version.__equal(ver1, ver2);
|
||||||
|
elseif op == ">" then return Version.__more(ver1, ver2);
|
||||||
|
elseif op == "<" then return Version.__less(ver1, ver2);
|
||||||
|
elseif op == ">=" then return Version.__more_or_equal(ver1, ver2);
|
||||||
|
elseif op == "<=" then return Version.__less_or_equal(ver1, ver2);
|
||||||
|
else return false; end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Version.parse(version)
|
||||||
|
local op = string.sub(version, 1, 2);
|
||||||
|
if op == ">=" or op == "=>" then
|
||||||
|
return ">=", string.sub(version, #op + 1);
|
||||||
|
elseif op == "<=" or op == "=<" then
|
||||||
|
return "<=", string.sub(version, #op + 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
op = string.sub(version, 1, 1);
|
||||||
|
if op == ">" or op == "<" then
|
||||||
|
return op, string.sub(version, #op + 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
return "=", version;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function compare_version(dependent_version, actual_version)
|
||||||
|
if Version.matches_pattern(dependent_version) and Version.matches_pattern(actual_version) then
|
||||||
|
local op, dep_ver = Version.parse_version(dependent_version);
|
||||||
|
Version.compare(op, dep_ver, actual_version);
|
||||||
|
elseif dependent_version == "*" or dependent_version == actual_version then
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function check_dependencies(packinfo)
|
function check_dependencies(packinfo)
|
||||||
if packinfo.dependencies == nil then
|
if packinfo.dependencies == nil then
|
||||||
return
|
return
|
||||||
@ -190,9 +265,14 @@ function check_dependencies(packinfo)
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local dep_pack = pack.get_info(depid);
|
local dep_pack = pack.get_info(depid);
|
||||||
if depver ~= "*" and depver ~= dep_pack.version then
|
|
||||||
return string.format("%s (%s@%s != %s)", gui.str("error.dependency-version-not-met"), depid, dep_pack.version, depver);
|
if not compare_version(depver, dep_pack.version) then
|
||||||
|
local op, ver = Version.parse(depver);
|
||||||
|
|
||||||
|
print(string.format("%s: %s !%s %s (%s)", gui.str("error.dependency-version-not-met"), dep_pack.version, op, ver, depid));
|
||||||
|
return string.format("%s: %s != %s (%s)", gui.str("error.dependency-version-not-met"), dep_pack.version, ver, depid);
|
||||||
end
|
end
|
||||||
|
|
||||||
if table.has(packs_installed, packinfo.id) then
|
if table.has(packs_installed, packinfo.id) then
|
||||||
|
|||||||
@ -133,14 +133,43 @@ ContentPack ContentPack::read(const io::path& folder) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string depVersion = "*";
|
std::string depVer = "*";
|
||||||
size_t version_pos = depName.rfind("@");
|
std::string depVerOperator = "=";
|
||||||
if (version_pos != std::string::npos){
|
|
||||||
depVersion = depName.substr(version_pos + 1);
|
size_t versionPos = depName.rfind("@");
|
||||||
depName = depName.substr(0, version_pos);
|
if (versionPos != std::string::npos) {
|
||||||
|
depVer = depName.substr(versionPos + 1);
|
||||||
|
depName = depName.substr(0, versionPos);
|
||||||
|
|
||||||
|
if (depVer.size() >= 2) {
|
||||||
|
std::string op = depVer.substr(0, 2);
|
||||||
|
std::uint8_t op_size = 0;
|
||||||
|
|
||||||
|
// Two symbol operators
|
||||||
|
if (op == ">=" || op == "=>" || op == "<=" || op == "=<") {
|
||||||
|
op_size = 2;
|
||||||
|
depVerOperator = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
// One symbol operators
|
||||||
|
else {
|
||||||
|
op = depVer.substr(0, 1);
|
||||||
|
|
||||||
|
if (op == ">" || op == "<") {
|
||||||
|
op_size = 1;
|
||||||
|
depVerOperator = op;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
depVer = depVer.substr(op_size);
|
||||||
|
} else {
|
||||||
|
if (depVer == ">" || depVer == "<"){
|
||||||
|
depVer = "*";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pack.dependencies.push_back({level, depName, depVersion});
|
pack.dependencies.push_back({level, depName, depVer, depVerOperator});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,11 +20,16 @@ public:
|
|||||||
io::path folder,
|
io::path folder,
|
||||||
const std::string& message
|
const std::string& message
|
||||||
);
|
);
|
||||||
|
|
||||||
std::string getPackId() const;
|
std::string getPackId() const;
|
||||||
io::path getFolder() const;
|
io::path getFolder() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class DependencyVersionOperator {
|
||||||
|
equal, more, less,
|
||||||
|
more_or_equal, less_or_equal
|
||||||
|
};
|
||||||
|
|
||||||
enum class DependencyLevel {
|
enum class DependencyLevel {
|
||||||
required, // dependency must be installed
|
required, // dependency must be installed
|
||||||
optional, // dependency will be installed if found
|
optional, // dependency will be installed if found
|
||||||
@ -35,7 +40,8 @@ enum class DependencyLevel {
|
|||||||
struct DependencyPack {
|
struct DependencyPack {
|
||||||
DependencyLevel level;
|
DependencyLevel level;
|
||||||
std::string id;
|
std::string id;
|
||||||
std::string verison;
|
std::string version;
|
||||||
|
std::string op;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ContentPackStats {
|
struct ContentPackStats {
|
||||||
|
|||||||
66
src/content/ContentPackVersion.cpp
Normal file
66
src/content/ContentPackVersion.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include "ContentPackVersion.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "coders/commons.hpp"
|
||||||
|
|
||||||
|
Version::Version(const std::string& version) {
|
||||||
|
major = 0;
|
||||||
|
minor = 0;
|
||||||
|
patch = 0;
|
||||||
|
|
||||||
|
std::vector<int> parts;
|
||||||
|
|
||||||
|
std::stringstream ss(version);
|
||||||
|
std::string part;
|
||||||
|
while (std::getline(ss, part, '.')) {
|
||||||
|
if (!part.empty()) {
|
||||||
|
parts.push_back(std::stoi(part));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts.size() > 0) major = parts[0];
|
||||||
|
if (parts.size() > 1) minor = parts[1];
|
||||||
|
if (parts.size() > 2) patch = parts[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
DependencyVersionOperator Version::string_to_operator(const std::string& op) {
|
||||||
|
if (op == "=")
|
||||||
|
return DependencyVersionOperator::equal;
|
||||||
|
else if (op == ">")
|
||||||
|
return DependencyVersionOperator::more;
|
||||||
|
else if (op == "<")
|
||||||
|
return DependencyVersionOperator::less;
|
||||||
|
else if (op == ">=" || op == "=>")
|
||||||
|
return DependencyVersionOperator::more_or_equal;
|
||||||
|
else if (op == "<=" || op == "=<")
|
||||||
|
return DependencyVersionOperator::less_or_equal;
|
||||||
|
else return DependencyVersionOperator::equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNumber(const std::string& s) {
|
||||||
|
return !s.empty() && std::all_of(s.begin(), s.end(), ::is_digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Version::matches_pattern(const std::string& version) {
|
||||||
|
for (char c : version) {
|
||||||
|
if (!isdigit(c) && c != '.') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss(version);
|
||||||
|
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
std::string part;
|
||||||
|
while (std::getline(ss, part, '.')) {
|
||||||
|
if (part.empty()) return false;
|
||||||
|
if (!isNumber(part)) return false;
|
||||||
|
|
||||||
|
parts.push_back(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.size() == 2 || parts.size() == 3;
|
||||||
|
}
|
||||||
51
src/content/ContentPackVersion.hpp
Normal file
51
src/content/ContentPackVersion.hpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "content/ContentPack.hpp"
|
||||||
|
|
||||||
|
class Version {
|
||||||
|
public:
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
int patch;
|
||||||
|
|
||||||
|
Version(const std::string& version);
|
||||||
|
|
||||||
|
bool operator==(const Version& other) const {
|
||||||
|
return major == other.major && minor == other.minor && patch == other.patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const Version& other) const {
|
||||||
|
if (major != other.major) return major < other.major;
|
||||||
|
if (minor != other.minor) return minor < other.minor;
|
||||||
|
return patch < other.patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool operator>(const Version& other) const {
|
||||||
|
return other < *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(const Version& other) const {
|
||||||
|
return !(*this < other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(const Version& other) const {
|
||||||
|
return !(*this > other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process_operator(const std::string& op, const Version& other) const {
|
||||||
|
auto dep_op = Version::string_to_operator(op);
|
||||||
|
|
||||||
|
switch(dep_op) {
|
||||||
|
case DependencyVersionOperator::equal: return *this == other;
|
||||||
|
case DependencyVersionOperator::more: return *this > other;
|
||||||
|
case DependencyVersionOperator::less: return *this < other;
|
||||||
|
case DependencyVersionOperator::less_or_equal: return *this <= other;
|
||||||
|
case DependencyVersionOperator::more_or_equal: return *this >= other;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DependencyVersionOperator string_to_operator(const std::string& op);
|
||||||
|
static bool matches_pattern(const std::string& version);
|
||||||
|
};
|
||||||
@ -3,6 +3,7 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "ContentPackVersion.hpp"
|
||||||
#include "util/listutil.hpp"
|
#include "util/listutil.hpp"
|
||||||
|
|
||||||
PacksManager::PacksManager() = default;
|
PacksManager::PacksManager() = default;
|
||||||
@ -105,12 +106,21 @@ static bool resolve_dependencies(
|
|||||||
// added
|
// added
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (dep.verison == "*" || dep.verison == found->second.version){
|
|
||||||
|
auto dep_pack = found -> second;
|
||||||
|
|
||||||
|
if (Version::matches_pattern(dep.version) && Version::matches_pattern(dep_pack.version)
|
||||||
|
&& Version(dep_pack.version)
|
||||||
|
.process_operator(dep.op, Version(dep.version))
|
||||||
|
) {
|
||||||
// dependency pack version meets the required one
|
// dependency pack version meets the required one
|
||||||
continue;
|
continue;
|
||||||
|
} else if (dep.version == "*" || dep.version == dep_pack.version){
|
||||||
|
// fallback: dependency pack version also meets required one
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
throw contentpack_error(
|
throw contentpack_error(
|
||||||
dep.id, io::path(), "does not meet required version '" + dep.verison +"' of '" + pack->id + "'"
|
dep.id, io::path(), "does not meet required version '" + dep.op + dep.version +"' of '" + pack->id + "'"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -115,7 +115,7 @@ static int l_pack_get_info(
|
|||||||
throw std::runtime_error("");
|
throw std::runtime_error("");
|
||||||
}
|
}
|
||||||
|
|
||||||
lua::pushfstring(L, "%s%s@%s", prefix.c_str(), dpack.id.c_str(), dpack.verison.c_str());
|
lua::pushfstring(L, "%s%s@%s%s", prefix.c_str(), dpack.id.c_str(), dpack.op.c_str(), dpack.version.c_str());
|
||||||
lua::rawseti(L, i + 1);
|
lua::rawseti(L, i + 1);
|
||||||
}
|
}
|
||||||
lua::setfield(L, "dependencies");
|
lua::setfield(L, "dependencies");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user