diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-05-19 00:03:42 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-05-19 00:44:24 +0900 |
| commit | 8807cbc7305e424725b2be8eed7ecd9234f7772e (patch) | |
| tree | 5998f055396505becf0f99fcba3c86514f00650b /internal/rosa/state.go | |
| parent | 0e95573f187f64de1a46f27af67325e57037b9a9 (diff) | |
internal/rosa: create metadata alongside artifact
This enables deferring evaluation of azalea-based packages and fixes the longstanding quirk of version being disjoint from other metadata.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/rosa/state.go')
| -rw-r--r-- | internal/rosa/state.go | 117 |
1 files changed, 67 insertions, 50 deletions
diff --git a/internal/rosa/state.go b/internal/rosa/state.go index efb51d96..c2f0650b 100644 --- a/internal/rosa/state.go +++ b/internal/rosa/state.go @@ -70,11 +70,9 @@ type ( // P represents multiple [ArtifactH]. type P []ArtifactH -// Artifact is stage-agnostic immutable data with a deterministic resulting -// [pkg.Artifact]. It can be created natively or through evaluation. -type Artifact struct { - f func(t Toolchain) (a pkg.Artifact, version string) - +// Metadata is stage-agnostic immutable data around [Artifact] not directly +// representable in the resulting [pkg.Artifact]. +type Metadata struct { // Unique package name. Name string `json:"name"` // Short user-facing description. @@ -85,6 +83,8 @@ type Artifact struct { // Runtime dependencies. Dependencies P `json:"dependencies"` + // Package version. + Version string `json:"version"` // Project identifier on [Anitya]. // // [Anitya]: https://release-monitoring.org/ @@ -98,7 +98,7 @@ type Artifact struct { } // GetLatest returns the latest version described by v. -func (meta *Artifact) GetLatest(v *Versions) string { +func (meta *Metadata) GetLatest(v *Versions) string { if meta.latest != nil { return meta.latest(v) } @@ -134,7 +134,7 @@ func (v *Versions) getStable() string { } // GetVersions returns versions fetched from Anitya. -func (meta *Artifact) GetVersions(ctx context.Context) (*Versions, error) { +func (meta *Metadata) GetVersions(ctx context.Context) (*Versions, error) { if meta.ID == 0 { return nil, UnpopulatedIDError{} } @@ -160,10 +160,13 @@ func (meta *Artifact) GetVersions(ctx context.Context) (*Versions, error) { return &v, errors.Join(err, resp.Body.Close()) } -// A cachedArtifact holds [pkg.Artifact] and its corresponding version string. +// Artifact is a lazily initialised [pkg.Artifact] with associated [Metadata]. +type Artifact func(t Toolchain) (meta *Metadata, a pkg.Artifact) + +// A cachedArtifact caches satisfied [Artifact]. type cachedArtifact struct { - a pkg.Artifact - v string + meta *Metadata + a pkg.Artifact } const ( @@ -242,20 +245,20 @@ func (s *S) DropCaches(targetArch string, flags int) { } } -// Get returns the address of the named [Artifact]. -func (s *S) Get(handle ArtifactH) (meta *Artifact) { +// get returns the named [Artifact]. +func (s *S) get(handle ArtifactH) (f Artifact) { s.wantsArch() v, ok := s.artifacts.Load(handle) if ok { - meta = v.(*Artifact) + f = v.(Artifact) } return } -// MustGet is like Get, but panics if the named [Artifact] is not registered. -func (s *S) MustGet(handle ArtifactH) (meta *Artifact) { - meta = s.Get(handle) - if meta == nil { +// mustGet is like get, but panics if the named [Artifact] is not registered. +func (s *S) mustGet(handle ArtifactH) (f Artifact) { + f = s.get(handle) + if f == nil { panic(HandleError(handle)) } return @@ -282,8 +285,8 @@ func (e LoadError) Error() string { return "cannot load " + strconv.Quote(e.Handle.String()) + ": " + e.Err.Error() } -// Load returns the resulting [pkg.Artifact] of [ArtifactH]. -func (t Toolchain) Load(handle ArtifactH) (pkg.Artifact, string) { +// Load satisfies an [Artifact] referred to by an [ArtifactH]. +func (t Toolchain) Load(handle ArtifactH) (*Metadata, pkg.Artifact) { defer func() { r := recover() if r == nil { @@ -305,36 +308,36 @@ func (t Toolchain) Load(handle ArtifactH) (pkg.Artifact, string) { e, ok := t.c[t.stage].Load(handle) if ok { r := e.(cachedArtifact) - return r.a, r.v + return r.meta, r.a } - meta := t.Get(handle) - if meta == nil { - return nil, "" + f := t.get(handle) + if f == nil { + return nil, nil } var r cachedArtifact - r.a, r.v = meta.f(t) + r.meta, r.a = f(t) t.c[t.stage].Store(handle, r) - return r.a, r.v + return r.meta, r.a } // MustLoad is like Load, but panics if the named [Artifact] is not registered. -func (t Toolchain) MustLoad(handle ArtifactH) (pkg.Artifact, string) { - a, version := t.Load(handle) - if a == nil { +func (t Toolchain) MustLoad(handle ArtifactH) (*Metadata, pkg.Artifact) { + meta, a := t.Load(handle) + if meta == nil { panic(HandleError(handle)) } - return a, version + return meta, a } // Register arranges for a new [Artifact] to be cured under s. It returns false // if another [Artifact] is already registered under the same name. -func (s *S) Register(meta *Artifact) bool { - if meta.Name == "" { +func (s *S) Register(name string, f Artifact) bool { + if name == "" { return false } - p := ArtifactH(unique.Make(meta.Name)) - _, ok := s.artifacts.LoadOrStore(p, meta) + p := ArtifactH(unique.Make(name)) + _, ok := s.artifacts.LoadOrStore(p, f) if !ok { s.artifactCount.Add(1) } @@ -346,16 +349,34 @@ func (s *S) Register(meta *Artifact) bool { type RegisterError ArtifactH func (e RegisterError) Error() string { + if ArtifactH(e).String() == "" { + return "attempting to register invalid name" + } return "attempting to register " + strconv.Quote(ArtifactH(e).String()) + " twice" } // MustRegister is like Register, but panics if registration fails. -func (s *S) MustRegister(meta *Artifact) { - if !s.Register(meta) { - panic(RegisterError(H(meta.Name))) +func (s *S) MustRegister(name string, f Artifact) { + if !s.Register(name, f) { + panic(RegisterError(H(name))) } } +// mustRegister registers an [Artifact] with the old function signature. +// +// Deprecated: Artifacts should be migrated to Register. +func (s *S) mustRegister( + f func(t Toolchain) (pkg.Artifact, string), + meta *Metadata, +) { + s.MustRegister(meta.Name, func(t Toolchain) (*Metadata, pkg.Artifact) { + v := *meta + a, version := f(t) + v.Version = version + return &v, a + }) +} + // Count returns the number of [Artifact] registered to s. func (s *S) Count() int { return int(s.artifactCount.Load()) @@ -567,7 +588,7 @@ func (ctx *evalContext) f( return unique.Make(azalea.Ident(name)) } - meta := Artifact{Name: string(name)} + meta := Metadata{Name: string(name)} var ( attr PackageAttr patches []string @@ -575,7 +596,6 @@ func (ctx *evalContext) f( early bool anitya int64 - version string sourceA any helper Helper @@ -584,11 +604,9 @@ func (ctx *evalContext) f( if err = args.Apply(map[unique.Handle[azalea.Ident]]any{ k("description"): &meta.Description, k("website"): &meta.Website, + k("version"): &meta.Version, k("anitya"): &anitya, - k("version"): &version, - k("source"): &sourceA, - k("writable"): &attr.Writable, k("chmod"): &attr.Chmod, k("enterSource"): &attr.EnterSource, @@ -598,6 +616,7 @@ func (ctx *evalContext) f( k("exclusive"): &excl, k("toyboxEarly"): &early, + k("source"): &sourceA, k("exec"): &helper, k("inputs"): &inputs, k("runtime"): &runtimes, @@ -630,7 +649,7 @@ func (ctx *evalContext) f( } meta.ID = int(anitya) - meta.f = func(t Toolchain) (pkg.Artifact, string) { + v = Artifact(func(t Toolchain) (*Metadata, pkg.Artifact) { var source pkg.Artifact switch p := sourceA.(type) { case pkg.Artifact: @@ -646,17 +665,15 @@ func (ctx *evalContext) f( }) } - return t.NewPackage( + return &meta, t.NewPackage( meta.Name, - version, + meta.Version, source, &attr, helper, inputsH..., - ), version - } - - v = meta + ) + }) set = true return } @@ -686,13 +703,13 @@ func (s *S) Evaluate(r io.Reader, b fs.FS) error { ctx := evalContext{b} for _, f := range pending { - meta, set, err := azalea.Evaluate[Artifact](ctx.f, s.getS(), *f) + lf, set, err := azalea.Evaluate[Artifact](ctx.f, s.getS(), *f) if err != nil { return err } else if !set { return errors.New("unexpected unset") } - if !s.Register(&meta) { + if !s.Register(string(f.Ident), lf) { return RegisterError(H(string(f.Ident))) } } |
