internal/rosa: general helper abstraction
All checks were successful
Test / Create distribution (push) Successful in 1m30s
Test / Sandbox (push) Successful in 3m33s
Test / Hakurei (push) Successful in 4m41s
Test / ShareFS (push) Successful in 4m46s
Test / Hpkg (push) Successful in 5m21s
Test / Sandbox (race detector) (push) Successful in 5m40s
Test / Hakurei (race detector) (push) Successful in 7m9s
Test / Flake checks (push) Successful in 1m43s

This greatly increases code sharing and makes implementations far simpler.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-03-01 22:58:39 +09:00
parent 51d3df2419
commit 2baa9df133

View File

@@ -392,3 +392,154 @@ cat /usr/src/` + name + `-patches/* | \
t.Load(Patch),
), nil, nil, script, paths...)
}
// helperInPlace is a special directory value for omitting the cd statement.
const helperInPlace = "\x00"
// Helper is a build system helper for [Toolchain.NewPackage].
type Helper interface {
// name returns the value passed to the name argument of [Toolchain.New].
name(name, version string) string
// extra returns helper-specific dependencies.
extra(flag int) []PArtifact
// wantsChmod returns whether the source directory should be made writable.
wantsChmod() bool
// wantsWrite returns whether the source directory should be mounted writable.
wantsWrite() bool
// scriptEarly returns the helper-specific segment of cure script that goes
// before the cd statement.
scriptEarly() string
// createDir returns whether the path returned by wantsDir should be created.
createDir() bool
// wantsDir returns the directory to enter before script.
//
// The zero value implies source directory if [PackageAttr.ScriptEarly] is
// also empty. The special value helperInPlace omits the cd statement.
wantsDir() string
// script returns the helper-specific segment of cure script.
script(name string) string
}
const (
// sourceTarXZ denotes a source tarball to be decompressed using [XZ].
sourceTarXZ = 1 + iota
)
// PackageAttr holds build-system-agnostic attributes.
type PackageAttr struct {
// Mount the source tree writable.
Writable bool
// Do not pass through [Toolchain.NewPatchedSource].
Chmod bool
// Unconditionally enter source directory early.
EnterSource bool
// Additional environment variables.
Env []string
// Runs before script emitted by [Helper]. Enters source if non-empty.
ScriptEarly string
// Passed to [Toolchain.NewPatchedSource].
Patches [][2]string
// Kind of source artifact.
SourceKind int
// Dependencies not provided by stage0.
NonStage0 []pkg.Artifact
// Passed through to [Toolchain.New], before source.
Paths []pkg.ExecPath
// Passed through to [Toolchain.New].
Flag int
}
// NewPackage constructs a [pkg.Artifact] via a build system helper.
func (t Toolchain) NewPackage(
name, version string,
source pkg.Artifact,
attr *PackageAttr,
helper Helper,
extra ...PArtifact,
) pkg.Artifact {
if attr == nil {
attr = new(PackageAttr)
}
if name == "" || version == "" {
panic("name must be non-empty")
}
if source == nil {
panic("source must be non-nil")
}
wantsChmod, wantsWrite := helper.wantsChmod(), helper.wantsWrite()
if attr.SourceKind > 0 &&
(attr.Writable || attr.Chmod || wantsChmod || wantsWrite || len(attr.Patches) > 0) {
panic("source processing requested on a non-unpacked kind")
}
dc := len(attr.NonStage0)
if !t.isStage0() {
dc += 1<<3 + len(extra)
}
extraRes := make([]pkg.Artifact, 0, dc)
extraRes = append(extraRes, attr.NonStage0...)
if !t.isStage0() {
for _, p := range helper.extra(attr.Flag) {
extraRes = append(extraRes, t.Load(p))
}
for _, p := range extra {
extraRes = append(extraRes, t.Load(p))
}
}
var scriptEarly string
var sourceSuffix string
switch attr.SourceKind {
case sourceTarXZ:
sourceSuffix = ".tar.xz"
scriptEarly += `
tar -C /usr/src/ -xf '/usr/src/` + name + `.tar.xz'
mv '/usr/src/` + name + `-` + version + `' '/usr/src/` + name + `'
`
break
}
dir := helper.wantsDir()
helperScriptEarly := helper.scriptEarly()
if attr.EnterSource ||
dir == "" ||
attr.ScriptEarly != "" ||
helperScriptEarly != "" {
scriptEarly += `
cd '/usr/src/` + name + `/'
`
}
scriptEarly += attr.ScriptEarly + helperScriptEarly
if dir != "" && dir != helperInPlace {
if helper.createDir() {
scriptEarly += "\nmkdir -p " + dir
}
scriptEarly += "\ncd " + dir + "\n"
} else if !attr.EnterSource && attr.ScriptEarly == "" {
panic("cannot remain in root")
}
return t.New(
helper.name(name, version),
attr.Flag,
extraRes,
nil,
attr.Env,
scriptEarly+helper.script(name),
slices.Concat(attr.Paths, []pkg.ExecPath{
pkg.Path(AbsUsrSrc.Append(
name+sourceSuffix,
), attr.Writable || wantsWrite, t.NewPatchedSource(
name, version, source, !attr.Chmod && !wantsChmod, attr.Patches...,
)),
})...,
)
}