diff --git a/internal/pkg/exec.go b/internal/pkg/exec.go index 3d3f0b6..0c43cff 100644 --- a/internal/pkg/exec.go +++ b/internal/pkg/exec.go @@ -105,6 +105,9 @@ type execArtifact struct { // equivalent to execTimeoutDefault. This value is never encoded in Params // because it cannot affect outcome. timeout time.Duration + + // Caller-supplied exclusivity value, returned as is by IsExclusive. + exclusive bool } var _ fmt.Stringer = new(execArtifact) @@ -123,7 +126,7 @@ var _ KnownChecksum = new(execNetArtifact) func (a *execNetArtifact) Checksum() Checksum { return a.checksum } // Kind returns the hardcoded [Kind] constant. -func (a *execNetArtifact) Kind() Kind { return KindExecNet } +func (*execNetArtifact) Kind() Kind { return KindExecNet } // Params is [Checksum] concatenated with [KindExec] params. func (a *execNetArtifact) Params(ctx *IContext) { @@ -157,13 +160,14 @@ func (a *execNetArtifact) Cure(f *FContext) error { // negative timeout value is equivalent tp [ExecTimeoutDefault], a timeout value // greater than [ExecTimeoutMax] is equivalent to [ExecTimeoutMax]. // -// The user-facing name is not accessible from the container and does not -// affect curing outcome. Because of this, it is omitted from parameter data -// for computing identifier. +// The user-facing name and exclusivity value are not accessible from the +// container and does not affect curing outcome. Because of this, it is omitted +// from parameter data for computing identifier. func NewExec( name string, checksum *Checksum, timeout time.Duration, + exclusive bool, dir *check.Absolute, env []string, @@ -181,7 +185,7 @@ func NewExec( if timeout > ExecTimeoutMax { timeout = ExecTimeoutMax } - a := execArtifact{name, paths, dir, env, pathname, args, timeout} + a := execArtifact{name, paths, dir, env, pathname, args, timeout, exclusive} if checksum == nil { return &a } @@ -189,7 +193,7 @@ func NewExec( } // Kind returns the hardcoded [Kind] constant. -func (a *execArtifact) Kind() Kind { return KindExec } +func (*execArtifact) Kind() Kind { return KindExec } // Params writes paths, executable pathname and args. func (a *execArtifact) Params(ctx *IContext) { @@ -237,6 +241,9 @@ func (a *execArtifact) Dependencies() []Artifact { return slices.Concat(artifacts...) } +// IsExclusive returns the caller-supplied exclusivity value. +func (a *execArtifact) IsExclusive() bool { return a.exclusive } + // String returns the caller-supplied reporting name. func (a *execArtifact) String() string { return a.name } diff --git a/internal/pkg/exec_test.go b/internal/pkg/exec_test.go index 862a28c..1c6f8e5 100644 --- a/internal/pkg/exec_test.go +++ b/internal/pkg/exec_test.go @@ -39,7 +39,7 @@ func TestExec(t *testing.T) { cureMany(t, c, []cureStep{ {"container", pkg.NewExec( - "exec-offline", nil, 0, + "exec-offline", nil, 0, false, pkg.AbsWork, []string{"HAKUREI_TEST=1"}, check.MustAbs("/opt/bin/testtool"), @@ -62,7 +62,7 @@ func TestExec(t *testing.T) { ), ignorePathname, wantChecksumOffline, nil}, {"error passthrough", pkg.NewExec( - "", nil, 0, + "", nil, 0, true, pkg.AbsWork, []string{"HAKUREI_TEST=1"}, check.MustAbs("/opt/bin/testtool"), @@ -85,7 +85,7 @@ func TestExec(t *testing.T) { }}, {"invalid paths", pkg.NewExec( - "", nil, 0, + "", nil, 0, false, pkg.AbsWork, []string{"HAKUREI_TEST=1"}, check.MustAbs("/opt/bin/testtool"), @@ -98,7 +98,7 @@ func TestExec(t *testing.T) { // check init failure passthrough var exitError *exec.ExitError if _, _, err := c.Cure(pkg.NewExec( - "", nil, 0, + "", nil, 0, false, pkg.AbsWork, nil, check.MustAbs("/opt/bin/testtool"), @@ -120,7 +120,7 @@ func TestExec(t *testing.T) { ) cureMany(t, c, []cureStep{ {"container", pkg.NewExec( - "exec-net", &wantChecksum, 0, + "exec-net", &wantChecksum, 0, false, pkg.AbsWork, []string{"HAKUREI_TEST=1"}, check.MustAbs("/opt/bin/testtool"), @@ -152,7 +152,7 @@ func TestExec(t *testing.T) { cureMany(t, c, []cureStep{ {"container", pkg.NewExec( - "exec-overlay-root", nil, 0, + "exec-overlay-root", nil, 0, false, pkg.AbsWork, []string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"}, check.MustAbs("/opt/bin/testtool"), @@ -178,7 +178,7 @@ func TestExec(t *testing.T) { cureMany(t, c, []cureStep{ {"container", pkg.NewExec( - "exec-overlay-work", nil, 0, + "exec-overlay-work", nil, 0, false, pkg.AbsWork, []string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"}, check.MustAbs("/work/bin/testtool"), @@ -209,7 +209,7 @@ func TestExec(t *testing.T) { cureMany(t, c, []cureStep{ {"container", pkg.NewExec( - "exec-multiple-layers", nil, 0, + "exec-multiple-layers", nil, 0, false, pkg.AbsWork, []string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"}, check.MustAbs("/opt/bin/testtool"), @@ -262,7 +262,7 @@ func TestExec(t *testing.T) { cureMany(t, c, []cureStep{ {"container", pkg.NewExec( - "exec-layer-promotion", nil, 0, + "exec-layer-promotion", nil, 0, true, pkg.AbsWork, []string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"}, check.MustAbs("/opt/bin/testtool"), diff --git a/internal/pkg/file.go b/internal/pkg/file.go index 9e075cd..c2093d6 100644 --- a/internal/pkg/file.go +++ b/internal/pkg/file.go @@ -37,13 +37,16 @@ func NewFile(name string, data []byte) FileArtifact { } // Kind returns the hardcoded [Kind] constant. -func (a *fileArtifact) Kind() Kind { return KindFile } +func (*fileArtifact) Kind() Kind { return KindFile } // Params writes the result of Cure. func (a *fileArtifact) Params(ctx *IContext) { ctx.GetHash().Write(*a) } // Dependencies returns a nil slice. -func (a *fileArtifact) Dependencies() []Artifact { return nil } +func (*fileArtifact) Dependencies() []Artifact { return nil } + +// IsExclusive returns false: Cure returns a prepopulated buffer. +func (*fileArtifact) IsExclusive() bool { return false } // Checksum computes and returns the checksum of caller-supplied data. func (a *fileArtifact) Checksum() Checksum { diff --git a/internal/pkg/net.go b/internal/pkg/net.go index 00c2bc6..7e35cd8 100644 --- a/internal/pkg/net.go +++ b/internal/pkg/net.go @@ -40,7 +40,7 @@ func NewHTTPGet( } // Kind returns the hardcoded [Kind] constant. -func (a *httpArtifact) Kind() Kind { return KindHTTPGet } +func (*httpArtifact) Kind() Kind { return KindHTTPGet } // Params writes the backing url string. Client is not represented as it does // not affect [Cache.Cure] outcome. @@ -49,7 +49,10 @@ func (a *httpArtifact) Params(ctx *IContext) { } // Dependencies returns a nil slice. -func (a *httpArtifact) Dependencies() []Artifact { return nil } +func (*httpArtifact) Dependencies() []Artifact { return nil } + +// IsExclusive returns false: Cure returns as soon as a response is received. +func (*httpArtifact) IsExclusive() bool { return false } // Checksum returns the caller-supplied checksum. func (a *httpArtifact) Checksum() Checksum { return a.checksum.Value() } diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go index b3b0851..15114fd 100644 --- a/internal/pkg/pkg.go +++ b/internal/pkg/pkg.go @@ -253,6 +253,24 @@ type Artifact interface { // // Result must remain identical across multiple invocations. Dependencies() []Artifact + + // IsExclusive returns whether the [Artifact] is exclusive. Exclusive + // artifacts might not run in parallel with each other, and are still + // subject to the cures limit. + // + // Some implementations may saturate the CPU for a nontrivial amount of + // time. Curing multiple such implementations simultaneously causes + // significant CPU scheduler overhead. An exclusive artifact will generally + // not be cured alongside another exclusive artifact, thus alleviating this + // overhead. + // + // Note that [Cache] reserves the right to still cure exclusive + // artifacts concurrently as this is not a synchronisation primitive but + // an optimisation one. Implementations are forbidden from accessing global + // state regardless of exclusivity. + // + // Result must remain identical across multiple invocations. + IsExclusive() bool } // FloodArtifact refers to an [Artifact] requiring its entire dependency graph @@ -472,6 +490,8 @@ type Cache struct { // Synchronises access to ident and corresponding filesystem entries. identMu sync.RWMutex + // Synchronises entry into exclusive artifacts for the cure method. + exclMu sync.Mutex // Buffered I/O free list, must not be accessed directly. bufioPool sync.Pool @@ -1215,7 +1235,10 @@ func (e *DependencyCureError) Error() string { } // enterCure must be called before entering an [Artifact] implementation. -func (c *Cache) enterCure(curesExempt bool) error { +func (c *Cache) enterCure(a Artifact, curesExempt bool) error { + if a.IsExclusive() { + c.exclMu.Lock() + } if curesExempt { return nil } @@ -1225,15 +1248,23 @@ func (c *Cache) enterCure(curesExempt bool) error { return nil case <-c.ctx.Done(): + if a.IsExclusive() { + c.exclMu.Unlock() + } return c.ctx.Err() } } // exitCure must be called after exiting an [Artifact] implementation. -func (c *Cache) exitCure(curesExempt bool) { - if !curesExempt { - <-c.cures +func (c *Cache) exitCure(a Artifact, curesExempt bool) { + if a.IsExclusive() { + c.exclMu.Unlock() } + if curesExempt { + return + } + + <-c.cures } // getWriter is like [bufio.NewWriter] but for bufioPool. @@ -1456,7 +1487,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) ( }() var r io.ReadCloser - if err = c.enterCure(curesExempt); err != nil { + if err = c.enterCure(a, curesExempt); err != nil { return } r, err = f.Cure(&RContext{c}) @@ -1505,7 +1536,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) ( err = closeErr } } - c.exitCure(curesExempt) + c.exitCure(a, curesExempt) if err != nil { return } @@ -1539,11 +1570,11 @@ func (c *Cache) cure(a Artifact, curesExempt bool) ( switch ca := a.(type) { case TrivialArtifact: defer t.destroy(&err) - if err = c.enterCure(curesExempt); err != nil { + if err = c.enterCure(a, curesExempt); err != nil { return } err = ca.Cure(&t) - c.exitCure(curesExempt) + c.exitCure(a, curesExempt) if err != nil { return } @@ -1573,11 +1604,11 @@ func (c *Cache) cure(a Artifact, curesExempt bool) ( } defer f.destroy(&err) - if err = c.enterCure(curesExempt); err != nil { + if err = c.enterCure(a, curesExempt); err != nil { return } err = ca.Cure(&f) - c.exitCure(curesExempt) + c.exitCure(a, curesExempt) if err != nil { return } diff --git a/internal/pkg/pkg_test.go b/internal/pkg/pkg_test.go index fe618a6..d791f10 100644 --- a/internal/pkg/pkg_test.go +++ b/internal/pkg/pkg_test.go @@ -96,12 +96,14 @@ func (a *stubArtifact) Kind() pkg.Kind { return a.kind } func (a *stubArtifact) Params(ctx *pkg.IContext) { ctx.GetHash().Write(a.params) } func (a *stubArtifact) Dependencies() []pkg.Artifact { return a.deps } func (a *stubArtifact) Cure(t *pkg.TContext) error { return a.cure(t) } +func (*stubArtifact) IsExclusive() bool { return false } // A stubArtifactF implements [FloodArtifact] with hardcoded behaviour. type stubArtifactF struct { kind pkg.Kind params []byte deps []pkg.Artifact + excl bool cure func(f *pkg.FContext) error } @@ -110,6 +112,7 @@ func (a *stubArtifactF) Kind() pkg.Kind { return a.kind } func (a *stubArtifactF) Params(ctx *pkg.IContext) { ctx.GetHash().Write(a.params) } func (a *stubArtifactF) Dependencies() []pkg.Artifact { return a.deps } func (a *stubArtifactF) Cure(f *pkg.FContext) error { return a.cure(f) } +func (a *stubArtifactF) IsExclusive() bool { return a.excl } // A stubFile implements [FileArtifact] with hardcoded behaviour. type stubFile struct { diff --git a/internal/pkg/tar.go b/internal/pkg/tar.go index c56176b..474df03 100644 --- a/internal/pkg/tar.go +++ b/internal/pkg/tar.go @@ -80,6 +80,9 @@ func (a *tarArtifact) Dependencies() []Artifact { return []Artifact{a.f} } +// IsExclusive returns false: decompressor and tar reader are fully sequential. +func (a *tarArtifact) IsExclusive() bool { return false } + // A DisallowedTypeflagError describes a disallowed typeflag encountered while // unpacking a tarball. type DisallowedTypeflagError byte diff --git a/internal/rosa/acl.go b/internal/rosa/acl.go index 7cd78af..945a53a 100644 --- a/internal/rosa/acl.go +++ b/internal/rosa/acl.go @@ -7,7 +7,7 @@ func (t Toolchain) newAttr() pkg.Artifact { version = "2.5.2" checksum = "YWEphrz6vg1sUMmHHVr1CRo53pFXRhq_pjN-AlG8UgwZK1y6m7zuDhxqJhD0SV0l" ) - return t.New("attr-"+version, []pkg.Artifact{ + return t.New("attr-"+version, false, []pkg.Artifact{ t.Load(Make), t.Load(Perl), }, nil, nil, ` @@ -75,7 +75,7 @@ func (t Toolchain) newACL() pkg.Artifact { version = "2.3.2" checksum = "-fY5nwH4K8ZHBCRXrzLdguPkqjKI6WIiGu4dBtrZ1o0t6AIU73w8wwJz_UyjIS0P" ) - return t.New("acl-"+version, []pkg.Artifact{ + return t.New("acl-"+version, false, []pkg.Artifact{ t.Load(Make), t.Load(Attr), diff --git a/internal/rosa/busybox.go b/internal/rosa/busybox.go index ba5e2d9..df4bfd4 100644 --- a/internal/rosa/busybox.go +++ b/internal/rosa/busybox.go @@ -25,6 +25,9 @@ func (a busyboxBin) Kind() pkg.Kind { return kindBusyboxBin } // Params is a noop. func (a busyboxBin) Params(*pkg.IContext) {} +// IsExclusive returns false: Cure performs a trivial filesystem write. +func (busyboxBin) IsExclusive() bool { return false } + // Dependencies returns the underlying busybox [pkg.File]. func (a busyboxBin) Dependencies() []pkg.Artifact { return []pkg.Artifact{a.bin} @@ -80,7 +83,8 @@ func newBusyboxBin() pkg.Artifact { checksum = "L7OBIsPu9enNHn7FqpBT1kOg_mCLNmetSeNMA3i4Y60Z5jTgnlX3qX3zcQtLx5AB" ) return pkg.NewExec( - "busybox-bin-"+version, nil, pkg.ExecTimeoutMax, fhs.AbsRoot, []string{ + "busybox-bin-"+version, nil, pkg.ExecTimeoutMax, false, + fhs.AbsRoot, []string{ "PATH=/system/bin", }, AbsSystem.Append("bin", "busybox"), @@ -111,7 +115,7 @@ func (t Toolchain) newBusybox() pkg.Artifact { env = append(env, "EXTRA_LDFLAGS=-static") } - return t.New("busybox-"+version, stage3Concat(t, []pkg.Artifact{}, + return t.New("busybox-"+version, false, stage3Concat(t, []pkg.Artifact{}, t.Load(Make), t.Load(KernelHeaders), ), nil, slices.Concat([]string{ diff --git a/internal/rosa/cmake.go b/internal/rosa/cmake.go index 4f2e6d2..1412160 100644 --- a/internal/rosa/cmake.go +++ b/internal/rosa/cmake.go @@ -13,7 +13,7 @@ func (t Toolchain) newCMake() pkg.Artifact { version = "4.2.1" checksum = "Y3OdbMsob6Xk2y1DCME6z4Fryb5_TkFD7knRT8dTNIRtSqbiCJyyDN9AxggN_I75" ) - return t.New("cmake-"+version, []pkg.Artifact{ + return t.New("cmake-"+version, false, []pkg.Artifact{ t.Load(Make), t.Load(KernelHeaders), }, nil, nil, ` @@ -59,6 +59,9 @@ type CMakeAttr struct { // Override the default installation prefix [AbsSystem]. Prefix *check.Absolute + + // Return an exclusive artifact. + Exclusive bool } // NewViaCMake returns a [pkg.Artifact] for compiling and installing via CMake. @@ -94,7 +97,7 @@ chmod -R +w "${ROSA_SOURCE}" } sourcePath := AbsUsrSrc.Append(name) - return t.New(name+"-"+variant+"-"+version, stage3Concat(t, attr.Extra, + return t.New(name+"-"+variant+"-"+version, attr.Exclusive, stage3Concat(t, attr.Extra, t.Load(CMake), t.Load(Ninja), ), nil, slices.Concat([]string{ diff --git a/internal/rosa/etc.go b/internal/rosa/etc.go index 2281a0d..1168729 100644 --- a/internal/rosa/etc.go +++ b/internal/rosa/etc.go @@ -89,6 +89,9 @@ func (cureEtc) Kind() pkg.Kind { return kindEtc } // Params is a noop. func (cureEtc) Params(*pkg.IContext) {} +// IsExclusive returns false: Cure performs a few trivial filesystem writes. +func (cureEtc) IsExclusive() bool { return false } + // Dependencies returns a slice containing the backing iana-etc release. func (a cureEtc) Dependencies() []pkg.Artifact { if a.iana != nil { diff --git a/internal/rosa/git.go b/internal/rosa/git.go index 4508d3b..ec1c3e4 100644 --- a/internal/rosa/git.go +++ b/internal/rosa/git.go @@ -9,7 +9,7 @@ func (t Toolchain) newGit() pkg.Artifact { version = "2.52.0" checksum = "uH3J1HAN_c6PfGNJd2OBwW4zo36n71wmkdvityYnrh8Ak0D1IifiAvEWz9Vi9DmS" ) - return t.New("git-"+version, stage3Concat(t, []pkg.Artifact{}, + return t.New("git-"+version, false, stage3Concat(t, []pkg.Artifact{}, t.Load(Make), t.Load(Perl), t.Load(M4), diff --git a/internal/rosa/gnu.go b/internal/rosa/gnu.go index 0da7ea8..e3fe7ae 100644 --- a/internal/rosa/gnu.go +++ b/internal/rosa/gnu.go @@ -7,7 +7,7 @@ func (t Toolchain) newMake() pkg.Artifact { version = "4.4.1" checksum = "YS_B07ZcAy9PbaK5_vKGj64SrxO2VMpnMKfc9I0Q9IC1rn0RwOH7802pJoj2Mq4a" ) - return t.New("make-"+version, nil, nil, nil, ` + return t.New("make-"+version, false, nil, nil, nil, ` cd "$(mktemp -d)" /usr/src/make/configure \ --prefix=/system \ @@ -29,7 +29,7 @@ func (t Toolchain) newM4() pkg.Artifact { version = "1.4.20" checksum = "RT0_L3m4Co86bVBY3lCFAEs040yI1WdeNmRylFpah8IZovTm6O4wI7qiHJN3qsW9" ) - return t.New("m4-"+version, []pkg.Artifact{ + return t.New("m4-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` cd /usr/src/m4 @@ -55,7 +55,7 @@ func (t Toolchain) newAutoconf() pkg.Artifact { version = "2.72" checksum = "-c5blYkC-xLDer3TWEqJTyh1RLbOd1c5dnRLKsDnIrg_wWNOLBpaqMY8FvmUFJ33" ) - return t.New("autoconf-"+version, []pkg.Artifact{ + return t.New("autoconf-"+version, false, []pkg.Artifact{ t.Load(Make), t.Load(M4), t.Load(Perl), @@ -83,7 +83,7 @@ func (t Toolchain) newGettext() pkg.Artifact { version = "0.26" checksum = "IMu7yDZX7xL5UO1ZxXc-iBMbY9LLEUlOroyuSlHMZwg9MKtxG7HIm8F2LheDua0y" ) - return t.New("gettext-"+version, []pkg.Artifact{ + return t.New("gettext-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` cd /usr/src/gettext @@ -119,7 +119,7 @@ func (t Toolchain) newDiffutils() pkg.Artifact { version = "3.12" checksum = "9J5VAq5oA7eqwzS1Yvw-l3G5o-TccUrNQR3PvyB_lgdryOFAfxtvQfKfhdpquE44" ) - return t.New("diffutils-"+version, []pkg.Artifact{ + return t.New("diffutils-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` cd /usr/src/diffutils @@ -148,7 +148,7 @@ func (t Toolchain) newPatch() pkg.Artifact { version = "2.8" checksum = "MA0BQc662i8QYBD-DdGgyyfTwaeALZ1K0yusV9rAmNiIsQdX-69YC4t9JEGXZkeR" ) - return t.New("patch-"+version, []pkg.Artifact{ + return t.New("patch-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` cd /usr/src/patch @@ -177,7 +177,7 @@ func (t Toolchain) newBash() pkg.Artifact { version = "5.3" checksum = "4LQ_GRoB_ko-Ih8QPf_xRKA02xAm_TOxQgcJLmFDT6udUPxTAWrsj-ZNeuTusyDq" ) - return t.New("bash-"+version, []pkg.Artifact{ + return t.New("bash-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` cd "$(mktemp -d)" @@ -201,7 +201,7 @@ func (t Toolchain) newCoreutils() pkg.Artifact { version = "9.9" checksum = "B1_TaXj1j5aiVIcazLWu8Ix03wDV54uo2_iBry4qHG6Y-9bjDpUPlkNLmU_3Nvw6" ) - return t.New("coreutils-"+version, []pkg.Artifact{ + return t.New("coreutils-"+version, false, []pkg.Artifact{ t.Load(Make), t.Load(Perl), @@ -232,7 +232,7 @@ func (t Toolchain) newGperf() pkg.Artifact { version = "3.3" checksum = "RtIy9pPb_Bb8-31J2Nw-rRGso2JlS-lDlVhuNYhqR7Nt4xM_nObznxAlBMnarJv7" ) - return t.New("gperf-"+version, []pkg.Artifact{ + return t.New("gperf-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` cd "$(mktemp -d)" diff --git a/internal/rosa/go.go b/internal/rosa/go.go index 6998710..9b315ad 100644 --- a/internal/rosa/go.go +++ b/internal/rosa/go.go @@ -10,7 +10,7 @@ import ( // newGoBootstrap returns the Go bootstrap toolchain. func (t Toolchain) newGoBootstrap() pkg.Artifact { const checksum = "8o9JL_ToiQKadCTb04nvBDkp8O1xiWOolAxVEqaTGodieNe4lOFEjlOxN3bwwe23" - return t.New("go1.4-bootstrap", []pkg.Artifact{ + return t.New("go1.4-bootstrap", false, []pkg.Artifact{ t.Load(Bash), }, nil, []string{ "CGO_ENABLED=0", @@ -50,7 +50,7 @@ func (t Toolchain) newGo( script string, extra ...pkg.Artifact, ) pkg.Artifact { - return t.New("go"+version, slices.Concat([]pkg.Artifact{ + return t.New("go"+version, false, slices.Concat([]pkg.Artifact{ t.Load(Bash), }, extra), nil, slices.Concat([]string{ "CC=cc", diff --git a/internal/rosa/kernel.go b/internal/rosa/kernel.go index 96e3bff..a963982 100644 --- a/internal/rosa/kernel.go +++ b/internal/rosa/kernel.go @@ -8,6 +8,7 @@ import ( // newKernel is a helper for interacting with Kbuild. func (t Toolchain) newKernel( + exclusive bool, patches [][2]string, script string, extra ...pkg.Artifact, @@ -16,7 +17,7 @@ func (t Toolchain) newKernel( version = "6.18.5" checksum = "-V1e1WWl7HuePkmm84sSKF7nLuHfUs494uNMzMqXEyxcNE_PUE0FICL0oGWn44mM" ) - return t.New("kernel-"+version, slices.Concat([]pkg.Artifact{ + return t.New("kernel-"+version, exclusive, slices.Concat([]pkg.Artifact{ t.Load(Make), }, extra), nil, nil, ` export LLVM=1 @@ -34,7 +35,7 @@ cd /usr/src/linux } func (t Toolchain) newKernelHeaders() pkg.Artifact { - return t.newKernel(nil, ` + return t.newKernel(false, nil, ` make "-j$(nproc)" \ INSTALL_HDR_PATH=/work/system \ headers_install diff --git a/internal/rosa/libexpat.go b/internal/rosa/libexpat.go index 2d7ff5b..ea6b227 100644 --- a/internal/rosa/libexpat.go +++ b/internal/rosa/libexpat.go @@ -11,7 +11,7 @@ func (t Toolchain) newLibexpat() pkg.Artifact { version = "2.7.3" checksum = "GmkoD23nRi9cMT0cgG1XRMrZWD82UcOMzkkvP1gkwSFWCBgeSXMuoLpa8-v8kxW-" ) - return t.New("libexpat-"+version, []pkg.Artifact{ + return t.New("libexpat-"+version, false, []pkg.Artifact{ t.Load(Make), t.Load(Bash), }, nil, nil, ` diff --git a/internal/rosa/libffi.go b/internal/rosa/libffi.go index 745bbef..1e18a37 100644 --- a/internal/rosa/libffi.go +++ b/internal/rosa/libffi.go @@ -7,7 +7,7 @@ func (t Toolchain) newLibffi() pkg.Artifact { version = "3.4.5" checksum = "apIJzypF4rDudeRoI_n3K7N-zCeBLTbQlHRn9NSAZqdLAWA80mR0gXPTpHsL7oMl" ) - return t.New("libffi-"+version, []pkg.Artifact{ + return t.New("libffi-"+version, false, []pkg.Artifact{ t.Load(Make), t.Load(KernelHeaders), }, nil, nil, ` diff --git a/internal/rosa/libgd.go b/internal/rosa/libgd.go index 330159a..0ab414c 100644 --- a/internal/rosa/libgd.go +++ b/internal/rosa/libgd.go @@ -7,7 +7,7 @@ func (t Toolchain) newLibgd() pkg.Artifact { version = "2.3.3" checksum = "8T-sh1_FJT9K9aajgxzh8ot6vWIF-xxjcKAHvTak9MgGUcsFfzP8cAvvv44u2r36" ) - return t.New("libgd-"+version, []pkg.Artifact{ + return t.New("libgd-"+version, false, []pkg.Artifact{ t.Load(Make), t.Load(Zlib), diff --git a/internal/rosa/libseccomp.go b/internal/rosa/libseccomp.go index f42480c..aae5626 100644 --- a/internal/rosa/libseccomp.go +++ b/internal/rosa/libseccomp.go @@ -9,7 +9,7 @@ func (t Toolchain) newLibseccomp() pkg.Artifact { version = "2.6.0" checksum = "mMu-iR71guPjFbb31u-YexBaanKE_nYPjPux-vuBiPfS_0kbwJdfCGlkofaUm-EY" ) - return t.New("libseccomp-"+version, []pkg.Artifact{ + return t.New("libseccomp-"+version, false, []pkg.Artifact{ t.Load(Make), t.Load(Bash), t.Load(Gperf), diff --git a/internal/rosa/libxml2.go b/internal/rosa/libxml2.go index 02993e4..e373ad9 100644 --- a/internal/rosa/libxml2.go +++ b/internal/rosa/libxml2.go @@ -11,7 +11,7 @@ func (t Toolchain) newLibxml2() pkg.Artifact { version = "2.15.1" checksum = "pYzAR3cNrEHezhEMirgiq7jbboLzwMj5GD7SQp0jhSIMdgoU4G9oU9Gxun3zzUIU" ) - return t.New("libxml2-"+version, []pkg.Artifact{ + return t.New("libxml2-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` cd /usr/src/ diff --git a/internal/rosa/llvm.go b/internal/rosa/llvm.go index 59d8046..bfd75b2 100644 --- a/internal/rosa/llvm.go +++ b/internal/rosa/llvm.go @@ -197,6 +197,8 @@ cp -r /system/include /usr/include && rm -rf /system/include "ROSA_LLVM_RUNTIMES=" + strings.Join(runtimes, ";"), }, attr.env), ScriptEarly: scriptEarly, Script: script + attr.script, + + Exclusive: true, }) } diff --git a/internal/rosa/meson.go b/internal/rosa/meson.go index 05960df..400ce04 100644 --- a/internal/rosa/meson.go +++ b/internal/rosa/meson.go @@ -7,7 +7,7 @@ func (t Toolchain) newMeson() pkg.Artifact { version = "1.10.1" checksum = "w895BXF_icncnXatT_OLCFe2PYEtg4KrKooMgUYdN-nQVvbFX3PvYWHGEpogsHtd" ) - return t.New("meson-"+version, []pkg.Artifact{ + return t.New("meson-"+version, false, []pkg.Artifact{ t.Load(Python), t.Load(Setuptools), }, nil, nil, ` diff --git a/internal/rosa/musl.go b/internal/rosa/musl.go index acb052b..bc4be30 100644 --- a/internal/rosa/musl.go +++ b/internal/rosa/musl.go @@ -42,7 +42,7 @@ rmdir -v /work/lib script = "" } - return t.New("musl-"+version, stage3Concat(t, attr.Extra, + return t.New("musl-"+version, false, stage3Concat(t, attr.Extra, t.Load(Make), ), nil, slices.Concat([]string{ "ROSA_MUSL_TARGET=" + target, diff --git a/internal/rosa/ninja.go b/internal/rosa/ninja.go index 42496e1..27047a5 100644 --- a/internal/rosa/ninja.go +++ b/internal/rosa/ninja.go @@ -7,7 +7,7 @@ func (t Toolchain) newNinja() pkg.Artifact { version = "1.13.2" checksum = "ygKWMa0YV2lWKiFro5hnL-vcKbc_-RACZuPu0Io8qDvgQlZ0dxv7hPNSFkt4214v" ) - return t.New("ninja-"+version, []pkg.Artifact{ + return t.New("ninja-"+version, false, []pkg.Artifact{ t.Load(CMake), t.Load(Python), }, nil, nil, ` diff --git a/internal/rosa/perl.go b/internal/rosa/perl.go index 77e9d67..5675604 100644 --- a/internal/rosa/perl.go +++ b/internal/rosa/perl.go @@ -7,7 +7,7 @@ func (t Toolchain) newPerl() pkg.Artifact { version = "5.42.0" checksum = "2KR7Jbpk-ZVn1a30LQRwbgUvg2AXlPQZfzrqCr31qD5-yEsTwVQ_W76eZH-EdxM9" ) - return t.New("perl-"+version, []pkg.Artifact{ + return t.New("perl-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` chmod -R +w /usr/src/perl && cd /usr/src/perl diff --git a/internal/rosa/pkg-config.go b/internal/rosa/pkg-config.go index d6ae9c8..0a61ce4 100644 --- a/internal/rosa/pkg-config.go +++ b/internal/rosa/pkg-config.go @@ -7,7 +7,7 @@ func (t Toolchain) newPkgConfig() pkg.Artifact { version = "0.29.2" checksum = "gi7yAvkwo20Inys1tHbeYZ3Wjdm5VPkrnO0Q6_QZPCAwa1zrA8F4a63cdZDd-717" ) - return t.New("pkg-config-"+version, []pkg.Artifact{ + return t.New("pkg-config-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` cd "$(mktemp -d)" diff --git a/internal/rosa/python.go b/internal/rosa/python.go index db56b49..4be17f6 100644 --- a/internal/rosa/python.go +++ b/internal/rosa/python.go @@ -32,7 +32,7 @@ func (t Toolchain) newPython() pkg.Artifact { // breaks on llvm "test_dbm_gnu", } - return t.New("python-"+version, []pkg.Artifact{ + return t.New("python-"+version, false, []pkg.Artifact{ t.Load(Make), t.Load(Zlib), t.Load(Libffi), @@ -69,7 +69,7 @@ func (t Toolchain) newSetuptools() pkg.Artifact { version = "80.10.1" checksum = "p3rlwEmy1krcUH1KabprQz1TCYjJ8ZUjOQknQsWh3q-XEqLGEd3P4VrCc7ouHGXU" ) - return t.New("setuptools-"+version, []pkg.Artifact{ + return t.New("setuptools-"+version, false, []pkg.Artifact{ t.Load(Python), }, nil, nil, ` pip3 install \ diff --git a/internal/rosa/rosa.go b/internal/rosa/rosa.go index df1ed9f..6b092fd 100644 --- a/internal/rosa/rosa.go +++ b/internal/rosa/rosa.go @@ -176,6 +176,7 @@ var absCureScript = fhs.AbsUsrBin.Append(".cure-script") // New returns a [pkg.Artifact] compiled on this toolchain. func (t Toolchain) New( name string, + exclusive bool, extra []pkg.Artifact, checksum *pkg.Checksum, env []string, @@ -206,7 +207,7 @@ func (t Toolchain) New( args[0] = "bash" support = slices.Concat([]pkg.Artifact{ cureEtc{}, - toolchainBusybox.New("stage3-"+version, nil, nil, nil, ` + toolchainBusybox.New("stage3-"+version, false, nil, nil, nil, ` tar -C /work -xf /usr/src/stage3.tar.xz rm -rf /work/dev/ /work/proc/ ln -vs ../usr/bin /work/bin @@ -258,7 +259,7 @@ ln -vs ../usr/bin /work/bin } return pkg.NewExec( - name, checksum, pkg.ExecTimeoutMax, + name, checksum, pkg.ExecTimeoutMax, exclusive, fhs.AbsRoot, env, path, args, @@ -307,7 +308,7 @@ cat /usr/src/` + name + `-patches/* | \ ` aname += "-patched" } - return t.New(aname, stage3Concat(t, []pkg.Artifact{}, + return t.New(aname, false, stage3Concat(t, []pkg.Artifact{}, t.Load(Patch), ), nil, nil, script, paths...) } diff --git a/internal/rosa/rsync.go b/internal/rosa/rsync.go index c43244b..8ce704e 100644 --- a/internal/rosa/rsync.go +++ b/internal/rosa/rsync.go @@ -7,7 +7,7 @@ func (t Toolchain) newRsync() pkg.Artifact { version = "3.4.1" checksum = "VBlTsBWd9z3r2-ex7GkWeWxkUc5OrlgDzikAC0pK7ufTjAJ0MbmC_N04oSVTGPiv" ) - return t.New("rsync-"+version, []pkg.Artifact{ + return t.New("rsync-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` cd "$(mktemp -d)" diff --git a/internal/rosa/wayland.go b/internal/rosa/wayland.go index e3e711b..4b1ec92 100644 --- a/internal/rosa/wayland.go +++ b/internal/rosa/wayland.go @@ -7,7 +7,7 @@ func (t Toolchain) newWayland() pkg.Artifact { version = "1.24.0" checksum = "JxgLiFRRGw2D3uhVw8ZeDbs3V7K_d4z_ypDog2LBqiA_5y2vVbUAk5NT6D5ozm0m" ) - return t.New("wayland-"+version, []pkg.Artifact{ + return t.New("wayland-"+version, false, []pkg.Artifact{ t.Load(Python), t.Load(Meson), t.Load(PkgConfig), @@ -50,7 +50,7 @@ func (t Toolchain) newWaylandProtocols() pkg.Artifact { version = "1.47" checksum = "B_NodZ7AQfCstcx7kgbaVjpkYOzbAQq0a4NOk-SA8bQixAE20FY3p1-6gsbPgHn9" ) - return t.New("wayland-protocols-"+version, []pkg.Artifact{ + return t.New("wayland-protocols-"+version, false, []pkg.Artifact{ t.Load(Python), t.Load(Meson), t.Load(PkgConfig), diff --git a/internal/rosa/zlib.go b/internal/rosa/zlib.go index 8d77a48..5232bc3 100644 --- a/internal/rosa/zlib.go +++ b/internal/rosa/zlib.go @@ -7,7 +7,7 @@ func (t Toolchain) newZlib() pkg.Artifact { version = "1.3.1" checksum = "E-eIpNzE8oJ5DsqH4UuA_0GDKuQF5csqI8ooDx2w7Vx-woJ2mb-YtSbEyIMN44mH" ) - return t.New("zlib-"+version, []pkg.Artifact{ + return t.New("zlib-"+version, false, []pkg.Artifact{ t.Load(Make), }, nil, nil, ` cd "$(mktemp -d)"