aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-03-12 23:14:12 +0900
committerOphestra <cat@gensokyo.uk>2026-03-13 10:31:14 +0900
commit0130f8ea6d88b451ac218f97b07d10eb11ee2f71 (patch)
tree6f2af99c25030c6b4ea3a116fc060bb47d115547 /internal
parentfaac5c4a839e81323760a9a6cd09407f769eef10 (diff)
internal/rosa: represent runtime dependencies
This also resolves indirect dependencies, reducing noise. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal')
-rw-r--r--internal/rosa/all.go34
-rw-r--r--internal/rosa/rosa.go49
2 files changed, 81 insertions, 2 deletions
diff --git a/internal/rosa/all.go b/internal/rosa/all.go
index d1116e88..49f0ada6 100644
--- a/internal/rosa/all.go
+++ b/internal/rosa/all.go
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"errors"
+ "fmt"
"net/http"
"strconv"
"sync"
@@ -167,6 +168,36 @@ const (
PresetEnd
)
+// P represents multiple [PArtifact] and is stable through JSON.
+type P []PArtifact
+
+// MarshalJSON represents [PArtifact] by their [Metadata.Name].
+func (s P) MarshalJSON() ([]byte, error) {
+ names := make([]string, len(s))
+ for i, p := range s {
+ names[i] = GetMetadata(p).Name
+ }
+ return json.Marshal(names)
+}
+
+// UnmarshalJSON resolves the value created by MarshalJSON back to [P].
+func (s *P) UnmarshalJSON(data []byte) error {
+ var names []string
+ if err := json.Unmarshal(data, &names); err != nil {
+ return err
+ }
+
+ *s = make(P, len(names))
+ for i, name := range names {
+ if p, ok := ResolveName(name); !ok {
+ return fmt.Errorf("unknown artifact %q", name)
+ } else {
+ (*s)[i] = p
+ }
+ }
+ return nil
+}
+
// Metadata is stage-agnostic information of a [PArtifact] not directly
// representable in the resulting [pkg.Artifact].
type Metadata struct {
@@ -179,6 +210,9 @@ type Metadata struct {
// Project home page.
Website string `json:"website,omitempty"`
+ // Runtime dependencies.
+ Dependencies P `json:"dependencies"`
+
// Project identifier on [Anitya].
//
// [Anitya]: https://release-monitoring.org/
diff --git a/internal/rosa/rosa.go b/internal/rosa/rosa.go
index fbdba172..060a23b4 100644
--- a/internal/rosa/rosa.go
+++ b/internal/rosa/rosa.go
@@ -8,6 +8,7 @@ import (
"slices"
"strconv"
"strings"
+ "sync"
"hakurei.app/container/fhs"
"hakurei.app/internal/pkg"
@@ -454,6 +455,48 @@ type PackageAttr struct {
Flag int
}
+// pa holds whether a [PArtifact] is present.
+type pa = [PresetEnd]bool
+
+// paPool holds addresses of pa.
+var paPool = sync.Pool{New: func() any { return new(pa) }}
+
+// paGet returns the address of a new pa.
+func paGet() *pa { return paPool.Get().(*pa) }
+
+// paPut returns a pa to paPool.
+func paPut(pv *pa) { *pv = pa{}; paPool.Put(pv) }
+
+// appendPreset recursively appends a [PArtifact] and its runtime dependencies.
+func (t Toolchain) appendPreset(
+ a []pkg.Artifact,
+ pv *pa, p PArtifact,
+) []pkg.Artifact {
+ if pv[p] {
+ return a
+ }
+ pv[p] = true
+
+ for _, d := range GetMetadata(p).Dependencies {
+ a = t.appendPreset(a, pv, d)
+ }
+ return append(a, t.Load(p))
+}
+
+// AppendPresets recursively appends multiple [PArtifact] and their runtime
+// dependencies.
+func (t Toolchain) AppendPresets(
+ a []pkg.Artifact,
+ presets ...PArtifact,
+) []pkg.Artifact {
+ pv := paGet()
+ for _, p := range presets {
+ a = t.appendPreset(a, pv, p)
+ }
+ paPut(pv)
+ return a
+}
+
// NewPackage constructs a [pkg.Artifact] via a build system helper.
func (t Toolchain) NewPackage(
name, version string,
@@ -486,12 +529,14 @@ func (t Toolchain) NewPackage(
extraRes := make([]pkg.Artifact, 0, dc)
extraRes = append(extraRes, attr.NonStage0...)
if !t.isStage0() {
+ pv := paGet()
for _, p := range helper.extra(attr.Flag) {
- extraRes = append(extraRes, t.Load(p))
+ extraRes = t.appendPreset(extraRes, pv, p)
}
for _, p := range extra {
- extraRes = append(extraRes, t.Load(p))
+ extraRes = t.appendPreset(extraRes, pv, p)
}
+ paPut(pv)
}
var scriptEarly string