#!/usr/libexec/flua -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright(c) 2025 The FreeBSD Foundation. -- -- This software was developed by Isaac Freund -- under sponsorship from the FreeBSD Foundation. -- Run a command using the OS shell and capture the stdout -- Strips exactly one trailing newline if present, does not strip any other whitespace. -- Asserts that the command exits cleanly local function capture(command) local p = io.popen(command) local output = p:read("*a") assert(p:close()) -- Strip exactly one trailing newline from the output, if there is one return output:match("(.-)\n$") or output end local function append_list(list, other) for _, item in ipairs(other) do table.insert(list, item) end end -- Returns a list of packages to be included in the given media local function select_packages(pkg, media, all_libcompats) local components = { kernel = {}, kernel_dbg = {}, base = {}, base_dbg = {}, src = {}, tests = {}, } for compat in all_libcompats:gmatch("%S+") do components["lib" .. compat] = {} components["lib" .. compat .. "_dbg"] = {} end local rquery = capture(pkg .. "rquery -U -r FreeBSD-base %n") for package in rquery:gmatch("[^\n]+") do if package == "FreeBSD-src" or package:match("^FreeBSD%-src%-.*") then table.insert(components["src"], package) elseif package == "FreeBSD-tests" or package:match("^FreeBSD%-tests%-.*") then table.insert(components["tests"], package) elseif package:match("^FreeBSD%-kernel%-.*") and package ~= "FreeBSD-kernel-man" then -- Kernels other than FreeBSD-kernel-generic are ignored if package == "FreeBSD-kernel-generic" then table.insert(components["kernel"], package) elseif package == "FreeBSD-kernel-generic-dbg" then table.insert(components["kernel_dbg"], package) end elseif package:match(".*%-dbg$") then table.insert(components["base_dbg"], package) else local found = false for compat in all_libcompats:gmatch("%S+") do if package:match(".*%-dbg%-lib" .. compat .. "$") then table.insert(components["lib" .. compat .. "_dbg"], package) found = true break elseif package:match(".*%-lib" .. compat .. "$") then table.insert(components["lib" .. compat], package) found = true break end end if not found then table.insert(components["base"], package) end end end assert(#components["kernel"] == 1) assert(#components["base"] > 0) local selected = {} if media == "disc" then append_list(selected, components["base"]) append_list(selected, components["kernel"]) append_list(selected, components["kernel_dbg"]) append_list(selected, components["src"]) append_list(selected, components["tests"]) for compat in all_libcompats:gmatch("%S+") do append_list(selected, components["lib" .. compat]) end else assert(media == "dvd") append_list(selected, components["base"]) append_list(selected, components["base_dbg"]) append_list(selected, components["kernel"]) append_list(selected, components["kernel_dbg"]) append_list(selected, components["src"]) append_list(selected, components["tests"]) for compat in all_libcompats:gmatch("%S+") do append_list(selected, components["lib" .. compat]) append_list(selected, components["lib" .. compat .. "_dbg"]) end end return selected end local function main() -- Determines package subset selected local media = assert(arg[1]) assert(media == "disc" or media == "dvd") -- Local repository to fetch from local source = assert(arg[2]) -- Directory to create new repository local target = assert(arg[3]) -- =hitespace separated list of all libcompat names (e.g. "32") local all_libcompats = assert(arg[4]) assert(os.execute("mkdir -p pkgbase-repo-conf")) local f = assert(io.open("pkgbase-repo-conf/FreeBSD-base.conf", "w")) assert(f:write(string.format([[ FreeBSD-base: { url: "file://%s", enabled: yes } ]], source))) assert(f:close()) local pkg = "pkg -o ASSUME_ALWAYS_YES=yes -o IGNORE_OSVERSION=yes " .. "-o INSTALL_AS_USER=1 -o PKG_DBDIR=./pkgdb -R ./pkgbase-repo-conf " assert(os.execute(pkg .. "update")) local packages = select_packages(pkg, media, all_libcompats) assert(os.execute(pkg .. "fetch -o " .. target .. " " .. table.concat(packages, " "))) assert(os.execute(pkg .. "repo " .. target)) end main()