xref: /freebsd/release/packages/generate-set-ucl.lua (revision c8f9a9abd8000a8514e0beee99ffcf48d05ce47b)
166f36c36SLexi Winter#!/usr/libexec/flua
2*c8f9a9abSLexi Winter--
3*c8f9a9abSLexi Winter-- Copyright (c) 2024-2025 Baptiste Daroussin <bapt@FreeBSD.org>
4*c8f9a9abSLexi Winter-- Copyright (c) 2025 Lexi Winter <ivy@FreeBSD.org>
5*c8f9a9abSLexi Winter--
6*c8f9a9abSLexi Winter-- SPDX-License-Identifier: BSD-2-Clause
7*c8f9a9abSLexi Winter--
866f36c36SLexi Winter
966f36c36SLexi Winter--[[ usage:
109e6cea12SJose Luis Durangenerate-set-ucl.lua <template> [<variablename> <variablevalue>]
1166f36c36SLexi Winter
1266f36c36SLexi WinterGenerate the UCL for a set metapackage.  The variables provided will be
1366f36c36SLexi Wintersubstituted as UCL variables.
1466f36c36SLexi Winter]]--
1566f36c36SLexi Winter
1666f36c36SLexi Winterlocal ucl = require("ucl")
1766f36c36SLexi Winter
1866f36c36SLexi Winter-- This parser is the output UCL we want to build.
1966f36c36SLexi Winterlocal parser = ucl.parser()
2066f36c36SLexi Winter
2166f36c36SLexi Winterif #arg < 1 then
2266f36c36SLexi Winter	io.stderr:write(arg[0] .. ": missing template filename\n")
2366f36c36SLexi Winter	os.exit(1)
2466f36c36SLexi Winterend
2566f36c36SLexi Winter
2666f36c36SLexi Winterlocal template = table.remove(arg, 1)
2766f36c36SLexi Winter
2866f36c36SLexi Winter-- Set any $VARIABLES from the command line in the parser.  This causes ucl to
2966f36c36SLexi Winter-- automatically replace them when we load the source ucl.
3066f36c36SLexi Winterif #arg % 2 ~= 0 then
3166f36c36SLexi Winter	io.stderr:write(arg[0] .. ": expected an even number of arguments, "
3266f36c36SLexi Winter	    .. "got " .. #arg .. "\n")
3366f36c36SLexi Winter	os.exit(1)
3466f36c36SLexi Winterend
3566f36c36SLexi Winter
3666f36c36SLexi Winterlocal pkgprefix = nil
3766f36c36SLexi Winterlocal pkgversion = nil
3866f36c36SLexi Winterlocal pkgdeps = ""
3966f36c36SLexi Winter
4066f36c36SLexi Winterfor i = 2, #arg, 2 do
4166f36c36SLexi Winter	local varname = arg[i - 1]
4266f36c36SLexi Winter	local varvalue = arg[i]
4366f36c36SLexi Winter
4466f36c36SLexi Winter	if varname == "PKG_NAME_PREFIX" and #varvalue > 0 then
4566f36c36SLexi Winter		pkgprefix = varvalue
4666f36c36SLexi Winter	elseif varname == "VERSION" and #varvalue > 0 then
4766f36c36SLexi Winter		pkgversion = varvalue
4866f36c36SLexi Winter	elseif varname == "SET_DEPENDS" and #varvalue > 0 then
4966f36c36SLexi Winter		pkgdeps = varvalue
5066f36c36SLexi Winter	end
5166f36c36SLexi Winter
5266f36c36SLexi Winter	parser:register_variable(varname, varvalue)
5366f36c36SLexi Winterend
5466f36c36SLexi Winter
5566f36c36SLexi Winter-- Load the source template.
5666f36c36SLexi Winterlocal res,err = parser:parse_file(template)
5766f36c36SLexi Winterif not res then
5866f36c36SLexi Winter	io.stderr:write(arg[0] .. ": fail to parse(" .. template .. "): "
5966f36c36SLexi Winter	    .. err .. "\n")
6066f36c36SLexi Winter	os.exit(1)
6166f36c36SLexi Winterend
6266f36c36SLexi Winter
6366f36c36SLexi Winterlocal obj = parser:get_object()
6466f36c36SLexi Winter
6566f36c36SLexi Winter-- Dependency handling.
6666f36c36SLexi Winterobj["deps"] = obj["deps"] or {}
6766f36c36SLexi Winter
6866f36c36SLexi Winter-- If PKG_NAME_PREFIX is provided, rewrite the names of dependency packages.
6966f36c36SLexi Winter-- We can't do this in UCL since variable substitution doesn't work in array
7066f36c36SLexi Winter-- keys.  Note that this only applies to dependencies from the set UCL files,
7166f36c36SLexi Winter-- because SET_DEPENDS already have the correct prefix.
7266f36c36SLexi Winterif pkgprefix ~= nil then
7366f36c36SLexi Winter	newdeps = {}
7466f36c36SLexi Winter	for dep, opts in pairs(obj["deps"]) do
7566f36c36SLexi Winter		local newdep = pkgprefix .. "-" .. dep
7666f36c36SLexi Winter		newdeps[newdep] = opts
7766f36c36SLexi Winter	end
7866f36c36SLexi Winter	obj["deps"] = newdeps
7966f36c36SLexi Winterend
8066f36c36SLexi Winter
8166f36c36SLexi Winter-- Add dependencies from SET_DEPENDS.
8266f36c36SLexi Winterfor dep in string.gmatch(pkgdeps, "[^%s]+") do
8366f36c36SLexi Winter	obj["deps"][dep] = {
84a507a702SLexi Winter		["origin"] = "base/"..dep
8566f36c36SLexi Winter	}
8666f36c36SLexi Winterend
8766f36c36SLexi Winter
88a507a702SLexi Winter-- Add a version and origin key to all dependencies, otherwise pkg
89a507a702SLexi Winter-- doesn't like it.
9066f36c36SLexi Winterfor dep, opts in pairs(obj["deps"]) do
91a507a702SLexi Winter	obj["deps"][dep]["origin"] = obj["deps"][dep]["origin"] or "base/"..dep
92a507a702SLexi Winter	obj["deps"][dep]["version"] = obj["deps"][dep]["version"] or pkgversion
9366f36c36SLexi Winterend
9466f36c36SLexi Winter
9566f36c36SLexi Winter-- If there are no dependencies, remove the deps key, otherwise pkg raises an
9666f36c36SLexi Winter-- error trying to read the manifest.
9766f36c36SLexi Winterif next(obj["deps"]) == nil then
9866f36c36SLexi Winter	obj["deps"] = nil
9966f36c36SLexi Winterend
10066f36c36SLexi Winter
10166f36c36SLexi Winter-- Write the output.
10266f36c36SLexi Winterio.stdout:write(ucl.to_format(obj, 'ucl', true))
103