2 Commits

Author SHA1 Message Date
mae
0f944f7a0e cmd/pkgserver: add createPackageIndex 2026-03-09 01:27:46 -05:00
mae
223037e7c2 cmd/pkgserver: add command handler 2026-03-08 22:28:08 -05:00

View File

@@ -1,9 +1,23 @@
package main
import (
"cmp"
"context"
"embed"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"slices"
"syscall"
"unique"
"hakurei.app/command"
"hakurei.app/container/check"
"hakurei.app/internal/pkg"
"hakurei.app/internal/rosa"
"hakurei.app/message"
)
//go:generate sh -c "sass ui/static/dark.scss ui/static/dark.css && sass ui/static/light.scss ui/static/light.css && tsc ui/static/index.ts"
@@ -43,13 +57,118 @@ func serveStaticContent(w http.ResponseWriter, r *http.Request) {
}
}
func serveAPI(w http.ResponseWriter, r *http.Request) {
func serveAPI(pi *PackageIndex) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {}
}
type SortOrders int
const (
DeclarationDescending SortOrders = iota
DeclarationAscending
NameAscending
NameDescending
limitSortOrders
)
type PackageIndex [limitSortOrders][rosa.PresetUnexportedStart]*PackageIndexEntry
type PackageIndexEntry struct {
id unique.Handle[pkg.ID]
name string
description string
website string
version string
status []byte
}
func createPackageIndex(cache *pkg.Cache, report *rosa.Report) *PackageIndex {
var index PackageIndex
var work []PackageIndexEntry
for p := range rosa.PresetUnexportedStart {
m := rosa.GetMetadata(p)
v := rosa.Std.Version(p)
a := rosa.Std.Load(p)
id := cache.Ident(a)
status, n := report.ArtifactOf(id)
work[p] = PackageIndexEntry{
id: id,
name: m.Name,
description: m.Description,
website: m.Website,
version: v,
status: status[:n],
}
}
for i, p := range work {
index[DeclarationAscending][i] = &p
}
slices.Reverse(work)
for i, p := range work {
index[DeclarationDescending][i] = &p
}
slices.SortFunc(work, func(a PackageIndexEntry, b PackageIndexEntry) int {
return cmp.Compare(a.name, b.name)
})
for i, p := range work {
index[NameAscending][i] = &p
}
slices.Reverse(work)
for i, p := range work {
index[NameDescending][i] = &p
}
return &index
}
func main() {
http.HandleFunc("GET /{$}", serveWebUI)
http.HandleFunc("GET /favicon.ico", serveStaticContent)
http.HandleFunc("GET /static/", serveStaticContent)
http.HandleFunc("GET /api/", serveAPI)
http.ListenAndServe(":8067", nil)
log.SetFlags(0)
log.SetPrefix("pkgserver: ")
var (
flagBaseDir string
flagPort uint16
)
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
defer stop()
msg := message.New(log.Default())
c := command.New(os.Stderr, log.Printf, "pkgserver", func(args []string) error {
reportPath := args[0]
baseDir, err := check.NewAbs(flagBaseDir)
if err != nil {
return err
}
cache, err := pkg.Open(ctx, msg, 0, baseDir)
if err != nil {
return err
}
report, err := rosa.OpenReport(reportPath)
if err != nil {
return err
}
defer report.HandleAccess(&err)()
index := createPackageIndex(cache, report)
http.HandleFunc("GET /{$}", serveWebUI)
http.HandleFunc("GET /favicon.ico", serveStaticContent)
http.HandleFunc("GET /static/", serveStaticContent)
http.HandleFunc("GET /api/", serveAPI(index))
err = http.ListenAndServe(fmt.Sprintf(":%d", flagPort), nil)
if err != nil {
return err
}
return nil
}).Flag(
&flagBaseDir,
"b", command.StringFlag(""),
"base directory for cache",
).Flag(
&flagPort,
"p", command.IntFlag(8067),
"http listen port",
)
c.MustParse(os.Args[1:], func(e error) {
log.Fatal(e)
})
}