planner: Compare versions properly

parent 618e089d
......@@ -25,6 +25,7 @@ local pcall = pcall
local require = require
local next = next
local tostring = tostring
local tonumber = tonumber
local unpack = unpack
local io = io
local os = os
......@@ -857,4 +858,58 @@ function config_modified(file, hash)
end
end
--[[
Compare two version strings. Return -1, 0, 1 if the first version
is smaller, equal or larger respectively.
]]
function version_cmp(v1, v2)
--[[
Split the version strings to numerical and non-numerical parts.
Then compare these segments lexicographically, using numerical
comparison if both are numbers and string comparison if at least
one of them isn't.
This should produce expected results when comparing two version
strings with the same schema (and when the schema is at least somehow
sane).
]]
local function explode(v)
local result = {}
for d, D in v:gmatch("(%d*)(%D*)") do
table.insert(result, d)
table.insert(result, D)
end
return result
end
local e1 = explode(v1)
local e2 = explode(v2)
local idx = 1
while true do
if e1[idx] == nil and e2[idx] == nil then
-- No more parts of versions in either one
return 0
end
local p1 = e1[idx] or ""
local p2 = e2[idx] or ""
if p1 ~= p2 then
-- They differ. Decide by this one.
if p1:match('^%d+$') and p2:match('^%d+$') then
if tonumber(p1) < tonumber(p2) then
return -1
else
return 1
end
else
if p1 < p2 then
return -1
else
return 1
end
end
end
-- They are the same. Try next segment of the version.
idx = idx + 1
end
end
return _M
......@@ -26,7 +26,8 @@ local table = table
local DIE = DIE
local DBG = DBG
local WARN = WARN
local utils = utils
local utils = require "utils"
local backend = require "backend"
module "planner"
......@@ -37,8 +38,7 @@ function candidate_choose(candidates, name)
-- First choose the candidates from the repositories with the highest priority
candidates = utils.filter_best(candidates, function (c) return c.repo.priority end, function (_1, _2) return _1 > _2 end)
-- Then according to package versions
-- FIXME: The function for comparing versions doesn't work
candidates = utils.filter_best(candidates, function (c) return c.Version end, function (_1, _2) return _1 > _2 end)
candidates = utils.filter_best(candidates, function (c) return c.Version end, function (_1, _2) return backend.version_cmp(_1, _2) == 1 end)
-- Then according to the repo order
candidates = utils.filter_best(candidates, function (c) return c.repo.serial end, function (_1, _2) return _1 < _2 end)
if #candidates > 1 then
......
......@@ -739,6 +739,15 @@ Depends: libc, ubox, libubox, libuci
]]))
end
function test_version_cmp()
assert_equal(0, B.version_cmp("1.2.3", "1.2.3"))
assert_equal(-1, B.version_cmp("1.2.3", "1.2.4"))
assert_equal(1, B.version_cmp("1.3.3", "1.2.4"))
assert_equal(-1, B.version_cmp("1.2.3", "1.2.3-2"))
assert_equal(-1, B.version_cmp("1.2.3a", "1.2.3c"))
assert_equal(1, B.version_cmp("1.10", "1.2"))
end
function setup()
local sdir = os.getenv("S") or "."
-- Use a shortened version of a real status file for tests
......
......@@ -125,8 +125,8 @@ function test_deps()
local pkgs = {
dep1 = {
candidates = {
{Package = 'dep1', Depends = {}, Version = 1, repo = def_repo},
{Package = 'dep1', Depends = {}, Version = 2, repo = def_repo}
{Package = 'dep1', Depends = {}, Version = "1", repo = def_repo},
{Package = 'dep1', Depends = {}, Version = "2", repo = def_repo}
},
modifier = {
deps = {}
......@@ -184,7 +184,7 @@ function test_deps()
local expected = {
{
action = "require",
package = {Package = 'dep1', Depends = {}, Version = 2, repo = def_repo},
package = {Package = 'dep1', Depends = {}, Version = "2", repo = def_repo},
modifier = {
deps = {}
},
......@@ -408,29 +408,29 @@ end
function test_candidate_choose()
local t1 = {
{
Version = 1,
Version = "1",
repo = def_repo
},
{
Version = 3,
Version = "3",
repo = def_repo
},
{
Version = 2,
Version = "2",
repo = def_repo
}
}
assert_equal(t1[2], planner.candidate_choose(t1, "test"))
local t2 = {
{
Version = 2,
Version = "2",
repo = {
priority = 40,
serial = 1
}
},
{
Version = 1,
Version = "1",
repo = {
priority = 50,
serial = 2
......@@ -440,14 +440,14 @@ function test_candidate_choose()
assert_equal(t2[2], planner.candidate_choose(t2, "test"))
local t3 = {
{
Version = 1,
Version = "1",
repo = {
priority = 50,
serial = 2
}
},
{
Version = 1,
Version = "1",
repo = {
priority = 50,
serial = 1
......@@ -457,11 +457,11 @@ function test_candidate_choose()
assert_equal(t3[2], planner.candidate_choose(t3, "test"))
local t4 = {
{
Version = 1,
Version = "1",
repo = def_repo
},
{
Version = 1,
Version = "1",
repo = def_repo
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment