Compare commits

..

39 Commits

Author SHA1 Message Date
maemachinebroke 689605ea67 cmd/pkgserver: update 2026-05-01 19:21:38 +09:00
maemachinebroke 3306350ff2 cmd/pkgserver: fix gitignore 2026-05-01 19:21:38 +09:00
maemachinebroke b34baa0d1c cmd/pkgserver: better no results handling 2026-05-01 19:21:38 +09:00
maemachinebroke f692738354 cmd/pkgserver: better no results handling 2026-05-01 19:21:38 +09:00
maemachinebroke 93fcfbcc64 cmd/pkgserver: finish search implementation 2026-05-01 19:21:38 +09:00
maemachinebroke 8c9de5916d cmd/pkgserver: remove get endpoint count field 2026-05-01 19:21:37 +09:00
maemachinebroke 1eee301e3a cmd/pkgserver: search endpoint 2026-05-01 19:21:37 +09:00
maemachinebroke 402716b610 cmd/pkgserver: pagination bugfix 2026-05-01 19:21:37 +09:00
cat b7e71be6e8 cmd/pkgserver: guard sass/ts behind build tag
Packaging nodejs and ruby is an immense burden for the Rosa OS base system, and these files diff poorly.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
maemachinebroke 9cf82d9521 cmd/pkgserver: add size 2026-05-01 19:21:37 +09:00
cat ff65ca303f cmd/pkgserver: expose size and store pre-encoded ident
This change also handles SIGSEGV correctly in newStatusHandler, and makes serving status fully zero copy.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat 1c73aa2936 cmd/pkgserver: look up status by name once
This has far less overhead.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat c267fa8c53 cmd/pkgserver: refer to preset in index
This enables referencing back to internal/rosa through an entry obtained via the index.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat acc8eef161 cmd/pkgserver: handle unversioned value
This omits the field for an unversioned artifact, and only does so once on startup.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat 374fa33ef5 cmd/pkgserver: determine disposition route in mux
This removes duplicate checks and uses the more sound check in mux.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat 8e697e70b6 cmd/pkgserver: format get error messages
This improves source code readability on smaller displays.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat 305d700f1e cmd/pkgserver: constant string in pattern
This resolves patterns at compile time.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat 6973eb1224 cmd/pkgserver: satisfy handler signature in method
This is somewhat cleaner.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat 9c3ee25906 cmd/pkgserver: log instead of write encoding error
This message is unlikely to be useful to the user, and output may be partially written at this point, causing the error to be even less intelligible.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat c11985a477 cmd/pkgserver: appropriately mark test helpers
This improves usefulness of test log messages.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat a6f9fe7981 cmd/pkgserver: do not omit report field
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat 25d6b85aef cmd/pkgserver: gracefully shut down on signal
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat 134bfb01be cmd/pkgserver: specify full addr string in flag
This allows greater flexibility.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat dae754678e cmd/pkgserver: make report argument optional
This allows serving metadata only without a populated report. This also removes the out-of-bounds read on args when no arguments are passed.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat 3241e4f24a cmd/pkgserver: embed internal/rosa metadata
This change also cleans up and reduces some unnecessary copies.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat eab70c42bc cmd/pkgserver: do not assume default mux
This helps with testing.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
cat cc451595b8 cmd/pkgserver: create index without report
This is useful for testing, where report testdata is not available.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
maemachinebroke 6f58938615 cmd/pkgserver: add sort orders, change pagination rules 2026-05-01 19:21:37 +09:00
maemachinebroke dd511b0a19 cmd/pkgserver: add /status endpoint 2026-05-01 19:21:37 +09:00
maemachinebroke 6f13b21403 cmd/pkgserver: minimum viable frontend 2026-05-01 19:21:37 +09:00
maemachinebroke 251d312597 cmd/pkgserver: api versioning 2026-05-01 19:21:37 +09:00
maemachinebroke e7ace18573 cmd/pkgserver: add get endpoint 2026-05-01 19:21:37 +09:00
maemachinebroke 24a859ac2c cmd/pkgserver: add count endpoint and restructure 2026-05-01 19:21:37 +09:00
maemachinebroke 29320d3387 cmd/pkgserver: add status endpoint 2026-05-01 19:21:37 +09:00
maemachinebroke c537403257 cmd/pkgserver: add createPackageIndex 2026-05-01 19:21:37 +09:00
maemachinebroke 035fa01a3b cmd/pkgserver: add command handler 2026-05-01 19:21:37 +09:00
maemachinebroke 09fd010912 cmd/pkgserver: replace favicon 2026-05-01 19:21:37 +09:00
maemachinebroke 7094c9219f cmd/pkgserver: pagination 2026-05-01 19:21:37 +09:00
maemachinebroke 237183740c cmd/pkgserver: basic web ui 2026-05-01 19:21:37 +09:00
26 changed files with 219 additions and 311 deletions
+1 -1
View File
@@ -7,7 +7,7 @@
# go generate # go generate
/cmd/hakurei/LICENSE /cmd/hakurei/LICENSE
/cmd/mbf/internal/pkgserver/ui/static /cmd/pkgserver/ui/static/*.js
/internal/pkg/testdata/testtool /internal/pkg/testdata/testtool
/internal/rosa/hakurei_current.tar.gz /internal/rosa/hakurei_current.tar.gz
+14 -1
View File
@@ -17,12 +17,25 @@ func commandInfo(
args []string, args []string,
w io.Writer, w io.Writer,
writeStatus bool, writeStatus bool,
r *rosa.Report, reportPath string,
) (err error) { ) (err error) {
if len(args) == 0 { if len(args) == 0 {
return errors.New("info requires at least 1 argument") return errors.New("info requires at least 1 argument")
} }
var r *rosa.Report
if reportPath != "" {
if r, err = rosa.OpenReport(reportPath); err != nil {
return err
}
defer func() {
if closeErr := r.Close(); err == nil {
err = closeErr
}
}()
defer r.HandleAccess(&err)()
}
// recovered by HandleAccess // recovered by HandleAccess
mustPrintln := func(a ...any) { mustPrintln := func(a ...any) {
if _, _err := fmt.Fprintln(w, a...); _err != nil { if _, _err := fmt.Fprintln(w, a...); _err != nil {
+6 -17
View File
@@ -95,7 +95,7 @@ status : not in report
var ( var (
cm *cache cm *cache
buf strings.Builder buf strings.Builder
r *rosa.Report rp string
) )
if tc.status != nil || tc.report != "" { if tc.status != nil || tc.report != "" {
@@ -108,25 +108,14 @@ status : not in report
} }
if tc.report != "" { if tc.report != "" {
pathname := filepath.Join(t.TempDir(), "report") rp = filepath.Join(t.TempDir(), "report")
err := os.WriteFile( if err := os.WriteFile(
pathname, rp,
unsafe.Slice(unsafe.StringData(tc.report), len(tc.report)), unsafe.Slice(unsafe.StringData(tc.report), len(tc.report)),
0400, 0400,
) ); err != nil {
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
r, err = rosa.OpenReport(pathname)
if err != nil {
t.Fatal(err)
}
defer func() {
if err = r.Close(); err != nil {
t.Fatal(err)
}
}()
} }
if tc.status != nil { if tc.status != nil {
@@ -168,7 +157,7 @@ status : not in report
tc.args, tc.args,
&buf, &buf,
cm != nil, cm != nil,
r, rp,
); !reflect.DeepEqual(err, wantErr) { ); !reflect.DeepEqual(err, wantErr) {
t.Fatalf("commandInfo: error = %v, want %v", err, wantErr) t.Fatalf("commandInfo: error = %v, want %v", err, wantErr)
} }
-9
View File
@@ -1,9 +0,0 @@
// Package ui holds the static web UI.
package ui
import "net/http"
// Register arranges for mux to serve the embedded frontend.
func Register(mux *http.ServeMux) {
mux.Handle("GET /", http.FileServer(http.FS(static)))
}
-21
View File
@@ -1,21 +0,0 @@
//go:build frontend
package ui
import (
"embed"
"io/fs"
)
//go:generate tsc
//go:generate cp index.html style.css static
//go:embed static
var _static embed.FS
var static = func() fs.FS {
if f, err := fs.Sub(_static, "static"); err != nil {
panic(err)
} else {
return f
}
}()
+2 -61
View File
@@ -20,7 +20,6 @@ import (
"io" "io"
"log" "log"
"net" "net"
"net/http"
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
@@ -42,9 +41,6 @@ import (
"hakurei.app/internal/pkg" "hakurei.app/internal/pkg"
"hakurei.app/internal/rosa" "hakurei.app/internal/rosa"
"hakurei.app/message" "hakurei.app/message"
"hakurei.app/cmd/mbf/internal/pkgserver"
"hakurei.app/cmd/mbf/internal/pkgserver/ui"
) )
func main() { func main() {
@@ -140,17 +136,7 @@ func main() {
c.NewCommand( c.NewCommand(
"checksum", "Compute checksum of data read from standard input", "checksum", "Compute checksum of data read from standard input",
func([]string) error { func([]string) error {
done := make(chan struct{}) go func() { <-ctx.Done(); os.Exit(1) }()
defer close(done)
go func() {
select {
case <-ctx.Done():
os.Exit(1)
case <-done:
return
}
}()
h := sha512.New384() h := sha512.New384()
if _, err := io.Copy(h, os.Stdin); err != nil { if _, err := io.Copy(h, os.Stdin); err != nil {
return err return err
@@ -184,7 +170,6 @@ func main() {
{ {
var ( var (
flagBind string
flagStatus bool flagStatus bool
flagReport string flagReport string
) )
@@ -192,52 +177,8 @@ func main() {
"info", "info",
"Display out-of-band metadata of an artifact", "Display out-of-band metadata of an artifact",
func(args []string) (err error) { func(args []string) (err error) {
const shutdownTimeout = 15 * time.Second return commandInfo(&cm, args, os.Stdout, flagStatus, flagReport)
var r *rosa.Report
if flagReport != "" {
if r, err = rosa.OpenReport(flagReport); err != nil {
return err
}
defer func() {
if closeErr := r.Close(); err == nil {
err = closeErr
}
}()
defer r.HandleAccess(&err)()
}
if flagBind == "" {
return commandInfo(&cm, args, os.Stdout, flagStatus, r)
}
var mux http.ServeMux
ui.Register(&mux)
if err = pkgserver.Register(ctx, &mux, r); err != nil {
return
}
server := http.Server{Addr: flagBind, Handler: &mux}
go func() {
<-ctx.Done()
cc, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
if _err := server.Shutdown(cc); _err != nil {
log.Fatal(_err)
}
}()
msg.Verbosef("listening on %q", flagBind)
err = server.ListenAndServe()
if errors.Is(err, http.ErrServerClosed) {
err = nil
}
return
}, },
).Flag(
&flagBind,
"bind", command.StringFlag(""),
"TCP address for the server to listen on",
).Flag( ).Flag(
&flagStatus, &flagStatus,
"status", command.BoolFlag(false), "status", command.BoolFlag(false),
-47
View File
@@ -1,47 +0,0 @@
package main
import (
"net"
"os"
"testing"
"hakurei.app/internal/rosa"
)
func TestMain(m *testing.M) {
rosa.DropCaches(rosa.OptLLVMNoLTO)
os.Exit(m.Run())
}
func TestCureAll(t *testing.T) {
t.Parallel()
const env = "ROSA_TEST_DAEMON"
if !testing.Verbose() {
t.Skip("verbose flag not set")
}
pathname, ok := os.LookupEnv(env)
if !ok {
t.Skip(env + " not set")
}
addr := net.UnixAddr{Net: "unix", Name: pathname}
t.Cleanup(func() {
if t.Failed() {
if err := abortRemote(t.Context(), &addr, false); err != nil {
t.Fatal(err)
}
}
})
for i := range rosa.PresetEnd {
p := rosa.PArtifact(i)
t.Run(rosa.GetMetadata(p).Name, func(t *testing.T) {
_, err := cureRemote(t.Context(), &addr, rosa.Std.Load(p), 0)
if err != nil {
t.Error(err)
}
})
}
}
@@ -1,8 +1,6 @@
// Package pkgserver implements the package metadata service backend. package main
package pkgserver
import ( import (
"context"
"encoding/json" "encoding/json"
"log" "log"
"net/http" "net/http"
@@ -10,7 +8,6 @@ import (
"path" "path"
"strconv" "strconv"
"sync" "sync"
"time"
"hakurei.app/internal/info" "hakurei.app/internal/info"
"hakurei.app/internal/rosa" "hakurei.app/internal/rosa"
@@ -161,29 +158,6 @@ func (index *packageIndex) registerAPI(mux *http.ServeMux) {
mux.HandleFunc("GET /status/", index.newStatusHandler(true)) mux.HandleFunc("GET /status/", index.newStatusHandler(true))
} }
// Register arranges for mux to service API requests.
func Register(ctx context.Context, mux *http.ServeMux, report *rosa.Report) error {
var index packageIndex
index.search = make(searchCache)
if err := index.populate(report); err != nil {
return err
}
ticker := time.NewTicker(1 * time.Minute)
go func() {
for {
select {
case <-ctx.Done():
ticker.Stop()
return
case <-ticker.C:
index.search.clean()
}
}
}()
index.registerAPI(mux)
return nil
}
// writeAPIPayload sets headers common to API responses and encodes payload as // writeAPIPayload sets headers common to API responses and encodes payload as
// JSON for the response body. // JSON for the response body.
func writeAPIPayload(w http.ResponseWriter, payload any) { func writeAPIPayload(w http.ResponseWriter, payload any) {
@@ -1,4 +1,4 @@
package pkgserver package main
import ( import (
"net/http" "net/http"
@@ -118,31 +118,33 @@ func TestAPIGet(t *testing.T) {
checkStatus(t, resp, http.StatusOK) checkStatus(t, resp, http.StatusOK)
checkAPIHeader(t, w.Header()) checkAPIHeader(t, w.Header())
checkPayloadFunc(t, resp, func(got *struct { checkPayloadFunc(t, resp, func(got *struct {
Count int `json:"count"`
Values []*metadata `json:"values"` Values []*metadata `json:"values"`
}) bool { }) bool {
return slices.EqualFunc(got.Values, want, func(a, b *metadata) bool { return got.Count == len(want) &&
return (a.Version == b.Version || slices.EqualFunc(got.Values, want, func(a, b *metadata) bool {
a.Version == rosa.Unversioned || return (a.Version == b.Version ||
b.Version == rosa.Unversioned) && a.Version == rosa.Unversioned ||
a.HasReport == b.HasReport && b.Version == rosa.Unversioned) &&
a.Name == b.Name && a.HasReport == b.HasReport &&
a.Description == b.Description && a.Name == b.Name &&
a.Website == b.Website a.Description == b.Description &&
}) a.Website == b.Website
})
}) })
}) })
} }
checkWithSuffix("declarationAscending", "?limit=2&index=1&sort=0", []*metadata{ checkWithSuffix("declarationAscending", "?limit=2&index=0&sort=0", []*metadata{
{
Metadata: rosa.GetMetadata(0),
Version: rosa.Std.Version(0),
},
{ {
Metadata: rosa.GetMetadata(1), Metadata: rosa.GetMetadata(1),
Version: rosa.Std.Version(1), Version: rosa.Std.Version(1),
}, },
{
Metadata: rosa.GetMetadata(2),
Version: rosa.Std.Version(2),
},
}) })
checkWithSuffix("declarationAscending offset", "?limit=3&index=5&sort=0", []*metadata{ checkWithSuffix("declarationAscending offset", "?limit=3&index=5&sort=0", []*metadata{
{ {
@@ -1,4 +1,4 @@
package pkgserver package main
import ( import (
"cmp" "cmp"
@@ -50,7 +50,7 @@ type metadata struct {
} }
// populate deterministically populates packageIndex, optionally with a report. // populate deterministically populates packageIndex, optionally with a report.
func (index *packageIndex) populate(report *rosa.Report) (err error) { func (index *packageIndex) populate(cache *pkg.Cache, report *rosa.Report) (err error) {
if report != nil { if report != nil {
defer report.HandleAccess(&err)() defer report.HandleAccess(&err)()
index.handleAccess = report.HandleAccess index.handleAccess = report.HandleAccess
@@ -58,7 +58,6 @@ func (index *packageIndex) populate(report *rosa.Report) (err error) {
var work [rosa.PresetUnexportedStart]*metadata var work [rosa.PresetUnexportedStart]*metadata
index.names = make(map[string]*metadata) index.names = make(map[string]*metadata)
ir := pkg.NewIR()
for p := range rosa.PresetUnexportedStart { for p := range rosa.PresetUnexportedStart {
m := metadata{ m := metadata{
p: p, p: p,
@@ -73,8 +72,8 @@ func (index *packageIndex) populate(report *rosa.Report) (err error) {
m.Version = "" m.Version = ""
} }
if report != nil { if cache != nil && report != nil {
id := ir.Ident(rosa.Std.Load(p)) id := cache.Ident(rosa.Std.Load(p))
m.ids = pkg.Encode(id.Value()) m.ids = pkg.Encode(id.Value())
m.status, m.Size = report.ArtifactOf(id) m.status, m.Size = report.ArtifactOf(id)
m.HasReport = m.Size >= 0 m.HasReport = m.Size >= 0
+114
View File
@@ -0,0 +1,114 @@
package main
import (
"context"
"errors"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"hakurei.app/check"
"hakurei.app/command"
"hakurei.app/internal/pkg"
"hakurei.app/internal/rosa"
"hakurei.app/message"
)
const shutdownTimeout = 15 * time.Second
func main() {
log.SetFlags(0)
log.SetPrefix("pkgserver: ")
var (
flagBaseDir string
flagAddr string
)
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 {
var (
cache *pkg.Cache
report *rosa.Report
)
switch len(args) {
case 0:
break
case 1:
baseDir, err := check.NewAbs(flagBaseDir)
if err != nil {
return err
}
cache, err = pkg.Open(ctx, msg, 0, 0, 0, baseDir)
if err != nil {
return err
}
defer cache.Close()
report, err = rosa.OpenReport(args[0])
if err != nil {
return err
}
default:
return errors.New("pkgserver requires 1 argument")
}
var index packageIndex
index.search = make(searchCache)
if err := index.populate(cache, report); err != nil {
return err
}
ticker := time.NewTicker(1 * time.Minute)
go func() {
for {
select {
case <-ctx.Done():
ticker.Stop()
return
case <-ticker.C:
index.search.clean()
}
}
}()
var mux http.ServeMux
uiRoutes(&mux)
index.registerAPI(&mux)
server := http.Server{
Addr: flagAddr,
Handler: &mux,
}
go func() {
<-ctx.Done()
c, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
if err := server.Shutdown(c); err != nil {
log.Fatal(err)
}
}()
return server.ListenAndServe()
}).Flag(
&flagBaseDir,
"b", command.StringFlag(""),
"base directory for cache",
).Flag(
&flagAddr,
"addr", command.StringFlag(":8067"),
"TCP network address to listen on",
)
c.MustParse(os.Args[1:], func(err error) {
if errors.Is(err, http.ErrServerClosed) {
os.Exit(0)
}
log.Fatal(err)
})
}
@@ -1,4 +1,4 @@
package pkgserver package main
import ( import (
"bytes" "bytes"
@@ -15,7 +15,7 @@ func newIndex(t *testing.T) *packageIndex {
t.Helper() t.Helper()
var index packageIndex var index packageIndex
if err := index.populate(nil); err != nil { if err := index.populate(nil, nil); err != nil {
t.Fatalf("populate: error = %v", err) t.Fatalf("populate: error = %v", err)
} }
return &index return &index
@@ -1,4 +1,4 @@
package pkgserver package main
import ( import (
"cmp" "cmp"
+33
View File
@@ -0,0 +1,33 @@
package main
import "net/http"
func serveWebUI(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Pragma", "no-cache")
w.Header().Set("Expires", "0")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-XSS-Protection", "1")
w.Header().Set("X-Frame-Options", "DENY")
http.ServeFileFS(w, r, content, "ui/index.html")
}
func serveStaticContent(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/static/style.css":
http.ServeFileFS(w, r, content, "ui/static/style.css")
case "/favicon.ico":
http.ServeFileFS(w, r, content, "ui/static/favicon.ico")
case "/static/index.js":
http.ServeFileFS(w, r, content, "ui/static/index.js")
default:
http.NotFound(w, r)
}
}
func uiRoutes(mux *http.ServeMux) {
mux.HandleFunc("GET /{$}", serveWebUI)
mux.HandleFunc("GET /favicon.ico", serveStaticContent)
mux.HandleFunc("GET /static/", serveStaticContent)
}
@@ -3,9 +3,9 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="static/style.css">
<title>Hakurei PkgServer</title> <title>Hakurei PkgServer</title>
<script src="index.js"></script> <script src="static/index.js"></script>
</head> </head>
<body> <body>
<h1>Hakurei PkgServer</h1> <h1>Hakurei PkgServer</h1>
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+9
View File
@@ -0,0 +1,9 @@
//go:build frontend
package main
import "embed"
//go:generate tsc -p ui
//go:embed ui/*
var content embed.FS
@@ -1,7 +1,7 @@
//go:build !frontend //go:build !frontend
package ui package main
import "testing/fstest" import "testing/fstest"
var static fstest.MapFS var content fstest.MapFS
+1 -46
View File
@@ -2,47 +2,10 @@ package rosa
import ( import (
"runtime" "runtime"
"slices"
"strconv"
"strings"
"hakurei.app/internal/pkg" "hakurei.app/internal/pkg"
) )
// skipGNUTests generates a string for skipping specific tests by number in a
// GNU test suite. This is nontrivial because the test suite does not support
// excluding tests in any way, so ranges for all but the skipped tests have to
// be specified instead.
//
// For example, to skip test 764, ranges around the skipped test must be
// specified:
//
// 1-763 765-
//
// Tests are numbered starting from 1. The resulting string is unquoted.
func skipGNUTests(tests ...int) string {
tests = slices.Clone(tests)
slices.Sort(tests)
var buf strings.Builder
if tests[0] != 1 {
buf.WriteString("1-")
}
for i, n := range tests {
if n != 1 && (i == 0 || tests[i-1] != n-1) {
buf.WriteString(strconv.Itoa(n - 1))
buf.WriteString(" ")
}
if i == len(tests)-1 || tests[i+1] != n+1 {
buf.WriteString(strconv.Itoa(n + 1))
buf.WriteString("-")
}
}
return buf.String()
}
func (t Toolchain) newM4() (pkg.Artifact, string) { func (t Toolchain) newM4() (pkg.Artifact, string) {
const ( const (
version = "1.4.21" version = "1.4.21"
@@ -84,15 +47,7 @@ func (t Toolchain) newBison() (pkg.Artifact, string) {
"https://ftpmirror.gnu.org/gnu/bison/bison-"+version+".tar.gz", "https://ftpmirror.gnu.org/gnu/bison/bison-"+version+".tar.gz",
checksum, checksum,
pkg.TarGzip, pkg.TarGzip,
), nil, &MakeHelper{ ), nil, (*MakeHelper)(nil),
Check: []string{
"TESTSUITEFLAGS=" + jobsFlagE + "' " + skipGNUTests(
// clang miscompiles (SIGILL)
764,
) + "'",
"check",
},
},
M4, M4,
Diffutils, Diffutils,
Sed, Sed,
-35
View File
@@ -1,35 +0,0 @@
package rosa
import (
"slices"
"strconv"
"strings"
"testing"
)
func TestSkipGNUTests(t *testing.T) {
t.Parallel()
testCases := []struct {
tests []int
want string
}{
{[]int{764}, "1-763 765-"},
{[]int{764, 0xcafe, 37, 9}, "1-8 10-36 38-763 765-51965 51967-"},
{[]int{1, 2, 0xbed}, "3-3052 3054-"},
{[]int{3, 4}, "1-2 5-"},
}
for _, tc := range testCases {
t.Run(strings.Join(slices.Collect(func(yield func(string) bool) {
for _, n := range tc.tests {
yield(strconv.Itoa(n))
}
}), ","), func(t *testing.T) {
t.Parallel()
if got := skipGNUTests(tc.tests...); got != tc.want {
t.Errorf("skipGNUTests: %q, want %q", got, tc.want)
}
})
}
}
+9 -11
View File
@@ -10,9 +10,9 @@ import (
// newGoBootstrap returns the Go bootstrap toolchain. // newGoBootstrap returns the Go bootstrap toolchain.
func (t Toolchain) newGoBootstrap() pkg.Artifact { func (t Toolchain) newGoBootstrap() pkg.Artifact {
const checksum = "8o9JL_ToiQKadCTb04nvBDkp8O1xiWOolAxVEqaTGodieNe4lOFEjlOxN3bwwe23" const checksum = "8o9JL_ToiQKadCTb04nvBDkp8O1xiWOolAxVEqaTGodieNe4lOFEjlOxN3bwwe23"
return t.New("go1.4-bootstrap", 0, t.AppendPresets(nil, return t.New("go1.4-bootstrap", 0, []pkg.Artifact{
Bash, t.Load(Bash),
), nil, []string{ }, nil, []string{
"CGO_ENABLED=0", "CGO_ENABLED=0",
}, ` }, `
mkdir -p /var/tmp/ /work/system/ mkdir -p /var/tmp/ /work/system/
@@ -35,9 +35,9 @@ func (t Toolchain) newGo(
script string, script string,
extra ...pkg.Artifact, extra ...pkg.Artifact,
) pkg.Artifact { ) pkg.Artifact {
return t.New("go"+version, 0, t.AppendPresets(extra, return t.New("go"+version, 0, slices.Concat([]pkg.Artifact{
Bash, t.Load(Bash),
), nil, slices.Concat([]string{ }, extra), nil, slices.Concat([]string{
"CC=cc", "CC=cc",
"GOCACHE=/tmp/gocache", "GOCACHE=/tmp/gocache",
"GOROOT_BOOTSTRAP=/system/go", "GOROOT_BOOTSTRAP=/system/go",
@@ -127,8 +127,8 @@ sed -i \
) )
go125 := t.newGo( go125 := t.newGo(
"1.25.9", "1.25.7",
"gShJb9uOMk5AxqPSwvn53ZO56S6PyP6nfojzrHUiJ3krAvrgjJpYa6-DPA-jxbpN", "fyylHdBVRUobnBjYj3NKBaYPUw3kGmo2mEELiZonOYurPfbarNU1x77B99Fjut7Q",
[]string{"CGO_ENABLED=0"}, ` []string{"CGO_ENABLED=0"}, `
sed -i \ sed -i \
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \ 's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
@@ -156,9 +156,7 @@ sed -i \
internal/runtime/gc/scan/scan_amd64.go internal/runtime/gc/scan/scan_amd64.go
rm \ rm \
os/root_unix_test.go \ os/root_unix_test.go
cmd/cgo/internal/testsanitizers/tsan_test.go \
cmd/cgo/internal/testsanitizers/cshared_test.go
`, go125, `, go125,
), version ), version
} }
-1
View File
@@ -28,7 +28,6 @@ var (
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
rosa.DropCaches(rosa.OptLLVMNoLTO)
container.TryArgv0(nil) container.TryArgv0(nil)
code := m.Run() code := m.Run()
+1 -7
View File
@@ -27,14 +27,8 @@ chmod -R +w ..
sed -i \ sed -i \
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \ 's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
cmd/link/internal/`+runtime.GOARCH+`/obj.go cmd/link/internal/`+runtime.GOARCH+`/obj.go
sed -i \
's/cpu.X86.HasAVX512VBMI/& \&\& cpu.X86.HasPOPCNT/' \
internal/runtime/gc/scan/scan_amd64.go
rm \ rm \
os/root_unix_test.go \ os/root_unix_test.go
cmd/cgo/internal/testsanitizers/tsan_test.go \
cmd/cgo/internal/testsanitizers/cshared_test.go
./all.bash ./all.bash
`, pkg.Path(AbsUsrSrc.Append("tamago"), false, newFromGitHub( `, pkg.Path(AbsUsrSrc.Append("tamago"), false, newFromGitHub(