--follow now follows the deptree of the definition --follow is incompatible with --all build_system = "custom" example with build.sh
244 lines
7.3 KiB
Plaintext
Executable File
244 lines
7.3 KiB
Plaintext
Executable File
#!/usr/bin/env lua
|
|
-- zeta-makepkg — build Zeta binary packages from declarative .recipe files.
|
|
--
|
|
-- Usage:
|
|
-- zeta-makepkg <recipe> [flags] Build a package from a recipe
|
|
-- zeta-makepkg --index [flags] Regenerate packages/index.lua
|
|
--
|
|
-- Flags:
|
|
-- --output <dir> Output repository root (default: .)
|
|
-- --no-index Skip index.lua update
|
|
-- --keep-work Preserve build work directory
|
|
-- --force Overwrite existing package
|
|
-- --help Show this help
|
|
--
|
|
-- Pipeline:
|
|
-- LOAD recipe → FETCH source → EXTRACT → BUILD → TEST → PACKAGE → INDEX
|
|
|
|
-- Lua 5.1 compat: arg[0] is the script path, not the interpreter.
|
|
local here
|
|
if arg and arg[0] and arg[0]:match("[/\\]") then
|
|
here = arg[0]:match("^(.*)[/\\][^/\\]*$")
|
|
elseif arg and arg[-1] then
|
|
-- Lua 5.1 sends script path as arg[-1] when using env.
|
|
here = arg[-1]:match("^(.*)[/\\][^/\\]*$")
|
|
else
|
|
here = "."
|
|
end
|
|
|
|
-- Resolve the real directory in case we were invoked via a symlink.
|
|
if here then
|
|
local f = io.popen("cd " .. here:gsub("'", "'\\''") .. " 2>/dev/null && pwd")
|
|
if f then
|
|
local real = f:read("*l")
|
|
f:close()
|
|
if real and real ~= "" then here = real end
|
|
end
|
|
else
|
|
here = "."
|
|
end
|
|
|
|
-- Library path: works both from the repo tree (../lib/) and when installed
|
|
-- via 'make install' (/usr/local/lib/zeta-toolchain/).
|
|
package.path = here .. "/../lib/?.lua;"
|
|
.. here .. "/../lib/zeta-toolchain/?.lua;"
|
|
.. package.path
|
|
|
|
local path = require("path")
|
|
local log = require("log")
|
|
local build = require("build")
|
|
local indexer = require("indexer")
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Help
|
|
---------------------------------------------------------------------------
|
|
|
|
local HELP = [[
|
|
zeta-makepkg — build Zeta binary packages from declarative .recipe files.
|
|
|
|
Usage:
|
|
zeta-makepkg <recipe> [flags]
|
|
zeta-makepkg --all <dir> [flags]
|
|
zeta-makepkg --index [flags]
|
|
|
|
Commands:
|
|
<recipe> Build a package from a .recipe file
|
|
--all <dir> Build all .recipe files found in <dir>
|
|
--index Regenerate packages/index.lua from existing package.lua files
|
|
|
|
Flags:
|
|
--output <dir> Output repository root (default: .)
|
|
Creates packages/<name>/ with tarball + package.lua
|
|
--repo <url> Base URL for generated package.lua manifests
|
|
(default: https://raw.githubusercontent.com/gretagen/...)
|
|
-j, --jobs <N> Number of parallel build jobs (default: nproc)
|
|
-w, --workers <N> Number of parallel package builds for --all (default: 1)
|
|
--no-index Don't update packages/index.lua after building
|
|
--keep-work Don't remove the build work directory
|
|
--follow Build all dependencies first (bottom-up), then the package.
|
|
Incompatible with --all.
|
|
--force Overwrite existing package tarball
|
|
--help Show this help
|
|
|
|
Cache:
|
|
Downloaded sources are cached in ~/.cache/zeta-makepkg/sources/
|
|
Build work is done in /tmp/zeta-makepkg/<name>-<timestamp>/
|
|
|
|
Examples:
|
|
zeta-makepkg mypkg.recipe
|
|
zeta-makepkg mypkg.recipe --output ~/zeta-packages --force
|
|
zeta-makepkg --all recipes/ --output ~/zeta-packages
|
|
zeta-makepkg --index --output ~/zeta-packages
|
|
]]
|
|
|
|
---------------------------------------------------------------------------
|
|
-- CLI parsing
|
|
---------------------------------------------------------------------------
|
|
|
|
local function parse_cli(args)
|
|
local opts = {
|
|
output = ".",
|
|
no_index = false,
|
|
keep_work = false,
|
|
force = false,
|
|
index = false,
|
|
all = nil,
|
|
follow = false,
|
|
help = false,
|
|
recipe = nil,
|
|
jobs = nil, -- nil = auto-detect (nproc)
|
|
workers = 1, -- parallel package builds (--all only)
|
|
repo = "https://raw.githubusercontent.com/gretagen/zeta-packages/refs/heads/main",
|
|
}
|
|
|
|
local i = 1
|
|
while i <= #args do
|
|
local a = args[i]
|
|
if a == "--help" or a == "-h" then
|
|
opts.help = true
|
|
elseif a == "--index" then
|
|
opts.index = true
|
|
elseif a == "--all" then
|
|
i = i + 1
|
|
if i > #args then
|
|
io.stderr:write("error: --all requires a directory argument\n")
|
|
return nil
|
|
end
|
|
opts.all = args[i]
|
|
elseif a == "--output" then
|
|
i = i + 1
|
|
if i > #args then
|
|
io.stderr:write("error: --output requires a directory argument\n")
|
|
return nil
|
|
end
|
|
opts.output = args[i]
|
|
elseif a == "--repo" then
|
|
i = i + 1
|
|
if i > #args then
|
|
io.stderr:write("error: --repo requires a URL argument\n")
|
|
return nil
|
|
end
|
|
opts.repo = args[i]
|
|
elseif a == "--no-index" then
|
|
opts.no_index = true
|
|
elseif a == "--keep-work" then
|
|
opts.keep_work = true
|
|
elseif a == "--force" then
|
|
opts.force = true
|
|
elseif a == "--follow" then
|
|
opts.follow = true
|
|
elseif a == "--jobs" then
|
|
i = i + 1
|
|
if i > #args then
|
|
io.stderr:write("error: --jobs requires a number argument\n")
|
|
return nil
|
|
end
|
|
local n = tonumber(args[i])
|
|
if not n or n < 1 then
|
|
io.stderr:write(("error: invalid jobs value %q\n"):format(args[i]))
|
|
return nil
|
|
end
|
|
opts.jobs = n
|
|
elseif a:match("^%-j%d+$") then
|
|
local n = tonumber(a:match("^%-j(%d+)$"))
|
|
opts.jobs = n
|
|
elseif a == "-j" then
|
|
i = i + 1
|
|
if i > #args then
|
|
io.stderr:write("error: -j requires a number argument\n")
|
|
return nil
|
|
end
|
|
local n = tonumber(args[i])
|
|
if not n or n < 1 then
|
|
io.stderr:write(("error: invalid jobs value %q\n"):format(args[i]))
|
|
return nil
|
|
end
|
|
opts.jobs = n
|
|
elseif a == "--workers" then
|
|
i = i + 1
|
|
if i > #args then
|
|
io.stderr:write("error: --workers requires a number argument\n")
|
|
return nil
|
|
end
|
|
local n = tonumber(args[i])
|
|
if not n or n < 1 then
|
|
io.stderr:write(("error: invalid workers value %q\n"):format(args[i]))
|
|
return nil
|
|
end
|
|
opts.workers = n
|
|
elseif a:match("^%-w%d+$") then
|
|
local n = tonumber(a:match("^%-w(%d+)$"))
|
|
opts.workers = n
|
|
elseif a:match("^%-") then
|
|
io.stderr:write(("error: unknown flag %s\n"):format(a))
|
|
return nil
|
|
elseif not opts.recipe and not opts.index then
|
|
opts.recipe = a
|
|
else
|
|
io.stderr:write(("error: unexpected argument %s\n"):format(a))
|
|
return nil
|
|
end
|
|
i = i + 1
|
|
end
|
|
|
|
return opts
|
|
end
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Dispatch
|
|
---------------------------------------------------------------------------
|
|
|
|
local args = {}
|
|
for i = 1, #arg do args[i] = arg[i] end
|
|
|
|
local opts = parse_cli(args)
|
|
if not opts then
|
|
io.stderr:write("Run 'zeta-makepkg --help' for usage.\n")
|
|
os.exit(1)
|
|
end
|
|
|
|
if opts.help then
|
|
io.write(HELP)
|
|
os.exit(0)
|
|
end
|
|
|
|
if opts.follow and opts.all then
|
|
io.stderr:write("error: --follow and --all are incompatible\n")
|
|
os.exit(1)
|
|
end
|
|
|
|
if opts.index then
|
|
indexer.generate(path.join(opts.output, "packages"))
|
|
elseif opts.all then
|
|
build.all(opts.all, opts, arg[0])
|
|
elseif opts.recipe then
|
|
local ok, err = pcall(build.single, opts.recipe, opts)
|
|
if not ok then
|
|
log.fatal(tostring(err))
|
|
end
|
|
else
|
|
io.stderr:write("error: no recipe specified\n")
|
|
io.stderr:write("Run 'zeta-makepkg --help' for usage.\n")
|
|
os.exit(1)
|
|
end
|