236 lines
5.6 KiB
Lua
236 lines
5.6 KiB
Lua
-- local db = require("solvitdb")
|
|
local db = {}
|
|
local fs = require("filesystem")
|
|
local json = require("json")
|
|
local dbpath = "/ag2/testdb.json"
|
|
function db.create()
|
|
local handle = fs.open(dbpath,"w")
|
|
handle:write("{}")
|
|
handle:close()
|
|
end
|
|
function db.readJSON()
|
|
local handle = fs.open(dbpath,"r")
|
|
local content = ""
|
|
while true do
|
|
local s = handle:read(math.huge or math.maxinteger)
|
|
if not s then break end
|
|
content=content..s
|
|
end
|
|
handle:close()
|
|
return content
|
|
end
|
|
function db.get(pack)
|
|
local dbc = json.decode(db.readJSON())
|
|
return dbc[pack]
|
|
end
|
|
function db.set(pack,info)
|
|
local dbc = json.decode(db.readJSON())
|
|
dbc[pack]=info
|
|
local handle = fs.open(dbpath,"w")
|
|
handle:write(json.encode(dbc))
|
|
handle:close()
|
|
end
|
|
function db.remove(pack)
|
|
local dbc = json.decode(db.readJSON())
|
|
dbc[pack]=nil
|
|
local handle = fs.open(dbpath,"w")
|
|
handle:write(json.encode(dbc))
|
|
handle:close()
|
|
end
|
|
|
|
local avs = {}
|
|
function avs.splitSingular(s)
|
|
local result = {}
|
|
for str in string.gmatch(s, "([^.]+)") do
|
|
table.insert(result,tonumber(str) or -1)
|
|
end
|
|
return result
|
|
end
|
|
|
|
function avs.parse(pack)
|
|
if not string.find(pack,"=") then
|
|
return {pack}
|
|
end
|
|
local idx=pack:find("=")
|
|
local name=pack:sub(1,idx-1)
|
|
local verstr=pack:sub(idx+1)
|
|
if string.find(verstr,"-") then
|
|
idx=verstr:find("-")
|
|
verstr={verstr:sub(1,idx-1),verstr:sub(idx+1)}
|
|
else
|
|
verstr={verstr}
|
|
end
|
|
for i=1,#verstr do
|
|
verstr[i]=avs.splitSingular(verstr[i])
|
|
end
|
|
if #verstr>1 then
|
|
for i=1,3 do
|
|
verstr[1][i]=math.max(verstr[1][i],0)
|
|
end
|
|
end
|
|
return {name,verstr}
|
|
end
|
|
|
|
function avs.serializeSingle(ver)
|
|
local ver2 = table.copy(ver)
|
|
for i=1,3 do
|
|
if ver2[i]==-1 then
|
|
ver2[i]="*"
|
|
else
|
|
ver2[i]=tostring(ver2[i])
|
|
end
|
|
end
|
|
return ver2[1].."."..ver2[2].."."..ver2[3]
|
|
end
|
|
|
|
function avs.serializeVersion(ver)
|
|
out=""
|
|
for i=1,#ver do
|
|
out=out..avs.serializeSingle(ver[i])
|
|
if i~=#ver then
|
|
out=out.."-"
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
|
|
function avs.serializePack(pack)
|
|
if #pack==1 then
|
|
return pack[1]
|
|
end
|
|
return pack[1].."="..avs.serializeVersion(pack[2])
|
|
end
|
|
|
|
function avs.singleGreater(ver1,ver2)
|
|
for i=1,3 do
|
|
if ver1[i]~=ver2[i] then
|
|
if ver1[i]==-1 or ver1[i]>ver2[i] then
|
|
return true
|
|
end
|
|
if ver2[i]==-1 or ver2[i]>ver1[i] then
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function avs.singleLesser(ver1,ver2)
|
|
return avs.singleGreater(ver2,ver1)
|
|
end
|
|
|
|
function avs.singleMin(ver1,ver2)
|
|
return avs.singleLesser(ver1,ver2) and ver1 or ver2
|
|
end
|
|
|
|
function avs.singleMax(ver1,ver2)
|
|
return avs.singleGreater(ver1,ver2) and ver1 or ver2
|
|
end
|
|
|
|
function avs.compatibleRange(vers)
|
|
for i=1,#vers do
|
|
if type(vers[i])=="string" then vers[i]=avs.parse(vers[i])[2] end
|
|
if #vers[i]==1 then vers[i]={vers[i][1],vers[i][1]} end
|
|
end
|
|
local range = vers[1]
|
|
for i=2,#vers do
|
|
range[1]=avs.singleMax(range[1],vers[i][1])
|
|
range[2]=avs.singleMin(range[2],vers[i][2])
|
|
end
|
|
if avs.singleGreater(range[1],range[2]) then
|
|
return nil
|
|
end
|
|
return range
|
|
end
|
|
|
|
local function packageInArray(pack,arr)
|
|
for i=1,#arr do
|
|
if arr[i][1]==pack[1] then -- TODO: check for compatible package version
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function startTransaction()
|
|
if not fs.exists(dbpath) then
|
|
db.create()
|
|
end
|
|
|
|
local packInfo = {}
|
|
local ins = {}
|
|
local rem = {}
|
|
local transaction = {}
|
|
function transaction.install(name)
|
|
table.insert(ins,avs.parse(name))
|
|
end
|
|
function transaction.remove(name)
|
|
end
|
|
function transaction.addInfo(name,info)
|
|
packInfo[name]=info
|
|
-- print(require("serialize").table(packInfo))
|
|
end
|
|
function transaction.finalize(settings)
|
|
local function getPackInfo(pack)
|
|
return packInfo[avs.serializePack(pack)]
|
|
end
|
|
|
|
local foundDeps=false
|
|
repeat
|
|
foundDeps=false
|
|
-- find missing package information
|
|
local missing = {}
|
|
for i=1,#ins do
|
|
if getPackInfo(ins[i])==nil then
|
|
table.insert(missing,avs.serializePack(ins[i]))
|
|
end
|
|
end
|
|
if #missing>0 then
|
|
return false,missing
|
|
end
|
|
-- find dependencies
|
|
local i=1
|
|
while i<=#ins do
|
|
local deps = getPackInfo(ins[i]).dependencies
|
|
if deps and #deps>=1 then
|
|
for j=1,#deps do
|
|
local dep = avs.parse(deps[j])
|
|
if (not packageInArray(dep,ins)) and db.get(dep[1]) then
|
|
foundDeps=true
|
|
table.insert(ins,j,dep)
|
|
end
|
|
end
|
|
i=i+#deps
|
|
end
|
|
i=i+1
|
|
end
|
|
until not foundDeps
|
|
|
|
return {install=ins}
|
|
|
|
-- return "true, {["install"] = {"dep1", "package1", "package2"}, ["remove"] = {"package3"}}" on success
|
|
-- return "false, {"dep1"}" when not enough data
|
|
-- return "false, "[verbose string]"" when conflict found
|
|
-- TODO: be able to resolve conflicts
|
|
-- TODO: implement removing packages
|
|
-- TODO: handle same constant AVS
|
|
-- TODO: handle different constant AVS conflict
|
|
-- TODO: handle same range AVS
|
|
-- TODO: handle different intercompatible 1.*.* range AVS
|
|
-- TODO: handle different incompatible 1.*.* range AVS
|
|
-- TODO: handle different intercompatible 1.*.*-2.*.* range AVS
|
|
-- TODO: handle different incompatible 1.*.*-2.*.* range AVS
|
|
-- TODO: handle conflicts from package info
|
|
-- TODO: handle reverse conflicts from another package's info
|
|
end
|
|
function transaction.store()
|
|
for i,v in pairs(packInfo) do
|
|
db.set(i,v)
|
|
end
|
|
-- TODO: make and store reverse dependencies
|
|
end
|
|
return transaction
|
|
end
|
|
|
|
return { avs=avs,startTransaction=startTransaction }
|