From 91e85f9809ed406d2120e424aaa2f249ee18e2c2 Mon Sep 17 00:00:00 2001 From: Aki Date: Mon, 1 Jan 2024 23:07:21 +0100 Subject: Implemented first and easy part of reading package lists --- Makefile | 4 ++++ ensure.lua | 10 +++++++++ ensure/list.lua | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ spec/list_spec.lua | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 Makefile create mode 100644 ensure.lua create mode 100644 ensure/list.lua create mode 100644 spec/list_spec.lua diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..beb6190 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +test: + busted + +.PHONY: test diff --git a/ensure.lua b/ensure.lua new file mode 100644 index 0000000..0dd264b --- /dev/null +++ b/ensure.lua @@ -0,0 +1,10 @@ +#!/usr/bin/env lua +local l = require "ensure.list" +local loud = { + identifier = l.default.identifier, + invalid = function (_, name) io.stderr:write(string.format("invalid package name: %q\n", name)) end, +} +local p = l.all(arg[1] or os.getenv("ENSURE") or "/etc/ensure.d", loud) +for _, name in pairs(p) do + print(name) +end diff --git a/ensure/list.lua b/ensure/list.lua new file mode 100644 index 0000000..b38a62f --- /dev/null +++ b/ensure/list.lua @@ -0,0 +1,55 @@ +local dir = require "pl.dir" +local lpeg = require "lpeg" + +local list = {} + + +local function apply (state, method, ...) + if state[method] then + return state[method](state, ...) + end + return nil +end + + +local first = lpeg.R"az" + lpeg.R"09" + lpeg.S"@+_" +local rest = first + lpeg.S".-" +local space = lpeg.S" \t\n\r" +local boundary = #(space + lpeg.P(-1)) +local identifier = lpeg.Cc"identifier" * lpeg.C(first * rest^0) * boundary +local invalid = lpeg.Cc"invalid" * lpeg.C((1 - space)^1) * boundary +local entry = lpeg.Carg(1) * (identifier + invalid) / apply +local packages = space^0 * lpeg.Ct((entry * (space^1 * entry)^0)^-1) * space^0 * -lpeg.P(1) +-- TODO: Comments? +list.default = { + identifier = function (self, name) return name end, + invalid = function (self, text) end, +} + + +function list.read (text, handler) + handler = handler or list.default + return packages:match(text, nil, handler) +end + + +function list.all (dirpath, handler) + local all = {} + local lists = dir.getfiles(dirpath, "*.list") + for _, path in pairs(lists) do + local handle = io.open(path) + local packages = list.read(handle:read"a", handler) + handle:close() + if packages then + for _, name in pairs(packages) do + table.insert(all, name) + end + else + error(string.format("invalid packages list: %s", config)) + end + end + return all +end + + +return list diff --git a/spec/list_spec.lua b/spec/list_spec.lua new file mode 100644 index 0000000..d7b5889 --- /dev/null +++ b/spec/list_spec.lua @@ -0,0 +1,62 @@ +local list = require "ensure.list" + + +local function handler_with_errors () + local errors = {} + local handler = { + identifier = function (_, name) + return name + end, + invalid = function (_, text) + table.insert(errors, text) + end, + } + return handler, errors +end + + +describe("List reader", function() + it("should translate empty file into an empty table", function() + assert.are.same({}, list.read"") + end) + + it("should match valid package names", function() + local samples = {"name", "@name", "+name", "_name", "name-1.45"} + for _, name in pairs(samples) do + assert.are.same({name}, list.read(name)) + end + end) + + it("should split package names on whitespace", function() + assert.are.same( + {"one", "two", "three", "four", "five"}, + list.read [[one two three + four five]] + ) + end) + + it("should ignore leading and trailing whitespace", function() + assert.are.same({"name"}, list.read" name ") + end) + + it("should not match invalid package names", function() + assert.are.same({}, list.read".hey") + assert.are.same({}, list.read"a=3") + end) + + it("should allow custom handlers", function() + local handler = {} + stub(handler, "identifier") + stub(handler, "invalid") + local _ = list.read("correct .incorrect", handler) + assert.stub(handler.identifier).was.called() + assert.stub(handler.invalid).was.called() + end) + + it("should match valid and invalid names together", function() + local handler, errors = handler_with_errors() + local output = list.read("correct .incorrect another -and-not", handler) + assert.are.same({"correct", "another"}, output) + assert.are.same({".incorrect", "-and-not"}, errors) + end) +end) -- cgit v1.1