39 Commits

Author SHA1 Message Date
mae
689605ea67 cmd/pkgserver: update 2026-05-01 19:21:38 +09:00
mae
3306350ff2 cmd/pkgserver: fix gitignore 2026-05-01 19:21:38 +09:00
mae
b34baa0d1c cmd/pkgserver: better no results handling 2026-05-01 19:21:38 +09:00
mae
f692738354 cmd/pkgserver: better no results handling 2026-05-01 19:21:38 +09:00
mae
93fcfbcc64 cmd/pkgserver: finish search implementation 2026-05-01 19:21:38 +09:00
mae
8c9de5916d cmd/pkgserver: remove get endpoint count field 2026-05-01 19:21:37 +09:00
mae
1eee301e3a cmd/pkgserver: search endpoint 2026-05-01 19:21:37 +09:00
mae
402716b610 cmd/pkgserver: pagination bugfix 2026-05-01 19:21:37 +09:00
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
mae
9cf82d9521 cmd/pkgserver: add size 2026-05-01 19:21:37 +09:00
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
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
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
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
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
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
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
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
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
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
a6f9fe7981 cmd/pkgserver: do not omit report field
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
25d6b85aef cmd/pkgserver: gracefully shut down on signal
Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-05-01 19:21:37 +09:00
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
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
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
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
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
mae
6f58938615 cmd/pkgserver: add sort orders, change pagination rules 2026-05-01 19:21:37 +09:00
mae
dd511b0a19 cmd/pkgserver: add /status endpoint 2026-05-01 19:21:37 +09:00
mae
6f13b21403 cmd/pkgserver: minimum viable frontend 2026-05-01 19:21:37 +09:00
mae
251d312597 cmd/pkgserver: api versioning 2026-05-01 19:21:37 +09:00
mae
e7ace18573 cmd/pkgserver: add get endpoint 2026-05-01 19:21:37 +09:00
mae
24a859ac2c cmd/pkgserver: add count endpoint and restructure 2026-05-01 19:21:37 +09:00
mae
29320d3387 cmd/pkgserver: add status endpoint 2026-05-01 19:21:37 +09:00
mae
c537403257 cmd/pkgserver: add createPackageIndex 2026-05-01 19:21:37 +09:00
mae
035fa01a3b cmd/pkgserver: add command handler 2026-05-01 19:21:37 +09:00
mae
09fd010912 cmd/pkgserver: replace favicon 2026-05-01 19:21:37 +09:00
mae
7094c9219f cmd/pkgserver: pagination 2026-05-01 19:21:37 +09:00
mae
237183740c cmd/pkgserver: basic web ui 2026-05-01 19:21:37 +09:00
26 changed files with 219 additions and 311 deletions

2
.gitignore vendored
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

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 {

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)
} }

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)))
}

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
}
}()

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),

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)
}
})
}
}

View File

@@ -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) {

View File

@@ -1,4 +1,4 @@
package pkgserver package main
import ( import (
"net/http" "net/http"
@@ -118,9 +118,11 @@ 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) &&
slices.EqualFunc(got.Values, want, func(a, b *metadata) bool {
return (a.Version == b.Version || return (a.Version == b.Version ||
a.Version == rosa.Unversioned || a.Version == rosa.Unversioned ||
b.Version == rosa.Unversioned) && b.Version == rosa.Unversioned) &&
@@ -134,15 +136,15 @@ func TestAPIGet(t *testing.T) {
}) })
} }
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{
{ {

View File

@@ -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
cmd/pkgserver/main.go Normal file
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)
})
}

View File

@@ -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

View File

@@ -1,4 +1,4 @@
package pkgserver package main
import ( import (
"cmp" "cmp"

33
cmd/pkgserver/ui.go Normal file
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)
}

View File

@@ -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
cmd/pkgserver/ui_full.go Normal file
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

View File

@@ -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

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,

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)
}
})
}
}

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
} }

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()

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(