xref: /freebsd/release/scripts/pkgbase-stage.lua (revision 9065390ddc7b1ce2613777f6a947200950a5ac71)
1#!/usr/libexec/flua
2
3-- SPDX-License-Identifier: BSD-2-Clause
4--
5-- Copyright(c) 2025 The FreeBSD Foundation.
6--
7-- This software was developed by Isaac Freund <ifreund@freebsdfoundation.org>
8-- under sponsorship from the FreeBSD Foundation.
9
10-- Run a command using the OS shell and capture the stdout
11-- Strips exactly one trailing newline if present, does not strip any other whitespace.
12-- Asserts that the command exits cleanly
13local function capture(command)
14	local p = io.popen(command)
15	local output = p:read("*a")
16	assert(p:close())
17	-- Strip exactly one trailing newline from the output, if there is one
18	return output:match("(.-)\n$") or output
19end
20
21local function append_list(list, other)
22	for _, item in ipairs(other) do
23		table.insert(list, item)
24	end
25end
26
27-- Returns a list of packages to be included in the given media
28local function select_packages(pkg, media, all_libcompats)
29	local components = {
30		kernel = {},
31		kernel_dbg = {},
32		base = {},
33		base_dbg = {},
34		src = {},
35		tests = {},
36	}
37
38	for compat in all_libcompats:gmatch("%S+") do
39		components["lib" .. compat] = {}
40		components["lib" .. compat .. "_dbg"] = {}
41	end
42
43	local rquery = capture(pkg .. "rquery -U -r FreeBSD-base %n")
44	for package in rquery:gmatch("[^\n]+") do
45		if package == "FreeBSD-src" or package:match("^FreeBSD%-src%-.*") then
46			table.insert(components["src"], package)
47		elseif package == "FreeBSD-tests" or package:match("^FreeBSD%-tests%-.*") then
48			table.insert(components["tests"], package)
49		elseif package:match("^FreeBSD%-kernel%-.*") and
50			package ~= "FreeBSD-kernel-man"
51		then
52			-- Kernels other than FreeBSD-kernel-generic are ignored
53			-- Note that on powerpc64 and powerpc64le the names are
54			-- slightly different.
55			if package:match("^FreeBSD%-kernel%-generic.*%-dbg") then
56				table.insert(components["kernel_dbg"], package)
57			elseif package:match("^FreeBSD%-kernel%-generic.*") then
58				table.insert(components["kernel"], package)
59			end
60		elseif package:match(".*%-dbg$") then
61			table.insert(components["base_dbg"], package)
62		else
63			local found = false
64			for compat in all_libcompats:gmatch("%S+") do
65				if package:match(".*%-dbg%-lib" .. compat .. "$") then
66					table.insert(components["lib" .. compat .. "_dbg"], package)
67					found = true
68					break
69				elseif package:match(".*%-lib" .. compat .. "$") then
70					table.insert(components["lib" .. compat], package)
71					found = true
72					break
73				end
74			end
75			if not found then
76				table.insert(components["base"], package)
77			end
78		end
79	end
80	assert(#components["kernel"] == 1)
81	assert(#components["base"] > 0)
82
83	local selected = {}
84	if media == "disc" then
85		append_list(selected, components["base"])
86		append_list(selected, components["kernel"])
87		append_list(selected, components["kernel_dbg"])
88		append_list(selected, components["src"])
89		append_list(selected, components["tests"])
90		for compat in all_libcompats:gmatch("%S+") do
91			append_list(selected, components["lib" .. compat])
92		end
93	else
94		assert(media == "dvd")
95		append_list(selected, components["base"])
96		append_list(selected, components["base_dbg"])
97		append_list(selected, components["kernel"])
98		append_list(selected, components["kernel_dbg"])
99		append_list(selected, components["src"])
100		append_list(selected, components["tests"])
101		for compat in all_libcompats:gmatch("%S+") do
102			append_list(selected, components["lib" .. compat])
103			append_list(selected, components["lib" .. compat .. "_dbg"])
104		end
105	end
106
107	return selected
108end
109
110local function main()
111	-- Determines package subset selected
112	local media = assert(arg[1])
113	assert(media == "disc" or media == "dvd")
114	-- Local repository to fetch from
115	local source = assert(arg[2])
116	-- Directory to create new repository
117	local target = assert(arg[3])
118	-- =hitespace separated list of all libcompat names (e.g. "32")
119	local all_libcompats = assert(arg[4])
120	-- ABI of repository
121	local ABI = assert(arg[5])
122
123	assert(os.execute("mkdir -p pkgbase-repo-conf"))
124	local f <close> = assert(io.open("pkgbase-repo-conf/FreeBSD-base.conf", "w"))
125	assert(f:write(string.format([[
126	FreeBSD-base: {
127	  url: "file://%s",
128	  enabled: yes
129	}
130	]], source)))
131	assert(f:close())
132
133	local pkg = "pkg -o ASSUME_ALWAYS_YES=yes -o IGNORE_OSVERSION=yes " ..
134	    "-o ABI=" .. ABI .. " " ..
135	    "-o INSTALL_AS_USER=1 -o PKG_DBDIR=./pkgdb -R ./pkgbase-repo-conf "
136
137	assert(os.execute(pkg .. "update"))
138
139	local packages = select_packages(pkg, media, all_libcompats)
140
141	assert(os.execute(pkg .. "fetch -o " .. target .. " " .. table.concat(packages, " ")))
142	assert(os.execute(pkg .. "repo " .. target))
143end
144
145main()
146