forked from rosa/hakurei
Compare commits
31 Commits
689605ea67
...
v0.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
337bf20f50
|
|||
|
1cb792cf6e
|
|||
|
b2b40b07e8
|
|||
|
da11b26ec1
|
|||
|
024489e800
|
|||
|
0f795712b0
|
|||
|
7e2210ff71
|
|||
|
a71a008f3c
|
|||
|
162265b47e
|
|||
|
3fa7ac04e4
|
|||
|
bf2867d653
|
|||
|
ec0f0f6507
|
|||
|
a77a802955
|
|||
|
4407e14dfc
|
|||
|
e024d3184a
|
|||
|
8e1bf00c2d
|
|||
|
b111e22050
|
|||
|
1fa458c0be
|
|||
|
2c7ae67a67
|
|||
|
3826621b21
|
|||
|
041b505c2e
|
|||
|
e6debce649
|
|||
|
aa26b86fce
|
|||
|
a57a8fd5d8
|
|||
|
1d5d063d6a
|
|||
|
e61628a34e
|
|||
|
5a18f14929
|
|||
|
f12880688d
|
|||
|
bb5bbfe16a
|
|||
|
427e1ca37c
|
|||
|
96fdd9ecc5
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,7 +7,7 @@
|
||||
|
||||
# go generate
|
||||
/cmd/hakurei/LICENSE
|
||||
/cmd/pkgserver/ui/static/*.js
|
||||
/cmd/mbf/internal/pkgserver/ui/static
|
||||
/internal/pkg/testdata/testtool
|
||||
/internal/rosa/hakurei_current.tar.gz
|
||||
|
||||
|
||||
8
all.sh
8
all.sh
@@ -2,5 +2,9 @@
|
||||
|
||||
TOOLCHAIN_VERSION="$(go version)"
|
||||
cd "$(dirname -- "$0")/"
|
||||
echo "# Building cmd/dist using ${TOOLCHAIN_VERSION}."
|
||||
go run -v --tags=dist ./cmd/dist
|
||||
echo "Building cmd/dist using ${TOOLCHAIN_VERSION}."
|
||||
FLAGS=''
|
||||
if test -n "$VERBOSE"; then
|
||||
FLAGS="$FLAGS -v"
|
||||
fi
|
||||
go run $FLAGS --tags=dist ./cmd/dist
|
||||
|
||||
@@ -4,15 +4,23 @@ import "strings"
|
||||
|
||||
const (
|
||||
// SpecialOverlayEscape is the escape string for overlay mount options.
|
||||
//
|
||||
// Deprecated: This is no longer used and will be removed in 0.5.
|
||||
SpecialOverlayEscape = `\`
|
||||
// SpecialOverlayOption is the separator string between overlay mount options.
|
||||
//
|
||||
// Deprecated: This is no longer used and will be removed in 0.5.
|
||||
SpecialOverlayOption = ","
|
||||
// SpecialOverlayPath is the separator string between overlay paths.
|
||||
//
|
||||
// Deprecated: This is no longer used and will be removed in 0.5.
|
||||
SpecialOverlayPath = ":"
|
||||
)
|
||||
|
||||
// EscapeOverlayDataSegment escapes a string for formatting into the data
|
||||
// argument of an overlay mount system call.
|
||||
//
|
||||
// Deprecated: This is no longer used and will be removed in 0.5.
|
||||
func EscapeOverlayDataSegment(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
|
||||
27
cmd/dist/main.go
vendored
27
cmd/dist/main.go
vendored
@@ -42,14 +42,18 @@ func mustRun(ctx context.Context, name string, arg ...string) {
|
||||
var comp []byte
|
||||
|
||||
func main() {
|
||||
fmt.Println()
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("# ")
|
||||
log.SetPrefix("")
|
||||
|
||||
verbose := os.Getenv("VERBOSE") != ""
|
||||
version := getenv("HAKUREI_VERSION", "untagged")
|
||||
prefix := getenv("PREFIX", "/usr")
|
||||
destdir := getenv("DESTDIR", "dist")
|
||||
|
||||
if verbose {
|
||||
log.Println()
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(destdir, 0755); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -76,12 +80,17 @@ func main() {
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
defer cancel()
|
||||
|
||||
log.Println("Building hakurei.")
|
||||
verboseFlag := "-v"
|
||||
if !verbose {
|
||||
verboseFlag = "-buildvcs=false"
|
||||
}
|
||||
|
||||
log.Printf("Building hakurei for %s/%s.", runtime.GOOS, runtime.GOARCH)
|
||||
mustRun(ctx, "go", "generate", "./...")
|
||||
mustRun(
|
||||
ctx, "go", "build",
|
||||
"-trimpath",
|
||||
"-v", "-o", s,
|
||||
verboseFlag, "-o", s,
|
||||
"-ldflags=-s -w "+
|
||||
"-buildid= -linkmode external -extldflags=-static "+
|
||||
"-X hakurei.app/internal/info.buildVersion="+version+" "+
|
||||
@@ -90,17 +99,17 @@ func main() {
|
||||
"-X main.hakureiPath="+prefix+"/bin/hakurei",
|
||||
"./...",
|
||||
)
|
||||
fmt.Println()
|
||||
log.Println()
|
||||
|
||||
log.Println("Testing Hakurei.")
|
||||
log.Println("##### Testing Hakurei.")
|
||||
mustRun(
|
||||
ctx, "go", "test",
|
||||
"-ldflags=-buildid= -linkmode external -extldflags=-static",
|
||||
"./...",
|
||||
)
|
||||
fmt.Println()
|
||||
log.Println()
|
||||
|
||||
log.Println("Creating distribution.")
|
||||
log.Println("##### Creating distribution.")
|
||||
const suffix = ".tar.gz"
|
||||
distName := "hakurei-" + version + "-" + runtime.GOARCH
|
||||
var f *os.File
|
||||
@@ -121,7 +130,7 @@ func main() {
|
||||
}()
|
||||
|
||||
h := sha512.New()
|
||||
gw := gzip.NewWriter(io.MultiWriter(f, h))
|
||||
gw, _ := gzip.NewWriterLevel(io.MultiWriter(f, h), gzip.BestCompression)
|
||||
tw := tar.NewWriter(gw)
|
||||
|
||||
mustWriteHeader := func(name string, size int64, mode os.FileMode) {
|
||||
|
||||
@@ -17,25 +17,12 @@ func commandInfo(
|
||||
args []string,
|
||||
w io.Writer,
|
||||
writeStatus bool,
|
||||
reportPath string,
|
||||
r *rosa.Report,
|
||||
) (err error) {
|
||||
if len(args) == 0 {
|
||||
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
|
||||
mustPrintln := func(a ...any) {
|
||||
if _, _err := fmt.Fprintln(w, a...); _err != nil {
|
||||
|
||||
@@ -95,7 +95,7 @@ status : not in report
|
||||
var (
|
||||
cm *cache
|
||||
buf strings.Builder
|
||||
rp string
|
||||
r *rosa.Report
|
||||
)
|
||||
|
||||
if tc.status != nil || tc.report != "" {
|
||||
@@ -108,14 +108,25 @@ status : not in report
|
||||
}
|
||||
|
||||
if tc.report != "" {
|
||||
rp = filepath.Join(t.TempDir(), "report")
|
||||
if err := os.WriteFile(
|
||||
rp,
|
||||
pathname := filepath.Join(t.TempDir(), "report")
|
||||
err := os.WriteFile(
|
||||
pathname,
|
||||
unsafe.Slice(unsafe.StringData(tc.report), len(tc.report)),
|
||||
0400,
|
||||
); err != nil {
|
||||
)
|
||||
if err != nil {
|
||||
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 {
|
||||
@@ -157,7 +168,7 @@ status : not in report
|
||||
tc.args,
|
||||
&buf,
|
||||
cm != nil,
|
||||
rp,
|
||||
r,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Fatalf("commandInfo: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package main
|
||||
// Package pkgserver implements the package metadata service backend.
|
||||
package pkgserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -8,6 +10,7 @@ import (
|
||||
"path"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"hakurei.app/internal/info"
|
||||
"hakurei.app/internal/rosa"
|
||||
@@ -158,6 +161,29 @@ func (index *packageIndex) registerAPI(mux *http.ServeMux) {
|
||||
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
|
||||
// JSON for the response body.
|
||||
func writeAPIPayload(w http.ResponseWriter, payload any) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package pkgserver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
@@ -118,33 +118,31 @@ func TestAPIGet(t *testing.T) {
|
||||
checkStatus(t, resp, http.StatusOK)
|
||||
checkAPIHeader(t, w.Header())
|
||||
checkPayloadFunc(t, resp, func(got *struct {
|
||||
Count int `json:"count"`
|
||||
Values []*metadata `json:"values"`
|
||||
}) bool {
|
||||
return got.Count == len(want) &&
|
||||
slices.EqualFunc(got.Values, want, func(a, b *metadata) bool {
|
||||
return (a.Version == b.Version ||
|
||||
a.Version == rosa.Unversioned ||
|
||||
b.Version == rosa.Unversioned) &&
|
||||
a.HasReport == b.HasReport &&
|
||||
a.Name == b.Name &&
|
||||
a.Description == b.Description &&
|
||||
a.Website == b.Website
|
||||
})
|
||||
return slices.EqualFunc(got.Values, want, func(a, b *metadata) bool {
|
||||
return (a.Version == b.Version ||
|
||||
a.Version == rosa.Unversioned ||
|
||||
b.Version == rosa.Unversioned) &&
|
||||
a.HasReport == b.HasReport &&
|
||||
a.Name == b.Name &&
|
||||
a.Description == b.Description &&
|
||||
a.Website == b.Website
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
checkWithSuffix("declarationAscending", "?limit=2&index=0&sort=0", []*metadata{
|
||||
{
|
||||
Metadata: rosa.GetMetadata(0),
|
||||
Version: rosa.Std.Version(0),
|
||||
},
|
||||
checkWithSuffix("declarationAscending", "?limit=2&index=1&sort=0", []*metadata{
|
||||
{
|
||||
Metadata: rosa.GetMetadata(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{
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package pkgserver
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
@@ -50,7 +50,7 @@ type metadata struct {
|
||||
}
|
||||
|
||||
// populate deterministically populates packageIndex, optionally with a report.
|
||||
func (index *packageIndex) populate(cache *pkg.Cache, report *rosa.Report) (err error) {
|
||||
func (index *packageIndex) populate(report *rosa.Report) (err error) {
|
||||
if report != nil {
|
||||
defer report.HandleAccess(&err)()
|
||||
index.handleAccess = report.HandleAccess
|
||||
@@ -58,6 +58,7 @@ func (index *packageIndex) populate(cache *pkg.Cache, report *rosa.Report) (err
|
||||
|
||||
var work [rosa.PresetUnexportedStart]*metadata
|
||||
index.names = make(map[string]*metadata)
|
||||
ir := pkg.NewIR()
|
||||
for p := range rosa.PresetUnexportedStart {
|
||||
m := metadata{
|
||||
p: p,
|
||||
@@ -72,8 +73,8 @@ func (index *packageIndex) populate(cache *pkg.Cache, report *rosa.Report) (err
|
||||
m.Version = ""
|
||||
}
|
||||
|
||||
if cache != nil && report != nil {
|
||||
id := cache.Ident(rosa.Std.Load(p))
|
||||
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
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package pkgserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -15,7 +15,7 @@ func newIndex(t *testing.T) *packageIndex {
|
||||
t.Helper()
|
||||
|
||||
var index packageIndex
|
||||
if err := index.populate(nil, nil); err != nil {
|
||||
if err := index.populate(nil); err != nil {
|
||||
t.Fatalf("populate: error = %v", err)
|
||||
}
|
||||
return &index
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package pkgserver
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
@@ -3,9 +3,9 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="static/style.css">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>Hakurei PkgServer</title>
|
||||
<script src="static/index.js"></script>
|
||||
<script src="index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hakurei PkgServer</h1>
|
||||
9
cmd/mbf/internal/pkgserver/ui/ui.go
Normal file
9
cmd/mbf/internal/pkgserver/ui/ui.go
Normal file
@@ -0,0 +1,9 @@
|
||||
// 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
cmd/mbf/internal/pkgserver/ui/ui_full.go
Normal file
21
cmd/mbf/internal/pkgserver/ui/ui_full.go
Normal file
@@ -0,0 +1,21 @@
|
||||
//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
|
||||
}
|
||||
}()
|
||||
@@ -1,7 +1,7 @@
|
||||
//go:build !frontend
|
||||
|
||||
package main
|
||||
package ui
|
||||
|
||||
import "testing/fstest"
|
||||
|
||||
var content fstest.MapFS
|
||||
var static fstest.MapFS
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
@@ -41,6 +42,9 @@ import (
|
||||
"hakurei.app/internal/pkg"
|
||||
"hakurei.app/internal/rosa"
|
||||
"hakurei.app/message"
|
||||
|
||||
"hakurei.app/cmd/mbf/internal/pkgserver"
|
||||
"hakurei.app/cmd/mbf/internal/pkgserver/ui"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -136,7 +140,17 @@ func main() {
|
||||
c.NewCommand(
|
||||
"checksum", "Compute checksum of data read from standard input",
|
||||
func([]string) error {
|
||||
go func() { <-ctx.Done(); os.Exit(1) }()
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
os.Exit(1)
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
h := sha512.New384()
|
||||
if _, err := io.Copy(h, os.Stdin); err != nil {
|
||||
return err
|
||||
@@ -170,6 +184,7 @@ func main() {
|
||||
|
||||
{
|
||||
var (
|
||||
flagBind string
|
||||
flagStatus bool
|
||||
flagReport string
|
||||
)
|
||||
@@ -177,8 +192,52 @@ func main() {
|
||||
"info",
|
||||
"Display out-of-band metadata of an artifact",
|
||||
func(args []string) (err error) {
|
||||
return commandInfo(&cm, args, os.Stdout, flagStatus, flagReport)
|
||||
const shutdownTimeout = 15 * time.Second
|
||||
|
||||
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(
|
||||
&flagStatus,
|
||||
"status", command.BoolFlag(false),
|
||||
@@ -412,6 +471,9 @@ func main() {
|
||||
flagExport string
|
||||
flagRemote bool
|
||||
flagNoReply bool
|
||||
|
||||
flagBoot bool
|
||||
flagStd bool
|
||||
)
|
||||
c.NewCommand(
|
||||
"cure",
|
||||
@@ -425,11 +487,18 @@ func main() {
|
||||
return fmt.Errorf("unknown artifact %q", args[0])
|
||||
}
|
||||
|
||||
t := rosa.Std
|
||||
if flagBoot {
|
||||
t -= 2
|
||||
} else if flagStd {
|
||||
t -= 1
|
||||
}
|
||||
|
||||
switch {
|
||||
default:
|
||||
var pathname *check.Absolute
|
||||
err := cm.Do(func(cache *pkg.Cache) (err error) {
|
||||
pathname, _, err = cache.Cure(rosa.Std.Load(p))
|
||||
pathname, _, err = cache.Cure(t.Load(p))
|
||||
return
|
||||
})
|
||||
if err != nil {
|
||||
@@ -482,7 +551,7 @@ func main() {
|
||||
return cm.Do(func(cache *pkg.Cache) error {
|
||||
return cache.EnterExec(
|
||||
ctx,
|
||||
rosa.Std.Load(p),
|
||||
t.Load(p),
|
||||
true, os.Stdin, os.Stdout, os.Stderr,
|
||||
rosa.AbsSystem.Append("bin", "mksh"),
|
||||
"sh",
|
||||
@@ -494,7 +563,7 @@ func main() {
|
||||
if flagNoReply {
|
||||
flags |= remoteNoReply
|
||||
}
|
||||
a := rosa.Std.Load(p)
|
||||
a := t.Load(p)
|
||||
pathname, err := cureRemote(ctx, &addr, a, flags)
|
||||
if !flagNoReply && err == nil {
|
||||
log.Println(pathname)
|
||||
@@ -532,6 +601,14 @@ func main() {
|
||||
&flagNoReply,
|
||||
"no-reply", command.BoolFlag(false),
|
||||
"Do not receive a reply from the daemon",
|
||||
).Flag(
|
||||
&flagBoot,
|
||||
"boot", command.BoolFlag(false),
|
||||
"Build on the stage0 toolchain",
|
||||
).Flag(
|
||||
&flagStd,
|
||||
"std", command.BoolFlag(false),
|
||||
"Build on the intermediate toolchain",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
47
cmd/mbf/main_test.go
Normal file
47
cmd/mbf/main_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
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,114 +0,0 @@
|
||||
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,33 +0,0 @@
|
||||
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)
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
@@ -1,9 +0,0 @@
|
||||
//go:build frontend
|
||||
|
||||
package main
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:generate tsc -p ui
|
||||
//go:embed ui/*
|
||||
var content embed.FS
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
_ "unsafe" // for go:linkname
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/command"
|
||||
@@ -233,6 +234,9 @@ func earlyMnt(mnt ...*vfs.MountInfoEntry) func(*testing.T, context.Context) []*v
|
||||
return func(*testing.T, context.Context) []*vfs.MountInfoEntry { return mnt }
|
||||
}
|
||||
|
||||
//go:linkname toHost hakurei.app/container.toHost
|
||||
func toHost(name string) string
|
||||
|
||||
var containerTestCases = []struct {
|
||||
name string
|
||||
filter bool
|
||||
@@ -332,13 +336,15 @@ var containerTestCases = []struct {
|
||||
func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry {
|
||||
return []*vfs.MountInfoEntry{
|
||||
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay",
|
||||
"rw,lowerdir="+
|
||||
container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*check.Absolute).String())+":"+
|
||||
container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
||||
"rw"+
|
||||
",lowerdir+="+
|
||||
toHost(ctx.Value(testVal("lower0")).(*check.Absolute).String())+
|
||||
",lowerdir+="+
|
||||
toHost(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
||||
",upperdir="+
|
||||
container.InternalToHostOvlEscape(ctx.Value(testVal("upper")).(*check.Absolute).String())+
|
||||
toHost(ctx.Value(testVal("upper")).(*check.Absolute).String())+
|
||||
",workdir="+
|
||||
container.InternalToHostOvlEscape(ctx.Value(testVal("work")).(*check.Absolute).String())+
|
||||
toHost(ctx.Value(testVal("work")).(*check.Absolute).String())+
|
||||
",redirect_dir=nofollow,uuid=on,userxattr"),
|
||||
}
|
||||
},
|
||||
@@ -388,9 +394,11 @@ var containerTestCases = []struct {
|
||||
func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry {
|
||||
return []*vfs.MountInfoEntry{
|
||||
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay",
|
||||
"ro,lowerdir="+
|
||||
container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*check.Absolute).String())+":"+
|
||||
container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
||||
"ro"+
|
||||
",lowerdir+="+
|
||||
toHost(ctx.Value(testVal("lower0")).(*check.Absolute).String())+
|
||||
",lowerdir+="+
|
||||
toHost(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
||||
",redirect_dir=nofollow,userxattr"),
|
||||
}
|
||||
},
|
||||
|
||||
@@ -65,6 +65,8 @@ type syscallDispatcher interface {
|
||||
remount(msg message.Msg, target string, flags uintptr) error
|
||||
// mountTmpfs provides mountTmpfs.
|
||||
mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error
|
||||
// mountOverlay provides mountOverlay.
|
||||
mountOverlay(target string, options [][2]string) error
|
||||
// ensureFile provides ensureFile.
|
||||
ensureFile(name string, perm, pperm os.FileMode) error
|
||||
// mustLoopback provides mustLoopback.
|
||||
@@ -169,6 +171,9 @@ func (direct) remount(msg message.Msg, target string, flags uintptr) error {
|
||||
func (k direct) mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error {
|
||||
return mountTmpfs(k, fsname, target, flags, size, perm)
|
||||
}
|
||||
func (k direct) mountOverlay(target string, options [][2]string) error {
|
||||
return mountOverlay(target, options)
|
||||
}
|
||||
func (direct) ensureFile(name string, perm, pperm os.FileMode) error {
|
||||
return ensureFile(name, perm, pperm)
|
||||
}
|
||||
|
||||
@@ -468,6 +468,14 @@ func (k *kstub) mountTmpfs(fsname, target string, flags uintptr, size int, perm
|
||||
stub.CheckArg(k.Stub, "perm", perm, 4))
|
||||
}
|
||||
|
||||
func (k *kstub) mountOverlay(target string, options [][2]string) error {
|
||||
k.Helper()
|
||||
return k.Expects("mountOverlay").Error(
|
||||
stub.CheckArg(k.Stub, "target", target, 0),
|
||||
stub.CheckArgReflect(k.Stub, "options", options, 1),
|
||||
)
|
||||
}
|
||||
|
||||
func (k *kstub) ensureFile(name string, perm, pperm os.FileMode) error {
|
||||
k.Helper()
|
||||
return k.Expects("ensureFile").Error(
|
||||
|
||||
@@ -118,6 +118,10 @@ func errnoFallback(op, path string, err error) (syscall.Errno, *os.PathError) {
|
||||
|
||||
// mount wraps syscall.Mount for error handling.
|
||||
func mount(source, target, fstype string, flags uintptr, data string) error {
|
||||
if max(len(source), len(target), len(data))+1 > os.Getpagesize() {
|
||||
return &MountError{source, target, fstype, flags, data, syscall.ENOMEM}
|
||||
}
|
||||
|
||||
err := syscall.Mount(source, target, fstype, flags, data)
|
||||
if err == nil {
|
||||
return nil
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/ext"
|
||||
"hakurei.app/fhs"
|
||||
)
|
||||
|
||||
@@ -150,7 +150,7 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error {
|
||||
if v, err := k.evalSymlinks(o.Upper.String()); err != nil {
|
||||
return err
|
||||
} else {
|
||||
o.upper = check.EscapeOverlayDataSegment(toHost(v))
|
||||
o.upper = toHost(v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error {
|
||||
if v, err := k.evalSymlinks(o.Work.String()); err != nil {
|
||||
return err
|
||||
} else {
|
||||
o.work = check.EscapeOverlayDataSegment(toHost(v))
|
||||
o.work = toHost(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,12 +168,39 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error {
|
||||
if v, err := k.evalSymlinks(a.String()); err != nil {
|
||||
return err
|
||||
} else {
|
||||
o.lower[i] = check.EscapeOverlayDataSegment(toHost(v))
|
||||
o.lower[i] = toHost(v)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mountOverlay sets up an overlay mount via [ext.FS].
|
||||
func mountOverlay(target string, options [][2]string) error {
|
||||
fs, err := ext.OpenFS(SourceOverlay, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = fs.SetString("source", SourceOverlay); err != nil {
|
||||
_ = fs.Close()
|
||||
return err
|
||||
}
|
||||
for _, option := range options {
|
||||
if err = fs.SetString(option[0], option[1]); err != nil {
|
||||
_ = fs.Close()
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = fs.SetFlag(OptionOverlayUserxattr); err != nil {
|
||||
_ = fs.Close()
|
||||
return err
|
||||
}
|
||||
if err = fs.Mount(target, 0); err != nil {
|
||||
_ = fs.Close()
|
||||
return err
|
||||
}
|
||||
return fs.Close()
|
||||
}
|
||||
|
||||
func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
target := o.Target.String()
|
||||
if !o.noPrefix {
|
||||
@@ -194,7 +221,7 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
}
|
||||
}
|
||||
|
||||
options := make([]string, 0, 4)
|
||||
options := make([][2]string, 0, 2+len(o.lower))
|
||||
|
||||
if o.upper == zeroString && o.work == zeroString { // readonly
|
||||
if len(o.Lower) < 2 {
|
||||
@@ -205,15 +232,16 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
if len(o.Lower) == 0 {
|
||||
return &OverlayArgumentError{OverlayEmptyLower, zeroString}
|
||||
}
|
||||
options = append(options,
|
||||
OptionOverlayUpperdir+"="+o.upper,
|
||||
OptionOverlayWorkdir+"="+o.work)
|
||||
options = append(options, [][2]string{
|
||||
{OptionOverlayUpperdir, o.upper},
|
||||
{OptionOverlayWorkdir, o.work},
|
||||
}...)
|
||||
}
|
||||
for _, lower := range o.lower {
|
||||
options = append(options, [2]string{OptionOverlayLowerdir + "+", lower})
|
||||
}
|
||||
options = append(options,
|
||||
OptionOverlayLowerdir+"="+strings.Join(o.lower, check.SpecialOverlayPath),
|
||||
OptionOverlayUserxattr)
|
||||
|
||||
return k.mount(SourceOverlay, target, FstypeOverlay, 0, strings.Join(options, check.SpecialOverlayOption))
|
||||
return k.mountOverlay(target, options)
|
||||
}
|
||||
|
||||
func (o *MountOverlayOp) late(*setupState, syscallDispatcher) error { return nil }
|
||||
|
||||
@@ -97,13 +97,12 @@ func TestMountOverlayOp(t *testing.T) {
|
||||
call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0705)}, nil, nil),
|
||||
call("mkdirTemp", stub.ExpectArgs{"/", "overlay.upper.*"}, "overlay.upper.32768", nil),
|
||||
call("mkdirTemp", stub.ExpectArgs{"/", "overlay.work.*"}, "overlay.work.32768", nil),
|
||||
call("mount", stub.ExpectArgs{"overlay", "/sysroot", "overlay", uintptr(0), "" +
|
||||
"upperdir=overlay.upper.32768," +
|
||||
"workdir=overlay.work.32768," +
|
||||
"lowerdir=" +
|
||||
`/host/var/lib/planterette/base/debian\:f92c9052:` +
|
||||
`/host/var/lib/planterette/app/org.chromium.Chromium@debian\:f92c9052,` +
|
||||
"userxattr"}, nil, nil),
|
||||
call("mountOverlay", stub.ExpectArgs{"/sysroot", [][2]string{
|
||||
{"upperdir", "overlay.upper.32768"},
|
||||
{"workdir", "overlay.work.32768"},
|
||||
{"lowerdir+", `/host/var/lib/planterette/base/debian:f92c9052`},
|
||||
{"lowerdir+", `/host/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052`},
|
||||
}}, nil, nil),
|
||||
}, nil},
|
||||
|
||||
{"short lower ro", &Params{ParentPerm: 0755}, &MountOverlayOp{
|
||||
@@ -129,11 +128,10 @@ func TestMountOverlayOp(t *testing.T) {
|
||||
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil),
|
||||
}, nil, []stub.Call{
|
||||
call("mkdirAll", stub.ExpectArgs{"/nix/store", os.FileMode(0755)}, nil, nil),
|
||||
call("mount", stub.ExpectArgs{"overlay", "/nix/store", "overlay", uintptr(0), "" +
|
||||
"lowerdir=" +
|
||||
"/host/mnt-root/nix/.ro-store:" +
|
||||
"/host/mnt-root/nix/.ro-store0," +
|
||||
"userxattr"}, nil, nil),
|
||||
call("mountOverlay", stub.ExpectArgs{"/nix/store", [][2]string{
|
||||
{"lowerdir+", "/host/mnt-root/nix/.ro-store"},
|
||||
{"lowerdir+", "/host/mnt-root/nix/.ro-store0"},
|
||||
}}, nil, nil),
|
||||
}, nil},
|
||||
|
||||
{"success ro", &Params{ParentPerm: 0755}, &MountOverlayOp{
|
||||
@@ -147,11 +145,10 @@ func TestMountOverlayOp(t *testing.T) {
|
||||
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil),
|
||||
}, nil, []stub.Call{
|
||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0755)}, nil, nil),
|
||||
call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
||||
"lowerdir=" +
|
||||
"/host/mnt-root/nix/.ro-store:" +
|
||||
"/host/mnt-root/nix/.ro-store0," +
|
||||
"userxattr"}, nil, nil),
|
||||
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
||||
{"lowerdir+", "/host/mnt-root/nix/.ro-store"},
|
||||
{"lowerdir+", "/host/mnt-root/nix/.ro-store0"},
|
||||
}}, nil, nil),
|
||||
}, nil},
|
||||
|
||||
{"nil lower", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
@@ -219,7 +216,11 @@ func TestMountOverlayOp(t *testing.T) {
|
||||
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil),
|
||||
}, nil, []stub.Call{
|
||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
||||
call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "upperdir=/host/mnt-root/nix/.rw-store/.upper,workdir=/host/mnt-root/nix/.rw-store/.work,lowerdir=/host/mnt-root/nix/ro-store,userxattr"}, nil, stub.UniqueError(0)),
|
||||
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
||||
{"upperdir", "/host/mnt-root/nix/.rw-store/.upper"},
|
||||
{"workdir", "/host/mnt-root/nix/.rw-store/.work"},
|
||||
{"lowerdir+", "/host/mnt-root/nix/ro-store"},
|
||||
}}, nil, stub.UniqueError(0)),
|
||||
}, stub.UniqueError(0)},
|
||||
|
||||
{"success single layer", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
@@ -233,11 +234,11 @@ func TestMountOverlayOp(t *testing.T) {
|
||||
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil),
|
||||
}, nil, []stub.Call{
|
||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
||||
call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
||||
"upperdir=/host/mnt-root/nix/.rw-store/.upper," +
|
||||
"workdir=/host/mnt-root/nix/.rw-store/.work," +
|
||||
"lowerdir=/host/mnt-root/nix/ro-store," +
|
||||
"userxattr"}, nil, nil),
|
||||
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
||||
{"upperdir", "/host/mnt-root/nix/.rw-store/.upper"},
|
||||
{"workdir", "/host/mnt-root/nix/.rw-store/.work"},
|
||||
{"lowerdir+", "/host/mnt-root/nix/ro-store"},
|
||||
}}, nil, nil),
|
||||
}, nil},
|
||||
|
||||
{"success", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||
@@ -261,16 +262,15 @@ func TestMountOverlayOp(t *testing.T) {
|
||||
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store3"}, "/mnt-root/nix/ro-store3", nil),
|
||||
}, nil, []stub.Call{
|
||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
||||
call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
||||
"upperdir=/host/mnt-root/nix/.rw-store/.upper," +
|
||||
"workdir=/host/mnt-root/nix/.rw-store/.work," +
|
||||
"lowerdir=" +
|
||||
"/host/mnt-root/nix/ro-store:" +
|
||||
"/host/mnt-root/nix/ro-store0:" +
|
||||
"/host/mnt-root/nix/ro-store1:" +
|
||||
"/host/mnt-root/nix/ro-store2:" +
|
||||
"/host/mnt-root/nix/ro-store3," +
|
||||
"userxattr"}, nil, nil),
|
||||
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
||||
{"upperdir", "/host/mnt-root/nix/.rw-store/.upper"},
|
||||
{"workdir", "/host/mnt-root/nix/.rw-store/.work"},
|
||||
{"lowerdir+", "/host/mnt-root/nix/ro-store"},
|
||||
{"lowerdir+", "/host/mnt-root/nix/ro-store0"},
|
||||
{"lowerdir+", "/host/mnt-root/nix/ro-store1"},
|
||||
{"lowerdir+", "/host/mnt-root/nix/ro-store2"},
|
||||
{"lowerdir+", "/host/mnt-root/nix/ro-store3"},
|
||||
}}, nil, nil),
|
||||
}, nil},
|
||||
})
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/vfs"
|
||||
)
|
||||
|
||||
@@ -50,9 +49,6 @@ func TestToHost(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// InternalToHostOvlEscape exports toHost passed to [check.EscapeOverlayDataSegment].
|
||||
func InternalToHostOvlEscape(s string) string { return check.EscapeOverlayDataSegment(toHost(s)) }
|
||||
|
||||
func TestCreateFile(t *testing.T) {
|
||||
t.Run("nonexistent", func(t *testing.T) {
|
||||
t.Run("mkdir", func(t *testing.T) {
|
||||
|
||||
267
ext/fs.go
Normal file
267
ext/fs.go
Normal file
@@ -0,0 +1,267 @@
|
||||
package ext
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// include/uapi/linux/mount.h
|
||||
|
||||
/*
|
||||
* move_mount() flags.
|
||||
*/
|
||||
const (
|
||||
MOVE_MOUNT_F_SYMLINKS = 1 << iota /* Follow symlinks on from path */
|
||||
MOVE_MOUNT_F_AUTOMOUNTS /* Follow automounts on from path */
|
||||
MOVE_MOUNT_F_EMPTY_PATH /* Empty from path permitted */
|
||||
_
|
||||
MOVE_MOUNT_T_SYMLINKS /* Follow symlinks on to path */
|
||||
MOVE_MOUNT_T_AUTOMOUNTS /* Follow automounts on to path */
|
||||
MOVE_MOUNT_T_EMPTY_PATH /* Empty to path permitted */
|
||||
_
|
||||
MOVE_MOUNT_SET_GROUP /* Set sharing group instead */
|
||||
MOVE_MOUNT_BENEATH /* Mount beneath top mount */
|
||||
)
|
||||
|
||||
/*
|
||||
* fsopen() flags.
|
||||
*/
|
||||
const (
|
||||
FSOPEN_CLOEXEC = 1 << iota
|
||||
)
|
||||
|
||||
/*
|
||||
* fspick() flags.
|
||||
*/
|
||||
const (
|
||||
FSPICK_CLOEXEC = 1 << iota
|
||||
FSPICK_SYMLINK_NOFOLLOW
|
||||
FSPICK_NO_AUTOMOUNT
|
||||
FSPICK_EMPTY_PATH
|
||||
)
|
||||
|
||||
/*
|
||||
* The type of fsconfig() call made.
|
||||
*/
|
||||
const (
|
||||
FSCONFIG_SET_FLAG = iota /* Set parameter, supplying no value */
|
||||
FSCONFIG_SET_STRING /* Set parameter, supplying a string value */
|
||||
FSCONFIG_SET_BINARY /* Set parameter, supplying a binary blob value */
|
||||
FSCONFIG_SET_PATH /* Set parameter, supplying an object by path */
|
||||
FSCONFIG_SET_PATH_EMPTY /* Set parameter, supplying an object by (empty) path */
|
||||
FSCONFIG_SET_FD /* Set parameter, supplying an object by fd */
|
||||
FSCONFIG_CMD_CREATE /* Create new or reuse existing superblock */
|
||||
FSCONFIG_CMD_RECONFIGURE /* Invoke superblock reconfiguration */
|
||||
FSCONFIG_CMD_CREATE_EXCL /* Create new superblock, fail if reusing existing superblock */
|
||||
)
|
||||
|
||||
/*
|
||||
* fsmount() flags.
|
||||
*/
|
||||
const (
|
||||
FSMOUNT_CLOEXEC = 1 << iota
|
||||
)
|
||||
|
||||
/*
|
||||
* Mount attributes.
|
||||
*/
|
||||
const (
|
||||
MOUNT_ATTR_RDONLY = 0x00000001 /* Mount read-only */
|
||||
MOUNT_ATTR_NOSUID = 0x00000002 /* Ignore suid and sgid bits */
|
||||
MOUNT_ATTR_NODEV = 0x00000004 /* Disallow access to device special files */
|
||||
MOUNT_ATTR_NOEXEC = 0x00000008 /* Disallow program execution */
|
||||
MOUNT_ATTR__ATIME = 0x00000070 /* Setting on how atime should be updated */
|
||||
MOUNT_ATTR_RELATIME = 0x00000000 /* - Update atime relative to mtime/ctime. */
|
||||
MOUNT_ATTR_NOATIME = 0x00000010 /* - Do not update access times. */
|
||||
MOUNT_ATTR_STRICTATIME = 0x00000020 /* - Always perform atime updates */
|
||||
MOUNT_ATTR_NODIRATIME = 0x00000080 /* Do not update directory access times */
|
||||
MOUNT_ATTR_IDMAP = 0x00100000 /* Idmap mount to @userns_fd in struct mount_attr. */
|
||||
MOUNT_ATTR_NOSYMFOLLOW = 0x00200000 /* Do not follow symlinks */
|
||||
)
|
||||
|
||||
// FS provides low-level wrappers around the suite of file-descriptor-based
|
||||
// mount facilities in Linux.
|
||||
type FS struct {
|
||||
fd uintptr
|
||||
c runtime.Cleanup
|
||||
}
|
||||
|
||||
// newFS allocates a new [FS] for the specified fd.
|
||||
func newFS(fd uintptr) *FS {
|
||||
fs := FS{fd: fd}
|
||||
fs.c = runtime.AddCleanup(&fs, func(fd uintptr) {
|
||||
_ = syscall.Close(int(fd))
|
||||
}, fd)
|
||||
return &fs
|
||||
}
|
||||
|
||||
// Close closes the underlying filesystem context.
|
||||
func (fs *FS) Close() error {
|
||||
if fs == nil {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
err := syscall.Close(int(fs.fd))
|
||||
fs.c.Stop()
|
||||
return err
|
||||
}
|
||||
|
||||
// OpenFS creates a new filesystem context.
|
||||
func OpenFS(fsname string, flags int) (fs *FS, err error) {
|
||||
var s *byte
|
||||
s, err = syscall.BytePtrFromString(fsname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fd, _, errno := syscall.Syscall(
|
||||
SYS_FSOPEN,
|
||||
uintptr(unsafe.Pointer(s)),
|
||||
uintptr(flags|FSOPEN_CLOEXEC),
|
||||
0,
|
||||
)
|
||||
if errno != 0 {
|
||||
err = os.NewSyscallError("fsopen", errno)
|
||||
} else {
|
||||
fs = newFS(fd)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PickFS selects filesystem for reconfiguration.
|
||||
func PickFS(dirfd int, pathname string, flags int) (fs *FS, err error) {
|
||||
var s *byte
|
||||
s, err = syscall.BytePtrFromString(pathname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fd, _, errno := syscall.Syscall(
|
||||
SYS_FSPICK,
|
||||
uintptr(dirfd),
|
||||
uintptr(unsafe.Pointer(s)),
|
||||
uintptr(flags|FSPICK_CLOEXEC),
|
||||
)
|
||||
if errno != 0 {
|
||||
err = os.NewSyscallError("fspick", errno)
|
||||
} else {
|
||||
fs = newFS(fd)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// config configures new or existing filesystem context.
|
||||
func (fs *FS) config(cmd uint, key *byte, value unsafe.Pointer, aux int) (err error) {
|
||||
_, _, errno := syscall.Syscall6(
|
||||
SYS_FSCONFIG,
|
||||
fs.fd,
|
||||
uintptr(cmd),
|
||||
uintptr(unsafe.Pointer(key)),
|
||||
uintptr(value),
|
||||
uintptr(aux),
|
||||
0,
|
||||
)
|
||||
if errno != 0 {
|
||||
err = os.NewSyscallError("fsconfig", errno)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SetFlag sets the flag parameter named by key. ([FSCONFIG_SET_FLAG])
|
||||
func (fs *FS) SetFlag(key string) (err error) {
|
||||
var s *byte
|
||||
s, err = syscall.BytePtrFromString(key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return fs.config(FSCONFIG_SET_FLAG, s, nil, 0)
|
||||
}
|
||||
|
||||
// SetString sets the string parameter named by key to the value specified by
|
||||
// value. ([FSCONFIG_SET_STRING])
|
||||
func (fs *FS) SetString(key, value string) (err error) {
|
||||
var s0 *byte
|
||||
s0, err = syscall.BytePtrFromString(key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var s1 *byte
|
||||
s1, err = syscall.BytePtrFromString(value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return fs.config(FSCONFIG_SET_STRING, s0, unsafe.Pointer(s1), 0)
|
||||
}
|
||||
|
||||
// mount instantiates mount object from filesystem context.
|
||||
func (fs *FS) mount(flags, attrFlags int) (fsfd int, err error) {
|
||||
r, _, errno := syscall.Syscall(
|
||||
SYS_FSMOUNT,
|
||||
fs.fd,
|
||||
uintptr(flags|FSMOUNT_CLOEXEC),
|
||||
uintptr(attrFlags),
|
||||
)
|
||||
fsfd = int(r)
|
||||
if errno != 0 {
|
||||
err = os.NewSyscallError("fsmount", errno)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MoveMount moves or attaches mount object to filesystem.
|
||||
func MoveMount(
|
||||
fromDirfd int,
|
||||
fromPathname string,
|
||||
toDirfd int,
|
||||
toPathname string,
|
||||
flags int,
|
||||
) (err error) {
|
||||
var s0 *byte
|
||||
s0, err = syscall.BytePtrFromString(fromPathname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var s1 *byte
|
||||
s1, err = syscall.BytePtrFromString(toPathname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, _, errno := syscall.Syscall6(
|
||||
SYS_MOVE_MOUNT,
|
||||
uintptr(fromDirfd),
|
||||
uintptr(unsafe.Pointer(s0)),
|
||||
uintptr(toDirfd),
|
||||
uintptr(unsafe.Pointer(s1)),
|
||||
uintptr(flags),
|
||||
0,
|
||||
)
|
||||
if errno != 0 {
|
||||
err = os.NewSyscallError("move_mount", errno)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Mount attaches the underlying filesystem context to the specified pathname.
|
||||
func (fs *FS) Mount(pathname string, attrFlags int) error {
|
||||
if err := fs.config(FSCONFIG_CMD_CREATE_EXCL, nil, nil, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
fd, err := fs.mount(0, attrFlags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = MoveMount(
|
||||
fd, "",
|
||||
-1, pathname,
|
||||
MOVE_MOUNT_F_EMPTY_PATH,
|
||||
)
|
||||
closeErr := syscall.Close(fd)
|
||||
if err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
return err
|
||||
}
|
||||
36
internal/pkg/testdata/main.go
vendored
36
internal/pkg/testdata/main.go
vendored
@@ -14,7 +14,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/vfs"
|
||||
)
|
||||
@@ -159,43 +158,24 @@ func main() {
|
||||
m.Source != "overlay" || m.FsType != "overlay" {
|
||||
log.Fatal("unexpected root mount entry")
|
||||
}
|
||||
var lowerdir string
|
||||
var lowerdir []string
|
||||
for _, o := range strings.Split(m.FsOptstr, ",") {
|
||||
const lowerdirKey = "lowerdir="
|
||||
const lowerdirKey = "lowerdir+="
|
||||
if strings.HasPrefix(o, lowerdirKey) {
|
||||
lowerdir = o[len(lowerdirKey):]
|
||||
lowerdir = append(lowerdir, o[len(lowerdirKey):])
|
||||
}
|
||||
}
|
||||
if !layers {
|
||||
if filepath.Base(lowerdir) != checksumEmptyDir {
|
||||
if len(lowerdir) != 1 || filepath.Base(lowerdir[0]) != checksumEmptyDir {
|
||||
log.Fatal("unexpected artifact checksum")
|
||||
}
|
||||
} else {
|
||||
ident = "p1t_drXr34i-jZNuxDMLaMOdL6tZvQqhavNafGynGqxOZoXAUTSn7kqNh3Ovv3DT"
|
||||
|
||||
lowerdirsEscaped := strings.Split(lowerdir, ":")
|
||||
lowerdirs := lowerdirsEscaped[:0]
|
||||
// ignore the option separator since it does not appear in ident
|
||||
for i, e := range lowerdirsEscaped {
|
||||
if len(e) > 0 &&
|
||||
e[len(e)-1] == check.SpecialOverlayEscape[0] &&
|
||||
(len(e) == 1 || e[len(e)-2] != check.SpecialOverlayEscape[0]) {
|
||||
// ignore escaped pathname separator since it does not
|
||||
// appear in ident
|
||||
|
||||
e = e[:len(e)-1]
|
||||
if len(lowerdirsEscaped) != i {
|
||||
lowerdirsEscaped[i+1] = e + lowerdirsEscaped[i+1]
|
||||
continue
|
||||
}
|
||||
}
|
||||
lowerdirs = append(lowerdirs, e)
|
||||
}
|
||||
|
||||
if len(lowerdirs) != 2 ||
|
||||
filepath.Base(lowerdirs[0]) != "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU" ||
|
||||
filepath.Base(lowerdirs[1]) != "nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK" {
|
||||
log.Fatalf("unexpected lowerdirs %s", strings.Join(lowerdirs, ", "))
|
||||
if len(lowerdir) != 2 ||
|
||||
filepath.Base(lowerdir[0]) != "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU" ||
|
||||
filepath.Base(lowerdir[1]) != "nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK" {
|
||||
log.Fatalf("unexpected lowerdirs %s", strings.Join(lowerdir, ", "))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -72,7 +72,10 @@ const (
|
||||
HakureiDist
|
||||
IPTables
|
||||
Kmod
|
||||
LIT
|
||||
LibX11
|
||||
LibXau
|
||||
LibXext
|
||||
Libbsd
|
||||
Libcap
|
||||
Libdrm
|
||||
@@ -92,8 +95,10 @@ const (
|
||||
Libtool
|
||||
Libucontext
|
||||
Libunistring
|
||||
Libxshmfence
|
||||
Libxml2
|
||||
Libxslt
|
||||
Libxtrans
|
||||
M4
|
||||
MPC
|
||||
MPFR
|
||||
@@ -148,6 +153,7 @@ const (
|
||||
Rsync
|
||||
Sed
|
||||
SPIRVHeaders
|
||||
SPIRVLLVMTranslator
|
||||
SPIRVTools
|
||||
SquashfsTools
|
||||
Strace
|
||||
@@ -164,14 +170,27 @@ const (
|
||||
XCBProto
|
||||
XDGDBusProxy
|
||||
XZ
|
||||
Xproto
|
||||
XorgProto
|
||||
Zlib
|
||||
Zstd
|
||||
|
||||
// PresetUnexportedStart is the first unexported preset.
|
||||
PresetUnexportedStart
|
||||
|
||||
buildcatrust = iota - 1
|
||||
llvmSource = iota - 1
|
||||
// earlyCompilerRT is an early, standalone compiler-rt installation for the
|
||||
// standalone runtimes build.
|
||||
//
|
||||
// earlyCompilerRT must only be loaded by [LLVM].
|
||||
earlyCompilerRT
|
||||
// earlyRuntimes is an early, standalone installation of LLVM runtimes to
|
||||
// work around the cmake build system leaking the system LLVM installation
|
||||
// when invoking the newly built toolchain.
|
||||
//
|
||||
// earlyRuntimes must only be loaded by [LLVM].
|
||||
earlyRuntimes
|
||||
|
||||
buildcatrust
|
||||
utilMacros
|
||||
|
||||
// Musl is a standalone libc that does not depend on the toolchain.
|
||||
|
||||
@@ -122,6 +122,8 @@ type CMakeHelper struct {
|
||||
// Path elements joined with source.
|
||||
Append []string
|
||||
|
||||
// Value of CMAKE_BUILD_TYPE. The zero value is equivalent to "Release".
|
||||
BuildType string
|
||||
// CMake CACHE entries.
|
||||
Cache []KV
|
||||
// Runs after install.
|
||||
@@ -164,14 +166,7 @@ func (*CMakeHelper) wantsDir() string { return "/cure/" }
|
||||
// script generates the cure script.
|
||||
func (attr *CMakeHelper) script(name string) string {
|
||||
if attr == nil {
|
||||
attr = &CMakeHelper{
|
||||
Cache: []KV{
|
||||
{"CMAKE_BUILD_TYPE", "Release"},
|
||||
},
|
||||
}
|
||||
}
|
||||
if len(attr.Cache) == 0 {
|
||||
panic("CACHE must be non-empty")
|
||||
attr = new(CMakeHelper)
|
||||
}
|
||||
|
||||
generate := "Ninja"
|
||||
@@ -189,6 +184,13 @@ func (attr *CMakeHelper) script(name string) string {
|
||||
script += "\n" + test
|
||||
}
|
||||
|
||||
cache := make([]KV, 1, 1+len(attr.Cache))
|
||||
cache[0] = KV{"CMAKE_BUILD_TYPE", "Release"}
|
||||
if attr.BuildType != "" {
|
||||
cache[0][1] = attr.BuildType
|
||||
}
|
||||
cache = append(cache, attr.Cache...)
|
||||
|
||||
return `
|
||||
cmake -G ` + generate + ` \
|
||||
-DCMAKE_C_COMPILER_TARGET="${ROSA_TRIPLE}" \
|
||||
@@ -196,7 +198,7 @@ cmake -G ` + generate + ` \
|
||||
-DCMAKE_ASM_COMPILER_TARGET="${ROSA_TRIPLE}" \
|
||||
-DCMAKE_INSTALL_LIBDIR=lib \
|
||||
` + strings.Join(slices.Collect(func(yield func(string) bool) {
|
||||
for _, v := range attr.Cache {
|
||||
for _, v := range cache {
|
||||
if !yield("-D" + v[0] + "=" + v[1]) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -17,10 +17,6 @@ func (t Toolchain) newSPIRVHeaders() (pkg.Artifact, string) {
|
||||
"vulkan-sdk-"+version,
|
||||
checksum,
|
||||
), nil, &CMakeHelper{
|
||||
Cache: []KV{
|
||||
{"CMAKE_BUILD_TYPE", "Release"},
|
||||
},
|
||||
|
||||
// upstream has no tests
|
||||
SkipTest: true,
|
||||
}), version
|
||||
@@ -67,7 +63,6 @@ func (t Toolchain) newSPIRVTools() (pkg.Artifact, string) {
|
||||
checksum,
|
||||
), nil, &CMakeHelper{
|
||||
Cache: []KV{
|
||||
{"CMAKE_BUILD_TYPE", "Release"},
|
||||
{"SPIRV-Headers_SOURCE_DIR", "/system"},
|
||||
},
|
||||
},
|
||||
@@ -109,7 +104,6 @@ func (t Toolchain) newGlslang() (pkg.Artifact, string) {
|
||||
Chmod: true,
|
||||
}, &CMakeHelper{
|
||||
Cache: []KV{
|
||||
{"CMAKE_BUILD_TYPE", "Release"},
|
||||
{"BUILD_SHARED_LIBS", "ON"},
|
||||
{"ALLOW_EXTERNAL_SPIRV_TOOLS", "ON"},
|
||||
},
|
||||
@@ -132,3 +126,65 @@ func init() {
|
||||
ID: 205796,
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newSPIRVLLVMTranslator() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "22.1.2"
|
||||
checksum = "JZAaV5ewYcm-35YA_U2BM2IcsQouZtX1BLZR0zh2vSlfEXMsT5OCtY4Gh5RJkcGy"
|
||||
)
|
||||
return t.NewPackage("spirv-llvm-translator", version, newFromGitHub(
|
||||
"KhronosGroup/SPIRV-LLVM-Translator",
|
||||
"v"+version, checksum,
|
||||
), &PackageAttr{
|
||||
Patches: []KV{
|
||||
{"remove-early-prefix", `diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index c000a77e..86f79b03 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -172,5 +172,5 @@ install(
|
||||
FILES
|
||||
${CMAKE_BINARY_DIR}/LLVMSPIRVLib.pc
|
||||
DESTINATION
|
||||
- ${CMAKE_INSTALL_PREFIX}/lib${LLVM_LIBDIR_SUFFIX}/pkgconfig
|
||||
+ lib${LLVM_LIBDIR_SUFFIX}/pkgconfig
|
||||
)
|
||||
`},
|
||||
},
|
||||
|
||||
// litArgs emits shell syntax
|
||||
ScriptEarly: `
|
||||
export LIT_OPTS=` + litArgs(true,
|
||||
// error: line 13: OpTypeCooperativeMatrixKHR Scope is limited to Workgroup and Subgroup
|
||||
"cooperative_matrix_constant_null.spvasm") + `
|
||||
`,
|
||||
}, &CMakeHelper{
|
||||
Cache: []KV{
|
||||
{"CMAKE_SKIP_BUILD_RPATH", "ON"},
|
||||
{"BUILD_SHARED_LIBS", "ON"},
|
||||
{"LLVM_SPIRV_ENABLE_LIBSPIRV_DIS", "ON"},
|
||||
{"LLVM_EXTERNAL_SPIRV_HEADERS_SOURCE_DIR", "/system"},
|
||||
{"LLVM_EXTERNAL_LIT", "/system/bin/lit"},
|
||||
{"LLVM_INCLUDE_TESTS", "ON"},
|
||||
},
|
||||
},
|
||||
Bash,
|
||||
LIT,
|
||||
|
||||
SPIRVTools,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[SPIRVLLVMTranslator] = Metadata{
|
||||
f: Toolchain.newSPIRVLLVMTranslator,
|
||||
|
||||
Name: "spirv-llvm-translator",
|
||||
Description: "bi-directional translation between SPIR-V and LLVM IR",
|
||||
Website: "https://github.com/KhronosGroup/SPIRV-LLVM-Translator",
|
||||
|
||||
Dependencies: P{
|
||||
SPIRVTools,
|
||||
},
|
||||
|
||||
ID: 227273,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,47 @@ package rosa
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"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) {
|
||||
const (
|
||||
version = "1.4.21"
|
||||
@@ -47,7 +84,15 @@ func (t Toolchain) newBison() (pkg.Artifact, string) {
|
||||
"https://ftpmirror.gnu.org/gnu/bison/bison-"+version+".tar.gz",
|
||||
checksum,
|
||||
pkg.TarGzip,
|
||||
), nil, (*MakeHelper)(nil),
|
||||
), nil, &MakeHelper{
|
||||
Check: []string{
|
||||
"TESTSUITEFLAGS=" + jobsFlagE + "' " + skipGNUTests(
|
||||
// clang miscompiles (SIGILL)
|
||||
764,
|
||||
) + "'",
|
||||
"check",
|
||||
},
|
||||
},
|
||||
M4,
|
||||
Diffutils,
|
||||
Sed,
|
||||
|
||||
35
internal/rosa/gnu_test.go
Normal file
35
internal/rosa/gnu_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
// newGoBootstrap returns the Go bootstrap toolchain.
|
||||
func (t Toolchain) newGoBootstrap() pkg.Artifact {
|
||||
const checksum = "8o9JL_ToiQKadCTb04nvBDkp8O1xiWOolAxVEqaTGodieNe4lOFEjlOxN3bwwe23"
|
||||
return t.New("go1.4-bootstrap", 0, []pkg.Artifact{
|
||||
t.Load(Bash),
|
||||
}, nil, []string{
|
||||
return t.New("go1.4-bootstrap", 0, t.AppendPresets(nil,
|
||||
Bash,
|
||||
), nil, []string{
|
||||
"CGO_ENABLED=0",
|
||||
}, `
|
||||
mkdir -p /var/tmp/ /work/system/
|
||||
@@ -35,9 +35,9 @@ func (t Toolchain) newGo(
|
||||
script string,
|
||||
extra ...pkg.Artifact,
|
||||
) pkg.Artifact {
|
||||
return t.New("go"+version, 0, slices.Concat([]pkg.Artifact{
|
||||
t.Load(Bash),
|
||||
}, extra), nil, slices.Concat([]string{
|
||||
return t.New("go"+version, 0, t.AppendPresets(extra,
|
||||
Bash,
|
||||
), nil, slices.Concat([]string{
|
||||
"CC=cc",
|
||||
"GOCACHE=/tmp/gocache",
|
||||
"GOROOT_BOOTSTRAP=/system/go",
|
||||
@@ -127,8 +127,8 @@ sed -i \
|
||||
)
|
||||
|
||||
go125 := t.newGo(
|
||||
"1.25.7",
|
||||
"fyylHdBVRUobnBjYj3NKBaYPUw3kGmo2mEELiZonOYurPfbarNU1x77B99Fjut7Q",
|
||||
"1.25.9",
|
||||
"gShJb9uOMk5AxqPSwvn53ZO56S6PyP6nfojzrHUiJ3krAvrgjJpYa6-DPA-jxbpN",
|
||||
[]string{"CGO_ENABLED=0"}, `
|
||||
sed -i \
|
||||
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
|
||||
@@ -156,7 +156,9 @@ sed -i \
|
||||
internal/runtime/gc/scan/scan_amd64.go
|
||||
|
||||
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,
|
||||
), version
|
||||
}
|
||||
|
||||
@@ -7,9 +7,8 @@ func (t Toolchain) newHakurei(
|
||||
withHostname bool,
|
||||
) pkg.Artifact {
|
||||
hostname := `
|
||||
echo '# Building test helper (hostname).'
|
||||
go build -v -o /bin/hostname /usr/src/hostname/main.go
|
||||
echo
|
||||
echo 'Building test helper (hostname).'
|
||||
go build -o /bin/hostname /usr/src/hostname/main.go
|
||||
`
|
||||
if !withHostname {
|
||||
hostname = ""
|
||||
|
||||
@@ -2,20 +2,157 @@ package rosa
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
// litArgs returns [LIT] arguments for optional verbosity and check skipping.
|
||||
func litArgs(verbose bool, skipChecks ...string) string {
|
||||
args := []string{"-sv"}
|
||||
if verbose {
|
||||
args[0] = "--verbose"
|
||||
}
|
||||
|
||||
if len(skipChecks) > 0 {
|
||||
skipChecks = slices.Clone(skipChecks)
|
||||
for i, s := range skipChecks {
|
||||
s = regexp.QuoteMeta(s)
|
||||
s = strings.ReplaceAll(s, "/", "\\/")
|
||||
skipChecks[i] = s
|
||||
}
|
||||
args = append(args,
|
||||
"--filter-out='\\''"+strings.Join(skipChecks, "|")+"'\\''")
|
||||
}
|
||||
|
||||
return "'" + strings.Join(args, " ") + "'"
|
||||
}
|
||||
|
||||
func (t Toolchain) newEarlyCompilerRT() (pkg.Artifact, string) {
|
||||
version := t.Version(llvmSource)
|
||||
major, _, _ := strings.Cut(version, ".")
|
||||
return t.NewPackage("early-compiler-rt", version, t.Load(llvmSource), &PackageAttr{
|
||||
Flag: TExclusive,
|
||||
}, &CMakeHelper{
|
||||
Append: []string{"compiler-rt"},
|
||||
|
||||
Cache: []KV{
|
||||
// libc++ not yet available
|
||||
{"CMAKE_CXX_COMPILER_TARGET", ""},
|
||||
|
||||
{"LLVM_HOST_TRIPLE", `"${ROSA_TRIPLE}"`},
|
||||
{"LLVM_DEFAULT_TARGET_TRIPLE", `"${ROSA_TRIPLE}"`},
|
||||
{"LLVM_ENABLE_PER_TARGET_RUNTIME_DIR", "ON"},
|
||||
|
||||
{"COMPILER_RT_BUILD_BUILTINS", "ON"},
|
||||
{"COMPILER_RT_DEFAULT_TARGET_ONLY", "OFF"},
|
||||
{"COMPILER_RT_SANITIZERS_TO_BUILD", "asan"},
|
||||
|
||||
// does not work without libunwind
|
||||
{"COMPILER_RT_BUILD_CTX_PROFILE", "OFF"},
|
||||
{"COMPILER_RT_BUILD_LIBFUZZER", "OFF"},
|
||||
{"COMPILER_RT_BUILD_MEMPROF", "OFF"},
|
||||
{"COMPILER_RT_BUILD_PROFILE", "OFF"},
|
||||
{"COMPILER_RT_BUILD_XRAY", "OFF"},
|
||||
},
|
||||
SkipTest: true,
|
||||
Script: `
|
||||
mkdir -p "/work/system/lib/clang/` + major + `/lib/"
|
||||
ln -s \
|
||||
"../../../${ROSA_TRIPLE}" \
|
||||
"/work/system/lib/clang/` + major + `/lib/"
|
||||
|
||||
ln -s \
|
||||
"clang_rt.crtbegin-` + linuxArch() + `.o" \
|
||||
"/work/system/lib/${ROSA_TRIPLE}/crtbeginS.o"
|
||||
ln -s \
|
||||
"clang_rt.crtend-` + linuxArch() + `.o" \
|
||||
"/work/system/lib/${ROSA_TRIPLE}/crtendS.o"
|
||||
`,
|
||||
},
|
||||
Python,
|
||||
|
||||
muslHeaders,
|
||||
KernelHeaders,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[earlyCompilerRT] = Metadata{
|
||||
f: Toolchain.newEarlyCompilerRT,
|
||||
|
||||
Name: "early-compiler-rt",
|
||||
Description: "early LLVM runtime: compiler-rt",
|
||||
|
||||
Dependencies: P{
|
||||
Musl,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newEarlyRuntimes() (pkg.Artifact, string) {
|
||||
version := t.Version(llvmSource)
|
||||
return t.NewPackage("early-runtimes", version, t.Load(llvmSource), &PackageAttr{
|
||||
Flag: TExclusive,
|
||||
}, &CMakeHelper{
|
||||
Append: []string{"runtimes"},
|
||||
|
||||
Cache: []KV{
|
||||
// libc++ not yet available
|
||||
{"CMAKE_CXX_COMPILER_WORKS", "ON"},
|
||||
|
||||
{"LLVM_HOST_TRIPLE", `"${ROSA_TRIPLE}"`},
|
||||
{"LLVM_DEFAULT_TARGET_TRIPLE", `"${ROSA_TRIPLE}"`},
|
||||
{"LLVM_ENABLE_RUNTIMES", "'libunwind;libcxx;libcxxabi'"},
|
||||
|
||||
{"LIBUNWIND_USE_COMPILER_RT", "ON"},
|
||||
{"LIBCXX_HAS_MUSL_LIBC", "ON"},
|
||||
{"LIBCXX_USE_COMPILER_RT", "ON"},
|
||||
{"LIBCXX_HAS_ATOMIC_LIB", "OFF"},
|
||||
{"LIBCXXABI_USE_COMPILER_RT", "ON"},
|
||||
{"LIBCXXABI_USE_LLVM_UNWINDER", "ON"},
|
||||
{"LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL", "OFF"},
|
||||
|
||||
{"LLVM_ENABLE_ZLIB", "FORCE_ON"},
|
||||
{"LLVM_ENABLE_ZSTD", "FORCE_ON"},
|
||||
{"LLVM_ENABLE_LIBXML2", "OFF"},
|
||||
},
|
||||
SkipTest: true,
|
||||
},
|
||||
Python,
|
||||
|
||||
Zlib,
|
||||
Zstd,
|
||||
earlyCompilerRT,
|
||||
KernelHeaders,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[earlyRuntimes] = Metadata{
|
||||
f: Toolchain.newEarlyRuntimes,
|
||||
|
||||
Name: "early-runtimes",
|
||||
Description: "early LLVM runtimes: libunwind, libcxx, libcxxabi",
|
||||
|
||||
Dependencies: P{
|
||||
earlyCompilerRT,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newLLVM() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "22.1.4"
|
||||
checksum = "Bk3t-tV5sD5T0bqefFMcLeFuAwXnhFipywZmqst5hAZs97QQWGKB_5XyAFjj5tDB"
|
||||
)
|
||||
var early PArtifact = muslHeaders
|
||||
if t.isStage0() {
|
||||
// The LLVM build system is buggy around LLVM_LINK_LLVM_DYLIB and leaks
|
||||
// the system installation when invoking the newly built toolchain. This
|
||||
// is worked around in stage0 by providing standalone builds of
|
||||
// runtimes. Later stages rely on 3-stage determinism and allows the
|
||||
// system installation from its previous stage to leak through.
|
||||
early = earlyRuntimes
|
||||
}
|
||||
|
||||
cache := []KV{
|
||||
{"CMAKE_BUILD_TYPE", "Release"},
|
||||
|
||||
{"ENABLE_LINKER_BUILD_ID", "ON"},
|
||||
{"COMPILER_RT_USE_BUILTINS_LIBRARY", "ON"},
|
||||
{"COMPILER_RT_DEFAULT_TARGET_ONLY", "ON"},
|
||||
@@ -93,10 +230,14 @@ func (t Toolchain) newLLVM() (pkg.Artifact, string) {
|
||||
// unwind: fails on musl
|
||||
"eh_frame_fde_pc_range",
|
||||
}
|
||||
for i, s := range skipChecks {
|
||||
s = regexp.QuoteMeta(s)
|
||||
s = strings.ReplaceAll(s, "/", "\\/")
|
||||
skipChecks[i] = s
|
||||
switch runtime.GOARCH {
|
||||
case "arm64":
|
||||
skipChecks = append(skipChecks,
|
||||
// LLVM: intermittently crashes
|
||||
"ExecutionEngine/OrcLazy/multiple-compile-threads-basic.ll",
|
||||
// unwind: unexpectedly passes
|
||||
"unwind_leaffunction",
|
||||
)
|
||||
}
|
||||
|
||||
if presetOpts&OptLLVMNoLTO == 0 {
|
||||
@@ -110,25 +251,20 @@ func (t Toolchain) newLLVM() (pkg.Artifact, string) {
|
||||
// symbols: clock_gettime, mallopt
|
||||
{"COMPILER_RT_INCLUDE_TESTS", "OFF"},
|
||||
|
||||
{"LLVM_LIT_ARGS", "'" + strings.Join([]string{
|
||||
"--verbose",
|
||||
"--filter-out='\\''" + strings.Join(skipChecks, "|") + "'\\''",
|
||||
}, " ") + "'"},
|
||||
{"LLVM_BUILD_TESTS", "ON"},
|
||||
{"LLVM_LIT_ARGS", litArgs(true, skipChecks...)},
|
||||
}...)
|
||||
}
|
||||
|
||||
return t.NewPackage("llvm", version, t.NewPatchedSource("llvm", version, newFromGitHub(
|
||||
"llvm/llvm-project",
|
||||
"llvmorg-"+version,
|
||||
checksum,
|
||||
), true, llvmPatches...), nil, &CMakeHelper{
|
||||
version := t.Version(llvmSource)
|
||||
return t.NewPackage("llvm", version, t.Load(llvmSource), nil, &CMakeHelper{
|
||||
Append: []string{"llvm"},
|
||||
|
||||
Cache: cache,
|
||||
Script: `
|
||||
ln -s ld.lld /work/system/bin/ld
|
||||
|
||||
ln -s clang /work/system/bin/cc
|
||||
ln -s clang /work/system/bin/cpp
|
||||
ln -s clang++ /work/system/bin/c++
|
||||
`,
|
||||
|
||||
@@ -159,11 +295,31 @@ ninja ` + jobsFlagE + ` check-all
|
||||
|
||||
Zlib,
|
||||
Zstd,
|
||||
muslHeaders,
|
||||
early,
|
||||
KernelHeaders,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
const (
|
||||
version = "22.1.4"
|
||||
checksum = "Bk3t-tV5sD5T0bqefFMcLeFuAwXnhFipywZmqst5hAZs97QQWGKB_5XyAFjj5tDB"
|
||||
)
|
||||
|
||||
artifactsM[llvmSource] = Metadata{
|
||||
f: func(t Toolchain) (pkg.Artifact, string) {
|
||||
return t.NewPatchedSource("llvm", version, newFromGitHub(
|
||||
"llvm/llvm-project",
|
||||
"llvmorg-"+version,
|
||||
checksum,
|
||||
), true, llvmPatches...), version
|
||||
},
|
||||
|
||||
Name: "llvm-project",
|
||||
Description: "LLVM monorepo with Rosa OS patches",
|
||||
|
||||
ID: 1830,
|
||||
}
|
||||
|
||||
artifactsM[LLVM] = Metadata{
|
||||
f: Toolchain.newLLVM,
|
||||
|
||||
@@ -176,7 +332,5 @@ func init() {
|
||||
Zstd,
|
||||
Musl,
|
||||
},
|
||||
|
||||
ID: 1830,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,6 +351,29 @@ func init() {
|
||||
)
|
||||
}
|
||||
|
||||
func init() {
|
||||
artifactsM[LIT] = Metadata{
|
||||
f: func(t Toolchain) (pkg.Artifact, string) {
|
||||
version := t.Version(LLVM)
|
||||
return t.NewPackage("lit", version, t.Load(llvmSource), nil, &PipHelper{
|
||||
Append: []string{"llvm", "utils", "lit"},
|
||||
// already checked during llvm
|
||||
SkipCheck: true,
|
||||
},
|
||||
PythonSetuptools,
|
||||
), version
|
||||
},
|
||||
|
||||
Name: "lit",
|
||||
Description: "a portable tool for executing LLVM and Clang style test suites",
|
||||
Website: "https://llvm.org/docs/CommandGuide/lit.html",
|
||||
|
||||
Dependencies: P{
|
||||
Python,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
const (
|
||||
version = "1.1.1"
|
||||
|
||||
@@ -28,6 +28,7 @@ var (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
rosa.DropCaches(rosa.OptLLVMNoLTO)
|
||||
container.TryArgv0(nil)
|
||||
|
||||
code := m.Run()
|
||||
|
||||
@@ -47,6 +47,7 @@ func NewStage0() pkg.Artifact {
|
||||
"stage0-"+triplet()+".tar.bz2",
|
||||
perArch[string]{
|
||||
"amd64": "ldz-WkSx2wxUK4ndi-tlaaU8ykOowbpGRcBsciAcIDdnX6-QfzQg_se3lsZYuzuK",
|
||||
"arm64": "_mo39S_sgzPYaIQ_Wi13O46KPQuWqCCiZdildpz6a8MTh2khIt68tNIulyUGBV2z",
|
||||
}.unwrap(),
|
||||
pkg.TarBzip2,
|
||||
)
|
||||
|
||||
@@ -27,8 +27,14 @@ chmod -R +w ..
|
||||
sed -i \
|
||||
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
|
||||
cmd/link/internal/`+runtime.GOARCH+`/obj.go
|
||||
sed -i \
|
||||
's/cpu.X86.HasAVX512VBMI/& \&\& cpu.X86.HasPOPCNT/' \
|
||||
internal/runtime/gc/scan/scan_amd64.go
|
||||
|
||||
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
|
||||
`, pkg.Path(AbsUsrSrc.Append("tamago"), false, newFromGitHub(
|
||||
|
||||
@@ -26,19 +26,50 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newXproto() (pkg.Artifact, string) {
|
||||
func (t Toolchain) newLibxtrans() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "7.0.31"
|
||||
checksum = "Cm69urWY5RctKpR78eGzuwrjDEfXGkvHRdodj6sjypOGy5FF4-lmnUttVHYV1ydg"
|
||||
version = "1.6.0"
|
||||
checksum = "1cxDCF59fLf1HyGDMcjR1L50ZbjD0RTTEDUpOJYcHXu6HUK_Ds0x-KREY7rLNxu9"
|
||||
)
|
||||
return t.NewPackage("xproto", version, newTar(
|
||||
"https://www.x.org/releases/individual/proto/"+
|
||||
"xproto-"+version+".tar.bz2",
|
||||
return t.NewPackage("libxtrans", version, newFromGitLab(
|
||||
"gitlab.freedesktop.org",
|
||||
"xorg/lib/libxtrans",
|
||||
"xtrans-"+version,
|
||||
checksum,
|
||||
pkg.TarBzip2,
|
||||
), nil, &MakeHelper{
|
||||
// ancient configure script
|
||||
Generate: "autoreconf -if",
|
||||
Generate: "NOCONFIGURE=1 ./autogen.sh",
|
||||
},
|
||||
Automake,
|
||||
Libtool,
|
||||
PkgConfig,
|
||||
|
||||
utilMacros,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[Libxtrans] = Metadata{
|
||||
f: Toolchain.newLibxtrans,
|
||||
|
||||
Name: "libxtrans",
|
||||
Description: "X Window System Protocols Transport layer shared code",
|
||||
Website: "https://gitlab.freedesktop.org/xorg/lib/libxtrans",
|
||||
|
||||
ID: 13441,
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newXorgProto() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "2025.1"
|
||||
checksum = "pTwJiBJHKA6Rgm3cVDXy1lyvXNIUzTRaukvvYdk1xWoJ_1G-Dfjm9MyewuyIjoHz"
|
||||
)
|
||||
return t.NewPackage("xorgproto", version, newFromGitLab(
|
||||
"gitlab.freedesktop.org",
|
||||
"xorg/proto/xorgproto",
|
||||
"xorgproto-"+version,
|
||||
checksum,
|
||||
), nil, &MakeHelper{
|
||||
Generate: "NOCONFIGURE=1 ./autogen.sh",
|
||||
},
|
||||
Automake,
|
||||
PkgConfig,
|
||||
@@ -47,14 +78,14 @@ func (t Toolchain) newXproto() (pkg.Artifact, string) {
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[Xproto] = Metadata{
|
||||
f: Toolchain.newXproto,
|
||||
artifactsM[XorgProto] = Metadata{
|
||||
f: Toolchain.newXorgProto,
|
||||
|
||||
Name: "xproto",
|
||||
Name: "xorgproto",
|
||||
Description: "X Window System unified protocol definitions",
|
||||
Website: "https://gitlab.freedesktop.org/xorg/proto/xorgproto",
|
||||
|
||||
ID: 13650,
|
||||
ID: 17190,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +108,7 @@ func (t Toolchain) newLibXau() (pkg.Artifact, string) {
|
||||
PkgConfig,
|
||||
|
||||
utilMacros,
|
||||
Xproto,
|
||||
XorgProto,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
@@ -89,13 +120,186 @@ func init() {
|
||||
Website: "https://gitlab.freedesktop.org/xorg/lib/libxau",
|
||||
|
||||
Dependencies: P{
|
||||
Xproto,
|
||||
XorgProto,
|
||||
},
|
||||
|
||||
ID: 1765,
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newXCBProto() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "1.17.0"
|
||||
checksum = "_NtbKaJ_iyT7XiJz25mXQ7y-niTzE8sHPvLXZPcqtNoV_-vTzqkezJ8Hp2U1enCv"
|
||||
)
|
||||
return t.NewPackage("xcb-proto", version, newTar(
|
||||
"https://xcb.freedesktop.org/dist/xcb-proto-"+version+".tar.gz",
|
||||
checksum,
|
||||
pkg.TarGzip,
|
||||
), nil, (*MakeHelper)(nil),
|
||||
Python,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[XCBProto] = Metadata{
|
||||
f: Toolchain.newXCBProto,
|
||||
|
||||
Name: "xcb-proto",
|
||||
Description: "XML-XCB protocol descriptions used by libxcb for the X11 protocol & extensions",
|
||||
Website: "https://gitlab.freedesktop.org/xorg/proto/xcbproto",
|
||||
|
||||
ID: 13646,
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newXCB() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "1.17.0"
|
||||
checksum = "hjjsc79LpWM_hZjNWbDDS6qRQUXREjjekS6UbUsDq-RR1_AjgNDxhRvZf-1_kzDd"
|
||||
)
|
||||
return t.NewPackage("xcb", version, newTar(
|
||||
"https://xcb.freedesktop.org/dist/libxcb-"+version+".tar.gz",
|
||||
checksum,
|
||||
pkg.TarGzip,
|
||||
), nil, (*MakeHelper)(nil),
|
||||
Python,
|
||||
PkgConfig,
|
||||
|
||||
XCBProto,
|
||||
LibXau,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[XCB] = Metadata{
|
||||
f: Toolchain.newXCB,
|
||||
|
||||
Name: "xcb",
|
||||
Description: "The X protocol C-language Binding",
|
||||
Website: "https://xcb.freedesktop.org/",
|
||||
|
||||
Dependencies: P{
|
||||
XCBProto,
|
||||
LibXau,
|
||||
},
|
||||
|
||||
ID: 1767,
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newLibX11() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "1.8.13"
|
||||
checksum = "ARh-cuZY_U2v3DbPS1byc7ybh9NInZc-yav7SJiusk_C7408s058qWV83ocMd2pT"
|
||||
)
|
||||
return t.NewPackage("libX11", version, newFromGitLab(
|
||||
"gitlab.freedesktop.org",
|
||||
"xorg/lib/libx11",
|
||||
"libX11-"+version,
|
||||
checksum,
|
||||
), nil, &MakeHelper{
|
||||
Generate: "NOCONFIGURE=1 ./autogen.sh",
|
||||
|
||||
Configure: []KV{
|
||||
{"enable-static"},
|
||||
{"without-xmlto"},
|
||||
},
|
||||
},
|
||||
Automake,
|
||||
Libtool,
|
||||
PkgConfig,
|
||||
|
||||
utilMacros,
|
||||
Libxtrans,
|
||||
XorgProto,
|
||||
XCB,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[LibX11] = Metadata{
|
||||
f: Toolchain.newLibX11,
|
||||
|
||||
Name: "libX11",
|
||||
Description: `Core X11 protocol client library (aka "Xlib")`,
|
||||
Website: "https://gitlab.freedesktop.org/xorg/lib/libx11",
|
||||
|
||||
Dependencies: P{
|
||||
XCB,
|
||||
},
|
||||
|
||||
ID: 1764,
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newLibXext() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "1.3.7"
|
||||
checksum = "-0wvUDaucLPLNOrK1pcKhHNoO-5nUqQyyw6JAbhx65gRjuMiNKKaF2_tcrbC_KNq"
|
||||
)
|
||||
return t.NewPackage("libXext", version, newFromGitLab(
|
||||
"gitlab.freedesktop.org",
|
||||
"xorg/lib/libxext",
|
||||
"libXext-"+version,
|
||||
checksum,
|
||||
), nil, &MakeHelper{
|
||||
Generate: "NOCONFIGURE=1 ./autogen.sh",
|
||||
},
|
||||
Automake,
|
||||
Libtool,
|
||||
PkgConfig,
|
||||
|
||||
utilMacros,
|
||||
LibX11,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[LibXext] = Metadata{
|
||||
f: Toolchain.newLibXext,
|
||||
|
||||
Name: "libXext",
|
||||
Description: "Xlib-based library for common extensions to the X11 protocol",
|
||||
Website: "https://gitlab.freedesktop.org/xorg/lib/libxext",
|
||||
|
||||
Dependencies: P{
|
||||
LibX11,
|
||||
},
|
||||
|
||||
ID: 1774,
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newLibxshmfence() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "1.3.3"
|
||||
checksum = "JamExTPg81By2fs3vWdeo_dzlpBQeAwXr2sDXeHJqm9XBoLW5pamiD6FgAWtAKyA"
|
||||
)
|
||||
return t.NewPackage("libxshmfence", version, newFromGitLab(
|
||||
"gitlab.freedesktop.org",
|
||||
"xorg/lib/libxshmfence",
|
||||
"libxshmfence-"+version,
|
||||
checksum,
|
||||
), nil, &MakeHelper{
|
||||
Generate: "NOCONFIGURE=1 ./autogen.sh",
|
||||
},
|
||||
Automake,
|
||||
Libtool,
|
||||
PkgConfig,
|
||||
|
||||
utilMacros,
|
||||
XorgProto,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[Libxshmfence] = Metadata{
|
||||
f: Toolchain.newLibxshmfence,
|
||||
|
||||
Name: "libxshmfence",
|
||||
Description: "shared memory 'SyncFence' synchronization primitive",
|
||||
Website: "https://gitlab.freedesktop.org/xorg/lib/libxshmfence",
|
||||
|
||||
ID: 1792,
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newLibpciaccess() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "0.19"
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newXCBProto() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "1.17.0"
|
||||
checksum = "_NtbKaJ_iyT7XiJz25mXQ7y-niTzE8sHPvLXZPcqtNoV_-vTzqkezJ8Hp2U1enCv"
|
||||
)
|
||||
return t.NewPackage("xcb-proto", version, newTar(
|
||||
"https://xcb.freedesktop.org/dist/xcb-proto-"+version+".tar.gz",
|
||||
checksum,
|
||||
pkg.TarGzip,
|
||||
), nil, (*MakeHelper)(nil),
|
||||
Python,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[XCBProto] = Metadata{
|
||||
f: Toolchain.newXCBProto,
|
||||
|
||||
Name: "xcb-proto",
|
||||
Description: "XML-XCB protocol descriptions used by libxcb for the X11 protocol & extensions",
|
||||
Website: "https://gitlab.freedesktop.org/xorg/proto/xcbproto",
|
||||
|
||||
ID: 13646,
|
||||
}
|
||||
}
|
||||
|
||||
func (t Toolchain) newXCB() (pkg.Artifact, string) {
|
||||
const (
|
||||
version = "1.17.0"
|
||||
checksum = "hjjsc79LpWM_hZjNWbDDS6qRQUXREjjekS6UbUsDq-RR1_AjgNDxhRvZf-1_kzDd"
|
||||
)
|
||||
return t.NewPackage("xcb", version, newTar(
|
||||
"https://xcb.freedesktop.org/dist/libxcb-"+version+".tar.gz",
|
||||
checksum,
|
||||
pkg.TarGzip,
|
||||
), nil, (*MakeHelper)(nil),
|
||||
Python,
|
||||
PkgConfig,
|
||||
|
||||
XCBProto,
|
||||
LibXau,
|
||||
), version
|
||||
}
|
||||
func init() {
|
||||
artifactsM[XCB] = Metadata{
|
||||
f: Toolchain.newXCB,
|
||||
|
||||
Name: "xcb",
|
||||
Description: "The X protocol C-language Binding",
|
||||
Website: "https://xcb.freedesktop.org/",
|
||||
|
||||
Dependencies: P{
|
||||
XCBProto,
|
||||
LibXau,
|
||||
},
|
||||
|
||||
ID: 1767,
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,6 @@ func (t Toolchain) newZlib() (pkg.Artifact, string) {
|
||||
pkg.TarGzip,
|
||||
), nil, &CMakeHelper{
|
||||
Cache: []KV{
|
||||
{"CMAKE_BUILD_TYPE", "Release"},
|
||||
|
||||
{"CMAKE_C_FLAGS", "-fPIC"},
|
||||
{"ZLIB_BUILD_TESTING", "ON"},
|
||||
{"ZLIB_BUILD_SHARED", "ON"},
|
||||
|
||||
@@ -19,9 +19,6 @@ func (t Toolchain) newZstd() (pkg.Artifact, string) {
|
||||
Chmod: true,
|
||||
}, &CMakeHelper{
|
||||
Append: []string{"build", "cmake"},
|
||||
Cache: []KV{
|
||||
{"CMAKE_BUILD_TYPE", "Release"},
|
||||
},
|
||||
Test: `
|
||||
make -C /usr/src/zstd/tests datagen
|
||||
ZSTD_BIN=/cure/programs/zstd /usr/src/zstd/tests/playTests.sh
|
||||
|
||||
@@ -35,7 +35,7 @@ package
|
||||
|
||||
|
||||
*Default:*
|
||||
` <derivation hakurei-static-x86_64-unknown-linux-musl-0.4.0> `
|
||||
` <derivation hakurei-static-x86_64-unknown-linux-musl-0.4.1> `
|
||||
|
||||
|
||||
|
||||
@@ -842,7 +842,7 @@ package
|
||||
|
||||
|
||||
*Default:*
|
||||
` <derivation hakurei-hsu-0.4.0> `
|
||||
` <derivation hakurei-hsu-0.4.1> `
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
buildGo126Module rec {
|
||||
pname = "hakurei";
|
||||
version = "0.4.0";
|
||||
version = "0.4.1";
|
||||
|
||||
srcFiltered = builtins.path {
|
||||
name = "${pname}-src";
|
||||
|
||||
@@ -237,8 +237,8 @@ in
|
||||
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||
(ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr")
|
||||
(ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr")
|
||||
(ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr")
|
||||
(ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr")
|
||||
(ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent "/var/lib/hakurei/u0/a4" "/var/lib/hakurei/u0/a4" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
|
||||
@@ -264,8 +264,8 @@ in
|
||||
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||
(ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr")
|
||||
(ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr")
|
||||
(ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr")
|
||||
(ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr")
|
||||
(ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent "/var/lib/hakurei/u0/a3" "/var/lib/hakurei/u0/a3" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent ignore "/run/user/1000/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
|
||||
@@ -270,8 +270,8 @@ in
|
||||
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||
(ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr")
|
||||
(ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,uuid=on,userxattr")
|
||||
(ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr")
|
||||
(ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,uuid=on,userxattr")
|
||||
(ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent "/var/lib/hakurei/u0/a2" "/var/lib/hakurei/u0/a2" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
(ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||
|
||||
Reference in New Issue
Block a user