bliss

KISS in Lua
git clone git://bvnf.space/bliss.git
Log | Files | Refs | README | LICENSE

commit 5b28d35e545b60453103e3acda32ac158af9e121
parent b2dc5a6e890d7d66a8b686a30250f2f0dcd24dea
Author: phoebos <ben@bvnf.space>
Date:   Fri, 16 Jun 2023 14:04:41 +0100

add pkg.order using a tsort

Diffstat:
Mbliss/pkg.lua | 33+++++++++++++++++++++++++++++++++
Abliss/tsort.lua | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 110 insertions(+), 0 deletions(-)

diff --git a/bliss/pkg.lua b/bliss/pkg.lua @@ -1,4 +1,5 @@ local utils = require 'bliss.utils' +local tsort = require 'bliss.tsort' local sys_stat = require 'posix.sys.stat' local function read_lines(file) @@ -33,6 +34,11 @@ local function find_version(pkg, path) return ver[1] end +local function find_depends(pkg, path) + local p = find(pkg, path) .. "/depends" + return read_lines(p) +end + local function find_sources(pkg, repo_dir) local p = repo_dir .. "/sources" @@ -77,10 +83,37 @@ local function resolve(pkg, sources, env, repo_dir) return caches end +local function order(env, pkgs) + local t = tsort.new() + + for _,p in ipairs(pkgs) do + local deps = find_depends(p, env.PATH) + local deps_nomake = {} + for _,v in ipairs(deps) do + table.insert(deps_nomake, v[1]) + end + t:add(p, deps_nomake) + end + + local s, x,y = t:sort() + if not s then + utils.die("Circular dependency detected: " .. x .. " <> " .. y) + end + + -- return s reversed (in order to be built) + local r = {} + for i = #s, 1, -1 do + r[i] = s[i] + end + return r +end + local M = { find = find, find_version = find_version, + find_depends = find_depends, find_sources = find_sources, resolve = resolve, + order = order, } return M diff --git a/bliss/tsort.lua b/bliss/tsort.lua @@ -0,0 +1,77 @@ +-- This module is not included in init.lua, but used locally by pkg.lua. +local tsort = {} + +-- Returns a table of reverse deps +local function reverse(input) + local reversed = {} + for k,v in pairs(input) do + for _,w in ipairs(v) do + reversed[w] = reversed[w] or {} + table.insert(reversed[w], k) + end + end + return reversed +end + +local function find_cycle(revlinks, start) + local ret = {[start] = 1} + local old + + local t = revlinks[start][1] + while t and not ret[t] do + ret[t] = 1 + old = t + t = revlinks[t][1] + end + return t, old +end + +function tsort.new() + return setmetatable({nodes={}}, {__index = tsort}) +end + +function tsort:add(node, deps) + self.nodes[node] = deps +end + +function tsort:sort() + if not self.nodes then return nil end + local L = {} + local reversed = reverse(self.nodes) + + -- find nodes with no incoming edges + local S = {} + for k in pairs(self.nodes) do + if not reversed[k] or #reversed[k] == 0 then + table.insert(S, k) + end + end + + while #S ~= 0 do + local n = table.remove(S, 1) + table.insert(L, n) + for _,v in ipairs(self.nodes[n] or {}) do + -- remove edge n -> v + for i,j in ipairs(reversed[v]) do + if j == n then + table.remove(reversed[v], i) + end + end + if not reversed[v] or #reversed[v] == 0 then + table.insert(S, v) + reversed[v] = nil + end + end + end + + for k,v in pairs(reversed) do + if #v ~= 0 then + -- cycle detected + local x,y = find_cycle(reversed, k) + return nil, x, y + end + end + return L +end + +return tsort