diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-09-15 00:06:21 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-09-15 00:06:21 +0900 |
| commit | 834db962958652502aba88362dbe91df2ee618ee (patch) | |
| tree | 9c06fbcab83ad56e2d90f24a8d2cf016c6c1d005 /cmd/mbf/internal/pkgsite/index.go | |
| parent | cce7a996b06e516f5afcd41d2d67c2392000b6ab (diff) | |
cmd/mbf: rename pkgsite
This name is less ambiguous than pkgserver.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'cmd/mbf/internal/pkgsite/index.go')
| -rw-r--r-- | cmd/mbf/internal/pkgsite/index.go | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/cmd/mbf/internal/pkgsite/index.go b/cmd/mbf/internal/pkgsite/index.go new file mode 100644 index 00000000..760806c0 --- /dev/null +++ b/cmd/mbf/internal/pkgsite/index.go @@ -0,0 +1,108 @@ +package pkgsite + +import ( + "cmp" + "errors" + "slices" + "strings" + + "hakurei.app/internal/rosa" + "hakurei.app/pkg" +) + +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][]*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 { + handle rosa.ArtifactH + *rosa.Metadata + + // Copied from [rosa.Metadata], [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 + } + + handles := rosa.Collect() + work := make([]*metadata, len(handles)) + index.names = make(map[string]*metadata) + ir := pkg.NewIR() + for i, handle := range handles { + meta, a := rosa.MustLoad(handle) + m := metadata{ + handle: handle, + + Metadata: meta, + Version: meta.Version, + } + if m.Version == "" { + return errors.New("invalid version from " + m.Name) + } + if m.Version == rosa.Unversioned { + m.Version = "" + } + + if report != nil { + id := ir.Ident(a) + m.ids = pkg.Encode(id.Value()) + m.status, m.Size = report.ArtifactOf(id) + m.HasReport = m.Size >= 0 + } + + work[i] = &m + index.names[m.Name] = &m + } + + index.sorts[declarationAscending] = work + index.sorts[declarationDescending] = slices.Clone(work) + slices.Reverse(index.sorts[declarationDescending][:]) + + index.sorts[nameAscending] = slices.Clone(work) + slices.SortFunc(index.sorts[nameAscending][:], func(a, b *metadata) int { + return strings.Compare(a.Name, b.Name) + }) + index.sorts[nameDescending] = slices.Clone(index.sorts[nameAscending]) + slices.Reverse(index.sorts[nameDescending][:]) + + index.sorts[sizeAscending] = slices.Clone(work) + slices.SortFunc(index.sorts[sizeAscending][:], func(a, b *metadata) int { + return cmp.Compare(a.Size, b.Size) + }) + index.sorts[sizeDescending] = slices.Clone(index.sorts[sizeAscending]) + slices.Reverse(index.sorts[sizeDescending][:]) + + return +} |
