Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a38b614c6 | |||
| 3286fff076 | |||
| fd1884a84b | |||
| fe6424bd6d | |||
| 004ac511a9 | |||
| ba17f9d4f3 | |||
| ea62f64b8f | |||
| 86669363ac | |||
| 6f5b7964f4 | |||
| a195c3760c | |||
| cfe52dce82 | |||
| 8483d8a005 | |||
| 5bc5aed024 | |||
| 9465649d13 | |||
| 33c461aa67 | |||
| dee0204fc0 | |||
| 2f916ed0c0 | |||
| 55ce3a2f90 | |||
| 3f6a07ef59 | |||
| 02941e7c23 | |||
| b9601881b7 | |||
| 58596f0af5 | |||
| 02cde40289 | |||
| 5014534884 | |||
| 13cf99ced4 | |||
| 6bfb258fd0 | |||
| b649645189 | |||
| 3ddba4e21f | |||
| 40a906c6c2 | |||
| 06894e2104 | |||
| 56f0392b86 | |||
| e2315f6c1a | |||
| e4aee49eb0 | |||
| 6c03cc8b8a | |||
| 59ade6a86b | |||
| 59ab493035 | |||
| d80a3346e2 | |||
| 327a34aacb | |||
| ea7c6b3b48 |
+2
-2
@@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
# go generate
|
# go generate
|
||||||
/cmd/hakurei/LICENSE
|
/cmd/hakurei/LICENSE
|
||||||
/cmd/mbf/internal/pkgserver/ui/static
|
/cmd/pkgserver/ui/static/*.js
|
||||||
/internal/pkg/internal/testtool/testtool
|
/internal/pkg/testdata/testtool
|
||||||
/internal/rosa/hakurei_current.tar.gz
|
/internal/rosa/hakurei_current.tar.gz
|
||||||
|
|
||||||
# cmd/dist default destination
|
# cmd/dist default destination
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
|
|
||||||
HAKUREI_DIST_MAKE='' exec "$(dirname -- "$0")/cmd/dist/dist.sh"
|
TOOLCHAIN_VERSION="$(go version)"
|
||||||
|
cd "$(dirname -- "$0")/"
|
||||||
|
echo "# Building cmd/dist using ${TOOLCHAIN_VERSION}."
|
||||||
|
go run -v --tags=dist ./cmd/dist
|
||||||
|
|||||||
@@ -4,23 +4,15 @@ import "strings"
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// SpecialOverlayEscape is the escape string for overlay mount options.
|
// SpecialOverlayEscape is the escape string for overlay mount options.
|
||||||
//
|
|
||||||
// Deprecated: This is no longer used and will be removed in 0.5.
|
|
||||||
SpecialOverlayEscape = `\`
|
SpecialOverlayEscape = `\`
|
||||||
// SpecialOverlayOption is the separator string between overlay mount options.
|
// SpecialOverlayOption is the separator string between overlay mount options.
|
||||||
//
|
|
||||||
// Deprecated: This is no longer used and will be removed in 0.5.
|
|
||||||
SpecialOverlayOption = ","
|
SpecialOverlayOption = ","
|
||||||
// SpecialOverlayPath is the separator string between overlay paths.
|
// SpecialOverlayPath is the separator string between overlay paths.
|
||||||
//
|
|
||||||
// Deprecated: This is no longer used and will be removed in 0.5.
|
|
||||||
SpecialOverlayPath = ":"
|
SpecialOverlayPath = ":"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EscapeOverlayDataSegment escapes a string for formatting into the data
|
// EscapeOverlayDataSegment escapes a string for formatting into the data
|
||||||
// argument of an overlay mount system call.
|
// 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 {
|
func EscapeOverlayDataSegment(s string) string {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
Vendored
-1
@@ -1 +0,0 @@
|
|||||||
v0.4.3
|
|
||||||
Vendored
-10
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
|
|
||||||
TOOLCHAIN_VERSION="$(go version)"
|
|
||||||
cd "$(dirname -- "$0")/../.."
|
|
||||||
echo "Building cmd/dist using ${TOOLCHAIN_VERSION}."
|
|
||||||
FLAGS=''
|
|
||||||
if test -n "$VERBOSE"; then
|
|
||||||
FLAGS="$FLAGS -v"
|
|
||||||
fi
|
|
||||||
go run $FLAGS --tags=dist ./cmd/dist
|
|
||||||
Vendored
+10
-27
@@ -18,13 +18,8 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate sh -c "git describe --tags > VERSION"
|
|
||||||
//go:embed VERSION
|
|
||||||
var version string
|
|
||||||
|
|
||||||
// getenv looks up an environment variable, and returns fallback if it is unset.
|
// getenv looks up an environment variable, and returns fallback if it is unset.
|
||||||
func getenv(key, fallback string) string {
|
func getenv(key, fallback string) string {
|
||||||
if v, ok := os.LookupEnv(key); ok {
|
if v, ok := os.LookupEnv(key); ok {
|
||||||
@@ -47,19 +42,14 @@ func mustRun(ctx context.Context, name string, arg ...string) {
|
|||||||
var comp []byte
|
var comp []byte
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
fmt.Println()
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
log.SetPrefix("")
|
log.SetPrefix("# ")
|
||||||
|
|
||||||
verbose := os.Getenv("VERBOSE") != ""
|
version := getenv("HAKUREI_VERSION", "untagged")
|
||||||
runTests := os.Getenv("HAKUREI_DIST_MAKE") == ""
|
|
||||||
version = getenv("HAKUREI_VERSION", strings.TrimSpace(version))
|
|
||||||
prefix := getenv("PREFIX", "/usr")
|
prefix := getenv("PREFIX", "/usr")
|
||||||
destdir := getenv("DESTDIR", "dist")
|
destdir := getenv("DESTDIR", "dist")
|
||||||
|
|
||||||
if verbose {
|
|
||||||
log.Println()
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.MkdirAll(destdir, 0755); err != nil {
|
if err := os.MkdirAll(destdir, 0755); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -86,17 +76,12 @@ func main() {
|
|||||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
verboseFlag := "-v"
|
log.Println("Building hakurei.")
|
||||||
if !verbose {
|
|
||||||
verboseFlag = "-buildvcs=false"
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Building hakurei for %s/%s.", runtime.GOOS, runtime.GOARCH)
|
|
||||||
mustRun(ctx, "go", "generate", "./...")
|
mustRun(ctx, "go", "generate", "./...")
|
||||||
mustRun(
|
mustRun(
|
||||||
ctx, "go", "build",
|
ctx, "go", "build",
|
||||||
"-trimpath",
|
"-trimpath",
|
||||||
verboseFlag, "-o", s,
|
"-v", "-o", s,
|
||||||
"-ldflags=-s -w "+
|
"-ldflags=-s -w "+
|
||||||
"-buildid= -linkmode external -extldflags=-static "+
|
"-buildid= -linkmode external -extldflags=-static "+
|
||||||
"-X hakurei.app/internal/info.buildVersion="+version+" "+
|
"-X hakurei.app/internal/info.buildVersion="+version+" "+
|
||||||
@@ -105,19 +90,17 @@ func main() {
|
|||||||
"-X main.hakureiPath="+prefix+"/bin/hakurei",
|
"-X main.hakureiPath="+prefix+"/bin/hakurei",
|
||||||
"./...",
|
"./...",
|
||||||
)
|
)
|
||||||
log.Println()
|
fmt.Println()
|
||||||
|
|
||||||
if runTests {
|
log.Println("Testing Hakurei.")
|
||||||
log.Println("##### Testing Hakurei.")
|
|
||||||
mustRun(
|
mustRun(
|
||||||
ctx, "go", "test",
|
ctx, "go", "test",
|
||||||
"-ldflags=-buildid= -linkmode external -extldflags=-static",
|
"-ldflags=-buildid= -linkmode external -extldflags=-static",
|
||||||
"./...",
|
"./...",
|
||||||
)
|
)
|
||||||
log.Println()
|
fmt.Println()
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("##### Creating distribution.")
|
log.Println("Creating distribution.")
|
||||||
const suffix = ".tar.gz"
|
const suffix = ".tar.gz"
|
||||||
distName := "hakurei-" + version + "-" + runtime.GOARCH
|
distName := "hakurei-" + version + "-" + runtime.GOARCH
|
||||||
var f *os.File
|
var f *os.File
|
||||||
@@ -138,7 +121,7 @@ func main() {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
h := sha512.New()
|
h := sha512.New()
|
||||||
gw, _ := gzip.NewWriterLevel(io.MultiWriter(f, h), gzip.BestCompression)
|
gw := gzip.NewWriter(io.MultiWriter(f, h))
|
||||||
tw := tar.NewWriter(gw)
|
tw := tar.NewWriter(gw)
|
||||||
|
|
||||||
mustWriteHeader := func(name string, size int64, mode os.FileMode) {
|
mustWriteHeader := func(name string, size int64, mode os.FileMode) {
|
||||||
|
|||||||
+4
-45
@@ -7,7 +7,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/check"
|
"hakurei.app/check"
|
||||||
"hakurei.app/container"
|
|
||||||
"hakurei.app/internal/pkg"
|
"hakurei.app/internal/pkg"
|
||||||
"hakurei.app/message"
|
"hakurei.app/message"
|
||||||
)
|
)
|
||||||
@@ -21,14 +20,7 @@ type cache struct {
|
|||||||
c *pkg.Cache
|
c *pkg.Cache
|
||||||
|
|
||||||
cures, jobs int
|
cures, jobs int
|
||||||
// Primarily to work around missing landlock LSM.
|
hostAbstract, idle bool
|
||||||
hostAbstract bool
|
|
||||||
// Set SCHED_IDLE.
|
|
||||||
idle bool
|
|
||||||
// Unset [pkg.CSuppressInit].
|
|
||||||
verboseInit bool
|
|
||||||
// Loaded artifact of [rosa.QEMU].
|
|
||||||
qemu pkg.Artifact
|
|
||||||
|
|
||||||
base string
|
base string
|
||||||
}
|
}
|
||||||
@@ -39,6 +31,9 @@ func (cache *cache) open() (err error) {
|
|||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cache.base == "" {
|
||||||
|
cache.base = "cache"
|
||||||
|
}
|
||||||
var base *check.Absolute
|
var base *check.Absolute
|
||||||
if cache.base, err = filepath.Abs(cache.base); err != nil {
|
if cache.base, err = filepath.Abs(cache.base); err != nil {
|
||||||
return
|
return
|
||||||
@@ -53,9 +48,6 @@ func (cache *cache) open() (err error) {
|
|||||||
if cache.hostAbstract {
|
if cache.hostAbstract {
|
||||||
flags |= pkg.CHostAbstract
|
flags |= pkg.CHostAbstract
|
||||||
}
|
}
|
||||||
if !cache.verboseInit {
|
|
||||||
flags |= pkg.CSuppressInit
|
|
||||||
}
|
|
||||||
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
defer close(done)
|
defer close(done)
|
||||||
@@ -81,39 +73,6 @@ func (cache *cache) open() (err error) {
|
|||||||
cache.jobs,
|
cache.jobs,
|
||||||
base,
|
base,
|
||||||
)
|
)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
done <- struct{}{}
|
|
||||||
|
|
||||||
if cache.qemu != nil {
|
|
||||||
var pathname *check.Absolute
|
|
||||||
pathname, _, err = cache.c.Cure(cache.qemu)
|
|
||||||
if err != nil {
|
|
||||||
cache.c.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pkg.RegisterArch("riscv64", container.BinfmtEntry{
|
|
||||||
Offset: 0,
|
|
||||||
Magic: "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00",
|
|
||||||
Mask: "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff",
|
|
||||||
Interpreter: pathname.Append(
|
|
||||||
"system/bin",
|
|
||||||
"qemu-riscv64",
|
|
||||||
),
|
|
||||||
})
|
|
||||||
pkg.RegisterArch("arm64", container.BinfmtEntry{
|
|
||||||
Offset: 0,
|
|
||||||
Magic: "\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00",
|
|
||||||
Mask: "\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff",
|
|
||||||
Interpreter: pathname.Append(
|
|
||||||
"system/bin",
|
|
||||||
"qemu-aarch64",
|
|
||||||
),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-17
@@ -99,9 +99,10 @@ func cancelIdent(
|
|||||||
var ident pkg.ID
|
var ident pkg.ID
|
||||||
if _, err := io.ReadFull(conn, ident[:]); err != nil {
|
if _, err := io.ReadFull(conn, ident[:]); err != nil {
|
||||||
return nil, false, errors.Join(err, conn.Close())
|
return nil, false, errors.Join(err, conn.Close())
|
||||||
|
} else if err = conn.Close(); err != nil {
|
||||||
|
return nil, false, err
|
||||||
}
|
}
|
||||||
ok := cache.Cancel(unique.Make(ident))
|
return &ident, cache.Cancel(unique.Make(ident)), nil
|
||||||
return &ident, ok, conn.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// serve services connections from a [net.UnixListener].
|
// serve services connections from a [net.UnixListener].
|
||||||
@@ -193,11 +194,11 @@ func serve(
|
|||||||
}
|
}
|
||||||
|
|
||||||
case specialAbort:
|
case specialAbort:
|
||||||
log.Println("aborting all pending cures")
|
|
||||||
cm.c.Abort()
|
|
||||||
if _err := conn.Close(); _err != nil {
|
if _err := conn.Close(); _err != nil {
|
||||||
log.Println(_err)
|
log.Println(_err)
|
||||||
}
|
}
|
||||||
|
log.Println("aborting all pending cures")
|
||||||
|
cm.c.Abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -305,7 +306,6 @@ func cancelRemote(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
addr *net.UnixAddr,
|
addr *net.UnixAddr,
|
||||||
a pkg.Artifact,
|
a pkg.Artifact,
|
||||||
wait bool,
|
|
||||||
) error {
|
) error {
|
||||||
done, conn, err := dial(ctx, addr)
|
done, conn, err := dial(ctx, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -324,19 +324,13 @@ func cancelRemote(
|
|||||||
} else if n != len(id) {
|
} else if n != len(id) {
|
||||||
return errors.Join(io.ErrShortWrite, conn.Close())
|
return errors.Join(io.ErrShortWrite, conn.Close())
|
||||||
}
|
}
|
||||||
if wait {
|
return conn.Close()
|
||||||
if _, err = conn.Read(make([]byte, 1)); err == io.EOF {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.Join(err, conn.Close())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// abortRemote aborts all [pkg.Artifact] curing on a daemon.
|
// abortRemote aborts all [pkg.Artifact] curing on a daemon.
|
||||||
func abortRemote(
|
func abortRemote(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
addr *net.UnixAddr,
|
addr *net.UnixAddr,
|
||||||
wait bool,
|
|
||||||
) error {
|
) error {
|
||||||
done, conn, err := dial(ctx, addr)
|
done, conn, err := dial(ctx, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -345,10 +339,5 @@ func abortRemote(
|
|||||||
defer close(done)
|
defer close(done)
|
||||||
|
|
||||||
err = writeSpecialHeader(conn, specialAbort)
|
err = writeSpecialHeader(conn, specialAbort)
|
||||||
if wait && err == nil {
|
|
||||||
if _, err = conn.Read(make([]byte, 1)); err == io.EOF {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.Join(err, conn.Close())
|
return errors.Join(err, conn.Close())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,11 +106,11 @@ func TestDaemon(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err = cancelRemote(ctx, &addr, pkg.NewFile("nonexistent", nil), true); err != nil {
|
if err = cancelRemote(ctx, &addr, pkg.NewFile("nonexistent", nil)); err != nil {
|
||||||
t.Fatalf("cancelRemote: error = %v", err)
|
t.Fatalf("cancelRemote: error = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = abortRemote(ctx, &addr, true); err != nil {
|
if err = abortRemote(ctx, &addr); err != nil {
|
||||||
t.Fatalf("abortRemote: error = %v", err)
|
t.Fatalf("abortRemote: error = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-14
@@ -6,7 +6,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"unique"
|
|
||||||
|
|
||||||
"hakurei.app/internal/pkg"
|
"hakurei.app/internal/pkg"
|
||||||
"hakurei.app/internal/rosa"
|
"hakurei.app/internal/rosa"
|
||||||
@@ -18,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 {
|
||||||
@@ -36,19 +48,17 @@ func commandInfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t := rosa.Native().Std()
|
|
||||||
for i, name := range args {
|
for i, name := range args {
|
||||||
handle := rosa.ArtifactH(unique.Make(name))
|
if p, ok := rosa.ResolveName(name); !ok {
|
||||||
if meta, a := t.Load(handle); meta == nil {
|
|
||||||
return fmt.Errorf("unknown artifact %q", name)
|
return fmt.Errorf("unknown artifact %q", name)
|
||||||
} else {
|
} else {
|
||||||
var suffix string
|
var suffix string
|
||||||
|
if version := rosa.Std.Version(p); version != rosa.Unversioned {
|
||||||
if meta.Version != rosa.Unversioned {
|
suffix += "-" + version
|
||||||
suffix += "-" + meta.Version
|
|
||||||
}
|
}
|
||||||
mustPrintln("name : " + name + suffix)
|
mustPrintln("name : " + name + suffix)
|
||||||
|
|
||||||
|
meta := rosa.GetMetadata(p)
|
||||||
mustPrintln("description : " + meta.Description)
|
mustPrintln("description : " + meta.Description)
|
||||||
if meta.Website != "" {
|
if meta.Website != "" {
|
||||||
mustPrintln("website : " +
|
mustPrintln("website : " +
|
||||||
@@ -57,10 +67,9 @@ func commandInfo(
|
|||||||
if len(meta.Dependencies) > 0 {
|
if len(meta.Dependencies) > 0 {
|
||||||
mustPrint("depends on :")
|
mustPrint("depends on :")
|
||||||
for _, d := range meta.Dependencies {
|
for _, d := range meta.Dependencies {
|
||||||
_meta, _ := rosa.Native().Std().MustLoad(d)
|
s := rosa.GetMetadata(d).Name
|
||||||
s := _meta.Name
|
if version := rosa.Std.Version(d); version != rosa.Unversioned {
|
||||||
if _meta.Version != rosa.Unversioned {
|
s += "-" + version
|
||||||
s += "-" + _meta.Version
|
|
||||||
}
|
}
|
||||||
mustPrint(" " + s)
|
mustPrint(" " + s)
|
||||||
}
|
}
|
||||||
@@ -72,7 +81,7 @@ func commandInfo(
|
|||||||
if r == nil {
|
if r == nil {
|
||||||
var f io.ReadSeekCloser
|
var f io.ReadSeekCloser
|
||||||
err = cm.Do(func(cache *pkg.Cache) (err error) {
|
err = cm.Do(func(cache *pkg.Cache) (err error) {
|
||||||
f, err = cache.OpenStatus(a)
|
f, err = cache.OpenStatus(rosa.Std.Load(p))
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -91,7 +100,7 @@ func commandInfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
} else if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
||||||
status, n := r.ArtifactOf(cache.Ident(a))
|
status, n := r.ArtifactOf(cache.Ident(rosa.Std.Load(p)))
|
||||||
if status == nil {
|
if status == nil {
|
||||||
mustPrintln(
|
mustPrintln(
|
||||||
statusPrefix + "not in report",
|
statusPrefix + "not in report",
|
||||||
|
|||||||
+19
-39
@@ -10,7 +10,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"unique"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"hakurei.app/internal/pkg"
|
"hakurei.app/internal/pkg"
|
||||||
@@ -21,14 +20,6 @@ import (
|
|||||||
func TestInfo(t *testing.T) {
|
func TestInfo(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
_t := rosa.Native().Std()
|
|
||||||
qemuMeta, _ := _t.Load(rosa.H("qemu"))
|
|
||||||
glibMeta, _ := _t.Load(rosa.H("glib"))
|
|
||||||
zlibMeta, zlib := _t.Load(rosa.H("zlib"))
|
|
||||||
zstdMeta, _ := _t.Load(rosa.H("zstd"))
|
|
||||||
hakureiMeta, _ := _t.Load(rosa.H("hakurei"))
|
|
||||||
hakureiDistMeta, _ := _t.Load(rosa.H("hakurei-dist"))
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
args []string
|
args []string
|
||||||
@@ -38,24 +29,24 @@ func TestInfo(t *testing.T) {
|
|||||||
wantErr any
|
wantErr any
|
||||||
}{
|
}{
|
||||||
{"qemu", []string{"qemu"}, nil, "", `
|
{"qemu", []string{"qemu"}, nil, "", `
|
||||||
name : qemu-` + qemuMeta.Version + `
|
name : qemu-` + rosa.Std.Version(rosa.QEMU) + `
|
||||||
description : a generic and open source machine emulator and virtualizer
|
description : a generic and open source machine emulator and virtualizer
|
||||||
website : https://www.qemu.org
|
website : https://www.qemu.org
|
||||||
depends on : glib-` + glibMeta.Version + ` zstd-` + zstdMeta.Version + `
|
depends on : glib-` + rosa.Std.Version(rosa.GLib) + ` zstd-` + rosa.Std.Version(rosa.Zstd) + `
|
||||||
`, nil},
|
`, nil},
|
||||||
|
|
||||||
{"multi", []string{"hakurei", "hakurei-dist"}, nil, "", `
|
{"multi", []string{"hakurei", "hakurei-dist"}, nil, "", `
|
||||||
name : hakurei-` + hakureiMeta.Version + `
|
name : hakurei-` + rosa.Std.Version(rosa.Hakurei) + `
|
||||||
description : low-level userspace tooling for Rosa OS
|
description : low-level userspace tooling for Rosa OS
|
||||||
website : https://hakurei.app
|
website : https://hakurei.app
|
||||||
|
|
||||||
name : hakurei-dist-` + hakureiDistMeta.Version + `
|
name : hakurei-dist-` + rosa.Std.Version(rosa.HakureiDist) + `
|
||||||
description : low-level userspace tooling for Rosa OS (distribution tarball)
|
description : low-level userspace tooling for Rosa OS (distribution tarball)
|
||||||
website : https://hakurei.app
|
website : https://hakurei.app
|
||||||
`, nil},
|
`, nil},
|
||||||
|
|
||||||
{"nonexistent", []string{"zlib", "\x00"}, nil, "", `
|
{"nonexistent", []string{"zlib", "\x00"}, nil, "", `
|
||||||
name : zlib-` + zlibMeta.Version + `
|
name : zlib-` + rosa.Std.Version(rosa.Zlib) + `
|
||||||
description : lossless data-compression library
|
description : lossless data-compression library
|
||||||
website : https://zlib.net
|
website : https://zlib.net
|
||||||
|
|
||||||
@@ -65,12 +56,12 @@ website : https://zlib.net
|
|||||||
"zstd": "internal/pkg (amd64) on satori\n",
|
"zstd": "internal/pkg (amd64) on satori\n",
|
||||||
"hakurei": "internal/pkg (amd64) on satori\n\n",
|
"hakurei": "internal/pkg (amd64) on satori\n\n",
|
||||||
}, "", `
|
}, "", `
|
||||||
name : zlib-` + zlibMeta.Version + `
|
name : zlib-` + rosa.Std.Version(rosa.Zlib) + `
|
||||||
description : lossless data-compression library
|
description : lossless data-compression library
|
||||||
website : https://zlib.net
|
website : https://zlib.net
|
||||||
status : not yet cured
|
status : not yet cured
|
||||||
|
|
||||||
name : zstd-` + zstdMeta.Version + `
|
name : zstd-` + rosa.Std.Version(rosa.Zstd) + `
|
||||||
description : a fast compression algorithm
|
description : a fast compression algorithm
|
||||||
website : https://facebook.github.io/zstd
|
website : https://facebook.github.io/zstd
|
||||||
status : internal/pkg (amd64) on satori
|
status : internal/pkg (amd64) on satori
|
||||||
@@ -79,19 +70,19 @@ status : internal/pkg (amd64) on satori
|
|||||||
{"status cache perm", []string{"zlib"}, map[string]string{
|
{"status cache perm", []string{"zlib"}, map[string]string{
|
||||||
"zlib": "\x00",
|
"zlib": "\x00",
|
||||||
}, "", `
|
}, "", `
|
||||||
name : zlib-` + zlibMeta.Version + `
|
name : zlib-` + rosa.Std.Version(rosa.Zlib) + `
|
||||||
description : lossless data-compression library
|
description : lossless data-compression library
|
||||||
website : https://zlib.net
|
website : https://zlib.net
|
||||||
`, func(cm *cache) error {
|
`, func(cm *cache) error {
|
||||||
return &os.PathError{
|
return &os.PathError{
|
||||||
Op: "open",
|
Op: "open",
|
||||||
Path: filepath.Join(cm.base, "status", pkg.Encode(cm.c.Ident(zlib).Value())),
|
Path: filepath.Join(cm.base, "status", pkg.Encode(cm.c.Ident(rosa.Std.Load(rosa.Zlib)).Value())),
|
||||||
Err: syscall.EACCES,
|
Err: syscall.EACCES,
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
|
|
||||||
{"status report", []string{"zlib"}, nil, strings.Repeat("\x00", len(pkg.Checksum{})+8), `
|
{"status report", []string{"zlib"}, nil, strings.Repeat("\x00", len(pkg.Checksum{})+8), `
|
||||||
name : zlib-` + zlibMeta.Version + `
|
name : zlib-` + rosa.Std.Version(rosa.Zlib) + `
|
||||||
description : lossless data-compression library
|
description : lossless data-compression library
|
||||||
website : https://zlib.net
|
website : https://zlib.net
|
||||||
status : not in report
|
status : not in report
|
||||||
@@ -104,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 != "" {
|
||||||
@@ -117,31 +108,20 @@ 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 {
|
||||||
for name, status := range tc.status {
|
for name, status := range tc.status {
|
||||||
_, a := _t.Load(rosa.ArtifactH(unique.Make(name)))
|
p, ok := rosa.ResolveName(name)
|
||||||
if a == nil {
|
if !ok {
|
||||||
t.Fatalf("invalid name %q", name)
|
t.Fatalf("invalid name %q", name)
|
||||||
}
|
}
|
||||||
perm := os.FileMode(0400)
|
perm := os.FileMode(0400)
|
||||||
@@ -152,7 +132,7 @@ status : not in report
|
|||||||
return os.WriteFile(filepath.Join(
|
return os.WriteFile(filepath.Join(
|
||||||
cm.base,
|
cm.base,
|
||||||
"status",
|
"status",
|
||||||
pkg.Encode(cache.Ident(a).Value()),
|
pkg.Encode(cache.Ident(rosa.Std.Load(p)).Value()),
|
||||||
), unsafe.Slice(unsafe.StringData(status), len(status)), perm)
|
), unsafe.Slice(unsafe.StringData(status), len(status)), perm)
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Fatalf("Do: error = %v", err)
|
t.Fatalf("Do: error = %v", err)
|
||||||
@@ -177,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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)))
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
+53
-275
@@ -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() {
|
||||||
@@ -58,82 +54,34 @@ func main() {
|
|||||||
log.Fatal("this program must not run as root")
|
log.Fatal("this program must not run as root")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
r := recover()
|
|
||||||
if r == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
e, ok := r.(rosa.LoadError)
|
|
||||||
if !ok {
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
log.Fatal(e)
|
|
||||||
}()
|
|
||||||
|
|
||||||
ctx, stop := signal.NotifyContext(context.Background(),
|
ctx, stop := signal.NotifyContext(context.Background(),
|
||||||
syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||||
defer stop()
|
defer stop()
|
||||||
|
|
||||||
var cm cache
|
var cm cache
|
||||||
defer func() { cm.Close() }()
|
defer func() {
|
||||||
|
cm.Close()
|
||||||
|
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Println(r)
|
||||||
|
log.Fatal("consider scrubbing the on-disk cache")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
flagQuiet bool
|
flagQuiet bool
|
||||||
flagQEMU bool
|
|
||||||
flagArch string
|
|
||||||
flagCheck bool
|
|
||||||
flagLTO bool
|
|
||||||
flagPT bool
|
|
||||||
|
|
||||||
flagCrossOverride int
|
|
||||||
|
|
||||||
addr net.UnixAddr
|
addr net.UnixAddr
|
||||||
)
|
)
|
||||||
c := command.New(os.Stderr, log.Printf, "mbf", func([]string) error {
|
c := command.New(os.Stderr, log.Printf, "mbf", func([]string) error {
|
||||||
if !rosa.Native().HasStageEarly() {
|
|
||||||
return pkg.UnsupportedArchError(runtime.GOARCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
if flagPT {
|
|
||||||
log.Println("parsed in", rosa.ParseTime())
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.SwapVerbose(!flagQuiet)
|
msg.SwapVerbose(!flagQuiet)
|
||||||
cm.ctx, cm.msg = ctx, msg
|
cm.ctx, cm.msg = ctx, msg
|
||||||
cm.base = os.ExpandEnv(cm.base)
|
cm.base = os.ExpandEnv(cm.base)
|
||||||
if cm.base == "" {
|
|
||||||
cm.base = "cache"
|
|
||||||
}
|
|
||||||
|
|
||||||
addr.Net = "unix"
|
addr.Net = "unix"
|
||||||
addr.Name = os.ExpandEnv(addr.Name)
|
addr.Name = os.ExpandEnv(addr.Name)
|
||||||
if addr.Name == "" {
|
if addr.Name == "" {
|
||||||
addr.Name = filepath.Join(cm.base, "daemon")
|
addr.Name = "daemon"
|
||||||
}
|
|
||||||
|
|
||||||
var flags int
|
|
||||||
if !flagCheck {
|
|
||||||
flags |= rosa.OptSkipCheck
|
|
||||||
}
|
|
||||||
if !flagLTO {
|
|
||||||
flags |= rosa.OptLLVMNoLTO
|
|
||||||
}
|
|
||||||
rosa.Native().DropCaches("", flags)
|
|
||||||
cross := flagArch != "" && flagArch != runtime.GOARCH
|
|
||||||
if flagQEMU || cross {
|
|
||||||
_, cm.qemu = rosa.Native().Std().MustLoad(rosa.H("qemu"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if cross {
|
|
||||||
if flagCrossOverride != -1 {
|
|
||||||
flags = flagCrossOverride
|
|
||||||
}
|
|
||||||
|
|
||||||
rosa.Native().DropCaches(flagArch, flags)
|
|
||||||
if !rosa.Native().HasStageEarly() {
|
|
||||||
return pkg.UnsupportedArchError(flagArch)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -141,30 +89,6 @@ func main() {
|
|||||||
&flagQuiet,
|
&flagQuiet,
|
||||||
"q", command.BoolFlag(false),
|
"q", command.BoolFlag(false),
|
||||||
"Do not print cure messages",
|
"Do not print cure messages",
|
||||||
).Flag(
|
|
||||||
&flagQEMU,
|
|
||||||
"register", command.BoolFlag(false),
|
|
||||||
"Enable additional target architectures",
|
|
||||||
).Flag(
|
|
||||||
&flagArch,
|
|
||||||
"arch", command.StringFlag(runtime.GOARCH),
|
|
||||||
"Target architecture",
|
|
||||||
).Flag(
|
|
||||||
&flagLTO,
|
|
||||||
"lto", command.BoolFlag(false),
|
|
||||||
"Enable LTO in stage2 and stage3 LLVM toolchains",
|
|
||||||
).Flag(
|
|
||||||
&flagCheck,
|
|
||||||
"check", command.BoolFlag(true),
|
|
||||||
"Run test suites",
|
|
||||||
).Flag(
|
|
||||||
&flagCrossOverride,
|
|
||||||
"cross-flags", command.IntFlag(-1),
|
|
||||||
"Override non-native target preset flags",
|
|
||||||
).Flag(
|
|
||||||
&cm.verboseInit,
|
|
||||||
"v", command.BoolFlag(false),
|
|
||||||
"Do not suppress verbose output from init",
|
|
||||||
).Flag(
|
).Flag(
|
||||||
&cm.cures,
|
&cm.cures,
|
||||||
"cures", command.IntFlag(0),
|
"cures", command.IntFlag(0),
|
||||||
@@ -192,26 +116,12 @@ func main() {
|
|||||||
&addr.Name,
|
&addr.Name,
|
||||||
"socket", command.StringFlag("$MBF_DAEMON_SOCKET"),
|
"socket", command.StringFlag("$MBF_DAEMON_SOCKET"),
|
||||||
"Pathname of socket to bind to",
|
"Pathname of socket to bind to",
|
||||||
).Flag(
|
|
||||||
&flagPT,
|
|
||||||
"parse-time", command.BoolFlag(false),
|
|
||||||
"Print duration of the initial azalea parse",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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
|
||||||
@@ -245,7 +155,6 @@ func main() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var (
|
var (
|
||||||
flagBind string
|
|
||||||
flagStatus bool
|
flagStatus bool
|
||||||
flagReport string
|
flagReport string
|
||||||
)
|
)
|
||||||
@@ -253,52 +162,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),
|
||||||
@@ -357,12 +222,12 @@ func main() {
|
|||||||
n atomic.Uint64
|
n atomic.Uint64
|
||||||
)
|
)
|
||||||
|
|
||||||
w := make(chan rosa.ArtifactH)
|
w := make(chan rosa.PArtifact)
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
for range max(flagJobs, 1) {
|
for range max(flagJobs, 1) {
|
||||||
wg.Go(func() {
|
wg.Go(func() {
|
||||||
for p := range w {
|
for p := range w {
|
||||||
meta, _ := rosa.Native().Std().MustLoad(p)
|
meta := rosa.GetMetadata(p)
|
||||||
if meta.ID == 0 {
|
if meta.ID == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -375,9 +240,12 @@ func main() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if latest := meta.GetLatest(v); meta.Version != latest {
|
if current, latest :=
|
||||||
|
rosa.Std.Version(p),
|
||||||
|
meta.GetLatest(v); current != latest {
|
||||||
|
|
||||||
n.Add(1)
|
n.Add(1)
|
||||||
log.Printf("%s %s < %s", meta.Name, meta.Version, latest)
|
log.Printf("%s %s < %s", meta.Name, current, latest)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,9 +255,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
for _, p := range rosa.Native().CollectAll() {
|
for i := range rosa.PresetEnd {
|
||||||
select {
|
select {
|
||||||
case w <- p:
|
case w <- rosa.PArtifact(i):
|
||||||
break
|
break
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
break done
|
break done
|
||||||
@@ -434,9 +302,9 @@ func main() {
|
|||||||
"stage3",
|
"stage3",
|
||||||
"Check for toolchain 3-stage non-determinism",
|
"Check for toolchain 3-stage non-determinism",
|
||||||
func(args []string) (err error) {
|
func(args []string) (err error) {
|
||||||
s := rosa.Std
|
t := rosa.Std
|
||||||
if flagGentoo != "" {
|
if flagGentoo != "" {
|
||||||
s -= 3 // magic number to discourage misuse
|
t -= 3 // magic number to discourage misuse
|
||||||
|
|
||||||
var checksum pkg.Checksum
|
var checksum pkg.Checksum
|
||||||
if len(flagChecksum) != 0 {
|
if len(flagChecksum) != 0 {
|
||||||
@@ -444,7 +312,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rosa.Native().SetGentooStage3(flagGentoo, checksum)
|
rosa.SetGentooStage3(flagGentoo, checksum)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -452,10 +320,10 @@ func main() {
|
|||||||
checksum [2]unique.Handle[pkg.Checksum]
|
checksum [2]unique.Handle[pkg.Checksum]
|
||||||
)
|
)
|
||||||
|
|
||||||
_llvm := rosa.H("llvm")
|
|
||||||
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
||||||
_, llvm := rosa.Native().New(s - 2).Load(_llvm)
|
pathname, _, err = cache.Cure(
|
||||||
pathname, _, err = cache.Cure(llvm)
|
(t - 2).Load(rosa.Clang),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
@@ -463,16 +331,18 @@ func main() {
|
|||||||
log.Println("stage1:", pathname)
|
log.Println("stage1:", pathname)
|
||||||
|
|
||||||
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
||||||
_, llvm := rosa.Native().New(s - 1).Load(_llvm)
|
pathname, checksum[0], err = cache.Cure(
|
||||||
pathname, checksum[0], err = cache.Cure(llvm)
|
(t - 1).Load(rosa.Clang),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Println("stage2:", pathname)
|
log.Println("stage2:", pathname)
|
||||||
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
||||||
_, llvm := rosa.Native().New(s).Load(_llvm)
|
pathname, checksum[1], err = cache.Cure(
|
||||||
pathname, checksum[1], err = cache.Cure(llvm)
|
t.Load(rosa.Clang),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
@@ -493,7 +363,9 @@ func main() {
|
|||||||
|
|
||||||
if flagStage0 {
|
if flagStage0 {
|
||||||
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
if err = cm.Do(func(cache *pkg.Cache) (err error) {
|
||||||
pathname, _, err = cache.Cure(rosa.Native().Std().NewStage0())
|
pathname, _, err = cache.Cure(
|
||||||
|
t.Load(rosa.Stage0),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
@@ -525,11 +397,6 @@ func main() {
|
|||||||
flagExport string
|
flagExport string
|
||||||
flagRemote bool
|
flagRemote bool
|
||||||
flagNoReply bool
|
flagNoReply bool
|
||||||
flagFaults bool
|
|
||||||
flagPop bool
|
|
||||||
|
|
||||||
flagBoot bool
|
|
||||||
flagStd bool
|
|
||||||
)
|
)
|
||||||
c.NewCommand(
|
c.NewCommand(
|
||||||
"cure",
|
"cure",
|
||||||
@@ -538,16 +405,8 @@ func main() {
|
|||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return errors.New("cure requires 1 argument")
|
return errors.New("cure requires 1 argument")
|
||||||
}
|
}
|
||||||
|
p, ok := rosa.ResolveName(args[0])
|
||||||
t := rosa.Std
|
if !ok {
|
||||||
if flagBoot {
|
|
||||||
t -= 2
|
|
||||||
} else if flagStd {
|
|
||||||
t -= 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_, a := rosa.Native().New(t).Load(rosa.ArtifactH(unique.Make(args[0])))
|
|
||||||
if a == nil {
|
|
||||||
return fmt.Errorf("unknown artifact %q", args[0])
|
return fmt.Errorf("unknown artifact %q", args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,7 +414,7 @@ func main() {
|
|||||||
default:
|
default:
|
||||||
var pathname *check.Absolute
|
var pathname *check.Absolute
|
||||||
err := cm.Do(func(cache *pkg.Cache) (err error) {
|
err := cm.Do(func(cache *pkg.Cache) (err error) {
|
||||||
pathname, _, err = cache.Cure(a)
|
pathname, _, err = cache.Cure(rosa.Std.Load(p))
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -597,7 +456,7 @@ func main() {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = pkg.NewIR().EncodeAll(f, a); err != nil {
|
if err = pkg.NewIR().EncodeAll(f, rosa.Std.Load(p)); err != nil {
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -608,7 +467,7 @@ func main() {
|
|||||||
return cm.Do(func(cache *pkg.Cache) error {
|
return cm.Do(func(cache *pkg.Cache) error {
|
||||||
return cache.EnterExec(
|
return cache.EnterExec(
|
||||||
ctx,
|
ctx,
|
||||||
a,
|
rosa.Std.Load(p),
|
||||||
true, os.Stdin, os.Stdout, os.Stderr,
|
true, os.Stdin, os.Stdout, os.Stderr,
|
||||||
rosa.AbsSystem.Append("bin", "mksh"),
|
rosa.AbsSystem.Append("bin", "mksh"),
|
||||||
"sh",
|
"sh",
|
||||||
@@ -620,6 +479,7 @@ func main() {
|
|||||||
if flagNoReply {
|
if flagNoReply {
|
||||||
flags |= remoteNoReply
|
flags |= remoteNoReply
|
||||||
}
|
}
|
||||||
|
a := rosa.Std.Load(p)
|
||||||
pathname, err := cureRemote(ctx, &addr, a, flags)
|
pathname, err := cureRemote(ctx, &addr, a, flags)
|
||||||
if !flagNoReply && err == nil {
|
if !flagNoReply && err == nil {
|
||||||
log.Println(pathname)
|
log.Println(pathname)
|
||||||
@@ -629,55 +489,12 @@ func main() {
|
|||||||
cc, cancel := context.WithDeadline(context.Background(), daemonDeadline())
|
cc, cancel := context.WithDeadline(context.Background(), daemonDeadline())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if _err := cancelRemote(cc, &addr, a, false); _err != nil {
|
if _err := cancelRemote(cc, &addr, a); _err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|
||||||
case flagFaults:
|
|
||||||
var faults []pkg.Fault
|
|
||||||
if err := cm.Do(func(cache *pkg.Cache) (err error) {
|
|
||||||
faults, err = cache.ReadFaults(a)
|
|
||||||
return
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fault := range faults {
|
|
||||||
log.Printf("%s: %s ago", fault.String(), time.Since(fault.Time()))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
|
|
||||||
case flagPop:
|
|
||||||
var faults []pkg.Fault
|
|
||||||
if err := cm.Do(func(cache *pkg.Cache) (err error) {
|
|
||||||
faults, err = cache.ReadFaults(a)
|
|
||||||
return
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(faults) == 0 {
|
|
||||||
return errors.New("no fault entries found")
|
|
||||||
}
|
|
||||||
fault := faults[len(faults)-1]
|
|
||||||
r, err := fault.Open()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err = io.Copy(os.Stdout, r); err != nil {
|
|
||||||
_ = r.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
if err = r.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("faulting cure terminated %s ago", time.Since(fault.Time()))
|
|
||||||
return fault.Destroy()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
).Flag(
|
).Flag(
|
||||||
@@ -700,52 +517,13 @@ func main() {
|
|||||||
&flagNoReply,
|
&flagNoReply,
|
||||||
"no-reply", command.BoolFlag(false),
|
"no-reply", command.BoolFlag(false),
|
||||||
"Do not receive a reply from the daemon",
|
"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",
|
|
||||||
).Flag(
|
|
||||||
&flagFaults,
|
|
||||||
"faults", command.BoolFlag(false),
|
|
||||||
"Display fault entries of the specified artifact",
|
|
||||||
).Flag(
|
|
||||||
&flagPop,
|
|
||||||
"pop", command.BoolFlag(false),
|
|
||||||
"Display and destroy the most recent fault entry",
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.NewCommand(
|
|
||||||
"clear",
|
|
||||||
"Remove all fault entries from the cache",
|
|
||||||
func([]string) error {
|
|
||||||
return cm.Do(func(*pkg.Cache) error {
|
|
||||||
pathname := filepath.Join(cm.base, "fault")
|
|
||||||
dents, err := os.ReadDir(pathname)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, dent := range dents {
|
|
||||||
msg.Verbosef("destroying entry %s", dent.Name())
|
|
||||||
if err = os.Remove(filepath.Join(pathname, dent.Name())); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Printf("destroyed %d fault entries", len(dents))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
c.NewCommand(
|
c.NewCommand(
|
||||||
"abort",
|
"abort",
|
||||||
"Abort all pending cures on the daemon",
|
"Abort all pending cures on the daemon",
|
||||||
func([]string) error { return abortRemote(ctx, &addr, false) },
|
func([]string) error { return abortRemote(ctx, &addr) },
|
||||||
)
|
)
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -759,26 +537,27 @@ func main() {
|
|||||||
"shell",
|
"shell",
|
||||||
"Interactive shell in the specified Rosa OS environment",
|
"Interactive shell in the specified Rosa OS environment",
|
||||||
func(args []string) error {
|
func(args []string) error {
|
||||||
handles := make([]rosa.ArtifactH, len(args), len(args)+3)
|
presets := make([]rosa.PArtifact, len(args)+3)
|
||||||
for i, arg := range args {
|
for i, arg := range args {
|
||||||
handles[i] = rosa.ArtifactH(unique.Make(arg))
|
p, ok := rosa.ResolveName(arg)
|
||||||
if meta, _ := rosa.Native().Std().Load(handles[i]); meta == nil {
|
if !ok {
|
||||||
return fmt.Errorf("unknown artifact %q", arg)
|
return fmt.Errorf("unknown artifact %q", arg)
|
||||||
}
|
}
|
||||||
|
presets[i] = p
|
||||||
}
|
}
|
||||||
|
|
||||||
base := rosa.H("llvm")
|
base := rosa.Clang
|
||||||
if !flagWithToolchain {
|
if !flagWithToolchain {
|
||||||
base = rosa.H("musl")
|
base = rosa.Musl
|
||||||
}
|
}
|
||||||
handles = append(handles,
|
presets = append(presets,
|
||||||
base,
|
base,
|
||||||
rosa.H("mksh"),
|
rosa.Mksh,
|
||||||
rosa.H("toybox"),
|
rosa.Toybox,
|
||||||
)
|
)
|
||||||
|
|
||||||
root := make(pkg.Collect, 0, 6+len(args))
|
root := make(pkg.Collect, 0, 6+len(args))
|
||||||
root = rosa.Native().Std().Append(root, handles...)
|
root = rosa.Std.AppendPresets(root, presets...)
|
||||||
|
|
||||||
if err := cm.Do(func(cache *pkg.Cache) error {
|
if err := cm.Do(func(cache *pkg.Cache) error {
|
||||||
_, _, err := cache.Cure(&root)
|
_, _, err := cache.Cure(&root)
|
||||||
@@ -839,7 +618,6 @@ func main() {
|
|||||||
z.Hostname = "localhost"
|
z.Hostname = "localhost"
|
||||||
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
|
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
|
||||||
z.Stdin, z.Stdout, z.Stderr = os.Stdin, os.Stdout, os.Stderr
|
z.Stdin, z.Stdout, z.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||||
z.Quiet = !cm.verboseInit
|
|
||||||
if s, ok := os.LookupEnv("TERM"); ok {
|
if s, ok := os.LookupEnv("TERM"); ok {
|
||||||
z.Env = append(z.Env, "TERM="+s)
|
z.Env = append(z.Env, "TERM="+s)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"hakurei.app/internal/rosa"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
rosa.Native().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 _, handle := range rosa.Native().Collect() {
|
|
||||||
_, a := rosa.Native().Std().MustLoad(handle)
|
|
||||||
t.Run(handle.String(), func(t *testing.T) {
|
|
||||||
_, err := cureRemote(t.Context(), &addr, a, 0)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
// Package pkgserver implements the package metadata service backend.
|
package main
|
||||||
package pkgserver
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -10,7 +8,6 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"hakurei.app/internal/info"
|
"hakurei.app/internal/info"
|
||||||
"hakurei.app/internal/rosa"
|
"hakurei.app/internal/rosa"
|
||||||
@@ -30,7 +27,7 @@ var (
|
|||||||
// handleInfo writes constant system information.
|
// handleInfo writes constant system information.
|
||||||
func handleInfo(w http.ResponseWriter, _ *http.Request) {
|
func handleInfo(w http.ResponseWriter, _ *http.Request) {
|
||||||
infoPayloadOnce.Do(func() {
|
infoPayloadOnce.Do(func() {
|
||||||
infoPayload.Count = len(rosa.Native().Collect())
|
infoPayload.Count = int(rosa.PresetUnexportedStart)
|
||||||
infoPayload.HakureiVersion = info.Version()
|
infoPayload.HakureiVersion = info.Version()
|
||||||
})
|
})
|
||||||
// TODO(mae): cache entire response if no additional fields are planned
|
// TODO(mae): cache entire response if no additional fields are planned
|
||||||
@@ -91,7 +88,7 @@ func (index *packageIndex) handleGet(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil || i >= len(index.sorts[0]) || i < 0 {
|
if err != nil || i >= len(index.sorts[0]) || i < 0 {
|
||||||
http.Error(
|
http.Error(
|
||||||
w, "index must be an integer between 0 and "+
|
w, "index must be an integer between 0 and "+
|
||||||
strconv.Itoa(len(index.sorts[0])-1),
|
strconv.Itoa(int(rosa.PresetUnexportedStart-1)),
|
||||||
http.StatusBadRequest,
|
http.StatusBadRequest,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@@ -125,7 +122,7 @@ func (index *packageIndex) handleSearch(w http.ResponseWriter, r *http.Request)
|
|||||||
if err != nil || i >= len(index.sorts[0]) || i < 0 {
|
if err != nil || i >= len(index.sorts[0]) || i < 0 {
|
||||||
http.Error(
|
http.Error(
|
||||||
w, "index must be an integer between 0 and "+
|
w, "index must be an integer between 0 and "+
|
||||||
strconv.Itoa(len(index.sorts[0])-1),
|
strconv.Itoa(int(rosa.PresetUnexportedStart-1)),
|
||||||
http.StatusBadRequest,
|
http.StatusBadRequest,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@@ -161,29 +158,6 @@ func (index *packageIndex) registerAPI(mux *http.ServeMux) {
|
|||||||
mux.HandleFunc("GET /status/", index.newStatusHandler(true))
|
mux.HandleFunc("GET /status/", index.newStatusHandler(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register arranges for mux to service API requests.
|
|
||||||
func Register(ctx context.Context, mux *http.ServeMux, report *rosa.Report) error {
|
|
||||||
var index packageIndex
|
|
||||||
index.search = make(searchCache)
|
|
||||||
if err := index.populate(report); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ticker := time.NewTicker(1 * time.Minute)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
ticker.Stop()
|
|
||||||
return
|
|
||||||
case <-ticker.C:
|
|
||||||
index.search.clean()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
index.registerAPI(mux)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeAPIPayload sets headers common to API responses and encodes payload as
|
// writeAPIPayload sets headers common to API responses and encodes payload as
|
||||||
// JSON for the response body.
|
// JSON for the response body.
|
||||||
func writeAPIPayload(w http.ResponseWriter, payload any) {
|
func writeAPIPayload(w http.ResponseWriter, payload any) {
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package pkgserver
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ func TestAPIInfo(t *testing.T) {
|
|||||||
checkPayload(t, resp, struct {
|
checkPayload(t, resp, struct {
|
||||||
Count int `json:"count"`
|
Count int `json:"count"`
|
||||||
HakureiVersion string `json:"hakurei_version"`
|
HakureiVersion string `json:"hakurei_version"`
|
||||||
}{len(rosa.Native().Collect()), info.Version()})
|
}{int(rosa.PresetUnexportedStart), info.Version()})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPIGet(t *testing.T) {
|
func TestAPIGet(t *testing.T) {
|
||||||
@@ -92,12 +93,11 @@ func TestAPIGet(t *testing.T) {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
count := len(rosa.Native().Collect())
|
|
||||||
t.Run("index", func(t *testing.T) {
|
t.Run("index", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
checkValidate(
|
checkValidate(
|
||||||
t, "limit=1&sort=0&index", 0, count-1,
|
t, "limit=1&sort=0&index", 0, int(rosa.PresetUnexportedStart-1),
|
||||||
"index must be an integer between 0 and "+strconv.Itoa(count-1),
|
"index must be an integer between 0 and "+strconv.Itoa(int(rosa.PresetUnexportedStart-1)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -108,4 +108,76 @@ func TestAPIGet(t *testing.T) {
|
|||||||
"sort must be an integer between 0 and "+strconv.Itoa(int(sortOrderEnd)),
|
"sort must be an integer between 0 and "+strconv.Itoa(int(sortOrderEnd)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
checkWithSuffix := func(name, suffix string, want []*metadata) {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
w := newRequest(suffix)
|
||||||
|
resp := w.Result()
|
||||||
|
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
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
checkWithSuffix("declarationAscending", "?limit=2&index=0&sort=0", []*metadata{
|
||||||
|
{
|
||||||
|
Metadata: rosa.GetMetadata(0),
|
||||||
|
Version: rosa.Std.Version(0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Metadata: rosa.GetMetadata(1),
|
||||||
|
Version: rosa.Std.Version(1),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
checkWithSuffix("declarationAscending offset", "?limit=3&index=5&sort=0", []*metadata{
|
||||||
|
{
|
||||||
|
Metadata: rosa.GetMetadata(5),
|
||||||
|
Version: rosa.Std.Version(5),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Metadata: rosa.GetMetadata(6),
|
||||||
|
Version: rosa.Std.Version(6),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Metadata: rosa.GetMetadata(7),
|
||||||
|
Version: rosa.Std.Version(7),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
checkWithSuffix("declarationDescending", "?limit=3&index=0&sort=1", []*metadata{
|
||||||
|
{
|
||||||
|
Metadata: rosa.GetMetadata(rosa.PresetUnexportedStart - 1),
|
||||||
|
Version: rosa.Std.Version(rosa.PresetUnexportedStart - 1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Metadata: rosa.GetMetadata(rosa.PresetUnexportedStart - 2),
|
||||||
|
Version: rosa.Std.Version(rosa.PresetUnexportedStart - 2),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Metadata: rosa.GetMetadata(rosa.PresetUnexportedStart - 3),
|
||||||
|
Version: rosa.Std.Version(rosa.PresetUnexportedStart - 3),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
checkWithSuffix("declarationDescending offset", "?limit=1&index=37&sort=1", []*metadata{
|
||||||
|
{
|
||||||
|
Metadata: rosa.GetMetadata(rosa.PresetUnexportedStart - 38),
|
||||||
|
Version: rosa.Std.Version(rosa.PresetUnexportedStart - 38),
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package pkgserver
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
@@ -23,7 +23,7 @@ const (
|
|||||||
|
|
||||||
// packageIndex refers to metadata by name and various sort orders.
|
// packageIndex refers to metadata by name and various sort orders.
|
||||||
type packageIndex struct {
|
type packageIndex struct {
|
||||||
sorts [sortOrderEnd + 1][]*metadata
|
sorts [sortOrderEnd + 1][rosa.PresetUnexportedStart]*metadata
|
||||||
names map[string]*metadata
|
names map[string]*metadata
|
||||||
search searchCache
|
search searchCache
|
||||||
// Taken from [rosa.Report] if available.
|
// Taken from [rosa.Report] if available.
|
||||||
@@ -32,11 +32,11 @@ type packageIndex struct {
|
|||||||
|
|
||||||
// metadata holds [rosa.Metadata] extended with additional information.
|
// metadata holds [rosa.Metadata] extended with additional information.
|
||||||
type metadata struct {
|
type metadata struct {
|
||||||
handle rosa.ArtifactH
|
p rosa.PArtifact
|
||||||
*rosa.Metadata
|
*rosa.Metadata
|
||||||
|
|
||||||
// Copied from [rosa.Metadata], [rosa.Unversioned] is equivalent to the zero
|
// Populated via [rosa.Toolchain.Version], [rosa.Unversioned] is equivalent
|
||||||
// value. Otherwise, the zero value is invalid.
|
// to the zero value. Otherwise, the zero value is invalid.
|
||||||
Version string `json:"version,omitempty"`
|
Version string `json:"version,omitempty"`
|
||||||
// Output data size, available if present in report.
|
// Output data size, available if present in report.
|
||||||
Size int64 `json:"size,omitempty"`
|
Size int64 `json:"size,omitempty"`
|
||||||
@@ -50,23 +50,20 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
handles := rosa.Native().Collect()
|
var work [rosa.PresetUnexportedStart]*metadata
|
||||||
work := make([]*metadata, len(handles))
|
|
||||||
index.names = make(map[string]*metadata)
|
index.names = make(map[string]*metadata)
|
||||||
ir := pkg.NewIR()
|
for p := range rosa.PresetUnexportedStart {
|
||||||
for i, handle := range handles {
|
|
||||||
meta, a := rosa.Native().Std().MustLoad(handle)
|
|
||||||
m := metadata{
|
m := metadata{
|
||||||
handle: handle,
|
p: p,
|
||||||
|
|
||||||
Metadata: meta,
|
Metadata: rosa.GetMetadata(p),
|
||||||
Version: meta.Version,
|
Version: rosa.Std.Version(p),
|
||||||
}
|
}
|
||||||
if m.Version == "" {
|
if m.Version == "" {
|
||||||
return errors.New("invalid version from " + m.Name)
|
return errors.New("invalid version from " + m.Name)
|
||||||
@@ -75,33 +72,33 @@ func (index *packageIndex) populate(report *rosa.Report) (err error) {
|
|||||||
m.Version = ""
|
m.Version = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if report != nil {
|
if cache != nil && report != nil {
|
||||||
id := ir.Ident(a)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
work[i] = &m
|
work[p] = &m
|
||||||
index.names[m.Name] = &m
|
index.names[m.Name] = &m
|
||||||
}
|
}
|
||||||
|
|
||||||
index.sorts[declarationAscending] = work
|
index.sorts[declarationAscending] = work
|
||||||
index.sorts[declarationDescending] = slices.Clone(work)
|
index.sorts[declarationDescending] = work
|
||||||
slices.Reverse(index.sorts[declarationDescending][:])
|
slices.Reverse(index.sorts[declarationDescending][:])
|
||||||
|
|
||||||
index.sorts[nameAscending] = slices.Clone(work)
|
index.sorts[nameAscending] = work
|
||||||
slices.SortFunc(index.sorts[nameAscending][:], func(a, b *metadata) int {
|
slices.SortFunc(index.sorts[nameAscending][:], func(a, b *metadata) int {
|
||||||
return strings.Compare(a.Name, b.Name)
|
return strings.Compare(a.Name, b.Name)
|
||||||
})
|
})
|
||||||
index.sorts[nameDescending] = slices.Clone(index.sorts[nameAscending])
|
index.sorts[nameDescending] = index.sorts[nameAscending]
|
||||||
slices.Reverse(index.sorts[nameDescending][:])
|
slices.Reverse(index.sorts[nameDescending][:])
|
||||||
|
|
||||||
index.sorts[sizeAscending] = slices.Clone(work)
|
index.sorts[sizeAscending] = work
|
||||||
slices.SortFunc(index.sorts[sizeAscending][:], func(a, b *metadata) int {
|
slices.SortFunc(index.sorts[sizeAscending][:], func(a, b *metadata) int {
|
||||||
return cmp.Compare(a.Size, b.Size)
|
return cmp.Compare(a.Size, b.Size)
|
||||||
})
|
})
|
||||||
index.sorts[sizeDescending] = slices.Clone(index.sorts[sizeAscending])
|
index.sorts[sizeDescending] = index.sorts[sizeAscending]
|
||||||
slices.Reverse(index.sorts[sizeDescending][:])
|
slices.Reverse(index.sorts[sizeDescending][:])
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"hakurei.app/check"
|
||||||
|
"hakurei.app/command"
|
||||||
|
"hakurei.app/internal/pkg"
|
||||||
|
"hakurei.app/internal/rosa"
|
||||||
|
"hakurei.app/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
const shutdownTimeout = 15 * time.Second
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.SetPrefix("pkgserver: ")
|
||||||
|
|
||||||
|
var (
|
||||||
|
flagBaseDir string
|
||||||
|
flagAddr string
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||||
|
defer stop()
|
||||||
|
msg := message.New(log.Default())
|
||||||
|
|
||||||
|
c := command.New(os.Stderr, log.Printf, "pkgserver", func(args []string) error {
|
||||||
|
var (
|
||||||
|
cache *pkg.Cache
|
||||||
|
report *rosa.Report
|
||||||
|
)
|
||||||
|
switch len(args) {
|
||||||
|
case 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
baseDir, err := check.NewAbs(flagBaseDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cache, err = pkg.Open(ctx, msg, 0, 0, 0, baseDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer cache.Close()
|
||||||
|
|
||||||
|
report, err = rosa.OpenReport(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return errors.New("pkgserver requires 1 argument")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var index packageIndex
|
||||||
|
index.search = make(searchCache)
|
||||||
|
if err := index.populate(cache, report); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ticker := time.NewTicker(1 * time.Minute)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
ticker.Stop()
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
index.search.clean()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var mux http.ServeMux
|
||||||
|
uiRoutes(&mux)
|
||||||
|
index.registerAPI(&mux)
|
||||||
|
server := http.Server{
|
||||||
|
Addr: flagAddr,
|
||||||
|
Handler: &mux,
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
c, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
|
||||||
|
defer cancel()
|
||||||
|
if err := server.Shutdown(c); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return server.ListenAndServe()
|
||||||
|
}).Flag(
|
||||||
|
&flagBaseDir,
|
||||||
|
"b", command.StringFlag(""),
|
||||||
|
"base directory for cache",
|
||||||
|
).Flag(
|
||||||
|
&flagAddr,
|
||||||
|
"addr", command.StringFlag(":8067"),
|
||||||
|
"TCP network address to listen on",
|
||||||
|
)
|
||||||
|
c.MustParse(os.Args[1:], func(err error) {
|
||||||
|
if errors.Is(err, http.ErrServerClosed) {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
log.Fatal(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package pkgserver
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -15,7 +15,7 @@ func newIndex(t *testing.T) *packageIndex {
|
|||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
var index packageIndex
|
var index packageIndex
|
||||||
if err := index.populate(nil); err != nil {
|
if err := index.populate(nil, nil); err != nil {
|
||||||
t.Fatalf("populate: error = %v", err)
|
t.Fatalf("populate: error = %v", err)
|
||||||
}
|
}
|
||||||
return &index
|
return &index
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package pkgserver
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func serveWebUI(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
w.Header().Set("Pragma", "no-cache")
|
||||||
|
w.Header().Set("Expires", "0")
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
w.Header().Set("X-XSS-Protection", "1")
|
||||||
|
w.Header().Set("X-Frame-Options", "DENY")
|
||||||
|
|
||||||
|
http.ServeFileFS(w, r, content, "ui/index.html")
|
||||||
|
}
|
||||||
|
func serveStaticContent(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.URL.Path {
|
||||||
|
case "/static/style.css":
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/style.css")
|
||||||
|
case "/favicon.ico":
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/favicon.ico")
|
||||||
|
case "/static/index.js":
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/index.js")
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func uiRoutes(mux *http.ServeMux) {
|
||||||
|
mux.HandleFunc("GET /{$}", serveWebUI)
|
||||||
|
mux.HandleFunc("GET /favicon.ico", serveStaticContent)
|
||||||
|
mux.HandleFunc("GET /static/", serveStaticContent)
|
||||||
|
}
|
||||||
@@ -3,13 +3,12 @@
|
|||||||
<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">
|
||||||
<link rel="icon" href="https://hakurei.app/favicon.ico"/>
|
<title>Hakurei PkgServer</title>
|
||||||
<title>Rosa OS Packages</title>
|
<script src="static/index.js"></script>
|
||||||
<script src="index.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Rosa OS Packages</h1>
|
<h1>Hakurei PkgServer</h1>
|
||||||
<div class="top-controls" id="top-controls-regular">
|
<div class="top-controls" id="top-controls-regular">
|
||||||
<p>Showing entries <span id="entry-counter"></span>.</p>
|
<p>Showing entries <span id="entry-counter"></span>.</p>
|
||||||
<span id="search-bar">
|
<span id="search-bar">
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build frontend
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "embed"
|
||||||
|
|
||||||
|
//go:generate tsc -p ui
|
||||||
|
//go:embed ui/*
|
||||||
|
var content embed.FS
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
//go:build !frontend
|
//go:build !frontend
|
||||||
|
|
||||||
package ui
|
package main
|
||||||
|
|
||||||
import "testing/fstest"
|
import "testing/fstest"
|
||||||
|
|
||||||
var static fstest.MapFS
|
var content fstest.MapFS
|
||||||
@@ -20,14 +20,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
virtualisation = {
|
virtualisation = {
|
||||||
# Hopefully reduces spurious test failures:
|
|
||||||
memorySize = if pkgs.stdenv.hostPlatform.is32bit then 2046 else 8192;
|
|
||||||
|
|
||||||
diskSize = 6 * 1024;
|
diskSize = 6 * 1024;
|
||||||
|
|
||||||
qemu.options = [
|
qemu.options = [
|
||||||
# Increase test performance:
|
# Increase test performance:
|
||||||
"-smp 16"
|
"-smp 8"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ testers.nixosTest {
|
|||||||
# For go tests:
|
# For go tests:
|
||||||
(pkgs.writeShellScriptBin "sharefs-workload-hakurei-tests" ''
|
(pkgs.writeShellScriptBin "sharefs-workload-hakurei-tests" ''
|
||||||
cp -r "${self.packages.${system}.hakurei.src}" "/sdcard/hakurei" && cd "/sdcard/hakurei"
|
cp -r "${self.packages.${system}.hakurei.src}" "/sdcard/hakurei" && cd "/sdcard/hakurei"
|
||||||
${fhs}/bin/hakurei-fhs -c 'ROSA_SKIP_BINFMT=1 CC="clang -O3 -Werror" go test ./...'
|
${fhs}/bin/hakurei-fhs -c 'CC="clang -O3 -Werror" go test ./...'
|
||||||
'')
|
'')
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
package container
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"hakurei.app/check"
|
|
||||||
)
|
|
||||||
|
|
||||||
// escapeBinfmt escapes magic/mask sequences in a [BinfmtEntry].
|
|
||||||
func escapeBinfmt(buf *strings.Builder, s string) string {
|
|
||||||
const lowerhex = "0123456789abcdef"
|
|
||||||
|
|
||||||
buf.Reset()
|
|
||||||
for _, c := range unsafe.Slice(unsafe.StringData(s), len(s)) {
|
|
||||||
switch c {
|
|
||||||
case 0, '\\', ':':
|
|
||||||
buf.WriteString(`\x`)
|
|
||||||
buf.WriteByte(lowerhex[c>>4])
|
|
||||||
buf.WriteByte(lowerhex[c&0xf])
|
|
||||||
|
|
||||||
default:
|
|
||||||
buf.WriteByte(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// BinfmtEntry is an entry to be registered by the init process.
|
|
||||||
type BinfmtEntry struct {
|
|
||||||
// The offset of the magic/mask in the file, counted in bytes.
|
|
||||||
Offset byte
|
|
||||||
// The byte sequence binfmt_misc is matching for.
|
|
||||||
Magic string
|
|
||||||
// An (optional, defaults to all 0xff) mask.
|
|
||||||
Mask string
|
|
||||||
// The program that should be invoked with the binary as first argument.
|
|
||||||
Interpreter *check.Absolute
|
|
||||||
}
|
|
||||||
|
|
||||||
// Valid returns whether e can be registered into the kernel.
|
|
||||||
func (e *BinfmtEntry) Valid() bool {
|
|
||||||
return e != nil &&
|
|
||||||
int(e.Offset)+max(len(e.Magic), len(e.Mask)) < 128 &&
|
|
||||||
e.Interpreter != nil && len(e.Interpreter.String()) < 128
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
package container
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"hakurei.app/fhs"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEscapeBinfmt(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
magic string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{"packed DOS applications", "\x0eDEX", "\x0eDEX"},
|
|
||||||
|
|
||||||
{"riscv64 magic",
|
|
||||||
"\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00",
|
|
||||||
"\x7fELF\x02\x01\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\x02\\x00\xf3\\x00"},
|
|
||||||
{"riscv64 mask",
|
|
||||||
"\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff",
|
|
||||||
"\xff\xff\xff\xff\xff\xff\xff\\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff"},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
got := escapeBinfmt(new(strings.Builder), tc.magic)
|
|
||||||
if got != tc.want {
|
|
||||||
t.Errorf("escapeBinfmt: %q, want %q", got, tc.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBinfmtEntry(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
e BinfmtEntry
|
|
||||||
valid bool
|
|
||||||
}{
|
|
||||||
{"zero", BinfmtEntry{}, false},
|
|
||||||
{"large offset", BinfmtEntry{Offset: 128}, false},
|
|
||||||
{"long magic", BinfmtEntry{Magic: strings.Repeat("\x00", 128)}, false},
|
|
||||||
{"long mask", BinfmtEntry{Mask: strings.Repeat("\x00", 128)}, false},
|
|
||||||
{"valid", BinfmtEntry{Interpreter: fhs.AbsRoot}, true},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
if tc.e.Valid() != tc.valid {
|
|
||||||
t.Errorf("Valid: %v", !tc.valid)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,6 @@ const (
|
|||||||
CAP_SETPCAP = 0x8
|
CAP_SETPCAP = 0x8
|
||||||
CAP_NET_ADMIN = 0xc
|
CAP_NET_ADMIN = 0xc
|
||||||
CAP_DAC_OVERRIDE = 0x1
|
CAP_DAC_OVERRIDE = 0x1
|
||||||
CAP_SETFCAP = 0x1f
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|||||||
+6
-27
@@ -67,9 +67,6 @@ type (
|
|||||||
// Copied to the underlying [exec.Cmd].
|
// Copied to the underlying [exec.Cmd].
|
||||||
WaitDelay time.Duration
|
WaitDelay time.Duration
|
||||||
|
|
||||||
// Suppress verbose output of init.
|
|
||||||
Quiet bool
|
|
||||||
|
|
||||||
cmd *exec.Cmd
|
cmd *exec.Cmd
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
msg message.Msg
|
msg message.Msg
|
||||||
@@ -91,20 +88,12 @@ type (
|
|||||||
// Time to wait for processes lingering after the initial process terminates.
|
// Time to wait for processes lingering after the initial process terminates.
|
||||||
AdoptWaitDelay time.Duration
|
AdoptWaitDelay time.Duration
|
||||||
|
|
||||||
// Map uid/gid 0 in the init process. Requires [FstypeProc] attached to
|
|
||||||
// [fhs.Proc] in the container filesystem.
|
|
||||||
InitAsRoot bool
|
|
||||||
// Mapped Uid in user namespace.
|
// Mapped Uid in user namespace.
|
||||||
Uid int
|
Uid int
|
||||||
// Mapped Gid in user namespace.
|
// Mapped Gid in user namespace.
|
||||||
Gid int
|
Gid int
|
||||||
// Hostname value in UTS namespace.
|
// Hostname value in UTS namespace.
|
||||||
Hostname string
|
Hostname string
|
||||||
// Register binfmt_misc entries.
|
|
||||||
Binfmt []BinfmtEntry
|
|
||||||
// Alternative pathname to attach binfmt_misc filesystem. The zero value
|
|
||||||
// requires [FstypeProc] to be made available at [fhs.Proc].
|
|
||||||
BinfmtPath *check.Absolute
|
|
||||||
// Sequential container setup ops.
|
// Sequential container setup ops.
|
||||||
*Ops
|
*Ops
|
||||||
|
|
||||||
@@ -224,9 +213,6 @@ func (p *Container) Start() error {
|
|||||||
if p.cmd.Process != nil {
|
if p.cmd.Process != nil {
|
||||||
return errors.New("container: already started")
|
return errors.New("container: already started")
|
||||||
}
|
}
|
||||||
if !p.InitAsRoot && len(p.Binfmt) > 0 {
|
|
||||||
return errors.New("container: init as root required, but not enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ensureCloseOnExec(); err != nil {
|
if err := ensureCloseOnExec(); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -297,18 +283,6 @@ func (p *Container) Start() error {
|
|||||||
if !p.HostNet {
|
if !p.HostNet {
|
||||||
p.cmd.SysProcAttr.Cloneflags |= CLONE_NEWNET
|
p.cmd.SysProcAttr.Cloneflags |= CLONE_NEWNET
|
||||||
}
|
}
|
||||||
if p.InitAsRoot {
|
|
||||||
p.cmd.SysProcAttr.AmbientCaps = append(p.cmd.SysProcAttr.AmbientCaps,
|
|
||||||
// mappings during init as root
|
|
||||||
CAP_SETFCAP,
|
|
||||||
)
|
|
||||||
|
|
||||||
if !p.SeccompDisable &&
|
|
||||||
len(p.SeccompRules) == 0 &&
|
|
||||||
p.SeccompPresets&std.PresetDenyNS != 0 {
|
|
||||||
return errors.New("container: as root requires late namespace creation")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// place setup pipe before user supplied extra files, this is later restored by init
|
// place setup pipe before user supplied extra files, this is later restored by init
|
||||||
if r, w, err := os.Pipe(); err != nil {
|
if r, w, err := os.Pipe(); err != nil {
|
||||||
@@ -368,6 +342,8 @@ func (p *Container) Start() error {
|
|||||||
Err: ENOSYS,
|
Err: ENOSYS,
|
||||||
Origin: true,
|
Origin: true,
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
p.msg.Verbosef("landlock abi version %d", abi)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rulesetFd, err := rulesetAttr.Create(0); err != nil {
|
if rulesetFd, err := rulesetAttr.Create(0); err != nil {
|
||||||
@@ -377,6 +353,7 @@ func (p *Container) Start() error {
|
|||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
p.msg.Verbosef("enforcing landlock ruleset %s", rulesetAttr)
|
||||||
if err = landlock.RestrictSelf(rulesetFd, 0); err != nil {
|
if err = landlock.RestrictSelf(rulesetFd, 0); err != nil {
|
||||||
_ = Close(rulesetFd)
|
_ = Close(rulesetFd)
|
||||||
return &StartError{
|
return &StartError{
|
||||||
@@ -433,6 +410,7 @@ func (p *Container) Start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.msg.Verbose("starting container init")
|
||||||
if err := p.cmd.Start(); err != nil {
|
if err := p.cmd.Start(); err != nil {
|
||||||
return &StartError{
|
return &StartError{
|
||||||
Step: "start container init",
|
Step: "start container init",
|
||||||
@@ -503,6 +481,7 @@ func (p *Container) Serve() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case <-done:
|
case <-done:
|
||||||
|
p.msg.Verbose("setup payload took", time.Since(t))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}(p.setup[1])
|
}(p.setup[1])
|
||||||
@@ -512,7 +491,7 @@ func (p *Container) Serve() (err error) {
|
|||||||
Getuid(),
|
Getuid(),
|
||||||
Getgid(),
|
Getgid(),
|
||||||
len(p.ExtraFiles),
|
len(p.ExtraFiles),
|
||||||
p.msg.IsVerbose() && !p.Quiet,
|
p.msg.IsVerbose(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+53
-175
@@ -16,8 +16,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"hakurei.app/check"
|
"hakurei.app/check"
|
||||||
"hakurei.app/command"
|
"hakurei.app/command"
|
||||||
@@ -235,9 +233,6 @@ func earlyMnt(mnt ...*vfs.MountInfoEntry) func(*testing.T, context.Context) []*v
|
|||||||
return func(*testing.T, context.Context) []*vfs.MountInfoEntry { return mnt }
|
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 {
|
var containerTestCases = []struct {
|
||||||
name string
|
name string
|
||||||
filter bool
|
filter bool
|
||||||
@@ -337,15 +332,13 @@ var containerTestCases = []struct {
|
|||||||
func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry {
|
func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry {
|
||||||
return []*vfs.MountInfoEntry{
|
return []*vfs.MountInfoEntry{
|
||||||
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay",
|
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay",
|
||||||
"rw"+
|
"rw,lowerdir="+
|
||||||
",lowerdir+="+
|
container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*check.Absolute).String())+":"+
|
||||||
toHost(ctx.Value(testVal("lower0")).(*check.Absolute).String())+
|
container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
||||||
",lowerdir+="+
|
|
||||||
toHost(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
|
||||||
",upperdir="+
|
",upperdir="+
|
||||||
toHost(ctx.Value(testVal("upper")).(*check.Absolute).String())+
|
container.InternalToHostOvlEscape(ctx.Value(testVal("upper")).(*check.Absolute).String())+
|
||||||
",workdir="+
|
",workdir="+
|
||||||
toHost(ctx.Value(testVal("work")).(*check.Absolute).String())+
|
container.InternalToHostOvlEscape(ctx.Value(testVal("work")).(*check.Absolute).String())+
|
||||||
",redirect_dir=nofollow,uuid=on,userxattr"),
|
",redirect_dir=nofollow,uuid=on,userxattr"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -395,11 +388,9 @@ var containerTestCases = []struct {
|
|||||||
func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry {
|
func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry {
|
||||||
return []*vfs.MountInfoEntry{
|
return []*vfs.MountInfoEntry{
|
||||||
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay",
|
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay",
|
||||||
"ro"+
|
"ro,lowerdir="+
|
||||||
",lowerdir+="+
|
container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*check.Absolute).String())+":"+
|
||||||
toHost(ctx.Value(testVal("lower0")).(*check.Absolute).String())+
|
container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
||||||
",lowerdir+="+
|
|
||||||
toHost(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
|
||||||
",redirect_dir=nofollow,userxattr"),
|
",redirect_dir=nofollow,userxattr"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -409,11 +400,39 @@ var containerTestCases = []struct {
|
|||||||
func TestContainer(t *testing.T) {
|
func TestContainer(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
var suffix string
|
t.Run("cancel", testContainerCancel(nil, func(t *testing.T, c *container.Container) {
|
||||||
runTests:
|
wantErr := context.Canceled
|
||||||
|
wantExitCode := 0
|
||||||
|
if err := c.Wait(); !reflect.DeepEqual(err, wantErr) {
|
||||||
|
if m, ok := container.InternalMessageFromError(err); ok {
|
||||||
|
t.Error(m)
|
||||||
|
}
|
||||||
|
t.Errorf("Wait: error = %#v, want %#v", err, wantErr)
|
||||||
|
}
|
||||||
|
if ps := c.ProcessState(); ps == nil {
|
||||||
|
t.Errorf("ProcessState unexpectedly returned nil")
|
||||||
|
} else if code := ps.ExitCode(); code != wantExitCode {
|
||||||
|
t.Errorf("ExitCode: %d, want %d", code, wantExitCode)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
t.Run("forward", testContainerCancel(func(c *container.Container) {
|
||||||
|
c.ForwardCancel = true
|
||||||
|
}, func(t *testing.T, c *container.Container) {
|
||||||
|
var exitError *exec.ExitError
|
||||||
|
if err := c.Wait(); !errors.As(err, &exitError) {
|
||||||
|
if m, ok := container.InternalMessageFromError(err); ok {
|
||||||
|
t.Error(m)
|
||||||
|
}
|
||||||
|
t.Errorf("Wait: error = %v", err)
|
||||||
|
}
|
||||||
|
if code := exitError.ExitCode(); code != blockExitCodeInterrupt {
|
||||||
|
t.Errorf("ExitCode: %d, want %d", code, blockExitCodeInterrupt)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
for i, tc := range containerTestCases {
|
for i, tc := range containerTestCases {
|
||||||
_suffix := suffix
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
t.Run(tc.name+_suffix, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
wantOps, wantOpsCtx := tc.ops(t)
|
wantOps, wantOpsCtx := tc.ops(t)
|
||||||
@@ -437,8 +456,6 @@ runTests:
|
|||||||
c.SeccompDisable = !tc.filter
|
c.SeccompDisable = !tc.filter
|
||||||
c.RetainSession = tc.session
|
c.RetainSession = tc.session
|
||||||
c.HostNet = tc.net
|
c.HostNet = tc.net
|
||||||
c.InitAsRoot = _suffix != ""
|
|
||||||
c.Env = append(c.Env, "HAKUREI_TEST_SUFFIX="+_suffix)
|
|
||||||
if info.CanDegrade {
|
if info.CanDegrade {
|
||||||
if _, err := landlock.GetABI(); err != nil {
|
if _, err := landlock.GetABI(); err != nil {
|
||||||
if !errors.Is(err, syscall.ENOSYS) {
|
if !errors.Is(err, syscall.ENOSYS) {
|
||||||
@@ -448,9 +465,6 @@ runTests:
|
|||||||
t.Log("Landlock LSM is unavailable, enabling HostAbstract")
|
t.Log("Landlock LSM is unavailable, enabling HostAbstract")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.InitAsRoot {
|
|
||||||
c.SeccompPresets &= ^std.PresetDenyNS
|
|
||||||
}
|
|
||||||
|
|
||||||
c.
|
c.
|
||||||
Readonly(check.MustAbs(pathReadonly), 0755).
|
Readonly(check.MustAbs(pathReadonly), 0755).
|
||||||
@@ -519,11 +533,6 @@ runTests:
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if suffix == "" {
|
|
||||||
suffix = " as root"
|
|
||||||
goto runTests
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ent(root, target, vfsOptstr, fsType, source, fsOptstr string) *vfs.MountInfoEntry {
|
func ent(root, target, vfsOptstr, fsType, source, fsOptstr string) *vfs.MountInfoEntry {
|
||||||
@@ -546,10 +555,11 @@ func hostnameFromTestCase(name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testContainerCancel(
|
func testContainerCancel(
|
||||||
t *testing.T,
|
|
||||||
containerExtra func(c *container.Container),
|
containerExtra func(c *container.Container),
|
||||||
waitCheck func(ps *os.ProcessState, waitErr error),
|
waitCheck func(t *testing.T, c *container.Container),
|
||||||
) {
|
) func(t *testing.T) {
|
||||||
|
return func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
ctx, cancel := context.WithCancel(t.Context())
|
ctx, cancel := context.WithCancel(t.Context())
|
||||||
|
|
||||||
c := helperNewContainer(ctx, "block")
|
c := helperNewContainer(ctx, "block")
|
||||||
@@ -559,36 +569,25 @@ func testContainerCancel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ready := make(chan struct{})
|
ready := make(chan struct{})
|
||||||
var waitErr error
|
if r, w, err := os.Pipe(); err != nil {
|
||||||
r, w, err := os.Pipe()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot pipe: %v", err)
|
t.Fatalf("cannot pipe: %v", err)
|
||||||
}
|
} else {
|
||||||
|
|
||||||
c.ExtraFiles = append(c.ExtraFiles, w)
|
c.ExtraFiles = append(c.ExtraFiles, w)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(ready)
|
defer close(ready)
|
||||||
if _, _err := r.Read(make([]byte, 1)); _err != nil {
|
if _, err = r.Read(make([]byte, 1)); err != nil {
|
||||||
panic(_err)
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
if err = c.Start(); err != nil {
|
if err := c.Start(); err != nil {
|
||||||
if m, ok := container.InternalMessageFromError(err); ok {
|
if m, ok := container.InternalMessageFromError(err); ok {
|
||||||
t.Fatal(m)
|
t.Fatal(m)
|
||||||
} else {
|
} else {
|
||||||
t.Fatalf("cannot start container: %v", err)
|
t.Fatalf("cannot start container: %v", err)
|
||||||
}
|
}
|
||||||
}
|
} else if err = c.Serve(); err != nil {
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
defer close(done)
|
|
||||||
waitErr = c.Wait()
|
|
||||||
_ = r.SetReadDeadline(time.Now())
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = c.Serve(); err != nil {
|
|
||||||
if m, ok := container.InternalMessageFromError(err); ok {
|
if m, ok := container.InternalMessageFromError(err); ok {
|
||||||
t.Error(m)
|
t.Error(m)
|
||||||
} else {
|
} else {
|
||||||
@@ -597,67 +596,8 @@ func testContainerCancel(
|
|||||||
}
|
}
|
||||||
<-ready
|
<-ready
|
||||||
cancel()
|
cancel()
|
||||||
<-done
|
waitCheck(t, c)
|
||||||
waitCheck(c.ProcessState(), waitErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestForward(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
f := func(ps *os.ProcessState, waitErr error) {
|
|
||||||
var exitError *exec.ExitError
|
|
||||||
if !errors.As(waitErr, &exitError) {
|
|
||||||
if m, ok := container.InternalMessageFromError(waitErr); ok {
|
|
||||||
t.Error(m)
|
|
||||||
}
|
}
|
||||||
t.Errorf("Wait: error = %v", waitErr)
|
|
||||||
}
|
|
||||||
if code := exitError.ExitCode(); code != blockExitCodeInterrupt {
|
|
||||||
t.Errorf("ExitCode: %d, want %d", code, blockExitCodeInterrupt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Run("direct", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
testContainerCancel(t, func(c *container.Container) {
|
|
||||||
c.ForwardCancel = true
|
|
||||||
}, f)
|
|
||||||
})
|
|
||||||
t.Run("as root", func(t *testing.T) {
|
|
||||||
testContainerCancel(t, func(c *container.Container) {
|
|
||||||
c.ForwardCancel = true
|
|
||||||
c.InitAsRoot = true
|
|
||||||
c.Proc(fhs.AbsProc)
|
|
||||||
}, f)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCancel(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
f := func(ps *os.ProcessState, waitErr error) {
|
|
||||||
wantErr := context.Canceled
|
|
||||||
if !reflect.DeepEqual(waitErr, wantErr) {
|
|
||||||
if m, ok := container.InternalMessageFromError(waitErr); ok {
|
|
||||||
t.Error(m)
|
|
||||||
}
|
|
||||||
t.Errorf("Wait: error = %#v, want %#v", waitErr, wantErr)
|
|
||||||
}
|
|
||||||
if ps == nil {
|
|
||||||
t.Errorf("ProcessState unexpectedly returned nil")
|
|
||||||
} else if code := ps.ExitCode(); code != 0 {
|
|
||||||
t.Errorf("ExitCode: %d, want %d", code, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Run("direct", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
testContainerCancel(t, nil, f)
|
|
||||||
})
|
|
||||||
t.Run("as root", func(t *testing.T) {
|
|
||||||
testContainerCancel(t, func(c *container.Container) {
|
|
||||||
c.InitAsRoot = true
|
|
||||||
c.Proc(fhs.AbsProc)
|
|
||||||
}, f)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainerString(t *testing.T) {
|
func TestContainerString(t *testing.T) {
|
||||||
@@ -693,8 +633,6 @@ func init() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
c.Command("container", command.UsageInternal, func(args []string) error {
|
c.Command("container", command.UsageInternal, func(args []string) error {
|
||||||
asRoot := os.Getenv("HAKUREI_TEST_SUFFIX") == " as root"
|
|
||||||
|
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return syscall.EINVAL
|
return syscall.EINVAL
|
||||||
}
|
}
|
||||||
@@ -712,66 +650,6 @@ func init() {
|
|||||||
return fmt.Errorf("gid: %d, want %d", gid, tc.gid)
|
return fmt.Errorf("gid: %d, want %d", gid, tc.gid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// no attack surface increase during as root due to no_new_privs
|
|
||||||
var wantBounding uintptr = 1
|
|
||||||
asRootNot := " not"
|
|
||||||
if !asRoot {
|
|
||||||
wantBounding = 0
|
|
||||||
asRootNot = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
PR_CAP_AMBIENT = 0x2f
|
|
||||||
PR_CAP_AMBIENT_IS_SET = 0x1
|
|
||||||
)
|
|
||||||
for i := range container.LastCap(nil) + 1 {
|
|
||||||
r, _, errno := syscall.Syscall(
|
|
||||||
syscall.SYS_PRCTL,
|
|
||||||
PR_CAP_AMBIENT,
|
|
||||||
PR_CAP_AMBIENT_IS_SET,
|
|
||||||
i,
|
|
||||||
)
|
|
||||||
if errno != 0 {
|
|
||||||
return os.NewSyscallError("prctl", errno)
|
|
||||||
}
|
|
||||||
if r != 0 {
|
|
||||||
return fmt.Errorf("capability %d in ambient set", i)
|
|
||||||
}
|
|
||||||
|
|
||||||
r, _, errno = syscall.Syscall(
|
|
||||||
syscall.SYS_PRCTL,
|
|
||||||
syscall.PR_CAPBSET_READ,
|
|
||||||
i,
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
if errno != 0 {
|
|
||||||
return os.NewSyscallError("prctl", errno)
|
|
||||||
}
|
|
||||||
if r != wantBounding {
|
|
||||||
return fmt.Errorf("capability %d%s in bounding set", i, asRootNot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const _LINUX_CAPABILITY_VERSION_3 = 0x20080522
|
|
||||||
var capData struct {
|
|
||||||
effective uint32
|
|
||||||
permitted uint32
|
|
||||||
inheritable uint32
|
|
||||||
}
|
|
||||||
if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&struct {
|
|
||||||
version uint32
|
|
||||||
pid int32
|
|
||||||
}{_LINUX_CAPABILITY_VERSION_3, 0})), uintptr(unsafe.Pointer(&capData)), 0); errno != 0 {
|
|
||||||
return os.NewSyscallError("capget", errno)
|
|
||||||
}
|
|
||||||
|
|
||||||
if max(capData.effective, capData.permitted, capData.inheritable) != 0 {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"effective = %d, permitted = %d, inheritable = %d",
|
|
||||||
capData.effective, capData.permitted, capData.inheritable,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
wantHost := hostnameFromTestCase(tc.name)
|
wantHost := hostnameFromTestCase(tc.name)
|
||||||
if host, err := os.Hostname(); err != nil {
|
if host, err := os.Hostname(); err != nil {
|
||||||
return fmt.Errorf("cannot get hostname: %v", err)
|
return fmt.Errorf("cannot get hostname: %v", err)
|
||||||
@@ -889,7 +767,7 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
c.MustParse(os.Args[1:], func(err error) {
|
c.MustParse(os.Args[1:], func(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -65,8 +65,6 @@ type syscallDispatcher interface {
|
|||||||
remount(msg message.Msg, target string, flags uintptr) error
|
remount(msg message.Msg, target string, flags uintptr) error
|
||||||
// mountTmpfs provides mountTmpfs.
|
// mountTmpfs provides mountTmpfs.
|
||||||
mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error
|
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 provides ensureFile.
|
||||||
ensureFile(name string, perm, pperm os.FileMode) error
|
ensureFile(name string, perm, pperm os.FileMode) error
|
||||||
// mustLoopback provides mustLoopback.
|
// mustLoopback provides mustLoopback.
|
||||||
@@ -171,9 +169,6 @@ 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 {
|
func (k direct) mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error {
|
||||||
return mountTmpfs(k, fsname, target, flags, size, perm)
|
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 {
|
func (direct) ensureFile(name string, perm, pperm os.FileMode) error {
|
||||||
return ensureFile(name, perm, pperm)
|
return ensureFile(name, perm, pperm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -468,14 +468,6 @@ func (k *kstub) mountTmpfs(fsname, target string, flags uintptr, size int, perm
|
|||||||
stub.CheckArg(k.Stub, "perm", perm, 4))
|
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 {
|
func (k *kstub) ensureFile(name string, perm, pperm os.FileMode) error {
|
||||||
k.Helper()
|
k.Helper()
|
||||||
return k.Expects("ensureFile").Error(
|
return k.Expects("ensureFile").Error(
|
||||||
|
|||||||
@@ -118,10 +118,6 @@ func errnoFallback(op, path string, err error) (syscall.Errno, *os.PathError) {
|
|||||||
|
|
||||||
// mount wraps syscall.Mount for error handling.
|
// mount wraps syscall.Mount for error handling.
|
||||||
func mount(source, target, fstype string, flags uintptr, data string) error {
|
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)
|
err := syscall.Mount(source, target, fstype, flags, data)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+23
-106
@@ -11,13 +11,11 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
. "syscall"
|
. "syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/check"
|
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
"hakurei.app/ext"
|
"hakurei.app/ext"
|
||||||
"hakurei.app/fhs"
|
"hakurei.app/fhs"
|
||||||
@@ -184,33 +182,23 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
uid, gid := param.Uid, param.Gid
|
|
||||||
if param.InitAsRoot {
|
|
||||||
uid, gid = 0, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// write uid/gid map here so parent does not need to set dumpable
|
// write uid/gid map here so parent does not need to set dumpable
|
||||||
if err := k.setDumpable(ext.SUID_DUMP_USER); err != nil {
|
if err := k.setDumpable(ext.SUID_DUMP_USER); err != nil {
|
||||||
k.fatalf(msg, "cannot set SUID_DUMP_USER: %v", err)
|
k.fatalf(msg, "cannot set SUID_DUMP_USER: %v", err)
|
||||||
}
|
}
|
||||||
if err := k.writeFile(
|
if err := k.writeFile(fhs.Proc+"self/uid_map",
|
||||||
fhs.Proc+"self/uid_map",
|
append([]byte{}, strconv.Itoa(param.Uid)+" "+strconv.Itoa(param.HostUid)+" 1\n"...),
|
||||||
[]byte(strconv.Itoa(uid)+" "+strconv.Itoa(param.HostUid)+" 1\n"),
|
0); err != nil {
|
||||||
0,
|
|
||||||
); err != nil {
|
|
||||||
k.fatalf(msg, "%v", err)
|
k.fatalf(msg, "%v", err)
|
||||||
}
|
}
|
||||||
if err := k.writeFile(
|
if err := k.writeFile(fhs.Proc+"self/setgroups",
|
||||||
fhs.Proc+"self/setgroups",
|
|
||||||
[]byte("deny\n"),
|
[]byte("deny\n"),
|
||||||
0,
|
0); err != nil && !os.IsNotExist(err) {
|
||||||
); err != nil && !os.IsNotExist(err) {
|
|
||||||
k.fatalf(msg, "%v", err)
|
k.fatalf(msg, "%v", err)
|
||||||
}
|
}
|
||||||
if err := k.writeFile(fhs.Proc+"self/gid_map",
|
if err := k.writeFile(fhs.Proc+"self/gid_map",
|
||||||
[]byte(strconv.Itoa(gid)+" "+strconv.Itoa(param.HostGid)+" 1\n"),
|
append([]byte{}, strconv.Itoa(param.Gid)+" "+strconv.Itoa(param.HostGid)+" 1\n"...),
|
||||||
0,
|
0); err != nil {
|
||||||
); err != nil {
|
|
||||||
k.fatalf(msg, "%v", err)
|
k.fatalf(msg, "%v", err)
|
||||||
}
|
}
|
||||||
if err := k.setDumpable(ext.SUID_DUMP_DISABLE); err != nil {
|
if err := k.setDumpable(ext.SUID_DUMP_DISABLE); err != nil {
|
||||||
@@ -235,23 +223,6 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
state := &setupState{process: make(map[int]WaitStatus), Params: ¶m.Params, Msg: msg, Context: ctx}
|
state := &setupState{process: make(map[int]WaitStatus), Params: ¶m.Params, Msg: msg, Context: ctx}
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := k.mount(SourceTmpfsRootfs, intermediateHostPath, FstypeTmpfs, MS_NODEV|MS_NOSUID, zeroString); err != nil {
|
|
||||||
k.fatalf(msg, "cannot mount intermediate root: %v", optionalErrorUnwrap(err))
|
|
||||||
}
|
|
||||||
if err := k.chdir(intermediateHostPath); err != nil {
|
|
||||||
k.fatalf(msg, "cannot enter intermediate host path: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(param.Binfmt) > 0 {
|
|
||||||
for i, e := range param.Binfmt {
|
|
||||||
if pathname, err := k.evalSymlinks(e.Interpreter.String()); err != nil {
|
|
||||||
k.fatal(msg, err)
|
|
||||||
} else if param.Binfmt[i].Interpreter, err = check.NewAbs(pathname); err != nil {
|
|
||||||
k.fatal(msg, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* early is called right before pivot_root into intermediate root;
|
/* early is called right before pivot_root into intermediate root;
|
||||||
this step is mostly for gathering information that would otherwise be
|
this step is mostly for gathering information that would otherwise be
|
||||||
difficult to obtain via library functions after pivot_root, and
|
difficult to obtain via library functions after pivot_root, and
|
||||||
@@ -271,6 +242,13 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := k.mount(SourceTmpfsRootfs, intermediateHostPath, FstypeTmpfs, MS_NODEV|MS_NOSUID, zeroString); err != nil {
|
||||||
|
k.fatalf(msg, "cannot mount intermediate root: %v", optionalErrorUnwrap(err))
|
||||||
|
}
|
||||||
|
if err := k.chdir(intermediateHostPath); err != nil {
|
||||||
|
k.fatalf(msg, "cannot enter intermediate host path: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := k.mkdir(sysrootDir, 0755); err != nil {
|
if err := k.mkdir(sysrootDir, 0755); err != nil {
|
||||||
k.fatalf(msg, "%v", err)
|
k.fatalf(msg, "%v", err)
|
||||||
}
|
}
|
||||||
@@ -307,48 +285,6 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(param.Binfmt) > 0 {
|
|
||||||
const interpreter = "/interpreter"
|
|
||||||
|
|
||||||
if param.BinfmtPath == nil {
|
|
||||||
param.BinfmtPath = fhs.AbsProcSys.Append("fs/binfmt_misc")
|
|
||||||
}
|
|
||||||
binfmt := sysrootPath + param.BinfmtPath.String()
|
|
||||||
if err := k.mkdirAll(binfmt, 0); err != nil {
|
|
||||||
k.fatal(msg, err)
|
|
||||||
}
|
|
||||||
if err := k.mount(
|
|
||||||
SourceBinfmtMisc,
|
|
||||||
binfmt,
|
|
||||||
FstypeBinfmtMisc,
|
|
||||||
MS_NOSUID|MS_NOEXEC|MS_NODEV,
|
|
||||||
zeroString,
|
|
||||||
); err != nil {
|
|
||||||
k.fatal(msg, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf strings.Builder
|
|
||||||
buf.Grow(1920)
|
|
||||||
|
|
||||||
register := binfmt + "/register"
|
|
||||||
for i, e := range param.Binfmt {
|
|
||||||
if err := k.symlink(hostPath+e.Interpreter.String(), interpreter); err != nil {
|
|
||||||
k.fatal(msg, err)
|
|
||||||
} else if err = k.writeFile(register, []byte(":"+
|
|
||||||
strconv.Itoa(i)+":"+
|
|
||||||
"M:"+
|
|
||||||
strconv.Itoa(int(e.Offset))+":"+
|
|
||||||
escapeBinfmt(&buf, e.Magic)+":"+
|
|
||||||
escapeBinfmt(&buf, e.Mask)+":"+
|
|
||||||
interpreter+":"+
|
|
||||||
"F"), 0); err != nil {
|
|
||||||
k.fatal(msg, err)
|
|
||||||
} else if err = k.remove(interpreter); err != nil {
|
|
||||||
k.fatal(msg, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup requiring host root complete at this point
|
// setup requiring host root complete at this point
|
||||||
if err := k.mount(hostDir, hostDir, zeroString, MS_SILENT|MS_REC|MS_PRIVATE, zeroString); err != nil {
|
if err := k.mount(hostDir, hostDir, zeroString, MS_SILENT|MS_REC|MS_PRIVATE, zeroString); err != nil {
|
||||||
k.fatalf(msg, "cannot make host root rprivate: %v", optionalErrorUnwrap(err))
|
k.fatalf(msg, "cannot make host root rprivate: %v", optionalErrorUnwrap(err))
|
||||||
@@ -387,19 +323,11 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var keepCaps []uintptr
|
|
||||||
if param.Privileged {
|
|
||||||
keepCaps = append(keepCaps, CAP_SYS_ADMIN, CAP_SETPCAP)
|
|
||||||
}
|
|
||||||
if param.InitAsRoot {
|
|
||||||
keepCaps = append(keepCaps, CAP_SETFCAP)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := k.capAmbientClearAll(); err != nil {
|
if err := k.capAmbientClearAll(); err != nil {
|
||||||
k.fatalf(msg, "cannot clear the ambient capability set: %v", err)
|
k.fatalf(msg, "cannot clear the ambient capability set: %v", err)
|
||||||
}
|
}
|
||||||
for i := range lastcap + 1 {
|
for i := uintptr(0); i <= lastcap; i++ {
|
||||||
if slices.Contains(keepCaps, i) {
|
if param.Privileged && i == CAP_SYS_ADMIN {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := k.capBoundingSetDrop(i); err != nil {
|
if err := k.capBoundingSetDrop(i); err != nil {
|
||||||
@@ -408,23 +336,20 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var keep [2]uint32
|
var keep [2]uint32
|
||||||
for _, c := range keepCaps {
|
if param.Privileged {
|
||||||
keep[capToIndex(c)] |= capToMask(c)
|
keep[capToIndex(CAP_SYS_ADMIN)] |= capToMask(CAP_SYS_ADMIN)
|
||||||
}
|
|
||||||
|
|
||||||
|
if err := k.capAmbientRaise(CAP_SYS_ADMIN); err != nil {
|
||||||
|
k.fatalf(msg, "cannot raise CAP_SYS_ADMIN: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := k.capset(
|
if err := k.capset(
|
||||||
&capHeader{_LINUX_CAPABILITY_VERSION_3, 0},
|
&capHeader{_LINUX_CAPABILITY_VERSION_3, 0},
|
||||||
&[2]capData{{keep[0], keep[0], keep[0]}, {keep[1], keep[1], keep[1]}},
|
&[2]capData{{0, keep[0], keep[0]}, {0, keep[1], keep[1]}},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
k.fatalf(msg, "cannot capset: %v", err)
|
k.fatalf(msg, "cannot capset: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range keepCaps {
|
|
||||||
if err := k.capAmbientRaise(c); err != nil {
|
|
||||||
k.fatalf(msg, "cannot raise %#x: %v", c, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !param.SeccompDisable {
|
if !param.SeccompDisable {
|
||||||
rules := param.SeccompRules
|
rules := param.SeccompRules
|
||||||
if len(rules) == 0 { // non-empty rules slice always overrides presets
|
if len(rules) == 0 { // non-empty rules slice always overrides presets
|
||||||
@@ -549,14 +474,6 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
cmd.ExtraFiles = extraFiles
|
cmd.ExtraFiles = extraFiles
|
||||||
cmd.Dir = param.Dir.String()
|
cmd.Dir = param.Dir.String()
|
||||||
|
|
||||||
if param.InitAsRoot {
|
|
||||||
cmd.SysProcAttr = &SysProcAttr{
|
|
||||||
Cloneflags: CLONE_NEWUSER,
|
|
||||||
UidMappings: []SysProcIDMap{{ContainerID: param.Uid, HostID: 0, Size: 1}},
|
|
||||||
GidMappings: []SysProcIDMap{{ContainerID: param.Gid, HostID: 0, Size: 1}},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Verbosef("starting initial process %s", param.Path)
|
msg.Verbosef("starting initial process %s", param.Path)
|
||||||
if err := k.start(cmd); err != nil {
|
if err := k.start(cmd); err != nil {
|
||||||
k.fatalf(msg, "%v", err)
|
k.fatalf(msg, "%v", err)
|
||||||
|
|||||||
+73
-73
@@ -332,8 +332,6 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("fatalf", stub.ExpectArgs{"invalid op at index %d", []any{0}}, nil, nil),
|
call("fatalf", stub.ExpectArgs{"invalid op at index %d", []any{0}}, nil, nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
@@ -372,8 +370,6 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("fatalf", stub.ExpectArgs{"invalid op at index %d", []any{0}}, nil, nil),
|
call("fatalf", stub.ExpectArgs{"invalid op at index %d", []any{0}}, nil, nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
@@ -412,8 +408,6 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", stub.UniqueError(61)),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", stub.UniqueError(61)),
|
||||||
call("fatalf", stub.ExpectArgs{"cannot prepare op at index %d: %v", []any{0, stub.UniqueError(61)}}, nil, nil),
|
call("fatalf", stub.ExpectArgs{"cannot prepare op at index %d: %v", []any{0, stub.UniqueError(61)}}, nil, nil),
|
||||||
@@ -453,8 +447,6 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", &os.PathError{Op: "readlink", Path: "/", Err: stub.UniqueError(60)}),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", &os.PathError{Op: "readlink", Path: "/", Err: stub.UniqueError(60)}),
|
||||||
call("fatal", stub.ExpectArgs{[]any{"cannot readlink /: unique error 60 injected by the test suite"}}, nil, nil),
|
call("fatal", stub.ExpectArgs{[]any{"cannot readlink /: unique error 60 injected by the test suite"}}, nil, nil),
|
||||||
@@ -494,6 +486,9 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
|
/* begin early */
|
||||||
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
|
/* end early */
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, stub.UniqueError(58)),
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, stub.UniqueError(58)),
|
||||||
call("fatalf", stub.ExpectArgs{"cannot mount intermediate root: %v", []any{stub.UniqueError(58)}}, nil, nil),
|
call("fatalf", stub.ExpectArgs{"cannot mount intermediate root: %v", []any{stub.UniqueError(58)}}, nil, nil),
|
||||||
},
|
},
|
||||||
@@ -531,6 +526,9 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
|
/* begin early */
|
||||||
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
|
/* end early */
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, stub.UniqueError(56)),
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, stub.UniqueError(56)),
|
||||||
call("fatalf", stub.ExpectArgs{"cannot enter intermediate host path: %v", []any{stub.UniqueError(56)}}, nil, nil),
|
call("fatalf", stub.ExpectArgs{"cannot enter intermediate host path: %v", []any{stub.UniqueError(56)}}, nil, nil),
|
||||||
@@ -569,11 +567,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, stub.UniqueError(54)),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, stub.UniqueError(54)),
|
||||||
call("fatalf", stub.ExpectArgs{"%v", []any{stub.UniqueError(54)}}, nil, nil),
|
call("fatalf", stub.ExpectArgs{"%v", []any{stub.UniqueError(54)}}, nil, nil),
|
||||||
},
|
},
|
||||||
@@ -611,11 +609,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, stub.UniqueError(52)),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, stub.UniqueError(52)),
|
||||||
call("fatalf", stub.ExpectArgs{"cannot bind sysroot: %v", []any{stub.UniqueError(52)}}, nil, nil),
|
call("fatalf", stub.ExpectArgs{"cannot bind sysroot: %v", []any{stub.UniqueError(52)}}, nil, nil),
|
||||||
@@ -654,11 +652,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, stub.UniqueError(50)),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, stub.UniqueError(50)),
|
||||||
@@ -698,11 +696,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -743,11 +741,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -789,11 +787,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -844,11 +842,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -899,11 +897,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -955,11 +953,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1012,11 +1010,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1071,11 +1069,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1131,11 +1129,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1192,11 +1190,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1254,11 +1252,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1317,11 +1315,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1381,11 +1379,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1446,11 +1444,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1512,11 +1510,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1586,11 +1584,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1624,6 +1622,7 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x5)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x5)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x6)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x6)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x7)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x7)}, nil, nil),
|
||||||
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x8)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x9)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x9)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xa)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xa)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xb)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xb)}, nil, nil),
|
||||||
@@ -1655,9 +1654,8 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x26)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x26)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x27)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x27)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x28)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x28)}, nil, nil),
|
||||||
call("capset", stub.ExpectArgs{&capHeader{_LINUX_CAPABILITY_VERSION_3, 0}, &[2]capData{{0x200100, 0x200100, 0x200100}, {0, 0, 0}}}, nil, nil),
|
|
||||||
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x15)}, nil, stub.UniqueError(19)),
|
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x15)}, nil, stub.UniqueError(19)),
|
||||||
call("fatalf", stub.ExpectArgs{"cannot raise %#x: %v", []any{uintptr(0x15), stub.UniqueError(19)}}, nil, nil),
|
call("fatalf", stub.ExpectArgs{"cannot raise CAP_SYS_ADMIN: %v", []any{stub.UniqueError(19)}}, nil, nil),
|
||||||
},
|
},
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
@@ -1693,11 +1691,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1731,6 +1729,7 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x5)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x5)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x6)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x6)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x7)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x7)}, nil, nil),
|
||||||
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x8)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x9)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x9)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xa)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xa)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xb)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xb)}, nil, nil),
|
||||||
@@ -1762,7 +1761,8 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x26)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x26)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x27)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x27)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x28)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x28)}, nil, nil),
|
||||||
call("capset", stub.ExpectArgs{&capHeader{_LINUX_CAPABILITY_VERSION_3, 0}, &[2]capData{{0x200100, 0x200100, 0x200100}, {0, 0, 0}}}, nil, stub.UniqueError(17)),
|
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x15)}, nil, nil),
|
||||||
|
call("capset", stub.ExpectArgs{&capHeader{_LINUX_CAPABILITY_VERSION_3, 0}, &[2]capData{{0, 0x200000, 0x200000}, {0, 0, 0}}}, nil, stub.UniqueError(17)),
|
||||||
call("fatalf", stub.ExpectArgs{"cannot capset: %v", []any{stub.UniqueError(17)}}, nil, nil),
|
call("fatalf", stub.ExpectArgs{"cannot capset: %v", []any{stub.UniqueError(17)}}, nil, nil),
|
||||||
},
|
},
|
||||||
}, nil},
|
}, nil},
|
||||||
@@ -1799,11 +1799,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -1837,6 +1837,7 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x5)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x5)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x6)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x6)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x7)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x7)}, nil, nil),
|
||||||
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x8)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x9)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x9)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xa)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xa)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xb)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xb)}, nil, nil),
|
||||||
@@ -1868,9 +1869,8 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x26)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x26)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x27)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x27)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x28)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x28)}, nil, nil),
|
||||||
call("capset", stub.ExpectArgs{&capHeader{_LINUX_CAPABILITY_VERSION_3, 0}, &[2]capData{{0x200100, 0x200100, 0x200100}, {0, 0, 0}}}, nil, nil),
|
|
||||||
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x15)}, nil, nil),
|
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x15)}, nil, nil),
|
||||||
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x8)}, nil, nil),
|
call("capset", stub.ExpectArgs{&capHeader{_LINUX_CAPABILITY_VERSION_3, 0}, &[2]capData{{0, 0x200000, 0x200000}, {0, 0, 0}}}, nil, nil),
|
||||||
call("verbosef", stub.ExpectArgs{"resolving presets %#x", []any{std.FilterPreset(0xf)}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"resolving presets %#x", []any{std.FilterPreset(0xf)}}, nil, nil),
|
||||||
call("seccompLoad", stub.ExpectArgs{seccomp.Preset(0xf, 0), seccomp.ExportFlag(0)}, nil, stub.UniqueError(15)),
|
call("seccompLoad", stub.ExpectArgs{seccomp.Preset(0xf, 0), seccomp.ExportFlag(0)}, nil, stub.UniqueError(15)),
|
||||||
call("fatalf", stub.ExpectArgs{"cannot load syscall filter: %v", []any{stub.UniqueError(15)}}, nil, nil),
|
call("fatalf", stub.ExpectArgs{"cannot load syscall filter: %v", []any{stub.UniqueError(15)}}, nil, nil),
|
||||||
@@ -1908,11 +1908,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -2032,11 +2032,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(4), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(4), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -2132,11 +2132,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(4), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(4), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -2232,11 +2232,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(4), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(4), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -2323,11 +2323,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(4), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(4), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -2418,11 +2418,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(4), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(4), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -2520,11 +2520,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -2659,11 +2659,11 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
call("sethostname", stub.ExpectArgs{[]byte("hakurei-check")}, nil, nil),
|
||||||
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
call("lastcap", stub.ExpectArgs{}, uintptr(40), nil),
|
||||||
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"", "/", "", uintptr(0x8c000), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
|
||||||
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
|
||||||
/* begin early */
|
/* begin early */
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/"}, "/", nil),
|
||||||
/* end early */
|
/* end early */
|
||||||
|
call("mount", stub.ExpectArgs{"rootfs", "/proc/self/fd", "tmpfs", uintptr(6), ""}, nil, nil),
|
||||||
|
call("chdir", stub.ExpectArgs{"/proc/self/fd"}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"sysroot", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"sysroot", "sysroot", "", uintptr(0xd000), ""}, nil, nil),
|
||||||
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
call("mkdir", stub.ExpectArgs{"host", os.FileMode(0755)}, nil, nil),
|
||||||
@@ -2697,6 +2697,7 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x5)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x5)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x6)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x6)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x7)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x7)}, nil, nil),
|
||||||
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x8)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x9)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x9)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xa)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xa)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xb)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0xb)}, nil, nil),
|
||||||
@@ -2728,9 +2729,8 @@ func TestInitEntrypoint(t *testing.T) {
|
|||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x26)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x26)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x27)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x27)}, nil, nil),
|
||||||
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x28)}, nil, nil),
|
call("capBoundingSetDrop", stub.ExpectArgs{uintptr(0x28)}, nil, nil),
|
||||||
call("capset", stub.ExpectArgs{&capHeader{_LINUX_CAPABILITY_VERSION_3, 0}, &[2]capData{{0x200100, 0x200100, 0x200100}, {0, 0, 0}}}, nil, nil),
|
|
||||||
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x15)}, nil, nil),
|
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x15)}, nil, nil),
|
||||||
call("capAmbientRaise", stub.ExpectArgs{uintptr(0x8)}, nil, nil),
|
call("capset", stub.ExpectArgs{&capHeader{_LINUX_CAPABILITY_VERSION_3, 0}, &[2]capData{{0, 0x200000, 0x200000}, {0, 0, 0}}}, nil, nil),
|
||||||
call("verbosef", stub.ExpectArgs{"resolving presets %#x", []any{std.FilterPreset(0xf)}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"resolving presets %#x", []any{std.FilterPreset(0xf)}}, nil, nil),
|
||||||
call("seccompLoad", stub.ExpectArgs{seccomp.Preset(0xf, 0), seccomp.ExportFlag(0)}, nil, nil),
|
call("seccompLoad", stub.ExpectArgs{seccomp.Preset(0xf, 0), seccomp.ExportFlag(0)}, nil, nil),
|
||||||
call("verbosef", stub.ExpectArgs{"%d filter rules loaded", []any{73}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"%d filter rules loaded", []any{73}}, nil, nil),
|
||||||
|
|||||||
+12
-40
@@ -4,9 +4,9 @@ import (
|
|||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"hakurei.app/check"
|
"hakurei.app/check"
|
||||||
"hakurei.app/ext"
|
|
||||||
"hakurei.app/fhs"
|
"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 {
|
if v, err := k.evalSymlinks(o.Upper.String()); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
o.upper = toHost(v)
|
o.upper = check.EscapeOverlayDataSegment(toHost(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error {
|
|||||||
if v, err := k.evalSymlinks(o.Work.String()); err != nil {
|
if v, err := k.evalSymlinks(o.Work.String()); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
o.work = toHost(v)
|
o.work = check.EscapeOverlayDataSegment(toHost(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,39 +168,12 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error {
|
|||||||
if v, err := k.evalSymlinks(a.String()); err != nil {
|
if v, err := k.evalSymlinks(a.String()); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
o.lower[i] = toHost(v)
|
o.lower[i] = check.EscapeOverlayDataSegment(toHost(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
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 {
|
func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
|
||||||
target := o.Target.String()
|
target := o.Target.String()
|
||||||
if !o.noPrefix {
|
if !o.noPrefix {
|
||||||
@@ -221,7 +194,7 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
options := make([][2]string, 0, 2+len(o.lower))
|
options := make([]string, 0, 4)
|
||||||
|
|
||||||
if o.upper == zeroString && o.work == zeroString { // readonly
|
if o.upper == zeroString && o.work == zeroString { // readonly
|
||||||
if len(o.Lower) < 2 {
|
if len(o.Lower) < 2 {
|
||||||
@@ -232,16 +205,15 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
|
|||||||
if len(o.Lower) == 0 {
|
if len(o.Lower) == 0 {
|
||||||
return &OverlayArgumentError{OverlayEmptyLower, zeroString}
|
return &OverlayArgumentError{OverlayEmptyLower, zeroString}
|
||||||
}
|
}
|
||||||
options = append(options, [][2]string{
|
options = append(options,
|
||||||
{OptionOverlayUpperdir, o.upper},
|
OptionOverlayUpperdir+"="+o.upper,
|
||||||
{OptionOverlayWorkdir, o.work},
|
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.mountOverlay(target, options)
|
return k.mount(SourceOverlay, target, FstypeOverlay, 0, strings.Join(options, check.SpecialOverlayOption))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *MountOverlayOp) late(*setupState, syscallDispatcher) error { return nil }
|
func (o *MountOverlayOp) late(*setupState, syscallDispatcher) error { return nil }
|
||||||
|
|||||||
@@ -97,12 +97,13 @@ func TestMountOverlayOp(t *testing.T) {
|
|||||||
call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0705)}, nil, nil),
|
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.upper.*"}, "overlay.upper.32768", nil),
|
||||||
call("mkdirTemp", stub.ExpectArgs{"/", "overlay.work.*"}, "overlay.work.32768", nil),
|
call("mkdirTemp", stub.ExpectArgs{"/", "overlay.work.*"}, "overlay.work.32768", nil),
|
||||||
call("mountOverlay", stub.ExpectArgs{"/sysroot", [][2]string{
|
call("mount", stub.ExpectArgs{"overlay", "/sysroot", "overlay", uintptr(0), "" +
|
||||||
{"upperdir", "overlay.upper.32768"},
|
"upperdir=overlay.upper.32768," +
|
||||||
{"workdir", "overlay.work.32768"},
|
"workdir=overlay.work.32768," +
|
||||||
{"lowerdir+", `/host/var/lib/planterette/base/debian:f92c9052`},
|
"lowerdir=" +
|
||||||
{"lowerdir+", `/host/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052`},
|
`/host/var/lib/planterette/base/debian\:f92c9052:` +
|
||||||
}}, nil, nil),
|
`/host/var/lib/planterette/app/org.chromium.Chromium@debian\:f92c9052,` +
|
||||||
|
"userxattr"}, nil, nil),
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"short lower ro", &Params{ParentPerm: 0755}, &MountOverlayOp{
|
{"short lower ro", &Params{ParentPerm: 0755}, &MountOverlayOp{
|
||||||
@@ -128,10 +129,11 @@ func TestMountOverlayOp(t *testing.T) {
|
|||||||
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/nix/store", os.FileMode(0755)}, nil, nil),
|
call("mkdirAll", stub.ExpectArgs{"/nix/store", os.FileMode(0755)}, nil, nil),
|
||||||
call("mountOverlay", stub.ExpectArgs{"/nix/store", [][2]string{
|
call("mount", stub.ExpectArgs{"overlay", "/nix/store", "overlay", uintptr(0), "" +
|
||||||
{"lowerdir+", "/host/mnt-root/nix/.ro-store"},
|
"lowerdir=" +
|
||||||
{"lowerdir+", "/host/mnt-root/nix/.ro-store0"},
|
"/host/mnt-root/nix/.ro-store:" +
|
||||||
}}, nil, nil),
|
"/host/mnt-root/nix/.ro-store0," +
|
||||||
|
"userxattr"}, nil, nil),
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"success ro", &Params{ParentPerm: 0755}, &MountOverlayOp{
|
{"success ro", &Params{ParentPerm: 0755}, &MountOverlayOp{
|
||||||
@@ -145,10 +147,11 @@ func TestMountOverlayOp(t *testing.T) {
|
|||||||
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0755)}, nil, nil),
|
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0755)}, nil, nil),
|
||||||
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
||||||
{"lowerdir+", "/host/mnt-root/nix/.ro-store"},
|
"lowerdir=" +
|
||||||
{"lowerdir+", "/host/mnt-root/nix/.ro-store0"},
|
"/host/mnt-root/nix/.ro-store:" +
|
||||||
}}, nil, nil),
|
"/host/mnt-root/nix/.ro-store0," +
|
||||||
|
"userxattr"}, nil, nil),
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"nil lower", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
{"nil lower", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||||
@@ -216,11 +219,7 @@ func TestMountOverlayOp(t *testing.T) {
|
|||||||
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
||||||
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
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)),
|
||||||
{"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)},
|
}, stub.UniqueError(0)},
|
||||||
|
|
||||||
{"success single layer", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
{"success single layer", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||||
@@ -234,11 +233,11 @@ func TestMountOverlayOp(t *testing.T) {
|
|||||||
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
||||||
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
||||||
{"upperdir", "/host/mnt-root/nix/.rw-store/.upper"},
|
"upperdir=/host/mnt-root/nix/.rw-store/.upper," +
|
||||||
{"workdir", "/host/mnt-root/nix/.rw-store/.work"},
|
"workdir=/host/mnt-root/nix/.rw-store/.work," +
|
||||||
{"lowerdir+", "/host/mnt-root/nix/ro-store"},
|
"lowerdir=/host/mnt-root/nix/ro-store," +
|
||||||
}}, nil, nil),
|
"userxattr"}, nil, nil),
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"success", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
{"success", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
||||||
@@ -262,15 +261,16 @@ func TestMountOverlayOp(t *testing.T) {
|
|||||||
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store3"}, "/mnt-root/nix/ro-store3", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store3"}, "/mnt-root/nix/ro-store3", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
||||||
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
||||||
{"upperdir", "/host/mnt-root/nix/.rw-store/.upper"},
|
"upperdir=/host/mnt-root/nix/.rw-store/.upper," +
|
||||||
{"workdir", "/host/mnt-root/nix/.rw-store/.work"},
|
"workdir=/host/mnt-root/nix/.rw-store/.work," +
|
||||||
{"lowerdir+", "/host/mnt-root/nix/ro-store"},
|
"lowerdir=" +
|
||||||
{"lowerdir+", "/host/mnt-root/nix/ro-store0"},
|
"/host/mnt-root/nix/ro-store:" +
|
||||||
{"lowerdir+", "/host/mnt-root/nix/ro-store1"},
|
"/host/mnt-root/nix/ro-store0:" +
|
||||||
{"lowerdir+", "/host/mnt-root/nix/ro-store2"},
|
"/host/mnt-root/nix/ro-store1:" +
|
||||||
{"lowerdir+", "/host/mnt-root/nix/ro-store3"},
|
"/host/mnt-root/nix/ro-store2:" +
|
||||||
}}, nil, nil),
|
"/host/mnt-root/nix/ro-store3," +
|
||||||
|
"userxattr"}, nil, nil),
|
||||||
}, nil},
|
}, nil},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,6 @@ const (
|
|||||||
// SourceMqueue is used when mounting mqueue.
|
// SourceMqueue is used when mounting mqueue.
|
||||||
// Note that any source value is allowed when fstype is [FstypeMqueue].
|
// Note that any source value is allowed when fstype is [FstypeMqueue].
|
||||||
SourceMqueue = "mqueue"
|
SourceMqueue = "mqueue"
|
||||||
// SourceBinfmtMisc is used when mounting binfmt_misc.
|
|
||||||
// Note that any source value is allowed when fstype is [SourceBinfmtMisc].
|
|
||||||
SourceBinfmtMisc = "binfmt_misc"
|
|
||||||
// SourceOverlay is used when mounting overlay.
|
// SourceOverlay is used when mounting overlay.
|
||||||
// Note that any source value is allowed when fstype is [FstypeOverlay].
|
// Note that any source value is allowed when fstype is [FstypeOverlay].
|
||||||
SourceOverlay = "overlay"
|
SourceOverlay = "overlay"
|
||||||
@@ -73,9 +70,6 @@ const (
|
|||||||
// FstypeMqueue represents the mqueue pseudo-filesystem.
|
// FstypeMqueue represents the mqueue pseudo-filesystem.
|
||||||
// This filesystem type is usually mounted on /dev/mqueue.
|
// This filesystem type is usually mounted on /dev/mqueue.
|
||||||
FstypeMqueue = "mqueue"
|
FstypeMqueue = "mqueue"
|
||||||
// FstypeBinfmtMisc represents the binfmt_misc pseudo-filesystem.
|
|
||||||
// This filesystem type is usually mounted on /proc/sys/fs/binfmt_misc.
|
|
||||||
FstypeBinfmtMisc = "binfmt_misc"
|
|
||||||
// FstypeOverlay represents the overlay pseudo-filesystem.
|
// FstypeOverlay represents the overlay pseudo-filesystem.
|
||||||
// This filesystem type can be mounted anywhere in the container filesystem.
|
// This filesystem type can be mounted anywhere in the container filesystem.
|
||||||
FstypeOverlay = "overlay"
|
FstypeOverlay = "overlay"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"hakurei.app/check"
|
||||||
"hakurei.app/vfs"
|
"hakurei.app/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,6 +50,9 @@ 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) {
|
func TestCreateFile(t *testing.T) {
|
||||||
t.Run("nonexistent", func(t *testing.T) {
|
t.Run("nonexistent", func(t *testing.T) {
|
||||||
t.Run("mkdir", func(t *testing.T) {
|
t.Run("mkdir", func(t *testing.T) {
|
||||||
|
|||||||
@@ -1,267 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -42,8 +42,6 @@ var (
|
|||||||
AbsDevShm = unsafeAbs(DevShm)
|
AbsDevShm = unsafeAbs(DevShm)
|
||||||
// AbsProc is [Proc] as [check.Absolute].
|
// AbsProc is [Proc] as [check.Absolute].
|
||||||
AbsProc = unsafeAbs(Proc)
|
AbsProc = unsafeAbs(Proc)
|
||||||
// AbsProcSys is [ProcSys] as [check.Absolute].
|
|
||||||
AbsProcSys = unsafeAbs(ProcSys)
|
|
||||||
// AbsProcSelfExe is [ProcSelfExe] as [check.Absolute].
|
// AbsProcSelfExe is [ProcSelfExe] as [check.Absolute].
|
||||||
AbsProcSelfExe = unsafeAbs(ProcSelfExe)
|
AbsProcSelfExe = unsafeAbs(ProcSelfExe)
|
||||||
// AbsSys is [Sys] as [check.Absolute].
|
// AbsSys is [Sys] as [check.Absolute].
|
||||||
|
|||||||
@@ -139,6 +139,7 @@
|
|||||||
GOCACHE="$(mktemp -d)" \
|
GOCACHE="$(mktemp -d)" \
|
||||||
PATH="${pkgs.pkgsStatic.musl.bin}/bin:$PATH" \
|
PATH="${pkgs.pkgsStatic.musl.bin}/bin:$PATH" \
|
||||||
DESTDIR="$out" \
|
DESTDIR="$out" \
|
||||||
|
HAKUREI_VERSION="v${hakurei.version}" \
|
||||||
./all.sh
|
./all.sh
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,78 @@ func TestFlatten(t *testing.T) {
|
|||||||
{Mode: fs.ModeDir | 0700, Path: "work"},
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
}, pkg.MustDecode("E4vEZKhCcL2gPZ2Tt59FS3lDng-d_2SKa2i5G_RbDfwGn6EemptFaGLPUDiOa94C"), nil},
|
}, pkg.MustDecode("E4vEZKhCcL2gPZ2Tt59FS3lDng-d_2SKa2i5G_RbDfwGn6EemptFaGLPUDiOa94C"), nil},
|
||||||
|
|
||||||
|
{"sample cache file", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX": {Mode: 0400, Data: []byte{0}},
|
||||||
|
"checksum/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq": {Mode: 0400, Data: []byte{0, 0, 0, 0, 0xad, 0xb, 0, 4, 0xfe, 0xfe, 0, 0, 0xfe, 0xca, 0, 0}},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
|
||||||
|
"identifier/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq")},
|
||||||
|
"identifier/cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq")},
|
||||||
|
"identifier/deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq")},
|
||||||
|
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: 0400, Path: "checksum/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq", Data: []byte{0, 0, 0, 0, 0xad, 0xb, 0, 4, 0xfe, 0xfe, 0, 0, 0xfe, 0xca, 0, 0}},
|
||||||
|
{Mode: 0400, Path: "checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX", Data: []byte{0}},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq", Data: []byte("../checksum/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe", Data: []byte("../checksum/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", Data: []byte("../checksum/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX", Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("St9rlE-mGZ5gXwiv_hzQ_B8bZP-UUvSNmf4nHUZzCMOumb6hKnheZSe0dmnuc4Q2"), nil},
|
||||||
|
|
||||||
|
{"sample http get cure", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU": {Mode: 0400, Data: []byte("\x7f\xe1\x69\xa2\xdd\x63\x96\x26\x83\x79\x61\x8b\xf0\x3f\xd5\x16\x9a\x39\x3a\xdb\xcf\xb1\xbc\x8d\x33\xff\x75\xee\x62\x56\xa9\xf0\x27\xac\x13\x94\x69")},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/oM-2pUlk-mOxK1t3aMWZer69UdOQlAXiAgMrpZ1476VoOqpYVP1aGFS9_HYy-D8_": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU")},
|
||||||
|
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: 0400, Path: "checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU", Data: []byte("\x7f\xe1\x69\xa2\xdd\x63\x96\x26\x83\x79\x61\x8b\xf0\x3f\xd5\x16\x9a\x39\x3a\xdb\xcf\xb1\xbc\x8d\x33\xff\x75\xee\x62\x56\xa9\xf0\x27\xac\x13\x94\x69")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/oM-2pUlk-mOxK1t3aMWZer69UdOQlAXiAgMrpZ1476VoOqpYVP1aGFS9_HYy-D8_", Data: []byte("../checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("L_0RFHpr9JUS4Zp14rz2dESSRvfLzpvqsLhR1-YjQt8hYlmEdVl7vI3_-v8UNPKs"), nil},
|
||||||
|
|
||||||
|
{"sample directory step simple", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0500},
|
||||||
|
|
||||||
|
"check": {Mode: 0400, Data: []byte{0, 0}},
|
||||||
|
|
||||||
|
"lib": {Mode: fs.ModeDir | 0700},
|
||||||
|
"lib/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
|
||||||
|
"lib/pkgconfig": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "."},
|
||||||
|
|
||||||
|
{Mode: 0400, Path: "check", Data: []byte{0, 0}},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "lib"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "lib/libedac.so", Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "lib/pkgconfig"},
|
||||||
|
}, pkg.MustDecode("qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b"), nil},
|
||||||
|
|
||||||
{"sample directory step garbage", fstest.MapFS{
|
{"sample directory step garbage", fstest.MapFS{
|
||||||
".": {Mode: fs.ModeDir | 0500},
|
".": {Mode: fs.ModeDir | 0500},
|
||||||
|
|
||||||
@@ -79,6 +151,421 @@ func TestFlatten(t *testing.T) {
|
|||||||
|
|
||||||
{Mode: fs.ModeDir | 0500, Path: "lib/pkgconfig"},
|
{Mode: fs.ModeDir | 0500, Path: "lib/pkgconfig"},
|
||||||
}, pkg.MustDecode("CUx-3hSbTWPsbMfDhgalG4Ni_GmR9TnVX8F99tY_P5GtkYvczg9RrF5zO0jX9XYT"), nil},
|
}, pkg.MustDecode("CUx-3hSbTWPsbMfDhgalG4Ni_GmR9TnVX8F99tY_P5GtkYvczg9RrF5zO0jX9XYT"), nil},
|
||||||
|
|
||||||
|
{"sample directory", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b/check": {Mode: 0400, Data: []byte{0, 0}},
|
||||||
|
"checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b/lib": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b/lib/pkgconfig": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b/lib/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||||
|
"identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||||
|
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b"},
|
||||||
|
{Mode: 0400, Path: "checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b/check", Data: []byte{0, 0}},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b/lib"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b/lib/libedac.so", Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b/lib/pkgconfig"},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY", Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa", Data: []byte("../checksum/qRN6in76LndiiOZJheHkwyW8UT1N5-f-bXvHfDvwrMw2fSkOoZdh8pWE1qhLk65b")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("WVpvsVqVKg9Nsh744x57h51AuWUoUR2nnh8Md-EYBQpk6ziyTuUn6PLtF2e0Eu_d"), nil},
|
||||||
|
|
||||||
|
{"sample no assume checksum", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/Aubi5EG4_Y8DhL9bQ3Q4HFBhLRF7X5gt9D3CNCQfT-TeBtlRXc7Zi_JYZEMoCC7M": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/Aubi5EG4_Y8DhL9bQ3Q4HFBhLRF7X5gt9D3CNCQfT-TeBtlRXc7Zi_JYZEMoCC7M/check": {Mode: 0400, Data: []byte{}},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/Aubi5EG4_Y8DhL9bQ3Q4HFBhLRF7X5gt9D3CNCQfT-TeBtlRXc7Zi_JYZEMoCC7M")},
|
||||||
|
"identifier/_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/Aubi5EG4_Y8DhL9bQ3Q4HFBhLRF7X5gt9D3CNCQfT-TeBtlRXc7Zi_JYZEMoCC7M")},
|
||||||
|
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/Aubi5EG4_Y8DhL9bQ3Q4HFBhLRF7X5gt9D3CNCQfT-TeBtlRXc7Zi_JYZEMoCC7M"},
|
||||||
|
{Mode: 0400, Path: "checksum/Aubi5EG4_Y8DhL9bQ3Q4HFBhLRF7X5gt9D3CNCQfT-TeBtlRXc7Zi_JYZEMoCC7M/check", Data: []byte{}},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", Data: []byte("../checksum/Aubi5EG4_Y8DhL9bQ3Q4HFBhLRF7X5gt9D3CNCQfT-TeBtlRXc7Zi_JYZEMoCC7M")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", Data: []byte("../checksum/Aubi5EG4_Y8DhL9bQ3Q4HFBhLRF7X5gt9D3CNCQfT-TeBtlRXc7Zi_JYZEMoCC7M")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("OC290t23aimNo2Rp2pPwan5GI2KRLRdOwYxXQMD9jw0QROgHnNXWodoWdV0hwu2w"), nil},
|
||||||
|
|
||||||
|
{"sample tar step unpack", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0500},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/check": {Mode: 0400, Data: []byte{0, 0}},
|
||||||
|
"checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/pkgconfig": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0500},
|
||||||
|
"identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
||||||
|
"identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
||||||
|
|
||||||
|
"work": {Mode: fs.ModeDir | 0500},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP"},
|
||||||
|
{Mode: 0400, Path: "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/check", Data: []byte{0, 0}},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/libedac.so", Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/pkgconfig"},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY", Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa", Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "work"},
|
||||||
|
}, pkg.MustDecode("cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM"), nil},
|
||||||
|
|
||||||
|
{"sample tar", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/check": {Mode: 0400, Data: []byte{0, 0}},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/pkgconfig": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/identifier": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
||||||
|
"checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/work": {Mode: fs.ModeDir | 0500},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/W5S65DEhawz_WKaok5NjUKLmnD9dNl5RPauNJjcOVcB3VM4eGhSaLGmXbL8vZpiw": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM")},
|
||||||
|
"identifier/rg7F1D5hwv6o4xctjD5zDq4i5MD0mArTsUIWfhUbik8xC6Bsyt3mjXXOm3goojTz": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM")},
|
||||||
|
|
||||||
|
"temp": {Mode: fs.ModeDir | 0700},
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP"},
|
||||||
|
{Mode: 0400, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/check", Data: []byte{0, 0}},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/libedac.so", Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/pkgconfig"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY", Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa", Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM/work"},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/W5S65DEhawz_WKaok5NjUKLmnD9dNl5RPauNJjcOVcB3VM4eGhSaLGmXbL8vZpiw", Data: []byte("../checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/rg7F1D5hwv6o4xctjD5zDq4i5MD0mArTsUIWfhUbik8xC6Bsyt3mjXXOm3goojTz", Data: []byte("../checksum/cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "temp"},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("NQTlc466JmSVLIyWklm_u8_g95jEEb98PxJU-kjwxLpfdjwMWJq0G8ze9R4Vo1Vu"), nil},
|
||||||
|
|
||||||
|
{"sample tar expand step unpack", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0500},
|
||||||
|
|
||||||
|
"libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "libedac.so", Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
}, pkg.MustDecode("CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN"), nil},
|
||||||
|
|
||||||
|
{"sample tar expand", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/W5S65DEhawz_WKaok5NjUKLmnD9dNl5RPauNJjcOVcB3VM4eGhSaLGmXbL8vZpiw": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN")},
|
||||||
|
"identifier/_v1blm2h-_KA-dVaawdpLas6MjHc6rbhhFS8JWwx8iJxZGUu8EBbRrhr5AaZ9PJL": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN")},
|
||||||
|
|
||||||
|
"temp": {Mode: fs.ModeDir | 0700},
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "checksum/CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN/libedac.so", Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/W5S65DEhawz_WKaok5NjUKLmnD9dNl5RPauNJjcOVcB3VM4eGhSaLGmXbL8vZpiw", Data: []byte("../checksum/CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/_v1blm2h-_KA-dVaawdpLas6MjHc6rbhhFS8JWwx8iJxZGUu8EBbRrhr5AaZ9PJL", Data: []byte("../checksum/CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "temp"},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("hSoSSgCYTNonX3Q8FjvjD1fBl-E-BQyA6OTXro2OadXqbST4tZ-akGXszdeqphRe"), nil},
|
||||||
|
|
||||||
|
{"testtool", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0500},
|
||||||
|
|
||||||
|
"check": {Mode: 0400, Data: []byte{0}},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "."},
|
||||||
|
|
||||||
|
{Mode: 0400, Path: "check", Data: []byte{0}},
|
||||||
|
}, pkg.MustDecode("GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9"), nil},
|
||||||
|
|
||||||
|
{"sample exec container", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check": {Mode: 0400, Data: []byte{0}},
|
||||||
|
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||||
|
"identifier/dztPS6jRjiZtCF4_p8AzfnxGp6obkhrgFVsxdodbKWUoAEVtDz3MykepJB4kI_ks": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
|
||||||
|
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
|
||||||
|
"temp": {Mode: fs.ModeDir | 0700},
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9"},
|
||||||
|
{Mode: 0400, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check", Data: []byte{0}},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU"},
|
||||||
|
{Mode: 0400, Path: "checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb", Data: []byte{}},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/dztPS6jRjiZtCF4_p8AzfnxGp6obkhrgFVsxdodbKWUoAEVtDz3MykepJB4kI_ks", Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK", Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "temp"},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("Q5DluWQCAeohLoiGRImurwFp3vdz9IfQCoj7Fuhh73s4KQPRHpEQEnHTdNHmB8Fx"), nil},
|
||||||
|
|
||||||
|
{"testtool net", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0500},
|
||||||
|
|
||||||
|
"check": {Mode: 0400, Data: []byte("net")},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "."},
|
||||||
|
|
||||||
|
{Mode: 0400, Path: "check", Data: []byte("net")},
|
||||||
|
}, pkg.MustDecode("a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W"), nil},
|
||||||
|
|
||||||
|
{"sample exec net container", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}},
|
||||||
|
"checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W/check": {Mode: 0400, Data: []byte("net")},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/G8qPxD9puvvoOVV7lrT80eyDeIl3G_CCFoKw12c8mCjMdG1zF7NEPkwYpNubClK3": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W")},
|
||||||
|
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||||
|
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
|
||||||
|
"temp": {Mode: fs.ModeDir | 0700},
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU"},
|
||||||
|
{Mode: 0400, Path: "checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb", Data: []byte{}},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W"},
|
||||||
|
{Mode: 0400, Path: "checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W/check", Data: []byte("net")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/G8qPxD9puvvoOVV7lrT80eyDeIl3G_CCFoKw12c8mCjMdG1zF7NEPkwYpNubClK3", Data: []byte("../checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK", Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "temp"},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("bPYvvqxpfV7xcC1EptqyKNK1klLJgYHMDkzBcoOyK6j_Aj5hb0mXNPwTwPSK5F6Z"), nil},
|
||||||
|
|
||||||
|
{"sample exec container overlay root", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check": {Mode: 0400, Data: []byte{0}},
|
||||||
|
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/RdMA-mubnrHuu3Ky1wWyxauSYCO0ZH_zCPUj3uDHqkfwv5sGcByoF_g5PjlGiClb": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
|
||||||
|
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
|
||||||
|
"temp": {Mode: fs.ModeDir | 0700},
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9"},
|
||||||
|
{Mode: 0400, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check", Data: []byte{0}},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU"},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/RdMA-mubnrHuu3Ky1wWyxauSYCO0ZH_zCPUj3uDHqkfwv5sGcByoF_g5PjlGiClb", Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK", Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "temp"},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("PO2DSSCa4yoSgEYRcCSZfQfwow1yRigL3Ry-hI0RDI4aGuFBha-EfXeSJnG_5_Rl"), nil},
|
||||||
|
|
||||||
|
{"sample exec container overlay work", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check": {Mode: 0400, Data: []byte{0}},
|
||||||
|
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/5hlaukCirnXE4W_RSLJFOZN47Z5RiHnacXzdFp_70cLgiJUGR6cSb_HaFftkzi0-": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
|
||||||
|
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
|
||||||
|
"temp": {Mode: fs.ModeDir | 0700},
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9"},
|
||||||
|
{Mode: 0400, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check", Data: []byte{0}},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU"},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/5hlaukCirnXE4W_RSLJFOZN47Z5RiHnacXzdFp_70cLgiJUGR6cSb_HaFftkzi0-", Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK", Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "temp"},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("iaRt6l_Wm2n-h5UsDewZxQkCmjZjyL8r7wv32QT2kyV55-Lx09Dq4gfg9BiwPnKs"), nil},
|
||||||
|
|
||||||
|
{"sample exec container multiple layers", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check": {Mode: 0400, Data: []byte{0}},
|
||||||
|
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}},
|
||||||
|
"checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK/check": {Mode: 0400, Data: []byte("layers")},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||||
|
"identifier/B-kc5iJMx8GtlCua4dz6BiJHnDAOUfPjgpbKq4e-QEn0_CZkSYs3fOA1ve06qMs2": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK")},
|
||||||
|
"identifier/p1t_drXr34i-jZNuxDMLaMOdL6tZvQqhavNafGynGqxOZoXAUTSn7kqNh3Ovv3DT": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
|
||||||
|
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
|
||||||
|
"temp": {Mode: fs.ModeDir | 0700},
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9"},
|
||||||
|
{Mode: 0400, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check", Data: []byte{0}},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU"},
|
||||||
|
{Mode: 0400, Path: "checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb", Data: []byte{}},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK"},
|
||||||
|
{Mode: 0400, Path: "checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK/check", Data: []byte("layers")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/B-kc5iJMx8GtlCua4dz6BiJHnDAOUfPjgpbKq4e-QEn0_CZkSYs3fOA1ve06qMs2", Data: []byte("../checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/p1t_drXr34i-jZNuxDMLaMOdL6tZvQqhavNafGynGqxOZoXAUTSn7kqNh3Ovv3DT", Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK", Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "temp"},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("O2YzyR7IUGU5J2CADy0hUZ3A5NkP_Vwzs4UadEdn2oMZZVWRtH0xZGJ3HXiimTnZ"), nil},
|
||||||
|
|
||||||
|
{"sample exec container layer promotion", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9": {Mode: fs.ModeDir | 0500},
|
||||||
|
"checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check": {Mode: 0400, Data: []byte{0}},
|
||||||
|
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/kvJIqZo5DKFOxC2ZQ-8_nPaQzEAz9cIm3p6guO-uLqm-xaiPu7oRkSnsu411jd_U": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
"identifier/xXTIYcXmgJWNLC91c417RRrNM9cjELwEZHpGvf8Fk_GNP5agRJp_SicD0w9aMeLJ": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
|
||||||
|
|
||||||
|
"temp": {Mode: fs.ModeDir | 0700},
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9"},
|
||||||
|
{Mode: 0400, Path: "checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9/check", Data: []byte{0}},
|
||||||
|
{Mode: fs.ModeDir | 0500, Path: "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU"},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/kvJIqZo5DKFOxC2ZQ-8_nPaQzEAz9cIm3p6guO-uLqm-xaiPu7oRkSnsu411jd_U", Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK", Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/xXTIYcXmgJWNLC91c417RRrNM9cjELwEZHpGvf8Fk_GNP5agRJp_SicD0w9aMeLJ", Data: []byte("../checksum/GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "temp"},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("3EaW6WibLi9gl03_UieiFPaFcPy5p4x3JPxrnLJxGaTI-bh3HU9DK9IMx7c3rrNm"), nil},
|
||||||
|
|
||||||
|
{"sample file short", fstest.MapFS{
|
||||||
|
".": {Mode: fs.ModeDir | 0700},
|
||||||
|
|
||||||
|
"checksum": {Mode: fs.ModeDir | 0700},
|
||||||
|
"checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX": {Mode: 0400, Data: []byte{0}},
|
||||||
|
|
||||||
|
"identifier": {Mode: fs.ModeDir | 0700},
|
||||||
|
"identifier/3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
|
||||||
|
|
||||||
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
|
}, []pkg.FlatEntry{
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "."},
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "checksum"},
|
||||||
|
{Mode: 0400, Path: "checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX", Data: []byte{0}},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "identifier"},
|
||||||
|
{Mode: fs.ModeSymlink | 0777, Path: "identifier/3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi", Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
|
||||||
|
|
||||||
|
{Mode: fs.ModeDir | 0700, Path: "work"},
|
||||||
|
}, pkg.MustDecode("iR6H5OIsyOW4EwEgtm9rGzGF6DVtyHLySEtwnFE8bnus9VJcoCbR4JIek7Lw-vwT"), nil},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
|||||||
+34
-104
@@ -9,10 +9,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"unique"
|
"unique"
|
||||||
@@ -96,32 +94,6 @@ func MustPath(pathname string, writable bool, a ...Artifact) ExecPath {
|
|||||||
return ExecPath{check.MustAbs(pathname), a, writable}
|
return ExecPath{check.MustAbs(pathname), a, writable}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
binfmt map[string]container.BinfmtEntry
|
|
||||||
binfmtMu sync.RWMutex
|
|
||||||
)
|
|
||||||
|
|
||||||
// RegisterArch arranges for [KindExec] and [KindExecNet] to support a new
|
|
||||||
// architecture via a binfmt_misc entry. Each architecture must be registered
|
|
||||||
// at most once.
|
|
||||||
func RegisterArch(arch string, e container.BinfmtEntry) {
|
|
||||||
if arch == "" {
|
|
||||||
panic(UnsupportedArchError(arch))
|
|
||||||
}
|
|
||||||
|
|
||||||
binfmtMu.Lock()
|
|
||||||
defer binfmtMu.Unlock()
|
|
||||||
|
|
||||||
if binfmt == nil {
|
|
||||||
binfmt = make(map[string]container.BinfmtEntry)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := binfmt[arch]; ok {
|
|
||||||
panic("attempting to register " + strconv.Quote(arch) + " twice")
|
|
||||||
}
|
|
||||||
binfmt[arch] = e
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// ExecTimeoutDefault replaces out of range [NewExec] timeout values.
|
// ExecTimeoutDefault replaces out of range [NewExec] timeout values.
|
||||||
ExecTimeoutDefault = 15 * time.Minute
|
ExecTimeoutDefault = 15 * time.Minute
|
||||||
@@ -138,8 +110,6 @@ type execArtifact struct {
|
|||||||
// Caller-supplied user-facing reporting name, guaranteed to be nonzero
|
// Caller-supplied user-facing reporting name, guaranteed to be nonzero
|
||||||
// during initialisation.
|
// during initialisation.
|
||||||
name string
|
name string
|
||||||
// Target architecture.
|
|
||||||
arch string
|
|
||||||
// Caller-supplied inner mount points.
|
// Caller-supplied inner mount points.
|
||||||
paths []ExecPath
|
paths []ExecPath
|
||||||
|
|
||||||
@@ -162,40 +132,28 @@ type execArtifact struct {
|
|||||||
|
|
||||||
var _ fmt.Stringer = new(execArtifact)
|
var _ fmt.Stringer = new(execArtifact)
|
||||||
|
|
||||||
// execMeasuredArtifact is like execArtifact but implements [KnownChecksum] and
|
// execNetArtifact is like execArtifact but implements [KnownChecksum] and has
|
||||||
// has its resulting container optionally keep the host net namespace.
|
// its resulting container keep the host net namespace.
|
||||||
type execMeasuredArtifact struct {
|
type execNetArtifact struct {
|
||||||
checksum Checksum
|
checksum Checksum
|
||||||
|
|
||||||
// Whether to keep host net namespace.
|
|
||||||
hostNet bool
|
|
||||||
|
|
||||||
execArtifact
|
execArtifact
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ KnownChecksum = new(execMeasuredArtifact)
|
var _ KnownChecksum = new(execNetArtifact)
|
||||||
|
|
||||||
// Checksum returns the caller-supplied checksum.
|
// Checksum returns the caller-supplied checksum.
|
||||||
func (a *execMeasuredArtifact) Checksum() Checksum { return a.checksum }
|
func (a *execNetArtifact) Checksum() Checksum { return a.checksum }
|
||||||
|
|
||||||
// Kind returns [KindExecNet], or [KindExec] if hostNet is false.
|
// Kind returns the hardcoded [Kind] constant.
|
||||||
func (a *execMeasuredArtifact) Kind() Kind {
|
func (*execNetArtifact) Kind() Kind { return KindExecNet }
|
||||||
if a == nil || a.hostNet {
|
|
||||||
return KindExecNet
|
|
||||||
}
|
|
||||||
return KindExec
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cure cures the [Artifact] in the container described by the caller. The
|
// Cure cures the [Artifact] in the container described by the caller. The
|
||||||
// container optionally retains host networking.
|
// container retains host networking.
|
||||||
func (a *execMeasuredArtifact) Cure(f *FContext) error {
|
func (a *execNetArtifact) Cure(f *FContext) error {
|
||||||
return a.cure(f, a.hostNet)
|
return a.cure(f, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrNetChecksum is panicked by [NewExec] if host net namespace is requested
|
|
||||||
// with a nil checksum.
|
|
||||||
var ErrNetChecksum = errors.New("attempting to keep net namespace without checksum")
|
|
||||||
|
|
||||||
// NewExec returns a new [Artifact] that executes the program path in a
|
// NewExec returns a new [Artifact] that executes the program path in a
|
||||||
// container with specified paths bind mounted read-only in order. A private
|
// container with specified paths bind mounted read-only in order. A private
|
||||||
// instance of /proc and /dev is made available to the container.
|
// instance of /proc and /dev is made available to the container.
|
||||||
@@ -209,7 +167,7 @@ var ErrNetChecksum = errors.New("attempting to keep net namespace without checks
|
|||||||
// regular or symlink.
|
// regular or symlink.
|
||||||
//
|
//
|
||||||
// If checksum is non-nil, the resulting [Artifact] implements [KnownChecksum]
|
// If checksum is non-nil, the resulting [Artifact] implements [KnownChecksum]
|
||||||
// and its container optionally runs in the host net namespace.
|
// and its container runs in the host net namespace.
|
||||||
//
|
//
|
||||||
// The container is allowed to run for the specified duration before the initial
|
// The container is allowed to run for the specified duration before the initial
|
||||||
// process and all processes originating from it is terminated. A zero or
|
// process and all processes originating from it is terminated. A zero or
|
||||||
@@ -220,10 +178,10 @@ var ErrNetChecksum = errors.New("attempting to keep net namespace without checks
|
|||||||
// container and does not affect curing outcome. Because of this, it is omitted
|
// container and does not affect curing outcome. Because of this, it is omitted
|
||||||
// from parameter data for computing identifier.
|
// from parameter data for computing identifier.
|
||||||
func NewExec(
|
func NewExec(
|
||||||
name, arch string,
|
name string,
|
||||||
checksum *Checksum,
|
checksum *Checksum,
|
||||||
timeout time.Duration,
|
timeout time.Duration,
|
||||||
hostNet, exclusive bool,
|
exclusive bool,
|
||||||
|
|
||||||
dir *check.Absolute,
|
dir *check.Absolute,
|
||||||
env []string,
|
env []string,
|
||||||
@@ -235,23 +193,17 @@ func NewExec(
|
|||||||
if name == "" {
|
if name == "" {
|
||||||
name = "exec-" + filepath.Base(pathname.String())
|
name = "exec-" + filepath.Base(pathname.String())
|
||||||
}
|
}
|
||||||
if arch == "" {
|
|
||||||
arch = runtime.GOARCH
|
|
||||||
}
|
|
||||||
if timeout <= 0 {
|
if timeout <= 0 {
|
||||||
timeout = ExecTimeoutDefault
|
timeout = ExecTimeoutDefault
|
||||||
}
|
}
|
||||||
if timeout > ExecTimeoutMax {
|
if timeout > ExecTimeoutMax {
|
||||||
timeout = ExecTimeoutMax
|
timeout = ExecTimeoutMax
|
||||||
}
|
}
|
||||||
a := execArtifact{name, arch, paths, dir, env, pathname, args, timeout, exclusive}
|
a := execArtifact{name, paths, dir, env, pathname, args, timeout, exclusive}
|
||||||
if checksum == nil {
|
if checksum == nil {
|
||||||
if hostNet {
|
|
||||||
panic(ErrNetChecksum)
|
|
||||||
}
|
|
||||||
return &a
|
return &a
|
||||||
}
|
}
|
||||||
return &execMeasuredArtifact{*checksum, hostNet, a}
|
return &execNetArtifact{*checksum, a}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kind returns the hardcoded [Kind] constant.
|
// Kind returns the hardcoded [Kind] constant.
|
||||||
@@ -259,7 +211,6 @@ func (*execArtifact) Kind() Kind { return KindExec }
|
|||||||
|
|
||||||
// Params writes paths, executable pathname and args.
|
// Params writes paths, executable pathname and args.
|
||||||
func (a *execArtifact) Params(ctx *IContext) {
|
func (a *execArtifact) Params(ctx *IContext) {
|
||||||
ctx.WriteString(a.arch)
|
|
||||||
ctx.WriteString(a.name)
|
ctx.WriteString(a.name)
|
||||||
|
|
||||||
ctx.WriteUint32(uint32(len(a.paths)))
|
ctx.WriteUint32(uint32(len(a.paths)))
|
||||||
@@ -306,26 +257,11 @@ func (a *execArtifact) Params(ctx *IContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsupportedArchError describes an unsupported or invalid architecture.
|
|
||||||
type UnsupportedArchError string
|
|
||||||
|
|
||||||
func (e UnsupportedArchError) Error() string {
|
|
||||||
if e == "" {
|
|
||||||
return "invalid architecture name"
|
|
||||||
}
|
|
||||||
return "unsupported architecture " + string(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// readExecArtifact interprets IR values and returns the address of execArtifact
|
// readExecArtifact interprets IR values and returns the address of execArtifact
|
||||||
// or execNetArtifact.
|
// or execNetArtifact.
|
||||||
func readExecArtifact(r *IRReader, net bool) Artifact {
|
func readExecArtifact(r *IRReader, net bool) Artifact {
|
||||||
r.DiscardAll()
|
r.DiscardAll()
|
||||||
|
|
||||||
arch := r.ReadString()
|
|
||||||
if arch == "" {
|
|
||||||
panic(UnsupportedArchError(arch))
|
|
||||||
}
|
|
||||||
|
|
||||||
name := r.ReadString()
|
name := r.ReadString()
|
||||||
|
|
||||||
sz := r.ReadUint32()
|
sz := r.ReadUint32()
|
||||||
@@ -376,17 +312,22 @@ func readExecArtifact(r *IRReader, net bool) Artifact {
|
|||||||
exclusive := r.ReadUint32() != 0
|
exclusive := r.ReadUint32() != 0
|
||||||
|
|
||||||
checksum, ok := r.Finalise()
|
checksum, ok := r.Finalise()
|
||||||
var checksumP *Checksum
|
|
||||||
if ok {
|
|
||||||
checksumP = new(checksum.Value())
|
|
||||||
}
|
|
||||||
|
|
||||||
if net && !ok {
|
var checksumP *Checksum
|
||||||
|
if net {
|
||||||
|
if !ok {
|
||||||
panic(ErrExpectedChecksum)
|
panic(ErrExpectedChecksum)
|
||||||
}
|
}
|
||||||
|
checksumVal := checksum.Value()
|
||||||
|
checksumP = &checksumVal
|
||||||
|
} else {
|
||||||
|
if ok {
|
||||||
|
panic(ErrUnexpectedChecksum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NewExec(
|
return NewExec(
|
||||||
name, arch, checksumP, timeout, net, exclusive, dir, env, pathname, args, paths...,
|
name, checksumP, timeout, exclusive, dir, env, pathname, args, paths...,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,23 +436,11 @@ func (a *execArtifact) makeContainer(
|
|||||||
if z.HostNet {
|
if z.HostNet {
|
||||||
z.Hostname = "cure-net"
|
z.Hostname = "cure-net"
|
||||||
}
|
}
|
||||||
z.Quiet = flags&CSuppressInit != 0
|
|
||||||
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
|
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
|
||||||
z.Dir, z.Path, z.Args = a.dir, a.path, a.args
|
z.Dir, z.Path, z.Args = a.dir, a.path, a.args
|
||||||
z.Env = slices.Concat(a.env, []string{EnvJobs + "=" + strconv.Itoa(jobs)})
|
z.Env = slices.Concat(a.env, []string{EnvJobs + "=" + strconv.Itoa(jobs)})
|
||||||
z.Grow(len(a.paths) + 4)
|
z.Grow(len(a.paths) + 4)
|
||||||
|
|
||||||
if a.arch != runtime.GOARCH {
|
|
||||||
binfmtMu.RLock()
|
|
||||||
e, ok := binfmt[a.arch]
|
|
||||||
binfmtMu.RUnlock()
|
|
||||||
if !ok {
|
|
||||||
return nil, UnsupportedArchError(a.arch)
|
|
||||||
}
|
|
||||||
z.Binfmt = []container.BinfmtEntry{e}
|
|
||||||
z.InitAsRoot = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, b := range a.paths {
|
for i, b := range a.paths {
|
||||||
if i == overlayWorkIndex {
|
if i == overlayWorkIndex {
|
||||||
if err = os.MkdirAll(work.String(), 0700); err != nil {
|
if err = os.MkdirAll(work.String(), 0700); err != nil {
|
||||||
@@ -598,9 +527,9 @@ func (c *Cache) EnterExec(
|
|||||||
case *execArtifact:
|
case *execArtifact:
|
||||||
e = f
|
e = f
|
||||||
|
|
||||||
case *execMeasuredArtifact:
|
case *execNetArtifact:
|
||||||
e = &f.execArtifact
|
e = &f.execArtifact
|
||||||
hostNet = f.hostNet
|
hostNet = true
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ErrNotExec
|
return ErrNotExec
|
||||||
@@ -701,6 +630,12 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
|||||||
_ = stdout.Close()
|
_ = stdout.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
if err != nil && !errors.As(err, new(*exec.ExitError)) {
|
||||||
|
_ = stdout.Close()
|
||||||
|
_ = stderr.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
brStdout, brStderr := f.cache.getReader(stdout), f.cache.getReader(stderr)
|
brStdout, brStderr := f.cache.getReader(stdout), f.cache.getReader(stderr)
|
||||||
stdoutDone, stderrDone := make(chan struct{}), make(chan struct{})
|
stdoutDone, stderrDone := make(chan struct{}), make(chan struct{})
|
||||||
@@ -715,11 +650,6 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
|||||||
io.TeeReader(brStderr, status),
|
io.TeeReader(brStderr, status),
|
||||||
)
|
)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil && !errors.As(err, new(*exec.ExitError)) {
|
|
||||||
_ = stdout.Close()
|
|
||||||
_ = stderr.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
<-stdoutDone
|
<-stdoutDone
|
||||||
<-stderrDone
|
<-stderrDone
|
||||||
f.cache.putReader(brStdout)
|
f.cache.putReader(brStdout)
|
||||||
|
|||||||
+52
-299
@@ -1,70 +1,44 @@
|
|||||||
package pkg_test
|
package pkg_test
|
||||||
|
|
||||||
|
//go:generate env CGO_ENABLED=0 go build -tags testtool -o testdata/testtool ./testdata
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"errors"
|
"errors"
|
||||||
"io/fs"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
|
||||||
"slices"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
|
"unique"
|
||||||
|
|
||||||
"hakurei.app/check"
|
"hakurei.app/check"
|
||||||
"hakurei.app/container"
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal/info"
|
|
||||||
"hakurei.app/internal/pkg"
|
"hakurei.app/internal/pkg"
|
||||||
"hakurei.app/internal/stub"
|
"hakurei.app/internal/stub"
|
||||||
|
|
||||||
"hakurei.app/internal/pkg/internal/testtool/expected"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// testtoolBin is the container test tool binary made available to the
|
// testtoolBin is the container test tool binary made available to the
|
||||||
// execArtifact for testing its curing environment.
|
// execArtifact for testing its curing environment.
|
||||||
//
|
//
|
||||||
//go:generate env CGO_ENABLED=0 go build -tags testtool -o internal/testtool ./internal/testtool
|
//go:embed testdata/testtool
|
||||||
//go:embed internal/testtool/testtool
|
|
||||||
var testtoolBin []byte
|
var testtoolBin []byte
|
||||||
|
|
||||||
func init() {
|
|
||||||
pathname, err := filepath.Abs("internal/testtool/testtool")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
pkg.RegisterArch("cafe", container.BinfmtEntry{
|
|
||||||
Magic: expected.Magic,
|
|
||||||
Interpreter: check.MustAbs(pathname),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExec(t *testing.T) {
|
func TestExec(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
wantOffline := expectsFS{
|
wantChecksumOffline := pkg.MustDecode(
|
||||||
".": {Mode: fs.ModeDir | 0500},
|
"GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9",
|
||||||
|
)
|
||||||
"check": {Mode: 0400, Data: []byte{0}},
|
|
||||||
}
|
|
||||||
wantOfflineEncode := pkg.Encode(wantOffline.hash())
|
|
||||||
failingArtifact := &stubArtifact{
|
|
||||||
kind: pkg.KindTar,
|
|
||||||
params: []byte("doomed artifact"),
|
|
||||||
cure: func(t *pkg.TContext) error {
|
|
||||||
return stub.UniqueError(0xcafe)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
checkWithCache(t, []cacheTestCase{
|
checkWithCache(t, []cacheTestCase{
|
||||||
{"offline", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
{"offline", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
testtool, testtoolDestroy := newTesttool()
|
testtool, testtoolDestroy := newTesttool()
|
||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
"exec-offline", "", new(wantOffline.hash()), 0, false, false,
|
"exec-offline", nil, 0, false,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -84,128 +58,67 @@ func TestExec(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
pkg.MustPath("/opt", false, testtool),
|
pkg.MustPath("/opt", false, testtool),
|
||||||
), ignorePathname, wantOffline, nil},
|
), ignorePathname, wantChecksumOffline, nil},
|
||||||
|
|
||||||
{"substitution", pkg.NewExec(
|
|
||||||
"exec-offline", "", new(wantOffline.hash()), 0, false, false,
|
|
||||||
pkg.AbsWork,
|
|
||||||
[]string{"HAKUREI_TEST=1"},
|
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
|
||||||
[]string{"testtool"},
|
|
||||||
|
|
||||||
pkg.MustPath("/file", false, newStubFile(
|
|
||||||
pkg.KindHTTPGet,
|
|
||||||
pkg.ID{0xfe, 0},
|
|
||||||
nil,
|
|
||||||
nil, nil,
|
|
||||||
)),
|
|
||||||
// substitution miss fails in testtool due to differing idents
|
|
||||||
pkg.MustPath("/.hakurei", false, &stubArtifact{
|
|
||||||
kind: pkg.KindTar,
|
|
||||||
params: []byte("empty directory (substituted)"),
|
|
||||||
cure: func(t *pkg.TContext) error {
|
|
||||||
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
pkg.MustPath("/opt", false, testtool),
|
|
||||||
), ignorePathname, wantOffline, nil},
|
|
||||||
|
|
||||||
{"error passthrough", pkg.NewExec(
|
{"error passthrough", pkg.NewExec(
|
||||||
"", "", nil, 0, false, true,
|
"", nil, 0, true,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
|
|
||||||
pkg.MustPath("/proc/nonexistent", false, failingArtifact),
|
pkg.MustPath("/proc/nonexistent", false, &stubArtifact{
|
||||||
), nil, nil, &pkg.DependencyCureError{
|
kind: pkg.KindTar,
|
||||||
|
params: []byte("doomed artifact"),
|
||||||
|
cure: func(t *pkg.TContext) error {
|
||||||
|
return stub.UniqueError(0xcafe)
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
), nil, pkg.Checksum{}, &pkg.DependencyCureError{
|
||||||
{
|
{
|
||||||
A: failingArtifact,
|
Ident: unique.Make(pkg.ID(pkg.MustDecode(
|
||||||
|
"Sowo6oZRmG6xVtUaxB6bDWZhVsqAJsIJWUp0OPKlE103cY0lodx7dem8J-qQF0Z1",
|
||||||
|
))),
|
||||||
Err: stub.UniqueError(0xcafe),
|
Err: stub.UniqueError(0xcafe),
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
|
|
||||||
{"invalid paths", pkg.NewExec(
|
{"invalid paths", pkg.NewExec(
|
||||||
"", "", nil, 0, false, false,
|
"", nil, 0, false,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
|
|
||||||
pkg.ExecPath{},
|
pkg.ExecPath{},
|
||||||
), nil, nil, pkg.ErrInvalidPaths},
|
), nil, pkg.Checksum{}, pkg.ErrInvalidPaths},
|
||||||
})
|
})
|
||||||
|
|
||||||
// check init failure passthrough
|
// check init failure passthrough
|
||||||
initFailureArtifact := pkg.NewExec(
|
var exitError *exec.ExitError
|
||||||
"", "", nil, 0, false, false,
|
if _, _, err := c.Cure(pkg.NewExec(
|
||||||
|
"", nil, 0, false,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
nil,
|
nil,
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
)
|
)); !errors.As(err, &exitError) ||
|
||||||
var exitError *exec.ExitError
|
|
||||||
if _, _, err := c.Cure(initFailureArtifact); !errors.As(err, &exitError) ||
|
|
||||||
exitError.ExitCode() != hst.ExitFailure {
|
exitError.ExitCode() != hst.ExitFailure {
|
||||||
t.Fatalf("Cure: error = %v, want init exit status 1", err)
|
t.Fatalf("Cure: error = %v, want init exit status 1", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var faultStatus []byte
|
|
||||||
if faults, err := c.ReadFaults(initFailureArtifact); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
} else if len(faults) != 1 {
|
|
||||||
t.Fatalf("ReadFaults: %v", faults)
|
|
||||||
} else if faultStatus, err = os.ReadFile(faults[0].String()); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
} else if err = faults[0].Destroy(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
} else {
|
|
||||||
t.Logf("destroyed expected fault at %s", faults[0].Time().UTC())
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.HasPrefix(faultStatus, []byte(
|
|
||||||
"internal/pkg ",
|
|
||||||
)) || !bytes.Contains(faultStatus, []byte(
|
|
||||||
"\ninit: fork/exec /opt/bin/testtool: no such file or directory\n",
|
|
||||||
)) {
|
|
||||||
t.Errorf("unexpected status:\n%s", string(faultStatus))
|
|
||||||
}
|
|
||||||
|
|
||||||
destroyStatus(t, base, 2, 1)
|
|
||||||
testtoolDestroy(t, base, c)
|
testtoolDestroy(t, base, c)
|
||||||
}, expectsFS{
|
}, pkg.MustDecode("Q5DluWQCAeohLoiGRImurwFp3vdz9IfQCoj7Fuhh73s4KQPRHpEQEnHTdNHmB8Fx")},
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
{"net", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
"checksum/" + wantOfflineEncode: {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantOfflineEncode + "/check": {Mode: 0400, Data: []byte{0}},
|
|
||||||
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/QwS7SmiatdqryQYgESdGw7Yw2PcpNf0vNfpvUA0t92BTlKiUjfCrXyMW17G2X77X": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
|
||||||
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
|
||||||
"identifier/" + expected.Offline: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
|
||||||
"identifier/" + expected.OfflineS: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
|
||||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"temp": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"net", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
||||||
testtool, testtoolDestroy := newTesttool()
|
testtool, testtoolDestroy := newTesttool()
|
||||||
|
|
||||||
wantNet := expectsFS{
|
wantChecksum := pkg.MustDecode(
|
||||||
".": {Mode: fs.ModeDir | 0500},
|
"a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W",
|
||||||
|
)
|
||||||
"check": {Mode: 0400, Data: []byte("net")},
|
|
||||||
}
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
"exec-net", "", new(wantNet.hash()), 0, true, false,
|
"exec-net", &wantChecksum, 0, false,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -225,37 +138,18 @@ func TestExec(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
pkg.MustPath("/opt", false, testtool),
|
pkg.MustPath("/opt", false, testtool),
|
||||||
), ignorePathname, wantNet, nil},
|
), ignorePathname, wantChecksum, nil},
|
||||||
})
|
})
|
||||||
|
|
||||||
destroyStatus(t, base, 2, 0)
|
|
||||||
testtoolDestroy(t, base, c)
|
testtoolDestroy(t, base, c)
|
||||||
}, expectsFS{
|
}, pkg.MustDecode("bPYvvqxpfV7xcC1EptqyKNK1klLJgYHMDkzBcoOyK6j_Aj5hb0mXNPwTwPSK5F6Z")},
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
{"overlay root", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}},
|
|
||||||
"checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W/check": {Mode: 0400, Data: []byte("net")},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/" + expected.Net: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W")},
|
|
||||||
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
|
||||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"temp": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"overlay root", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
||||||
testtool, testtoolDestroy := newTesttool()
|
testtool, testtoolDestroy := newTesttool()
|
||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
"exec-overlay-root", "", nil, 0, false, false,
|
"exec-overlay-root", nil, 0, false,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -269,35 +163,18 @@ func TestExec(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
pkg.MustPath("/opt", false, testtool),
|
pkg.MustPath("/opt", false, testtool),
|
||||||
), ignorePathname, wantOffline, nil},
|
), ignorePathname, wantChecksumOffline, nil},
|
||||||
})
|
})
|
||||||
|
|
||||||
destroyStatus(t, base, 2, 0)
|
|
||||||
testtoolDestroy(t, base, c)
|
testtoolDestroy(t, base, c)
|
||||||
}, expectsFS{
|
}, pkg.MustDecode("PO2DSSCa4yoSgEYRcCSZfQfwow1yRigL3Ry-hI0RDI4aGuFBha-EfXeSJnG_5_Rl")},
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
{"overlay work", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
"checksum/" + wantOfflineEncode: {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantOfflineEncode + "/check": {Mode: 0400, Data: []byte{0}},
|
|
||||||
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/" + expected.OvlRoot: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
|
||||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"temp": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"overlay work", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
||||||
testtool, testtoolDestroy := newTesttool()
|
testtool, testtoolDestroy := newTesttool()
|
||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
"exec-overlay-work", "", nil, 0, false, false,
|
"exec-overlay-work", nil, 0, false,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
||||||
check.MustAbs("/work/bin/testtool"),
|
check.MustAbs("/work/bin/testtool"),
|
||||||
@@ -316,35 +193,18 @@ func TestExec(t *testing.T) {
|
|||||||
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
||||||
},
|
},
|
||||||
}), pkg.Path(pkg.AbsWork, false /* ignored */, testtool),
|
}), pkg.Path(pkg.AbsWork, false /* ignored */, testtool),
|
||||||
), ignorePathname, wantOffline, nil},
|
), ignorePathname, wantChecksumOffline, nil},
|
||||||
})
|
})
|
||||||
|
|
||||||
destroyStatus(t, base, 2, 0)
|
|
||||||
testtoolDestroy(t, base, c)
|
testtoolDestroy(t, base, c)
|
||||||
}, expectsFS{
|
}, pkg.MustDecode("iaRt6l_Wm2n-h5UsDewZxQkCmjZjyL8r7wv32QT2kyV55-Lx09Dq4gfg9BiwPnKs")},
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
{"multiple layers", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
"checksum/" + wantOfflineEncode: {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantOfflineEncode + "/check": {Mode: 0400, Data: []byte{0}},
|
|
||||||
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/" + expected.Work: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
|
||||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"temp": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"multiple layers", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
||||||
testtool, testtoolDestroy := newTesttool()
|
testtool, testtoolDestroy := newTesttool()
|
||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
"exec-multiple-layers", "", nil, 0, false, false,
|
"exec-multiple-layers", nil, 0, false,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -385,40 +245,18 @@ func TestExec(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
pkg.MustPath("/opt", false, testtool),
|
pkg.MustPath("/opt", false, testtool),
|
||||||
), ignorePathname, wantOffline, nil},
|
), ignorePathname, wantChecksumOffline, nil},
|
||||||
})
|
})
|
||||||
|
|
||||||
destroyStatus(t, base, 2, 0)
|
|
||||||
testtoolDestroy(t, base, c)
|
testtoolDestroy(t, base, c)
|
||||||
}, expectsFS{
|
}, pkg.MustDecode("O2YzyR7IUGU5J2CADy0hUZ3A5NkP_Vwzs4UadEdn2oMZZVWRtH0xZGJ3HXiimTnZ")},
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
{"overlay layer promotion", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
"checksum/" + wantOfflineEncode: {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantOfflineEncode + "/check": {Mode: 0400, Data: []byte{0}},
|
|
||||||
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}},
|
|
||||||
"checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK/check": {Mode: 0400, Data: []byte("layers")},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")},
|
|
||||||
"identifier/B-kc5iJMx8GtlCua4dz6BiJHnDAOUfPjgpbKq4e-QEn0_CZkSYs3fOA1ve06qMs2": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK")},
|
|
||||||
"identifier/" + expected.Layers: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
|
||||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"temp": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"overlay layer promotion", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
||||||
testtool, testtoolDestroy := newTesttool()
|
testtool, testtoolDestroy := newTesttool()
|
||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"container", pkg.NewExec(
|
{"container", pkg.NewExec(
|
||||||
"exec-layer-promotion", "", nil, 0, false, true,
|
"exec-layer-promotion", nil, 0, true,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -438,96 +276,11 @@ func TestExec(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
pkg.MustPath("/opt", false, testtool),
|
pkg.MustPath("/opt", false, testtool),
|
||||||
), ignorePathname, wantOffline, nil},
|
), ignorePathname, wantChecksumOffline, nil},
|
||||||
})
|
})
|
||||||
|
|
||||||
destroyStatus(t, base, 2, 0)
|
|
||||||
testtoolDestroy(t, base, c)
|
testtoolDestroy(t, base, c)
|
||||||
}, expectsFS{
|
}, pkg.MustDecode("3EaW6WibLi9gl03_UieiFPaFcPy5p4x3JPxrnLJxGaTI-bh3HU9DK9IMx7c3rrNm")},
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
|
||||||
"checksum/" + wantOfflineEncode: {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantOfflineEncode + "/check": {Mode: 0400, Data: []byte{0}},
|
|
||||||
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/kvJIqZo5DKFOxC2ZQ-8_nPaQzEAz9cIm3p6guO-uLqm-xaiPu7oRkSnsu411jd_U": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
|
||||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
|
||||||
"identifier/" + expected.Promote: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"temp": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"binfmt", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
||||||
if info.CanDegrade && os.Getenv("ROSA_SKIP_BINFMT") != "" {
|
|
||||||
t.Skip("binfmt_misc test explicitly skipped")
|
|
||||||
}
|
|
||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
|
||||||
{"container", pkg.NewExec(
|
|
||||||
"exec-binfmt", "cafe", nil, 0, false, true,
|
|
||||||
pkg.AbsWork,
|
|
||||||
[]string{"HAKUREI_TEST=1", "HAKUREI_BINFMT=1"},
|
|
||||||
check.MustAbs("/opt/bin/sample"),
|
|
||||||
[]string{"sample"},
|
|
||||||
|
|
||||||
pkg.MustPath("/", true, &stubArtifact{
|
|
||||||
kind: pkg.KindTar,
|
|
||||||
params: []byte("empty directory"),
|
|
||||||
cure: func(t *pkg.TContext) error {
|
|
||||||
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
pkg.MustPath("/opt", false, overrideIdent{pkg.ID{0xfe, 0xff}, &stubArtifact{
|
|
||||||
kind: pkg.KindTar,
|
|
||||||
cure: func(t *pkg.TContext) error {
|
|
||||||
work := t.GetWorkDir()
|
|
||||||
if err := os.MkdirAll(
|
|
||||||
work.Append("bin").String(),
|
|
||||||
0700,
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.WriteFile(t.GetWorkDir().Append(
|
|
||||||
"bin",
|
|
||||||
"sample",
|
|
||||||
).String(), []byte(expected.Full), 0500)
|
|
||||||
},
|
|
||||||
}}),
|
|
||||||
), ignorePathname, expectsFS{
|
|
||||||
".": {Mode: fs.ModeDir | 0500},
|
|
||||||
|
|
||||||
"check": {Mode: 0400, Data: []byte("binfmt")},
|
|
||||||
}, nil},
|
|
||||||
})
|
|
||||||
|
|
||||||
destroyStatus(t, base, 2, 0)
|
|
||||||
}, expectsFS{
|
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
|
||||||
"checksum/5aevg3YpDxjqQZ-pdvXK7YqgkL5JKqcoStYQxeD96kuYar6K2mRQWMHib6NQRnpV": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/5aevg3YpDxjqQZ-pdvXK7YqgkL5JKqcoStYQxeD96kuYar6K2mRQWMHib6NQRnpV/bin": {Mode: fs.ModeDir | 0700},
|
|
||||||
"checksum/5aevg3YpDxjqQZ-pdvXK7YqgkL5JKqcoStYQxeD96kuYar6K2mRQWMHib6NQRnpV/bin/sample": {Mode: 0500, Data: []byte("\xca\xfe\xba\xbe\xfd\xfd:3")},
|
|
||||||
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/UnDo4B5KneEUY5b4vRUk_y9MWgkWuw2N8f8a2XayO686xXur-aZmX2-7n_8tKMe3": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/UnDo4B5KneEUY5b4vRUk_y9MWgkWuw2N8f8a2XayO686xXur-aZmX2-7n_8tKMe3/check": {Mode: 0400, Data: []byte("binfmt")},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/6VQTJ1lI5BmVuI1YFYJ8ClO3MRORvTTrcWFDcUU-l5Ga8EofxCxGlSTYN-u8dKj_": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/UnDo4B5KneEUY5b4vRUk_y9MWgkWuw2N8f8a2XayO686xXur-aZmX2-7n_8tKMe3")},
|
|
||||||
"identifier/_v8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/5aevg3YpDxjqQZ-pdvXK7YqgkL5JKqcoStYQxeD96kuYar6K2mRQWMHib6NQRnpV")},
|
|
||||||
"identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"temp": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package pkg_test
|
package pkg_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/check"
|
"hakurei.app/check"
|
||||||
@@ -11,27 +10,18 @@ import (
|
|||||||
func TestFile(t *testing.T) {
|
func TestFile(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
want := expectsFile{0}
|
|
||||||
checkWithCache(t, []cacheTestCase{
|
checkWithCache(t, []cacheTestCase{
|
||||||
{"file", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
{"file", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"short", pkg.NewFile("null", []byte{0}), base.Append(
|
{"short", pkg.NewFile("null", []byte{0}), base.Append(
|
||||||
"identifier",
|
"identifier",
|
||||||
"3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi",
|
"3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi",
|
||||||
), want, nil},
|
), pkg.MustDecode(
|
||||||
|
"vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX",
|
||||||
|
), nil},
|
||||||
})
|
})
|
||||||
}, expectsFS{
|
}, pkg.MustDecode(
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
"iR6H5OIsyOW4EwEgtm9rGzGF6DVtyHLySEtwnFE8bnus9VJcoCbR4JIek7Lw-vwT",
|
||||||
|
)},
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
|
||||||
"checksum/" + pkg.Encode(want.hash()): {Mode: 0400, Data: []byte{0}},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX")},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
// Package expected contains data shared between test helper and test harness.
|
|
||||||
package expected
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Magic are magic bytes in the binfmt test case.
|
|
||||||
Magic = "\xca\xfe\xba\xbe\xfd\xfd"
|
|
||||||
// Full is the full content of the binfmt test case executable.
|
|
||||||
Full = Magic + ":3"
|
|
||||||
)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package expected
|
|
||||||
|
|
||||||
const (
|
|
||||||
Offline = "q5ktDTq0miP-VvB2blxqXQeaRXCUWgP_KbC18KNtUDtyoaI_h5mHmGuPMArVEBDs"
|
|
||||||
OfflineS = "IY91PCtOpCYy21AaIK0c9f8-Z6fb2_2ewoHWkt4dxoLf0GOrWqS8yAGFLV84b1Dw"
|
|
||||||
OvlRoot = "NacZGXwuRkTvcHaG08a22ujJ8qCWN0RSoFlRSR5FSt0ZcBbJ28FRvkYsHEtX7G8i"
|
|
||||||
Layers = "WBJDrATtX6rIE5yAu8ePX3WmDF0Tt9kFiue0m3cRnyRoVx1my8a67fh3CAW486oP"
|
|
||||||
Net = "CmYtj2sNB3LHtqiDuck_Lz3MjLLIiwyP8N4NDitQ1Icvv__LVP9p8tm-sHeQaKKp"
|
|
||||||
Promote = "TX3eCloaQFkV-SZIH6Jg6E5WKH--rcXY1P0jnZKmLFKWrNqnOzd4G9eIBh6i5ywN"
|
|
||||||
Work = "OuNiLSC68pZhAOr1YQ4WbV1tzASA0nxLEBcK7lO7MqxDY_j8dmP_C612RTuF23Lu"
|
|
||||||
)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package expected
|
|
||||||
|
|
||||||
const (
|
|
||||||
Offline = "WapqyoPxbWSnq07dWHt71mHaJXq99pAjJfFlELlJljSiZMhTFqqlzU1_mN86shSj"
|
|
||||||
OfflineS = "ibQZHcdXgNQ1OiMX1FrburBbGPVvKEHvPilbQCkm_0oV0BQCHomyyTbYNrFMGIwl"
|
|
||||||
OvlRoot = "V9anFOiRvjGfAeBhLl14AL8TKdWZyD0WTPYe4fS9mOBw8iW5Lmarvt6TG6MV8uWm"
|
|
||||||
Layers = "tKx7JNRoSBdK_7MdzI-nwTNV2wmiPzwYdcd17oLmXKL_iLmUzUiA79qTqdrTasrv"
|
|
||||||
Net = "aXyDLzBCJ9XltXZIfetEVsEkrqHfcXuD5XE_FcUnYbN3emwL55N6P8LlHzNfGnM5"
|
|
||||||
Promote = "3k4V16n96Lq04gjFSKmm4sFjyQ883FFBNXgTy9s_DjeTwxT3pg_iacEh8yMb_S4m"
|
|
||||||
Work = "6Q49MhFWRE3Ne6MycwAotgl1GtoU5WCHqJNWG2byYZCY-zX-IxPrWiKk7bKkNzhE"
|
|
||||||
)
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package expected
|
|
||||||
|
|
||||||
const (
|
|
||||||
Offline = "Z6yXE5gOJScL3srmnVMWgCXccDiUNZ5snSrf6RkXuU1_U0rX_kGVwsfHUgNG_awd"
|
|
||||||
OfflineS = "zN16xv6LKRJRipUJwupyxg2rZcvf-qpsMn_qCxUmgxlTSuNwYI70ZEb7dHW5k0gO"
|
|
||||||
OvlRoot = "zYXJHFRLuxvUhuisZEXgGgVvdQd6piMfp5jmtT6jdVjvC2gICXquOq-UTwlrSD5I"
|
|
||||||
Layers = "_F8EDazHbcLeT0sVSQXRN_kn9IjduqJcDYgzXpsT-hpKU4EBcZ0PISN2zchpqMbm"
|
|
||||||
Net = "CA_FAaSIYJgapBEHV40doxpH23PdUEy_6s1TZc7wfSPN0XYqwGpMceXXDSabGveO"
|
|
||||||
Promote = "_3LPrLp--4h9k4GsNNApu9hHtAafq-GUhfU6d4hJKBDKT3bz_szOsvkXxc5sK53d"
|
|
||||||
Work = "FEgHeiCD_WT4wsfB-9kDH5n6cRWCEYtJmXdKZgmUUukAOoXumH_hLlosXREC-tqq"
|
|
||||||
)
|
|
||||||
+1
-43
@@ -76,9 +76,6 @@ type IContext struct {
|
|||||||
// Written to by various methods, should be zeroed after [Artifact.Params]
|
// Written to by various methods, should be zeroed after [Artifact.Params]
|
||||||
// returns and must not be exposed directly.
|
// returns and must not be exposed directly.
|
||||||
w io.Writer
|
w io.Writer
|
||||||
// Optional [Artifact] to cureRes cache, replaces [IRKindIdent] with
|
|
||||||
// checksum values if non-nil.
|
|
||||||
inputs map[Artifact]cureRes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// irZero is a zero IR word.
|
// irZero is a zero IR word.
|
||||||
@@ -166,15 +163,7 @@ func (i *IContext) WriteIdent(a Artifact) {
|
|||||||
defer i.ic.putIdentBuf(buf)
|
defer i.ic.putIdentBuf(buf)
|
||||||
|
|
||||||
IRKindIdent.encodeHeader(0).put(buf[:])
|
IRKindIdent.encodeHeader(0).put(buf[:])
|
||||||
if i.inputs != nil {
|
|
||||||
res, ok := i.inputs[a]
|
|
||||||
if !ok {
|
|
||||||
panic(InvalidLookupError(i.ic.Ident(a).Value()))
|
|
||||||
}
|
|
||||||
*(*ID)(buf[wordSize:]) = res.checksum.Value()
|
|
||||||
} else {
|
|
||||||
*(*ID)(buf[wordSize:]) = i.ic.Ident(a).Value()
|
*(*ID)(buf[wordSize:]) = i.ic.Ident(a).Value()
|
||||||
}
|
|
||||||
i.mustWrite(buf[:])
|
i.mustWrite(buf[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,19 +207,8 @@ func (i *IContext) WriteString(s string) {
|
|||||||
// Encode writes a deterministic, efficient representation of a to w and returns
|
// Encode writes a deterministic, efficient representation of a to w and returns
|
||||||
// the first non-nil error encountered while writing to w.
|
// the first non-nil error encountered while writing to w.
|
||||||
func (ic *irCache) Encode(w io.Writer, a Artifact) (err error) {
|
func (ic *irCache) Encode(w io.Writer, a Artifact) (err error) {
|
||||||
return ic.encode(w, a, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode implements Encode but replaces identifiers with their cured checksums
|
|
||||||
// for a non-nil ident. Caller must acquire Cache.identMu.
|
|
||||||
func (ic *irCache) encode(
|
|
||||||
w io.Writer,
|
|
||||||
a Artifact,
|
|
||||||
inputs map[Artifact]cureRes,
|
|
||||||
) (err error) {
|
|
||||||
deps := a.Dependencies()
|
deps := a.Dependencies()
|
||||||
idents := make([]*extIdent, len(deps))
|
idents := make([]*extIdent, len(deps))
|
||||||
if inputs == nil {
|
|
||||||
for i, d := range deps {
|
for i, d := range deps {
|
||||||
dbuf, did := ic.unsafeIdent(d, true)
|
dbuf, did := ic.unsafeIdent(d, true)
|
||||||
if dbuf == nil {
|
if dbuf == nil {
|
||||||
@@ -243,20 +221,6 @@ func (ic *irCache) encode(
|
|||||||
defer ic.putIdentBuf(dbuf)
|
defer ic.putIdentBuf(dbuf)
|
||||||
idents[i] = dbuf
|
idents[i] = dbuf
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for i, d := range deps {
|
|
||||||
res, ok := inputs[d]
|
|
||||||
if !ok {
|
|
||||||
return InvalidLookupError(ic.Ident(d).Value())
|
|
||||||
}
|
|
||||||
|
|
||||||
dbuf := ic.getIdentBuf()
|
|
||||||
binary.LittleEndian.PutUint64(dbuf[:], uint64(d.Kind()))
|
|
||||||
*(*ID)(dbuf[wordSize:]) = res.checksum.Value()
|
|
||||||
defer ic.putIdentBuf(dbuf)
|
|
||||||
idents[i] = dbuf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
slices.SortFunc(idents, func(a, b *extIdent) int {
|
slices.SortFunc(idents, func(a, b *extIdent) int {
|
||||||
return bytes.Compare(a[:], b[:])
|
return bytes.Compare(a[:], b[:])
|
||||||
})
|
})
|
||||||
@@ -280,7 +244,7 @@ func (ic *irCache) encode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func() {
|
func() {
|
||||||
i := IContext{ic, w, inputs}
|
i := IContext{ic, w}
|
||||||
|
|
||||||
defer panicToError(&err)
|
defer panicToError(&err)
|
||||||
defer func() { i.ic, i.w = nil, nil }()
|
defer func() { i.ic, i.w = nil, nil }()
|
||||||
@@ -468,12 +432,6 @@ func (e InvalidKindError) Error() string {
|
|||||||
// register is not safe for concurrent use. register must not be called after
|
// register is not safe for concurrent use. register must not be called after
|
||||||
// the first instance of [Cache] has been opened.
|
// the first instance of [Cache] has been opened.
|
||||||
func register(k Kind, f IRReadFunc) {
|
func register(k Kind, f IRReadFunc) {
|
||||||
openMu.Lock()
|
|
||||||
defer openMu.Unlock()
|
|
||||||
|
|
||||||
if opened {
|
|
||||||
panic("attempting to register after open")
|
|
||||||
}
|
|
||||||
if _, ok := irArtifact[k]; ok {
|
if _, ok := irArtifact[k]; ok {
|
||||||
panic("attempting to register " + strconv.Itoa(int(k)) + " twice")
|
panic("attempting to register " + strconv.Itoa(int(k)) + " twice")
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-33
@@ -3,7 +3,6 @@ package pkg_test
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@ func TestIRRoundtrip(t *testing.T) {
|
|||||||
)},
|
)},
|
||||||
|
|
||||||
{"exec offline", pkg.NewExec(
|
{"exec offline", pkg.NewExec(
|
||||||
"exec-offline", "", nil, 0, false, false,
|
"exec-offline", nil, 0, false,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -59,9 +58,9 @@ func TestIRRoundtrip(t *testing.T) {
|
|||||||
)},
|
)},
|
||||||
|
|
||||||
{"exec net", pkg.NewExec(
|
{"exec net", pkg.NewExec(
|
||||||
"exec-net", "",
|
"exec-net",
|
||||||
(*pkg.Checksum)(bytes.Repeat([]byte{0xfc}, len(pkg.Checksum{}))),
|
(*pkg.Checksum)(bytes.Repeat([]byte{0xfc}, len(pkg.Checksum{}))),
|
||||||
0, false, false,
|
0, false,
|
||||||
pkg.AbsWork,
|
pkg.AbsWork,
|
||||||
[]string{"HAKUREI_TEST=1"},
|
[]string{"HAKUREI_TEST=1"},
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
@@ -80,28 +79,6 @@ func TestIRRoundtrip(t *testing.T) {
|
|||||||
)),
|
)),
|
||||||
)},
|
)},
|
||||||
|
|
||||||
{"exec measured", pkg.NewExec(
|
|
||||||
"exec-measured", "",
|
|
||||||
(*pkg.Checksum)(bytes.Repeat([]byte{0xfd}, len(pkg.Checksum{}))),
|
|
||||||
0, false, false,
|
|
||||||
pkg.AbsWork,
|
|
||||||
[]string{"HAKUREI_TEST=1"},
|
|
||||||
check.MustAbs("/opt/bin/testtool"),
|
|
||||||
[]string{"testtool", "measured"},
|
|
||||||
|
|
||||||
pkg.MustPath("/file", false, pkg.NewFile("file", []byte(
|
|
||||||
"stub file",
|
|
||||||
))), pkg.MustPath("/.hakurei", false, pkg.NewHTTPGetTar(
|
|
||||||
nil, "file:///hakurei.tar",
|
|
||||||
pkg.Checksum(bytes.Repeat([]byte{0xfd}, len(pkg.Checksum{}))),
|
|
||||||
pkg.TarUncompressed,
|
|
||||||
)), pkg.MustPath("/opt", false, pkg.NewHTTPGetTar(
|
|
||||||
nil, "file:///testtool.tar.gz",
|
|
||||||
pkg.Checksum(bytes.Repeat([]byte{0xfd}, len(pkg.Checksum{}))),
|
|
||||||
pkg.TarGzip,
|
|
||||||
)),
|
|
||||||
)},
|
|
||||||
|
|
||||||
{"file anonymous", pkg.NewFile("", []byte{0})},
|
{"file anonymous", pkg.NewFile("", []byte{0})},
|
||||||
{"file", pkg.NewFile("stub", []byte("stub"))},
|
{"file", pkg.NewFile("stub", []byte("stub"))},
|
||||||
}
|
}
|
||||||
@@ -128,13 +105,9 @@ func TestIRRoundtrip(t *testing.T) {
|
|||||||
if err := <-done; err != nil {
|
if err := <-done; err != nil {
|
||||||
t.Fatalf("EncodeAll: error = %v", err)
|
t.Fatalf("EncodeAll: error = %v", err)
|
||||||
}
|
}
|
||||||
}, expectsFS{
|
}, pkg.MustDecode(
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
"E4vEZKhCcL2gPZ2Tt59FS3lDng-d_2SKa2i5G_RbDfwGn6EemptFaGLPUDiOa94C",
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
),
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkWithCache(t, testCasesCache)
|
checkWithCache(t, testCasesCache)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package pkg_test
|
|||||||
import (
|
import (
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -86,13 +85,7 @@ func TestHTTPGet(t *testing.T) {
|
|||||||
if _, err := f.Cure(r); !reflect.DeepEqual(err, wantErrNotFound) {
|
if _, err := f.Cure(r); !reflect.DeepEqual(err, wantErrNotFound) {
|
||||||
t.Fatalf("Cure: error = %#v, want %#v", err, wantErrNotFound)
|
t.Fatalf("Cure: error = %#v, want %#v", err, wantErrNotFound)
|
||||||
}
|
}
|
||||||
}, expectsFS{
|
}, pkg.MustDecode("E4vEZKhCcL2gPZ2Tt59FS3lDng-d_2SKa2i5G_RbDfwGn6EemptFaGLPUDiOa94C")},
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"cure", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
{"cure", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
r := newRContext(t, c)
|
r := newRContext(t, c)
|
||||||
@@ -151,18 +144,6 @@ func TestHTTPGet(t *testing.T) {
|
|||||||
if _, _, err := c.Cure(f); !reflect.DeepEqual(err, wantErrNotFound) {
|
if _, _, err := c.Cure(f); !reflect.DeepEqual(err, wantErrNotFound) {
|
||||||
t.Fatalf("Pathname: error = %#v, want %#v", err, wantErrNotFound)
|
t.Fatalf("Pathname: error = %#v, want %#v", err, wantErrNotFound)
|
||||||
}
|
}
|
||||||
}, expectsFS{
|
}, pkg.MustDecode("L_0RFHpr9JUS4Zp14rz2dESSRvfLzpvqsLhR1-YjQt8hYlmEdVl7vI3_-v8UNPKs")},
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
|
||||||
"checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU": {Mode: 0400, Data: []byte("\x7f\xe1\x69\xa2\xdd\x63\x96\x26\x83\x79\x61\x8b\xf0\x3f\xd5\x16\x9a\x39\x3a\xdb\xcf\xb1\xbc\x8d\x33\xff\x75\xee\x62\x56\xa9\xf0\x27\xac\x13\x94\x69")},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/oM-2pUlk-mOxK1t3aMWZer69UdOQlAXiAgMrpZ1476VoOqpYVP1aGFS9_HYy-D8_": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fLYGIMHgN1louE-JzITJZJo2SDniPu-IHBXubtvQWFO-hXnDVKNuscV7-zlyr5fU")},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-421
@@ -4,7 +4,6 @@ package pkg
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"cmp"
|
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
@@ -16,17 +15,14 @@ import (
|
|||||||
"io/fs"
|
"io/fs"
|
||||||
"maps"
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
"unique"
|
"unique"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
@@ -74,64 +70,6 @@ func MustDecode(s string) (checksum Checksum) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
// extension is a string uniquely identifying a set of custom [Artifact]
|
|
||||||
// implementations registered by calling [Register].
|
|
||||||
extension string
|
|
||||||
|
|
||||||
// openMu synchronises access to global state for initialisation.
|
|
||||||
openMu sync.Mutex
|
|
||||||
// opened is false if [Open] was never called.
|
|
||||||
opened bool
|
|
||||||
)
|
|
||||||
|
|
||||||
// Extension returns a string uniquely identifying the currently registered set
|
|
||||||
// of custom [Artifact], or the zero value if none was registered.
|
|
||||||
func Extension() string { return extension }
|
|
||||||
|
|
||||||
// ValidExtension returns whether s is valid for use in a call to SetExtension.
|
|
||||||
func ValidExtension(s string) bool {
|
|
||||||
if l := len(s); l == 0 || l > 128 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, v := range s {
|
|
||||||
if v < 'a' || v > 'z' {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrInvalidExtension is returned for a variant identification string for which
|
|
||||||
// [ValidExtension] returns false.
|
|
||||||
var ErrInvalidExtension = errors.New("invalid extension variant identification string")
|
|
||||||
|
|
||||||
// SetExtension sets the extension variant identification string. SetExtension
|
|
||||||
// must be called before [Open] if custom [Artifact] implementations had been
|
|
||||||
// recorded by calling [Register].
|
|
||||||
//
|
|
||||||
// The variant identification string must be between 1 and 128 bytes long and
|
|
||||||
// consists of only bytes between 'a' and 'z'.
|
|
||||||
//
|
|
||||||
// SetExtension is not safe for concurrent use. SetExtension is called at most
|
|
||||||
// once and must not be called after the first instance of Cache has been opened.
|
|
||||||
func SetExtension(s string) {
|
|
||||||
openMu.Lock()
|
|
||||||
defer openMu.Unlock()
|
|
||||||
|
|
||||||
if opened {
|
|
||||||
panic("attempting to set extension after open")
|
|
||||||
}
|
|
||||||
if extension != "" {
|
|
||||||
panic("attempting to set extension twice")
|
|
||||||
}
|
|
||||||
if !ValidExtension(s) {
|
|
||||||
panic(ErrInvalidExtension)
|
|
||||||
}
|
|
||||||
extension = s
|
|
||||||
statusHeader = makeStatusHeader(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// common holds elements and receives methods shared between different contexts.
|
// common holds elements and receives methods shared between different contexts.
|
||||||
type common struct {
|
type common struct {
|
||||||
// Context specific to this [Artifact]. The toplevel context in [Cache] must
|
// Context specific to this [Artifact]. The toplevel context in [Cache] must
|
||||||
@@ -164,27 +102,19 @@ type TContext struct {
|
|||||||
common
|
common
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeStatusHeader creates the header written to every status file. This should
|
// statusHeader is the header written to all status files in dirStatus.
|
||||||
// not be called directly, its result is stored in statusHeader and will not
|
var statusHeader = func() string {
|
||||||
// change after the first [Cache] is opened.
|
|
||||||
func makeStatusHeader(extension string) string {
|
|
||||||
s := programName
|
s := programName
|
||||||
if v := info.Version(); v != info.FallbackVersion {
|
if v := info.Version(); v != info.FallbackVersion {
|
||||||
s += " " + v
|
s += " " + v
|
||||||
}
|
}
|
||||||
if extension != "" {
|
|
||||||
s += " with " + extension + " extensions"
|
|
||||||
}
|
|
||||||
s += " (" + runtime.GOARCH + ")"
|
s += " (" + runtime.GOARCH + ")"
|
||||||
if name, err := os.Hostname(); err == nil {
|
if name, err := os.Hostname(); err == nil {
|
||||||
s += " on " + name
|
s += " on " + name
|
||||||
}
|
}
|
||||||
s += "\n\n"
|
s += "\n\n"
|
||||||
return s
|
return s
|
||||||
}
|
}()
|
||||||
|
|
||||||
// statusHeader is the header written to all status files in dirStatus.
|
|
||||||
var statusHeader = makeStatusHeader("")
|
|
||||||
|
|
||||||
// prepareStatus initialises the status file once.
|
// prepareStatus initialises the status file once.
|
||||||
func (t *TContext) prepareStatus() error {
|
func (t *TContext) prepareStatus() error {
|
||||||
@@ -250,14 +180,7 @@ func (t *TContext) destroy(errP *error) {
|
|||||||
*errP = errors.Join(*errP, err)
|
*errP = errors.Join(*errP, err)
|
||||||
}
|
}
|
||||||
if *errP != nil {
|
if *errP != nil {
|
||||||
*errP = errors.Join(*errP, os.Rename(
|
*errP = errors.Join(*errP, os.Remove(t.statusPath.String()))
|
||||||
t.statusPath.String(), t.cache.base.Append(
|
|
||||||
dirFault,
|
|
||||||
t.ids+"."+strconv.FormatUint(uint64(
|
|
||||||
time.Now().UnixNano(),
|
|
||||||
), 10),
|
|
||||||
).String(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
t.status = nil
|
t.status = nil
|
||||||
}
|
}
|
||||||
@@ -504,9 +427,6 @@ const (
|
|||||||
// KindFile is the kind of [Artifact] returned by [NewFile].
|
// KindFile is the kind of [Artifact] returned by [NewFile].
|
||||||
KindFile
|
KindFile
|
||||||
|
|
||||||
// _kindEnd is the total number of kinds and does not denote a kind.
|
|
||||||
_kindEnd
|
|
||||||
|
|
||||||
// KindCustomOffset is the first [Kind] value reserved for implementations
|
// KindCustomOffset is the first [Kind] value reserved for implementations
|
||||||
// not from this package.
|
// not from this package.
|
||||||
KindCustomOffset = 1 << 31
|
KindCustomOffset = 1 << 31
|
||||||
@@ -518,34 +438,30 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// fileLock is the lock file for exclusive access to the cache directory.
|
// fileLock is the file name appended to Cache.base for guaranteeing
|
||||||
|
// exclusive access to the cache directory.
|
||||||
fileLock = "lock"
|
fileLock = "lock"
|
||||||
// fileVariant is a file holding the variant identification string set by a
|
|
||||||
// prior call to [SetExtension].
|
|
||||||
fileVariant = "variant"
|
|
||||||
|
|
||||||
// dirSubstitute holds symlinks to artifacts by checksum, named after their
|
// dirIdentifier is the directory name appended to Cache.base for storing
|
||||||
// substitute identifier.
|
// artifacts named after their [ID].
|
||||||
dirSubstitute = "substitute"
|
|
||||||
// dirIdentifier holds symlinks to artifacts by checksum, named after their
|
|
||||||
// IR-based identifier.
|
|
||||||
dirIdentifier = "identifier"
|
dirIdentifier = "identifier"
|
||||||
// dirChecksum holds artifacts named after their [Checksum].
|
// dirChecksum is the directory name appended to Cache.base for storing
|
||||||
|
// artifacts named after their [Checksum].
|
||||||
dirChecksum = "checksum"
|
dirChecksum = "checksum"
|
||||||
// dirStatus holds artifact metadata and logs named after their IR-based
|
// dirStatus is the directory name appended to Cache.base for storing
|
||||||
// identifier. For [FloodArtifact], the same file is also available under
|
// artifact metadata and logs named after their [ID].
|
||||||
// its substitute identifier.
|
|
||||||
dirStatus = "status"
|
dirStatus = "status"
|
||||||
// dirFault holds status files of faulted cures.
|
|
||||||
dirFault = "fault"
|
|
||||||
|
|
||||||
// dirWork holds working pathnames set up during [Cache.Cure].
|
// dirWork is the directory name appended to Cache.base for working
|
||||||
|
// pathnames set up during [Cache.Cure].
|
||||||
dirWork = "work"
|
dirWork = "work"
|
||||||
// dirTemp holds scratch space allocated during [Cache.Cure].
|
// dirTemp is the directory name appended to Cache.base for scratch space
|
||||||
|
// pathnames allocated during [Cache.Cure].
|
||||||
dirTemp = "temp"
|
dirTemp = "temp"
|
||||||
|
|
||||||
// dirExecScratch is scratch space set up for the container started by
|
// dirExecScratch is the directory name appended to Cache.base for scratch
|
||||||
// [Cache.EnterExec]. Exclusivity via Cache.inExec.
|
// space setting up the container started by [Cache.EnterExec]. Exclusivity
|
||||||
|
// via Cache.inExec.
|
||||||
dirExecScratch = "scratch"
|
dirExecScratch = "scratch"
|
||||||
|
|
||||||
// checksumLinknamePrefix is prepended to the encoded [Checksum] value
|
// checksumLinknamePrefix is prepended to the encoded [Checksum] value
|
||||||
@@ -624,17 +540,6 @@ const (
|
|||||||
// impurity due to [KindExecNet] being [KnownChecksum]. This flag exists
|
// impurity due to [KindExecNet] being [KnownChecksum]. This flag exists
|
||||||
// to support kernels without Landlock LSM enabled.
|
// to support kernels without Landlock LSM enabled.
|
||||||
CHostAbstract
|
CHostAbstract
|
||||||
|
|
||||||
// CPromoteVariant allows [pkg.Open] to promote an unextended on-disk cache
|
|
||||||
// to the current extension variant. This is a one-way operation.
|
|
||||||
CPromoteVariant
|
|
||||||
|
|
||||||
// CSuppressInit arranges for verbose output of the container init to be
|
|
||||||
// suppressed regardless of [message.Msg] state.
|
|
||||||
CSuppressInit
|
|
||||||
|
|
||||||
// CIgnoreSubstitutes disables content-based dependency substitution.
|
|
||||||
CIgnoreSubstitutes
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// toplevel holds [context.WithCancel] over caller-supplied context, where all
|
// toplevel holds [context.WithCancel] over caller-supplied context, where all
|
||||||
@@ -690,11 +595,6 @@ type Cache struct {
|
|||||||
// Synchronises access to dirChecksum.
|
// Synchronises access to dirChecksum.
|
||||||
checksumMu sync.RWMutex
|
checksumMu sync.RWMutex
|
||||||
|
|
||||||
// Presence of an alternative in the cache. Keys are not valid identifiers
|
|
||||||
// and must not be used as such.
|
|
||||||
substitute map[unique.Handle[ID]]unique.Handle[Checksum]
|
|
||||||
// Synchronises access to substitute and corresponding filesystem entries.
|
|
||||||
substituteMu sync.RWMutex
|
|
||||||
// Identifier to content pair cache.
|
// Identifier to content pair cache.
|
||||||
ident map[unique.Handle[ID]]unique.Handle[Checksum]
|
ident map[unique.Handle[ID]]unique.Handle[Checksum]
|
||||||
// Identifier to error pair for unrecoverably faulted [Artifact].
|
// Identifier to error pair for unrecoverably faulted [Artifact].
|
||||||
@@ -905,14 +805,11 @@ func (c *Cache) Scrub(checks int) error {
|
|||||||
checks = runtime.NumCPU()
|
checks = runtime.NumCPU()
|
||||||
}
|
}
|
||||||
|
|
||||||
c.substituteMu.Lock()
|
|
||||||
defer c.substituteMu.Unlock()
|
|
||||||
c.identMu.Lock()
|
c.identMu.Lock()
|
||||||
defer c.identMu.Unlock()
|
defer c.identMu.Unlock()
|
||||||
c.checksumMu.Lock()
|
c.checksumMu.Lock()
|
||||||
defer c.checksumMu.Unlock()
|
defer c.checksumMu.Unlock()
|
||||||
|
|
||||||
c.substitute = make(map[unique.Handle[ID]]unique.Handle[Checksum])
|
|
||||||
c.ident = make(map[unique.Handle[ID]]unique.Handle[Checksum])
|
c.ident = make(map[unique.Handle[ID]]unique.Handle[Checksum])
|
||||||
c.identErr = make(map[unique.Handle[ID]]error)
|
c.identErr = make(map[unique.Handle[ID]]error)
|
||||||
c.artifact.Clear()
|
c.artifact.Clear()
|
||||||
@@ -1020,11 +917,7 @@ func (c *Cache) Scrub(checks int) error {
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, suffix := range []string{
|
dir = c.base.Append(dirIdentifier)
|
||||||
dirSubstitute,
|
|
||||||
dirIdentifier,
|
|
||||||
} {
|
|
||||||
dir = c.base.Append(suffix)
|
|
||||||
if entries, readdirErr := os.ReadDir(dir.String()); readdirErr != nil {
|
if entries, readdirErr := os.ReadDir(dir.String()); readdirErr != nil {
|
||||||
addErr(dir, readdirErr)
|
addErr(dir, readdirErr)
|
||||||
} else {
|
} else {
|
||||||
@@ -1066,7 +959,6 @@ func (c *Cache) Scrub(checks int) error {
|
|||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
dir = c.base.Append(dirStatus)
|
dir = c.base.Append(dirStatus)
|
||||||
if entries, readdirErr := os.ReadDir(dir.String()); readdirErr != nil {
|
if entries, readdirErr := os.ReadDir(dir.String()); readdirErr != nil {
|
||||||
@@ -1213,52 +1105,6 @@ func (c *Cache) finaliseIdent(
|
|||||||
close(done)
|
close(done)
|
||||||
}
|
}
|
||||||
|
|
||||||
// zeroChecksum is a zero [Checksum] handle, used for comparison only.
|
|
||||||
var zeroChecksum unique.Handle[Checksum]
|
|
||||||
|
|
||||||
// loadSubstitute returns a checksum corresponding to a substitute identifier,
|
|
||||||
// or zeroChecksum if an alternative is not available.
|
|
||||||
func (c *Cache) loadSubstitute(
|
|
||||||
substitute unique.Handle[ID],
|
|
||||||
) (unique.Handle[Checksum], error) {
|
|
||||||
c.substituteMu.RLock()
|
|
||||||
if checksum, ok := c.substitute[substitute]; ok {
|
|
||||||
c.substituteMu.RUnlock()
|
|
||||||
return checksum, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
linkname, err := os.Readlink(c.base.Append(
|
|
||||||
dirSubstitute,
|
|
||||||
Encode(substitute.Value()),
|
|
||||||
).String())
|
|
||||||
c.substituteMu.RUnlock()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
|
||||||
return zeroChecksum, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.substituteMu.Lock()
|
|
||||||
c.substitute[substitute] = zeroChecksum
|
|
||||||
c.substituteMu.Unlock()
|
|
||||||
return zeroChecksum, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var checksum unique.Handle[Checksum]
|
|
||||||
buf := c.getIdentBuf()
|
|
||||||
err = Decode((*Checksum)(buf[:]), filepath.Base(linkname))
|
|
||||||
if err == nil {
|
|
||||||
checksum = unique.Make(Checksum(buf[:]))
|
|
||||||
|
|
||||||
c.substituteMu.Lock()
|
|
||||||
c.substitute[substitute] = checksum
|
|
||||||
c.substituteMu.Unlock()
|
|
||||||
}
|
|
||||||
c.putIdentBuf(buf)
|
|
||||||
|
|
||||||
return checksum, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done returns a channel that is closed when the ongoing cure of an [Artifact]
|
// Done returns a channel that is closed when the ongoing cure of an [Artifact]
|
||||||
// referred to by the specified identifier completes. Done may return nil if
|
// referred to by the specified identifier completes. Done may return nil if
|
||||||
// no ongoing cure of the specified identifier exists.
|
// no ongoing cure of the specified identifier exists.
|
||||||
@@ -1493,7 +1339,7 @@ func (c *Cache) Cure(a Artifact) (
|
|||||||
|
|
||||||
// CureError wraps a non-nil error returned attempting to cure an [Artifact].
|
// CureError wraps a non-nil error returned attempting to cure an [Artifact].
|
||||||
type CureError struct {
|
type CureError struct {
|
||||||
A Artifact
|
Ident unique.Handle[ID]
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1507,63 +1353,40 @@ func (e *CureError) Error() string { return e.Err.Error() }
|
|||||||
type DependencyCureError []*CureError
|
type DependencyCureError []*CureError
|
||||||
|
|
||||||
// unwrapM recursively expands underlying errors into a caller-supplied map.
|
// unwrapM recursively expands underlying errors into a caller-supplied map.
|
||||||
func (e *DependencyCureError) unwrapM(
|
func (e *DependencyCureError) unwrapM(me map[unique.Handle[ID]]*CureError) {
|
||||||
ctx context.Context,
|
|
||||||
ir *IRCache,
|
|
||||||
me map[unique.Handle[ID]]*CureError,
|
|
||||||
) {
|
|
||||||
for _, err := range *e {
|
for _, err := range *e {
|
||||||
if ctx.Err() != nil {
|
if _, ok := me[err.Ident]; ok {
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
id := ir.Ident(err.A)
|
|
||||||
if _, ok := me[id]; ok {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _e, ok := err.Err.(*DependencyCureError); ok {
|
if _e, ok := err.Err.(*DependencyCureError); ok {
|
||||||
_e.unwrapM(ctx, ir, me)
|
_e.unwrapM(me)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
me[id] = err
|
me[err.Ident] = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unwrap recursively expands and deduplicates underlying errors.
|
// unwrap recursively expands and deduplicates underlying errors.
|
||||||
func (e *DependencyCureError) unwrap(
|
func (e *DependencyCureError) unwrap() DependencyCureError {
|
||||||
ctx context.Context,
|
|
||||||
ir *IRCache,
|
|
||||||
) DependencyCureError {
|
|
||||||
me := make(map[unique.Handle[ID]]*CureError)
|
me := make(map[unique.Handle[ID]]*CureError)
|
||||||
e.unwrapM(ctx, ir, me)
|
e.unwrapM(me)
|
||||||
type ent struct {
|
errs := slices.AppendSeq(
|
||||||
id unique.Handle[ID]
|
make(DependencyCureError, 0, len(me)),
|
||||||
err *CureError
|
maps.Values(me),
|
||||||
}
|
)
|
||||||
errs := make([]*ent, 0, len(me))
|
|
||||||
for id, err := range me {
|
|
||||||
errs = append(errs, &ent{id, err})
|
|
||||||
}
|
|
||||||
|
|
||||||
var identBuf [2]ID
|
var identBuf [2]ID
|
||||||
slices.SortFunc(errs, func(a, b *ent) int {
|
slices.SortFunc(errs, func(a, b *CureError) int {
|
||||||
identBuf[0], identBuf[1] = a.id.Value(), b.id.Value()
|
identBuf[0], identBuf[1] = a.Ident.Value(), b.Ident.Value()
|
||||||
return slices.Compare(identBuf[0][:], identBuf[1][:])
|
return slices.Compare(identBuf[0][:], identBuf[1][:])
|
||||||
})
|
})
|
||||||
|
|
||||||
_errs := make(DependencyCureError, len(errs))
|
return errs
|
||||||
for i, v := range errs {
|
|
||||||
_errs[i] = v.err
|
|
||||||
}
|
|
||||||
return _errs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap returns a deduplicated slice of underlying errors.
|
// Unwrap returns a deduplicated slice of underlying errors.
|
||||||
func (e *DependencyCureError) Unwrap() []error {
|
func (e *DependencyCureError) Unwrap() []error {
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
errs := e.unwrap()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
errs := e.unwrap(ctx, NewIR())
|
|
||||||
_errs := make([]error, len(errs))
|
_errs := make([]error, len(errs))
|
||||||
for i, err := range errs {
|
for i, err := range errs {
|
||||||
_errs[i] = err
|
_errs[i] = err
|
||||||
@@ -1573,23 +1396,14 @@ func (e *DependencyCureError) Unwrap() []error {
|
|||||||
|
|
||||||
// Error returns a user-facing multiline error message.
|
// Error returns a user-facing multiline error message.
|
||||||
func (e *DependencyCureError) Error() string {
|
func (e *DependencyCureError) Error() string {
|
||||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
|
errs := e.unwrap()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
ir := NewIR()
|
|
||||||
errs := e.unwrap(ctx, ir)
|
|
||||||
if len(errs) == 0 {
|
if len(errs) == 0 {
|
||||||
return "invalid dependency cure outcome"
|
return "invalid dependency cure outcome"
|
||||||
}
|
}
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
buf.WriteString("errors curing dependencies:")
|
buf.WriteString("errors curing dependencies:")
|
||||||
for _, err := range errs {
|
for _, err := range errs {
|
||||||
buf.WriteString("\n\t" +
|
buf.WriteString("\n\t" + Encode(err.Ident.Value()) + ": " + err.Error())
|
||||||
reportName(err.A, ir.Ident(err.A)) + ": " +
|
|
||||||
err.Error())
|
|
||||||
}
|
|
||||||
if ctx.Err() != nil {
|
|
||||||
buf.WriteString("\nerror resolution cancelled")
|
|
||||||
}
|
}
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
@@ -1759,44 +1573,16 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var checksums string
|
||||||
checksums string
|
|
||||||
substitute unique.Handle[ID]
|
|
||||||
alternative *check.Absolute
|
|
||||||
)
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err == nil && checksums != "" {
|
if err == nil && checksums != "" {
|
||||||
linkname := checksumLinknamePrefix + checksums
|
|
||||||
|
|
||||||
err = os.Symlink(
|
err = os.Symlink(
|
||||||
linkname,
|
checksumLinknamePrefix+checksums,
|
||||||
pathname.String(),
|
pathname.String(),
|
||||||
)
|
)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = zeroTimes(pathname.String())
|
err = zeroTimes(pathname.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil && alternative != nil {
|
|
||||||
c.substituteMu.Lock()
|
|
||||||
err = os.Symlink(
|
|
||||||
linkname,
|
|
||||||
alternative.String(),
|
|
||||||
)
|
|
||||||
if errors.Is(err, os.ErrExist) {
|
|
||||||
c.msg.Verbosef(
|
|
||||||
"creating alternative over %s for artifact %s",
|
|
||||||
Encode(substitute.Value()), ids,
|
|
||||||
)
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
err = zeroTimes(alternative.String())
|
|
||||||
}
|
|
||||||
if err == nil && checksum != zeroChecksum {
|
|
||||||
c.substitute[substitute] = checksum
|
|
||||||
}
|
|
||||||
c.substituteMu.Unlock()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -1993,64 +1779,11 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
|||||||
f.deps[deps[i]] = p
|
f.deps[deps[i]] = p
|
||||||
}
|
}
|
||||||
|
|
||||||
sh := sha512.New384()
|
|
||||||
err = c.encode(sh, a, f.deps)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := c.getIdentBuf()
|
|
||||||
sh.Sum(buf[wordSize:wordSize])
|
|
||||||
substitute = unique.Make(ID(buf[wordSize:]))
|
|
||||||
substitutes := Encode(substitute.Value())
|
|
||||||
c.putIdentBuf(buf)
|
|
||||||
alternative = c.base.Append(
|
|
||||||
dirSubstitute,
|
|
||||||
substitutes,
|
|
||||||
)
|
|
||||||
|
|
||||||
if c.flags&CIgnoreSubstitutes == 0 {
|
|
||||||
var substituteChecksum unique.Handle[Checksum]
|
|
||||||
substituteChecksum, err = c.loadSubstitute(substitute)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if substituteChecksum != zeroChecksum {
|
|
||||||
checksum = substituteChecksum
|
|
||||||
checksums = Encode(checksum.Value())
|
|
||||||
checksumPathname = c.base.Append(
|
|
||||||
dirChecksum,
|
|
||||||
checksums,
|
|
||||||
)
|
|
||||||
if _, err = os.Lstat(c.base.Append(
|
|
||||||
dirStatus,
|
|
||||||
substitutes,
|
|
||||||
).String()); err == nil {
|
|
||||||
err = os.Symlink(substitutes, c.base.Append(
|
|
||||||
dirStatus,
|
|
||||||
ids,
|
|
||||||
).String())
|
|
||||||
} else if errors.Is(err, os.ErrNotExist) {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defer f.destroy(&err)
|
defer f.destroy(&err)
|
||||||
if err = c.enterCure(a, curesExempt); err != nil {
|
if err = c.enterCure(a, curesExempt); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = ca.Cure(&f)
|
err = ca.Cure(&f)
|
||||||
if err == nil && f.status != nil {
|
|
||||||
err = os.Link(c.base.Append(
|
|
||||||
dirStatus,
|
|
||||||
ids,
|
|
||||||
).String(), c.base.Append(
|
|
||||||
dirStatus,
|
|
||||||
substitutes,
|
|
||||||
).String())
|
|
||||||
}
|
|
||||||
c.exitCure(a, curesExempt)
|
c.exitCure(a, curesExempt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -2143,7 +1876,7 @@ func (pending *pendingArtifactDep) cure(c *Cache) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pending.errsMu.Lock()
|
pending.errsMu.Lock()
|
||||||
*pending.errs = append(*pending.errs, &CureError{pending.a, err})
|
*pending.errs = append(*pending.errs, &CureError{c.Ident(pending.a), err})
|
||||||
pending.errsMu.Unlock()
|
pending.errsMu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2159,52 +1892,6 @@ func (c *Cache) OpenStatus(a Artifact) (r io.ReadSeekCloser, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fault holds the pathname and termination time of an [Artifact] fault entry.
|
|
||||||
type Fault struct {
|
|
||||||
*check.Absolute
|
|
||||||
t uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time returns the instant in time where the fault occurred.
|
|
||||||
func (f Fault) Time() time.Time { return time.Unix(0, int64(f.t)) }
|
|
||||||
|
|
||||||
// Open opens the underlying entry for reading.
|
|
||||||
func (f Fault) Open() (io.ReadCloser, error) { return os.Open(f.Absolute.String()) }
|
|
||||||
|
|
||||||
// Destroy removes the underlying fault entry.
|
|
||||||
func (f Fault) Destroy() error { return os.Remove(f.Absolute.String()) }
|
|
||||||
|
|
||||||
// ReadFaults returns fault entries for an [Artifact].
|
|
||||||
func (c *Cache) ReadFaults(a Artifact) (faults []Fault, err error) {
|
|
||||||
prefix := Encode(c.Ident(a).Value()) + "."
|
|
||||||
var dents []os.DirEntry
|
|
||||||
if dents, err = os.ReadDir(c.base.Append(dirFault).String()); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, dent := range dents {
|
|
||||||
name := dent.Name()
|
|
||||||
if !strings.HasPrefix(name, prefix) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var t uint64
|
|
||||||
t, err = strconv.ParseUint(name[len(prefix):], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
faults = append(faults, Fault{c.base.Append(
|
|
||||||
dirFault,
|
|
||||||
name,
|
|
||||||
), t})
|
|
||||||
}
|
|
||||||
|
|
||||||
slices.SortFunc(faults, func(a, b Fault) int {
|
|
||||||
return cmp.Compare(a.t, b.t)
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abort cancels all pending cures and waits for them to clean up, but does not
|
// Abort cancels all pending cures and waits for them to clean up, but does not
|
||||||
// close the cache.
|
// close the cache.
|
||||||
func (c *Cache) Abort() {
|
func (c *Cache) Abort() {
|
||||||
@@ -2243,20 +1930,6 @@ func (c *Cache) Close() {
|
|||||||
c.unlock()
|
c.unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnsupportedVariantError describes an on-disk cache with an extension variant
|
|
||||||
// identification string that differs from the value returned by [Extension].
|
|
||||||
type UnsupportedVariantError string
|
|
||||||
|
|
||||||
func (e UnsupportedVariantError) Error() string {
|
|
||||||
return "unsupported variant " + strconv.Quote(string(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrWouldPromote is returned by [Open] if the [CPromoteVariant] bit is not
|
|
||||||
// set and the on-disk cache requires variant promotion.
|
|
||||||
ErrWouldPromote = errors.New("operation would promote unextended cache")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Open returns the address of a newly opened instance of [Cache].
|
// Open returns the address of a newly opened instance of [Cache].
|
||||||
//
|
//
|
||||||
// Concurrent cures of a [FloodArtifact] dependency graph is limited to the
|
// Concurrent cures of a [FloodArtifact] dependency graph is limited to the
|
||||||
@@ -2288,14 +1961,6 @@ func open(
|
|||||||
base *check.Absolute,
|
base *check.Absolute,
|
||||||
lock bool,
|
lock bool,
|
||||||
) (*Cache, error) {
|
) (*Cache, error) {
|
||||||
openMu.Lock()
|
|
||||||
defer openMu.Unlock()
|
|
||||||
opened = true
|
|
||||||
|
|
||||||
if extension == "" && len(irArtifact) != int(_kindEnd) {
|
|
||||||
panic("attempting to open cache with incomplete variant setup")
|
|
||||||
}
|
|
||||||
|
|
||||||
if cures < 1 {
|
if cures < 1 {
|
||||||
cures = runtime.NumCPU()
|
cures = runtime.NumCPU()
|
||||||
}
|
}
|
||||||
@@ -2304,17 +1969,13 @@ func open(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range []string{
|
for _, name := range []string{
|
||||||
dirSubstitute,
|
|
||||||
dirIdentifier,
|
dirIdentifier,
|
||||||
dirChecksum,
|
dirChecksum,
|
||||||
dirStatus,
|
dirStatus,
|
||||||
dirFault,
|
|
||||||
dirWork,
|
dirWork,
|
||||||
} {
|
} {
|
||||||
if err := os.MkdirAll(
|
if err := os.MkdirAll(base.Append(name).String(), 0700); err != nil &&
|
||||||
base.Append(name).String(),
|
!errors.Is(err, os.ErrExist) {
|
||||||
0700,
|
|
||||||
); err != nil && !errors.Is(err, os.ErrExist) {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2331,7 +1992,6 @@ func open(
|
|||||||
|
|
||||||
irCache: zeroIRCache(),
|
irCache: zeroIRCache(),
|
||||||
|
|
||||||
substitute: make(map[unique.Handle[ID]]unique.Handle[Checksum]),
|
|
||||||
ident: make(map[unique.Handle[ID]]unique.Handle[Checksum]),
|
ident: make(map[unique.Handle[ID]]unique.Handle[Checksum]),
|
||||||
identErr: make(map[unique.Handle[ID]]error),
|
identErr: make(map[unique.Handle[ID]]error),
|
||||||
identPending: make(map[unique.Handle[ID]]*pendingCure),
|
identPending: make(map[unique.Handle[ID]]*pendingCure),
|
||||||
@@ -2353,45 +2013,6 @@ func open(
|
|||||||
c.unlock = func() {}
|
c.unlock = func() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
variantPath := base.Append(fileVariant).String()
|
|
||||||
if p, err := os.ReadFile(variantPath); err != nil {
|
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
|
||||||
c.unlock()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// nonexistence implies newly created cache, or a cache predating
|
|
||||||
// variant identification strings, in which case it is silently promoted
|
|
||||||
if err = os.WriteFile(
|
|
||||||
variantPath,
|
|
||||||
[]byte(extension),
|
|
||||||
0400,
|
|
||||||
); err != nil {
|
|
||||||
c.unlock()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else if s := string(p); s == "" {
|
|
||||||
if extension != "" {
|
|
||||||
if flags&CPromoteVariant == 0 {
|
|
||||||
c.unlock()
|
|
||||||
return nil, ErrWouldPromote
|
|
||||||
}
|
|
||||||
if err = os.WriteFile(
|
|
||||||
variantPath,
|
|
||||||
[]byte(extension),
|
|
||||||
0400,
|
|
||||||
); err != nil {
|
|
||||||
c.unlock()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if !ValidExtension(s) {
|
|
||||||
c.unlock()
|
|
||||||
return nil, ErrInvalidExtension
|
|
||||||
} else if s != extension {
|
|
||||||
c.unlock()
|
|
||||||
return nil, UnsupportedVariantError(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+128
-739
File diff suppressed because it is too large
Load Diff
+14
-74
@@ -20,31 +20,6 @@ import (
|
|||||||
func TestTar(t *testing.T) {
|
func TestTar(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
want := expectsFS{
|
|
||||||
".": {Mode: fs.ModeDir | 0500},
|
|
||||||
|
|
||||||
"checksum": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/check": {Mode: 0400, Data: []byte{0, 0}},
|
|
||||||
"checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/pkgconfig": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0500},
|
|
||||||
"identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
|
||||||
"identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
|
||||||
|
|
||||||
"work": {Mode: fs.ModeDir | 0500},
|
|
||||||
}
|
|
||||||
wantEncode := pkg.Encode(want.hash())
|
|
||||||
|
|
||||||
wantExpand := expectsFS{
|
|
||||||
".": {Mode: fs.ModeDir | 0500},
|
|
||||||
|
|
||||||
"libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
|
||||||
}
|
|
||||||
wantExpandEncode := pkg.Encode(wantExpand.hash())
|
|
||||||
|
|
||||||
checkWithCache(t, []cacheTestCase{
|
checkWithCache(t, []cacheTestCase{
|
||||||
{"http", 0, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
{"http", 0, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
checkTarHTTP(t, base, c, fstest.MapFS{
|
checkTarHTTP(t, base, c, fstest.MapFS{
|
||||||
@@ -62,32 +37,10 @@ func TestTar(t *testing.T) {
|
|||||||
"identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
"identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
||||||
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
"work": {Mode: fs.ModeDir | 0700},
|
||||||
}, want)
|
}, pkg.MustDecode(
|
||||||
}, expectsFS{
|
"cTw0h3AmYe7XudSoyEMByduYXqGi-N5ZkTZ0t9K5elsu3i_jNIVF5T08KR1roBFM",
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
))
|
||||||
|
}, pkg.MustDecode("NQTlc466JmSVLIyWklm_u8_g95jEEb98PxJU-kjwxLpfdjwMWJq0G8ze9R4Vo1Vu")},
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
|
||||||
"checksum/" + wantEncode: {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantEncode + "/checksum": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantEncode + "/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantEncode + "/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/check": {Mode: 0400, Data: []byte{0, 0}},
|
|
||||||
"checksum/" + wantEncode + "/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantEncode + "/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
|
||||||
"checksum/" + wantEncode + "/checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/pkgconfig": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantEncode + "/identifier": {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantEncode + "/identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
|
||||||
"checksum/" + wantEncode + "/identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")},
|
|
||||||
"checksum/" + wantEncode + "/work": {Mode: fs.ModeDir | 0500},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/W5S65DEhawz_WKaok5NjUKLmnD9dNl5RPauNJjcOVcB3VM4eGhSaLGmXbL8vZpiw": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
|
|
||||||
"identifier/rg7F1D5hwv6o4xctjD5zDq4i5MD0mArTsUIWfhUbik8xC6Bsyt3mjXXOm3goojTz": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantEncode)},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"temp": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"http expand", 0, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
{"http expand", 0, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
checkTarHTTP(t, base, c, fstest.MapFS{
|
checkTarHTTP(t, base, c, fstest.MapFS{
|
||||||
@@ -95,23 +48,10 @@ func TestTar(t *testing.T) {
|
|||||||
|
|
||||||
"lib": {Mode: fs.ModeDir | 0700},
|
"lib": {Mode: fs.ModeDir | 0700},
|
||||||
"lib/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
"lib/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
||||||
}, wantExpand)
|
}, pkg.MustDecode(
|
||||||
}, expectsFS{
|
"CH3AiUrCCcVOjOYLaMKKK1Da78989JtfHeIsxMzWOQFiN4mrCLDYpoDxLWqJWCUN",
|
||||||
".": {Mode: fs.ModeDir | 0700},
|
))
|
||||||
|
}, pkg.MustDecode("hSoSSgCYTNonX3Q8FjvjD1fBl-E-BQyA6OTXro2OadXqbST4tZ-akGXszdeqphRe")},
|
||||||
"checksum": {Mode: fs.ModeDir | 0700},
|
|
||||||
"checksum/" + wantExpandEncode: {Mode: fs.ModeDir | 0500},
|
|
||||||
"checksum/" + wantExpandEncode + "/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")},
|
|
||||||
|
|
||||||
"identifier": {Mode: fs.ModeDir | 0700},
|
|
||||||
"identifier/W5S65DEhawz_WKaok5NjUKLmnD9dNl5RPauNJjcOVcB3VM4eGhSaLGmXbL8vZpiw": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
|
|
||||||
"identifier/_v1blm2h-_KA-dVaawdpLas6MjHc6rbhhFS8JWwx8iJxZGUu8EBbRrhr5AaZ9PJL": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantExpandEncode)},
|
|
||||||
|
|
||||||
"substitute": {Mode: fs.ModeDir | 0700},
|
|
||||||
|
|
||||||
"temp": {Mode: fs.ModeDir | 0700},
|
|
||||||
"work": {Mode: fs.ModeDir | 0700},
|
|
||||||
}},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +60,7 @@ func checkTarHTTP(
|
|||||||
base *check.Absolute,
|
base *check.Absolute,
|
||||||
c *pkg.Cache,
|
c *pkg.Cache,
|
||||||
testdataFsys fs.FS,
|
testdataFsys fs.FS,
|
||||||
want expectsKnown,
|
wantChecksum pkg.Checksum,
|
||||||
) {
|
) {
|
||||||
var testdata string
|
var testdata string
|
||||||
{
|
{
|
||||||
@@ -254,24 +194,24 @@ func checkTarHTTP(
|
|||||||
{"file", a, base.Append(
|
{"file", a, base.Append(
|
||||||
"identifier",
|
"identifier",
|
||||||
pkg.Encode(wantIdent),
|
pkg.Encode(wantIdent),
|
||||||
), want, nil},
|
), wantChecksum, nil},
|
||||||
|
|
||||||
{"directory", pkg.NewTar(
|
{"directory", pkg.NewTar(
|
||||||
&tarDir,
|
&tarDir,
|
||||||
pkg.TarGzip,
|
pkg.TarGzip,
|
||||||
), ignorePathname, want, nil},
|
), ignorePathname, wantChecksum, nil},
|
||||||
|
|
||||||
{"multiple entries", pkg.NewTar(
|
{"multiple entries", pkg.NewTar(
|
||||||
&tarDirMulti,
|
&tarDirMulti,
|
||||||
pkg.TarGzip,
|
pkg.TarGzip,
|
||||||
), nil, nil, errors.New(
|
), nil, pkg.Checksum{}, errors.New(
|
||||||
"input directory does not contain a single regular file",
|
"input directory does not contain a single regular file",
|
||||||
)},
|
)},
|
||||||
|
|
||||||
{"bad type", pkg.NewTar(
|
{"bad type", pkg.NewTar(
|
||||||
&tarDirType,
|
&tarDirType,
|
||||||
pkg.TarGzip,
|
pkg.TarGzip,
|
||||||
), nil, nil, errors.New(
|
), nil, pkg.Checksum{}, errors.New(
|
||||||
"input directory does not contain a single regular file",
|
"input directory does not contain a single regular file",
|
||||||
)},
|
)},
|
||||||
|
|
||||||
@@ -281,6 +221,6 @@ func checkTarHTTP(
|
|||||||
cure: func(t *pkg.TContext) error {
|
cure: func(t *pkg.TContext) error {
|
||||||
return stub.UniqueError(0xcafe)
|
return stub.UniqueError(0xcafe)
|
||||||
},
|
},
|
||||||
}, pkg.TarGzip), nil, nil, stub.UniqueError(0xcafe)},
|
}, pkg.TarGzip), nil, pkg.Checksum{}, stub.UniqueError(0xcafe)},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,29 +14,15 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"hakurei.app/check"
|
||||||
"hakurei.app/fhs"
|
"hakurei.app/fhs"
|
||||||
"hakurei.app/vfs"
|
"hakurei.app/vfs"
|
||||||
|
|
||||||
"hakurei.app/internal/pkg/internal/testtool/expected"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
log.SetPrefix("testtool: ")
|
log.SetPrefix("testtool: ")
|
||||||
|
|
||||||
if os.Getenv("HAKUREI_BINFMT") == "1" {
|
|
||||||
wantArgs := []string{"/interpreter", "/opt/bin/sample"}
|
|
||||||
if !slices.Equal(os.Args, wantArgs) {
|
|
||||||
log.Fatalf("Args: %q, want %q", os.Args, wantArgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.WriteFile("check", []byte("binfmt"), 0400); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
environ := slices.DeleteFunc(slices.Clone(os.Environ()), func(s string) bool {
|
environ := slices.DeleteFunc(slices.Clone(os.Environ()), func(s string) bool {
|
||||||
return s == "CURE_JOBS="+strconv.Itoa(runtime.NumCPU())
|
return s == "CURE_JOBS="+strconv.Itoa(runtime.NumCPU())
|
||||||
})
|
})
|
||||||
@@ -162,40 +148,59 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const checksumEmptyDir = "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU"
|
const checksumEmptyDir = "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU"
|
||||||
ident := expected.Offline
|
ident := "dztPS6jRjiZtCF4_p8AzfnxGp6obkhrgFVsxdodbKWUoAEVtDz3MykepJB4kI_ks"
|
||||||
log.Println(m)
|
log.Println(m)
|
||||||
next := func() { m = m.Next; log.Println(m) }
|
next := func() { m = m.Next; log.Println(m) }
|
||||||
|
|
||||||
if overlayRoot {
|
if overlayRoot {
|
||||||
ident = expected.OvlRoot
|
ident = "RdMA-mubnrHuu3Ky1wWyxauSYCO0ZH_zCPUj3uDHqkfwv5sGcByoF_g5PjlGiClb"
|
||||||
|
|
||||||
if m.Root != "/" || m.Target != "/" ||
|
if m.Root != "/" || m.Target != "/" ||
|
||||||
m.Source != "overlay" || m.FsType != "overlay" {
|
m.Source != "overlay" || m.FsType != "overlay" {
|
||||||
log.Fatal("unexpected root mount entry")
|
log.Fatal("unexpected root mount entry")
|
||||||
}
|
}
|
||||||
var lowerdir []string
|
var lowerdir string
|
||||||
for _, o := range strings.Split(m.FsOptstr, ",") {
|
for _, o := range strings.Split(m.FsOptstr, ",") {
|
||||||
const lowerdirKey = "lowerdir+="
|
const lowerdirKey = "lowerdir="
|
||||||
if strings.HasPrefix(o, lowerdirKey) {
|
if strings.HasPrefix(o, lowerdirKey) {
|
||||||
lowerdir = append(lowerdir, o[len(lowerdirKey):])
|
lowerdir = o[len(lowerdirKey):]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !layers {
|
if !layers {
|
||||||
if len(lowerdir) != 1 || filepath.Base(lowerdir[0]) != checksumEmptyDir {
|
if filepath.Base(lowerdir) != checksumEmptyDir {
|
||||||
log.Fatal("unexpected artifact checksum")
|
log.Fatal("unexpected artifact checksum")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ident = expected.Layers
|
ident = "p1t_drXr34i-jZNuxDMLaMOdL6tZvQqhavNafGynGqxOZoXAUTSn7kqNh3Ovv3DT"
|
||||||
|
|
||||||
if len(lowerdir) != 2 ||
|
lowerdirsEscaped := strings.Split(lowerdir, ":")
|
||||||
filepath.Base(lowerdir[0]) != "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU" ||
|
lowerdirs := lowerdirsEscaped[:0]
|
||||||
filepath.Base(lowerdir[1]) != "nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK" {
|
// ignore the option separator since it does not appear in ident
|
||||||
log.Fatalf("unexpected lowerdirs %s", strings.Join(lowerdir, ", "))
|
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, ", "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if hostNet {
|
if hostNet {
|
||||||
ident = expected.Net
|
ident = "G8qPxD9puvvoOVV7lrT80eyDeIl3G_CCFoKw12c8mCjMdG1zF7NEPkwYpNubClK3"
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Root != "/sysroot" || m.Target != "/" {
|
if m.Root != "/sysroot" || m.Target != "/" {
|
||||||
@@ -214,14 +219,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if promote {
|
if promote {
|
||||||
ident = expected.Promote
|
ident = "xXTIYcXmgJWNLC91c417RRrNM9cjELwEZHpGvf8Fk_GNP5agRJp_SicD0w9aMeLJ"
|
||||||
}
|
}
|
||||||
|
|
||||||
next() // testtool artifact
|
next() // testtool artifact
|
||||||
|
|
||||||
next()
|
next()
|
||||||
if overlayWork {
|
if overlayWork {
|
||||||
ident = expected.Work
|
ident = "5hlaukCirnXE4W_RSLJFOZN47Z5RiHnacXzdFp_70cLgiJUGR6cSb_HaFftkzi0-"
|
||||||
if m.Root != "/" || m.Target != "/work" ||
|
if m.Root != "/" || m.Target != "/work" ||
|
||||||
m.Source != "overlay" || m.FsType != "overlay" {
|
m.Source != "overlay" || m.FsType != "overlay" {
|
||||||
log.Fatal("unexpected work mount entry")
|
log.Fatal("unexpected work mount entry")
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newAttr() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "2.5.2"
|
||||||
|
checksum = "YWEphrz6vg1sUMmHHVr1CRo53pFXRhq_pjN-AlG8UgwZK1y6m7zuDhxqJhD0SV0l"
|
||||||
|
)
|
||||||
|
return t.NewPackage("attr", version, newTar(
|
||||||
|
"https://download.savannah.nongnu.org/releases/attr/"+
|
||||||
|
"attr-"+version+".tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
), &PackageAttr{
|
||||||
|
Patches: []KV{
|
||||||
|
{"libgen-basename", `From 8a80d895dfd779373363c3a4b62ecce5a549efb2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Haelwenn (lanodan) Monnier" <contact@hacktivis.me>
|
||||||
|
Date: Sat, 30 Mar 2024 10:17:10 +0100
|
||||||
|
Subject: tools/attr.c: Add missing libgen.h include for basename(3)
|
||||||
|
|
||||||
|
Fixes compilation issue with musl and modern C99 compilers.
|
||||||
|
|
||||||
|
See: https://bugs.gentoo.org/926294
|
||||||
|
---
|
||||||
|
tools/attr.c | 1 +
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
|
diff --git a/tools/attr.c b/tools/attr.c
|
||||||
|
index f12e4af..6a3c1e9 100644
|
||||||
|
--- a/tools/attr.c
|
||||||
|
+++ b/tools/attr.c
|
||||||
|
@@ -28,6 +28,7 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <locale.h>
|
||||||
|
+#include <libgen.h>
|
||||||
|
|
||||||
|
#include <attr/attributes.h>
|
||||||
|
|
||||||
|
--
|
||||||
|
cgit v1.1`},
|
||||||
|
|
||||||
|
{"musl-errno", `diff --git a/test/attr.test b/test/attr.test
|
||||||
|
index 6ce2f9b..e9bde92 100644
|
||||||
|
--- a/test/attr.test
|
||||||
|
+++ b/test/attr.test
|
||||||
|
@@ -11,7 +11,7 @@ Try various valid and invalid names
|
||||||
|
|
||||||
|
$ touch f
|
||||||
|
$ setfattr -n user -v value f
|
||||||
|
- > setfattr: f: Operation not supported
|
||||||
|
+ > setfattr: f: Not supported
|
||||||
|
|
||||||
|
$ setfattr -n user. -v value f
|
||||||
|
> setfattr: f: Invalid argument
|
||||||
|
`},
|
||||||
|
},
|
||||||
|
|
||||||
|
ScriptEarly: `
|
||||||
|
ln -s ../../system/bin/perl /usr/bin
|
||||||
|
`,
|
||||||
|
}, (*MakeHelper)(nil),
|
||||||
|
Perl,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Attr] = Metadata{
|
||||||
|
f: Toolchain.newAttr,
|
||||||
|
|
||||||
|
Name: "attr",
|
||||||
|
Description: "Commands for Manipulating Filesystem Extended Attributes",
|
||||||
|
Website: "https://savannah.nongnu.org/projects/attr/",
|
||||||
|
|
||||||
|
ID: 137,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Toolchain) newACL() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "2.3.2"
|
||||||
|
checksum = "-fY5nwH4K8ZHBCRXrzLdguPkqjKI6WIiGu4dBtrZ1o0t6AIU73w8wwJz_UyjIS0P"
|
||||||
|
)
|
||||||
|
return t.NewPackage("acl", version, newTar(
|
||||||
|
"https://download.savannah.nongnu.org/releases/acl/"+
|
||||||
|
"acl-"+version+".tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
), nil, &MakeHelper{
|
||||||
|
// makes assumptions about uid_map/gid_map
|
||||||
|
SkipCheck: true,
|
||||||
|
},
|
||||||
|
Attr,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[ACL] = Metadata{
|
||||||
|
f: Toolchain.newACL,
|
||||||
|
|
||||||
|
Name: "acl",
|
||||||
|
Description: "Commands for Manipulating POSIX Access Control Lists",
|
||||||
|
Website: "https://savannah.nongnu.org/projects/acl/",
|
||||||
|
|
||||||
|
Dependencies: P{
|
||||||
|
Attr,
|
||||||
|
},
|
||||||
|
|
||||||
|
ID: 16,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,363 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"hakurei.app/internal/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PArtifact is a lazily-initialised [pkg.Artifact] preset.
|
||||||
|
type PArtifact int
|
||||||
|
|
||||||
|
const (
|
||||||
|
CompilerRT PArtifact = iota
|
||||||
|
LLVMRuntimes
|
||||||
|
Clang
|
||||||
|
|
||||||
|
// EarlyInit is the Rosa OS init program.
|
||||||
|
EarlyInit
|
||||||
|
// ImageSystem is the Rosa OS /system image.
|
||||||
|
ImageSystem
|
||||||
|
// ImageInitramfs is the Rosa OS initramfs archive.
|
||||||
|
ImageInitramfs
|
||||||
|
|
||||||
|
// Kernel is the generic Rosa OS Linux kernel.
|
||||||
|
Kernel
|
||||||
|
// KernelHeaders is an installation of kernel headers for [Kernel].
|
||||||
|
KernelHeaders
|
||||||
|
// KernelSource is a writable kernel source tree installed to [AbsUsrSrc].
|
||||||
|
KernelSource
|
||||||
|
// Firmware is firmware blobs for use with the Linux kernel.
|
||||||
|
Firmware
|
||||||
|
|
||||||
|
ACL
|
||||||
|
ArgpStandalone
|
||||||
|
Attr
|
||||||
|
Autoconf
|
||||||
|
Automake
|
||||||
|
BC
|
||||||
|
Bash
|
||||||
|
Binutils
|
||||||
|
Bison
|
||||||
|
Bzip2
|
||||||
|
CMake
|
||||||
|
Connman
|
||||||
|
Coreutils
|
||||||
|
Curl
|
||||||
|
DBus
|
||||||
|
DTC
|
||||||
|
Diffutils
|
||||||
|
Elfutils
|
||||||
|
Fakeroot
|
||||||
|
Findutils
|
||||||
|
Flex
|
||||||
|
Fuse
|
||||||
|
GMP
|
||||||
|
GLib
|
||||||
|
Gawk
|
||||||
|
GenInitCPIO
|
||||||
|
Gettext
|
||||||
|
Git
|
||||||
|
Glslang
|
||||||
|
GnuTLS
|
||||||
|
Go
|
||||||
|
Gperf
|
||||||
|
Grep
|
||||||
|
Gzip
|
||||||
|
Hakurei
|
||||||
|
HakureiDist
|
||||||
|
IPTables
|
||||||
|
Kmod
|
||||||
|
LibXau
|
||||||
|
Libbsd
|
||||||
|
Libcap
|
||||||
|
Libclc
|
||||||
|
Libdrm
|
||||||
|
Libev
|
||||||
|
Libexpat
|
||||||
|
Libffi
|
||||||
|
Libgd
|
||||||
|
Libglvnd
|
||||||
|
Libiconv
|
||||||
|
Libmd
|
||||||
|
Libmnl
|
||||||
|
Libpciaccess
|
||||||
|
Libnftnl
|
||||||
|
Libpsl
|
||||||
|
Libseccomp
|
||||||
|
Libtasn1
|
||||||
|
Libtool
|
||||||
|
Libucontext
|
||||||
|
Libunistring
|
||||||
|
Libxml2
|
||||||
|
Libxslt
|
||||||
|
M4
|
||||||
|
MPC
|
||||||
|
MPFR
|
||||||
|
Make
|
||||||
|
Meson
|
||||||
|
Mksh
|
||||||
|
MuslFts
|
||||||
|
MuslObstack
|
||||||
|
NSS
|
||||||
|
NSSCACert
|
||||||
|
Ncurses
|
||||||
|
Nettle
|
||||||
|
Ninja
|
||||||
|
OpenSSL
|
||||||
|
P11Kit
|
||||||
|
PCRE2
|
||||||
|
Parallel
|
||||||
|
Patch
|
||||||
|
Perl
|
||||||
|
PerlLocaleGettext
|
||||||
|
PerlMIMECharset
|
||||||
|
PerlModuleBuild
|
||||||
|
PerlPodParser
|
||||||
|
PerlSGMLS
|
||||||
|
PerlTermReadKey
|
||||||
|
PerlTextCharWidth
|
||||||
|
PerlTextWrapI18N
|
||||||
|
PerlUnicodeLineBreak
|
||||||
|
PerlYAMLTiny
|
||||||
|
PkgConfig
|
||||||
|
Procps
|
||||||
|
Python
|
||||||
|
PythonIniConfig
|
||||||
|
PythonMako
|
||||||
|
PythonMarkupSafe
|
||||||
|
PythonPackaging
|
||||||
|
PythonPluggy
|
||||||
|
PythonPyTest
|
||||||
|
PythonPyYAML
|
||||||
|
PythonPygments
|
||||||
|
QEMU
|
||||||
|
Rdfind
|
||||||
|
Readline
|
||||||
|
Rsync
|
||||||
|
Sed
|
||||||
|
Setuptools
|
||||||
|
SPIRVHeaders
|
||||||
|
SPIRVTools
|
||||||
|
SquashfsTools
|
||||||
|
Strace
|
||||||
|
TamaGo
|
||||||
|
Tar
|
||||||
|
Texinfo
|
||||||
|
Toybox
|
||||||
|
toyboxEarly
|
||||||
|
Unzip
|
||||||
|
UtilLinux
|
||||||
|
Wayland
|
||||||
|
WaylandProtocols
|
||||||
|
XCB
|
||||||
|
XCBProto
|
||||||
|
XDGDBusProxy
|
||||||
|
XZ
|
||||||
|
Xproto
|
||||||
|
Zlib
|
||||||
|
Zstd
|
||||||
|
|
||||||
|
// PresetUnexportedStart is the first unexported preset.
|
||||||
|
PresetUnexportedStart
|
||||||
|
|
||||||
|
llvmSource = iota - 1
|
||||||
|
buildcatrust
|
||||||
|
utilMacros
|
||||||
|
|
||||||
|
// Musl is a standalone libc that does not depend on the toolchain.
|
||||||
|
Musl
|
||||||
|
|
||||||
|
// gcc is a hacked-to-pieces GCC toolchain meant for use in intermediate
|
||||||
|
// stages only. This preset and its direct output must never be exposed.
|
||||||
|
gcc
|
||||||
|
|
||||||
|
// nettle3 is an older version of [Nettle].
|
||||||
|
nettle3
|
||||||
|
|
||||||
|
// Stage0 is a tarball containing all compile-time dependencies of artifacts
|
||||||
|
// part of the [Std] toolchain.
|
||||||
|
Stage0
|
||||||
|
|
||||||
|
// PresetEnd is the total number of presets and does not denote a preset.
|
||||||
|
PresetEnd
|
||||||
|
)
|
||||||
|
|
||||||
|
// P represents multiple [PArtifact] and is stable through JSON.
|
||||||
|
type P []PArtifact
|
||||||
|
|
||||||
|
// MarshalJSON represents [PArtifact] by their [Metadata.Name].
|
||||||
|
func (s P) MarshalJSON() ([]byte, error) {
|
||||||
|
names := make([]string, len(s))
|
||||||
|
for i, p := range s {
|
||||||
|
names[i] = GetMetadata(p).Name
|
||||||
|
}
|
||||||
|
return json.Marshal(names)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON resolves the value created by MarshalJSON back to [P].
|
||||||
|
func (s *P) UnmarshalJSON(data []byte) error {
|
||||||
|
var names []string
|
||||||
|
if err := json.Unmarshal(data, &names); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*s = make(P, len(names))
|
||||||
|
for i, name := range names {
|
||||||
|
if p, ok := ResolveName(name); !ok {
|
||||||
|
return fmt.Errorf("unknown artifact %q", name)
|
||||||
|
} else {
|
||||||
|
(*s)[i] = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata is stage-agnostic information of a [PArtifact] not directly
|
||||||
|
// representable in the resulting [pkg.Artifact].
|
||||||
|
type Metadata struct {
|
||||||
|
f func(t Toolchain) (a pkg.Artifact, version string)
|
||||||
|
|
||||||
|
// Unique package name.
|
||||||
|
Name string `json:"name"`
|
||||||
|
// Short user-facing description.
|
||||||
|
Description string `json:"description"`
|
||||||
|
// Project home page.
|
||||||
|
Website string `json:"website,omitempty"`
|
||||||
|
|
||||||
|
// Runtime dependencies.
|
||||||
|
Dependencies P `json:"dependencies"`
|
||||||
|
|
||||||
|
// Project identifier on [Anitya].
|
||||||
|
//
|
||||||
|
// [Anitya]: https://release-monitoring.org/
|
||||||
|
ID int `json:"-"`
|
||||||
|
|
||||||
|
// Optional custom version checking behaviour.
|
||||||
|
latest func(v *Versions) string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLatest returns the latest version described by v.
|
||||||
|
func (meta *Metadata) GetLatest(v *Versions) string {
|
||||||
|
if meta.latest != nil {
|
||||||
|
return meta.latest(v)
|
||||||
|
}
|
||||||
|
return v.Latest
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unversioned denotes an unversioned [PArtifact].
|
||||||
|
const Unversioned = "\x00"
|
||||||
|
|
||||||
|
// UnpopulatedIDError is returned by [Metadata.GetLatest] for an instance of
|
||||||
|
// [Metadata] where ID is not populated.
|
||||||
|
type UnpopulatedIDError struct{}
|
||||||
|
|
||||||
|
func (UnpopulatedIDError) Unwrap() error { return errors.ErrUnsupported }
|
||||||
|
func (UnpopulatedIDError) Error() string { return "Anitya ID is not populated" }
|
||||||
|
|
||||||
|
// Versions are package versions returned by Anitya.
|
||||||
|
type Versions struct {
|
||||||
|
// The latest version for the project, as determined by the version sorting algorithm.
|
||||||
|
Latest string `json:"latest_version"`
|
||||||
|
// List of all versions that aren’t flagged as pre-release.
|
||||||
|
Stable []string `json:"stable_versions"`
|
||||||
|
// List of all versions stored, sorted from newest to oldest.
|
||||||
|
All []string `json:"versions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// getStable returns the first Stable version, or Latest if that is unavailable.
|
||||||
|
func (v *Versions) getStable() string {
|
||||||
|
if len(v.Stable) == 0 {
|
||||||
|
return v.Latest
|
||||||
|
}
|
||||||
|
return v.Stable[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVersions returns versions fetched from Anitya.
|
||||||
|
func (meta *Metadata) GetVersions(ctx context.Context) (*Versions, error) {
|
||||||
|
if meta.ID == 0 {
|
||||||
|
return nil, UnpopulatedIDError{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp *http.Response
|
||||||
|
if req, err := http.NewRequestWithContext(
|
||||||
|
ctx,
|
||||||
|
http.MethodGet,
|
||||||
|
"https://release-monitoring.org/api/v2/versions/?project_id="+
|
||||||
|
strconv.Itoa(meta.ID),
|
||||||
|
nil,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
req.Header.Set("User-Agent", "Rosa/1.1")
|
||||||
|
if resp, err = http.DefaultClient.Do(req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var v Versions
|
||||||
|
err := json.NewDecoder(resp.Body).Decode(&v)
|
||||||
|
return &v, errors.Join(err, resp.Body.Close())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// artifactsM is an array of [PArtifact] metadata.
|
||||||
|
artifactsM [PresetEnd]Metadata
|
||||||
|
|
||||||
|
// artifacts stores the result of Metadata.f.
|
||||||
|
artifacts [_toolchainEnd][len(artifactsM)]struct {
|
||||||
|
a pkg.Artifact
|
||||||
|
v string
|
||||||
|
}
|
||||||
|
// artifactsOnce is for lazy initialisation of artifacts.
|
||||||
|
artifactsOnce [_toolchainEnd][len(artifactsM)]sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// zero zeros the value pointed to by p.
|
||||||
|
func zero[T any](p *T) { var v T; *p = v }
|
||||||
|
|
||||||
|
// DropCaches arranges for all cached [pkg.Artifact] to be freed some time after
|
||||||
|
// it returns. Must not be used concurrently with any other function from this
|
||||||
|
// package.
|
||||||
|
func DropCaches() {
|
||||||
|
zero(&artifacts)
|
||||||
|
zero(&artifactsOnce)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetadata returns [Metadata] of a [PArtifact].
|
||||||
|
func GetMetadata(p PArtifact) *Metadata { return &artifactsM[p] }
|
||||||
|
|
||||||
|
// construct constructs a [pkg.Artifact] corresponding to a [PArtifact] once.
|
||||||
|
func (t Toolchain) construct(p PArtifact) {
|
||||||
|
artifactsOnce[t][p].Do(func() {
|
||||||
|
artifacts[t][p].a, artifacts[t][p].v = artifactsM[p].f(t)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load returns the resulting [pkg.Artifact] of [PArtifact].
|
||||||
|
func (t Toolchain) Load(p PArtifact) pkg.Artifact {
|
||||||
|
t.construct(p)
|
||||||
|
return artifacts[t][p].a
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version returns the version string of [PArtifact].
|
||||||
|
func (t Toolchain) Version(p PArtifact) string {
|
||||||
|
t.construct(p)
|
||||||
|
return artifacts[t][p].v
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveName returns a [PArtifact] by name.
|
||||||
|
func ResolveName(name string) (p PArtifact, ok bool) {
|
||||||
|
for i := range PresetUnexportedStart {
|
||||||
|
if name == artifactsM[i].Name {
|
||||||
|
return i, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package rosa_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"hakurei.app/internal/rosa"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoad(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
for i := range rosa.PresetEnd {
|
||||||
|
p := rosa.PArtifact(i)
|
||||||
|
t.Run(rosa.GetMetadata(p).Name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
rosa.Std.Load(p)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAll(b *testing.B) {
|
||||||
|
for b.Loop() {
|
||||||
|
for i := range rosa.PresetEnd {
|
||||||
|
rosa.Std.Load(rosa.PArtifact(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.StopTimer()
|
||||||
|
rosa.DropCaches()
|
||||||
|
b.StartTimer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveName(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
for i := range rosa.PresetUnexportedStart {
|
||||||
|
p := i
|
||||||
|
name := rosa.GetMetadata(p).Name
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if got, ok := rosa.ResolveName(name); !ok {
|
||||||
|
t.Fatal("ResolveName: ok = false")
|
||||||
|
} else if got != p {
|
||||||
|
t.Fatalf("ResolveName: %d, want %d", got, p)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestResolveNameUnexported(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
for i := rosa.PresetUnexportedStart; i < rosa.PresetEnd; i++ {
|
||||||
|
p := i
|
||||||
|
name := rosa.GetMetadata(p).Name
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if got, ok := rosa.ResolveName(name); ok {
|
||||||
|
t.Fatalf("ResolveName: resolved unexported preset %d", got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnique(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
names := make(map[string]struct{})
|
||||||
|
for i := range rosa.PresetEnd {
|
||||||
|
name := rosa.GetMetadata(rosa.PArtifact(i)).Name
|
||||||
|
if _, ok := names[name]; ok {
|
||||||
|
t.Fatalf("name %s is not unique", name)
|
||||||
|
}
|
||||||
|
names[name] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newArgpStandalone() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "1.3"
|
||||||
|
checksum = "vtW0VyO2pJ-hPyYmDI2zwSLS8QL0sPAUKC1t3zNYbwN2TmsaE-fADhaVtNd3eNFl"
|
||||||
|
)
|
||||||
|
return t.NewPackage("argp-standalone", version, newTar(
|
||||||
|
"http://www.lysator.liu.se/~nisse/misc/"+
|
||||||
|
"argp-standalone-"+version+".tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
), &PackageAttr{
|
||||||
|
Env: []string{
|
||||||
|
"CC=cc -std=gnu89 -fPIC",
|
||||||
|
},
|
||||||
|
}, &MakeHelper{
|
||||||
|
Install: `
|
||||||
|
install -D -m644 /usr/src/argp-standalone/argp.h /work/system/include/argp.h
|
||||||
|
install -D -m755 libargp.a /work/system/lib/libargp.a
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
Diffutils,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[ArgpStandalone] = Metadata{
|
||||||
|
f: Toolchain.newArgpStandalone,
|
||||||
|
|
||||||
|
Name: "argp-standalone",
|
||||||
|
Description: "hierarchical argument parsing library broken out from glibc",
|
||||||
|
Website: "http://www.lysator.liu.se/~nisse/misc/",
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,348 +0,0 @@
|
|||||||
// Package azalea implements a proof-of-concept, domain-specific language for
|
|
||||||
// Rosa OS software packaging.
|
|
||||||
package azalea
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"strconv"
|
|
||||||
"text/scanner"
|
|
||||||
)
|
|
||||||
|
|
||||||
// idents are runes accepted in an identifier.
|
|
||||||
var idents = [...]bool{
|
|
||||||
'0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true,
|
|
||||||
'7': true, '8': true, '9': true,
|
|
||||||
|
|
||||||
'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true,
|
|
||||||
'H': true, 'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true,
|
|
||||||
'O': true, 'P': true, 'Q': true, 'R': true, 'S': true, 'T': true, 'U': true,
|
|
||||||
'V': true, 'W': true, 'X': true, 'Y': true, 'Z': true,
|
|
||||||
|
|
||||||
'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true,
|
|
||||||
'h': true, 'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true,
|
|
||||||
'o': true, 'p': true, 'q': true, 'r': true, 's': true, 't': true, 'u': true,
|
|
||||||
'v': true, 'w': true, 'x': true, 'y': true, 'z': true,
|
|
||||||
|
|
||||||
'-': true, '_': true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TokenError describes an unexpected token.
|
|
||||||
type TokenError [2]rune
|
|
||||||
|
|
||||||
func (e TokenError) Error() string {
|
|
||||||
return "expected " + scanner.TokenString(e[0]) +
|
|
||||||
", found " + scanner.TokenString(e[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExprError is an unexpected token encountered while parsing an expression.
|
|
||||||
type ExprError rune
|
|
||||||
|
|
||||||
func (e ExprError) Error() string {
|
|
||||||
return "unexpected token " + scanner.TokenString(rune(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
// must1 returns v, or panics if err is not nil.
|
|
||||||
func must1[T any](v T, err error) T {
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// parser retains the current token.
|
|
||||||
type parser struct {
|
|
||||||
s scanner.Scanner
|
|
||||||
tok rune
|
|
||||||
}
|
|
||||||
|
|
||||||
// scan advances the underlying scanner to the next token, storing its result.
|
|
||||||
func (p *parser) scan() rune { p.tok = p.s.Scan(); return p.tok }
|
|
||||||
|
|
||||||
// expects panics with [TokenError] for an unexpected tok.
|
|
||||||
func (p *parser) expects(expects rune) {
|
|
||||||
if p.tok != expects {
|
|
||||||
panic(TokenError{expects, p.tok})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// scanAs advances the scanner for an expected token.
|
|
||||||
func (p *parser) scanAs(expects rune) { p.scan(); p.expects(expects) }
|
|
||||||
|
|
||||||
// An Int is the value represented by an integer literal.
|
|
||||||
type Int int64
|
|
||||||
|
|
||||||
func (v Int) GoString() string {
|
|
||||||
return "azalea.Int(" + strconv.FormatInt(int64(v), 10) + ")"
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseInt parses the current token as a base 10 representation of a 64-bit
|
|
||||||
// signed integer.
|
|
||||||
func (p *parser) parseInt() Int {
|
|
||||||
v, err := strconv.ParseInt(p.s.TokenText(), 10, 64)
|
|
||||||
return must1(Int(v), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A String holds the unquoted content of a string literal.
|
|
||||||
type String string
|
|
||||||
|
|
||||||
func (v String) GoString() string {
|
|
||||||
return "azalea.String(" + strconv.Quote(string(v)) + ")"
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseString parses the current token as a string.
|
|
||||||
func (p *parser) parseString() String {
|
|
||||||
s, err := strconv.Unquote(p.s.TokenText())
|
|
||||||
return must1(String(s), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// An Ident holds the name of an identifier.
|
|
||||||
type Ident string
|
|
||||||
|
|
||||||
func (v Ident) GoString() string {
|
|
||||||
return "azalea.Ident(" + strconv.Quote(string(v)) + ")"
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Val are statements joined by the '+' operator. Only the [String] type
|
|
||||||
// supports concatenation.
|
|
||||||
type Val []any
|
|
||||||
|
|
||||||
// parseVal parses until the end of the [Val].
|
|
||||||
func (p *parser) parseVal() (v Val) {
|
|
||||||
v = append(v, p.parseExpr())
|
|
||||||
for p.tok == '+' {
|
|
||||||
p.scan()
|
|
||||||
v = append(v, p.parseExpr())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// An Array holds statements in an array.
|
|
||||||
type Array []Val
|
|
||||||
|
|
||||||
// A KV holds a key/value pair.
|
|
||||||
type KV struct {
|
|
||||||
K String
|
|
||||||
V Val
|
|
||||||
}
|
|
||||||
|
|
||||||
// An Arg represents an argument of [Func].
|
|
||||||
type Arg struct {
|
|
||||||
K []Ident
|
|
||||||
V Val
|
|
||||||
R bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Func is a function call or package declaration.
|
|
||||||
type Func struct {
|
|
||||||
// Function or package identifier.
|
|
||||||
Ident Ident
|
|
||||||
// Whether this is a package declaration.
|
|
||||||
Package bool
|
|
||||||
// Key-value arguments.
|
|
||||||
Args []Arg
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseExpr parses the current expression.
|
|
||||||
func (p *parser) parseExpr() any {
|
|
||||||
switch p.tok {
|
|
||||||
case scanner.Int:
|
|
||||||
v := p.parseInt()
|
|
||||||
p.scan()
|
|
||||||
return v
|
|
||||||
|
|
||||||
case scanner.String, scanner.RawString:
|
|
||||||
v := p.parseString()
|
|
||||||
p.scan()
|
|
||||||
return v
|
|
||||||
|
|
||||||
case scanner.Ident:
|
|
||||||
var v Func
|
|
||||||
v.Ident = Ident(p.s.TokenText())
|
|
||||||
if v.Package = v.Ident == "package"; v.Package {
|
|
||||||
p.scanAs(scanner.Ident)
|
|
||||||
v.Ident = Ident(p.s.TokenText())
|
|
||||||
}
|
|
||||||
|
|
||||||
p.scan()
|
|
||||||
switch p.tok {
|
|
||||||
case '{':
|
|
||||||
for {
|
|
||||||
p.scan()
|
|
||||||
switch p.tok {
|
|
||||||
case '}':
|
|
||||||
p.scan()
|
|
||||||
return v
|
|
||||||
|
|
||||||
case scanner.Ident:
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic(TokenError{scanner.Ident, p.tok})
|
|
||||||
}
|
|
||||||
|
|
||||||
arg := Arg{K: []Ident{Ident(p.s.TokenText())}}
|
|
||||||
delim := true
|
|
||||||
arg:
|
|
||||||
for {
|
|
||||||
p.scan()
|
|
||||||
switch p.tok {
|
|
||||||
case ',':
|
|
||||||
if delim {
|
|
||||||
delim = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
panic(ExprError(p.tok))
|
|
||||||
|
|
||||||
case scanner.Ident:
|
|
||||||
if delim {
|
|
||||||
panic(TokenError{',', p.tok})
|
|
||||||
}
|
|
||||||
delim = true
|
|
||||||
arg.K = append(arg.K, Ident(p.s.TokenText()))
|
|
||||||
|
|
||||||
default:
|
|
||||||
break arg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch p.tok {
|
|
||||||
case '=':
|
|
||||||
break
|
|
||||||
|
|
||||||
case '*':
|
|
||||||
arg.R = true
|
|
||||||
p.scanAs('=')
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic(TokenError{'=', p.tok})
|
|
||||||
}
|
|
||||||
p.scan()
|
|
||||||
arg.V = p.parseVal()
|
|
||||||
v.Args = append(v.Args, arg)
|
|
||||||
p.expects(';')
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return v.Ident
|
|
||||||
}
|
|
||||||
|
|
||||||
case '{':
|
|
||||||
var v []KV
|
|
||||||
for {
|
|
||||||
p.scan()
|
|
||||||
switch p.tok {
|
|
||||||
case '}':
|
|
||||||
p.scan()
|
|
||||||
return v
|
|
||||||
|
|
||||||
case scanner.String:
|
|
||||||
pair := KV{K: p.parseString()}
|
|
||||||
p.scan()
|
|
||||||
switch p.tok {
|
|
||||||
case ';':
|
|
||||||
break
|
|
||||||
|
|
||||||
case ':':
|
|
||||||
p.scan()
|
|
||||||
pair.V = p.parseVal()
|
|
||||||
p.expects(';')
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic(ExprError(p.tok))
|
|
||||||
}
|
|
||||||
v = append(v, pair)
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic(ExprError(p.tok))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case '[':
|
|
||||||
var (
|
|
||||||
v Array
|
|
||||||
delim bool
|
|
||||||
)
|
|
||||||
p.scan()
|
|
||||||
for {
|
|
||||||
switch p.tok {
|
|
||||||
case ',':
|
|
||||||
if delim {
|
|
||||||
p.scan()
|
|
||||||
delim = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
panic(ExprError(','))
|
|
||||||
case ']':
|
|
||||||
p.scan()
|
|
||||||
return v
|
|
||||||
case scanner.EOF:
|
|
||||||
panic(ExprError(scanner.EOF))
|
|
||||||
default:
|
|
||||||
if delim {
|
|
||||||
panic(TokenError{',', p.tok})
|
|
||||||
}
|
|
||||||
delim = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
v = append(v, p.parseVal())
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic(ExprError(p.tok))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScanError is the error count parsing all expressions.
|
|
||||||
type ScanError int
|
|
||||||
|
|
||||||
func (ScanError) Error() string {
|
|
||||||
return "aborting due to scanning errors"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse parses expressions from r.
|
|
||||||
func Parse(r io.Reader) (e []any, err error) {
|
|
||||||
var p parser
|
|
||||||
p.s.Init(r)
|
|
||||||
|
|
||||||
p.s.Mode = scanner.ScanIdents |
|
|
||||||
scanner.ScanInts |
|
|
||||||
scanner.ScanStrings |
|
|
||||||
scanner.ScanRawStrings |
|
|
||||||
scanner.ScanComments |
|
|
||||||
scanner.SkipComments
|
|
||||||
p.s.IsIdentRune = func(ch rune, i int) bool {
|
|
||||||
if i == 0 && ch >= '0' && ch <= '9' {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return ch > 0 && ch < rune(len(idents)) && idents[ch]
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
v := recover()
|
|
||||||
if v == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_err, ok := v.(error)
|
|
||||||
if !ok {
|
|
||||||
panic(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
err = _err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = errors.Join(err, _err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
p.scan()
|
|
||||||
for p.tok != scanner.EOF {
|
|
||||||
e = append(e, p.parseExpr())
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.s.ErrorCount != 0 {
|
|
||||||
err = ScanError(p.s.ErrorCount)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
package azalea_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"text/scanner"
|
|
||||||
|
|
||||||
. "hakurei.app/internal/rosa/azalea"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed testdata/gcc.az
|
|
||||||
var sample string
|
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
data string
|
|
||||||
want []any
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{"invalid", "}", nil, ExprError('}')},
|
|
||||||
{"bad sep", "f{v?}", nil, TokenError{'=', '?'}},
|
|
||||||
{"bad ident", "f{9}", nil, TokenError{scanner.Ident, scanner.Int}},
|
|
||||||
{"share bad sep", "f { v,,v = v; }", nil, ExprError(',')},
|
|
||||||
{"share missing sep", "f { v v }", nil, TokenError{',', scanner.Ident}},
|
|
||||||
|
|
||||||
{"ident", `v`, []any{Ident("v")}, nil},
|
|
||||||
{"concat", `f { v = v+"\xfd"+p{}+9; }`, []any{Func{
|
|
||||||
Ident: "f",
|
|
||||||
|
|
||||||
Args: []Arg{{K: []Ident{"v"}, V: Val{
|
|
||||||
Ident("v"),
|
|
||||||
String("\xfd"),
|
|
||||||
Func{Ident: "p"},
|
|
||||||
Int(9),
|
|
||||||
}}},
|
|
||||||
}}, nil},
|
|
||||||
{"truncated string concat", `f { v = v+; }`, nil,
|
|
||||||
ExprError(';')},
|
|
||||||
|
|
||||||
{"empty pairs", `{}`, []any{[]KV(nil)}, nil},
|
|
||||||
{"short kv", `{"\x00":v;}`, []any{[]KV{
|
|
||||||
{K: "\x00", V: Val{Ident("v")}},
|
|
||||||
}}, nil},
|
|
||||||
{"truncated kv", `{"\x00"`, nil, ExprError(scanner.EOF)},
|
|
||||||
{"ident kv", `{v="";}`, nil, ExprError(scanner.Ident)},
|
|
||||||
|
|
||||||
{"empty array", `[]`, []any{Array(nil)}, nil},
|
|
||||||
{"integer array", `[9]`, []any{Array{{Int(9)}}}, nil},
|
|
||||||
{"short array", `[ "\x00" ]`, []any{
|
|
||||||
Array{{String("\x00")}},
|
|
||||||
}, nil},
|
|
||||||
{"short array delim", `[ "\x00", ]`, []any{
|
|
||||||
Array{{String("\x00")}},
|
|
||||||
}, nil},
|
|
||||||
{"missing array value", `[ "\x00", , v ]`, nil, ExprError(',')},
|
|
||||||
{"missing array delimiter", `[ v0 v1 ]`, nil, TokenError{',', scanner.Ident}},
|
|
||||||
{"truncated array", `[ "\x00"`, nil,
|
|
||||||
ExprError(scanner.EOF)},
|
|
||||||
|
|
||||||
{"gcc", sample, []any{Func{
|
|
||||||
Ident: Ident("gcc"),
|
|
||||||
Package: true,
|
|
||||||
|
|
||||||
Args: []Arg{
|
|
||||||
{K: []Ident{Ident("description")}, V: Val{String("The GNU Compiler Collection")}},
|
|
||||||
{K: []Ident{Ident("website")}, V: Val{String("https://www.gnu.org/software/gcc")}},
|
|
||||||
{K: []Ident{Ident("anitya")}, V: Val{Int(6502)}},
|
|
||||||
|
|
||||||
{K: []Ident{Ident("version")}, V: Val{String("16.1.0")}, R: true},
|
|
||||||
{K: []Ident{Ident("source")}, V: Val{Func{
|
|
||||||
Ident: Ident("remoteTar"),
|
|
||||||
|
|
||||||
Args: []Arg{
|
|
||||||
{K: []Ident{Ident("url")}, V: Val{
|
|
||||||
String("https://ftp.tsukuba.wide.ad.jp/software/gcc/releases/"),
|
|
||||||
String("gcc-"),
|
|
||||||
Ident("version"),
|
|
||||||
String("/gcc-"),
|
|
||||||
Ident("version"),
|
|
||||||
String(".tar.gz"),
|
|
||||||
}},
|
|
||||||
{K: []Ident{Ident("checksum")}, V: Val{String("4ASoWbxaA2FW7PAB0zzHDPC5XnNhyaAyjtDPpGzceSLeYnEIXsNYZR3PA_Zu5P0K")}},
|
|
||||||
{K: []Ident{Ident("compress")}, V: Val{Ident("gzip")}},
|
|
||||||
},
|
|
||||||
}}},
|
|
||||||
{K: []Ident{Ident("patches")}, V: Val{Array{
|
|
||||||
{String("musl-off64_t-loff_t.patch")},
|
|
||||||
{String("musl-legacy-lfs.patch")},
|
|
||||||
}}},
|
|
||||||
|
|
||||||
{K: []Ident{Ident("exclusive")}, V: Val{Ident("true")}},
|
|
||||||
|
|
||||||
{K: []Ident{Ident("exec")}, V: Val{Func{
|
|
||||||
Ident: Ident("make"),
|
|
||||||
|
|
||||||
Args: []Arg{
|
|
||||||
{K: []Ident{Ident("configure")}, V: Val{[]KV{
|
|
||||||
{K: String("disable-multilib")},
|
|
||||||
{K: String("enable-default-pie")},
|
|
||||||
{K: String("disable-nls")},
|
|
||||||
{K: String("with-gnu-as")},
|
|
||||||
{K: String("with-gnu-ld")},
|
|
||||||
{K: String("with-system-zlib")},
|
|
||||||
{K: String("enable-languages"), V: Val{String("c,c++,go")}},
|
|
||||||
{K: String("with-native-system-header-dir"), V: Val{String("/system/include")}},
|
|
||||||
{K: String("with-multilib-list"), V: Val{Func{
|
|
||||||
Ident: Ident("arch"),
|
|
||||||
|
|
||||||
Args: []Arg{
|
|
||||||
{K: []Ident{Ident("amd64"), Ident("arm64")}, V: Val{String("''")}},
|
|
||||||
{K: []Ident{Ident("default")}, V: Val{Ident("unset")}},
|
|
||||||
},
|
|
||||||
}}},
|
|
||||||
}}},
|
|
||||||
{K: []Ident{Ident("make")}, V: Val{Array{
|
|
||||||
{String("BOOT_CFLAGS='-O2 -g'")},
|
|
||||||
{
|
|
||||||
Func{Ident: Ident("noop"), Args: []Arg{{K: []Ident{Ident("key")}, V: Val{Ident("value")}}}},
|
|
||||||
String("\x00"),
|
|
||||||
},
|
|
||||||
{String("bootstrap")},
|
|
||||||
}}},
|
|
||||||
|
|
||||||
{K: []Ident{Ident("skip-check")}, V: Val{Ident("true")}},
|
|
||||||
},
|
|
||||||
}}},
|
|
||||||
|
|
||||||
{K: []Ident{Ident("inputs")}, V: Val{Array{
|
|
||||||
{Ident("binutils")},
|
|
||||||
{Ident("mpc")},
|
|
||||||
{Ident("zlib")},
|
|
||||||
{Ident("libucontext")},
|
|
||||||
{Ident("kernel-headers")},
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
}}, nil},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
p, err := Parse(strings.NewReader(tc.data))
|
|
||||||
if !reflect.DeepEqual(p, tc.want) {
|
|
||||||
t.Errorf("Parse: %#v, want %#v", p, tc.want)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(err, tc.err) {
|
|
||||||
t.Errorf("Parse: error = %v, want %v", err, tc.err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkParse(b *testing.B) {
|
|
||||||
r := strings.NewReader(sample)
|
|
||||||
for b.Loop() {
|
|
||||||
if _, err := Parse(r); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b.StopTimer()
|
|
||||||
r.Reset(sample)
|
|
||||||
b.StartTimer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,392 +0,0 @@
|
|||||||
package azalea
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"maps"
|
|
||||||
"reflect"
|
|
||||||
"slices"
|
|
||||||
"unique"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Value are types supported by the language.
|
|
||||||
type Value interface {
|
|
||||||
bool | int64 | string | []string | []int64 | [][2]string
|
|
||||||
}
|
|
||||||
|
|
||||||
type (
|
|
||||||
// FArg is an argument passed to [F].
|
|
||||||
FArg struct {
|
|
||||||
K unique.Handle[Ident]
|
|
||||||
V any
|
|
||||||
R bool
|
|
||||||
}
|
|
||||||
// FArgs are arguments passed to [F].
|
|
||||||
FArgs []FArg
|
|
||||||
|
|
||||||
// PF implements the package declaration function.
|
|
||||||
PF func(name Ident, args FArgs) (v any, set bool, err error)
|
|
||||||
|
|
||||||
// F is the implementation of a [Func].
|
|
||||||
F struct {
|
|
||||||
F func(args FArgs) (v any, set bool, err error)
|
|
||||||
V map[unique.Handle[Ident]]any
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Apply applies named arguments and rejects unused arguments.
|
|
||||||
func (args FArgs) Apply(v map[unique.Handle[Ident]]any) error {
|
|
||||||
for _, arg := range args {
|
|
||||||
if arg.V == nil {
|
|
||||||
// unset
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
r, ok := v[arg.K]
|
|
||||||
if !ok {
|
|
||||||
if arg.R {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return UndefinedError(arg.K.Value())
|
|
||||||
}
|
|
||||||
err := storeE(r, arg.V)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Frame refers to local variables and debugging information.
|
|
||||||
type Frame struct {
|
|
||||||
// Local constants.
|
|
||||||
Val map[unique.Handle[Ident]]any
|
|
||||||
// Functions.
|
|
||||||
Func map[unique.Handle[Ident]]F
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnsupportedExprError is an expression with invalid concrete type.
|
|
||||||
type UnsupportedExprError struct{ E any }
|
|
||||||
|
|
||||||
func (e UnsupportedExprError) Error() string {
|
|
||||||
return fmt.Sprintf("unsupported expression %#v", e.E)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UndefinedError is an identifier not defined in any stack frame visible to the
|
|
||||||
// expression containing it.
|
|
||||||
type UndefinedError Ident
|
|
||||||
|
|
||||||
func (e UndefinedError) Error() string {
|
|
||||||
return "undefined: " + string(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// evaluate is evaluateAny with a type parameter.
|
|
||||||
func evaluate[T Value](d PF, s []Frame, expr any, rp *T) bool {
|
|
||||||
return evaluateAny(d, s, expr, rp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// evaluateArray evaluates expr and returns its values as a slice.
|
|
||||||
func evaluateArray[T Value](d PF, s []Frame, expr Array) []T {
|
|
||||||
r := make([]T, 0, len(expr))
|
|
||||||
for i := range expr {
|
|
||||||
var _r T
|
|
||||||
if evaluate(d, s, expr[i], &_r) {
|
|
||||||
r = append(r, _r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeError is an unexpected type during evaluation.
|
|
||||||
type TypeError struct {
|
|
||||||
Concrete, Asserted reflect.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e TypeError) Error() string {
|
|
||||||
return fmt.Sprintf("expected %s, got %s", e.Asserted, e.Concrete)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e TypeError) Is(err error) bool {
|
|
||||||
var v TypeError
|
|
||||||
return errors.As(err, &v) &&
|
|
||||||
e.Asserted == v.Asserted &&
|
|
||||||
e.Concrete == v.Concrete
|
|
||||||
}
|
|
||||||
|
|
||||||
// storeE is a convenience function to set the value of a result pointer.
|
|
||||||
func storeE(rp any, r any) error {
|
|
||||||
pv := reflect.ValueOf(rp).Elem()
|
|
||||||
v := reflect.ValueOf(r)
|
|
||||||
pt, vt := pv.Type(), v.Type()
|
|
||||||
if !vt.AssignableTo(pt) {
|
|
||||||
return TypeError{vt, pt}
|
|
||||||
}
|
|
||||||
pv.Set(v)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// store is like storeE, but panics if error is non-nil.
|
|
||||||
func store[T Value](rp any, r T) {
|
|
||||||
err := storeE(rp, r)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EvaluationError is an error and the expression it occurred in.
|
|
||||||
type EvaluationError struct {
|
|
||||||
Expr any
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap returns the underlying error.
|
|
||||||
func (e EvaluationError) Unwrap() error { return e.Err }
|
|
||||||
|
|
||||||
// Error returns a very long error description that should not be presented
|
|
||||||
// to the user directly.
|
|
||||||
func (e EvaluationError) Error() string {
|
|
||||||
return fmt.Sprintf("expression %#v: %v", e.Expr, e.Err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// IdentInputs is a special array argument in a package declaration whose
|
|
||||||
// values of [Ident] are kept as is when passed to a [PF].
|
|
||||||
IdentInputs = unique.Make(Ident("inputs"))
|
|
||||||
// IdentRuntime has the same semantics as [IdentInputs].
|
|
||||||
IdentRuntime = unique.Make(Ident("runtime"))
|
|
||||||
// IdentExtra has the same semantics as [IdentInputs].
|
|
||||||
IdentExtra = unique.Make(Ident("extra"))
|
|
||||||
// IdentSource is a special argument in a package declaration where an
|
|
||||||
// assignment of a [Val] with a single [Ident] passes through the evaluator.
|
|
||||||
IdentSource = unique.Make(Ident("source"))
|
|
||||||
|
|
||||||
// ErrInvalidSpecial is panicked for a special [PF] argument sharing its
|
|
||||||
// value or set for R.
|
|
||||||
ErrInvalidSpecial = errors.New("special must not be common or bound to scope")
|
|
||||||
)
|
|
||||||
|
|
||||||
// evaluateAny implements [Evaluate].
|
|
||||||
func evaluateAny(d PF, s []Frame, expr, rp any) bool {
|
|
||||||
defer func() {
|
|
||||||
r := recover()
|
|
||||||
if r == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err, ok := r.(error)
|
|
||||||
if !ok {
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok = err.(EvaluationError); ok {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
panic(EvaluationError{expr, err})
|
|
||||||
}()
|
|
||||||
|
|
||||||
switch e := expr.(type) {
|
|
||||||
case Int:
|
|
||||||
store(rp, int64(e))
|
|
||||||
return true
|
|
||||||
|
|
||||||
case String:
|
|
||||||
store(rp, string(e))
|
|
||||||
return true
|
|
||||||
|
|
||||||
case Ident:
|
|
||||||
var (
|
|
||||||
v any
|
|
||||||
ok bool
|
|
||||||
)
|
|
||||||
for i := range s {
|
|
||||||
v, ok = s[len(s)-1-i].Val[unique.Make(e)]
|
|
||||||
if ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
panic(UndefinedError(e))
|
|
||||||
}
|
|
||||||
if err := storeE(rp, v); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
|
|
||||||
case Val:
|
|
||||||
if len(e) == 1 {
|
|
||||||
switch v := e[0].(type) {
|
|
||||||
case Ident:
|
|
||||||
switch v {
|
|
||||||
case "unset":
|
|
||||||
return false
|
|
||||||
case "true":
|
|
||||||
store(rp, true)
|
|
||||||
return true
|
|
||||||
case "false":
|
|
||||||
store(rp, false)
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return evaluateAny(d, s, v, rp)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return evaluateAny(d, s, e[0], rp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var v string
|
|
||||||
for i := range e {
|
|
||||||
var _r string
|
|
||||||
if evaluate(d, s, e[i], &_r) {
|
|
||||||
v += _r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
store(rp, v)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case Array:
|
|
||||||
if len(e) > 0 && len(e[0]) == 1 {
|
|
||||||
if _, ok := e[0][0].(Int); ok {
|
|
||||||
store(rp, evaluateArray[int64](d, s, e))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
store(rp, evaluateArray[string](d, s, e))
|
|
||||||
return true
|
|
||||||
|
|
||||||
case []KV:
|
|
||||||
r := make([][2]string, 0, len(e))
|
|
||||||
for i := range e {
|
|
||||||
var _r string
|
|
||||||
if e[i].V == nil || evaluate(d, s, e[i].V, &_r) {
|
|
||||||
r = append(r, [2]string{string(e[i].K), _r})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
store(rp, r)
|
|
||||||
return true
|
|
||||||
|
|
||||||
case Func:
|
|
||||||
var (
|
|
||||||
f F
|
|
||||||
ok bool
|
|
||||||
)
|
|
||||||
if !e.Package {
|
|
||||||
for i := range s {
|
|
||||||
f, ok = s[len(s)-1-i].Func[unique.Make(e.Ident)]
|
|
||||||
if ok {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
panic(UndefinedError(e.Ident))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argc := len(e.Args)
|
|
||||||
for _, arg := range e.Args {
|
|
||||||
argc += len(arg.K) - 1
|
|
||||||
}
|
|
||||||
fargs := make([]FArg, 0, len(e.Args))
|
|
||||||
s = append(s, Frame{})
|
|
||||||
fp := &s[len(s)-1]
|
|
||||||
if !e.Package {
|
|
||||||
fp.Val = maps.Clone(f.V)
|
|
||||||
}
|
|
||||||
|
|
||||||
args:
|
|
||||||
for _, arg := range e.Args {
|
|
||||||
names := make([]unique.Handle[Ident], len(arg.K))
|
|
||||||
for i, name := range arg.K {
|
|
||||||
names[i] = unique.Make(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
farg := FArg{R: arg.R}
|
|
||||||
if e.Package {
|
|
||||||
for _, special := range [...]unique.Handle[Ident]{
|
|
||||||
IdentInputs,
|
|
||||||
IdentRuntime,
|
|
||||||
IdentExtra,
|
|
||||||
} {
|
|
||||||
if slices.Contains(names, special) {
|
|
||||||
if len(names) != 1 || len(arg.V) != 1 || arg.R {
|
|
||||||
panic(ErrInvalidSpecial)
|
|
||||||
}
|
|
||||||
farg.K = names[0]
|
|
||||||
if err := storeE(&farg.V, arg.V[0]); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fargs = append(fargs, farg)
|
|
||||||
continue args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if slices.Contains(names, IdentSource) {
|
|
||||||
if len(names) != 1 || len(arg.V) != 1 || arg.R {
|
|
||||||
panic(ErrInvalidSpecial)
|
|
||||||
}
|
|
||||||
if _, ok = arg.V[0].(Ident); ok {
|
|
||||||
farg.K = names[0]
|
|
||||||
if err := storeE(&farg.V, arg.V[0]); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fargs = append(fargs, farg)
|
|
||||||
continue args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !evaluateAny(d, s, arg.V, &farg.V) {
|
|
||||||
farg.V = nil
|
|
||||||
}
|
|
||||||
for _, name := range names {
|
|
||||||
farg.K = name
|
|
||||||
fargs = append(fargs, farg)
|
|
||||||
|
|
||||||
if arg.R && farg.V != nil {
|
|
||||||
if fp.Val == nil {
|
|
||||||
fp.Val = make(map[unique.Handle[Ident]]any)
|
|
||||||
}
|
|
||||||
(*fp).Val[name] = farg.V
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
v any
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if !e.Package {
|
|
||||||
v, ok, err = f.F(fargs)
|
|
||||||
} else {
|
|
||||||
v, ok, err = d(e.Ident, fargs)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
} else if v != nil {
|
|
||||||
if err = storeE(rp, v); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ok
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic(UnsupportedExprError{expr})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate evaluates a statement and returns its value.
|
|
||||||
func Evaluate[T any](d PF, s []Frame, expr any) (v T, set bool, err error) {
|
|
||||||
defer func() {
|
|
||||||
r := recover()
|
|
||||||
if r == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_err, ok := r.(error)
|
|
||||||
if !ok {
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
err = _err
|
|
||||||
}()
|
|
||||||
set = evaluateAny(d, s, expr, &v)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,407 +0,0 @@
|
|||||||
package azalea_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"unique"
|
|
||||||
|
|
||||||
. "hakurei.app/internal/rosa/azalea"
|
|
||||||
)
|
|
||||||
|
|
||||||
// makeStackCheck creates a stack with a single frame with a single function "f"
|
|
||||||
// which calls the check function internally.
|
|
||||||
func makeStackCheck(check func(args FArgs) (any, error)) []Frame {
|
|
||||||
return []Frame{{Func: map[unique.Handle[Ident]]F{
|
|
||||||
unique.Make(Ident("f")): {F: func(
|
|
||||||
args FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
set = true
|
|
||||||
v, err = check(args)
|
|
||||||
return
|
|
||||||
}},
|
|
||||||
}}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkArgs is like makeStackCheck, but the resulting function asserts that its
|
|
||||||
// args match the expected value.
|
|
||||||
func checkArgs(want FArgs) []Frame {
|
|
||||||
return makeStackCheck(func(args FArgs) (any, error) {
|
|
||||||
if !reflect.DeepEqual(args, want) {
|
|
||||||
return nil, fmt.Errorf("%#v, want %#v", args, want)
|
|
||||||
}
|
|
||||||
return "\xfd", nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEvaluate(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
data string
|
|
||||||
s []Frame
|
|
||||||
want any
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{"apply unset", `f { v = unset; }`, makeStackCheck(func(
|
|
||||||
args FArgs,
|
|
||||||
) (v any, err error) {
|
|
||||||
v = "\xfd"
|
|
||||||
err = args.Apply(map[unique.Handle[Ident]]any{
|
|
||||||
unique.Make(Ident("v")): &v,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}), "\xfd", nil},
|
|
||||||
|
|
||||||
{"apply bad type", `f { v = 9; }`, makeStackCheck(func(
|
|
||||||
args FArgs,
|
|
||||||
) (v any, err error) {
|
|
||||||
v = "\xfd"
|
|
||||||
err = args.Apply(map[unique.Handle[Ident]]any{
|
|
||||||
unique.Make(Ident("v")): &v,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}), "", TypeError{
|
|
||||||
Concrete: reflect.TypeFor[int64](),
|
|
||||||
Asserted: reflect.TypeFor[string](),
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"apply undefined", `f { v = 9; }`, makeStackCheck(func(
|
|
||||||
args FArgs,
|
|
||||||
) (v any, err error) {
|
|
||||||
v = "\xfd"
|
|
||||||
err = args.Apply(map[unique.Handle[Ident]]any{})
|
|
||||||
return
|
|
||||||
}), "", EvaluationError{
|
|
||||||
Expr: Func{
|
|
||||||
Ident: Ident("f"),
|
|
||||||
Args: []Arg{
|
|
||||||
{K: []Ident{"v"}, V: Val{Int(9)}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Err: UndefinedError("v"),
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"apply bound undefined", `f { _v* = "\x00"; v = _v; }`, makeStackCheck(func(
|
|
||||||
args FArgs,
|
|
||||||
) (v any, err error) {
|
|
||||||
v = "\xfd"
|
|
||||||
err = args.Apply(map[unique.Handle[Ident]]any{
|
|
||||||
unique.Make(Ident("v")): &v,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}), "\x00", nil},
|
|
||||||
|
|
||||||
{"undefined function", `f {}`, nil, "", EvaluationError{
|
|
||||||
Expr: Func{Ident: "f"},
|
|
||||||
Err: UndefinedError("f"),
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"error wrap deep", `f { v = nil; }`, makeStackCheck(func(
|
|
||||||
FArgs,
|
|
||||||
) (any, error) {
|
|
||||||
panic("unreachable")
|
|
||||||
}), "", EvaluationError{
|
|
||||||
Expr: Ident("nil"),
|
|
||||||
Err: UndefinedError("nil"),
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"common inputs", `package name { inputs, v = []; }`, nil, "", EvaluationError{
|
|
||||||
Expr: Func{
|
|
||||||
Ident: Ident("name"),
|
|
||||||
Package: true,
|
|
||||||
|
|
||||||
Args: []Arg{
|
|
||||||
{K: []Ident{
|
|
||||||
"inputs",
|
|
||||||
"v",
|
|
||||||
}, V: Val{Array(nil)}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Err: ErrInvalidSpecial,
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"bound inputs", `package name { inputs* = []; }`, nil, "", EvaluationError{
|
|
||||||
Expr: Func{
|
|
||||||
Ident: Ident("name"),
|
|
||||||
Package: true,
|
|
||||||
|
|
||||||
Args: []Arg{
|
|
||||||
{K: []Ident{"inputs"}, V: Val{Array(nil)}, R: true},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Err: ErrInvalidSpecial,
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"bound runtime", `package name { runtime* = []; }`, nil, "", EvaluationError{
|
|
||||||
Expr: Func{
|
|
||||||
Ident: Ident("name"),
|
|
||||||
Package: true,
|
|
||||||
|
|
||||||
Args: []Arg{
|
|
||||||
{K: []Ident{"runtime"}, V: Val{Array(nil)}, R: true},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Err: ErrInvalidSpecial,
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"concat inputs", `package name { inputs = ""+""; }`, nil, "", EvaluationError{
|
|
||||||
Expr: Func{
|
|
||||||
Ident: Ident("name"),
|
|
||||||
Package: true,
|
|
||||||
|
|
||||||
Args: []Arg{
|
|
||||||
{K: []Ident{"inputs"}, V: Val{String(""), String("")}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Err: ErrInvalidSpecial,
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"concat source", `package name { source = ""+""; }`, nil, "", EvaluationError{
|
|
||||||
Expr: Func{
|
|
||||||
Ident: Ident("name"),
|
|
||||||
Package: true,
|
|
||||||
|
|
||||||
Args: []Arg{
|
|
||||||
{K: []Ident{"source"}, V: Val{String(""), String("")}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Err: ErrInvalidSpecial,
|
|
||||||
}},
|
|
||||||
|
|
||||||
{"source handle", `package name { source = name; }`, nil, FArgs{
|
|
||||||
{K: unique.Make(Ident("source")), V: Ident("name")},
|
|
||||||
}, nil},
|
|
||||||
|
|
||||||
{"integer array", `f { v = [ 0 ]; _v = [ 0, 9 ]; }`, checkArgs(FArgs{
|
|
||||||
{K: unique.Make(Ident("v")), V: []int64{0}},
|
|
||||||
{K: unique.Make(Ident("_v")), V: []int64{0, 9}},
|
|
||||||
}), "\xfd", nil},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
var expr Func
|
|
||||||
if e, err := Parse(strings.NewReader(tc.data)); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
} else if len(e) != 1 {
|
|
||||||
t.Fatalf("got expression %#v", e)
|
|
||||||
} else {
|
|
||||||
expr = e[0].(Func)
|
|
||||||
}
|
|
||||||
const rPackage = "\xff\xff\xff\xff"
|
|
||||||
r, set, err := Evaluate[string](func(
|
|
||||||
name Ident,
|
|
||||||
args FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
v = rPackage
|
|
||||||
if !reflect.DeepEqual(args, tc.want) {
|
|
||||||
err = fmt.Errorf("%#v, want %#v", args, tc.want)
|
|
||||||
}
|
|
||||||
set = true
|
|
||||||
return
|
|
||||||
}, tc.s, expr)
|
|
||||||
if set != (err == nil) {
|
|
||||||
t.Error("Evaluate: unexpected unset")
|
|
||||||
}
|
|
||||||
|
|
||||||
if r != rPackage && r != tc.want {
|
|
||||||
t.Errorf("Evaluate: %q, want %q", r, tc.want)
|
|
||||||
}
|
|
||||||
|
|
||||||
var errEquals bool
|
|
||||||
if errors.As(err, new(TypeError)) {
|
|
||||||
errEquals = errors.Is(err, tc.err)
|
|
||||||
} else {
|
|
||||||
errEquals = reflect.DeepEqual(err, tc.err)
|
|
||||||
}
|
|
||||||
if !errEquals {
|
|
||||||
t.Errorf("Evaluate: error = %v, want %v", err, tc.err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEvaluateGCC(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
var gcc Func
|
|
||||||
if e, err := Parse(strings.NewReader(sample)); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
} else {
|
|
||||||
gcc = e[0].(Func)
|
|
||||||
}
|
|
||||||
|
|
||||||
var got [3]FArgs
|
|
||||||
if r, set, err := Evaluate[string](func(
|
|
||||||
name Ident,
|
|
||||||
args FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
v = "\x00"
|
|
||||||
set = true
|
|
||||||
got[0] = args
|
|
||||||
return
|
|
||||||
}, []Frame{{
|
|
||||||
Func: map[unique.Handle[Ident]]F{
|
|
||||||
unique.Make(Ident("remoteTar")): {F: func(
|
|
||||||
args FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
var url, checksum string
|
|
||||||
var compress int
|
|
||||||
if err = args.Apply(map[unique.Handle[Ident]]any{
|
|
||||||
unique.Make(Ident("url")): &url,
|
|
||||||
unique.Make(Ident("checksum")): &checksum,
|
|
||||||
unique.Make(Ident("compress")): &compress,
|
|
||||||
}); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if compress != 0xcafe {
|
|
||||||
err = fmt.Errorf("unexpected compress %#v", compress)
|
|
||||||
}
|
|
||||||
set = true
|
|
||||||
v = url + "?checksum=" + checksum
|
|
||||||
return
|
|
||||||
}, V: map[unique.Handle[Ident]]any{
|
|
||||||
unique.Make(Ident("gzip")): 0xcafe,
|
|
||||||
}},
|
|
||||||
|
|
||||||
unique.Make(Ident("make")): {F: func(
|
|
||||||
args FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
v = args
|
|
||||||
set = true
|
|
||||||
return
|
|
||||||
}},
|
|
||||||
|
|
||||||
unique.Make(Ident("arch")): {F: func(
|
|
||||||
args FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
set = false
|
|
||||||
got[1] = args
|
|
||||||
return
|
|
||||||
}},
|
|
||||||
|
|
||||||
unique.Make(Ident("noop")): {F: func(
|
|
||||||
args FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
set = false
|
|
||||||
set = true
|
|
||||||
got[2] = args
|
|
||||||
return
|
|
||||||
}, V: map[unique.Handle[Ident]]any{
|
|
||||||
unique.Make(Ident("value")): "\xfd",
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}}, gcc); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
} else if r != "\x00" {
|
|
||||||
t.Fatalf("package: %q", r)
|
|
||||||
} else if !set {
|
|
||||||
t.Fatal("package: unset")
|
|
||||||
}
|
|
||||||
|
|
||||||
want := [...]FArgs{
|
|
||||||
{
|
|
||||||
{K: unique.Make(Ident("description")), V: "The GNU Compiler Collection"},
|
|
||||||
{K: unique.Make(Ident("website")), V: "https://www.gnu.org/software/gcc"},
|
|
||||||
{K: unique.Make(Ident("anitya")), V: int64(6502)},
|
|
||||||
|
|
||||||
{K: unique.Make(Ident("version")), V: "16.1.0", R: true},
|
|
||||||
{K: unique.Make(Ident("source")), V: "https://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-16.1.0/gcc-16.1.0.tar.gz?checksum=4ASoWbxaA2FW7PAB0zzHDPC5XnNhyaAyjtDPpGzceSLeYnEIXsNYZR3PA_Zu5P0K"},
|
|
||||||
{K: unique.Make(Ident("patches")), V: []string{"musl-off64_t-loff_t.patch", "musl-legacy-lfs.patch"}},
|
|
||||||
|
|
||||||
{K: unique.Make(Ident("exclusive")), V: true},
|
|
||||||
{K: unique.Make(Ident("exec")), V: FArgs{
|
|
||||||
{K: unique.Make(Ident("configure")), V: [][2]string{
|
|
||||||
{"disable-multilib", ""},
|
|
||||||
{"enable-default-pie", ""},
|
|
||||||
{"disable-nls", ""},
|
|
||||||
{"with-gnu-as", ""},
|
|
||||||
{"with-gnu-ld", ""},
|
|
||||||
{"with-system-zlib", ""},
|
|
||||||
{"enable-languages", "c,c++,go"},
|
|
||||||
{"with-native-system-header-dir", "/system/include"},
|
|
||||||
}},
|
|
||||||
{K: unique.Make(Ident("make")), V: []string{
|
|
||||||
"BOOT_CFLAGS='-O2 -g'",
|
|
||||||
"\x00",
|
|
||||||
"bootstrap",
|
|
||||||
}},
|
|
||||||
{K: unique.Make(Ident("skip-check")), V: true},
|
|
||||||
}},
|
|
||||||
|
|
||||||
{K: unique.Make(Ident("inputs")), V: Array{
|
|
||||||
{Ident("binutils")},
|
|
||||||
{Ident("mpc")},
|
|
||||||
{Ident("zlib")},
|
|
||||||
{Ident("libucontext")},
|
|
||||||
{Ident("kernel-headers")},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{K: unique.Make(Ident("amd64")), V: "''"},
|
|
||||||
{K: unique.Make(Ident("arm64")), V: "''"},
|
|
||||||
{K: unique.Make(Ident("default"))},
|
|
||||||
},
|
|
||||||
{{K: unique.Make(Ident("key")), V: "\xfd"}},
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
|
||||||
t.Errorf("package: args = %#v, want %#v", got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkEvaluate(b *testing.B) {
|
|
||||||
var gcc Func
|
|
||||||
if e, err := Parse(strings.NewReader(sample)); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
} else {
|
|
||||||
gcc = e[0].(Func)
|
|
||||||
}
|
|
||||||
|
|
||||||
s := []Frame{{
|
|
||||||
Func: map[unique.Handle[Ident]]F{
|
|
||||||
unique.Make(Ident("remoteTar")): {F: func(
|
|
||||||
FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
return
|
|
||||||
}, V: map[unique.Handle[Ident]]any{
|
|
||||||
unique.Make(Ident("gzip")): 0xcafe,
|
|
||||||
}},
|
|
||||||
|
|
||||||
unique.Make(Ident("make")): {F: func(
|
|
||||||
FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
return
|
|
||||||
}},
|
|
||||||
|
|
||||||
unique.Make(Ident("arch")): {F: func(
|
|
||||||
FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
return
|
|
||||||
}},
|
|
||||||
|
|
||||||
unique.Make(Ident("noop")): {F: func(
|
|
||||||
FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
return
|
|
||||||
}, V: map[unique.Handle[Ident]]any{
|
|
||||||
unique.Make(Ident("value")): "\xfd",
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
for b.Loop() {
|
|
||||||
if _, _, err := Evaluate[string](func(
|
|
||||||
Ident,
|
|
||||||
FArgs,
|
|
||||||
) (v any, set bool, err error) {
|
|
||||||
return
|
|
||||||
}, s, gcc); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-57
@@ -1,57 +0,0 @@
|
|||||||
package gcc {
|
|
||||||
description = "The GNU Compiler Collection";
|
|
||||||
website = "https://www.gnu.org/software/gcc";
|
|
||||||
anitya = 6502;
|
|
||||||
|
|
||||||
version* = "16.1.0";
|
|
||||||
source = remoteTar {
|
|
||||||
url = "https://ftp.tsukuba.wide.ad.jp/software/gcc/releases/"+
|
|
||||||
"gcc-"+version+"/gcc-"+version+".tar.gz";
|
|
||||||
checksum = "4ASoWbxaA2FW7PAB0zzHDPC5XnNhyaAyjtDPpGzceSLeYnEIXsNYZR3PA_Zu5P0K";
|
|
||||||
compress = gzip;
|
|
||||||
};
|
|
||||||
patches = [
|
|
||||||
"musl-off64_t-loff_t.patch",
|
|
||||||
"musl-legacy-lfs.patch",
|
|
||||||
];
|
|
||||||
|
|
||||||
// GCC spends most of its time in its many configure scripts, however
|
|
||||||
// it also saturates the CPU for a consequential amount of time.
|
|
||||||
exclusive = true;
|
|
||||||
|
|
||||||
exec = make {
|
|
||||||
configure = {
|
|
||||||
"disable-multilib";
|
|
||||||
"enable-default-pie";
|
|
||||||
"disable-nls";
|
|
||||||
"with-gnu-as";
|
|
||||||
"with-gnu-ld";
|
|
||||||
"with-system-zlib";
|
|
||||||
"enable-languages": "c,c++,go";
|
|
||||||
"with-native-system-header-dir": "/system/include";
|
|
||||||
"with-multilib-list": arch {
|
|
||||||
amd64, arm64 = "''";
|
|
||||||
default = unset;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
make = [
|
|
||||||
"BOOT_CFLAGS='-O2 -g'",
|
|
||||||
noop { key = value; } + "\x00",
|
|
||||||
"bootstrap",
|
|
||||||
];
|
|
||||||
|
|
||||||
// This toolchain is hacked to pieces, it is not expected to ever work
|
|
||||||
// well in its current state. That does not matter as long as the
|
|
||||||
// toolchain it produces passes its own test suite.
|
|
||||||
skip-check = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
inputs = [
|
|
||||||
binutils,
|
|
||||||
|
|
||||||
mpc,
|
|
||||||
zlib,
|
|
||||||
libucontext,
|
|
||||||
kernel-headers,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package rosa
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path"
|
|
||||||
"slices"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"hakurei.app/internal/pkg"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// jobsE is expression for preferred job count set by [pkg].
|
|
||||||
jobsE = `"$` + pkg.EnvJobs + `"`
|
|
||||||
// jobsFlagE is expression for flag with preferred job count.
|
|
||||||
jobsFlagE = `"-j$` + pkg.EnvJobs + `"`
|
|
||||||
// jobsLE is expression for twice of preferred job count set by [pkg].
|
|
||||||
jobsLE = `"$(expr ` + jobsE + ` '*' 2)"`
|
|
||||||
// jobsLFlagE is expression for flag with double of preferred job count.
|
|
||||||
jobsLFlagE = `"-j$(expr ` + jobsE + ` '*' 2)"`
|
|
||||||
)
|
|
||||||
|
|
||||||
// newTar wraps [pkg.NewHTTPGetTar] with a simpler function signature.
|
|
||||||
func newTar(url, checksum string, compression uint32) pkg.Artifact {
|
|
||||||
return pkg.NewHTTPGetTar(nil, url, mustDecode(checksum), compression)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newFromCPAN is a helper for downloading release from CPAN.
|
|
||||||
func newFromCPAN(author, name, version, checksum string) pkg.Artifact {
|
|
||||||
return newTar(
|
|
||||||
"https://cpan.metacpan.org/authors/id/"+
|
|
||||||
author[:1]+"/"+author[:2]+"/"+author+"/"+
|
|
||||||
name+"-"+version+".tar.gz",
|
|
||||||
checksum,
|
|
||||||
pkg.TarGzip,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newFromGitLab is a helper for downloading source from GitLab.
|
|
||||||
func newFromGitLab(domain, suffix, ref, checksum string) pkg.Artifact {
|
|
||||||
return newTar(
|
|
||||||
"https://"+domain+"/"+suffix+"/-/archive/"+
|
|
||||||
ref+"/"+path.Base(suffix)+"-"+
|
|
||||||
strings.ReplaceAll(ref, "/", "-")+".tar.bz2",
|
|
||||||
checksum,
|
|
||||||
pkg.TarBzip2,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newFromGitHub is a helper for downloading source from Microsoft Github.
|
|
||||||
func newFromGitHub(suffix, tag, checksum string) pkg.Artifact {
|
|
||||||
return newTar(
|
|
||||||
"https://github.com/"+suffix+
|
|
||||||
"/archive/refs/tags/"+tag+".tar.gz",
|
|
||||||
checksum,
|
|
||||||
pkg.TarGzip,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newFromGitHubRelease is a helper for downloading release tarball from
|
|
||||||
// Microsoft Github.
|
|
||||||
func newFromGitHubRelease(
|
|
||||||
suffix, tag, name, checksum string,
|
|
||||||
compression uint32,
|
|
||||||
) pkg.Artifact {
|
|
||||||
return newTar(
|
|
||||||
"https://github.com/"+suffix+
|
|
||||||
"/releases/download/"+tag+"/"+name,
|
|
||||||
checksum,
|
|
||||||
compression,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 ...int64) 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(int(n - 1)))
|
|
||||||
buf.WriteString(" ")
|
|
||||||
}
|
|
||||||
if i == len(tests)-1 || tests[i+1] != n+1 {
|
|
||||||
buf.WriteString(strconv.Itoa(int(n + 1)))
|
|
||||||
buf.WriteString("-")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package rosa
|
|
||||||
|
|
||||||
import (
|
|
||||||
"slices"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSkipGNUTests(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
tests []int64
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{[]int64{764}, "1-763 765-"},
|
|
||||||
{[]int64{764, 0xcafe, 37, 9}, "1-8 10-36 38-763 765-51965 51967-"},
|
|
||||||
{[]int64{1, 2, 0xbed}, "3-3052 3054-"},
|
|
||||||
{[]int64{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(int(n)))
|
|
||||||
}
|
|
||||||
}), ","), func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
if got := skipGNUTests(tc.tests...); got != tc.want {
|
|
||||||
t.Errorf("skipGNUTests: %q, want %q", got, tc.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/fhs"
|
"hakurei.app/fhs"
|
||||||
@@ -85,13 +86,13 @@ func (a busyboxBin) Cure(t *pkg.TContext) (err error) {
|
|||||||
|
|
||||||
// newBusyboxBin returns a [pkg.Artifact] containing a busybox installation from
|
// newBusyboxBin returns a [pkg.Artifact] containing a busybox installation from
|
||||||
// the https://busybox.net/downloads/binaries/ binary release.
|
// the https://busybox.net/downloads/binaries/ binary release.
|
||||||
func (s *S) newBusyboxBin() pkg.Artifact {
|
func newBusyboxBin() pkg.Artifact {
|
||||||
var version, url, checksum string
|
var version, url, checksum string
|
||||||
switch s.arch {
|
switch runtime.GOARCH {
|
||||||
case "amd64":
|
case "amd64":
|
||||||
version = "1.35.0"
|
version = "1.35.0"
|
||||||
url = "https://busybox.net/downloads/binaries/" +
|
url = "https://busybox.net/downloads/binaries/" +
|
||||||
version + "-" + s.linuxArch() + "-linux-musl/busybox"
|
version + "-" + linuxArch() + "-linux-musl/busybox"
|
||||||
checksum = "L7OBIsPu9enNHn7FqpBT1kOg_mCLNmetSeNMA3i4Y60Z5jTgnlX3qX3zcQtLx5AB"
|
checksum = "L7OBIsPu9enNHn7FqpBT1kOg_mCLNmetSeNMA3i4Y60Z5jTgnlX3qX3zcQtLx5AB"
|
||||||
case "arm64":
|
case "arm64":
|
||||||
version = "1.31.0"
|
version = "1.31.0"
|
||||||
@@ -100,11 +101,11 @@ func (s *S) newBusyboxBin() pkg.Artifact {
|
|||||||
checksum = "npJjBO7iwhjW6Kx2aXeSxf8kXhVgTCDChOZTTsI8ZfFfa3tbsklxRiidZQdrVERg"
|
checksum = "npJjBO7iwhjW6Kx2aXeSxf8kXhVgTCDChOZTTsI8ZfFfa3tbsklxRiidZQdrVERg"
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("unsupported target " + s.arch)
|
panic("unsupported target " + runtime.GOARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pkg.NewExec(
|
return pkg.NewExec(
|
||||||
"busybox-bin-"+version, s.arch, nil, pkg.ExecTimeoutMax, false, false,
|
"busybox-bin-"+version, nil, pkg.ExecTimeoutMax, false,
|
||||||
fhs.AbsRoot, []string{
|
fhs.AbsRoot, []string{
|
||||||
"PATH=/system/bin",
|
"PATH=/system/bin",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newBzip2() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "1.0.8"
|
||||||
|
checksum = "cTLykcco7boom-s05H1JVsQi1AtChYL84nXkg_92Dm1Xt94Ob_qlMg_-NSguIK-c"
|
||||||
|
)
|
||||||
|
return t.NewPackage("bzip2", version, newTar(
|
||||||
|
"https://sourceware.org/pub/bzip2/bzip2-"+version+".tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
), &PackageAttr{
|
||||||
|
Writable: true,
|
||||||
|
EnterSource: true,
|
||||||
|
}, &MakeHelper{
|
||||||
|
// uses source tree as scratch space
|
||||||
|
SkipConfigure: true,
|
||||||
|
SkipCheck: true,
|
||||||
|
InPlace: true,
|
||||||
|
Make: []string{
|
||||||
|
"CC=cc",
|
||||||
|
},
|
||||||
|
Install: "make PREFIX=/work/system install",
|
||||||
|
}), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Bzip2] = Metadata{
|
||||||
|
f: Toolchain.newBzip2,
|
||||||
|
|
||||||
|
Name: "bzip2",
|
||||||
|
Description: "a freely available, patent free, high-quality data compressor",
|
||||||
|
Website: "https://sourceware.org/bzip2/",
|
||||||
|
|
||||||
|
ID: 237,
|
||||||
|
}
|
||||||
|
}
|
||||||
+127
-35
@@ -4,30 +4,129 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"hakurei.app/internal/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func (t Toolchain) newCMake() (pkg.Artifact, string) {
|
||||||
_cmake = H("cmake")
|
const (
|
||||||
_ninja = H("ninja")
|
version = "4.3.1"
|
||||||
)
|
checksum = "RHpzZiM1kJ5bwLjo9CpXSeHJJg3hTtV9QxBYpQoYwKFtRh5YhGWpShrqZCSOzQN6"
|
||||||
|
)
|
||||||
|
return t.NewPackage("cmake", version, newFromGitHubRelease(
|
||||||
|
"Kitware/CMake",
|
||||||
|
"v"+version,
|
||||||
|
"cmake-"+version+".tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
), &PackageAttr{
|
||||||
|
// test suite expects writable source tree
|
||||||
|
Writable: true,
|
||||||
|
|
||||||
|
// expected to be writable in the copy made during bootstrap
|
||||||
|
Chmod: true,
|
||||||
|
|
||||||
|
Patches: []KV{
|
||||||
|
{"bootstrap-test-no-openssl", `diff --git a/Tests/BootstrapTest.cmake b/Tests/BootstrapTest.cmake
|
||||||
|
index 137de78bc1..b4da52e664 100644
|
||||||
|
--- a/Tests/BootstrapTest.cmake
|
||||||
|
+++ b/Tests/BootstrapTest.cmake
|
||||||
|
@@ -9,7 +9,7 @@ if(NOT nproc EQUAL 0)
|
||||||
|
endif()
|
||||||
|
message(STATUS "running bootstrap: ${bootstrap} ${ninja_arg} ${parallel_arg}")
|
||||||
|
execute_process(
|
||||||
|
- COMMAND ${bootstrap} ${ninja_arg} ${parallel_arg}
|
||||||
|
+ COMMAND ${bootstrap} ${ninja_arg} ${parallel_arg} -- -DCMAKE_USE_OPENSSL=OFF
|
||||||
|
WORKING_DIRECTORY "${bin_dir}"
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
`},
|
||||||
|
|
||||||
|
{"disable-broken-tests-musl", `diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
|
||||||
|
index 2ead810437..f85cbb8b1c 100644
|
||||||
|
--- a/Tests/CMakeLists.txt
|
||||||
|
+++ b/Tests/CMakeLists.txt
|
||||||
|
@@ -384,7 +384,6 @@ if(BUILD_TESTING)
|
||||||
|
add_subdirectory(CMakeLib)
|
||||||
|
endif()
|
||||||
|
add_subdirectory(CMakeOnly)
|
||||||
|
- add_subdirectory(RunCMake)
|
||||||
|
|
||||||
|
add_subdirectory(FindPackageModeMakefileTest)
|
||||||
|
|
||||||
|
@@ -528,9 +527,6 @@ if(BUILD_TESTING)
|
||||||
|
-DCMake_TEST_CUDA:BOOL=${CMake_TEST_CUDA}
|
||||||
|
-DCMake_INSTALL_NAME_TOOL_BUG:BOOL=${CMake_INSTALL_NAME_TOOL_BUG}
|
||||||
|
)
|
||||||
|
- ADD_TEST_MACRO(ExportImport ExportImport)
|
||||||
|
- set_property(TEST ExportImport APPEND
|
||||||
|
- PROPERTY LABELS "CUDA")
|
||||||
|
ADD_TEST_MACRO(Unset Unset)
|
||||||
|
ADD_TEST_MACRO(PolicyScope PolicyScope)
|
||||||
|
ADD_TEST_MACRO(EmptyLibrary EmptyLibrary)
|
||||||
|
@@ -624,7 +620,6 @@ if(BUILD_TESTING)
|
||||||
|
# run test for BundleUtilities on supported platforms/compilers
|
||||||
|
if((MSVC OR
|
||||||
|
MINGW OR
|
||||||
|
- CMAKE_SYSTEM_NAME MATCHES "Linux" OR
|
||||||
|
CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||||
|
AND NOT CMAKE_GENERATOR STREQUAL "Watcom WMake")
|
||||||
|
|
||||||
|
@@ -3095,10 +3090,6 @@ if(BUILD_TESTING)
|
||||||
|
"${CMake_SOURCE_DIR}/Tests/CTestTestFdSetSize/test.cmake.in"
|
||||||
|
"${CMake_BINARY_DIR}/Tests/CTestTestFdSetSize/test.cmake"
|
||||||
|
@ONLY ESCAPE_QUOTES)
|
||||||
|
- add_test(CTestTestFdSetSize ${CMAKE_CTEST_COMMAND}
|
||||||
|
- -S "${CMake_BINARY_DIR}/Tests/CTestTestFdSetSize/test.cmake" -j20 -V --timeout 120
|
||||||
|
- --output-log "${CMake_BINARY_DIR}/Tests/CTestTestFdSetSize/testOutput.log"
|
||||||
|
- )
|
||||||
|
|
||||||
|
if(CMAKE_TESTS_CDASH_SERVER)
|
||||||
|
set(regex "^([^:]+)://([^/]+)(.*)$")
|
||||||
|
`},
|
||||||
|
},
|
||||||
|
}, &MakeHelper{
|
||||||
|
OmitDefaults: true,
|
||||||
|
|
||||||
|
ConfigureName: "/usr/src/cmake/bootstrap",
|
||||||
|
Configure: []KV{
|
||||||
|
{"prefix", "/system"},
|
||||||
|
{"parallel", jobsE},
|
||||||
|
{"--"},
|
||||||
|
{"-DCMAKE_USE_OPENSSL", "OFF"},
|
||||||
|
{"-DCMake_TEST_NO_NETWORK", "ON"},
|
||||||
|
},
|
||||||
|
Check: []string{
|
||||||
|
"CTEST_OUTPUT_ON_FAILURE=1",
|
||||||
|
"CTEST_PARALLEL_LEVEL=128",
|
||||||
|
"test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
KernelHeaders,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[CMake] = Metadata{
|
||||||
|
f: Toolchain.newCMake,
|
||||||
|
|
||||||
|
Name: "cmake",
|
||||||
|
Description: "cross-platform, open-source build system",
|
||||||
|
Website: "https://cmake.org/",
|
||||||
|
|
||||||
|
ID: 306,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CMakeHelper is the [CMake] build system helper.
|
// CMakeHelper is the [CMake] build system helper.
|
||||||
type CMakeHelper struct {
|
type CMakeHelper struct {
|
||||||
// Path elements joined with source.
|
// Path elements joined with source.
|
||||||
Append []string
|
Append []string
|
||||||
|
|
||||||
// Value of CMAKE_BUILD_TYPE. The zero value is equivalent to "Release".
|
|
||||||
BuildType string
|
|
||||||
// CMake CACHE entries.
|
// CMake CACHE entries.
|
||||||
Cache []KV
|
Cache []KV
|
||||||
// Runs after install.
|
// Runs after install.
|
||||||
Script string
|
Script string
|
||||||
|
|
||||||
// Replaces the default test command.
|
|
||||||
Test string
|
|
||||||
// Whether to skip running tests.
|
|
||||||
SkipTest bool
|
|
||||||
|
|
||||||
// Whether to generate Makefile instead.
|
// Whether to generate Makefile instead.
|
||||||
Make bool
|
Make bool
|
||||||
}
|
}
|
||||||
@@ -37,9 +136,9 @@ var _ Helper = new(CMakeHelper)
|
|||||||
// extra returns a hardcoded slice of [CMake] and [Ninja].
|
// extra returns a hardcoded slice of [CMake] and [Ninja].
|
||||||
func (attr *CMakeHelper) extra(int) P {
|
func (attr *CMakeHelper) extra(int) P {
|
||||||
if attr != nil && attr.Make {
|
if attr != nil && attr.Make {
|
||||||
return P{_cmake, _make}
|
return P{CMake, Make}
|
||||||
}
|
}
|
||||||
return P{_cmake, _ninja}
|
return P{CMake, Ninja}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wantsChmod returns false.
|
// wantsChmod returns false.
|
||||||
@@ -51,36 +150,29 @@ func (*CMakeHelper) wantsWrite() bool { return false }
|
|||||||
// scriptEarly returns the zero value.
|
// scriptEarly returns the zero value.
|
||||||
func (*CMakeHelper) scriptEarly() string { return "" }
|
func (*CMakeHelper) scriptEarly() string { return "" }
|
||||||
|
|
||||||
|
// createDir returns true.
|
||||||
|
func (*CMakeHelper) createDir() bool { return true }
|
||||||
|
|
||||||
// wantsDir returns a hardcoded, deterministic pathname.
|
// wantsDir returns a hardcoded, deterministic pathname.
|
||||||
func (*CMakeHelper) wantsDir() (string, bool) { return "/cure/", true }
|
func (*CMakeHelper) wantsDir() string { return "/cure/" }
|
||||||
|
|
||||||
// script generates the cure script.
|
// script generates the cure script.
|
||||||
func (attr *CMakeHelper) script(t Toolchain, name string) string {
|
func (attr *CMakeHelper) script(name string) string {
|
||||||
if attr == nil {
|
if attr == nil {
|
||||||
attr = new(CMakeHelper)
|
attr = &CMakeHelper{
|
||||||
|
Cache: []KV{
|
||||||
|
{"CMAKE_BUILD_TYPE", "Release"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(attr.Cache) == 0 {
|
||||||
|
panic("CACHE must be non-empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
generate := "Ninja"
|
generate := "Ninja"
|
||||||
test := "ninja " + jobsFlagE + " test"
|
|
||||||
if attr.Make {
|
if attr.Make {
|
||||||
generate = "'Unix Makefiles'"
|
generate = "'Unix Makefiles'"
|
||||||
test = "make " + jobsFlagE + " test"
|
|
||||||
}
|
}
|
||||||
if attr.Test != "" {
|
|
||||||
test = attr.Test
|
|
||||||
}
|
|
||||||
|
|
||||||
script := attr.Script
|
|
||||||
if !attr.SkipTest && t.opts&OptSkipCheck == 0 {
|
|
||||||
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 `
|
return `
|
||||||
cmake -G ` + generate + ` \
|
cmake -G ` + generate + ` \
|
||||||
@@ -89,7 +181,7 @@ cmake -G ` + generate + ` \
|
|||||||
-DCMAKE_ASM_COMPILER_TARGET="${ROSA_TRIPLE}" \
|
-DCMAKE_ASM_COMPILER_TARGET="${ROSA_TRIPLE}" \
|
||||||
-DCMAKE_INSTALL_LIBDIR=lib \
|
-DCMAKE_INSTALL_LIBDIR=lib \
|
||||||
` + strings.Join(slices.Collect(func(yield func(string) bool) {
|
` + strings.Join(slices.Collect(func(yield func(string) bool) {
|
||||||
for _, v := range cache {
|
for _, v := range attr.Cache {
|
||||||
if !yield("-D" + v[0] + "=" + v[1]) {
|
if !yield("-D" + v[0] + "=" + v[1]) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -99,5 +191,5 @@ cmake -G ` + generate + ` \
|
|||||||
'/usr/src/` + name + `/` + filepath.Join(attr.Append...) + `'
|
'/usr/src/` + name + `/` + filepath.Join(attr.Append...) + `'
|
||||||
cmake --build . --parallel=` + jobsE + `
|
cmake --build . --parallel=` + jobsE + `
|
||||||
cmake --install . --prefix=/work/system
|
cmake --install . --prefix=/work/system
|
||||||
` + script
|
` + attr.Script
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,20 @@
|
|||||||
musl does not implement res_ninit
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newConnman() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "2.0"
|
||||||
|
checksum = "MhVTdJOhndnZn2SWd8URKo_Pj7Zvc14tntEbrVOf9L3yVWJvpb3v3Q6104tWJgtW"
|
||||||
|
)
|
||||||
|
return t.NewPackage("connman", version, newTar(
|
||||||
|
"https://git.kernel.org/pub/scm/network/connman/connman.git/"+
|
||||||
|
"snapshot/connman-"+version+".tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
), &PackageAttr{
|
||||||
|
Patches: []KV{
|
||||||
|
{"alpine-musl-res", `musl does not implement res_ninit
|
||||||
|
|
||||||
--- a/gweb/gresolv.c
|
--- a/gweb/gresolv.c
|
||||||
+++ b/gweb/gresolv.c
|
+++ b/gweb/gresolv.c
|
||||||
@@ -57,3 +73,37 @@ musl does not implement res_ninit
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!resolv->nameserver_list)
|
if (!resolv->nameserver_list)
|
||||||
|
`},
|
||||||
|
},
|
||||||
|
}, &MakeHelper{
|
||||||
|
Generate: "./bootstrap",
|
||||||
|
},
|
||||||
|
Automake,
|
||||||
|
Libtool,
|
||||||
|
PkgConfig,
|
||||||
|
|
||||||
|
DBus,
|
||||||
|
IPTables,
|
||||||
|
GnuTLS,
|
||||||
|
Readline,
|
||||||
|
KernelHeaders,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Connman] = Metadata{
|
||||||
|
f: Toolchain.newConnman,
|
||||||
|
|
||||||
|
Name: "connman",
|
||||||
|
Description: "a daemon for managing Internet connections",
|
||||||
|
Website: "https://git.kernel.org/pub/scm/network/connman/connman.git/",
|
||||||
|
|
||||||
|
Dependencies: P{
|
||||||
|
DBus,
|
||||||
|
IPTables,
|
||||||
|
GnuTLS,
|
||||||
|
Readline,
|
||||||
|
},
|
||||||
|
|
||||||
|
ID: 337,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newCurl() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "8.19.0"
|
||||||
|
checksum = "YHuVLVVp8q_Y7-JWpID5ReNjq2Zk6t7ArHB6ngQXilp_R5l3cubdxu3UKo-xDByv"
|
||||||
|
)
|
||||||
|
return t.NewPackage("curl", version, newTar(
|
||||||
|
"https://curl.se/download/curl-"+version+".tar.bz2",
|
||||||
|
checksum,
|
||||||
|
pkg.TarBzip2,
|
||||||
|
), &PackageAttr{
|
||||||
|
// remove broken test
|
||||||
|
Writable: true,
|
||||||
|
ScriptEarly: `
|
||||||
|
chmod +w tests/data && rm -f tests/data/test459
|
||||||
|
`,
|
||||||
|
}, &MakeHelper{
|
||||||
|
Configure: []KV{
|
||||||
|
{"with-openssl"},
|
||||||
|
{"with-ca-bundle", "/system/etc/ssl/certs/ca-bundle.crt"},
|
||||||
|
|
||||||
|
{"disable-smb"},
|
||||||
|
},
|
||||||
|
Check: []string{
|
||||||
|
"TFLAGS=" + jobsLFlagE,
|
||||||
|
"test-nonflaky",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Perl,
|
||||||
|
Python,
|
||||||
|
PkgConfig,
|
||||||
|
Diffutils,
|
||||||
|
|
||||||
|
Libpsl,
|
||||||
|
OpenSSL,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Curl] = Metadata{
|
||||||
|
f: Toolchain.newCurl,
|
||||||
|
|
||||||
|
Name: "curl",
|
||||||
|
Description: "command line tool and library for transferring data with URLs",
|
||||||
|
Website: "https://curl.se/",
|
||||||
|
|
||||||
|
Dependencies: P{
|
||||||
|
Libpsl,
|
||||||
|
OpenSSL,
|
||||||
|
},
|
||||||
|
|
||||||
|
ID: 381,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newDBus() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "1.16.2"
|
||||||
|
checksum = "INwOuNdrDG7XW5ilW_vn8JSxEa444rRNc5ho97i84I1CNF09OmcFcV-gzbF4uCyg"
|
||||||
|
)
|
||||||
|
return t.NewPackage("dbus", version, newFromGitLab(
|
||||||
|
"gitlab.freedesktop.org",
|
||||||
|
"dbus/dbus",
|
||||||
|
"dbus-"+version,
|
||||||
|
checksum,
|
||||||
|
), &PackageAttr{
|
||||||
|
// OSError: [Errno 30] Read-only file system: '/usr/src/dbus/subprojects/packagecache'
|
||||||
|
Writable: true,
|
||||||
|
// PermissionError: [Errno 13] Permission denied: '/usr/src/dbus/subprojects/packagecache'
|
||||||
|
Chmod: true,
|
||||||
|
}, &MesonHelper{
|
||||||
|
Setup: []KV{
|
||||||
|
{"Depoll", "enabled"},
|
||||||
|
{"Dinotify", "enabled"},
|
||||||
|
{"Dx11_autolaunch", "disabled"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
GLib,
|
||||||
|
Libexpat,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[DBus] = Metadata{
|
||||||
|
f: Toolchain.newDBus,
|
||||||
|
|
||||||
|
Name: "dbus",
|
||||||
|
Description: "a message bus system",
|
||||||
|
Website: "https://www.freedesktop.org/wiki/Software/dbus/",
|
||||||
|
|
||||||
|
Dependencies: P{
|
||||||
|
GLib,
|
||||||
|
Libexpat,
|
||||||
|
},
|
||||||
|
|
||||||
|
ID: 5356,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Toolchain) newXDGDBusProxy() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "0.1.7"
|
||||||
|
checksum = "UW5Pe-TP-XAaN-kTbxrkOQ7eYdmlAQlr2pdreLtPT0uwdAz-7rzDP8V_8PWuZBup"
|
||||||
|
)
|
||||||
|
return t.NewPackage("xdg-dbus-proxy", version, newFromGitHub(
|
||||||
|
"flatpak/xdg-dbus-proxy",
|
||||||
|
version,
|
||||||
|
checksum,
|
||||||
|
), nil, &MesonHelper{
|
||||||
|
Setup: []KV{
|
||||||
|
{"Dman", "disabled"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
DBus,
|
||||||
|
|
||||||
|
GLib,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[XDGDBusProxy] = Metadata{
|
||||||
|
f: Toolchain.newXDGDBusProxy,
|
||||||
|
|
||||||
|
Name: "xdg-dbus-proxy",
|
||||||
|
Description: "a filtering proxy for D-Bus connections",
|
||||||
|
Website: "https://github.com/flatpak/xdg-dbus-proxy",
|
||||||
|
|
||||||
|
Dependencies: P{
|
||||||
|
GLib,
|
||||||
|
},
|
||||||
|
|
||||||
|
ID: 58434,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newDTC() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "1.7.2"
|
||||||
|
checksum = "vUoiRynPyYRexTpS6USweT5p4SVHvvVJs8uqFkkVD-YnFjwf6v3elQ0-Etrh00Dt"
|
||||||
|
)
|
||||||
|
return t.NewPackage("dtc", version, newTar(
|
||||||
|
"https://git.kernel.org/pub/scm/utils/dtc/dtc.git/snapshot/"+
|
||||||
|
"dtc-v"+version+".tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
), &PackageAttr{
|
||||||
|
// works around buggy test:
|
||||||
|
// fdtdump-runtest.sh /usr/src/dtc/tests/fdtdump.dts
|
||||||
|
Writable: true,
|
||||||
|
Chmod: true,
|
||||||
|
}, &MesonHelper{
|
||||||
|
Setup: []KV{
|
||||||
|
{"Dyaml", "disabled"},
|
||||||
|
{"Dstatic-build", "true"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Flex,
|
||||||
|
Bison,
|
||||||
|
M4,
|
||||||
|
Coreutils,
|
||||||
|
Diffutils,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[DTC] = Metadata{
|
||||||
|
f: Toolchain.newDTC,
|
||||||
|
|
||||||
|
Name: "dtc",
|
||||||
|
Description: "The Device Tree Compiler",
|
||||||
|
Website: "https://git.kernel.org/pub/scm/utils/dtc/dtc.git/",
|
||||||
|
|
||||||
|
ID: 16911,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newElfutils() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "0.195"
|
||||||
|
checksum = "JrGnBD38w8Mj0ZxDw3fKlRBFcLvRKu8rcYnX35R9yTlUSYnzTazyLboG-a2CsJlu"
|
||||||
|
)
|
||||||
|
return t.NewPackage("elfutils", version, newTar(
|
||||||
|
"https://sourceware.org/elfutils/ftp/"+
|
||||||
|
version+"/elfutils-"+version+".tar.bz2",
|
||||||
|
checksum,
|
||||||
|
pkg.TarBzip2,
|
||||||
|
), &PackageAttr{
|
||||||
|
Env: []string{
|
||||||
|
"CC=cc" +
|
||||||
|
// nonstandard glibc extension
|
||||||
|
" -DFNM_EXTMATCH=0",
|
||||||
|
},
|
||||||
|
}, &MakeHelper{
|
||||||
|
// nonstandard glibc extension
|
||||||
|
SkipCheck: true,
|
||||||
|
|
||||||
|
Configure: []KV{
|
||||||
|
{"enable-deterministic-archives"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
M4,
|
||||||
|
PkgConfig,
|
||||||
|
|
||||||
|
Zlib,
|
||||||
|
Bzip2,
|
||||||
|
Zstd,
|
||||||
|
ArgpStandalone,
|
||||||
|
MuslFts,
|
||||||
|
MuslObstack,
|
||||||
|
KernelHeaders,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Elfutils] = Metadata{
|
||||||
|
f: Toolchain.newElfutils,
|
||||||
|
|
||||||
|
Name: "elfutils",
|
||||||
|
Description: "utilities and libraries to handle ELF files and DWARF data",
|
||||||
|
Website: "https://sourceware.org/elfutils/",
|
||||||
|
|
||||||
|
Dependencies: P{
|
||||||
|
Zlib,
|
||||||
|
Bzip2,
|
||||||
|
Zstd,
|
||||||
|
MuslFts,
|
||||||
|
MuslObstack,
|
||||||
|
},
|
||||||
|
|
||||||
|
ID: 5679,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newFakeroot() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "1.37.2"
|
||||||
|
checksum = "4ve-eDqVspzQ6VWDhPS0NjW3aSenBJcPAJq_BFT7OOFgUdrQzoTBxZWipDAGWxF8"
|
||||||
|
)
|
||||||
|
return t.NewPackage("fakeroot", version, newFromGitLab(
|
||||||
|
"salsa.debian.org",
|
||||||
|
"clint/fakeroot",
|
||||||
|
"upstream/"+version,
|
||||||
|
checksum,
|
||||||
|
), &PackageAttr{
|
||||||
|
Patches: []KV{
|
||||||
|
{"remove-broken-docs", `diff --git a/doc/Makefile.am b/doc/Makefile.am
|
||||||
|
index f135ad9..85c784c 100644
|
||||||
|
--- a/doc/Makefile.am
|
||||||
|
+++ b/doc/Makefile.am
|
||||||
|
@@ -1,5 +1,4 @@
|
||||||
|
AUTOMAKE_OPTIONS=foreign
|
||||||
|
-SUBDIRS = de es fr nl pt ro sv
|
||||||
|
|
||||||
|
man_MANS = faked.1 fakeroot.1
|
||||||
|
|
||||||
|
`},
|
||||||
|
},
|
||||||
|
|
||||||
|
Env: []string{
|
||||||
|
"CONFIG_SHELL=/bin/sh",
|
||||||
|
},
|
||||||
|
}, &MakeHelper{
|
||||||
|
Generate: "./bootstrap",
|
||||||
|
|
||||||
|
// makes assumptions about /etc/passwd
|
||||||
|
SkipCheck: true,
|
||||||
|
},
|
||||||
|
Automake,
|
||||||
|
Libtool,
|
||||||
|
PkgConfig,
|
||||||
|
|
||||||
|
Attr,
|
||||||
|
Libcap,
|
||||||
|
KernelHeaders,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Fakeroot] = Metadata{
|
||||||
|
f: Toolchain.newFakeroot,
|
||||||
|
|
||||||
|
Name: "fakeroot",
|
||||||
|
Description: "tool for simulating superuser privileges",
|
||||||
|
Website: "https://salsa.debian.org/clint/fakeroot",
|
||||||
|
|
||||||
|
ID: 12048,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hakurei.app/internal/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t Toolchain) newFlex() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "2.6.4"
|
||||||
|
checksum = "p9POjQU7VhgOf3x5iFro8fjhy0NOanvA7CTeuWS_veSNgCixIJshTrWVkc5XLZkB"
|
||||||
|
)
|
||||||
|
return t.NewPackage("flex", version, newFromGitHubRelease(
|
||||||
|
"westes/flex",
|
||||||
|
"v"+version,
|
||||||
|
"flex-"+version+".tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
), nil, (*MakeHelper)(nil),
|
||||||
|
M4,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Flex] = Metadata{
|
||||||
|
f: Toolchain.newFlex,
|
||||||
|
|
||||||
|
Name: "flex",
|
||||||
|
Description: "scanner generator for lexing in C and C++",
|
||||||
|
Website: "https://github.com/westes/flex/",
|
||||||
|
|
||||||
|
ID: 819,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newFuse() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "3.18.2"
|
||||||
|
checksum = "iL-7b7eUtmlVSf5cSq0dzow3UiqSjBmzV3cI_ENPs1tXcHdktkG45j1V12h-4jZe"
|
||||||
|
)
|
||||||
|
return t.NewPackage("fuse", version, newFromGitHubRelease(
|
||||||
|
"libfuse/libfuse",
|
||||||
|
"fuse-"+version,
|
||||||
|
"fuse-"+version+".tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
), nil, &MesonHelper{
|
||||||
|
Setup: []KV{
|
||||||
|
{"Ddefault_library", "both"},
|
||||||
|
{"Dtests", "true"},
|
||||||
|
{"Duseroot", "false"},
|
||||||
|
{"Dinitscriptdir", "/system/etc"},
|
||||||
|
},
|
||||||
|
|
||||||
|
ScriptCompiled: "python3 -m pytest test/",
|
||||||
|
// this project uses pytest
|
||||||
|
SkipTest: true,
|
||||||
|
},
|
||||||
|
PythonPyTest,
|
||||||
|
|
||||||
|
KernelHeaders,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Fuse] = Metadata{
|
||||||
|
f: Toolchain.newFuse,
|
||||||
|
|
||||||
|
Name: "fuse",
|
||||||
|
Description: "the reference implementation of the Linux FUSE interface",
|
||||||
|
Website: "https://github.com/libfuse/libfuse/",
|
||||||
|
|
||||||
|
ID: 861,
|
||||||
|
}
|
||||||
|
}
|
||||||
+85
-7
@@ -7,10 +7,88 @@ import (
|
|||||||
"hakurei.app/internal/pkg"
|
"hakurei.app/internal/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func (t Toolchain) newGit() (pkg.Artifact, string) {
|
||||||
_git = H("git")
|
const (
|
||||||
_nssCACert = H("nss-cacert")
|
version = "2.53.0"
|
||||||
)
|
checksum = "rlqSTeNgSeVKJA7nvzGqddFH8q3eFEPB4qRZft-4zth8wTHnbTbm7J90kp_obHGm"
|
||||||
|
)
|
||||||
|
return t.NewPackage("git", version, newTar(
|
||||||
|
"https://www.kernel.org/pub/software/scm/git/"+
|
||||||
|
"git-"+version+".tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
), &PackageAttr{
|
||||||
|
ScriptEarly: `
|
||||||
|
ln -s ../../system/bin/perl /usr/bin/ || true
|
||||||
|
`,
|
||||||
|
|
||||||
|
// uses source tree as scratch space
|
||||||
|
EnterSource: true,
|
||||||
|
}, &MakeHelper{
|
||||||
|
InPlace: true,
|
||||||
|
Generate: "make configure",
|
||||||
|
ScriptMakeEarly: `
|
||||||
|
function disable_test {
|
||||||
|
local test=$1 pattern=${2:-''}
|
||||||
|
if [ $# -eq 1 ]; then
|
||||||
|
rm "t/${test}.sh"
|
||||||
|
else
|
||||||
|
sed -i "t/${test}.sh" \
|
||||||
|
-e "/^\s*test_expect_.*$pattern/,/^\s*' *\$/{s/^/: #/}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_test t5319-multi-pack-index
|
||||||
|
disable_test t1305-config-include
|
||||||
|
disable_test t3900-i18n-commit
|
||||||
|
disable_test t3507-cherry-pick-conflict
|
||||||
|
disable_test t4201-shortlog
|
||||||
|
disable_test t5303-pack-corruption-resilience
|
||||||
|
disable_test t4301-merge-tree-write-tree
|
||||||
|
disable_test t8005-blame-i18n
|
||||||
|
disable_test t9350-fast-export
|
||||||
|
disable_test t9300-fast-import
|
||||||
|
disable_test t0211-trace2-perf
|
||||||
|
disable_test t1517-outside-repo
|
||||||
|
disable_test t2200-add-update
|
||||||
|
`,
|
||||||
|
Check: []string{
|
||||||
|
"-C t",
|
||||||
|
`GIT_PROVE_OPTS="--jobs 32 --failures"`,
|
||||||
|
"prove",
|
||||||
|
},
|
||||||
|
Install: `make \
|
||||||
|
` + jobsFlagE + ` \
|
||||||
|
DESTDIR=/work \
|
||||||
|
NO_INSTALL_HARDLINKS=1 \
|
||||||
|
install`,
|
||||||
|
},
|
||||||
|
Diffutils,
|
||||||
|
Autoconf,
|
||||||
|
Gettext,
|
||||||
|
|
||||||
|
Zlib,
|
||||||
|
Curl,
|
||||||
|
Libexpat,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Git] = Metadata{
|
||||||
|
f: Toolchain.newGit,
|
||||||
|
|
||||||
|
Name: "git",
|
||||||
|
Description: "distributed version control system",
|
||||||
|
Website: "https://www.git-scm.com/",
|
||||||
|
|
||||||
|
Dependencies: P{
|
||||||
|
Zlib,
|
||||||
|
Curl,
|
||||||
|
Libexpat,
|
||||||
|
},
|
||||||
|
|
||||||
|
ID: 5350,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewViaGit returns a [pkg.Artifact] for cloning a git repository.
|
// NewViaGit returns a [pkg.Artifact] for cloning a git repository.
|
||||||
func (t Toolchain) NewViaGit(
|
func (t Toolchain) NewViaGit(
|
||||||
@@ -20,9 +98,9 @@ func (t Toolchain) NewViaGit(
|
|||||||
return t.New(strings.TrimSuffix(
|
return t.New(strings.TrimSuffix(
|
||||||
path.Base(url),
|
path.Base(url),
|
||||||
".git",
|
".git",
|
||||||
)+"-src-"+path.Base(rev), THostNet, t.Append(nil,
|
)+"-src-"+path.Base(rev), 0, t.AppendPresets(nil,
|
||||||
_nssCACert,
|
NSSCACert,
|
||||||
_git,
|
Git,
|
||||||
), &checksum, nil, `
|
), &checksum, nil, `
|
||||||
git \
|
git \
|
||||||
-c advice.detachedHead=false \
|
-c advice.detachedHead=false \
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"hakurei.app/internal/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t Toolchain) newSPIRVHeaders() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "1.4.341.0"
|
||||||
|
checksum = "0PL43-19Iaw4k7_D8J8BvoJ-iLgCVSYZ2ThgDPGfAJwIJFtre7l0cnQtLjcY-JvD"
|
||||||
|
)
|
||||||
|
return t.NewPackage("spirv-headers", version, newFromGitHub(
|
||||||
|
"KhronosGroup/SPIRV-Headers",
|
||||||
|
"vulkan-sdk-"+version,
|
||||||
|
checksum,
|
||||||
|
), nil, &CMakeHelper{
|
||||||
|
Cache: []KV{
|
||||||
|
{"CMAKE_BUILD_TYPE", "Release"},
|
||||||
|
},
|
||||||
|
}), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[SPIRVHeaders] = Metadata{
|
||||||
|
f: Toolchain.newSPIRVHeaders,
|
||||||
|
|
||||||
|
Name: "spirv-headers",
|
||||||
|
Description: "machine-readable files for the SPIR-V Registry",
|
||||||
|
Website: "https://github.com/KhronosGroup/SPIRV-Headers",
|
||||||
|
|
||||||
|
ID: 230542,
|
||||||
|
|
||||||
|
// upstream changed version scheme, anitya incapable of filtering them
|
||||||
|
latest: func(v *Versions) string {
|
||||||
|
for _, s := range v.Stable {
|
||||||
|
fields := strings.SplitN(s, ".", 4)
|
||||||
|
if len(fields) != 4 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if slices.ContainsFunc(fields, func(f string) bool {
|
||||||
|
return slices.ContainsFunc([]byte(f), func(d byte) bool {
|
||||||
|
return d < '0' || d > '9'
|
||||||
|
})
|
||||||
|
}) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return v.Latest
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Toolchain) newSPIRVTools() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "2026.1"
|
||||||
|
checksum = "ZSQPQx8NltCDzQLk4qlaVxyWRWeI_JtsjEpeFt3kezTanl9DTHfLixSUCezMFBjv"
|
||||||
|
)
|
||||||
|
return t.NewPackage("spirv-tools", version, newFromGitHub(
|
||||||
|
"KhronosGroup/SPIRV-Tools",
|
||||||
|
"v"+version,
|
||||||
|
checksum,
|
||||||
|
), nil, &CMakeHelper{
|
||||||
|
Cache: []KV{
|
||||||
|
{"CMAKE_BUILD_TYPE", "Release"},
|
||||||
|
{"SPIRV-Headers_SOURCE_DIR", "/system"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Python,
|
||||||
|
|
||||||
|
SPIRVHeaders,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[SPIRVTools] = Metadata{
|
||||||
|
f: Toolchain.newSPIRVTools,
|
||||||
|
|
||||||
|
Name: "spirv-tools",
|
||||||
|
Description: "an API and commands for processing SPIR-V modules",
|
||||||
|
Website: "https://github.com/KhronosGroup/SPIRV-Tools",
|
||||||
|
|
||||||
|
Dependencies: P{
|
||||||
|
SPIRVHeaders,
|
||||||
|
},
|
||||||
|
|
||||||
|
ID: 14894,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Toolchain) newGlslang() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "16.2.0"
|
||||||
|
checksum = "6_UuF9reLRDaVkgO-9IfB3kMwme3lQZM8LL8YsJwPdUFkrjzxJtf2A9X3w9nFxj2"
|
||||||
|
)
|
||||||
|
return t.NewPackage("glslang", version, newFromGitHub(
|
||||||
|
"KhronosGroup/glslang",
|
||||||
|
version,
|
||||||
|
checksum,
|
||||||
|
), &PackageAttr{
|
||||||
|
// test suite writes to source
|
||||||
|
Writable: true,
|
||||||
|
Chmod: true,
|
||||||
|
}, &CMakeHelper{
|
||||||
|
Cache: []KV{
|
||||||
|
{"CMAKE_BUILD_TYPE", "Release"},
|
||||||
|
{"BUILD_SHARED_LIBS", "ON"},
|
||||||
|
{"ALLOW_EXTERNAL_SPIRV_TOOLS", "ON"},
|
||||||
|
},
|
||||||
|
Script: "ctest",
|
||||||
|
},
|
||||||
|
Python,
|
||||||
|
Bash,
|
||||||
|
Diffutils,
|
||||||
|
|
||||||
|
SPIRVTools,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Glslang] = Metadata{
|
||||||
|
f: Toolchain.newGlslang,
|
||||||
|
|
||||||
|
Name: "glslang",
|
||||||
|
Description: "reference front end for GLSL/ESSL",
|
||||||
|
Website: "https://github.com/KhronosGroup/glslang",
|
||||||
|
|
||||||
|
ID: 205796,
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
+70
-89
@@ -1,112 +1,85 @@
|
|||||||
package rosa
|
package rosa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"runtime"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"hakurei.app/internal/pkg"
|
"hakurei.app/internal/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _go = H("go")
|
// 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{
|
||||||
|
"CGO_ENABLED=0",
|
||||||
|
}, `
|
||||||
|
mkdir -p /var/tmp/ /work/system/
|
||||||
|
cp -r /usr/src/go /work/system/
|
||||||
|
cd /work/system/go/src
|
||||||
|
chmod -R +w ..
|
||||||
|
|
||||||
|
./make.bash
|
||||||
|
`, pkg.Path(AbsUsrSrc.Append("go"), false, newTar(
|
||||||
|
"https://dl.google.com/go/go1.4-bootstrap-20171003.tar.gz",
|
||||||
|
checksum,
|
||||||
|
pkg.TarGzip,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
// newGo returns a specific version of the Go toolchain.
|
// newGo returns a specific version of the Go toolchain.
|
||||||
func (t Toolchain) newGo(
|
func (t Toolchain) newGo(
|
||||||
version, checksum string,
|
version, checksum string,
|
||||||
env []string,
|
env []string,
|
||||||
script string,
|
script string,
|
||||||
boot pkg.Artifact,
|
extra ...pkg.Artifact,
|
||||||
) pkg.Artifact {
|
) pkg.Artifact {
|
||||||
return t.NewPackage("go", version, newTar(
|
return t.New("go"+version, 0, slices.Concat([]pkg.Artifact{
|
||||||
"https://go.dev/dl/go"+version+".src.tar.gz",
|
t.Load(Bash),
|
||||||
checksum,
|
}, extra), nil, slices.Concat([]string{
|
||||||
pkg.TarGzip,
|
|
||||||
), &PackageAttr{
|
|
||||||
EnterSource: true,
|
|
||||||
Env: slices.Concat([]string{
|
|
||||||
"CC=cc",
|
"CC=cc",
|
||||||
"GOCACHE=/tmp/gocache",
|
"GOCACHE=/tmp/gocache",
|
||||||
"GOROOT_BOOTSTRAP=/system/go",
|
"GOROOT_BOOTSTRAP=/system/go",
|
||||||
"TMPDIR=/dev/shm/go",
|
"TMPDIR=/dev/shm/go",
|
||||||
}, env),
|
}, env), `
|
||||||
|
mkdir /work/system "${TMPDIR}"
|
||||||
Extra: []pkg.Artifact{boot},
|
cp -r /usr/src/go /work/system
|
||||||
}, &GenericHelper{
|
cd /work/system/go/src
|
||||||
InPlace: true,
|
|
||||||
Build: `
|
|
||||||
mkdir /work/system/ "${TMPDIR}"
|
|
||||||
cp -r . /work/system/go
|
|
||||||
cd /work/system/go/src/
|
|
||||||
chmod -R +w ..
|
chmod -R +w ..
|
||||||
` + script + `
|
`+script+`
|
||||||
set +u
|
./all.bash
|
||||||
. ./make.bash "$@" --no-banner
|
|
||||||
set -u
|
|
||||||
`,
|
|
||||||
Check: "bash run.bash --no-rebuild\n",
|
|
||||||
Install: `
|
|
||||||
../bin/go tool dist banner # print build info
|
|
||||||
|
|
||||||
mkdir /work/system/bin
|
mkdir /work/system/bin
|
||||||
ln -s \
|
ln -s \
|
||||||
../go/bin/go \
|
../go/bin/go \
|
||||||
../go/bin/gofmt \
|
../go/bin/gofmt \
|
||||||
/work/system/bin
|
/work/system/bin
|
||||||
`,
|
`, pkg.Path(AbsUsrSrc.Append("go"), false, newTar(
|
||||||
},
|
"https://go.dev/dl/go"+version+".src.tar.gz",
|
||||||
_bash,
|
checksum,
|
||||||
)
|
pkg.TarGzip,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func (t Toolchain) newGoLatest() (pkg.Artifact, string) {
|
||||||
const (
|
|
||||||
version = "1.26.3"
|
|
||||||
checksum = "lEiFocZFnN5fKvZzmwVdqc9pYUjAuhzqZGbuiOqxUP4XdcY8yECisKcqsQ_eNn1N"
|
|
||||||
)
|
|
||||||
meta := Metadata{
|
|
||||||
Name: "go",
|
|
||||||
Description: "the Go programming language toolchain",
|
|
||||||
Website: "https://go.dev",
|
|
||||||
Version: version,
|
|
||||||
|
|
||||||
ID: 1227,
|
|
||||||
}
|
|
||||||
native.MustRegister(meta.Name, func(t Toolchain) (*Metadata, pkg.Artifact) {
|
|
||||||
var (
|
var (
|
||||||
bootstrapEnv []string
|
bootstrapEnv []string
|
||||||
bootstrapEarly pkg.Artifact
|
bootstrapExtra []pkg.Artifact
|
||||||
|
|
||||||
finalEnv []string
|
finalEnv []string
|
||||||
)
|
)
|
||||||
switch t.arch {
|
switch runtime.GOARCH {
|
||||||
case "amd64":
|
case "amd64":
|
||||||
bootstrapEarly = t.NewPackage("go", "1.4-bootstrap", newTar(
|
bootstrapExtra = append(bootstrapExtra, t.newGoBootstrap())
|
||||||
"https://dl.google.com/go/go1.4-bootstrap-20171003.tar.gz",
|
|
||||||
"8o9JL_ToiQKadCTb04nvBDkp8O1xiWOolAxVEqaTGodieNe4lOFEjlOxN3bwwe23",
|
|
||||||
pkg.TarGzip,
|
|
||||||
), &PackageAttr{
|
|
||||||
EnterSource: true,
|
|
||||||
Env: []string{
|
|
||||||
"CGO_ENABLED=0",
|
|
||||||
},
|
|
||||||
}, &GenericHelper{
|
|
||||||
InPlace: true,
|
|
||||||
Build: `
|
|
||||||
mkdir /work/system/
|
|
||||||
cp -r . /work/system/go
|
|
||||||
cd /work/system/go/src/
|
|
||||||
mkdir -p /var/tmp/
|
|
||||||
./make.bash
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
_bash,
|
|
||||||
)
|
|
||||||
|
|
||||||
case "arm64", "riscv64":
|
case "arm64", "riscv64":
|
||||||
bootstrapEnv = append(bootstrapEnv, "GOROOT_BOOTSTRAP=/system")
|
bootstrapEnv = append(bootstrapEnv, "GOROOT_BOOTSTRAP=/system")
|
||||||
_, bootstrapEarly = t.MustLoad(H("gcc"))
|
bootstrapExtra = t.AppendPresets(bootstrapExtra, gcc)
|
||||||
finalEnv = append(finalEnv, "CGO_ENABLED=0")
|
finalEnv = append(finalEnv, "CGO_ENABLED=0")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("unsupported target " + t.arch)
|
panic("unsupported target " + runtime.GOARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
go119 := t.newGo(
|
go119 := t.newGo(
|
||||||
@@ -123,15 +96,15 @@ sed -i \
|
|||||||
echo \
|
echo \
|
||||||
'type syscallDescriptor = int' >> \
|
'type syscallDescriptor = int' >> \
|
||||||
os/rawconn_test.go
|
os/rawconn_test.go
|
||||||
`, bootstrapEarly)
|
`, bootstrapExtra...)
|
||||||
|
|
||||||
go121 := t.newGo(
|
go121 := t.newGo(
|
||||||
"1.21.13",
|
"1.21.13",
|
||||||
"YtrDka402BOAEwywx03Vz4QlVwoBiguJHzG7PuythMCPHXS8CVMLvzmvgEbu4Tzu",
|
"YtrDka402BOAEwywx03Vz4QlVwoBiguJHzG7PuythMCPHXS8CVMLvzmvgEbu4Tzu",
|
||||||
[]string{"CGO_ENABLED=0"}, `
|
[]string{"CGO_ENABLED=0"}, `
|
||||||
sed -i \
|
sed -i \
|
||||||
's,/lib/ld-musl-`+t.linuxArch()+`.so.1,/system/bin/linker,' \
|
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
|
||||||
cmd/link/internal/`+t.arch+`/obj.go
|
cmd/link/internal/`+runtime.GOARCH+`/obj.go
|
||||||
|
|
||||||
rm \
|
rm \
|
||||||
crypto/tls/handshake_client_test.go \
|
crypto/tls/handshake_client_test.go \
|
||||||
@@ -148,18 +121,18 @@ echo \
|
|||||||
"wcI32bl1tkqbgcelGtGWPI4RtlEddd-PTd76Eb-k7nXA5LbE9yTNdIL9QSOOxMOs",
|
"wcI32bl1tkqbgcelGtGWPI4RtlEddd-PTd76Eb-k7nXA5LbE9yTNdIL9QSOOxMOs",
|
||||||
[]string{"CGO_ENABLED=0"}, `
|
[]string{"CGO_ENABLED=0"}, `
|
||||||
sed -i \
|
sed -i \
|
||||||
's,/lib/ld-musl-`+t.linuxArch()+`.so.1,/system/bin/linker,' \
|
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
|
||||||
cmd/link/internal/`+t.arch+`/obj.go
|
cmd/link/internal/`+runtime.GOARCH+`/obj.go
|
||||||
`, go121,
|
`, go121,
|
||||||
)
|
)
|
||||||
|
|
||||||
go125 := t.newGo(
|
go125 := t.newGo(
|
||||||
"1.25.10",
|
"1.25.7",
|
||||||
"TwKwatkpwal-j9U2sDSRPEdM3YesI4Gm88YgGV59wtU-L85K9gA7UPy9SCxn6PMb",
|
"fyylHdBVRUobnBjYj3NKBaYPUw3kGmo2mEELiZonOYurPfbarNU1x77B99Fjut7Q",
|
||||||
[]string{"CGO_ENABLED=0"}, `
|
[]string{"CGO_ENABLED=0"}, `
|
||||||
sed -i \
|
sed -i \
|
||||||
's,/lib/ld-musl-`+t.linuxArch()+`.so.1,/system/bin/linker,' \
|
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
|
||||||
cmd/link/internal/`+t.arch+`/obj.go
|
cmd/link/internal/`+runtime.GOARCH+`/obj.go
|
||||||
|
|
||||||
rm \
|
rm \
|
||||||
os/root_unix_test.go \
|
os/root_unix_test.go \
|
||||||
@@ -167,23 +140,31 @@ rm \
|
|||||||
`, go123,
|
`, go123,
|
||||||
)
|
)
|
||||||
|
|
||||||
return &meta, t.newGo(
|
const (
|
||||||
|
version = "1.26.2"
|
||||||
|
checksum = "v-6BE89_1g3xYf-9oIYpJKFXlo3xKHYJj2_VGkaUq8ZVkIVQmLwrto-xGG03OISH"
|
||||||
|
)
|
||||||
|
return t.newGo(
|
||||||
version,
|
version,
|
||||||
checksum,
|
checksum,
|
||||||
finalEnv, `
|
finalEnv, `
|
||||||
sed -i \
|
sed -i \
|
||||||
's,/lib/ld-musl-`+t.linuxArch()+`.so.1,/system/bin/linker,' \
|
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
|
||||||
cmd/link/internal/`+t.arch+`/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
|
|
||||||
`, go125,
|
`, go125,
|
||||||
)
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Go] = Metadata{
|
||||||
|
f: Toolchain.newGoLatest,
|
||||||
|
|
||||||
})
|
Name: "go",
|
||||||
|
Description: "the Go programming language toolchain",
|
||||||
|
Website: "https://go.dev/",
|
||||||
|
|
||||||
|
ID: 1227,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hakurei.app/fhs"
|
||||||
|
"hakurei.app/internal/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t Toolchain) newGLib() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "2.88.0"
|
||||||
|
checksum = "T79Cg4z6j-sDZ2yIwvbY4ccRv2-fbwbqgcw59F5NQ6qJT6z4v261vbYp3dHO6Ma3"
|
||||||
|
)
|
||||||
|
return t.NewPackage("glib", version, t.newTagRemote(
|
||||||
|
"https://gitlab.gnome.org/GNOME/glib.git",
|
||||||
|
version, checksum,
|
||||||
|
), &PackageAttr{
|
||||||
|
Paths: []pkg.ExecPath{
|
||||||
|
pkg.Path(fhs.AbsEtc.Append(
|
||||||
|
"machine-id",
|
||||||
|
), false, pkg.NewFile(
|
||||||
|
"glib-machine-id",
|
||||||
|
[]byte("ffffffffffffffffffffffffffffffff\n"),
|
||||||
|
)),
|
||||||
|
pkg.Path(AbsSystem.Append(
|
||||||
|
"var/lib/dbus/machine-id",
|
||||||
|
), false, pkg.NewFile(
|
||||||
|
"glib-machine-id",
|
||||||
|
[]byte("fefefefefefefefefefefefefefefefe\n"),
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
}, &MesonHelper{
|
||||||
|
Setup: []KV{
|
||||||
|
{"Ddefault_library", "both"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PythonPackaging,
|
||||||
|
Bash,
|
||||||
|
|
||||||
|
PCRE2,
|
||||||
|
Libffi,
|
||||||
|
Zlib,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[GLib] = Metadata{
|
||||||
|
f: Toolchain.newGLib,
|
||||||
|
|
||||||
|
Name: "glib",
|
||||||
|
Description: "the GNU library of miscellaneous stuff",
|
||||||
|
Website: "https://developer.gnome.org/glib/",
|
||||||
|
|
||||||
|
Dependencies: P{
|
||||||
|
PCRE2,
|
||||||
|
Libffi,
|
||||||
|
Zlib,
|
||||||
|
},
|
||||||
|
|
||||||
|
ID: 10024,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
func (t Toolchain) newHakurei(
|
||||||
|
suffix, script string,
|
||||||
|
withHostname bool,
|
||||||
|
) pkg.Artifact {
|
||||||
|
hostname := `
|
||||||
|
echo '# Building test helper (hostname).'
|
||||||
|
go build -v -o /bin/hostname /usr/src/hostname/main.go
|
||||||
|
echo
|
||||||
|
`
|
||||||
|
if !withHostname {
|
||||||
|
hostname = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.New("hakurei"+suffix+"-"+hakureiVersion, 0, t.AppendPresets(nil,
|
||||||
|
Go,
|
||||||
|
PkgConfig,
|
||||||
|
|
||||||
|
// dist tarball
|
||||||
|
Gzip,
|
||||||
|
|
||||||
|
// statically linked
|
||||||
|
Libseccomp,
|
||||||
|
ACL,
|
||||||
|
Fuse,
|
||||||
|
XCB,
|
||||||
|
Wayland,
|
||||||
|
WaylandProtocols,
|
||||||
|
|
||||||
|
KernelHeaders,
|
||||||
|
), nil, []string{
|
||||||
|
"CGO_ENABLED=1",
|
||||||
|
"GOCACHE=/tmp/gocache",
|
||||||
|
"CC=clang -O3 -Werror",
|
||||||
|
}, hostname+`
|
||||||
|
cd /usr/src/hakurei
|
||||||
|
|
||||||
|
HAKUREI_VERSION='v`+hakureiVersion+`'
|
||||||
|
`+script, pkg.Path(AbsUsrSrc.Append("hakurei"), true, t.NewPatchedSource(
|
||||||
|
"hakurei", hakureiVersion, hakureiSource, false, hakureiPatches...,
|
||||||
|
)), pkg.Path(AbsUsrSrc.Append("hostname", "main.go"), false, pkg.NewFile(
|
||||||
|
"hostname.go",
|
||||||
|
[]byte(`
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if name, err := os.Hostname(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
} else {
|
||||||
|
os.Stdout.WriteString(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Hakurei] = Metadata{
|
||||||
|
f: func(t Toolchain) (pkg.Artifact, string) {
|
||||||
|
return t.newHakurei("", `
|
||||||
|
mkdir -p /work/system/libexec/hakurei/
|
||||||
|
|
||||||
|
echo '# Building hakurei.'
|
||||||
|
go generate -v ./...
|
||||||
|
go build -trimpath -v -tags=rosa -o /work/system/libexec/hakurei -ldflags="-s -w
|
||||||
|
-buildid=
|
||||||
|
-linkmode external
|
||||||
|
-extldflags=-static
|
||||||
|
-X hakurei.app/internal/info.buildVersion=${HAKUREI_VERSION}
|
||||||
|
-X hakurei.app/internal/info.hakureiPath=/system/bin/hakurei
|
||||||
|
-X hakurei.app/internal/info.hsuPath=/system/bin/hsu
|
||||||
|
-X main.hakureiPath=/system/bin/hakurei
|
||||||
|
" ./...
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo '# Testing hakurei.'
|
||||||
|
go test -ldflags='-buildid= -linkmode external -extldflags=-static' ./...
|
||||||
|
echo
|
||||||
|
|
||||||
|
mkdir -p /work/system/bin/
|
||||||
|
(cd /work/system/libexec/hakurei && mv \
|
||||||
|
hakurei \
|
||||||
|
sharefs \
|
||||||
|
../../bin/)
|
||||||
|
`, true), hakureiVersion
|
||||||
|
},
|
||||||
|
|
||||||
|
Name: "hakurei",
|
||||||
|
Description: "low-level userspace tooling for Rosa OS",
|
||||||
|
Website: "https://hakurei.app/",
|
||||||
|
|
||||||
|
ID: 388834,
|
||||||
|
}
|
||||||
|
artifactsM[HakureiDist] = Metadata{
|
||||||
|
f: func(t Toolchain) (pkg.Artifact, string) {
|
||||||
|
return t.newHakurei("-dist", `
|
||||||
|
export HAKUREI_VERSION
|
||||||
|
DESTDIR=/work /usr/src/hakurei/all.sh
|
||||||
|
`, true), hakureiVersion
|
||||||
|
},
|
||||||
|
|
||||||
|
Name: "hakurei-dist",
|
||||||
|
Description: "low-level userspace tooling for Rosa OS (distribution tarball)",
|
||||||
|
Website: "https://hakurei.app/",
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
//go:build current
|
||||||
|
|
||||||
|
package rosa
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"hakurei.app/internal/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
const hakureiVersion = "1.0-current"
|
||||||
|
|
||||||
|
// hakureiSourceTarball is a compressed tarball of the hakurei source code.
|
||||||
|
//
|
||||||
|
//go:generate tar -zc -C ../.. --exclude .git --exclude *.tar.gz -f hakurei_current.tar.gz .
|
||||||
|
//go:embed hakurei_current.tar.gz
|
||||||
|
var hakureiSourceTarball []byte
|
||||||
|
|
||||||
|
// hakureiSource is the source code at the time this package is compiled.
|
||||||
|
var hakureiSource = pkg.NewTar(pkg.NewFile(
|
||||||
|
"hakurei-current.tar.gz",
|
||||||
|
hakureiSourceTarball,
|
||||||
|
), pkg.TarGzip)
|
||||||
|
|
||||||
|
// hakureiPatches are patches applied against the compile-time source tree.
|
||||||
|
var hakureiPatches []KV
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
//go:build !current
|
||||||
|
|
||||||
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
const hakureiVersion = "0.4.0"
|
||||||
|
|
||||||
|
// hakureiSource is the source code of a hakurei release.
|
||||||
|
var hakureiSource = newTar(
|
||||||
|
"https://git.gensokyo.uk/rosa/hakurei/archive/"+
|
||||||
|
"v"+hakureiVersion+".tar.gz",
|
||||||
|
"wfQ9DqCW0Fw9o91wj-I55waoqzB-UqzzuC0_2h-P-1M78SgZ1WHSPCDJMth6EyC2",
|
||||||
|
pkg.TarGzip,
|
||||||
|
)
|
||||||
|
|
||||||
|
// hakureiPatches are patches applied against a hakurei release.
|
||||||
|
var hakureiPatches []KV
|
||||||
+54
-30
@@ -6,39 +6,56 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
meta := Metadata{
|
artifactsM[EarlyInit] = Metadata{
|
||||||
Name: "system-image",
|
Name: "earlyinit",
|
||||||
Description: "Rosa OS system image",
|
Description: "Rosa OS initramfs init program",
|
||||||
Version: Unversioned,
|
|
||||||
}
|
|
||||||
native.MustRegister(meta.Name, func(t Toolchain) (*Metadata, pkg.Artifact) {
|
|
||||||
return &meta, t.New("system.img", TNoToolchain, t.Append(nil,
|
|
||||||
H("squashfs-tools"),
|
|
||||||
), nil, nil, `
|
|
||||||
mksquashfs /mnt/system /work/system.img
|
|
||||||
`, pkg.Path(fhs.AbsRoot.Append("mnt"), false, t.Append(nil,
|
|
||||||
_musl,
|
|
||||||
_mksh,
|
|
||||||
_toybox,
|
|
||||||
|
|
||||||
H("kmod"),
|
f: func(t Toolchain) (pkg.Artifact, string) {
|
||||||
H("kernel"),
|
return t.newHakurei("-early-init", `
|
||||||
H("firmware"),
|
mkdir -p /work/system/libexec/hakurei/
|
||||||
)...))
|
|
||||||
})
|
echo '# Building earlyinit.'
|
||||||
|
go build -trimpath -v -o /work/system/libexec/hakurei -ldflags="-s -w
|
||||||
|
-buildid=
|
||||||
|
-linkmode external
|
||||||
|
-extldflags=-static
|
||||||
|
-X hakurei.app/internal/info.buildVersion=${HAKUREI_VERSION}
|
||||||
|
" ./cmd/earlyinit
|
||||||
|
echo
|
||||||
|
`, false), Unversioned
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t Toolchain) newImageSystem() (pkg.Artifact, string) {
|
||||||
|
return t.New("system.img", TNoToolchain, t.AppendPresets(nil,
|
||||||
|
SquashfsTools,
|
||||||
|
), nil, nil, `
|
||||||
|
mksquashfs /mnt/system /work/system.img
|
||||||
|
`, pkg.Path(fhs.AbsRoot.Append("mnt"), false, t.AppendPresets(nil,
|
||||||
|
Musl,
|
||||||
|
Mksh,
|
||||||
|
Toybox,
|
||||||
|
|
||||||
|
Kmod,
|
||||||
|
Kernel,
|
||||||
|
Firmware,
|
||||||
|
)...)), Unversioned
|
||||||
|
}
|
||||||
func init() {
|
func init() {
|
||||||
meta := Metadata{
|
artifactsM[ImageSystem] = Metadata{
|
||||||
Name: "initramfs-image",
|
Name: "system-image",
|
||||||
Description: "Rosa OS initramfs image",
|
Description: "Rosa OS system image",
|
||||||
Version: Unversioned,
|
|
||||||
|
f: Toolchain.newImageSystem,
|
||||||
}
|
}
|
||||||
native.MustRegister(meta.Name, func(t Toolchain) (*Metadata, pkg.Artifact) {
|
}
|
||||||
return &meta, t.New("initramfs", TNoToolchain, t.Append(nil,
|
|
||||||
_zstd,
|
func (t Toolchain) newImageInitramfs() (pkg.Artifact, string) {
|
||||||
H("earlyinit"),
|
return t.New("initramfs", TNoToolchain, t.AppendPresets(nil,
|
||||||
H("gen_init_cpio"),
|
Zstd,
|
||||||
|
EarlyInit,
|
||||||
|
GenInitCPIO,
|
||||||
), nil, nil, `
|
), nil, nil, `
|
||||||
gen_init_cpio -t 4294967295 -c /usr/src/initramfs | zstd > /work/initramfs.zst
|
gen_init_cpio -t 4294967295 -c /usr/src/initramfs | zstd > /work/initramfs.zst
|
||||||
`, pkg.Path(AbsUsrSrc.Append("initramfs"), false, pkg.NewFile("initramfs", []byte(`
|
`, pkg.Path(AbsUsrSrc.Append("initramfs"), false, pkg.NewFile("initramfs", []byte(`
|
||||||
@@ -46,6 +63,13 @@ dir /dev 0755 0 0
|
|||||||
nod /dev/null 0666 0 0 c 1 3
|
nod /dev/null 0666 0 0 c 1 3
|
||||||
nod /dev/console 0600 0 0 c 5 1
|
nod /dev/console 0600 0 0 c 5 1
|
||||||
file /init /system/libexec/hakurei/earlyinit 0555 0 0
|
file /init /system/libexec/hakurei/earlyinit 0555 0 0
|
||||||
`))))
|
`)))), Unversioned
|
||||||
})
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[ImageInitramfs] = Metadata{
|
||||||
|
Name: "initramfs-image",
|
||||||
|
Description: "Rosa OS initramfs image",
|
||||||
|
|
||||||
|
f: Toolchain.newImageInitramfs,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+726
-1
@@ -1,4 +1,97 @@
|
|||||||
From f54a91f5337cd918eb86cf600320d25b6cfd8209 Mon Sep 17 00:00:00 2001
|
package rosa
|
||||||
|
|
||||||
|
import "hakurei.app/internal/pkg"
|
||||||
|
|
||||||
|
const kernelVersion = "6.12.81"
|
||||||
|
|
||||||
|
var kernelSource = newTar(
|
||||||
|
"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/"+
|
||||||
|
"snapshot/linux-"+kernelVersion+".tar.gz",
|
||||||
|
"fBkNwf82DQXh74in6gaF2Jot7Vg-Vlcp9BUtCEipL9mvcM1EXLVFdV7FcrO20Eve",
|
||||||
|
pkg.TarGzip,
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t Toolchain) newKernelSource() (pkg.Artifact, string) {
|
||||||
|
return t.New("kernel-"+kernelVersion+"-src", 0, nil, nil, nil, `
|
||||||
|
mkdir -p /work/usr/src/
|
||||||
|
cp -r /usr/src/linux /work/usr/src/
|
||||||
|
chmod -R +w /work/usr/src/linux/
|
||||||
|
`, pkg.Path(AbsUsrSrc.Append("linux"), false, kernelSource)), kernelVersion
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[KernelSource] = Metadata{
|
||||||
|
f: Toolchain.newKernelSource,
|
||||||
|
|
||||||
|
Name: "kernel-source",
|
||||||
|
Description: "a writable kernel source tree installed to /usr/src/linux",
|
||||||
|
Website: "https://kernel.org/",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Toolchain) newKernelHeaders() (pkg.Artifact, string) {
|
||||||
|
return t.NewPackage("kernel-headers", kernelVersion, kernelSource, &PackageAttr{
|
||||||
|
Flag: TEarly,
|
||||||
|
}, &MakeHelper{
|
||||||
|
SkipConfigure: true,
|
||||||
|
|
||||||
|
SkipCheck: true,
|
||||||
|
Make: []string{
|
||||||
|
"-f /usr/src/kernel-headers/Makefile",
|
||||||
|
"O=/tmp/kbuild",
|
||||||
|
"LLVM=1",
|
||||||
|
`HOSTLDFLAGS="${LDFLAGS:-''}"`,
|
||||||
|
"INSTALL_HDR_PATH=/work/system",
|
||||||
|
"headers_install",
|
||||||
|
},
|
||||||
|
Install: "# headers installed during make",
|
||||||
|
},
|
||||||
|
Rsync,
|
||||||
|
), kernelVersion
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[KernelHeaders] = Metadata{
|
||||||
|
f: Toolchain.newKernelHeaders,
|
||||||
|
|
||||||
|
Name: "kernel-headers",
|
||||||
|
Description: "an installation of kernel headers",
|
||||||
|
Website: "https://kernel.org/",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Toolchain) newKernel() (pkg.Artifact, string) {
|
||||||
|
return t.NewPackage("kernel", kernelVersion, kernelSource, &PackageAttr{
|
||||||
|
Env: []string{
|
||||||
|
"PATH=/system/sbin",
|
||||||
|
},
|
||||||
|
ScriptEarly: `
|
||||||
|
install -Dm0400 \
|
||||||
|
/usr/src/.config \
|
||||||
|
/tmp/kbuild/.config
|
||||||
|
install -Dm0500 \
|
||||||
|
/usr/src/.installkernel \
|
||||||
|
/sbin/installkernel
|
||||||
|
`,
|
||||||
|
|
||||||
|
Paths: []pkg.ExecPath{
|
||||||
|
pkg.Path(AbsUsrSrc.Append(
|
||||||
|
".config",
|
||||||
|
), false, pkg.NewFile(".config", kernelConfig)),
|
||||||
|
pkg.Path(AbsUsrSrc.Append(
|
||||||
|
".installkernel",
|
||||||
|
), false, pkg.NewFile("installkernel", []byte(`#!/bin/sh -e
|
||||||
|
echo "Installing linux $1..."
|
||||||
|
cp -av "$2" "$4"
|
||||||
|
cp -av "$3" "$4"
|
||||||
|
`))),
|
||||||
|
pkg.Path(AbsUsrSrc.Append(
|
||||||
|
".depmod",
|
||||||
|
), false, pkg.NewFile("depmod", []byte(`#!/bin/sh
|
||||||
|
exec /system/sbin/depmod -m /lib/modules "$@"
|
||||||
|
`))),
|
||||||
|
},
|
||||||
|
|
||||||
|
Patches: []KV{
|
||||||
|
{"f54a91f5337cd918eb86cf600320d25b6cfd8209", `From f54a91f5337cd918eb86cf600320d25b6cfd8209 Mon Sep 17 00:00:00 2001
|
||||||
From: Nathan Chancellor <nathan@kernel.org>
|
From: Nathan Chancellor <nathan@kernel.org>
|
||||||
Date: Sat, 13 Dec 2025 19:58:10 +0900
|
Date: Sat, 13 Dec 2025 19:58:10 +0900
|
||||||
Subject: drm/amd/display: Reduce number of arguments of dcn30's
|
Subject: drm/amd/display: Reduce number of arguments of dcn30's
|
||||||
@@ -604,3 +697,635 @@ index abe51cf3aab2..a244504cc1f2 100644
|
|||||||
for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) {
|
for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) {
|
||||||
--
|
--
|
||||||
cgit 1.2.3-korg
|
cgit 1.2.3-korg
|
||||||
|
`},
|
||||||
|
|
||||||
|
{"6ce6fbfddc5b127e4f57c3b5bfdcf40239a4fc2f", `From 6ce6fbfddc5b127e4f57c3b5bfdcf40239a4fc2f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Nathan Chancellor <nathan@kernel.org>
|
||||||
|
Date: Sat, 13 Dec 2025 19:58:11 +0900
|
||||||
|
Subject: drm/amd/display: Reduce number of arguments of dcn30's
|
||||||
|
CalculateWatermarksAndDRAMSpeedChangeSupport()
|
||||||
|
|
||||||
|
CalculateWatermarksAndDRAMSpeedChangeSupport() has a large number of
|
||||||
|
parameters, which must be passed on the stack. Most of the parameters
|
||||||
|
between the two callsites are the same, so they can be accessed through
|
||||||
|
the existing mode_lib pointer, instead of being passed as explicit
|
||||||
|
arguments. Doing this reduces the stack size of
|
||||||
|
dml30_ModeSupportAndSystemConfigurationFull() from 1912 bytes to 1840
|
||||||
|
bytes building for x86_64 with clang-22, helping stay under the 2048
|
||||||
|
byte limit for display_mode_vba_30.c.
|
||||||
|
|
||||||
|
Additionally, now that there is a pointer to mode_lib->vba available,
|
||||||
|
use 'v' consistently throughout the entire function.
|
||||||
|
|
||||||
|
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
|
||||||
|
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
|
||||||
|
(cherry picked from commit 563dfbefdf633c8d958398ddfa3955f9f40e47d9)
|
||||||
|
---
|
||||||
|
.../amd/display/dc/dml/dcn30/display_mode_vba_30.c | 287 +++++----------------
|
||||||
|
1 file changed, 66 insertions(+), 221 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
|
||||||
|
index 2d19bb8de59c84..1df3412be3465d 100644
|
||||||
|
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
|
||||||
|
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/display_mode_vba_30.c
|
||||||
|
@@ -265,62 +265,23 @@ static void CalculateDynamicMetadataParameters(
|
||||||
|
static void CalculateWatermarksAndDRAMSpeedChangeSupport(
|
||||||
|
struct display_mode_lib *mode_lib,
|
||||||
|
unsigned int PrefetchMode,
|
||||||
|
- unsigned int NumberOfActivePlanes,
|
||||||
|
- unsigned int MaxLineBufferLines,
|
||||||
|
- unsigned int LineBufferSize,
|
||||||
|
- unsigned int DPPOutputBufferPixels,
|
||||||
|
- unsigned int DETBufferSizeInKByte,
|
||||||
|
- unsigned int WritebackInterfaceBufferSize,
|
||||||
|
double DCFCLK,
|
||||||
|
double ReturnBW,
|
||||||
|
- bool GPUVMEnable,
|
||||||
|
- unsigned int dpte_group_bytes[],
|
||||||
|
- unsigned int MetaChunkSize,
|
||||||
|
double UrgentLatency,
|
||||||
|
double ExtraLatency,
|
||||||
|
- double WritebackLatency,
|
||||||
|
- double WritebackChunkSize,
|
||||||
|
double SOCCLK,
|
||||||
|
- double DRAMClockChangeLatency,
|
||||||
|
- double SRExitTime,
|
||||||
|
- double SREnterPlusExitTime,
|
||||||
|
double DCFCLKDeepSleep,
|
||||||
|
unsigned int DPPPerPlane[],
|
||||||
|
- bool DCCEnable[],
|
||||||
|
double DPPCLK[],
|
||||||
|
unsigned int DETBufferSizeY[],
|
||||||
|
unsigned int DETBufferSizeC[],
|
||||||
|
unsigned int SwathHeightY[],
|
||||||
|
unsigned int SwathHeightC[],
|
||||||
|
- unsigned int LBBitPerPixel[],
|
||||||
|
double SwathWidthY[],
|
||||||
|
double SwathWidthC[],
|
||||||
|
- double HRatio[],
|
||||||
|
- double HRatioChroma[],
|
||||||
|
- unsigned int vtaps[],
|
||||||
|
- unsigned int VTAPsChroma[],
|
||||||
|
- double VRatio[],
|
||||||
|
- double VRatioChroma[],
|
||||||
|
- unsigned int HTotal[],
|
||||||
|
- double PixelClock[],
|
||||||
|
- unsigned int BlendingAndTiming[],
|
||||||
|
double BytePerPixelDETY[],
|
||||||
|
double BytePerPixelDETC[],
|
||||||
|
- double DSTXAfterScaler[],
|
||||||
|
- double DSTYAfterScaler[],
|
||||||
|
- bool WritebackEnable[],
|
||||||
|
- enum source_format_class WritebackPixelFormat[],
|
||||||
|
- double WritebackDestinationWidth[],
|
||||||
|
- double WritebackDestinationHeight[],
|
||||||
|
- double WritebackSourceHeight[],
|
||||||
|
- enum clock_change_support *DRAMClockChangeSupport,
|
||||||
|
- double *UrgentWatermark,
|
||||||
|
- double *WritebackUrgentWatermark,
|
||||||
|
- double *DRAMClockChangeWatermark,
|
||||||
|
- double *WritebackDRAMClockChangeWatermark,
|
||||||
|
- double *StutterExitWatermark,
|
||||||
|
- double *StutterEnterPlusExitWatermark,
|
||||||
|
- double *MinActiveDRAMClockChangeLatencySupported);
|
||||||
|
+ enum clock_change_support *DRAMClockChangeSupport);
|
||||||
|
static void CalculateDCFCLKDeepSleep(
|
||||||
|
struct display_mode_lib *mode_lib,
|
||||||
|
unsigned int NumberOfActivePlanes,
|
||||||
|
@@ -2646,62 +2607,23 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
|
||||||
|
CalculateWatermarksAndDRAMSpeedChangeSupport(
|
||||||
|
mode_lib,
|
||||||
|
PrefetchMode,
|
||||||
|
- v->NumberOfActivePlanes,
|
||||||
|
- v->MaxLineBufferLines,
|
||||||
|
- v->LineBufferSize,
|
||||||
|
- v->DPPOutputBufferPixels,
|
||||||
|
- v->DETBufferSizeInKByte[0],
|
||||||
|
- v->WritebackInterfaceBufferSize,
|
||||||
|
v->DCFCLK,
|
||||||
|
v->ReturnBW,
|
||||||
|
- v->GPUVMEnable,
|
||||||
|
- v->dpte_group_bytes,
|
||||||
|
- v->MetaChunkSize,
|
||||||
|
v->UrgentLatency,
|
||||||
|
v->UrgentExtraLatency,
|
||||||
|
- v->WritebackLatency,
|
||||||
|
- v->WritebackChunkSize,
|
||||||
|
v->SOCCLK,
|
||||||
|
- v->FinalDRAMClockChangeLatency,
|
||||||
|
- v->SRExitTime,
|
||||||
|
- v->SREnterPlusExitTime,
|
||||||
|
v->DCFCLKDeepSleep,
|
||||||
|
v->DPPPerPlane,
|
||||||
|
- v->DCCEnable,
|
||||||
|
v->DPPCLK,
|
||||||
|
v->DETBufferSizeY,
|
||||||
|
v->DETBufferSizeC,
|
||||||
|
v->SwathHeightY,
|
||||||
|
v->SwathHeightC,
|
||||||
|
- v->LBBitPerPixel,
|
||||||
|
v->SwathWidthY,
|
||||||
|
v->SwathWidthC,
|
||||||
|
- v->HRatio,
|
||||||
|
- v->HRatioChroma,
|
||||||
|
- v->vtaps,
|
||||||
|
- v->VTAPsChroma,
|
||||||
|
- v->VRatio,
|
||||||
|
- v->VRatioChroma,
|
||||||
|
- v->HTotal,
|
||||||
|
- v->PixelClock,
|
||||||
|
- v->BlendingAndTiming,
|
||||||
|
v->BytePerPixelDETY,
|
||||||
|
v->BytePerPixelDETC,
|
||||||
|
- v->DSTXAfterScaler,
|
||||||
|
- v->DSTYAfterScaler,
|
||||||
|
- v->WritebackEnable,
|
||||||
|
- v->WritebackPixelFormat,
|
||||||
|
- v->WritebackDestinationWidth,
|
||||||
|
- v->WritebackDestinationHeight,
|
||||||
|
- v->WritebackSourceHeight,
|
||||||
|
- &DRAMClockChangeSupport,
|
||||||
|
- &v->UrgentWatermark,
|
||||||
|
- &v->WritebackUrgentWatermark,
|
||||||
|
- &v->DRAMClockChangeWatermark,
|
||||||
|
- &v->WritebackDRAMClockChangeWatermark,
|
||||||
|
- &v->StutterExitWatermark,
|
||||||
|
- &v->StutterEnterPlusExitWatermark,
|
||||||
|
- &v->MinActiveDRAMClockChangeLatencySupported);
|
||||||
|
+ &DRAMClockChangeSupport);
|
||||||
|
|
||||||
|
for (k = 0; k < v->NumberOfActivePlanes; ++k) {
|
||||||
|
if (v->WritebackEnable[k] == true) {
|
||||||
|
@@ -4895,62 +4817,23 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
|
||||||
|
CalculateWatermarksAndDRAMSpeedChangeSupport(
|
||||||
|
mode_lib,
|
||||||
|
v->PrefetchModePerState[i][j],
|
||||||
|
- v->NumberOfActivePlanes,
|
||||||
|
- v->MaxLineBufferLines,
|
||||||
|
- v->LineBufferSize,
|
||||||
|
- v->DPPOutputBufferPixels,
|
||||||
|
- v->DETBufferSizeInKByte[0],
|
||||||
|
- v->WritebackInterfaceBufferSize,
|
||||||
|
v->DCFCLKState[i][j],
|
||||||
|
v->ReturnBWPerState[i][j],
|
||||||
|
- v->GPUVMEnable,
|
||||||
|
- v->dpte_group_bytes,
|
||||||
|
- v->MetaChunkSize,
|
||||||
|
v->UrgLatency[i],
|
||||||
|
v->ExtraLatency,
|
||||||
|
- v->WritebackLatency,
|
||||||
|
- v->WritebackChunkSize,
|
||||||
|
v->SOCCLKPerState[i],
|
||||||
|
- v->FinalDRAMClockChangeLatency,
|
||||||
|
- v->SRExitTime,
|
||||||
|
- v->SREnterPlusExitTime,
|
||||||
|
v->ProjectedDCFCLKDeepSleep[i][j],
|
||||||
|
v->NoOfDPPThisState,
|
||||||
|
- v->DCCEnable,
|
||||||
|
v->RequiredDPPCLKThisState,
|
||||||
|
v->DETBufferSizeYThisState,
|
||||||
|
v->DETBufferSizeCThisState,
|
||||||
|
v->SwathHeightYThisState,
|
||||||
|
v->SwathHeightCThisState,
|
||||||
|
- v->LBBitPerPixel,
|
||||||
|
v->SwathWidthYThisState,
|
||||||
|
v->SwathWidthCThisState,
|
||||||
|
- v->HRatio,
|
||||||
|
- v->HRatioChroma,
|
||||||
|
- v->vtaps,
|
||||||
|
- v->VTAPsChroma,
|
||||||
|
- v->VRatio,
|
||||||
|
- v->VRatioChroma,
|
||||||
|
- v->HTotal,
|
||||||
|
- v->PixelClock,
|
||||||
|
- v->BlendingAndTiming,
|
||||||
|
v->BytePerPixelInDETY,
|
||||||
|
v->BytePerPixelInDETC,
|
||||||
|
- v->DSTXAfterScaler,
|
||||||
|
- v->DSTYAfterScaler,
|
||||||
|
- v->WritebackEnable,
|
||||||
|
- v->WritebackPixelFormat,
|
||||||
|
- v->WritebackDestinationWidth,
|
||||||
|
- v->WritebackDestinationHeight,
|
||||||
|
- v->WritebackSourceHeight,
|
||||||
|
- &v->DRAMClockChangeSupport[i][j],
|
||||||
|
- &v->UrgentWatermark,
|
||||||
|
- &v->WritebackUrgentWatermark,
|
||||||
|
- &v->DRAMClockChangeWatermark,
|
||||||
|
- &v->WritebackDRAMClockChangeWatermark,
|
||||||
|
- &v->StutterExitWatermark,
|
||||||
|
- &v->StutterEnterPlusExitWatermark,
|
||||||
|
- &v->MinActiveDRAMClockChangeLatencySupported);
|
||||||
|
+ &v->DRAMClockChangeSupport[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -5067,63 +4950,25 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
|
||||||
|
static void CalculateWatermarksAndDRAMSpeedChangeSupport(
|
||||||
|
struct display_mode_lib *mode_lib,
|
||||||
|
unsigned int PrefetchMode,
|
||||||
|
- unsigned int NumberOfActivePlanes,
|
||||||
|
- unsigned int MaxLineBufferLines,
|
||||||
|
- unsigned int LineBufferSize,
|
||||||
|
- unsigned int DPPOutputBufferPixels,
|
||||||
|
- unsigned int DETBufferSizeInKByte,
|
||||||
|
- unsigned int WritebackInterfaceBufferSize,
|
||||||
|
double DCFCLK,
|
||||||
|
double ReturnBW,
|
||||||
|
- bool GPUVMEnable,
|
||||||
|
- unsigned int dpte_group_bytes[],
|
||||||
|
- unsigned int MetaChunkSize,
|
||||||
|
double UrgentLatency,
|
||||||
|
double ExtraLatency,
|
||||||
|
- double WritebackLatency,
|
||||||
|
- double WritebackChunkSize,
|
||||||
|
double SOCCLK,
|
||||||
|
- double DRAMClockChangeLatency,
|
||||||
|
- double SRExitTime,
|
||||||
|
- double SREnterPlusExitTime,
|
||||||
|
double DCFCLKDeepSleep,
|
||||||
|
unsigned int DPPPerPlane[],
|
||||||
|
- bool DCCEnable[],
|
||||||
|
double DPPCLK[],
|
||||||
|
unsigned int DETBufferSizeY[],
|
||||||
|
unsigned int DETBufferSizeC[],
|
||||||
|
unsigned int SwathHeightY[],
|
||||||
|
unsigned int SwathHeightC[],
|
||||||
|
- unsigned int LBBitPerPixel[],
|
||||||
|
double SwathWidthY[],
|
||||||
|
double SwathWidthC[],
|
||||||
|
- double HRatio[],
|
||||||
|
- double HRatioChroma[],
|
||||||
|
- unsigned int vtaps[],
|
||||||
|
- unsigned int VTAPsChroma[],
|
||||||
|
- double VRatio[],
|
||||||
|
- double VRatioChroma[],
|
||||||
|
- unsigned int HTotal[],
|
||||||
|
- double PixelClock[],
|
||||||
|
- unsigned int BlendingAndTiming[],
|
||||||
|
double BytePerPixelDETY[],
|
||||||
|
double BytePerPixelDETC[],
|
||||||
|
- double DSTXAfterScaler[],
|
||||||
|
- double DSTYAfterScaler[],
|
||||||
|
- bool WritebackEnable[],
|
||||||
|
- enum source_format_class WritebackPixelFormat[],
|
||||||
|
- double WritebackDestinationWidth[],
|
||||||
|
- double WritebackDestinationHeight[],
|
||||||
|
- double WritebackSourceHeight[],
|
||||||
|
- enum clock_change_support *DRAMClockChangeSupport,
|
||||||
|
- double *UrgentWatermark,
|
||||||
|
- double *WritebackUrgentWatermark,
|
||||||
|
- double *DRAMClockChangeWatermark,
|
||||||
|
- double *WritebackDRAMClockChangeWatermark,
|
||||||
|
- double *StutterExitWatermark,
|
||||||
|
- double *StutterEnterPlusExitWatermark,
|
||||||
|
- double *MinActiveDRAMClockChangeLatencySupported)
|
||||||
|
+ enum clock_change_support *DRAMClockChangeSupport)
|
||||||
|
{
|
||||||
|
+ struct vba_vars_st *v = &mode_lib->vba;
|
||||||
|
double EffectiveLBLatencyHidingY = 0;
|
||||||
|
double EffectiveLBLatencyHidingC = 0;
|
||||||
|
double LinesInDETY[DC__NUM_DPP__MAX] = { 0 };
|
||||||
|
@@ -5142,101 +4987,101 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport(
|
||||||
|
double WritebackDRAMClockChangeLatencyHiding = 0;
|
||||||
|
unsigned int k, j;
|
||||||
|
|
||||||
|
- mode_lib->vba.TotalActiveDPP = 0;
|
||||||
|
- mode_lib->vba.TotalDCCActiveDPP = 0;
|
||||||
|
- for (k = 0; k < NumberOfActivePlanes; ++k) {
|
||||||
|
- mode_lib->vba.TotalActiveDPP = mode_lib->vba.TotalActiveDPP + DPPPerPlane[k];
|
||||||
|
- if (DCCEnable[k] == true) {
|
||||||
|
- mode_lib->vba.TotalDCCActiveDPP = mode_lib->vba.TotalDCCActiveDPP + DPPPerPlane[k];
|
||||||
|
+ v->TotalActiveDPP = 0;
|
||||||
|
+ v->TotalDCCActiveDPP = 0;
|
||||||
|
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
|
||||||
|
+ v->TotalActiveDPP = v->TotalActiveDPP + DPPPerPlane[k];
|
||||||
|
+ if (v->DCCEnable[k] == true) {
|
||||||
|
+ v->TotalDCCActiveDPP = v->TotalDCCActiveDPP + DPPPerPlane[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- *UrgentWatermark = UrgentLatency + ExtraLatency;
|
||||||
|
+ v->UrgentWatermark = UrgentLatency + ExtraLatency;
|
||||||
|
|
||||||
|
- *DRAMClockChangeWatermark = DRAMClockChangeLatency + *UrgentWatermark;
|
||||||
|
+ v->DRAMClockChangeWatermark = v->FinalDRAMClockChangeLatency + v->UrgentWatermark;
|
||||||
|
|
||||||
|
- mode_lib->vba.TotalActiveWriteback = 0;
|
||||||
|
- for (k = 0; k < NumberOfActivePlanes; ++k) {
|
||||||
|
- if (WritebackEnable[k] == true) {
|
||||||
|
- mode_lib->vba.TotalActiveWriteback = mode_lib->vba.TotalActiveWriteback + 1;
|
||||||
|
+ v->TotalActiveWriteback = 0;
|
||||||
|
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
|
||||||
|
+ if (v->WritebackEnable[k] == true) {
|
||||||
|
+ v->TotalActiveWriteback = v->TotalActiveWriteback + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (mode_lib->vba.TotalActiveWriteback <= 1) {
|
||||||
|
- *WritebackUrgentWatermark = WritebackLatency;
|
||||||
|
+ if (v->TotalActiveWriteback <= 1) {
|
||||||
|
+ v->WritebackUrgentWatermark = v->WritebackLatency;
|
||||||
|
} else {
|
||||||
|
- *WritebackUrgentWatermark = WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
|
||||||
|
+ v->WritebackUrgentWatermark = v->WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (mode_lib->vba.TotalActiveWriteback <= 1) {
|
||||||
|
- *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency;
|
||||||
|
+ if (v->TotalActiveWriteback <= 1) {
|
||||||
|
+ v->WritebackDRAMClockChangeWatermark = v->FinalDRAMClockChangeLatency + v->WritebackLatency;
|
||||||
|
} else {
|
||||||
|
- *WritebackDRAMClockChangeWatermark = DRAMClockChangeLatency + WritebackLatency + WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
|
||||||
|
+ v->WritebackDRAMClockChangeWatermark = v->FinalDRAMClockChangeLatency + v->WritebackLatency + v->WritebackChunkSize * 1024.0 / 32.0 / SOCCLK;
|
||||||
|
}
|
||||||
|
|
||||||
|
- for (k = 0; k < NumberOfActivePlanes; ++k) {
|
||||||
|
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
|
||||||
|
|
||||||
|
- mode_lib->vba.LBLatencyHidingSourceLinesY = dml_min((double) MaxLineBufferLines, dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(HRatio[k], 1.0)), 1)) - (vtaps[k] - 1);
|
||||||
|
+ v->LBLatencyHidingSourceLinesY = dml_min((double) v->MaxLineBufferLines, dml_floor(v->LineBufferSize / v->LBBitPerPixel[k] / (SwathWidthY[k] / dml_max(v->HRatio[k], 1.0)), 1)) - (v->vtaps[k] - 1);
|
||||||
|
|
||||||
|
- mode_lib->vba.LBLatencyHidingSourceLinesC = dml_min((double) MaxLineBufferLines, dml_floor(LineBufferSize / LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(HRatioChroma[k], 1.0)), 1)) - (VTAPsChroma[k] - 1);
|
||||||
|
+ v->LBLatencyHidingSourceLinesC = dml_min((double) v->MaxLineBufferLines, dml_floor(v->LineBufferSize / v->LBBitPerPixel[k] / (SwathWidthC[k] / dml_max(v->HRatioChroma[k], 1.0)), 1)) - (v->VTAPsChroma[k] - 1);
|
||||||
|
|
||||||
|
- EffectiveLBLatencyHidingY = mode_lib->vba.LBLatencyHidingSourceLinesY / VRatio[k] * (HTotal[k] / PixelClock[k]);
|
||||||
|
+ EffectiveLBLatencyHidingY = v->LBLatencyHidingSourceLinesY / v->VRatio[k] * (v->HTotal[k] / v->PixelClock[k]);
|
||||||
|
|
||||||
|
- EffectiveLBLatencyHidingC = mode_lib->vba.LBLatencyHidingSourceLinesC / VRatioChroma[k] * (HTotal[k] / PixelClock[k]);
|
||||||
|
+ EffectiveLBLatencyHidingC = v->LBLatencyHidingSourceLinesC / v->VRatioChroma[k] * (v->HTotal[k] / v->PixelClock[k]);
|
||||||
|
|
||||||
|
LinesInDETY[k] = (double) DETBufferSizeY[k] / BytePerPixelDETY[k] / SwathWidthY[k];
|
||||||
|
LinesInDETYRoundedDownToSwath[k] = dml_floor(LinesInDETY[k], SwathHeightY[k]);
|
||||||
|
- FullDETBufferingTimeY[k] = LinesInDETYRoundedDownToSwath[k] * (HTotal[k] / PixelClock[k]) / VRatio[k];
|
||||||
|
+ FullDETBufferingTimeY[k] = LinesInDETYRoundedDownToSwath[k] * (v->HTotal[k] / v->PixelClock[k]) / v->VRatio[k];
|
||||||
|
if (BytePerPixelDETC[k] > 0) {
|
||||||
|
- LinesInDETC = mode_lib->vba.DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k];
|
||||||
|
+ LinesInDETC = v->DETBufferSizeC[k] / BytePerPixelDETC[k] / SwathWidthC[k];
|
||||||
|
LinesInDETCRoundedDownToSwath = dml_floor(LinesInDETC, SwathHeightC[k]);
|
||||||
|
- FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (HTotal[k] / PixelClock[k]) / VRatioChroma[k];
|
||||||
|
+ FullDETBufferingTimeC = LinesInDETCRoundedDownToSwath * (v->HTotal[k] / v->PixelClock[k]) / v->VRatioChroma[k];
|
||||||
|
} else {
|
||||||
|
LinesInDETC = 0;
|
||||||
|
FullDETBufferingTimeC = 999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
- ActiveDRAMClockChangeLatencyMarginY = EffectiveLBLatencyHidingY + FullDETBufferingTimeY[k] - *UrgentWatermark - (HTotal[k] / PixelClock[k]) * (DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) - *DRAMClockChangeWatermark;
|
||||||
|
+ ActiveDRAMClockChangeLatencyMarginY = EffectiveLBLatencyHidingY + FullDETBufferingTimeY[k] - v->UrgentWatermark - (v->HTotal[k] / v->PixelClock[k]) * (v->DSTXAfterScaler[k] / v->HTotal[k] + v->DSTYAfterScaler[k]) - v->DRAMClockChangeWatermark;
|
||||||
|
|
||||||
|
- if (NumberOfActivePlanes > 1) {
|
||||||
|
- ActiveDRAMClockChangeLatencyMarginY = ActiveDRAMClockChangeLatencyMarginY - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightY[k] * HTotal[k] / PixelClock[k] / VRatio[k];
|
||||||
|
+ if (v->NumberOfActivePlanes > 1) {
|
||||||
|
+ ActiveDRAMClockChangeLatencyMarginY = ActiveDRAMClockChangeLatencyMarginY - (1 - 1.0 / v->NumberOfActivePlanes) * SwathHeightY[k] * v->HTotal[k] / v->PixelClock[k] / v->VRatio[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BytePerPixelDETC[k] > 0) {
|
||||||
|
- ActiveDRAMClockChangeLatencyMarginC = EffectiveLBLatencyHidingC + FullDETBufferingTimeC - *UrgentWatermark - (HTotal[k] / PixelClock[k]) * (DSTXAfterScaler[k] / HTotal[k] + DSTYAfterScaler[k]) - *DRAMClockChangeWatermark;
|
||||||
|
+ ActiveDRAMClockChangeLatencyMarginC = EffectiveLBLatencyHidingC + FullDETBufferingTimeC - v->UrgentWatermark - (v->HTotal[k] / v->PixelClock[k]) * (v->DSTXAfterScaler[k] / v->HTotal[k] + v->DSTYAfterScaler[k]) - v->DRAMClockChangeWatermark;
|
||||||
|
|
||||||
|
- if (NumberOfActivePlanes > 1) {
|
||||||
|
- ActiveDRAMClockChangeLatencyMarginC = ActiveDRAMClockChangeLatencyMarginC - (1 - 1.0 / NumberOfActivePlanes) * SwathHeightC[k] * HTotal[k] / PixelClock[k] / VRatioChroma[k];
|
||||||
|
+ if (v->NumberOfActivePlanes > 1) {
|
||||||
|
+ ActiveDRAMClockChangeLatencyMarginC = ActiveDRAMClockChangeLatencyMarginC - (1 - 1.0 / v->NumberOfActivePlanes) * SwathHeightC[k] * v->HTotal[k] / v->PixelClock[k] / v->VRatioChroma[k];
|
||||||
|
}
|
||||||
|
- mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min(ActiveDRAMClockChangeLatencyMarginY, ActiveDRAMClockChangeLatencyMarginC);
|
||||||
|
+ v->ActiveDRAMClockChangeLatencyMargin[k] = dml_min(ActiveDRAMClockChangeLatencyMarginY, ActiveDRAMClockChangeLatencyMarginC);
|
||||||
|
} else {
|
||||||
|
- mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = ActiveDRAMClockChangeLatencyMarginY;
|
||||||
|
+ v->ActiveDRAMClockChangeLatencyMargin[k] = ActiveDRAMClockChangeLatencyMarginY;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (WritebackEnable[k] == true) {
|
||||||
|
+ if (v->WritebackEnable[k] == true) {
|
||||||
|
|
||||||
|
- WritebackDRAMClockChangeLatencyHiding = WritebackInterfaceBufferSize * 1024 / (WritebackDestinationWidth[k] * WritebackDestinationHeight[k] / (WritebackSourceHeight[k] * HTotal[k] / PixelClock[k]) * 4);
|
||||||
|
- if (WritebackPixelFormat[k] == dm_444_64) {
|
||||||
|
+ WritebackDRAMClockChangeLatencyHiding = v->WritebackInterfaceBufferSize * 1024 / (v->WritebackDestinationWidth[k] * v->WritebackDestinationHeight[k] / (v->WritebackSourceHeight[k] * v->HTotal[k] / v->PixelClock[k]) * 4);
|
||||||
|
+ if (v->WritebackPixelFormat[k] == dm_444_64) {
|
||||||
|
WritebackDRAMClockChangeLatencyHiding = WritebackDRAMClockChangeLatencyHiding / 2;
|
||||||
|
}
|
||||||
|
- if (mode_lib->vba.WritebackConfiguration == dm_whole_buffer_for_single_stream_interleave) {
|
||||||
|
+ if (v->WritebackConfiguration == dm_whole_buffer_for_single_stream_interleave) {
|
||||||
|
WritebackDRAMClockChangeLatencyHiding = WritebackDRAMClockChangeLatencyHiding * 2;
|
||||||
|
}
|
||||||
|
- WritebackDRAMClockChangeLatencyMargin = WritebackDRAMClockChangeLatencyHiding - mode_lib->vba.WritebackDRAMClockChangeWatermark;
|
||||||
|
- mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] = dml_min(mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k], WritebackDRAMClockChangeLatencyMargin);
|
||||||
|
+ WritebackDRAMClockChangeLatencyMargin = WritebackDRAMClockChangeLatencyHiding - v->WritebackDRAMClockChangeWatermark;
|
||||||
|
+ v->ActiveDRAMClockChangeLatencyMargin[k] = dml_min(v->ActiveDRAMClockChangeLatencyMargin[k], WritebackDRAMClockChangeLatencyMargin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- mode_lib->vba.MinActiveDRAMClockChangeMargin = 999999;
|
||||||
|
+ v->MinActiveDRAMClockChangeMargin = 999999;
|
||||||
|
PlaneWithMinActiveDRAMClockChangeMargin = 0;
|
||||||
|
- for (k = 0; k < NumberOfActivePlanes; ++k) {
|
||||||
|
- if (mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] < mode_lib->vba.MinActiveDRAMClockChangeMargin) {
|
||||||
|
- mode_lib->vba.MinActiveDRAMClockChangeMargin = mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k];
|
||||||
|
- if (BlendingAndTiming[k] == k) {
|
||||||
|
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
|
||||||
|
+ if (v->ActiveDRAMClockChangeLatencyMargin[k] < v->MinActiveDRAMClockChangeMargin) {
|
||||||
|
+ v->MinActiveDRAMClockChangeMargin = v->ActiveDRAMClockChangeLatencyMargin[k];
|
||||||
|
+ if (v->BlendingAndTiming[k] == k) {
|
||||||
|
PlaneWithMinActiveDRAMClockChangeMargin = k;
|
||||||
|
} else {
|
||||||
|
- for (j = 0; j < NumberOfActivePlanes; ++j) {
|
||||||
|
- if (BlendingAndTiming[k] == j) {
|
||||||
|
+ for (j = 0; j < v->NumberOfActivePlanes; ++j) {
|
||||||
|
+ if (v->BlendingAndTiming[k] == j) {
|
||||||
|
PlaneWithMinActiveDRAMClockChangeMargin = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -5244,40 +5089,40 @@ static void CalculateWatermarksAndDRAMSpeedChangeSupport(
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- *MinActiveDRAMClockChangeLatencySupported = mode_lib->vba.MinActiveDRAMClockChangeMargin + DRAMClockChangeLatency;
|
||||||
|
+ v->MinActiveDRAMClockChangeLatencySupported = v->MinActiveDRAMClockChangeMargin + v->FinalDRAMClockChangeLatency;
|
||||||
|
|
||||||
|
SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = 999999;
|
||||||
|
- for (k = 0; k < NumberOfActivePlanes; ++k) {
|
||||||
|
- if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (BlendingAndTiming[k] == k)) && !(BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin) && mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k] < SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank) {
|
||||||
|
- SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k];
|
||||||
|
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
|
||||||
|
+ if (!((k == PlaneWithMinActiveDRAMClockChangeMargin) && (v->BlendingAndTiming[k] == k)) && !(v->BlendingAndTiming[k] == PlaneWithMinActiveDRAMClockChangeMargin) && v->ActiveDRAMClockChangeLatencyMargin[k] < SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank) {
|
||||||
|
+ SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank = v->ActiveDRAMClockChangeLatencyMargin[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- mode_lib->vba.TotalNumberOfActiveOTG = 0;
|
||||||
|
- for (k = 0; k < NumberOfActivePlanes; ++k) {
|
||||||
|
- if (BlendingAndTiming[k] == k) {
|
||||||
|
- mode_lib->vba.TotalNumberOfActiveOTG = mode_lib->vba.TotalNumberOfActiveOTG + 1;
|
||||||
|
+ v->TotalNumberOfActiveOTG = 0;
|
||||||
|
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
|
||||||
|
+ if (v->BlendingAndTiming[k] == k) {
|
||||||
|
+ v->TotalNumberOfActiveOTG = v->TotalNumberOfActiveOTG + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (mode_lib->vba.MinActiveDRAMClockChangeMargin > 0) {
|
||||||
|
+ if (v->MinActiveDRAMClockChangeMargin > 0) {
|
||||||
|
*DRAMClockChangeSupport = dm_dram_clock_change_vactive;
|
||||||
|
- } else if (((mode_lib->vba.SynchronizedVBlank == true || mode_lib->vba.TotalNumberOfActiveOTG == 1 || SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank > 0) && PrefetchMode == 0)) {
|
||||||
|
+ } else if (((v->SynchronizedVBlank == true || v->TotalNumberOfActiveOTG == 1 || SecondMinActiveDRAMClockChangeMarginOneDisplayInVBLank > 0) && PrefetchMode == 0)) {
|
||||||
|
*DRAMClockChangeSupport = dm_dram_clock_change_vblank;
|
||||||
|
} else {
|
||||||
|
*DRAMClockChangeSupport = dm_dram_clock_change_unsupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
FullDETBufferingTimeYStutterCriticalPlane = FullDETBufferingTimeY[0];
|
||||||
|
- for (k = 0; k < NumberOfActivePlanes; ++k) {
|
||||||
|
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
|
||||||
|
if (FullDETBufferingTimeY[k] <= FullDETBufferingTimeYStutterCriticalPlane) {
|
||||||
|
FullDETBufferingTimeYStutterCriticalPlane = FullDETBufferingTimeY[k];
|
||||||
|
- TimeToFinishSwathTransferStutterCriticalPlane = (SwathHeightY[k] - (LinesInDETY[k] - LinesInDETYRoundedDownToSwath[k])) * (HTotal[k] / PixelClock[k]) / VRatio[k];
|
||||||
|
+ TimeToFinishSwathTransferStutterCriticalPlane = (SwathHeightY[k] - (LinesInDETY[k] - LinesInDETYRoundedDownToSwath[k])) * (v->HTotal[k] / v->PixelClock[k]) / v->VRatio[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- *StutterExitWatermark = SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep;
|
||||||
|
- *StutterEnterPlusExitWatermark = dml_max(SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep, TimeToFinishSwathTransferStutterCriticalPlane);
|
||||||
|
+ v->StutterExitWatermark = v->SRExitTime + ExtraLatency + 10 / DCFCLKDeepSleep;
|
||||||
|
+ v->StutterEnterPlusExitWatermark = dml_max(v->SREnterPlusExitTime + ExtraLatency + 10 / DCFCLKDeepSleep, TimeToFinishSwathTransferStutterCriticalPlane);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
--
|
||||||
|
cgit 1.2.3-korg
|
||||||
|
`},
|
||||||
|
},
|
||||||
|
|
||||||
|
Flag: TExclusive,
|
||||||
|
}, &MakeHelper{
|
||||||
|
OmitDefaults: true,
|
||||||
|
SkipConfigure: true,
|
||||||
|
|
||||||
|
// Build, install, and boot kernel before running kselftest on it.
|
||||||
|
SkipCheck: true,
|
||||||
|
|
||||||
|
Make: []string{
|
||||||
|
"-f /usr/src/kernel/Makefile",
|
||||||
|
"O=/tmp/kbuild",
|
||||||
|
|
||||||
|
"LLVM=1",
|
||||||
|
"KBUILD_BUILD_VERSION='1-Rosa'",
|
||||||
|
"KBUILD_BUILD_TIMESTAMP='2106-02-07 06:28:15 UTC'",
|
||||||
|
"KBUILD_BUILD_USER=kbuild",
|
||||||
|
"KBUILD_BUILD_HOST=localhost",
|
||||||
|
"all",
|
||||||
|
},
|
||||||
|
Install: `
|
||||||
|
# kernel is not aware of kmod moduledir
|
||||||
|
install -Dm0500 \
|
||||||
|
/usr/src/.depmod \
|
||||||
|
/sbin/depmod
|
||||||
|
|
||||||
|
make \
|
||||||
|
` + jobsFlagE + ` \
|
||||||
|
-f /usr/src/kernel/Makefile \
|
||||||
|
O=/tmp/kbuild \
|
||||||
|
LLVM=1 \
|
||||||
|
INSTALL_PATH=/work \
|
||||||
|
install \
|
||||||
|
INSTALL_MOD_PATH=/work/system \
|
||||||
|
DEPMOD=/sbin/depmod \
|
||||||
|
modules_install
|
||||||
|
rm -v /work/system/lib/modules/` + kernelVersion + `/build
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
Flex,
|
||||||
|
Bison,
|
||||||
|
M4,
|
||||||
|
Tar,
|
||||||
|
Perl,
|
||||||
|
BC,
|
||||||
|
Sed,
|
||||||
|
Gawk,
|
||||||
|
Coreutils,
|
||||||
|
Diffutils,
|
||||||
|
Python,
|
||||||
|
|
||||||
|
XZ,
|
||||||
|
Gzip,
|
||||||
|
Kmod,
|
||||||
|
Elfutils,
|
||||||
|
UtilLinux,
|
||||||
|
KernelHeaders,
|
||||||
|
), kernelVersion
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Kernel] = Metadata{
|
||||||
|
f: Toolchain.newKernel,
|
||||||
|
|
||||||
|
Name: "kernel",
|
||||||
|
Description: "the generic Rosa OS linux kernel",
|
||||||
|
Website: "https://kernel.org/",
|
||||||
|
|
||||||
|
ID: 375621,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Toolchain) newGenInitCPIO() (pkg.Artifact, string) {
|
||||||
|
return t.New("gen_init_cpio-"+kernelVersion, 0, nil, nil, nil, `
|
||||||
|
mkdir -p /work/system/bin/
|
||||||
|
cc -o /work/system/bin/gen_init_cpio /usr/src/linux/usr/gen_init_cpio.c
|
||||||
|
`, pkg.Path(AbsUsrSrc.Append("linux"), false, kernelSource)), kernelVersion
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[GenInitCPIO] = Metadata{
|
||||||
|
f: Toolchain.newGenInitCPIO,
|
||||||
|
|
||||||
|
Name: "gen_init_cpio",
|
||||||
|
Description: "a program in the kernel source tree for creating initramfs archive",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Toolchain) newFirmware() (pkg.Artifact, string) {
|
||||||
|
const (
|
||||||
|
version = "20260410"
|
||||||
|
checksum = "J8PdQlGqwrivpskPzbL6xacqR6mlKtXpe5RpzFfVzKPAgG81ZRXsc3qrxwdGJbil"
|
||||||
|
)
|
||||||
|
return t.NewPackage("firmware", version, newFromGitLab(
|
||||||
|
"gitlab.com",
|
||||||
|
"kernel-firmware/linux-firmware",
|
||||||
|
version,
|
||||||
|
checksum,
|
||||||
|
), &PackageAttr{
|
||||||
|
// dedup creates temporary file
|
||||||
|
Writable: true,
|
||||||
|
// does not use configure
|
||||||
|
EnterSource: true,
|
||||||
|
|
||||||
|
Env: []string{
|
||||||
|
"HOME=/proc/nonexistent",
|
||||||
|
},
|
||||||
|
}, &MakeHelper{
|
||||||
|
OmitDefaults: true,
|
||||||
|
SkipConfigure: true,
|
||||||
|
InPlace: true,
|
||||||
|
|
||||||
|
Make: []string{
|
||||||
|
"DESTDIR=/work/system",
|
||||||
|
"install-zst",
|
||||||
|
},
|
||||||
|
SkipCheck: true, // requires pre-commit
|
||||||
|
Install: "make " + jobsFlagE + " DESTDIR=/work/system dedup",
|
||||||
|
},
|
||||||
|
Parallel,
|
||||||
|
Rdfind,
|
||||||
|
Zstd,
|
||||||
|
Findutils,
|
||||||
|
Coreutils,
|
||||||
|
), version
|
||||||
|
}
|
||||||
|
func init() {
|
||||||
|
artifactsM[Firmware] = Metadata{
|
||||||
|
f: Toolchain.newFirmware,
|
||||||
|
|
||||||
|
Name: "firmware",
|
||||||
|
Description: "firmware blobs for use with the Linux kernel",
|
||||||
|
Website: "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/",
|
||||||
|
|
||||||
|
ID: 141464,
|
||||||
|
}
|
||||||
|
}
|
||||||
+20
-10
@@ -1,16 +1,16 @@
|
|||||||
#
|
#
|
||||||
# Automatically generated file; DO NOT EDIT.
|
# Automatically generated file; DO NOT EDIT.
|
||||||
# Linux/x86 6.12.87 Kernel Configuration
|
# Linux/x86 6.12.80 Kernel Configuration
|
||||||
#
|
#
|
||||||
CONFIG_CC_VERSION_TEXT="clang version 22.1.5"
|
CONFIG_CC_VERSION_TEXT="clang version 22.1.2"
|
||||||
CONFIG_GCC_VERSION=0
|
CONFIG_GCC_VERSION=0
|
||||||
CONFIG_CC_IS_CLANG=y
|
CONFIG_CC_IS_CLANG=y
|
||||||
CONFIG_CLANG_VERSION=220105
|
CONFIG_CLANG_VERSION=220102
|
||||||
CONFIG_AS_IS_LLVM=y
|
CONFIG_AS_IS_LLVM=y
|
||||||
CONFIG_AS_VERSION=220105
|
CONFIG_AS_VERSION=220102
|
||||||
CONFIG_LD_VERSION=0
|
CONFIG_LD_VERSION=0
|
||||||
CONFIG_LD_IS_LLD=y
|
CONFIG_LD_IS_LLD=y
|
||||||
CONFIG_LLD_VERSION=220105
|
CONFIG_LLD_VERSION=220102
|
||||||
CONFIG_RUSTC_VERSION=0
|
CONFIG_RUSTC_VERSION=0
|
||||||
CONFIG_RUSTC_LLVM_VERSION=0
|
CONFIG_RUSTC_LLVM_VERSION=0
|
||||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||||
@@ -3175,8 +3175,14 @@ CONFIG_PATA_ACPI=y
|
|||||||
CONFIG_ATA_GENERIC=y
|
CONFIG_ATA_GENERIC=y
|
||||||
CONFIG_PATA_LEGACY=m
|
CONFIG_PATA_LEGACY=m
|
||||||
CONFIG_MD=y
|
CONFIG_MD=y
|
||||||
# CONFIG_BLK_DEV_MD is not set
|
CONFIG_BLK_DEV_MD=m
|
||||||
CONFIG_MD_BITMAP_FILE=y
|
CONFIG_MD_BITMAP_FILE=y
|
||||||
|
CONFIG_MD_LINEAR=m
|
||||||
|
CONFIG_MD_RAID0=m
|
||||||
|
CONFIG_MD_RAID1=m
|
||||||
|
CONFIG_MD_RAID10=m
|
||||||
|
CONFIG_MD_RAID456=m
|
||||||
|
CONFIG_MD_CLUSTER=m
|
||||||
CONFIG_BCACHE=m
|
CONFIG_BCACHE=m
|
||||||
# CONFIG_BCACHE_DEBUG is not set
|
# CONFIG_BCACHE_DEBUG is not set
|
||||||
# CONFIG_BCACHE_ASYNC_REGISTRATION is not set
|
# CONFIG_BCACHE_ASYNC_REGISTRATION is not set
|
||||||
@@ -3199,7 +3205,7 @@ CONFIG_DM_ERA=m
|
|||||||
CONFIG_DM_CLONE=m
|
CONFIG_DM_CLONE=m
|
||||||
CONFIG_DM_MIRROR=m
|
CONFIG_DM_MIRROR=m
|
||||||
CONFIG_DM_LOG_USERSPACE=m
|
CONFIG_DM_LOG_USERSPACE=m
|
||||||
# CONFIG_DM_RAID is not set
|
CONFIG_DM_RAID=m
|
||||||
CONFIG_DM_ZERO=m
|
CONFIG_DM_ZERO=m
|
||||||
CONFIG_DM_MULTIPATH=m
|
CONFIG_DM_MULTIPATH=m
|
||||||
CONFIG_DM_MULTIPATH_QL=m
|
CONFIG_DM_MULTIPATH_QL=m
|
||||||
@@ -11630,7 +11636,10 @@ CONFIG_RANDSTRUCT_NONE=y
|
|||||||
|
|
||||||
CONFIG_XOR_BLOCKS=m
|
CONFIG_XOR_BLOCKS=m
|
||||||
CONFIG_ASYNC_CORE=m
|
CONFIG_ASYNC_CORE=m
|
||||||
|
CONFIG_ASYNC_MEMCPY=m
|
||||||
CONFIG_ASYNC_XOR=m
|
CONFIG_ASYNC_XOR=m
|
||||||
|
CONFIG_ASYNC_PQ=m
|
||||||
|
CONFIG_ASYNC_RAID6_RECOV=m
|
||||||
CONFIG_CRYPTO=y
|
CONFIG_CRYPTO=y
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -11916,6 +11925,8 @@ CONFIG_BINARY_PRINTF=y
|
|||||||
#
|
#
|
||||||
# Library routines
|
# Library routines
|
||||||
#
|
#
|
||||||
|
CONFIG_RAID6_PQ=m
|
||||||
|
CONFIG_RAID6_PQ_BENCHMARK=y
|
||||||
CONFIG_LINEAR_RANGES=y
|
CONFIG_LINEAR_RANGES=y
|
||||||
CONFIG_PACKING=y
|
CONFIG_PACKING=y
|
||||||
CONFIG_BITREVERSE=y
|
CONFIG_BITREVERSE=y
|
||||||
@@ -12137,9 +12148,7 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
|
|||||||
# CONFIG_DEBUG_INFO_DWARF4 is not set
|
# CONFIG_DEBUG_INFO_DWARF4 is not set
|
||||||
# CONFIG_DEBUG_INFO_DWARF5 is not set
|
# CONFIG_DEBUG_INFO_DWARF5 is not set
|
||||||
# CONFIG_DEBUG_INFO_REDUCED is not set
|
# CONFIG_DEBUG_INFO_REDUCED is not set
|
||||||
# CONFIG_DEBUG_INFO_COMPRESSED_NONE is not set
|
CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
|
||||||
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
|
|
||||||
CONFIG_DEBUG_INFO_COMPRESSED_ZSTD=y
|
|
||||||
# CONFIG_DEBUG_INFO_SPLIT is not set
|
# CONFIG_DEBUG_INFO_SPLIT is not set
|
||||||
# CONFIG_GDB_SCRIPTS is not set
|
# CONFIG_GDB_SCRIPTS is not set
|
||||||
CONFIG_FRAME_WARN=2048
|
CONFIG_FRAME_WARN=2048
|
||||||
@@ -12462,6 +12471,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
|
|||||||
# CONFIG_INTERVAL_TREE_TEST is not set
|
# CONFIG_INTERVAL_TREE_TEST is not set
|
||||||
# CONFIG_PERCPU_TEST is not set
|
# CONFIG_PERCPU_TEST is not set
|
||||||
# CONFIG_ATOMIC64_SELFTEST is not set
|
# CONFIG_ATOMIC64_SELFTEST is not set
|
||||||
|
# CONFIG_ASYNC_RAID6_TEST is not set
|
||||||
# CONFIG_TEST_HEXDUMP is not set
|
# CONFIG_TEST_HEXDUMP is not set
|
||||||
# CONFIG_TEST_KSTRTOX is not set
|
# CONFIG_TEST_KSTRTOX is not set
|
||||||
# CONFIG_TEST_PRINTF is not set
|
# CONFIG_TEST_PRINTF is not set
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed kernel_amd64.config
|
||||||
|
var kernelConfig []byte
|
||||||
|
|
||||||
|
const kernelName = "bzImage"
|
||||||
+22
-7
@@ -1,16 +1,16 @@
|
|||||||
#
|
#
|
||||||
# Automatically generated file; DO NOT EDIT.
|
# Automatically generated file; DO NOT EDIT.
|
||||||
# Linux/arm64 6.12.83 Kernel Configuration
|
# Linux/arm64 6.12.80 Kernel Configuration
|
||||||
#
|
#
|
||||||
CONFIG_CC_VERSION_TEXT="clang version 22.1.4"
|
CONFIG_CC_VERSION_TEXT="clang version 21.1.8"
|
||||||
CONFIG_GCC_VERSION=0
|
CONFIG_GCC_VERSION=0
|
||||||
CONFIG_CC_IS_CLANG=y
|
CONFIG_CC_IS_CLANG=y
|
||||||
CONFIG_CLANG_VERSION=220104
|
CONFIG_CLANG_VERSION=210108
|
||||||
CONFIG_AS_IS_LLVM=y
|
CONFIG_AS_IS_LLVM=y
|
||||||
CONFIG_AS_VERSION=220104
|
CONFIG_AS_VERSION=210108
|
||||||
CONFIG_LD_VERSION=0
|
CONFIG_LD_VERSION=0
|
||||||
CONFIG_LD_IS_LLD=y
|
CONFIG_LD_IS_LLD=y
|
||||||
CONFIG_LLD_VERSION=220104
|
CONFIG_LLD_VERSION=210108
|
||||||
CONFIG_RUSTC_VERSION=0
|
CONFIG_RUSTC_VERSION=0
|
||||||
CONFIG_RUSTC_LLVM_VERSION=0
|
CONFIG_RUSTC_LLVM_VERSION=0
|
||||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||||
@@ -3253,8 +3253,14 @@ CONFIG_PATA_ACPI=y
|
|||||||
CONFIG_ATA_GENERIC=y
|
CONFIG_ATA_GENERIC=y
|
||||||
CONFIG_PATA_LEGACY=m
|
CONFIG_PATA_LEGACY=m
|
||||||
CONFIG_MD=y
|
CONFIG_MD=y
|
||||||
# CONFIG_BLK_DEV_MD is not set
|
CONFIG_BLK_DEV_MD=m
|
||||||
CONFIG_MD_BITMAP_FILE=y
|
CONFIG_MD_BITMAP_FILE=y
|
||||||
|
CONFIG_MD_LINEAR=m
|
||||||
|
CONFIG_MD_RAID0=m
|
||||||
|
CONFIG_MD_RAID1=m
|
||||||
|
CONFIG_MD_RAID10=m
|
||||||
|
CONFIG_MD_RAID456=m
|
||||||
|
CONFIG_MD_CLUSTER=m
|
||||||
CONFIG_BCACHE=m
|
CONFIG_BCACHE=m
|
||||||
# CONFIG_BCACHE_DEBUG is not set
|
# CONFIG_BCACHE_DEBUG is not set
|
||||||
# CONFIG_BCACHE_ASYNC_REGISTRATION is not set
|
# CONFIG_BCACHE_ASYNC_REGISTRATION is not set
|
||||||
@@ -3277,7 +3283,7 @@ CONFIG_DM_ERA=m
|
|||||||
CONFIG_DM_CLONE=m
|
CONFIG_DM_CLONE=m
|
||||||
CONFIG_DM_MIRROR=m
|
CONFIG_DM_MIRROR=m
|
||||||
CONFIG_DM_LOG_USERSPACE=m
|
CONFIG_DM_LOG_USERSPACE=m
|
||||||
# CONFIG_DM_RAID is not set
|
CONFIG_DM_RAID=m
|
||||||
CONFIG_DM_ZERO=m
|
CONFIG_DM_ZERO=m
|
||||||
CONFIG_DM_MULTIPATH=m
|
CONFIG_DM_MULTIPATH=m
|
||||||
CONFIG_DM_MULTIPATH_QL=m
|
CONFIG_DM_MULTIPATH_QL=m
|
||||||
@@ -10294,6 +10300,7 @@ CONFIG_ALTERA_MSGDMA=m
|
|||||||
# CONFIG_AMBA_PL08X is not set
|
# CONFIG_AMBA_PL08X is not set
|
||||||
CONFIG_APPLE_ADMAC=m
|
CONFIG_APPLE_ADMAC=m
|
||||||
CONFIG_AXI_DMAC=m
|
CONFIG_AXI_DMAC=m
|
||||||
|
CONFIG_BCM_SBA_RAID=m
|
||||||
CONFIG_DMA_BCM2835=m
|
CONFIG_DMA_BCM2835=m
|
||||||
CONFIG_DMA_SUN6I=m
|
CONFIG_DMA_SUN6I=m
|
||||||
CONFIG_DW_AXI_DMAC=m
|
CONFIG_DW_AXI_DMAC=m
|
||||||
@@ -13285,7 +13292,12 @@ CONFIG_RANDSTRUCT_NONE=y
|
|||||||
|
|
||||||
CONFIG_XOR_BLOCKS=m
|
CONFIG_XOR_BLOCKS=m
|
||||||
CONFIG_ASYNC_CORE=m
|
CONFIG_ASYNC_CORE=m
|
||||||
|
CONFIG_ASYNC_MEMCPY=m
|
||||||
CONFIG_ASYNC_XOR=m
|
CONFIG_ASYNC_XOR=m
|
||||||
|
CONFIG_ASYNC_PQ=m
|
||||||
|
CONFIG_ASYNC_RAID6_RECOV=m
|
||||||
|
CONFIG_ASYNC_TX_DISABLE_PQ_VAL_DMA=y
|
||||||
|
CONFIG_ASYNC_TX_DISABLE_XOR_VAL_DMA=y
|
||||||
CONFIG_CRYPTO=y
|
CONFIG_CRYPTO=y
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -13628,6 +13640,8 @@ CONFIG_BINARY_PRINTF=y
|
|||||||
#
|
#
|
||||||
# Library routines
|
# Library routines
|
||||||
#
|
#
|
||||||
|
CONFIG_RAID6_PQ=m
|
||||||
|
CONFIG_RAID6_PQ_BENCHMARK=y
|
||||||
CONFIG_LINEAR_RANGES=y
|
CONFIG_LINEAR_RANGES=y
|
||||||
CONFIG_PACKING=y
|
CONFIG_PACKING=y
|
||||||
CONFIG_BITREVERSE=y
|
CONFIG_BITREVERSE=y
|
||||||
@@ -14158,6 +14172,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
|
|||||||
# CONFIG_INTERVAL_TREE_TEST is not set
|
# CONFIG_INTERVAL_TREE_TEST is not set
|
||||||
# CONFIG_PERCPU_TEST is not set
|
# CONFIG_PERCPU_TEST is not set
|
||||||
# CONFIG_ATOMIC64_SELFTEST is not set
|
# CONFIG_ATOMIC64_SELFTEST is not set
|
||||||
|
# CONFIG_ASYNC_RAID6_TEST is not set
|
||||||
# CONFIG_TEST_HEXDUMP is not set
|
# CONFIG_TEST_HEXDUMP is not set
|
||||||
# CONFIG_TEST_KSTRTOX is not set
|
# CONFIG_TEST_KSTRTOX is not set
|
||||||
# CONFIG_TEST_PRINTF is not set
|
# CONFIG_TEST_PRINTF is not set
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package rosa
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed kernel_arm64.config
|
||||||
|
var kernelConfig []byte
|
||||||
|
|
||||||
|
const kernelName = "vmlinuz.efi"
|
||||||
+20
-3
@@ -1,6 +1,6 @@
|
|||||||
#
|
#
|
||||||
# Automatically generated file; DO NOT EDIT.
|
# Automatically generated file; DO NOT EDIT.
|
||||||
# Linux/riscv 6.12.80 Kernel Configuration
|
# Linux/riscv 6.12.77 Kernel Configuration
|
||||||
#
|
#
|
||||||
CONFIG_CC_VERSION_TEXT="clang version 22.1.2"
|
CONFIG_CC_VERSION_TEXT="clang version 22.1.2"
|
||||||
CONFIG_GCC_VERSION=0
|
CONFIG_GCC_VERSION=0
|
||||||
@@ -37,6 +37,11 @@ CONFIG_BUILD_SALT=""
|
|||||||
CONFIG_HAVE_KERNEL_GZIP=y
|
CONFIG_HAVE_KERNEL_GZIP=y
|
||||||
CONFIG_HAVE_KERNEL_ZSTD=y
|
CONFIG_HAVE_KERNEL_ZSTD=y
|
||||||
# CONFIG_KERNEL_GZIP is not set
|
# CONFIG_KERNEL_GZIP is not set
|
||||||
|
# CONFIG_KERNEL_BZIP2 is not set
|
||||||
|
# CONFIG_KERNEL_LZMA is not set
|
||||||
|
# CONFIG_KERNEL_XZ is not set
|
||||||
|
# CONFIG_KERNEL_LZO is not set
|
||||||
|
# CONFIG_KERNEL_LZ4 is not set
|
||||||
CONFIG_KERNEL_ZSTD=y
|
CONFIG_KERNEL_ZSTD=y
|
||||||
CONFIG_DEFAULT_INIT=""
|
CONFIG_DEFAULT_INIT=""
|
||||||
CONFIG_DEFAULT_HOSTNAME="rosa-early"
|
CONFIG_DEFAULT_HOSTNAME="rosa-early"
|
||||||
@@ -2843,8 +2848,14 @@ CONFIG_PATA_ACPI=y
|
|||||||
CONFIG_ATA_GENERIC=y
|
CONFIG_ATA_GENERIC=y
|
||||||
CONFIG_PATA_LEGACY=m
|
CONFIG_PATA_LEGACY=m
|
||||||
CONFIG_MD=y
|
CONFIG_MD=y
|
||||||
# CONFIG_BLK_DEV_MD is not set
|
CONFIG_BLK_DEV_MD=m
|
||||||
CONFIG_MD_BITMAP_FILE=y
|
CONFIG_MD_BITMAP_FILE=y
|
||||||
|
CONFIG_MD_LINEAR=m
|
||||||
|
CONFIG_MD_RAID0=m
|
||||||
|
CONFIG_MD_RAID1=m
|
||||||
|
CONFIG_MD_RAID10=m
|
||||||
|
CONFIG_MD_RAID456=m
|
||||||
|
CONFIG_MD_CLUSTER=m
|
||||||
CONFIG_BCACHE=m
|
CONFIG_BCACHE=m
|
||||||
# CONFIG_BCACHE_DEBUG is not set
|
# CONFIG_BCACHE_DEBUG is not set
|
||||||
# CONFIG_BCACHE_ASYNC_REGISTRATION is not set
|
# CONFIG_BCACHE_ASYNC_REGISTRATION is not set
|
||||||
@@ -2867,7 +2878,7 @@ CONFIG_DM_ERA=m
|
|||||||
CONFIG_DM_CLONE=m
|
CONFIG_DM_CLONE=m
|
||||||
CONFIG_DM_MIRROR=m
|
CONFIG_DM_MIRROR=m
|
||||||
CONFIG_DM_LOG_USERSPACE=m
|
CONFIG_DM_LOG_USERSPACE=m
|
||||||
# CONFIG_DM_RAID is not set
|
CONFIG_DM_RAID=m
|
||||||
CONFIG_DM_ZERO=m
|
CONFIG_DM_ZERO=m
|
||||||
CONFIG_DM_MULTIPATH=m
|
CONFIG_DM_MULTIPATH=m
|
||||||
CONFIG_DM_MULTIPATH_QL=m
|
CONFIG_DM_MULTIPATH_QL=m
|
||||||
@@ -10644,7 +10655,10 @@ CONFIG_RANDSTRUCT_NONE=y
|
|||||||
|
|
||||||
CONFIG_XOR_BLOCKS=m
|
CONFIG_XOR_BLOCKS=m
|
||||||
CONFIG_ASYNC_CORE=m
|
CONFIG_ASYNC_CORE=m
|
||||||
|
CONFIG_ASYNC_MEMCPY=m
|
||||||
CONFIG_ASYNC_XOR=m
|
CONFIG_ASYNC_XOR=m
|
||||||
|
CONFIG_ASYNC_PQ=m
|
||||||
|
CONFIG_ASYNC_RAID6_RECOV=m
|
||||||
CONFIG_CRYPTO=y
|
CONFIG_CRYPTO=y
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -10904,6 +10918,8 @@ CONFIG_BINARY_PRINTF=y
|
|||||||
#
|
#
|
||||||
# Library routines
|
# Library routines
|
||||||
#
|
#
|
||||||
|
CONFIG_RAID6_PQ=m
|
||||||
|
CONFIG_RAID6_PQ_BENCHMARK=y
|
||||||
CONFIG_LINEAR_RANGES=y
|
CONFIG_LINEAR_RANGES=y
|
||||||
CONFIG_PACKING=y
|
CONFIG_PACKING=y
|
||||||
CONFIG_BITREVERSE=y
|
CONFIG_BITREVERSE=y
|
||||||
@@ -11392,6 +11408,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
|
|||||||
# CONFIG_INTERVAL_TREE_TEST is not set
|
# CONFIG_INTERVAL_TREE_TEST is not set
|
||||||
# CONFIG_PERCPU_TEST is not set
|
# CONFIG_PERCPU_TEST is not set
|
||||||
# CONFIG_ATOMIC64_SELFTEST is not set
|
# CONFIG_ATOMIC64_SELFTEST is not set
|
||||||
|
# CONFIG_ASYNC_RAID6_TEST is not set
|
||||||
# CONFIG_TEST_HEXDUMP is not set
|
# CONFIG_TEST_HEXDUMP is not set
|
||||||
# CONFIG_TEST_KSTRTOX is not set
|
# CONFIG_TEST_KSTRTOX is not set
|
||||||
# CONFIG_TEST_PRINTF is not set
|
# CONFIG_TEST_PRINTF is not set
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user