Path: blob/main/release/packages/generate-ucl.lua
102428 views
#!/usr/libexec/flua1--2-- Copyright (c) 2024-2025 Baptiste Daroussin <[email protected]>3-- Copyright (c) 2025 Lexi Winter <[email protected]>4--5-- SPDX-License-Identifier: BSD-2-Clause6--78--[[ usage:9generate-ucl.lua [<variablename> <variablevalue>]... <sourceucl> <destucl>1011Build a package's UCL configuration by loading the template UCL file12<sourceucl>, replacing any $VARIABLES in the UCL based on the provided13variables, then writing the result to <destucl>.14]]--1516local ucl = require("ucl")1718-- Give subpackages a special comment and description suffix to indicate what19-- they contain, so e.g. "foo-man" has " (manual pages)" appended to its20-- comment. This avoids having to create a separate ucl files for every21-- subpackage just to set this.22--23-- Note that this is not a key table because the order of the pattern matches24-- is important.25pkg_suffixes = {26{27"%-dev%-lib32$", "(32-bit development files)",28"This package contains development files for compiling "..29"32-bit applications on a 64-bit host."30},31{32"%-dbg%-lib32$", "(32-bit debugging symbols)",33"This package contains 32-bit external debugging symbols "..34"for use with a source-level debugger.",35},36{37"%-man%-lib32$", "(32-bit manual pages)",38"This package contains the online manual pages for 32-bit "..39"components on a 64-bit host.",40},41{42"%-lib32$", "(32-bit libraries)",43"This package contains 32-bit libraries for running 32-bit "..44"applications on a 64-bit host.",45},46{47"%-lib$", "(libraries)",48"This package contains runtime shared libraries.",49},50{51"%-dev$", "(development files)",52"This package contains development files for "..53"compiling applications."54},55{56"%-man$", "(manual pages)",57"This package contains the online manual pages."58},59{60"%-dbg$", "(debugging symbols)",61"This package contains external debugging symbols for use "..62"with a source-level debugger.",63},64}6566-- A list of packages which don't get the automatic suffix handling,67-- e.g. -man packages with no corresponding base package.68local no_suffix_pkgs = {69["kernel-man"] = true,70}7172function add_suffixes(obj)73local pkgname = obj["name"]7475for _,pattern in pairs(pkg_suffixes) do76if pkgname:match(pattern[1]) ~= nil then77obj["comment"] = obj["comment"] .. " " .. pattern[2]78obj["desc"] = obj["desc"] .. "\n\n" .. pattern[3]79return80end81end82end8384-- Hardcode a list of packages which don't get the automatic pkggenname85-- dependency because the base package doesn't exist. We should have a better86-- way to handle this.87local no_gen_deps = {88["libcompat-dev"] = true,89["libcompat-dev-lib32"] = true,90["libcompat-man"] = true,91["libcompiler_rt-dev"] = true,92["libcompiler_rt-dev-lib32"] = true,93["liby-dev"] = true,94["liby-dev-lib32"] = true,95["kernel-man"] = true,96}9798-- Return true if the package 'pkgname' should have a dependency on the package99-- pkggenname.100function add_gen_dep(pkgname, pkggenname)101if pkgname == pkggenname then102return false103end104if pkgname == nil or pkggenname == nil then105return false106end107if no_gen_deps[pkgname] ~= nil then108return false109end110if pkgname:match("%-lib$") ~= nil then111return false112end113if pkggenname == "kernel" then114return false115end116117return true118end119120local pkgname = nil121local pkggenname = nil122local pkgprefix = nil123local pkgversion = nil124125-- This parser is the output UCL we want to build.126local parser = ucl.parser()127128-- Set any $VARIABLES from the command line in the parser. This causes ucl to129-- automatically replace them when we load the source ucl.130if #arg < 2 or #arg % 2 ~= 0 then131io.stderr:write(arg[0] .. ": expected an even number of arguments, got " .. #arg)132os.exit(1)133end134135for i = 2, #arg - 2, 2 do136local varname = arg[i - 1]137local varvalue = arg[i]138139if varname == "PKGNAME" and #varvalue > 0 then140pkgname = varvalue141elseif varname == "PKGGENNAME" and #varvalue > 0 then142pkggenname = varvalue143elseif varname == "VERSION" and #varvalue > 0 then144pkgversion = varvalue145elseif varname == "PKG_NAME_PREFIX" and #varvalue > 0 then146pkgprefix = varvalue147end148149parser:register_variable(varname, varvalue)150end151152-- Load the source ucl file.153local res,err = parser:parse_file(arg[#arg - 1])154if not res then155io.stderr:write(arg[0] .. ": fail to parse("..arg[#arg - 1].."): "..err)156os.exit(1)157end158159local obj = parser:get_object()160161-- If pkgname is different from pkggenname, add a dependency on pkggenname.162-- This means that e.g. -dev packages depend on their respective base package.163if add_gen_dep(pkgname, pkggenname) then164if obj["deps"] == nil then165obj["deps"] = {}166end167obj["deps"][pkggenname] = {168["version"] = pkgversion,169["origin"] = "base/"..pkgprefix.."-"..pkggenname,170}171end172173--174-- Handle the 'set' annotation, a comma-separated list of sets which this175-- package should be placed in. If it's not specified, the package goes176-- in the default set which is base.177--178-- Ensure we have an annotations table to work with.179obj["annotations"] = obj["annotations"] or {}180-- If no set is provided, use the default set which is "base".181sets = obj["annotations"]["set"] or "base"182-- For subpackages, we may need to rewrite the set name. This is done a little183-- differently from the normal pkg suffix processing, because we don't need sets184-- to be as a granular as the base packages.185--186-- Create a single lib32 set for all lib32 packages. Most users don't need187-- lib32, so this avoids creating a large number of unnecessary lib32 sets.188-- However, lib32 debug symbols still go into their own package since they're189-- quite large.190if pkgname:match("%-dbg%-lib32$") then191sets = "lib32-dbg"192elseif pkgname:match("%-lib32$") then193sets = "lib32"194-- If this is a -dev package, put it in a single set called "devel" which195-- contains all development files. Also include lib*-man packages, which196-- contain manpages for libraries. Having a separate <set>-dev for every197-- set is not necessary, because generally you either want development198-- support or you don't.199elseif pkgname:match("%-dev$") or pkgname:match("^lib.*%-man$") then200sets = "devel"201-- Don't separate tests and tests-dbg into 2 sets, if the user wants tests202-- they should be able to debug failures.203elseif sets == "tests" then204sets = sets205-- If this is a -dbg package, put it in the -dbg subpackage of each set,206-- which means the user can install debug symbols only for the sets they207-- have installed.208elseif pkgname:match("%-dbg$") then209local newsets = {}210for set in sets:gmatch("[^,]+") do211newsets[#newsets + 1] = set .. "-dbg"212end213sets = table.concat(newsets, ",")214end215-- Put our new sets back into the package.216obj["annotations"]["set"] = sets217218-- If PKG_NAME_PREFIX is provided, rewrite the names of dependency packages.219-- We can't do this in UCL since variable substitution doesn't work in array220-- keys.221if pkgprefix ~= nil and obj["deps"] ~= nil then222newdeps = {}223for dep, opts in pairs(obj["deps"]) do224local newdep = pkgprefix .. "-" .. dep225-- Make sure origin is set.226opts["origin"] = opts["origin"] or "base/"..newdep227newdeps[newdep] = opts228end229obj["deps"] = newdeps230end231232-- Add comment and desc suffix.233if no_suffix_pkgs[pkgname] == nil then234add_suffixes(obj)235end236237-- Write the output file.238local f,err = io.open(arg[#arg], "w")239if not f then240io.stderr:write(arg[0] .. ": fail to open("..arg[#arg].."): ".. err)241os.exit(1)242end243244f:write(ucl.to_format(obj, 'ucl', true))245f:close()246247248