aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd/mbf/internal/pkgserver/index.go
diff options
context:
space:
mode:
authormae <mae@maestoso.online>2026-03-04 22:50:58 -0600
committerOphestra <cat@gensokyo.uk>2026-05-02 05:05:56 +0900
commit1d5d063d6a443c9d4a1206d2743e4824411da956 (patch)
treeb32105cf3896f394be91099cfbfb67785de39385 /cmd/mbf/internal/pkgserver/index.go
parente61628a34ecccae0feb5e059a2f808977261fa0e (diff)
cmd/mbf: package status dashboard
This displays package metadata with optional status from a report.
Diffstat (limited to 'cmd/mbf/internal/pkgserver/index.go')
-rw-r--r--cmd/mbf/internal/pkgserver/index.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/cmd/mbf/internal/pkgserver/index.go b/cmd/mbf/internal/pkgserver/index.go
new file mode 100644
index 00000000..911183da
--- /dev/null
+++ b/cmd/mbf/internal/pkgserver/index.go
@@ -0,0 +1,106 @@
+package pkgserver
+
+import (
+ "cmp"
+ "errors"
+ "slices"
+ "strings"
+
+ "hakurei.app/internal/pkg"
+ "hakurei.app/internal/rosa"
+)
+
+const (
+ declarationAscending = iota
+ declarationDescending
+ nameAscending
+ nameDescending
+ sizeAscending
+ sizeDescending
+
+ sortOrderEnd = iota - 1
+)
+
+// packageIndex refers to metadata by name and various sort orders.
+type packageIndex struct {
+ sorts [sortOrderEnd + 1][rosa.PresetUnexportedStart]*metadata
+ names map[string]*metadata
+ search searchCache
+ // Taken from [rosa.Report] if available.
+ handleAccess func(*error) func()
+}
+
+// metadata holds [rosa.Metadata] extended with additional information.
+type metadata struct {
+ p rosa.PArtifact
+ *rosa.Metadata
+
+ // Populated via [rosa.Toolchain.Version], [rosa.Unversioned] is equivalent
+ // to the zero value. Otherwise, the zero value is invalid.
+ Version string `json:"version,omitempty"`
+ // Output data size, available if present in report.
+ Size int64 `json:"size,omitempty"`
+ // Whether the underlying [pkg.Artifact] is present in the report.
+ HasReport bool `json:"report"`
+
+ // Ident string encoded ahead of time.
+ ids string
+ // Backed by [rosa.Report], access must be prepared by HandleAccess.
+ status []byte
+}
+
+// populate deterministically populates packageIndex, optionally with a report.
+func (index *packageIndex) populate(report *rosa.Report) (err error) {
+ if report != nil {
+ defer report.HandleAccess(&err)()
+ index.handleAccess = report.HandleAccess
+ }
+
+ var work [rosa.PresetUnexportedStart]*metadata
+ index.names = make(map[string]*metadata)
+ ir := pkg.NewIR()
+ for p := range rosa.PresetUnexportedStart {
+ m := metadata{
+ p: p,
+
+ Metadata: rosa.GetMetadata(p),
+ Version: rosa.Std.Version(p),
+ }
+ if m.Version == "" {
+ return errors.New("invalid version from " + m.Name)
+ }
+ if m.Version == rosa.Unversioned {
+ m.Version = ""
+ }
+
+ if report != nil {
+ id := ir.Ident(rosa.Std.Load(p))
+ m.ids = pkg.Encode(id.Value())
+ m.status, m.Size = report.ArtifactOf(id)
+ m.HasReport = m.Size >= 0
+ }
+
+ work[p] = &m
+ index.names[m.Name] = &m
+ }
+
+ index.sorts[declarationAscending] = work
+ index.sorts[declarationDescending] = work
+ slices.Reverse(index.sorts[declarationDescending][:])
+
+ index.sorts[nameAscending] = work
+ slices.SortFunc(index.sorts[nameAscending][:], func(a, b *metadata) int {
+ return strings.Compare(a.Name, b.Name)
+ })
+ index.sorts[nameDescending] = index.sorts[nameAscending]
+ slices.Reverse(index.sorts[nameDescending][:])
+
+ index.sorts[sizeAscending] = work
+ slices.SortFunc(index.sorts[sizeAscending][:], func(a, b *metadata) int {
+ return cmp.Compare(a.Size, b.Size)
+ })
+ index.sorts[sizeDescending] = index.sorts[sizeAscending]
+ slices.Reverse(index.sorts[sizeDescending][:])
+
+ return
+}