forked from rosa/hakurei
Compare commits
98 Commits
wip-azalea
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
17383ab353
|
|||
|
237e793895
|
|||
|
6cfd8fb934
|
|||
|
2f1534853a
|
|||
|
3f8e111d1c
|
|||
|
9fae451dc0
|
|||
|
e3666cda21
|
|||
|
9c51805b47
|
|||
|
3dca68fc95
|
|||
|
6495118165
|
|||
|
472849cfd6
|
|||
|
3c6e9b3d05
|
|||
|
aa5e77ef27
|
|||
|
76360979f9
|
|||
|
6d55ee536e
|
|||
|
c8e8651694
|
|||
|
aa5d38981d
|
|||
|
b08feac26c
|
|||
|
810b806a15
|
|||
|
4a42657d88
|
|||
|
f0b6659865
|
|||
|
a8ffaa20e0
|
|||
|
fb62ae00e4
|
|||
|
512d9b95bd
|
|||
|
5bf87561f5
|
|||
|
dde69dde61
|
|||
|
3ba6609444
|
|||
|
6dcc2fdc17
|
|||
|
c553b74807
|
|||
|
8c853c3eb6
|
|||
|
d2f322e911
|
|||
|
b538c69e01
|
|||
|
c921ba4680
|
|||
|
7404bf6025
|
|||
|
3975dd3e0f
|
|||
|
3ab7116b29
|
|||
|
9be165d6ee
|
|||
|
1c55e7c772
|
|||
|
a981d185cf
|
|||
|
d91951ca97
|
|||
|
09a2ffc3bc
|
|||
|
a6444658da
|
|||
|
ed5615033c
|
|||
|
d1319a497c
|
|||
|
cf7c34555c
|
|||
|
d96eecded0
|
|||
|
6863bcafd1
|
|||
|
39f023d0e5
|
|||
|
a8a2f692e7
|
|||
|
19f24c7206
|
|||
|
320432774a
|
|||
|
0721b0fe6d
|
|||
|
418e4a874d
|
|||
|
8378e7a2c9
|
|||
|
6210c9f272
|
|||
|
c2038fa925
|
|||
|
d797cca1f2
|
|||
|
2a51b433c8
|
|||
|
e5ce36532b
|
|||
|
4c647388b0
|
|||
|
3a5f4af114
|
|||
|
6195260480
|
|||
|
21044d5a60
|
|||
|
025810bf0f
|
|||
|
20354c0411
|
|||
|
9fbcd0daf2
|
|||
|
248f44a5a7
|
|||
|
401dd57cbc
|
|||
|
854bcc998b
|
|||
|
358247be5b
|
|||
|
f517a8ef07
|
|||
|
973218f91f
|
|||
|
0ea195837b
|
|||
|
1348991634
|
|||
|
14b445fde5
|
|||
|
218f7fa345
|
|||
|
cd493fd95f
|
|||
|
9db70c83e3
|
|||
|
4e09241e5f
|
|||
|
bd4b300ea6
|
|||
|
6dc8214a1a
|
|||
|
cada5a46ad
|
|||
|
e747942829
|
|||
|
33b855123e
|
|||
|
58ce134718
|
|||
|
2066093343
|
|||
|
07509b3ba2
|
|||
|
a7485d587a
|
|||
|
4892beefc1
|
|||
|
7ab54b8c94
|
|||
|
a4fab67811
|
|||
|
ed5cdd38a4
|
|||
|
f6318304ee
|
|||
|
cb618093d5
|
|||
|
b0b2471c0c
|
|||
|
344d2b8207
|
|||
|
3938e8bce5
|
|||
|
aee15b4f2a
|
@@ -0,0 +1 @@
|
||||
*.az linguist-language=Azalea
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build for release
|
||||
run: nix build --print-out-paths --print-build-logs .#dist
|
||||
run: nix build --print-out-paths --print-build-logs ./test#dist
|
||||
|
||||
- name: Release
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run NixOS test
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.hakurei
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.hakurei
|
||||
|
||||
- name: Upload test output
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run NixOS test
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.race
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.race
|
||||
|
||||
- name: Upload test output
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run NixOS test
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.sandbox
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sandbox
|
||||
|
||||
- name: Upload test output
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run NixOS test
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.sandbox-race
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sandbox-race
|
||||
|
||||
- name: Upload test output
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run NixOS test
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.sharefs
|
||||
run: nix build --out-link "result" --print-out-paths --print-build-logs ./test#checks.x86_64-linux.sharefs
|
||||
|
||||
- name: Upload test output
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run checks
|
||||
run: nix --print-build-logs --experimental-features 'nix-command flakes' flake check
|
||||
run: nix --print-build-logs --experimental-features 'nix-command flakes' flake check ./test
|
||||
|
||||
dist:
|
||||
name: Create distribution
|
||||
@@ -116,9 +116,9 @@ jobs:
|
||||
id: build-test
|
||||
run: >-
|
||||
export HAKUREI_REV="$(git rev-parse --short HEAD)" &&
|
||||
sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' package.nix &&
|
||||
nix build --print-out-paths --print-build-logs .#dist &&
|
||||
mv package.nix.old package.nix &&
|
||||
sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' test/package.nix &&
|
||||
nix build --print-out-paths --print-build-logs ./test#dist &&
|
||||
mv test/{package.nix.old,package.nix} &&
|
||||
echo "rev=$HAKUREI_REV" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Upload test build
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# produced by tools and text editors
|
||||
*.swp
|
||||
*.qcow2
|
||||
*.test
|
||||
*.out
|
||||
|
||||
@@ -58,8 +58,3 @@ package [internal/rosa](https://pkg.go.dev/hakurei.app/internal/rosa).
|
||||
|
||||
New dependencies will generally not be added. Patches adding new dependencies
|
||||
are very likely to be rejected.
|
||||
|
||||
## NixOS Module (deprecated)
|
||||
|
||||
The NixOS module is in maintenance mode and will be removed once planterette is
|
||||
feature-complete. Full module documentation can be found [here](options.md).
|
||||
|
||||
+110
-20
@@ -4,10 +4,12 @@ import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/ext"
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/hst"
|
||||
)
|
||||
@@ -31,10 +33,19 @@ func parsePair(s string) (source, target *check.Absolute, err error) {
|
||||
|
||||
// parse decodes a high-level configuration stream and returns its
|
||||
// corresponding [hst.Config].
|
||||
func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
func parse(
|
||||
id string,
|
||||
base *check.Absolute,
|
||||
r io.Reader,
|
||||
templateP *string,
|
||||
) (*hst.Config, error) {
|
||||
shell := fhs.AbsRoot.Append("bin", "zsh")
|
||||
home := hst.AbsPrivateTmp.Append("home")
|
||||
|
||||
root := hst.FSOverlay{
|
||||
Target: fhs.AbsRoot,
|
||||
Lower: []*check.Absolute{base.Append("initial")},
|
||||
}
|
||||
c := hst.Config{
|
||||
ID: id,
|
||||
Enablements: new(hst.Enablements),
|
||||
@@ -51,13 +62,7 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
Container: &hst.ContainerConfig{
|
||||
Env: make(map[string]string),
|
||||
Filesystem: []hst.FilesystemConfigJSON{
|
||||
{FilesystemConfig: &hst.FSOverlay{
|
||||
Target: fhs.AbsRoot,
|
||||
Lower: []*check.Absolute{
|
||||
base.Append("template", "initial"),
|
||||
},
|
||||
Upper: base.Append("template", "upper"),
|
||||
}},
|
||||
{FilesystemConfig: &root},
|
||||
{FilesystemConfig: &hst.FSBind{
|
||||
Target: home,
|
||||
Source: base.Append("state", id),
|
||||
@@ -70,12 +75,6 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
Write: true,
|
||||
Perm: 01777,
|
||||
}},
|
||||
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("block")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("bus")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("class")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("dev")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("devices")}},
|
||||
},
|
||||
|
||||
Username: "chronos",
|
||||
@@ -102,21 +101,28 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
if err := scanOnce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v, err := strconv.Atoi(s.Text()); err != nil {
|
||||
if template, identity, ok := strings.Cut(s.Text(), ":"); !ok {
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
} else if v, err := strconv.Atoi(identity); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
if templateP != nil {
|
||||
*templateP = template
|
||||
}
|
||||
c.Identity = v
|
||||
root.Upper = base.Append("template", template)
|
||||
}
|
||||
|
||||
if err := scanOnce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Container.Args = append(c.Container.Args, s.Text())
|
||||
c.Container.Args = append(c.Container.Args, s.Text(), "")
|
||||
|
||||
var flagGPU, flagSystemBus bool
|
||||
var flagInteractive, flagGPU, flagSystemBus bool
|
||||
flags := map[string]*bool{
|
||||
"gpu": &flagGPU,
|
||||
"system_bus": &flagSystemBus,
|
||||
"interactive": &flagInteractive,
|
||||
"gpu": &flagGPU,
|
||||
"system_bus": &flagSystemBus,
|
||||
}
|
||||
|
||||
for s.Scan() {
|
||||
@@ -176,10 +182,43 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
}
|
||||
|
||||
switch key {
|
||||
case "username":
|
||||
c.Container.Username = value
|
||||
continue
|
||||
|
||||
case "hostname":
|
||||
c.Container.Hostname = value
|
||||
continue
|
||||
|
||||
case "group":
|
||||
c.Groups = append(c.Groups, value)
|
||||
continue
|
||||
|
||||
case "sched_policy":
|
||||
if err := c.SchedPolicy.UnmarshalText([]byte(value)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
|
||||
case "sched_priority":
|
||||
v, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.SchedPriority = ext.Int(v)
|
||||
continue
|
||||
|
||||
case "insecure":
|
||||
switch value {
|
||||
case "pipewire":
|
||||
*c.Enablements |= hst.EPipeWire
|
||||
c.DirectPipeWire = true
|
||||
continue
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid insecure flag %q", value)
|
||||
}
|
||||
|
||||
case "env":
|
||||
if key, value, ok = strings.Cut(value, "="); !ok {
|
||||
return nil, fmt.Errorf("invalid environment %q", key)
|
||||
@@ -200,6 +239,20 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
)
|
||||
continue
|
||||
|
||||
case "ro+":
|
||||
source, target, err := parsePair(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Container.Filesystem = append(c.Container.Filesystem,
|
||||
hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{
|
||||
Target: target,
|
||||
Source: source,
|
||||
Optional: true,
|
||||
}},
|
||||
)
|
||||
continue
|
||||
|
||||
case "rw":
|
||||
source, target, err := parsePair(value)
|
||||
if err != nil {
|
||||
@@ -214,6 +267,20 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
)
|
||||
continue
|
||||
|
||||
case "dev":
|
||||
source, target, err := parsePair(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Container.Filesystem = append(c.Container.Filesystem,
|
||||
hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{
|
||||
Target: target,
|
||||
Source: source,
|
||||
Device: true,
|
||||
}},
|
||||
)
|
||||
continue
|
||||
|
||||
case "own":
|
||||
c.SessionBus.Own = append(c.SessionBus.Own, value)
|
||||
continue
|
||||
@@ -236,6 +303,10 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if flagInteractive {
|
||||
c.Container.Args[1] += "i"
|
||||
}
|
||||
|
||||
if flagGPU {
|
||||
c.Container.Filesystem = append(c.Container.Filesystem, []hst.FilesystemConfigJSON{
|
||||
{FilesystemConfig: &hst.FSBind{
|
||||
@@ -250,7 +321,10 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
c.SystemBus = nil
|
||||
}
|
||||
|
||||
if c.Container.Flags&hst.FShareTmpdir == 0 {
|
||||
if c.Container.Flags&hst.FShareTmpdir == 0 &&
|
||||
(c.Enablements.Unwrap()&hst.EX11 == 0 ||
|
||||
c.Container.Flags&(hst.FHostNet|hst.FHostAbstract) ==
|
||||
hst.FHostNet|hst.FHostAbstract) {
|
||||
c.Container.Filesystem = append(c.Container.Filesystem,
|
||||
hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSEphemeral{
|
||||
Target: fhs.AbsTmp,
|
||||
@@ -262,3 +336,19 @@ func parse(id string, base *check.Absolute, r io.Reader) (*hst.Config, error) {
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// list prints names of non-hidden entries in pathname.
|
||||
func list(pathname *check.Absolute, dir bool) error {
|
||||
dents, err := os.ReadDir(pathname.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, dent := range dents {
|
||||
name := dent.Name()
|
||||
if (dent.IsDir() != dir) || (len(name) > 0 && name[0] == '.') {
|
||||
continue
|
||||
}
|
||||
fmt.Println(dent.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+5
-9
@@ -20,7 +20,7 @@ func TestParse(t *testing.T) {
|
||||
want *hst.Config
|
||||
err error
|
||||
}{
|
||||
{"com.discordapp.Discord", `8
|
||||
{"com.discordapp.Discord", `nonfree:8
|
||||
exec Discord --ozone-platform-hint=wayland
|
||||
|
||||
gpu
|
||||
@@ -74,9 +74,9 @@ talk com.canonical.Unity
|
||||
{FilesystemConfig: &hst.FSOverlay{
|
||||
Target: fhs.AbsRoot,
|
||||
Lower: []*check.Absolute{
|
||||
base.Append("template", "initial"),
|
||||
base.Append("initial"),
|
||||
},
|
||||
Upper: base.Append("template", "upper"),
|
||||
Upper: base.Append("template", "nonfree"),
|
||||
}},
|
||||
{FilesystemConfig: &hst.FSBind{
|
||||
Target: hst.AbsPrivateTmp.Append("home"),
|
||||
@@ -91,12 +91,6 @@ talk com.canonical.Unity
|
||||
Perm: 01777,
|
||||
}},
|
||||
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("block")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("bus")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("class")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("dev")}},
|
||||
{FilesystemConfig: &hst.FSBind{Source: fhs.AbsSys.Append("devices")}},
|
||||
|
||||
{FilesystemConfig: &hst.FSBind{
|
||||
Source: check.MustAbs("/sdcard"),
|
||||
Write: true,
|
||||
@@ -120,6 +114,7 @@ talk com.canonical.Unity
|
||||
Args: []string{
|
||||
"zsh", "-c",
|
||||
"exec Discord --ozone-platform-hint=wayland",
|
||||
"",
|
||||
},
|
||||
|
||||
Flags: hst.FCoverRun | hst.FUserns | hst.FHostNet | hst.FMapRealUID |
|
||||
@@ -135,6 +130,7 @@ talk com.canonical.Unity
|
||||
tc.name,
|
||||
base,
|
||||
strings.NewReader(tc.data),
|
||||
nil,
|
||||
)
|
||||
|
||||
if !reflect.DeepEqual(err, tc.err) {
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/env"
|
||||
"hakurei.app/internal/lockedfile"
|
||||
"hakurei.app/internal/outcome"
|
||||
)
|
||||
|
||||
// MutationConflictError describes an active mutable instance.
|
||||
type MutationConflictError string
|
||||
|
||||
func (e MutationConflictError) Error() string {
|
||||
return "mutable instance active at " + string(e)
|
||||
}
|
||||
|
||||
// informTemplate guards intention of a template or its derivatives.
|
||||
func informTemplate(base *check.Absolute, name string, mutable bool) (func() error, error) {
|
||||
mu := lockedfile.MutexAt(base.Append("lock", name).String())
|
||||
if unlock, err := mu.Lock(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
defer unlock()
|
||||
}
|
||||
|
||||
marker := base.Append("lock", "."+name)
|
||||
if p, err := os.ReadFile(marker.String()); err == nil {
|
||||
if _, err = os.Stat(fhs.AbsProc.Append(string(p)).String()); err == nil {
|
||||
return nil, MutationConflictError(p)
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("removing stale marker by %s", string(p))
|
||||
if err = os.Remove(marker.String()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !mutable {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var active []hst.ID
|
||||
var sc hst.Paths
|
||||
env.CopyPaths().Copy(&sc, new(outcome.Hsu).MustID(nil))
|
||||
entries, copyError := outcome.NewStore(&sc).All()
|
||||
var s hst.State
|
||||
for eh := range entries {
|
||||
s = hst.State{}
|
||||
if _, err := eh.Load(&s); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if s.Validate(0) != nil || len(s.Container.Filesystem) < 1 {
|
||||
continue
|
||||
}
|
||||
root, ok := s.Container.Filesystem[0].FilesystemConfig.(*hst.FSOverlay)
|
||||
if !ok || root == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if !root.Target.Is(fhs.AbsRoot) ||
|
||||
len(root.Lower) != 1 ||
|
||||
!root.Lower[0].Is(base.Append("initial")) ||
|
||||
!root.Upper.Is(base.Append("template", name)) ||
|
||||
root.Work != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
active = append(active, s.ID)
|
||||
}
|
||||
if err := copyError(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(active) != 0 {
|
||||
var buf strings.Builder
|
||||
buf.WriteString("derivative instances still active:")
|
||||
for _, id := range active {
|
||||
buf.WriteString("\n\t")
|
||||
buf.WriteString(id.String())
|
||||
}
|
||||
return nil, errors.New(buf.String())
|
||||
}
|
||||
|
||||
return func() error { return os.RemoveAll(marker.String()) }, os.WriteFile(
|
||||
marker.String(),
|
||||
[]byte(strconv.Itoa(os.Getpid())),
|
||||
0400,
|
||||
)
|
||||
}
|
||||
|
||||
// acquireTemplate obtains exclusivity of a template.
|
||||
func acquireTemplate(base *check.Absolute, name string) (remove func() error, err error) {
|
||||
return informTemplate(base, name, true)
|
||||
}
|
||||
|
||||
// enterTemplate checks against exclusivity of a template.
|
||||
func enterTemplate(base *check.Absolute, name string) error {
|
||||
_, err := informTemplate(base, name, false)
|
||||
return err
|
||||
}
|
||||
+92
-36
@@ -7,6 +7,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -31,10 +32,11 @@ func main() {
|
||||
defer stop()
|
||||
|
||||
var (
|
||||
flagVerbose bool
|
||||
flagBase string
|
||||
flagVerbose bool
|
||||
flagBase string
|
||||
flagInsecure bool
|
||||
|
||||
base, template, initial, upper, work *check.Absolute
|
||||
base, template, initial *check.Absolute
|
||||
)
|
||||
c := command.New(os.Stderr, log.Printf, "app", func([]string) (err error) {
|
||||
msg.SwapVerbose(flagVerbose)
|
||||
@@ -49,9 +51,7 @@ func main() {
|
||||
}
|
||||
|
||||
template = base.Append("template")
|
||||
initial = template.Append("initial")
|
||||
upper = template.Append("upper")
|
||||
work = template.Append("work")
|
||||
initial = base.Append("initial")
|
||||
return
|
||||
}).Flag(
|
||||
&flagVerbose,
|
||||
@@ -59,8 +59,12 @@ func main() {
|
||||
"Increase log verbosity",
|
||||
).Flag(
|
||||
&flagBase,
|
||||
"d", command.StringFlag("$HAKUREI_APP_PATH"),
|
||||
"d", command.StringFlag("$ROSA_APP_PATH"),
|
||||
"Configuration and state directory",
|
||||
).Flag(
|
||||
&flagInsecure,
|
||||
"insecure", command.BoolFlag(false),
|
||||
"Allow use of insecure compatibility options",
|
||||
)
|
||||
|
||||
{
|
||||
@@ -70,17 +74,21 @@ func main() {
|
||||
)
|
||||
c.NewCommand(
|
||||
"enter", "Enter mutable state template",
|
||||
func([]string) error {
|
||||
func(args []string) error {
|
||||
if len(args) != 1 {
|
||||
return list(template, true)
|
||||
}
|
||||
|
||||
config := hst.Config{
|
||||
ID: "app.hakurei.mutable",
|
||||
ID: "app.hakurei.mutable." + args[0],
|
||||
Container: &hst.ContainerConfig{
|
||||
Hostname: "mutable",
|
||||
Hostname: args[0] + "-mutable",
|
||||
Filesystem: []hst.FilesystemConfigJSON{
|
||||
{FilesystemConfig: &hst.FSOverlay{
|
||||
Target: fhs.AbsRoot,
|
||||
Lower: []*check.Absolute{initial},
|
||||
Upper: upper,
|
||||
Work: work,
|
||||
Upper: template.Append(args[0]),
|
||||
Work: base.Append("work", args[0]),
|
||||
}},
|
||||
{FilesystemConfig: &hst.FSEphemeral{
|
||||
Target: fhs.AbsTmp,
|
||||
@@ -89,7 +97,8 @@ func main() {
|
||||
}},
|
||||
},
|
||||
Username: "chronos",
|
||||
Flags: hst.FMultiarch |
|
||||
Flags: hst.FNoPlace |
|
||||
hst.FMultiarch |
|
||||
hst.FDevel |
|
||||
hst.FUserns |
|
||||
hst.FHostNet |
|
||||
@@ -113,7 +122,12 @@ func main() {
|
||||
config.Container.Home = a
|
||||
}
|
||||
|
||||
return run(ctx, msg, &config)
|
||||
remove, err := acquireTemplate(base, args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = run(ctx, msg, false, &config)
|
||||
return errors.Join(err, remove())
|
||||
},
|
||||
).Flag(
|
||||
&flagShell,
|
||||
@@ -126,29 +140,65 @@ func main() {
|
||||
)
|
||||
}
|
||||
|
||||
c.NewCommand(
|
||||
"run", "Start the named application",
|
||||
func(args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.New("run requires 1 argument")
|
||||
}
|
||||
{
|
||||
var (
|
||||
flagCommand string
|
||||
)
|
||||
c.NewCommand(
|
||||
"run", "Start the named application",
|
||||
func(args []string) error {
|
||||
if len(args) < 1 {
|
||||
return list(base.Append("app"), false)
|
||||
}
|
||||
|
||||
var config *hst.Config
|
||||
f, err := os.Open(base.Append("app", args[0]).String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config, err = parse(args[0], base, f)
|
||||
if closeErr := f.Close(); err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var config *hst.Config
|
||||
var r io.Reader
|
||||
f, err := os.Open(base.Append("app", args[0]).String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r = f
|
||||
|
||||
return run(ctx, msg, config)
|
||||
},
|
||||
)
|
||||
var common *os.File
|
||||
if common, err = os.Open(base.Append("common").String()); err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
_ = f.Close()
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
r = io.MultiReader(f, common)
|
||||
}
|
||||
|
||||
var name string
|
||||
config, err = parse(args[0], base, r, &name)
|
||||
if closeErr := f.Close(); err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
if common != nil {
|
||||
if closeErr := common.Close(); err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if flagCommand != "" {
|
||||
config.Container.Args[2] = flagCommand
|
||||
}
|
||||
|
||||
if err = enterTemplate(base, name); err != nil {
|
||||
return err
|
||||
}
|
||||
return run(ctx, msg, flagInsecure, config, args[1:]...)
|
||||
},
|
||||
).
|
||||
Flag(
|
||||
&flagCommand,
|
||||
"command", command.StringFlag(""),
|
||||
"Override configured command",
|
||||
)
|
||||
}
|
||||
|
||||
c.MustParse(os.Args[1:], func(err error) {
|
||||
if e, ok := errors.AsType[*exec.ExitError](err); ok && e != nil {
|
||||
@@ -156,7 +206,13 @@ func main() {
|
||||
}
|
||||
|
||||
if w, ok := err.(interface{ Unwrap() []error }); !ok {
|
||||
log.Fatal(err)
|
||||
var m string
|
||||
m, ok = message.GetMessage(err)
|
||||
if !ok {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
log.Fatal(m)
|
||||
} else {
|
||||
errs := w.Unwrap()
|
||||
for i, e := range errs {
|
||||
|
||||
+11
-1
@@ -12,7 +12,13 @@ import (
|
||||
)
|
||||
|
||||
// run starts a container via cmd/hakurei and returns after it terminates.
|
||||
func run(ctx context.Context, msg message.Msg, config *hst.Config) error {
|
||||
func run(
|
||||
ctx context.Context,
|
||||
msg message.Msg,
|
||||
insecure bool,
|
||||
config *hst.Config,
|
||||
args ...string,
|
||||
) error {
|
||||
c, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
@@ -24,7 +30,11 @@ func run(ctx context.Context, msg message.Msg, config *hst.Config) error {
|
||||
if msg.IsVerbose() {
|
||||
cmd.Args = append(cmd.Args, "-v")
|
||||
}
|
||||
if insecure {
|
||||
cmd.Args = append(cmd.Args, "--insecure")
|
||||
}
|
||||
cmd.Args = append(cmd.Args, "run", "3")
|
||||
cmd.Args = append(cmd.Args, args...)
|
||||
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
v0.4.4
|
||||
v0.4.5
|
||||
|
||||
Vendored
+24
-9
@@ -35,8 +35,11 @@ func getenv(key, fallback string) string {
|
||||
|
||||
// mustRun runs a command with the current process's environment and panics
|
||||
// on error or non-zero exit code.
|
||||
func mustRun(ctx context.Context, name string, arg ...string) {
|
||||
func mustRun(ctx context.Context, env []string, name string, arg ...string) {
|
||||
cmd := exec.CommandContext(ctx, name, arg...)
|
||||
if env != nil {
|
||||
cmd.Env = append(cmd.Environ(), env...)
|
||||
}
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
panic(err)
|
||||
@@ -49,6 +52,7 @@ var comp []byte
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("")
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
verbose := os.Getenv("VERBOSE") != ""
|
||||
runTests := os.Getenv("HAKUREI_DIST_MAKE") == ""
|
||||
@@ -91,26 +95,37 @@ func main() {
|
||||
verboseFlag = "-buildvcs=false"
|
||||
}
|
||||
|
||||
log.Printf("Building hakurei for %s/%s.", runtime.GOOS, runtime.GOARCH)
|
||||
mustRun(ctx, "go", "generate", "./...")
|
||||
log.Printf("Building hakurei %s for %s/%s.", version, runtime.GOOS, runtime.GOARCH)
|
||||
mustRun(ctx, nil, "go", "generate", "./...")
|
||||
mustRun(
|
||||
ctx, "go", "build",
|
||||
ctx, nil, "go", "build",
|
||||
"-trimpath",
|
||||
verboseFlag, "-o", s,
|
||||
"-ldflags=-s -w "+
|
||||
"-buildid= -linkmode external -extldflags=-static "+
|
||||
"-X hakurei.app/internal/info.buildVersion="+version+" "+
|
||||
"-X hakurei.app/internal/info.hakureiPath="+prefix+"/bin/hakurei "+
|
||||
"-X hakurei.app/internal/info.hsuPath="+prefix+"/bin/hsu "+
|
||||
"-X main.hakureiPath="+prefix+"/bin/hakurei",
|
||||
"./...",
|
||||
"-X hakurei.app/internal/info.hsuPath="+prefix+"/bin/hsu",
|
||||
"./cmd/hakurei",
|
||||
"./cmd/sharefs",
|
||||
)
|
||||
log.Println()
|
||||
|
||||
log.Printf("Building cmd/hsu for %s/%s.", runtime.GOOS, runtime.GOARCH)
|
||||
mustRun(
|
||||
ctx, []string{"CGO_ENABLED=0"}, "go", "build",
|
||||
"-trimpath",
|
||||
verboseFlag, "-o", s,
|
||||
"-ldflags=-s -w "+
|
||||
"-buildid= "+
|
||||
"-X main.hakureiPath="+prefix+"/bin/hakurei",
|
||||
"./cmd/hsu",
|
||||
)
|
||||
|
||||
log.Println()
|
||||
if runTests {
|
||||
log.Println("##### Testing Hakurei.")
|
||||
mustRun(
|
||||
ctx, "go", "test",
|
||||
ctx, nil, "go", "test",
|
||||
"-ldflags=-buildid= -linkmode external -extldflags=-static",
|
||||
"./...",
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
@@ -51,13 +52,14 @@ func init() {
|
||||
func fatal(v ...any) {
|
||||
log.Println(v...)
|
||||
log.Println("unable to continue, please reboot and resolve the problem manually")
|
||||
log.SetOutput(io.Discard)
|
||||
select {}
|
||||
}
|
||||
|
||||
// must calls fatal with err if it is non-nil.
|
||||
func must(err error) {
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
fatal(err)
|
||||
select {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,9 @@ var _ report.RepresentableError = ModprobeError{}
|
||||
func (ModprobeError) Representable() {}
|
||||
func (e ModprobeError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"modprobe exit status %d: %s",
|
||||
e.ExitCode, strings.TrimSpace(e.Stderr),
|
||||
"%s (exit status %d)",
|
||||
strings.TrimPrefix(strings.TrimSpace(e.Stderr), "modprobe: "),
|
||||
e.ExitCode,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ func TestPrintShowInstance(t *testing.T) {
|
||||
Identity: 9 (org.chromium.Chromium)
|
||||
Enablements: wayland, dbus, pipewire
|
||||
Groups: video, dialout, plugdev
|
||||
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir
|
||||
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir
|
||||
Home: /data/data/org.chromium.Chromium
|
||||
Hostname: localhost
|
||||
Path: /run/current-system/sw/bin/chromium
|
||||
@@ -161,7 +161,7 @@ App
|
||||
Identity: 9 (org.chromium.Chromium)
|
||||
Enablements: wayland, dbus, pipewire
|
||||
Groups: video, dialout, plugdev
|
||||
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir
|
||||
Flags: multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir
|
||||
Home: /data/data/org.chromium.Chromium
|
||||
Hostname: localhost
|
||||
Path: /run/current-system/sw/bin/chromium
|
||||
@@ -354,6 +354,7 @@ App
|
||||
"tty": true,
|
||||
"multiarch": true,
|
||||
"map_real_uid": true,
|
||||
"noplace": true,
|
||||
"device": true,
|
||||
"cover_run": true,
|
||||
"share_runtime": true,
|
||||
@@ -506,6 +507,7 @@ App
|
||||
"tty": true,
|
||||
"multiarch": true,
|
||||
"map_real_uid": true,
|
||||
"noplace": true,
|
||||
"device": true,
|
||||
"cover_run": true,
|
||||
"share_runtime": true,
|
||||
@@ -705,6 +707,7 @@ func TestPrintPs(t *testing.T) {
|
||||
"tty": true,
|
||||
"multiarch": true,
|
||||
"map_real_uid": true,
|
||||
"noplace": true,
|
||||
"device": true,
|
||||
"cover_run": true,
|
||||
"share_runtime": true,
|
||||
|
||||
+11
-9
@@ -21,13 +21,15 @@ type cache struct {
|
||||
// Should generally not be used directly.
|
||||
c *pkg.Cache
|
||||
|
||||
cures, jobs int
|
||||
attr pkg.CacheAttr
|
||||
// Primarily to work around missing landlock LSM.
|
||||
hostAbstract bool
|
||||
// Set SCHED_IDLE.
|
||||
idle bool
|
||||
// Unset [pkg.CSuppressInit].
|
||||
verboseInit bool
|
||||
// Unset [pkg.CExternShallow].
|
||||
deep bool
|
||||
// Loaded artifact of [rosa.QEMU].
|
||||
qemu pkg.Artifact
|
||||
|
||||
@@ -47,15 +49,17 @@ func (cache *cache) open() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
var flags int
|
||||
if cache.idle {
|
||||
flags |= pkg.CSchedIdle
|
||||
cache.attr.Flags |= pkg.CSchedIdle
|
||||
}
|
||||
if cache.hostAbstract {
|
||||
flags |= pkg.CHostAbstract
|
||||
cache.attr.Flags |= pkg.CHostAbstract
|
||||
}
|
||||
if !cache.verboseInit {
|
||||
flags |= pkg.CSuppressInit
|
||||
cache.attr.Flags |= pkg.CSuppressInit
|
||||
}
|
||||
if !cache.deep {
|
||||
cache.attr.Flags |= pkg.CExternShallow
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
@@ -77,10 +81,8 @@ func (cache *cache) open() (err error) {
|
||||
cache.c, err = pkg.Open(
|
||||
cache.ctx,
|
||||
cache.msg,
|
||||
flags,
|
||||
cache.cures,
|
||||
cache.jobs,
|
||||
base,
|
||||
&cache.attr,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -95,7 +97,7 @@ func (cache *cache) open() (err error) {
|
||||
return
|
||||
}
|
||||
var r rosa.Remote
|
||||
if r, err = rosa.NewRemote(cache.mirror, pub, http.DefaultClient); err != nil {
|
||||
if r, err = rosa.NewRemote(http.DefaultClient, cache.mirror, pub); err != nil {
|
||||
cache.c.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ func TestNoReply(t *testing.T) {
|
||||
c, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(log.New(os.Stderr, "cir: ", 0)),
|
||||
0, 0, 0,
|
||||
check.MustAbs(t.TempDir()),
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
|
||||
+4
-1
@@ -21,7 +21,10 @@ func commandInfo(
|
||||
r *rosa.Report,
|
||||
) (err error) {
|
||||
if len(args) == 0 {
|
||||
return errors.New("info requires at least 1 argument")
|
||||
for _, h := range rosa.Native().CollectAll() {
|
||||
fmt.Println(h)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// recovered by HandleAccess
|
||||
|
||||
+138
-4
@@ -27,6 +27,7 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
@@ -202,11 +203,11 @@ func main() {
|
||||
"v", command.BoolFlag(false),
|
||||
"Do not suppress verbose output from init",
|
||||
).Flag(
|
||||
&cm.cures,
|
||||
&cm.attr.Cures,
|
||||
"cures", command.IntFlag(0),
|
||||
"Maximum number of dependencies to cure at any given time",
|
||||
).Flag(
|
||||
&cm.jobs,
|
||||
&cm.attr.Jobs,
|
||||
"jobs", command.IntFlag(0),
|
||||
"Preferred number of jobs to run, when applicable",
|
||||
).Flag(
|
||||
@@ -217,6 +218,11 @@ func main() {
|
||||
&cm.mirror,
|
||||
"r", command.StringFlag("$MBF_REMOTE"),
|
||||
"URL of mirror service",
|
||||
).Flag(
|
||||
&cm.deep,
|
||||
"deep", command.BoolFlag(false),
|
||||
"Cure all inputs even when the required artifact is available "+
|
||||
"via the mirror service",
|
||||
).Flag(
|
||||
&cm.idle,
|
||||
"sched-idle", command.BoolFlag(false),
|
||||
@@ -539,7 +545,9 @@ func main() {
|
||||
if base, err := os.OpenRoot(cm.base); err != nil {
|
||||
return err
|
||||
} else {
|
||||
h = rosa.NewMirror(msg, base.FS(), key)
|
||||
var mux http.ServeMux
|
||||
rosa.NewMirror(msg, base.FS(), key).Register(&mux)
|
||||
h = &mux
|
||||
}
|
||||
|
||||
server := http.Server{Addr: args[0], Handler: h}
|
||||
@@ -561,6 +569,47 @@ func main() {
|
||||
},
|
||||
)
|
||||
|
||||
c.NewCommand(
|
||||
"snapshot",
|
||||
"Populate an empty directory with a static mirror snapshot",
|
||||
func(args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.New("snapshot requires 1 argument")
|
||||
}
|
||||
|
||||
var key ed25519.PrivateKey
|
||||
if p, err := os.ReadFile(filepath.Join(cm.base, "ed25519")); err != nil {
|
||||
return err
|
||||
} else if len(p) != ed25519.PrivateKeySize {
|
||||
return errors.New("invalid private key")
|
||||
} else {
|
||||
key = p
|
||||
}
|
||||
|
||||
var m rosa.Mirror
|
||||
if base, err := os.OpenRoot(cm.base); err != nil {
|
||||
return err
|
||||
} else {
|
||||
m = rosa.NewMirror(msg, base.FS(), key)
|
||||
}
|
||||
|
||||
retry:
|
||||
root, err := os.OpenRoot(args[0])
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(args[0], 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
goto retry
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
go func() { <-ctx.Done(); _ = root.Close() }()
|
||||
return m.Populate(root)
|
||||
},
|
||||
)
|
||||
|
||||
{
|
||||
var (
|
||||
flagGentoo string
|
||||
@@ -648,6 +697,7 @@ func main() {
|
||||
flagNoReply bool
|
||||
flagFaults bool
|
||||
flagPop bool
|
||||
flagRebuild bool
|
||||
|
||||
flagBoot bool
|
||||
flagStd bool
|
||||
@@ -676,7 +726,11 @@ func main() {
|
||||
default:
|
||||
var pathname *check.Absolute
|
||||
err := cm.Do(func(cache *pkg.Cache) (err error) {
|
||||
pathname, _, err = cache.Cure(a)
|
||||
if flagRebuild {
|
||||
pathname, _, err = cache.CureNew(a)
|
||||
} else {
|
||||
pathname, _, err = cache.Cure(a)
|
||||
}
|
||||
return
|
||||
})
|
||||
if err != nil {
|
||||
@@ -837,9 +891,89 @@ func main() {
|
||||
&flagPop,
|
||||
"pop", command.BoolFlag(false),
|
||||
"Display and destroy the most recent fault entry",
|
||||
).Flag(
|
||||
&flagRebuild,
|
||||
"rebuild", command.BoolFlag(false),
|
||||
"Always enter the artifact implementation",
|
||||
)
|
||||
}
|
||||
|
||||
c.NewCommand(
|
||||
"validate",
|
||||
"Repeatedly cure named artifact to validate determinism",
|
||||
func(args []string) error {
|
||||
stage := rosa.Std
|
||||
if len(args) == 3 {
|
||||
switch args[0] {
|
||||
case "boot":
|
||||
stage -= 2
|
||||
case "std":
|
||||
stage -= 1
|
||||
|
||||
default:
|
||||
return fmt.Errorf("invalid stage %q", args[0])
|
||||
}
|
||||
args = args[1:]
|
||||
}
|
||||
|
||||
if len(args) != 2 {
|
||||
return errors.New("validate requires 2 arguments")
|
||||
}
|
||||
|
||||
n, err := strconv.Atoi(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid passes %q", args[0])
|
||||
}
|
||||
|
||||
if n < 2 {
|
||||
return errors.New("validate must rebuild at least twice")
|
||||
}
|
||||
|
||||
_, a := rosa.Native().New(stage).Load(rosa.ArtifactH(unique.Make(args[1])))
|
||||
if a == nil {
|
||||
return fmt.Errorf("unknown artifact %q", args[1])
|
||||
}
|
||||
|
||||
if !a.IsExclusive() && cm.attr.Jobs < 1 {
|
||||
cm.attr.Jobs = runtime.NumCPU()/n + 1
|
||||
}
|
||||
|
||||
res := make([]unique.Handle[pkg.Checksum], n)
|
||||
if err = cm.Do(func(cache *pkg.Cache) error {
|
||||
errs := make([]error, n)
|
||||
var wg sync.WaitGroup
|
||||
for i := range n {
|
||||
wg.Go(func() {
|
||||
_, res[i], errs[i] = cache.CureNew(a)
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
return errors.Join(errs...)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range n - 1 {
|
||||
if res[i] == res[i+1] {
|
||||
continue
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
buf.WriteString("nondeterminism:")
|
||||
for _, o := range res {
|
||||
buf.WriteString("\n\t")
|
||||
buf.WriteString(filepath.Join(
|
||||
cm.base,
|
||||
"checksum",
|
||||
pkg.Encode(o.Value()),
|
||||
))
|
||||
}
|
||||
return errors.New(buf.String())
|
||||
}
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
cleanC := c.New("clean", "Remove unused entries from the cache")
|
||||
cleanC.NewCommand(
|
||||
"fault",
|
||||
|
||||
@@ -65,6 +65,8 @@ const (
|
||||
// Some programs fail to connect to dbus session running as a different uid,
|
||||
// this option works around it by mapping priv-side caller uid in container.
|
||||
FMapRealUID
|
||||
// FNoPlace disables placement of /etc/passwd and /etc/group.
|
||||
FNoPlace
|
||||
|
||||
// FDevice mount /dev/ from the init mount namespace as is in the container
|
||||
// mount namespace.
|
||||
@@ -101,6 +103,8 @@ func (flags Flags) String() string {
|
||||
return "tty"
|
||||
case FMapRealUID:
|
||||
return "mapuid"
|
||||
case FNoPlace:
|
||||
return "noplace"
|
||||
case FDevice:
|
||||
return "device"
|
||||
case FCoverRun:
|
||||
@@ -197,6 +201,8 @@ type containerConfigJSON = struct {
|
||||
|
||||
// Corresponds to [FMapRealUID].
|
||||
MapRealUID bool `json:"map_real_uid"`
|
||||
// Corresponds to [FNoPlace].
|
||||
NoPlace bool `json:"noplace,omitempty"`
|
||||
|
||||
// Corresponds to [FDevice].
|
||||
Device bool `json:"device,omitempty"`
|
||||
@@ -224,6 +230,7 @@ func (c *ContainerConfig) MarshalJSON() ([]byte, error) {
|
||||
Tty: c.Flags&FTty != 0,
|
||||
Multiarch: c.Flags&FMultiarch != 0,
|
||||
MapRealUID: c.Flags&FMapRealUID != 0,
|
||||
NoPlace: c.Flags&FNoPlace != 0,
|
||||
Device: c.Flags&FDevice != 0,
|
||||
CoverRun: c.Flags&FCoverRun != 0,
|
||||
ShareRuntime: c.Flags&FShareRuntime != 0,
|
||||
@@ -266,6 +273,9 @@ func (c *ContainerConfig) UnmarshalJSON(data []byte) error {
|
||||
if v.MapRealUID {
|
||||
c.Flags |= FMapRealUID
|
||||
}
|
||||
if v.NoPlace {
|
||||
c.Flags |= FNoPlace
|
||||
}
|
||||
if v.Device {
|
||||
c.Flags |= FDevice
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ func TestFlagsString(t *testing.T) {
|
||||
}{
|
||||
{"none", 0, "none"},
|
||||
{"none high", hst.FAll + 1, "none"},
|
||||
{"all", hst.FAll, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir"},
|
||||
{"all high", math.MaxUint, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, device, cover_run, runtime, tmpdir"},
|
||||
{"all", hst.FAll, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir"},
|
||||
{"all high", math.MaxUint, "multiarch, compat, devel, userns, net, abstract, tty, mapuid, noplace, device, cover_run, runtime, tmpdir"},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -53,7 +53,7 @@ func TestContainerConfig(t *testing.T) {
|
||||
{"hostnet hostabstract mapuid", &hst.ContainerConfig{Flags: hst.FHostNet | hst.FHostAbstract | hst.FMapRealUID},
|
||||
`{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"host_net":true,"host_abstract":true,"map_real_uid":true}`},
|
||||
{"all", &hst.ContainerConfig{Flags: hst.FAll},
|
||||
`{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"seccomp_compat":true,"devel":true,"userns":true,"host_net":true,"host_abstract":true,"tty":true,"multiarch":true,"map_real_uid":true,"device":true,"cover_run":true,"share_runtime":true,"share_tmpdir":true}`},
|
||||
`{"env":null,"filesystem":null,"shell":null,"home":null,"args":null,"seccomp_compat":true,"devel":true,"userns":true,"host_net":true,"host_abstract":true,"tty":true,"multiarch":true,"map_real_uid":true,"noplace":true,"device":true,"cover_run":true,"share_runtime":true,"share_tmpdir":true}`},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
||||
+2
-2
@@ -82,9 +82,9 @@ func (o *FSOverlay) Apply(z *ApplyState) {
|
||||
z.Overlay(o.Target, o.Upper, o.Work, o.Lower...)
|
||||
} else {
|
||||
z.OverlayEphemeral(o.Target, slices.Concat(
|
||||
[]*check.Absolute{o.Upper},
|
||||
o.Lower,
|
||||
[]*check.Absolute{o.Upper})...,
|
||||
)
|
||||
)...)
|
||||
}
|
||||
} else {
|
||||
z.OverlayReadonly(o.Target, o.Lower...)
|
||||
|
||||
@@ -70,7 +70,7 @@ func TestFSOverlay(t *testing.T) {
|
||||
Upper: m("/tmp/upper"),
|
||||
}, true, container.Ops{&container.MountOverlayOp{
|
||||
Target: m("/"),
|
||||
Lower: ms("/tmp/.src0", "/tmp/.src1", "/tmp/upper"),
|
||||
Lower: ms("/tmp/upper", "/tmp/.src0", "/tmp/.src1"),
|
||||
Upper: fhs.AbsRoot,
|
||||
}}, m("/"), ms("/tmp/upper", "/tmp/.src0", "/tmp/.src1"),
|
||||
"e*/:/tmp/upper:/tmp/.src0:/tmp/.src1"},
|
||||
|
||||
@@ -244,6 +244,7 @@ func TestTemplate(t *testing.T) {
|
||||
"tty": true,
|
||||
"multiarch": true,
|
||||
"map_real_uid": true,
|
||||
"noplace": true,
|
||||
"device": true,
|
||||
"cover_run": true,
|
||||
"share_runtime": true,
|
||||
|
||||
Vendored
+24
-4
@@ -1,21 +1,29 @@
|
||||
// Package env provides the [Paths] struct for efficiently building paths from the environment.
|
||||
// Package env provides the [Paths] struct for efficiently building paths from
|
||||
// the environment.
|
||||
package env
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"hakurei.app/check"
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/hst"
|
||||
)
|
||||
|
||||
const VarRunNscd = fhs.Var + "run/nscd"
|
||||
|
||||
// Paths holds paths copied from the environment and is used to create [hst.Paths].
|
||||
type Paths struct {
|
||||
// TempDir is returned by [os.TempDir].
|
||||
TempDir *check.Absolute
|
||||
// RuntimePath is copied from $XDG_RUNTIME_DIR.
|
||||
RuntimePath *check.Absolute
|
||||
// Whether [VarRunNscd] is a directory.
|
||||
HasNscd bool
|
||||
}
|
||||
|
||||
// Copy expands [Paths] into [hst.Paths].
|
||||
@@ -37,14 +45,17 @@ func (env *Paths) Copy(v *hst.Paths, userid int) {
|
||||
}
|
||||
|
||||
// CopyPaths returns a populated [Paths].
|
||||
func CopyPaths() *Paths { return CopyPathsFunc(log.Fatalf, os.TempDir, os.Getenv) }
|
||||
func CopyPaths() *Paths {
|
||||
return CopyPathsFunc(log.Fatalf, os.TempDir, os.Getenv, os.Stat)
|
||||
}
|
||||
|
||||
// CopyPathsFunc returns a populated [Paths],
|
||||
// using the provided [log.Fatalf], [os.TempDir], [os.Getenv] functions.
|
||||
// CopyPathsFunc returns a populated [Paths], using the provided [log.Fatalf],
|
||||
// [os.TempDir], [os.Getenv] functions.
|
||||
func CopyPathsFunc(
|
||||
fatalf func(format string, v ...any),
|
||||
tempdir func() string,
|
||||
getenv func(key string) string,
|
||||
stat func(name string) (fs.FileInfo, error),
|
||||
) *Paths {
|
||||
const xdgRuntimeDir = "XDG_RUNTIME_DIR"
|
||||
|
||||
@@ -61,5 +72,14 @@ func CopyPathsFunc(
|
||||
env.RuntimePath = a
|
||||
}
|
||||
|
||||
if fi, err := stat(VarRunNscd); err != nil {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
fatalf("%v", err)
|
||||
panic("unreachable")
|
||||
}
|
||||
} else {
|
||||
env.HasNscd = fi.IsDir()
|
||||
}
|
||||
|
||||
return &env
|
||||
}
|
||||
|
||||
Vendored
+4
-1
@@ -2,6 +2,7 @@ package env_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@@ -104,7 +105,9 @@ func TestCopyPaths(t *testing.T) {
|
||||
t.Fatalf("fatalf: %q, want %q", got, tc.fatal)
|
||||
}
|
||||
panic(stub.PanicExit)
|
||||
}, func() string { return tc.tmp }, func(key string) string { return tc.env[key] })
|
||||
}, func() string { return tc.tmp }, func(key string) string { return tc.env[key] }, func(name string) (fs.FileInfo, error) {
|
||||
return nil, fs.ErrNotExist
|
||||
})
|
||||
|
||||
if tc.fatal != "" {
|
||||
t.Fatalf("copyPaths: expected fatal %q", tc.fatal)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/std"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/env"
|
||||
"hakurei.app/internal/stub"
|
||||
"hakurei.app/internal/system"
|
||||
"hakurei.app/message"
|
||||
@@ -174,6 +175,7 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
call("cmdOutput", stub.ExpectArgs{container.Nonexistent, os.Stderr, []string{}, "/"}, []byte("0"), nil),
|
||||
call("tempdir", stub.ExpectArgs{}, container.Nonexistent+"/tmp", nil),
|
||||
call("lookupEnv", stub.ExpectArgs{"XDG_RUNTIME_DIR"}, wantRuntimePath, nil),
|
||||
call("stat", stub.ExpectArgs{env.VarRunNscd}, stubFileInfoIsDir(true), nil),
|
||||
call("getuid", stub.ExpectArgs{}, 1000, nil),
|
||||
call("getgid", stub.ExpectArgs{}, 100, nil),
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ func newOutcomeState(k syscallDispatcher, msg message.Msg, id *hst.ID, config *h
|
||||
Paths: env.CopyPathsFunc(k.fatalf, k.tempdir, func(key string) string {
|
||||
v, _ := k.lookupEnv(key)
|
||||
return v
|
||||
}),
|
||||
}, k.stat),
|
||||
Container: config.Container,
|
||||
}
|
||||
|
||||
|
||||
@@ -143,10 +143,6 @@ func TestOutcomeRun(t *testing.T) {
|
||||
// spTmpdirOp
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/9"), fhs.AbsTmp, std.BindWritable).
|
||||
|
||||
// spAccountOp
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:1971:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
||||
|
||||
// spWaylandOp
|
||||
Bind(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1971/wayland-0"), 0).
|
||||
|
||||
@@ -453,7 +449,7 @@ func TestOutcomeRun(t *testing.T) {
|
||||
|
||||
Path: m("/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"),
|
||||
|
||||
Flags: hst.FUserns | hst.FHostNet | hst.FMapRealUID | hst.FShareRuntime | hst.FShareTmpdir,
|
||||
Flags: hst.FUserns | hst.FHostNet | hst.FMapRealUID | hst.FNoPlace | hst.FShareRuntime | hst.FShareTmpdir,
|
||||
},
|
||||
SystemBus: &hst.BusConfig{
|
||||
Talk: []string{"org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"},
|
||||
@@ -548,8 +544,6 @@ func TestOutcomeRun(t *testing.T) {
|
||||
Tmpfs(m("/run/user/"), xdgRuntimeDirSize, 0755).
|
||||
Bind(m("/tmp/hakurei.0/runtime/1"), m("/run/user/1971"), std.BindWritable).
|
||||
Bind(m("/tmp/hakurei.0/tmpdir/1"), m("/tmp/"), std.BindWritable).
|
||||
Place(m("/etc/passwd"), []byte("u0_a1:x:1971:100:Hakurei:/var/lib/persist/module/hakurei/0/1:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
||||
Bind(m("/run/user/1971/wayland-0"), m("/run/user/1971/wayland-0"), 0).
|
||||
Bind(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/pipewire"), m("/run/user/1971/pipewire-0"), 0).
|
||||
Bind(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/bus"), m("/run/user/1971/bus"), 0).
|
||||
@@ -716,7 +710,7 @@ func (k *stubNixOS) lookupEnv(key string) (string, bool) {
|
||||
func (k *stubNixOS) stat(name string) (fs.FileInfo, error) {
|
||||
switch name {
|
||||
case "/var/run/nscd":
|
||||
return nil, nil
|
||||
return stubFileInfoIsDir(true), nil
|
||||
case "/run/user/1971/pulse":
|
||||
return nil, nil
|
||||
case "/run/user/1971/pulse/native":
|
||||
|
||||
@@ -78,10 +78,6 @@ func TestShimEntrypoint(t *testing.T) {
|
||||
// spTmpdirOp
|
||||
Bind(m("/tmp/hakurei.10/tmpdir/9999"), fhs.AbsTmp, std.BindWritable).
|
||||
|
||||
// spAccountOp
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
||||
|
||||
// spWaylandOp
|
||||
Bind(m("/tmp/hakurei.10/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1000/wayland-0"), 0).
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"hakurei.app/fhs"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/validate"
|
||||
)
|
||||
|
||||
@@ -41,16 +42,18 @@ func (s spAccountOp) toContainer(state *outcomeStateParams) error {
|
||||
state.env["USER"] = username
|
||||
state.env["SHELL"] = state.Container.Shell.String()
|
||||
|
||||
state.params.
|
||||
Place(fhs.AbsEtc.Append("passwd"),
|
||||
[]byte(username+":x:"+
|
||||
state.mapuid.String()+":"+
|
||||
state.mapgid.String()+
|
||||
":Hakurei:"+
|
||||
state.Container.Home.String()+":"+
|
||||
state.Container.Shell.String()+"\n")).
|
||||
Place(fhs.AbsEtc.Append("group"),
|
||||
[]byte("hakurei:x:"+state.mapgid.String()+":\n"))
|
||||
if state.Container.Flags&hst.FNoPlace == 0 {
|
||||
state.params.
|
||||
Place(fhs.AbsEtc.Append("passwd"),
|
||||
[]byte(username+":x:"+
|
||||
state.mapuid.String()+":"+
|
||||
state.mapgid.String()+
|
||||
":Hakurei:"+
|
||||
state.Container.Home.String()+":"+
|
||||
state.Container.Shell.String()+"\n")).
|
||||
Place(fhs.AbsEtc.Append("group"),
|
||||
[]byte("hakurei:x:"+state.mapgid.String()+":\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ func TestSpAccountOp(t *testing.T) {
|
||||
{"success fallback username", func(bool, bool) outcomeOp { return spAccountOp{} }, func() *hst.Config {
|
||||
c := hst.Template()
|
||||
c.Container.Username = ""
|
||||
c.Container.Flags = hst.FMapRealUID
|
||||
return c
|
||||
}, nil, []stub.Call{
|
||||
// this op performs basic validation and does not make calls during toSystem
|
||||
@@ -60,9 +61,7 @@ func TestSpAccountOp(t *testing.T) {
|
||||
// this op configures the container state and does not make calls during toContainer
|
||||
}, &container.Params{
|
||||
Dir: config.Container.Home,
|
||||
Ops: new(container.Ops).
|
||||
Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")),
|
||||
Ops: new(container.Ops),
|
||||
}, paramsWantEnv(config, map[string]string{
|
||||
"HOME": config.Container.Home.String(),
|
||||
"USER": config.Container.Username,
|
||||
|
||||
@@ -18,13 +18,12 @@ import (
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal/acl"
|
||||
"hakurei.app/internal/dbus"
|
||||
"hakurei.app/internal/env"
|
||||
"hakurei.app/internal/system"
|
||||
"hakurei.app/internal/validate"
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
const varRunNscd = fhs.Var + "run/nscd"
|
||||
|
||||
func init() { gob.Register(new(spParamsOp)) }
|
||||
|
||||
// spParamsOp initialises unordered fields of [container.Params] and the
|
||||
@@ -136,17 +135,23 @@ type spFilesystemOp struct {
|
||||
}
|
||||
|
||||
func (s *spFilesystemOp) toSystem(state *outcomeStateSys) error {
|
||||
/* retrieve paths and hide them if they're made available in the sandbox;
|
||||
|
||||
this feature tries to improve user experience of permissive defaults, and
|
||||
to warn about issues in custom configuration; it is NOT a security feature
|
||||
and should not be treated as such, ALWAYS be careful with what you bind */
|
||||
// retrieve paths and hide them if they're made available in the sandbox
|
||||
//
|
||||
// this feature tries to improve user experience of permissive defaults, and
|
||||
// to warn about issues in custom configuration; it is NOT a security feature
|
||||
// and should not be treated as such, ALWAYS be careful with what you bind
|
||||
hidePaths := []string{
|
||||
state.sc.RuntimePath.String(),
|
||||
state.sc.SharePath.String(),
|
||||
}
|
||||
|
||||
// this causes emulated passwd database to be bypassed on some /etc/ setups
|
||||
varRunNscd,
|
||||
if state.Paths == nil || state.HasNscd {
|
||||
hidePaths = append(hidePaths,
|
||||
// this causes emulated passwd database to be bypassed on some /etc/
|
||||
// setups, made optional to avoid needlessly creating it on
|
||||
// non-glibc systems when invoking permissive defaults
|
||||
env.VarRunNscd,
|
||||
)
|
||||
}
|
||||
|
||||
// dbus.Address does not go through syscallDispatcher
|
||||
|
||||
@@ -278,6 +278,8 @@ type archiveArtifact struct {
|
||||
f Artifact
|
||||
}
|
||||
|
||||
var _ CuresExempt = archiveArtifact{}
|
||||
|
||||
// NewArchive returns a new [Artifact] backed by the supplied [Artifact]. The
|
||||
// source [Artifact] must be a [FileArtifact] and produce a stream compatible
|
||||
// with [Reader].
|
||||
@@ -301,8 +303,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a slice containing the backing file.
|
||||
func (a archiveArtifact) Dependencies() []Artifact {
|
||||
// Inputs returns a slice containing the backing file.
|
||||
func (a archiveArtifact) Inputs() []Artifact {
|
||||
return []Artifact{a.f}
|
||||
}
|
||||
|
||||
@@ -403,3 +405,7 @@ func (a archiveArtifact) Cure(t *TContext) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CuresExempt exempts the cheap [KindArchive] implementation often found at
|
||||
// the end of a [FileArtifact] pipeline.
|
||||
func (archiveArtifact) CuresExempt() {}
|
||||
|
||||
@@ -186,7 +186,7 @@ func TestArchiveArtifact(t *testing.T) {
|
||||
cureMany(t, c, []cureStep{
|
||||
{"sample", pkg.NewArchive(
|
||||
pkg.NewFile("", buf.Bytes()),
|
||||
), ignorePathname, expectsFS(want), nil},
|
||||
), ignorePathname, expectsFS(want), pkg.WNew, nil},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
@@ -238,7 +238,7 @@ func TestClean(t *testing.T) {
|
||||
base := makeBase(t)
|
||||
msg := message.New(log.New(os.Stderr, "clean: ", 0))
|
||||
msg.SwapVerbose(testing.Verbose())
|
||||
c, err := pkg.Open(t.Context(), msg, 0, 0, 0, base)
|
||||
c, err := pkg.Open(t.Context(), msg, base, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ type decompressArtifact struct {
|
||||
}
|
||||
|
||||
var _ FileArtifact = new(decompressArtifact)
|
||||
var _ CuresExempt = new(decompressArtifact)
|
||||
|
||||
// decompressArtifactNamed embeds decompressArtifact for a [fmt.Stringer] stream.
|
||||
type decompressArtifactNamed struct {
|
||||
@@ -65,8 +66,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a slice containing the backing file.
|
||||
func (a *decompressArtifact) Dependencies() []Artifact {
|
||||
// Inputs returns a slice containing the backing file.
|
||||
func (a *decompressArtifact) Inputs() []Artifact {
|
||||
return []Artifact{a.f}
|
||||
}
|
||||
|
||||
@@ -117,3 +118,7 @@ func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
}
|
||||
|
||||
// CuresExempt exempts the cheap [KindDecompress] implementation often part of
|
||||
// a [FileArtifact] pipeline.
|
||||
func (*decompressArtifact) CuresExempt() {}
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestDecompress(t *testing.T) {
|
||||
&client,
|
||||
"file:///testdata",
|
||||
pkg.Checksum{0xfd},
|
||||
), pkg.Gzip), nil, nil, &pkg.ChecksumMismatchError{
|
||||
), pkg.Gzip), nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
|
||||
Got: testdataChecksum,
|
||||
Want: pkg.Checksum{0xfd},
|
||||
}},
|
||||
@@ -52,7 +52,7 @@ func TestDecompress(t *testing.T) {
|
||||
&client,
|
||||
"file:///testdata",
|
||||
testdataChecksum,
|
||||
), pkg.Gzip), ignorePathname, expectsChecksum(sha512.Sum384([]byte{0})), nil},
|
||||
), pkg.Gzip), ignorePathname, expectsChecksum(sha512.Sum384([]byte{0})), pkg.WNew, nil},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
+22
-12
@@ -30,10 +30,16 @@ import (
|
||||
// AbsWork is the container pathname [TContext.GetWorkDir] is mounted on.
|
||||
var AbsWork = fhs.AbsRoot.Append("work/")
|
||||
|
||||
// EnvJobs is the name of the environment variable holding a decimal
|
||||
// representation of the preferred job count. Its value must not affect cure
|
||||
// outcome.
|
||||
const EnvJobs = "CURE_JOBS"
|
||||
const (
|
||||
// EnvJobs is the name of the environment variable holding a decimal
|
||||
// representation of the preferred job count. Its value must not affect cure
|
||||
// outcome.
|
||||
EnvJobs = "CURE_JOBS"
|
||||
// EnvLoad is the name of the environment variable holding a decimal
|
||||
// representation of the preferred loadavg target. Its value must not affect
|
||||
// cure outcome.
|
||||
EnvLoad = "CURE_LOAD"
|
||||
)
|
||||
|
||||
// ExecPath is a slice of [Artifact] and the [check.Absolute] pathname to make
|
||||
// it available at under in the container.
|
||||
@@ -407,9 +413,9 @@ func init() {
|
||||
func(r *IRReader) Artifact { return readExecArtifact(r, true) })
|
||||
}
|
||||
|
||||
// Dependencies returns a slice of all artifacts collected from caller-supplied
|
||||
// Inputs returns a slice of all artifacts collected from caller-supplied
|
||||
// [ExecPath].
|
||||
func (a *execArtifact) Dependencies() []Artifact {
|
||||
func (a *execArtifact) Inputs() []Artifact {
|
||||
artifacts := make([][]Artifact, 0, len(a.paths))
|
||||
for _, p := range a.paths {
|
||||
artifacts = append(artifacts, p.A)
|
||||
@@ -471,7 +477,7 @@ const SeccompPresets = std.PresetStrict &
|
||||
func (a *execArtifact) makeContainer(
|
||||
ctx context.Context,
|
||||
msg message.Msg,
|
||||
flags, jobs int,
|
||||
flags, jobs, load int,
|
||||
hostNet bool,
|
||||
temp, work *check.Absolute,
|
||||
getArtifact GetArtifactFunc,
|
||||
@@ -508,7 +514,10 @@ func (a *execArtifact) makeContainer(
|
||||
z.Quiet = flags&CSuppressInit != 0
|
||||
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
|
||||
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),
|
||||
EnvLoad + "=" + strconv.Itoa(load),
|
||||
})
|
||||
z.Grow(len(a.paths) + 4)
|
||||
|
||||
if a.arch != runtime.GOARCH {
|
||||
@@ -617,7 +626,7 @@ func (c *Cache) EnterExec(
|
||||
return ErrNotExec
|
||||
}
|
||||
|
||||
deps := Collect(a.Dependencies())
|
||||
deps := Collect(a.Inputs())
|
||||
if _, _, err = c.Cure(&deps); err == nil {
|
||||
return errors.New("unreachable")
|
||||
} else if !IsCollected(err) {
|
||||
@@ -649,8 +658,9 @@ func (c *Cache) EnterExec(
|
||||
var z *container.Container
|
||||
z, err = e.makeContainer(
|
||||
ctx, c.msg,
|
||||
c.flags,
|
||||
c.jobs,
|
||||
c.attr.Flags,
|
||||
c.attr.Jobs,
|
||||
c.attr.Load,
|
||||
hostNet,
|
||||
temp, work,
|
||||
func(a Artifact) (*check.Absolute, unique.Handle[Checksum]) {
|
||||
@@ -693,7 +703,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
||||
msg := f.GetMessage()
|
||||
var z *container.Container
|
||||
if z, err = a.makeContainer(
|
||||
ctx, msg, f.cache.flags, f.GetJobs(), hostNet,
|
||||
ctx, msg, f.cache.attr.Flags, f.GetJobs(), f.GetLoad(), hostNet,
|
||||
f.GetTempDir(), f.GetWorkDir(),
|
||||
f.GetArtifact,
|
||||
f.cache.Ident,
|
||||
|
||||
+10
-10
@@ -84,7 +84,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WNew, nil},
|
||||
|
||||
{"substitution", pkg.NewExec(
|
||||
"exec-offline", "", new(wantOffline.hash()), 0, false, false,
|
||||
@@ -108,7 +108,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WSubstitute, nil},
|
||||
|
||||
{"error passthrough", pkg.NewExec(
|
||||
"", "", nil, 0, false, true,
|
||||
@@ -118,7 +118,7 @@ func TestExec(t *testing.T) {
|
||||
[]string{"testtool"},
|
||||
|
||||
pkg.MustPath("/proc/nonexistent", false, failingArtifact),
|
||||
), nil, nil, &pkg.DependencyCureError{
|
||||
), nil, nil, pkg.WNew, &pkg.DependencyCureError{
|
||||
{
|
||||
A: failingArtifact,
|
||||
Err: stub.UniqueError(0xcafe),
|
||||
@@ -133,7 +133,7 @@ func TestExec(t *testing.T) {
|
||||
[]string{"testtool"},
|
||||
|
||||
pkg.ExecPath{},
|
||||
), nil, nil, pkg.ErrInvalidPaths},
|
||||
), nil, nil, pkg.WNew, pkg.ErrInvalidPaths},
|
||||
})
|
||||
|
||||
// check init failure passthrough
|
||||
@@ -225,7 +225,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantNet, nil},
|
||||
), ignorePathname, wantNet, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -269,7 +269,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -316,7 +316,7 @@ func TestExec(t *testing.T) {
|
||||
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
||||
},
|
||||
}), pkg.Path(pkg.AbsWork, false /* ignored */, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -385,7 +385,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -438,7 +438,7 @@ func TestExec(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
pkg.MustPath("/opt", false, testtool),
|
||||
), ignorePathname, wantOffline, nil},
|
||||
), ignorePathname, wantOffline, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
@@ -503,7 +503,7 @@ func TestExec(t *testing.T) {
|
||||
".": {Mode: fs.ModeDir | 0500},
|
||||
|
||||
"check": {Mode: 0400, Data: []byte("binfmt")},
|
||||
}, nil},
|
||||
}, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
destroyStatus(t, base, 2, 0)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
type fileArtifact []byte
|
||||
|
||||
var _ KnownChecksum = new(fileArtifact)
|
||||
var _ CuresExempt = new(fileArtifact)
|
||||
|
||||
// fileArtifactNamed embeds fileArtifact alongside a caller-supplied name.
|
||||
type fileArtifactNamed struct {
|
||||
@@ -62,8 +63,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a nil slice.
|
||||
func (*fileArtifact) Dependencies() []Artifact { return nil }
|
||||
// Inputs returns a nil slice.
|
||||
func (*fileArtifact) Inputs() []Artifact { return nil }
|
||||
|
||||
// IsExclusive returns false: Cure returns a prepopulated buffer.
|
||||
func (*fileArtifact) IsExclusive() bool { return false }
|
||||
@@ -79,3 +80,6 @@ func (a *fileArtifact) Checksum() Checksum {
|
||||
func (a *fileArtifact) Cure(*RContext) (io.ReadCloser, error) {
|
||||
return io.NopCloser(bytes.NewReader(*a)), nil
|
||||
}
|
||||
|
||||
// CuresExempt exempts the cheap [KindFile] implementation.
|
||||
func (*fileArtifact) CuresExempt() {}
|
||||
|
||||
@@ -18,7 +18,7 @@ func TestFile(t *testing.T) {
|
||||
{"short", pkg.NewFile("null", []byte{0}), base.Append(
|
||||
"identifier",
|
||||
"3376ALA7hIUm2LbzH2fDvRezgzod1eTK_G6XjyOgbM2u-6swvkFaF0BOwSl_juBi",
|
||||
), want, nil},
|
||||
), want, pkg.WNew, nil},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
@@ -38,7 +38,15 @@ func main() {
|
||||
}
|
||||
|
||||
environ := slices.DeleteFunc(slices.Clone(os.Environ()), func(s string) bool {
|
||||
return s == "CURE_JOBS="+strconv.Itoa(runtime.NumCPU())
|
||||
for _, t := range []string{
|
||||
"CURE_JOBS=" + strconv.Itoa(runtime.NumCPU()),
|
||||
"CURE_LOAD=" + strconv.Itoa(runtime.NumCPU()+2),
|
||||
} {
|
||||
if s == t {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
var hostNet, layers, promote bool
|
||||
|
||||
+22
-21
@@ -90,7 +90,7 @@ type IContext struct {
|
||||
// returns and must not be exposed directly.
|
||||
w io.Writer
|
||||
// Optional [Artifact] to cureRes cache, replaces [IRKindIdent] with
|
||||
// checksum values if non-nil.
|
||||
// checksum values if non-nil. The pathname field may not be populated.
|
||||
inputs map[Artifact]cureRes
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ func (i *IContext) mustWrite(p []byte) {
|
||||
|
||||
// WriteIdent writes the identifier of [Artifact] to the IR. The behaviour of
|
||||
// WriteIdent is not defined for an [Artifact] not part of the slice returned by
|
||||
// [Artifact.Dependencies].
|
||||
// [Artifact.Inputs].
|
||||
func (i *IContext) WriteIdent(a Artifact) {
|
||||
buf := i.ic.getIdentBuf()
|
||||
defer i.ic.putIdentBuf(buf)
|
||||
@@ -235,13 +235,14 @@ func (ic *irCache) Encode(w io.Writer, a Artifact) (err error) {
|
||||
}
|
||||
|
||||
// encode implements Encode but replaces identifiers with their cured checksums
|
||||
// for a non-nil ident. Caller must acquire Cache.identMu.
|
||||
// for a non-nil ident. The pathname field is unused. 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.Inputs()
|
||||
idents := make([]*extIdent, len(deps))
|
||||
if inputs == nil {
|
||||
for i, d := range deps {
|
||||
@@ -330,7 +331,7 @@ func (ic *irCache) encodeAll(
|
||||
return
|
||||
}
|
||||
|
||||
for _, d := range a.Dependencies() {
|
||||
for _, d := range a.Inputs() {
|
||||
if err = ic.encodeAll(w, d, encoded); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -432,9 +433,9 @@ type (
|
||||
// Common buffer for word-sized reads.
|
||||
buf [wordSize]byte
|
||||
|
||||
// Dependencies sent before params, sorted by identifier. Resliced on
|
||||
// Inputs sent before params, sorted by identifier. Resliced on
|
||||
// each call to Next and checked to be depleted during Finalise.
|
||||
deps []*extIdent
|
||||
inputs []*extIdent
|
||||
|
||||
// Number of values already read, -1 denotes a finalised IRReader.
|
||||
count int
|
||||
@@ -518,7 +519,7 @@ const (
|
||||
irMaxValues = 1 << 12
|
||||
|
||||
// irMaxDeps is the arbitrary maximum number of direct dependencies allowed
|
||||
// to be returned by [Artifact.Dependencies] and subsequently decoded by
|
||||
// to be returned by [Artifact.Inputs] and subsequently decoded by
|
||||
// [IRDecoder].
|
||||
irMaxDeps = 1 << 10
|
||||
)
|
||||
@@ -603,17 +604,17 @@ func (ir *IRReader) mustReadHeader(k IRValueKind) {
|
||||
|
||||
// putAll returns all dependency buffers to the underlying [Cache].
|
||||
func (ir *IRReader) putAll() {
|
||||
for _, buf := range ir.deps {
|
||||
for _, buf := range ir.inputs {
|
||||
ir.d.c.putIdentBuf(buf)
|
||||
}
|
||||
ir.deps = nil
|
||||
ir.inputs = nil
|
||||
}
|
||||
|
||||
// DiscardAll discards all unstructured dependencies. This is useful to
|
||||
// implementations that encode dependencies as [IRKindIdent] which are read back
|
||||
// via ReadIdent.
|
||||
func (ir *IRReader) DiscardAll() {
|
||||
if ir.deps == nil {
|
||||
if ir.inputs == nil {
|
||||
panic("attempting to discard dependencies twice")
|
||||
}
|
||||
ir.putAll()
|
||||
@@ -625,13 +626,13 @@ var ErrDependencyDepleted = errors.New("reading past end of dependencies")
|
||||
|
||||
// Next returns the next unstructured dependency.
|
||||
func (ir *IRReader) Next() Artifact {
|
||||
if len(ir.deps) == 0 {
|
||||
if len(ir.inputs) == 0 {
|
||||
panic(ErrDependencyDepleted)
|
||||
}
|
||||
|
||||
id := unique.Make(ID(ir.deps[0][wordSize:]))
|
||||
ir.d.c.putIdentBuf(ir.deps[0])
|
||||
ir.deps = ir.deps[1:]
|
||||
id := unique.Make(ID(ir.inputs[0][wordSize:]))
|
||||
ir.d.c.putIdentBuf(ir.inputs[0])
|
||||
ir.inputs = ir.inputs[1:]
|
||||
|
||||
if a, ok := ir.d.ident[id]; !ok {
|
||||
ir.putAll()
|
||||
@@ -684,8 +685,8 @@ func (ir *IRReader) Finalise() (checksum unique.Handle[Checksum], ok bool) {
|
||||
}
|
||||
ir.r, ir.ibw = nil, nil
|
||||
|
||||
if len(ir.deps) != 0 {
|
||||
panic(MissedDependencyError(len(ir.deps)))
|
||||
if len(ir.inputs) != 0 {
|
||||
panic(MissedDependencyError(len(ir.inputs)))
|
||||
}
|
||||
|
||||
return
|
||||
@@ -778,11 +779,11 @@ func (d *IRDecoder) decode() (a Artifact, err error) {
|
||||
err = ErrIRDepend
|
||||
return
|
||||
}
|
||||
ir.deps = make([]*extIdent, sz)
|
||||
for i := range ir.deps {
|
||||
ir.deps[i] = d.c.getIdentBuf()
|
||||
ir.inputs = make([]*extIdent, sz)
|
||||
for i := range ir.inputs {
|
||||
ir.inputs[i] = d.c.getIdentBuf()
|
||||
}
|
||||
for _, buf := range ir.deps {
|
||||
for _, buf := range ir.inputs {
|
||||
ir.mustRead(buf[:])
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -54,8 +54,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a nil slice.
|
||||
func (*httpArtifact) Dependencies() []Artifact { return nil }
|
||||
// Inputs returns a nil slice.
|
||||
func (*httpArtifact) Inputs() []Artifact { return nil }
|
||||
|
||||
// IsExclusive returns false: Cure returns as soon as a response is received.
|
||||
func (*httpArtifact) IsExclusive() bool { return false }
|
||||
|
||||
+369
-149
@@ -6,6 +6,7 @@ import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
@@ -278,7 +279,11 @@ func (c *common) GetMessage() message.Msg { return c.cache.msg }
|
||||
|
||||
// GetJobs returns the preferred number of jobs to run, when applicable. Its
|
||||
// value must not affect cure outcome.
|
||||
func (c *common) GetJobs() int { return c.cache.jobs }
|
||||
func (c *common) GetJobs() int { return c.cache.attr.Jobs }
|
||||
|
||||
// GetLoad returns the preferred load average target, when applicable. Its
|
||||
// value must not affect cure outcome.
|
||||
func (c *common) GetLoad() int { return c.cache.attr.Load }
|
||||
|
||||
// GetWorkDir returns a pathname to a directory which [Artifact] is expected to
|
||||
// write its output to. This is not the final resting place of the [Artifact]
|
||||
@@ -303,7 +308,7 @@ func (c *common) Open(a Artifact) (r io.ReadCloser, err error) {
|
||||
}
|
||||
|
||||
var pathname *check.Absolute
|
||||
if pathname, _, err = c.cache.cure(a, true); err != nil {
|
||||
if pathname, _, _, err = c.cache.cure(a, true, false); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -330,8 +335,8 @@ func (c *common) Open(a Artifact) (r io.ReadCloser, err error) {
|
||||
type FContext struct {
|
||||
TContext
|
||||
|
||||
// Cured top-level dependencies looked up by Pathname.
|
||||
deps map[Artifact]cureRes
|
||||
// Cured top-level inputs looked up by Pathname.
|
||||
inputs map[Artifact]cureRes
|
||||
}
|
||||
|
||||
// linkSubstitute links status for substitute if populated.
|
||||
@@ -356,24 +361,24 @@ func (f *FContext) linkSubstitute(ids, substitutes string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// InvalidLookupError is the identifier of non-dependency [Artifact] looked up
|
||||
// InvalidLookupError is the identifier of non-input [Artifact] looked up
|
||||
// via [FContext.GetArtifact] by a misbehaving [Artifact] implementation.
|
||||
type InvalidLookupError ID
|
||||
|
||||
func (e InvalidLookupError) Error() string {
|
||||
return "attempting to look up non-dependency artifact " + Encode(e)
|
||||
return "attempting to look up non-input artifact " + Encode(e)
|
||||
}
|
||||
|
||||
var _ error = InvalidLookupError{}
|
||||
|
||||
// GetArtifact returns the identifier pathname and checksum of an [Artifact].
|
||||
// Calling Pathname with an [Artifact] not part of the slice returned by
|
||||
// [Artifact.Dependencies] panics.
|
||||
// [Artifact.Inputs] panics.
|
||||
func (f *FContext) GetArtifact(a Artifact) (
|
||||
pathname *check.Absolute,
|
||||
checksum unique.Handle[Checksum],
|
||||
) {
|
||||
if res, ok := f.deps[a]; ok {
|
||||
if res, ok := f.inputs[a]; ok {
|
||||
return res.pathname, res.checksum
|
||||
}
|
||||
panic(InvalidLookupError(f.cache.Ident(a).Value()))
|
||||
@@ -405,13 +410,13 @@ type Artifact interface {
|
||||
// Result must remain identical across multiple invocations.
|
||||
Params(ctx *IContext)
|
||||
|
||||
// Dependencies returns a slice of [Artifact] that the current instance
|
||||
// depends on to produce its contents.
|
||||
// Inputs returns a slice of [Artifact] the current instance has access to
|
||||
// while producing its output.
|
||||
//
|
||||
// Callers must not modify the retuned slice.
|
||||
//
|
||||
// Result must remain identical across multiple invocations.
|
||||
Dependencies() []Artifact
|
||||
Inputs() []Artifact
|
||||
|
||||
// IsExclusive returns whether the [Artifact] is exclusive. Exclusive
|
||||
// artifacts might not run in parallel with each other, and are still
|
||||
@@ -485,6 +490,16 @@ type KnownChecksum interface {
|
||||
Checksum() Checksum
|
||||
}
|
||||
|
||||
// CuresExempt is optionally implemented for an artifact exempt to the
|
||||
// cache-wide cures counter and limit.
|
||||
type CuresExempt interface {
|
||||
Artifact
|
||||
|
||||
// CuresExempt is a no-op function but serves to distinguish implementations
|
||||
// that are cures-exempt.
|
||||
CuresExempt()
|
||||
}
|
||||
|
||||
// FileArtifact refers to an [Artifact] backed by a single file.
|
||||
//
|
||||
// FileArtifact does not support fine-grained cancellation. Its context is
|
||||
@@ -592,7 +607,7 @@ type cureRes struct {
|
||||
checksum unique.Handle[Checksum]
|
||||
}
|
||||
|
||||
// A pendingArtifactDep is a dependency [Artifact] pending concurrent curing,
|
||||
// A pendingArtifactDep is an input [Artifact] pending concurrent curing,
|
||||
// subject to the cures limit. Values pointed to by result addresses are safe
|
||||
// to access after the [sync.WaitGroup] associated with this pendingArtifactDep
|
||||
// is done. pendingArtifactDep must not be reused or modified after it is sent
|
||||
@@ -666,8 +681,12 @@ const (
|
||||
// suppressed regardless of [message.Msg] state.
|
||||
CSuppressInit
|
||||
|
||||
// CIgnoreSubstitutes disables content-based dependency substitution.
|
||||
// CIgnoreSubstitutes disables content-based input substitution.
|
||||
CIgnoreSubstitutes
|
||||
|
||||
// CExternShallow arranges for only non-flood inputs to be fetched when
|
||||
// curing an [Artifact] available via the external cache.
|
||||
CExternShallow
|
||||
)
|
||||
|
||||
// toplevel holds [context.WithCancel] over caller-supplied context, where all
|
||||
@@ -719,17 +738,15 @@ type Cache struct {
|
||||
parent context.Context
|
||||
// For deriving curing context, must not be accessed directly.
|
||||
toplevel atomic.Pointer[toplevel]
|
||||
// For waiting on dependency curing goroutines.
|
||||
// For waiting on input curing goroutines.
|
||||
wg sync.WaitGroup
|
||||
// Reports new cures and passed to [Artifact].
|
||||
msg message.Msg
|
||||
|
||||
// Directory where all [Cache] related files are placed.
|
||||
base *check.Absolute
|
||||
// Immutable cure options set by [Open].
|
||||
flags int
|
||||
// Immutable job count, when applicable.
|
||||
jobs int
|
||||
// Immutable [CacheAttr] populated by [Open].
|
||||
attr CacheAttr
|
||||
|
||||
// Must not be exposed directly.
|
||||
irCache
|
||||
@@ -760,6 +777,8 @@ type Cache struct {
|
||||
|
||||
// Optional external cache implementation.
|
||||
extern External
|
||||
// Caches responses from extern.
|
||||
externCache map[unique.Handle[ID]]unique.Handle[Checksum]
|
||||
// Synchronises access to extern.
|
||||
externMu sync.RWMutex
|
||||
|
||||
@@ -920,6 +939,7 @@ func readlinkChecksum(a *check.Absolute, buf *Checksum) error {
|
||||
// SetExternal sets e as the [External] implementation of c.
|
||||
func (c *Cache) SetExternal(e External) {
|
||||
c.externMu.Lock()
|
||||
c.externCache = make(map[unique.Handle[ID]]unique.Handle[Checksum])
|
||||
c.extern = e
|
||||
c.externMu.Unlock()
|
||||
}
|
||||
@@ -1431,7 +1451,7 @@ func (c *Cache) openFile(
|
||||
ctx context.Context,
|
||||
f FileArtifact,
|
||||
) (r io.ReadCloser, err error) {
|
||||
if kc, ok := f.(KnownChecksum); c.flags&CAssumeChecksum != 0 && ok {
|
||||
if kc, ok := f.(KnownChecksum); c.attr.Flags&CAssumeChecksum != 0 && ok {
|
||||
c.checksumMu.RLock()
|
||||
r, err = os.Open(c.base.Append(
|
||||
dirChecksum,
|
||||
@@ -1616,7 +1636,47 @@ func (c *Cache) Cure(a Artifact) (
|
||||
return
|
||||
}
|
||||
|
||||
return c.cure(a, true)
|
||||
pathname, checksum, _, err = c.cure(a, true, false)
|
||||
return
|
||||
}
|
||||
|
||||
// CureWhence is like Cure, but returns the whence value.
|
||||
func (c *Cache) CureWhence(a Artifact) (
|
||||
pathname *check.Absolute,
|
||||
checksum unique.Handle[Checksum],
|
||||
whence int,
|
||||
err error,
|
||||
) {
|
||||
c.abortMu.RLock()
|
||||
defer c.abortMu.RUnlock()
|
||||
|
||||
if err = c.toplevel.Load().ctx.Err(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return c.cure(a, true, false)
|
||||
}
|
||||
|
||||
// CureNew is like Cure, but always enters the implementation.
|
||||
func (c *Cache) CureNew(a Artifact) (
|
||||
pathname *check.Absolute,
|
||||
checksum unique.Handle[Checksum],
|
||||
err error,
|
||||
) {
|
||||
c.abortMu.RLock()
|
||||
defer c.abortMu.RUnlock()
|
||||
|
||||
if err = c.toplevel.Load().ctx.Err(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var whence int
|
||||
retry:
|
||||
pathname, checksum, whence, err = c.cure(a, true, true)
|
||||
if err != nil || whence == WNew {
|
||||
return
|
||||
}
|
||||
goto retry
|
||||
}
|
||||
|
||||
// CureError wraps a non-nil error returned attempting to cure an [Artifact].
|
||||
@@ -1838,71 +1898,11 @@ func (r *RContext) NewMeasuredReader(
|
||||
return r.cache.newMeasuredReader(rc, checksum)
|
||||
}
|
||||
|
||||
// tryExtern attempts to obtain an [Artifact] outcome from extern.
|
||||
func (c *Cache) tryExtern(ctx context.Context, id unique.Handle[ID]) (
|
||||
unique.Handle[Checksum],
|
||||
io.ReadCloser,
|
||||
error,
|
||||
) {
|
||||
c.externMu.RLock()
|
||||
defer c.externMu.RUnlock()
|
||||
|
||||
if c.extern == nil {
|
||||
return zeroChecksum, nil, nil
|
||||
}
|
||||
|
||||
v, err := c.extern.Artifact(ctx, id)
|
||||
if err != nil {
|
||||
return zeroChecksum, nil, err
|
||||
}
|
||||
if v == nil {
|
||||
return zeroChecksum, nil, nil
|
||||
}
|
||||
checksum := unique.Make(*v)
|
||||
|
||||
var got unique.Handle[Checksum]
|
||||
if _, got, err = c.Cure(c.extern.Checksum(checksum)); err != nil {
|
||||
return checksum, nil, err
|
||||
} else if got != checksum {
|
||||
return zeroChecksum, nil, &ChecksumMismatchError{got.Value(), checksum.Value()}
|
||||
}
|
||||
|
||||
var status io.ReadCloser
|
||||
status, err = c.extern.Status(&RContext{common{ctx, c}}, id)
|
||||
return checksum, status, err
|
||||
}
|
||||
|
||||
// cure implements Cure without acquiring a read lock on abortMu. cure must not
|
||||
// be entered during Abort.
|
||||
func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
pathname *check.Absolute,
|
||||
// tryChecksum dereferences a symlink to a cure outcome.
|
||||
func (c *Cache) tryChecksum(pathname *check.Absolute) (
|
||||
checksum unique.Handle[Checksum],
|
||||
err error,
|
||||
) {
|
||||
id := c.Ident(a)
|
||||
ids := Encode(id.Value())
|
||||
pathname = c.base.Append(
|
||||
dirIdentifier,
|
||||
ids,
|
||||
)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
pathname = nil
|
||||
checksum = unique.Handle[Checksum]{}
|
||||
}
|
||||
}()
|
||||
|
||||
var (
|
||||
ctx context.Context
|
||||
done chan<- struct{}
|
||||
)
|
||||
ctx, done, checksum, err = c.loadOrStoreIdent(id)
|
||||
if done == nil {
|
||||
return
|
||||
} else {
|
||||
defer func() { c.finaliseIdent(done, id, checksum, err) }()
|
||||
}
|
||||
|
||||
_, err = os.Lstat(pathname.String())
|
||||
if err == nil {
|
||||
var name string
|
||||
@@ -1915,9 +1915,180 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
checksum = unique.Make(Checksum(buf[:]))
|
||||
}
|
||||
c.putIdentBuf(buf)
|
||||
return
|
||||
}
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
return
|
||||
}
|
||||
|
||||
// tryLocal attempts to obtain an [Artifact] outcome from the filesystem.
|
||||
func (c *Cache) tryLocal(id unique.Handle[ID]) (unique.Handle[Checksum], error) {
|
||||
return c.tryChecksum(c.base.Append(
|
||||
dirIdentifier,
|
||||
Encode(id.Value()),
|
||||
))
|
||||
}
|
||||
|
||||
// tryExtern attempts to obtain an [Artifact] outcome from extern.
|
||||
func (c *Cache) tryExtern(ctx context.Context, id unique.Handle[ID]) (
|
||||
unique.Handle[Checksum],
|
||||
error,
|
||||
) {
|
||||
c.externMu.RLock()
|
||||
defer c.externMu.RUnlock()
|
||||
|
||||
checksum, ok := c.externCache[id]
|
||||
if !ok {
|
||||
if c.extern == nil {
|
||||
return zeroChecksum, nil
|
||||
}
|
||||
|
||||
v, err := c.extern.Artifact(ctx, id)
|
||||
if err != nil {
|
||||
return zeroChecksum, err
|
||||
}
|
||||
if v == nil {
|
||||
return zeroChecksum, nil
|
||||
}
|
||||
checksum = unique.Make(*v)
|
||||
|
||||
var got unique.Handle[Checksum]
|
||||
if _, got, err = c.Cure(c.extern.Checksum(checksum)); err != nil {
|
||||
return checksum, err
|
||||
} else if got != checksum {
|
||||
return zeroChecksum, &ChecksumMismatchError{got.Value(), checksum.Value()}
|
||||
}
|
||||
}
|
||||
return checksum, nil
|
||||
}
|
||||
|
||||
// cureMany concurrently collects outcome of multiple [Artifact].
|
||||
func (c *Cache) cureMany(
|
||||
inputs []Artifact,
|
||||
r map[Artifact]cureRes,
|
||||
shallow bool,
|
||||
) ([]bool, error) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(inputs))
|
||||
var mask []bool
|
||||
res := make([]cureRes, len(inputs))
|
||||
errs := make(DependencyCureError, 0, len(inputs))
|
||||
var errsMu sync.Mutex
|
||||
if shallow {
|
||||
mask = make([]bool, len(inputs))
|
||||
}
|
||||
for i, d := range inputs {
|
||||
if shallow {
|
||||
if _, ok := d.(FloodArtifact); ok {
|
||||
mask[i] = true
|
||||
wg.Done()
|
||||
continue
|
||||
}
|
||||
|
||||
if kc, ok := d.(KnownChecksum); ok {
|
||||
res[i].checksum = unique.Make(kc.Checksum())
|
||||
wg.Done()
|
||||
continue
|
||||
}
|
||||
}
|
||||
pending := pendingArtifactDep{d, &res[i], &errs, &errsMu, &wg}
|
||||
go pending.cure(c)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
if len(errs) > 0 {
|
||||
return mask, &errs
|
||||
}
|
||||
for i, p := range res {
|
||||
if shallow && mask[i] {
|
||||
continue
|
||||
}
|
||||
r[inputs[i]] = p
|
||||
}
|
||||
return mask, nil
|
||||
}
|
||||
|
||||
// HangingInputError describes an input of an [Artifact] on a sparse cache
|
||||
// without an outcome available locally or via [External].
|
||||
type HangingInputError unique.Handle[ID]
|
||||
|
||||
func (e HangingInputError) Error() string {
|
||||
return Encode(unique.Handle[ID](e).Value()) + " is unavailable"
|
||||
}
|
||||
|
||||
const (
|
||||
// WNew indicates a cure entering the implementation.
|
||||
WNew = iota
|
||||
// WCache indicates an [Artifact] present in the cache.
|
||||
WCache
|
||||
// WSubstitute indicates an [Artifact] hitting a content-based input
|
||||
// substitution.
|
||||
WSubstitute
|
||||
// WExternal indicates a cure entering the external cache.
|
||||
WExternal
|
||||
)
|
||||
|
||||
// WhenceString returns a printable string for a whence value.
|
||||
func WhenceString(whence int) string {
|
||||
switch whence {
|
||||
case WNew:
|
||||
return "new"
|
||||
case WCache:
|
||||
return "cache"
|
||||
case WSubstitute:
|
||||
return "substitute"
|
||||
case WExternal:
|
||||
return "external"
|
||||
|
||||
default:
|
||||
return "invalid whence " + strconv.Itoa(whence)
|
||||
}
|
||||
}
|
||||
|
||||
// cure implements Cure without acquiring a read lock on abortMu. cure must not
|
||||
// be entered during Abort.
|
||||
func (c *Cache) cure(a Artifact, curesExempt, rebuild bool) (
|
||||
pathname *check.Absolute,
|
||||
checksum unique.Handle[Checksum],
|
||||
whence int,
|
||||
err error,
|
||||
) {
|
||||
id := c.Ident(a)
|
||||
if rebuild {
|
||||
var v ID
|
||||
_, _ = rand.Read(v[:])
|
||||
id = unique.Make(v)
|
||||
}
|
||||
|
||||
ids := Encode(id.Value())
|
||||
pathname = c.base.Append(
|
||||
dirIdentifier,
|
||||
ids,
|
||||
)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
pathname = nil
|
||||
checksum = unique.Handle[Checksum]{}
|
||||
}
|
||||
}()
|
||||
|
||||
if _, ok := a.(CuresExempt); ok {
|
||||
curesExempt = true
|
||||
}
|
||||
|
||||
var (
|
||||
ctx context.Context
|
||||
done chan<- struct{}
|
||||
)
|
||||
ctx, done, checksum, err = c.loadOrStoreIdent(id)
|
||||
if done == nil {
|
||||
whence = WCache
|
||||
return
|
||||
} else {
|
||||
defer func() { c.finaliseIdent(done, id, checksum, err) }()
|
||||
}
|
||||
|
||||
checksum, err = c.tryChecksum(pathname)
|
||||
if err == nil || !errors.Is(err, os.ErrNotExist) {
|
||||
whence = WCache
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1972,7 +2143,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
checksums,
|
||||
)
|
||||
|
||||
if c.flags&CAssumeChecksum != 0 {
|
||||
if c.attr.Flags&CAssumeChecksum != 0 {
|
||||
c.checksumMu.RLock()
|
||||
checksumFi, err = os.Stat(checksumPathname.String())
|
||||
c.checksumMu.RUnlock()
|
||||
@@ -1987,6 +2158,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
}
|
||||
}
|
||||
|
||||
whence = WNew
|
||||
if c.msg.IsVerbose() {
|
||||
rn := reportName(a, id)
|
||||
c.msg.Verbosef("curing %s...", rn)
|
||||
@@ -2005,6 +2177,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
// cure FileArtifact outside type switch to skip TContext initialisation
|
||||
if f, ok := a.(FileArtifact); ok {
|
||||
if checksumFi != nil {
|
||||
whence = WCache
|
||||
if !checksumFi.Mode().IsRegular() {
|
||||
// unreachable
|
||||
err = InvalidFileModeError(checksumFi.Mode())
|
||||
@@ -2039,7 +2212,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
}
|
||||
r, err = f.Cure(&RContext{common{ctx, c}})
|
||||
if err == nil {
|
||||
if checksumPathname == nil || c.flags&CValidateKnown != 0 {
|
||||
if checksumPathname == nil || c.attr.Flags&CValidateKnown != 0 {
|
||||
h := sha512.New384()
|
||||
hbw := c.getWriter(h)
|
||||
_, err = io.Copy(w, io.TeeReader(r, hbw))
|
||||
@@ -2056,7 +2229,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
if checksumPathname == nil {
|
||||
checksum = unique.Make(Checksum(buf[:]))
|
||||
checksums = Encode(Checksum(buf[:]))
|
||||
} else if c.flags&CValidateKnown != 0 {
|
||||
} else if c.attr.Flags&CValidateKnown != 0 {
|
||||
if got := Checksum(buf[:]); got != checksum.Value() {
|
||||
err = &ChecksumMismatchError{
|
||||
Got: got,
|
||||
@@ -2109,6 +2282,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
}
|
||||
|
||||
if checksumFi != nil {
|
||||
whence = WCache
|
||||
if !checksumFi.Mode().IsDir() {
|
||||
// unreachable
|
||||
err = InvalidFileModeError(checksumFi.Mode())
|
||||
@@ -2139,30 +2313,64 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
break
|
||||
|
||||
case FloodArtifact:
|
||||
deps := a.Dependencies()
|
||||
f := FContext{t, make(map[Artifact]cureRes, len(deps))}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(deps))
|
||||
res := make([]cureRes, len(deps))
|
||||
errs := make(DependencyCureError, 0, len(deps))
|
||||
var errsMu sync.Mutex
|
||||
for i, d := range deps {
|
||||
pending := pendingArtifactDep{d, &res[i], &errs, &errsMu, &wg}
|
||||
go pending.cure(c)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
if len(errs) > 0 {
|
||||
err = &errs
|
||||
var externChecksum unique.Handle[Checksum]
|
||||
if externChecksum, err = c.tryExtern(ctx, id); err != nil {
|
||||
if c.msg.IsVerbose() {
|
||||
c.msg.Verbosef("extern %s: %v", reportName(ca, id), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
for i, p := range res {
|
||||
f.deps[deps[i]] = p
|
||||
extern := externChecksum != zeroChecksum
|
||||
shallow := extern && c.attr.Flags&CExternShallow != 0
|
||||
|
||||
inputs := a.Inputs()
|
||||
f := FContext{t, make(map[Artifact]cureRes, len(inputs))}
|
||||
var mask []bool
|
||||
if mask, err = c.cureMany(inputs, f.inputs, shallow); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if shallow {
|
||||
for i, d := range inputs {
|
||||
if !mask[i] {
|
||||
continue
|
||||
}
|
||||
|
||||
if kc, ok := d.(KnownChecksum); ok {
|
||||
f.inputs[d] = cureRes{checksum: unique.Make(kc.Checksum())}
|
||||
continue
|
||||
}
|
||||
|
||||
var sum unique.Handle[Checksum]
|
||||
did := c.Ident(d)
|
||||
sum, err = c.tryLocal(did)
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
return
|
||||
}
|
||||
|
||||
sum, err = c.tryExtern(ctx, did)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if sum == zeroChecksum {
|
||||
if c.msg.IsVerbose() {
|
||||
c.msg.Verbosef(
|
||||
"input %s not available",
|
||||
reportName(d, did),
|
||||
)
|
||||
}
|
||||
err = HangingInputError(did)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
f.inputs[d] = cureRes{checksum: sum}
|
||||
}
|
||||
}
|
||||
|
||||
sh := sha512.New384()
|
||||
err = c.encode(sh, a, f.deps)
|
||||
err = c.encode(sh, a, f.inputs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -2177,13 +2385,14 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
substitutes,
|
||||
)
|
||||
|
||||
if c.flags&CIgnoreSubstitutes == 0 {
|
||||
if !rebuild && c.attr.Flags&CIgnoreSubstitutes == 0 {
|
||||
var substituteChecksum unique.Handle[Checksum]
|
||||
substituteChecksum, err = c.loadSubstitute(substitute)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if substituteChecksum != zeroChecksum {
|
||||
whence = WSubstitute
|
||||
checksum = substituteChecksum
|
||||
checksums = Encode(checksum.Value())
|
||||
checksumPathname = c.base.Append(
|
||||
@@ -2207,21 +2416,9 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
|
||||
defer f.destroy(&err)
|
||||
|
||||
var (
|
||||
externChecksum unique.Handle[Checksum]
|
||||
externStatus io.ReadCloser
|
||||
)
|
||||
if externChecksum, externStatus, err = c.tryExtern(ctx, id); err != nil {
|
||||
if c.msg.IsVerbose() {
|
||||
c.msg.Verbosef("extern %s: %v", reportName(ca, id), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if externChecksum != zeroChecksum {
|
||||
if extern {
|
||||
whence = WExternal
|
||||
if checksum != zeroChecksum && externChecksum != checksum {
|
||||
if externStatus != nil {
|
||||
_ = externStatus.Close()
|
||||
}
|
||||
err = &ChecksumMismatchError{externChecksum.Value(), checksum.Value()}
|
||||
if c.msg.IsVerbose() {
|
||||
c.msg.Verbosef("extern %s: %v", reportName(ca, id), err)
|
||||
@@ -2229,6 +2426,14 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
return
|
||||
}
|
||||
|
||||
var externStatus io.ReadCloser
|
||||
c.externMu.RLock()
|
||||
externStatus, err = c.extern.Status(&RContext{common{ctx, c}}, id)
|
||||
c.externMu.RUnlock()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
checksum = externChecksum
|
||||
checksums = Encode(checksum.Value())
|
||||
checksumPathname = c.base.Append(
|
||||
@@ -2245,8 +2450,10 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
return
|
||||
} else if err = externStatus.Close(); err != nil {
|
||||
return
|
||||
} else if err = f.linkSubstitute(ids, substitutes); err != nil {
|
||||
return
|
||||
} else if !rebuild {
|
||||
if err = f.linkSubstitute(ids, substitutes); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -2258,7 +2465,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
err = ca.Cure(&f)
|
||||
c.exitCure(a, curesExempt)
|
||||
|
||||
if err == nil {
|
||||
if !rebuild && err == nil {
|
||||
err = f.linkSubstitute(ids, substitutes)
|
||||
}
|
||||
if err != nil {
|
||||
@@ -2352,7 +2559,7 @@ func (pending *pendingArtifactDep) cure(c *Cache) {
|
||||
defer pending.Done()
|
||||
|
||||
var err error
|
||||
pending.resP.pathname, pending.resP.checksum, err = c.cure(pending.a, false)
|
||||
pending.resP.pathname, pending.resP.checksum, _, err = c.cure(pending.a, false, false)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
@@ -2472,6 +2679,22 @@ var (
|
||||
ErrWouldPromote = errors.New("operation would promote unextended cache")
|
||||
)
|
||||
|
||||
// CacheAttr holds the attributes that will be applied to a new [Cache] opened
|
||||
// by [Open].
|
||||
type CacheAttr struct {
|
||||
// Concurrent cures of a [FloodArtifact] dependency graph.
|
||||
Cures int
|
||||
// Options affecting [Cache] behaviour.
|
||||
Flags int
|
||||
// Preferred job count, when applicable.
|
||||
Jobs int
|
||||
// Preferred loadavg target, when applicable.
|
||||
Load int
|
||||
|
||||
// Omit the [lockedfile] lock.
|
||||
skipLock bool
|
||||
}
|
||||
|
||||
// Open returns the address of a newly opened instance of [Cache].
|
||||
//
|
||||
// Concurrent cures of a [FloodArtifact] dependency graph is limited to the
|
||||
@@ -2488,20 +2711,8 @@ var (
|
||||
func Open(
|
||||
ctx context.Context,
|
||||
msg message.Msg,
|
||||
flags, cures, jobs int,
|
||||
base *check.Absolute,
|
||||
) (*Cache, error) {
|
||||
return open(ctx, msg, flags, cures, jobs, base, true)
|
||||
}
|
||||
|
||||
// open implements Open but allows omitting the [lockedfile] lock when called
|
||||
// from a test. This is used to simulate invalid states in the test suite.
|
||||
func open(
|
||||
ctx context.Context,
|
||||
msg message.Msg,
|
||||
flags, cures, jobs int,
|
||||
base *check.Absolute,
|
||||
lock bool,
|
||||
attr *CacheAttr,
|
||||
) (*Cache, error) {
|
||||
openMu.Lock()
|
||||
defer openMu.Unlock()
|
||||
@@ -2511,11 +2722,19 @@ func open(
|
||||
panic("attempting to open cache with incomplete variant setup")
|
||||
}
|
||||
|
||||
if cures < 1 {
|
||||
cures = runtime.NumCPU()
|
||||
var a CacheAttr
|
||||
if attr != nil {
|
||||
a = *attr
|
||||
}
|
||||
if jobs < 1 {
|
||||
jobs = runtime.NumCPU()
|
||||
|
||||
if a.Cures < 1 {
|
||||
a.Cures = runtime.NumCPU()
|
||||
}
|
||||
if a.Jobs < 1 {
|
||||
a.Jobs = runtime.NumCPU()
|
||||
}
|
||||
if a.Load < 1 {
|
||||
a.Load = runtime.NumCPU() + 2
|
||||
}
|
||||
|
||||
for _, name := range []string{
|
||||
@@ -2537,9 +2756,8 @@ func open(
|
||||
c := Cache{
|
||||
parent: ctx,
|
||||
|
||||
cures: make(chan struct{}, cures),
|
||||
flags: flags,
|
||||
jobs: jobs,
|
||||
cures: make(chan struct{}, a.Cures),
|
||||
attr: a,
|
||||
|
||||
msg: msg,
|
||||
base: base,
|
||||
@@ -2556,7 +2774,7 @@ func open(
|
||||
}
|
||||
c.toplevel.Store(newToplevel(ctx))
|
||||
|
||||
if lock || !testing.Testing() {
|
||||
if !a.skipLock || !testing.Testing() {
|
||||
if unlock, err := lockedfile.MutexAt(
|
||||
base.Append(fileLock).String(),
|
||||
).Lock(); err != nil {
|
||||
@@ -2617,7 +2835,7 @@ func open(
|
||||
}
|
||||
} else if s := string(p); s == "" {
|
||||
if extension != "" {
|
||||
if flags&CPromoteVariant == 0 {
|
||||
if a.Flags&CPromoteVariant == 0 {
|
||||
c.unlock()
|
||||
return nil, ErrWouldPromote
|
||||
}
|
||||
@@ -2656,6 +2874,8 @@ func IsCollected(err error) bool { return errors.As(err, new(Collected)) }
|
||||
// [pkg.Artifact]. It returns [Collected].
|
||||
type Collect []Artifact
|
||||
|
||||
var _ Artifact = new(Collect)
|
||||
|
||||
// Cure returns [Collected].
|
||||
func (*Collect) Cure(*FContext) error { return Collected{} }
|
||||
|
||||
@@ -2665,8 +2885,8 @@ func (*Collect) Kind() Kind { return kindCollection }
|
||||
// Params is a noop: dependencies are already represented in the header.
|
||||
func (*Collect) Params(*IContext) {}
|
||||
|
||||
// Dependencies returns [Collect] as is.
|
||||
func (c *Collect) Dependencies() []Artifact { return *c }
|
||||
// Inputs returns [Collect] as is.
|
||||
func (c *Collect) Inputs() []Artifact { return *c }
|
||||
|
||||
// IsExclusive returns false: Cure is a noop.
|
||||
func (*Collect) IsExclusive() bool { return false }
|
||||
|
||||
+231
-84
@@ -35,14 +35,14 @@ import (
|
||||
"hakurei.app/message"
|
||||
)
|
||||
|
||||
//go:linkname unsafeOpen hakurei.app/internal/pkg.open
|
||||
func unsafeOpen(
|
||||
ctx context.Context,
|
||||
msg message.Msg,
|
||||
flags, cures, jobs int,
|
||||
base *check.Absolute,
|
||||
lock bool,
|
||||
) (*pkg.Cache, error)
|
||||
var skipLock = func() pkg.CacheAttr {
|
||||
var attr pkg.CacheAttr
|
||||
*(*bool)(unsafe.Pointer(reflect.ValueOf(&attr).
|
||||
Elem().
|
||||
FieldByName("skipLock").
|
||||
UnsafeAddr())) = true
|
||||
return attr
|
||||
}()
|
||||
|
||||
var (
|
||||
// extension is a string uniquely identifying a set of custom [Artifact]
|
||||
@@ -140,11 +140,11 @@ type stubArtifact struct {
|
||||
cure func(t *pkg.TContext) error
|
||||
}
|
||||
|
||||
func (a *stubArtifact) Kind() pkg.Kind { return a.kind }
|
||||
func (a *stubArtifact) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
|
||||
func (a *stubArtifact) Dependencies() []pkg.Artifact { return a.deps }
|
||||
func (a *stubArtifact) Cure(t *pkg.TContext) error { return a.cure(t) }
|
||||
func (*stubArtifact) IsExclusive() bool { return false }
|
||||
func (a *stubArtifact) Kind() pkg.Kind { return a.kind }
|
||||
func (a *stubArtifact) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
|
||||
func (a *stubArtifact) Inputs() []pkg.Artifact { return a.deps }
|
||||
func (a *stubArtifact) Cure(t *pkg.TContext) error { return a.cure(t) }
|
||||
func (*stubArtifact) IsExclusive() bool { return false }
|
||||
|
||||
// A stubArtifactF implements [FloodArtifact] with hardcoded behaviour.
|
||||
type stubArtifactF struct {
|
||||
@@ -156,11 +156,11 @@ type stubArtifactF struct {
|
||||
cure func(f *pkg.FContext) error
|
||||
}
|
||||
|
||||
func (a *stubArtifactF) Kind() pkg.Kind { return a.kind }
|
||||
func (a *stubArtifactF) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
|
||||
func (a *stubArtifactF) Dependencies() []pkg.Artifact { return a.deps }
|
||||
func (a *stubArtifactF) Cure(f *pkg.FContext) error { return a.cure(f) }
|
||||
func (a *stubArtifactF) IsExclusive() bool { return a.excl }
|
||||
func (a *stubArtifactF) Kind() pkg.Kind { return a.kind }
|
||||
func (a *stubArtifactF) Params(ctx *pkg.IContext) { ctx.Write(a.params) }
|
||||
func (a *stubArtifactF) Inputs() []pkg.Artifact { return a.deps }
|
||||
func (a *stubArtifactF) Cure(f *pkg.FContext) error { return a.cure(f) }
|
||||
func (a *stubArtifactF) IsExclusive() bool { return a.excl }
|
||||
|
||||
// A stubFile implements [FileArtifact] with hardcoded behaviour.
|
||||
type stubFile struct {
|
||||
@@ -339,7 +339,7 @@ func TestIdent(t *testing.T) {
|
||||
var cache *pkg.Cache
|
||||
if a, err := check.NewAbs(t.TempDir()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cache, err = pkg.Open(t.Context(), msg, 0, 0, 0, a); err != nil {
|
||||
} else if cache, err = pkg.Open(t.Context(), msg, a, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(cache.Close)
|
||||
@@ -519,7 +519,10 @@ func checkWithCache(t *testing.T, testCases []cacheTestCase) {
|
||||
}
|
||||
|
||||
var scrubFunc func() error // scrub after hashing
|
||||
if c, err := pkg.Open(t.Context(), msg, flags, 1<<4, 0, base); err != nil {
|
||||
if c, err := pkg.Open(t.Context(), msg, base, &pkg.CacheAttr{
|
||||
Cures: 1 << 4,
|
||||
Flags: flags,
|
||||
}); err != nil {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
} else {
|
||||
t.Cleanup(c.Close)
|
||||
@@ -627,6 +630,7 @@ type cureStep struct {
|
||||
|
||||
pathname *check.Absolute
|
||||
output expectsKnown
|
||||
whence int
|
||||
err error
|
||||
}
|
||||
|
||||
@@ -646,7 +650,7 @@ func cureMany(t *testing.T, c *pkg.Cache, steps []cureStep) {
|
||||
|
||||
for _, step := range steps {
|
||||
t.Log("cure step:", step.name)
|
||||
if pathname, checksum, err := c.Cure(step.a); !reflect.DeepEqual(err, step.err) {
|
||||
if pathname, checksum, whence, err := c.CureWhence(step.a); !reflect.DeepEqual(err, step.err) {
|
||||
faults, _err := c.ReadFaults(step.a)
|
||||
if _err != nil {
|
||||
t.Errorf("ReadFaults: error = %v", _err)
|
||||
@@ -663,6 +667,8 @@ func cureMany(t *testing.T, c *pkg.Cache, steps []cureStep) {
|
||||
t.Logf("faulting cure terminated %s ago", time.Since(faults[0].Time()))
|
||||
}
|
||||
t.Fatalf("Cure: error = %v, want %v", err, step.err)
|
||||
} else if step.whence != whence {
|
||||
t.Fatalf("Cure: whence = %s, want %s", pkg.WhenceString(whence), pkg.WhenceString(step.whence))
|
||||
} else if step.pathname != ignorePathname && !pathname.Is(step.pathname) {
|
||||
t.Fatalf("Cure: pathname = %q, want %q", pathname, step.pathname)
|
||||
} else if step.output == nil || checksum != makeChecksumH(step.output.hash()) {
|
||||
@@ -774,28 +780,28 @@ func TestCache(t *testing.T) {
|
||||
identifier,
|
||||
new(testdata.hash()),
|
||||
testdata, nil,
|
||||
), wantPathname, testdata, nil},
|
||||
), wantPathname, testdata, pkg.WNew, nil},
|
||||
|
||||
{"identical content", newStubFile(
|
||||
pkg.KindHTTPGet,
|
||||
identifier0,
|
||||
new(testdata.hash()),
|
||||
testdata, nil,
|
||||
), wantPathname0, testdata, nil},
|
||||
), wantPathname0, testdata, pkg.WCache, nil},
|
||||
|
||||
{"existing entry", newStubFile(
|
||||
pkg.KindHTTPGet,
|
||||
identifier,
|
||||
new(testdata.hash()),
|
||||
testdata, nil,
|
||||
), wantPathname, testdata, nil},
|
||||
), wantPathname, testdata, pkg.WCache, nil},
|
||||
|
||||
{"checksum mismatch", newStubFile(
|
||||
pkg.KindHTTPGet,
|
||||
pkg.ID{0xff, 0},
|
||||
new(pkg.Checksum),
|
||||
testdata, nil,
|
||||
), nil, nil, &pkg.ChecksumMismatchError{
|
||||
), nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
|
||||
Got: testdata.hash(),
|
||||
}},
|
||||
|
||||
@@ -816,12 +822,12 @@ func TestCache(t *testing.T) {
|
||||
0x36, 0x65, 0x59, 0x33, 0xec, 0x2b,
|
||||
0x41, 0x34, 0x65, 0x96, 0x68, 0x17,
|
||||
0xa9, 0xc2, 0x08, 0xa1, 0x17, 0x17,
|
||||
}, nil},
|
||||
}, pkg.WNew, nil},
|
||||
|
||||
{"incomplete implementation", struct{ pkg.Artifact }{&stubArtifact{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("artifact overridden to be incomplete"),
|
||||
}}, nil, nil, pkg.InvalidArtifactError(pkg.MustDecode(
|
||||
}}, nil, nil, pkg.WNew, pkg.InvalidArtifactError(pkg.MustDecode(
|
||||
"E__uZ1sLIvb84vzSm5Uezb03RogsiaeTt1nfIVv8TKnnf4LqwtSi-smdHhlkZrUJ",
|
||||
))},
|
||||
|
||||
@@ -830,18 +836,18 @@ func TestCache(t *testing.T) {
|
||||
pkg.ID{0xff, 1},
|
||||
nil,
|
||||
nil, stub.UniqueError(0xcafe),
|
||||
), nil, nil, stub.UniqueError(0xcafe)},
|
||||
), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
|
||||
|
||||
{"error caching", newStubFile(
|
||||
pkg.KindHTTPGet,
|
||||
pkg.ID{0xff, 1},
|
||||
nil,
|
||||
nil, nil,
|
||||
), nil, nil, stub.UniqueError(0xcafe)},
|
||||
), nil, nil, pkg.WCache, stub.UniqueError(0xcafe)},
|
||||
|
||||
{"cache hit bad type", overrideChecksum{testdata.hash(), overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
}}}, nil, nil, pkg.InvalidFileModeError(
|
||||
}}}, nil, nil, pkg.WCache, pkg.InvalidFileModeError(
|
||||
0400,
|
||||
)},
|
||||
|
||||
@@ -853,7 +859,7 @@ func TestCache(t *testing.T) {
|
||||
cure: func(f *pkg.FContext) error {
|
||||
panic("attempting to cure impossible artifact")
|
||||
},
|
||||
}, nil, nil, &pkg.DependencyCureError{
|
||||
}, nil, nil, pkg.WNew, &pkg.DependencyCureError{
|
||||
{
|
||||
A: failingFile,
|
||||
Err: struct {
|
||||
@@ -864,10 +870,10 @@ func TestCache(t *testing.T) {
|
||||
}},
|
||||
})
|
||||
|
||||
if c0, err := unsafeOpen(
|
||||
if c0, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, base, false,
|
||||
base, &skipLock,
|
||||
); err != nil {
|
||||
t.Fatalf("open: error = %v", err)
|
||||
} else {
|
||||
@@ -875,7 +881,7 @@ func TestCache(t *testing.T) {
|
||||
cureMany(t, c0, []cureStep{
|
||||
{"cache hit ident", overrideIdent{
|
||||
id: identifier,
|
||||
}, wantPathname, testdata, nil},
|
||||
}, wantPathname, testdata, pkg.WCache, nil},
|
||||
|
||||
{"cache miss checksum match", newStubFile(
|
||||
pkg.KindHTTPGet,
|
||||
@@ -886,7 +892,7 @@ func TestCache(t *testing.T) {
|
||||
), base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(testdata.hash()),
|
||||
), testdata, nil},
|
||||
), testdata, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
// cure after close
|
||||
@@ -1016,30 +1022,30 @@ func TestCache(t *testing.T) {
|
||||
{"initial directory", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: makeSample,
|
||||
}}}, wantPathname, want, nil},
|
||||
}}}, wantPathname, want, pkg.WNew, nil},
|
||||
|
||||
{"identical identifier", overrideChecksum{want.hash(), overrideIdent{id, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
}}}, wantPathname, want, nil},
|
||||
}}}, wantPathname, want, pkg.WCache, nil},
|
||||
|
||||
{"identical checksum", overrideIdent{id0, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: makeSample,
|
||||
}}, wantPathname0, want, nil},
|
||||
}}, wantPathname0, want, pkg.WNew, nil},
|
||||
|
||||
{"cure fault", overrideIdent{pkg.ID{0xff, 0}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return makeGarbage(t.GetWorkDir(), stub.UniqueError(0xcafe))
|
||||
},
|
||||
}}, nil, nil, stub.UniqueError(0xcafe)},
|
||||
}}, nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
|
||||
|
||||
{"checksum mismatch", overrideChecksum{pkg.Checksum{}, overrideIdent{pkg.ID{0xff, 1}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return makeGarbage(t.GetWorkDir(), nil)
|
||||
},
|
||||
}}}, nil, nil, &pkg.ChecksumMismatchError{
|
||||
}}}, nil, nil, pkg.WNew, &pkg.ChecksumMismatchError{
|
||||
Got: pkg.MustDecode(
|
||||
"CUx-3hSbTWPsbMfDhgalG4Ni_GmR9TnVX8F99tY_P5GtkYvczg9RrF5zO0jX9XYT",
|
||||
),
|
||||
@@ -1050,7 +1056,7 @@ func TestCache(t *testing.T) {
|
||||
pkg.ID{0xff, 2},
|
||||
new(want.hash()),
|
||||
testdata, nil,
|
||||
), nil, nil, pkg.InvalidFileModeError(
|
||||
), nil, nil, pkg.WCache, pkg.InvalidFileModeError(
|
||||
fs.ModeDir | 0500,
|
||||
)},
|
||||
|
||||
@@ -1064,7 +1070,7 @@ func TestCache(t *testing.T) {
|
||||
_, err = io.ReadAll(r)
|
||||
return err
|
||||
},
|
||||
}}, nil, nil, &os.PathError{
|
||||
}}, nil, nil, pkg.WNew, &os.PathError{
|
||||
Op: "read",
|
||||
Path: base.Append(
|
||||
"checksum",
|
||||
@@ -1078,14 +1084,14 @@ func TestCache(t *testing.T) {
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return nil
|
||||
},
|
||||
}}, nil, nil, pkg.NoOutputError{}},
|
||||
}}, nil, nil, pkg.WNew, pkg.NoOutputError{}},
|
||||
|
||||
{"file output", overrideIdent{pkg.ID{0xff, 5}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return os.WriteFile(t.GetWorkDir().String(), []byte{0}, 0400)
|
||||
},
|
||||
}}, nil, nil, errors.New("non-file artifact produced regular file")},
|
||||
}}, nil, nil, pkg.WNew, errors.New("non-file artifact produced regular file")},
|
||||
|
||||
{"symlink output", overrideIdent{pkg.ID{0xff, 6}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
@@ -1095,7 +1101,7 @@ func TestCache(t *testing.T) {
|
||||
t.GetWorkDir().String(),
|
||||
)
|
||||
},
|
||||
}}, nil, nil, pkg.InvalidFileModeError(
|
||||
}}, nil, nil, pkg.WNew, pkg.InvalidFileModeError(
|
||||
fs.ModeSymlink | 0777,
|
||||
)},
|
||||
|
||||
@@ -1116,7 +1122,7 @@ func TestCache(t *testing.T) {
|
||||
}, base.Append(
|
||||
"identifier",
|
||||
"xMDWovje7OfyIaDy_2VnjpKxRqSOQ_LoeD946t-3WsS2V2SeMJ7nDGrNfpa4Pbc-",
|
||||
), want, nil},
|
||||
), want, pkg.WNew, nil},
|
||||
|
||||
{"substitutable", &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
@@ -1135,13 +1141,13 @@ func TestCache(t *testing.T) {
|
||||
}, base.Append(
|
||||
"identifier",
|
||||
"k2ilgG5KQ9NXnMoT2oB6NdwOnSPRn_H24oXQc4l6qOYIxIG9XfuEczeyrR8UEv_f",
|
||||
), want, nil},
|
||||
), want, pkg.WSubstitute, nil},
|
||||
})
|
||||
|
||||
if c0, err := unsafeOpen(
|
||||
if c0, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, base, false,
|
||||
base, &skipLock,
|
||||
); err != nil {
|
||||
t.Fatalf("open: error = %v", err)
|
||||
} else {
|
||||
@@ -1164,7 +1170,7 @@ func TestCache(t *testing.T) {
|
||||
}, base.Append(
|
||||
"identifier",
|
||||
"_EmV5nsYZ2UWHgRmLDMU8i-rJWDx-kv5_1pFrzQI7vMMCM5mAXivO8UZtVfOqMR_",
|
||||
), want, nil},
|
||||
), want, pkg.WSubstitute, nil},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1235,7 +1241,7 @@ func TestCache(t *testing.T) {
|
||||
pkg.ID{0xff, 1},
|
||||
nil,
|
||||
nil, stub.UniqueError(0xbad),
|
||||
), nil, nil, stub.UniqueError(0xbad)},
|
||||
), nil, nil, pkg.WNew, stub.UniqueError(0xbad)},
|
||||
|
||||
{"file output", overrideIdent{pkg.ID{0xff, 2}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
@@ -1246,7 +1252,7 @@ func TestCache(t *testing.T) {
|
||||
0400,
|
||||
)
|
||||
},
|
||||
}}, nil, nil, errors.New(
|
||||
}}, nil, nil, pkg.WNew, errors.New(
|
||||
"non-file artifact produced regular file",
|
||||
)},
|
||||
})
|
||||
@@ -1363,14 +1369,14 @@ func TestCache(t *testing.T) {
|
||||
}}}, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(pkg.ID{0xff, 0}),
|
||||
), want, nil},
|
||||
), want, pkg.WNew, nil},
|
||||
|
||||
{"reject", overrideChecksum{want.hash(), overrideIdent{pkg.ID{0xfe, 1}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return makeGarbage(t.GetWorkDir(), stub.UniqueError(0xbad))
|
||||
},
|
||||
}}}, nil, nil, stub.UniqueError(0xbad)},
|
||||
}}}, nil, nil, pkg.WNew, stub.UniqueError(0xbad)},
|
||||
|
||||
{"match", overrideChecksum{want.hash(), overrideIdent{pkg.ID{0xff, 1}, &stubArtifact{
|
||||
kind: pkg.KindTar,
|
||||
@@ -1380,7 +1386,7 @@ func TestCache(t *testing.T) {
|
||||
}}}, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(pkg.ID{0xff, 1}),
|
||||
), want, nil},
|
||||
), want, pkg.WNew, nil},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
@@ -1408,7 +1414,7 @@ func TestCache(t *testing.T) {
|
||||
), base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(pkg.Checksum{0xfe, 0}),
|
||||
), expectsChecksum{0xff, 0}, nil},
|
||||
), expectsChecksum{0xff, 0}, pkg.WNew, nil},
|
||||
})
|
||||
|
||||
for _, p := range [][]string{
|
||||
@@ -1485,7 +1491,7 @@ func TestCache(t *testing.T) {
|
||||
), expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0500},
|
||||
"result": {Mode: 0444},
|
||||
}, nil},
|
||||
}, pkg.WNew, nil},
|
||||
|
||||
{"substituted", substituted, base.Append(
|
||||
"identifier",
|
||||
@@ -1493,7 +1499,7 @@ func TestCache(t *testing.T) {
|
||||
), expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0500},
|
||||
"result": {Mode: 0444},
|
||||
}, nil},
|
||||
}, pkg.WSubstitute, nil},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
@@ -1586,14 +1592,14 @@ func TestCache(t *testing.T) {
|
||||
{"extern", a, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(wantIdent.Value()),
|
||||
), wantOutput, nil},
|
||||
), wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"substitute", _a, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(_wantIdent.Value()),
|
||||
), _wantOutput, nil},
|
||||
), _wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"mismatch", kca, nil, nil, &pkg.ChecksumMismatchError{
|
||||
{"mismatch", kca, nil, nil, pkg.WExternal, &pkg.ChecksumMismatchError{
|
||||
Got: wantChecksum,
|
||||
}},
|
||||
})
|
||||
@@ -1621,6 +1627,152 @@ func TestCache(t *testing.T) {
|
||||
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
}},
|
||||
|
||||
{"extern shallow", pkg.CExternShallow, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||
a := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("extern"),
|
||||
}
|
||||
wantIdent := c.Ident(a)
|
||||
wantOutput := expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0500},
|
||||
"result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")},
|
||||
}
|
||||
var wantChecksum pkg.Checksum
|
||||
if err := pkg.SumFS(
|
||||
&wantChecksum,
|
||||
fstest.MapFS(wantOutput),
|
||||
".",
|
||||
); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantChecksumH := unique.Make(wantChecksum)
|
||||
|
||||
_a := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("extern substitute"),
|
||||
deps: []pkg.Artifact{pkg.NewFile("", nil)},
|
||||
}
|
||||
_wantIdent := c.Ident(_a)
|
||||
_wantOutput := expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0500},
|
||||
}
|
||||
var _wantChecksum pkg.Checksum
|
||||
if err := pkg.SumFS(
|
||||
&_wantChecksum,
|
||||
fstest.MapFS(_wantOutput),
|
||||
".",
|
||||
); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_wantChecksumH := unique.Make(_wantChecksum)
|
||||
|
||||
kca := pkg.NewExec(
|
||||
"", "",
|
||||
new(pkg.Checksum), 0, false, false,
|
||||
fhs.AbsRoot, nil, fhs.AbsRoot, nil,
|
||||
)
|
||||
kcIdent := c.Ident(kca)
|
||||
|
||||
fia := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("flood input"),
|
||||
deps: []pkg.Artifact{_a},
|
||||
}
|
||||
fiaIdent := c.Ident(fia)
|
||||
|
||||
flia := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("flood input local"),
|
||||
deps: []pkg.Artifact{_a},
|
||||
}
|
||||
fliaIdent := c.Ident(flia)
|
||||
|
||||
h := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("hanging input"),
|
||||
}
|
||||
|
||||
fhia := &stubArtifactF{
|
||||
kind: pkg.KindExec,
|
||||
params: []byte("flood input local"),
|
||||
deps: []pkg.Artifact{h},
|
||||
}
|
||||
fhiaIdent := c.Ident(fhia)
|
||||
|
||||
c.SetExternal(stubExtern{
|
||||
artifact: map[unique.Handle[pkg.ID]]pkg.Checksum{
|
||||
wantIdent: wantChecksum,
|
||||
_wantIdent: _wantChecksum,
|
||||
kcIdent: wantChecksum,
|
||||
fiaIdent: wantChecksum,
|
||||
fliaIdent: wantChecksum,
|
||||
fhiaIdent: wantChecksum,
|
||||
},
|
||||
checksum: map[unique.Handle[pkg.Checksum]]fstest.MapFS{
|
||||
wantChecksumH: fstest.MapFS(wantOutput),
|
||||
_wantChecksumH: fstest.MapFS(_wantOutput),
|
||||
},
|
||||
status: map[unique.Handle[pkg.ID]]string{
|
||||
wantIdent: "\x00",
|
||||
kcIdent: "unreachable",
|
||||
},
|
||||
})
|
||||
|
||||
cureMany(t, c, []cureStep{
|
||||
{"extern", a, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(wantIdent.Value()),
|
||||
), wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"flood shallow extern", fia, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(fiaIdent.Value()),
|
||||
), wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"substitute", _a, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(_wantIdent.Value()),
|
||||
), _wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"flood shallow local", flia, base.Append(
|
||||
"identifier",
|
||||
pkg.Encode(fliaIdent.Value()),
|
||||
), wantOutput, pkg.WExternal, nil},
|
||||
|
||||
{"flood shallow hanging", fhia, nil, nil,
|
||||
pkg.WNew, pkg.HangingInputError(c.Ident(h))},
|
||||
|
||||
{"mismatch", kca, nil, nil, pkg.WExternal, &pkg.ChecksumMismatchError{
|
||||
Got: wantChecksum,
|
||||
}},
|
||||
})
|
||||
}, expectsFS{
|
||||
".": {Mode: fs.ModeDir | 0700},
|
||||
|
||||
"checksum": {Mode: fs.ModeDir | 0700},
|
||||
"checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500},
|
||||
"checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl": {Mode: fs.ModeDir | 0500},
|
||||
"checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl/result": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent")},
|
||||
|
||||
"identifier": {Mode: fs.ModeDir | 0700},
|
||||
"identifier/4HqRo4uTwRQjfy3d2cujMoDC_pC4iv20h4a7NYlx0UdbVuky18o5iK78TFEfPX2U": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/7AZcJm58ghFyTVf_v2baSntgpsxkP5el7ti9dC77C29n8YTEqQW9jRW92KGNdYnz": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"identifier/RJbTOOIlqsEkAxGlTIsbp4mHPO0Q2IlwU7Gh_FIaTxnhgxUjAQPXXgPyP2GJWX2A": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"identifier/c4aCI00C-ZVyo_FQDQLl1OYK4U_kjzxwrLdFDiXMHnbMcZXCkXo_nxUWauScZ_4V": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"identifier/gvCqzexZVqXjF8B5lKMcP5onmq3jJ6AKqzOW_WN0Fl2yTr9NKhPt9l_ClD2EOSlS": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"identifier/lqjQtzpJ6asInpsdxqNYVjTkRHK-gW0eUCqNCCk1KhZTuKwKAc5Z0H7tS-GWfRlg": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
|
||||
"status": {Mode: fs.ModeDir | 0700},
|
||||
"status/gvCqzexZVqXjF8B5lKMcP5onmq3jJ6AKqzOW_WN0Fl2yTr9NKhPt9l_ClD2EOSlS": {Mode: 0400, Data: []byte("\x00")},
|
||||
|
||||
"substitute": {Mode: fs.ModeDir | 0700},
|
||||
"substitute/qOYrxy9ztKeOA96Os811_0Ox5sd8FBOxis6psJAnRJL5MLazFMaqmd4g7t7k1OHk": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")},
|
||||
"substitute/vLTXKbImP9XTTSi7P3PIuqy5L5UgX4dFQm2traX4X_pCDvg9GDraX1LmaUpgLu4w": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
"substitute/yn1xEs5uSnu5EFLtkvjFSQ0C_fv50hU_w2wfDH_WBEzQhUiPJfyS3Eegy6YSclYN": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/fHkl_RuHOoc4rso__nV-qreikovd6Yhrq5mpBlkf5hmPGaxDlik2bYOQ4dhUQjtl")},
|
||||
|
||||
"work": {Mode: fs.ModeDir | 0700},
|
||||
}},
|
||||
}
|
||||
checkWithCache(t, testCases)
|
||||
}
|
||||
@@ -1635,7 +1787,7 @@ func TestErrors(t *testing.T) {
|
||||
}{
|
||||
{"InvalidLookupError", pkg.InvalidLookupError{
|
||||
0xff, 0xf0,
|
||||
}, "attempting to look up non-dependency artifact __AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},
|
||||
}, "attempting to look up non-input artifact __AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},
|
||||
|
||||
{"InvalidArtifactError", pkg.InvalidArtifactError{
|
||||
0xff, 0xfd,
|
||||
@@ -1883,7 +2035,7 @@ func (earlyFailureF) Kind() pkg.Kind { return pkg.KindExec }
|
||||
func (earlyFailureF) Params(*pkg.IContext) {}
|
||||
func (earlyFailureF) IsExclusive() bool { return false }
|
||||
|
||||
func (a earlyFailureF) Dependencies() []pkg.Artifact {
|
||||
func (a earlyFailureF) Inputs() []pkg.Artifact {
|
||||
deps := make([]pkg.Artifact, a)
|
||||
for i := range deps {
|
||||
deps[i] = a - 1
|
||||
@@ -1901,7 +2053,7 @@ func (a earlyFailureF) Cure(*pkg.FContext) error {
|
||||
func BenchmarkEarlyDCE(b *testing.B) {
|
||||
msg := message.New(log.New(os.Stderr, "dce: ", 0))
|
||||
msg.SwapVerbose(testing.Verbose())
|
||||
c, err := pkg.Open(b.Context(), msg, 0, 0, 0, check.MustAbs(b.TempDir()))
|
||||
c, err := pkg.Open(b.Context(), msg, check.MustAbs(b.TempDir()), nil)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -1950,7 +2102,8 @@ func TestOpen(t *testing.T) {
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, check.MustAbs(container.Nonexistent),
|
||||
check.MustAbs(container.Nonexistent),
|
||||
nil,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
|
||||
}
|
||||
@@ -1978,7 +2131,8 @@ func TestOpen(t *testing.T) {
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, tempDir.Append("cache"),
|
||||
tempDir.Append("cache"),
|
||||
nil,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
|
||||
}
|
||||
@@ -2000,7 +2154,8 @@ func TestOpen(t *testing.T) {
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, tempDir.Append("cache"),
|
||||
tempDir.Append("cache"),
|
||||
nil,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
|
||||
}
|
||||
@@ -2021,7 +2176,7 @@ func TestOpen(t *testing.T) {
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(nil),
|
||||
0, 0, 0, tempDir.Append("cache"),
|
||||
tempDir.Append("cache"), nil,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Errorf("Open: error = %#v, want %#v", err, wantErr)
|
||||
}
|
||||
@@ -2074,8 +2229,8 @@ func TestExtensionRegister(t *testing.T) {
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(log.Default()),
|
||||
0, 0, 0,
|
||||
check.MustAbs(container.Nonexistent),
|
||||
nil,
|
||||
); !errors.Is(err, os.ErrNotExist) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
@@ -2113,7 +2268,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
pkg.Register(pkg.KindCustomOffset, nil)
|
||||
|
||||
t.Cleanup(func() { opened = false })
|
||||
_, _ = pkg.Open(nil, nil, 0, 0, 0, nil)
|
||||
_, _ = pkg.Open(nil, nil, nil, nil)
|
||||
panic("unreachable")
|
||||
})
|
||||
|
||||
@@ -2124,11 +2279,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
|
||||
base := check.MustAbs(t.TempDir())
|
||||
t.Cleanup(func() { opened = false })
|
||||
if c, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
); err != nil {
|
||||
if c, err := pkg.Open(t.Context(), nil, base, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
c.Close()
|
||||
@@ -2156,8 +2307,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
}
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
base, nil,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Fatalf("Open: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
@@ -2178,8 +2328,8 @@ func TestExtensionRegister(t *testing.T) {
|
||||
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
nil,
|
||||
); !reflect.DeepEqual(err, pkg.ErrWouldPromote) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
@@ -2192,8 +2342,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
|
||||
if c, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
pkg.CPromoteVariant, 0, 0,
|
||||
base,
|
||||
base, &pkg.CacheAttr{Flags: pkg.CPromoteVariant},
|
||||
); err != nil {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
} else {
|
||||
@@ -2218,8 +2367,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
base, nil,
|
||||
); !reflect.DeepEqual(err, pkg.ErrInvalidExtension) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
@@ -2236,8 +2384,7 @@ func TestExtensionRegister(t *testing.T) {
|
||||
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
base, nil,
|
||||
); !reflect.DeepEqual(err, pkg.UnsupportedVariantError("rosa")) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
|
||||
+8
-2
@@ -16,6 +16,8 @@ type tarArtifact struct {
|
||||
f Artifact
|
||||
}
|
||||
|
||||
var _ CuresExempt = new(tarArtifact)
|
||||
|
||||
// tarArtifactNamed embeds tarArtifact for a [fmt.Stringer] tarball.
|
||||
type tarArtifactNamed struct {
|
||||
tarArtifact
|
||||
@@ -56,8 +58,8 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a slice containing the backing file.
|
||||
func (a *tarArtifact) Dependencies() []Artifact {
|
||||
// Inputs returns a slice containing the backing file.
|
||||
func (a *tarArtifact) Inputs() []Artifact {
|
||||
return []Artifact{a.f}
|
||||
}
|
||||
|
||||
@@ -211,3 +213,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CuresExempt exempts the cheap [KindTar] implementation often at the end of a
|
||||
// [FileArtifact] pipeline.
|
||||
func (*tarArtifact) CuresExempt() {}
|
||||
|
||||
@@ -212,24 +212,24 @@ func checkTarHTTP(
|
||||
&client,
|
||||
"file:///testdata",
|
||||
testdataChecksum,
|
||||
), pkg.Gzip)), ignorePathname, want, nil},
|
||||
), pkg.Gzip)), ignorePathname, want, pkg.WNew, nil},
|
||||
|
||||
{"directory", pkg.NewTar(pkg.NewDecompress(
|
||||
&tarDir,
|
||||
pkg.Gzip,
|
||||
)), ignorePathname, want, nil},
|
||||
)), ignorePathname, want, pkg.WNew, nil},
|
||||
|
||||
{"multiple entries", pkg.NewTar(pkg.NewDecompress(
|
||||
&tarDirMulti,
|
||||
pkg.Gzip,
|
||||
)), nil, nil, errors.New(
|
||||
)), nil, nil, pkg.WNew, errors.New(
|
||||
"input directory does not contain a single regular file",
|
||||
)},
|
||||
|
||||
{"bad type", pkg.NewTar(pkg.NewDecompress(
|
||||
&tarDirType,
|
||||
pkg.Gzip,
|
||||
)), nil, nil, errors.New(
|
||||
)), nil, nil, pkg.WNew, errors.New(
|
||||
"input directory does not contain a single regular file",
|
||||
)},
|
||||
|
||||
@@ -239,6 +239,6 @@ func checkTarHTTP(
|
||||
cure: func(t *pkg.TContext) error {
|
||||
return stub.UniqueError(0xcafe)
|
||||
},
|
||||
}), nil, nil, stub.UniqueError(0xcafe)},
|
||||
}), nil, nil, pkg.WNew, stub.UniqueError(0xcafe)},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -18,6 +18,11 @@ const (
|
||||
jobsLE = `"$(expr ` + jobsE + ` '*' 2)"`
|
||||
// jobsLFlagE is expression for flag with double of preferred job count.
|
||||
jobsLFlagE = `"-j$(expr ` + jobsE + ` '*' 2)"`
|
||||
|
||||
// loadE is expression for preferred loadavg target set by [pkg].
|
||||
loadE = `"$` + pkg.EnvLoad + `"`
|
||||
// loadFlagE is expression for flag with preferred loadavg target.
|
||||
loadFlagE = `"-l$` + pkg.EnvLoad + `"`
|
||||
)
|
||||
|
||||
// newTar wraps [pkg.NewHTTPGetTar] with a simpler function signature.
|
||||
|
||||
@@ -26,8 +26,8 @@ func (a busyboxBin) Params(*pkg.IContext) {}
|
||||
// IsExclusive returns false: Cure performs a trivial filesystem write.
|
||||
func (busyboxBin) IsExclusive() bool { return false }
|
||||
|
||||
// Dependencies returns the underlying busybox [pkg.FileArtifact].
|
||||
func (a busyboxBin) Dependencies() []pkg.Artifact {
|
||||
// Inputs returns the underlying busybox [pkg.FileArtifact].
|
||||
func (a busyboxBin) Inputs() []pkg.Artifact {
|
||||
return []pkg.Artifact{a.bin}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,10 +61,10 @@ func (attr *CMakeHelper) script(t Toolchain, name string) string {
|
||||
}
|
||||
|
||||
generate := "Ninja"
|
||||
test := "ninja " + jobsFlagE + " test"
|
||||
test := "ninja " + jobsFlagE + " " + loadFlagE + " test"
|
||||
if attr.Make {
|
||||
generate = "'Unix Makefiles'"
|
||||
test = "make " + jobsFlagE + " test"
|
||||
test = "make " + jobsFlagE + " " + loadFlagE + " test"
|
||||
}
|
||||
if attr.Test != "" {
|
||||
test = attr.Test
|
||||
@@ -97,7 +97,7 @@ cmake -G ` + generate + ` \
|
||||
}), " \\\n\t") + ` \
|
||||
-DCMAKE_INSTALL_PREFIX=/system \
|
||||
'/usr/src/` + name + `/` + filepath.Join(attr.Append...) + `'
|
||||
cmake --build . --parallel=` + jobsE + `
|
||||
cmake --build . --parallel=` + jobsE + ` -- ` + loadFlagE + `
|
||||
DESTDIR=/work cmake --install .
|
||||
` + script
|
||||
}
|
||||
|
||||
@@ -118,8 +118,8 @@ func init() {
|
||||
// IsExclusive returns false: Cure performs a few trivial filesystem writes.
|
||||
func (cureEtc) IsExclusive() bool { return false }
|
||||
|
||||
// Dependencies returns a slice containing the backing iana-etc release.
|
||||
func (a cureEtc) Dependencies() []pkg.Artifact {
|
||||
// Inputs returns a slice containing the backing iana-etc release.
|
||||
func (a cureEtc) Inputs() []pkg.Artifact {
|
||||
if !a.minimal {
|
||||
return []pkg.Artifact{ianaEtc}
|
||||
}
|
||||
|
||||
+8
-10
@@ -341,6 +341,13 @@ ln -s \
|
||||
|
||||
return &meta, t.NewPackage("llvm", meta.Version, source, &PackageAttr{
|
||||
Flag: TExclusive,
|
||||
Bin: []string{
|
||||
"chmod",
|
||||
"mkdir",
|
||||
"rm",
|
||||
"tr",
|
||||
"awk",
|
||||
},
|
||||
}, &CMakeHelper{
|
||||
Append: []string{"llvm"},
|
||||
|
||||
@@ -358,16 +365,7 @@ ln -s clang++ /work/system/bin/c++
|
||||
// on 3-stage determinism to test later stages.
|
||||
SkipTest: t.stage.isStage0(),
|
||||
|
||||
Test: `
|
||||
chmod +w /bin && ln -s \
|
||||
../system/bin/chmod \
|
||||
../system/bin/mkdir \
|
||||
../system/bin/rm \
|
||||
../system/bin/tr \
|
||||
../system/bin/awk \
|
||||
/bin
|
||||
ninja ` + jobsFlagE + ` check-all
|
||||
`,
|
||||
Test: "ninja " + jobsFlagE + " " + loadFlagE + " check-all",
|
||||
},
|
||||
_python,
|
||||
_perl,
|
||||
|
||||
@@ -89,7 +89,7 @@ func (attr *MakeHelper) wantsDir() (string, bool) {
|
||||
if attr != nil && attr.InPlace {
|
||||
return helperInPlace, false
|
||||
}
|
||||
return `"$(mktemp -d)"`, false
|
||||
return "/cure/", true
|
||||
}
|
||||
|
||||
// script generates the cure script.
|
||||
@@ -160,7 +160,8 @@ func (attr *MakeHelper) script(t Toolchain, name string) string {
|
||||
|
||||
scriptMake := `
|
||||
make \
|
||||
` + jobsFlagE
|
||||
` + jobsFlagE + ` \
|
||||
` + loadFlagE
|
||||
if len(attr.Make) > 0 {
|
||||
scriptMake += " \\\n\t" + strings.Join(attr.Make, " \\\n\t")
|
||||
}
|
||||
@@ -170,6 +171,7 @@ make \
|
||||
(!attr.SkipCheckEarly || !t.stage.isStage0()) {
|
||||
scriptMake += attr.ScriptCheckEarly + `make \
|
||||
` + jobsFlagE + ` \
|
||||
` + loadFlagE + ` \
|
||||
`
|
||||
if len(attr.Check) > 0 {
|
||||
scriptMake += strings.Join(attr.Check, " \\\n\t")
|
||||
|
||||
@@ -18,6 +18,8 @@ type MesonHelper struct {
|
||||
|
||||
// Flags passed to the setup command.
|
||||
Setup []KV
|
||||
// Test suites to skip.
|
||||
SkipTests []string
|
||||
// Whether to skip meson test.
|
||||
SkipTest bool
|
||||
// Run tests with interactive input/output.
|
||||
@@ -56,11 +58,15 @@ func (attr *MesonHelper) script(t Toolchain, name string) string {
|
||||
if !attr.SkipTest && t.opts&OptSkipCheck == 0 {
|
||||
scriptTest = `
|
||||
meson test \
|
||||
-t 10 \
|
||||
--print-errorlogs`
|
||||
if attr.InteractiveTest {
|
||||
scriptTest += ` \
|
||||
--interactive`
|
||||
}
|
||||
for _, suite := range attr.SkipTests {
|
||||
scriptTest += " \\\n\t--no-suite='" + suite + "'"
|
||||
}
|
||||
}
|
||||
|
||||
return `
|
||||
|
||||
+256
-113
@@ -14,6 +14,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unique"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
@@ -30,8 +31,8 @@ type Remote struct {
|
||||
c *http.Client
|
||||
}
|
||||
|
||||
// NewRemote returns a populated [Remote]
|
||||
func NewRemote(base string, pub ed25519.PublicKey, c *http.Client) (Remote, error) {
|
||||
// NewRemote returns a populated [Remote].
|
||||
func NewRemote(c *http.Client, base string, pub ed25519.PublicKey) (Remote, error) {
|
||||
u, err := url.Parse(base)
|
||||
return Remote{u, pub, c}, err
|
||||
}
|
||||
@@ -201,14 +202,261 @@ func (r Remote) Status(
|
||||
), nil
|
||||
}
|
||||
|
||||
// NewMirror returns an [http.Handler] for servicing mirror requests.
|
||||
// Mirror services requests made by [Remote].
|
||||
type Mirror struct {
|
||||
// Cache on-filesystem format.
|
||||
fsys fs.FS
|
||||
// Signs payloads.
|
||||
key ed25519.PrivateKey
|
||||
// Verbose output.
|
||||
msg message.Msg
|
||||
}
|
||||
|
||||
// Populate fills an empty root with a static mirror snapshot.
|
||||
func (m Mirror) Populate(root *os.Root) error {
|
||||
if dents, err := fs.ReadDir(root.FS(), "."); err != nil {
|
||||
return err
|
||||
} else if len(dents) > 0 {
|
||||
return syscall.ENOTEMPTY
|
||||
}
|
||||
|
||||
for _, name := range []string{
|
||||
dirArtifact,
|
||||
dirOutcome,
|
||||
dirStatus,
|
||||
} {
|
||||
if err := root.Mkdir(name, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var w *os.File
|
||||
|
||||
if dents, err := fs.ReadDir(m.fsys, "identifier"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
for _, dent := range dents {
|
||||
name := dent.Name()
|
||||
var buf [2 * len(pkg.Checksum{})]byte
|
||||
if err = pkg.Decode(
|
||||
(*pkg.Checksum)(buf[:len(pkg.Checksum{})]),
|
||||
name,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if w, err = root.OpenFile(
|
||||
filepath.Join(dirArtifact, name),
|
||||
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
|
||||
0444,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.writeArtifact(&buf, w, nil)
|
||||
if err = errors.Join(err, w.Close()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if dents, err := fs.ReadDir(m.fsys, "checksum"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
for _, dent := range dents {
|
||||
name := dent.Name()
|
||||
var buf pkg.Checksum
|
||||
if err = pkg.Decode(&buf, name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var fsys fs.FS
|
||||
fsys, err = fs.Sub(m.fsys, filepath.Join("checksum", name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if w, err = root.OpenFile(
|
||||
filepath.Join(dirOutcome, name),
|
||||
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
|
||||
0444,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.msg.Verbosef("exporting outcome %s", name)
|
||||
err = pkg.Write(fsys, ".", w)
|
||||
if err = errors.Join(err, w.Close()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if dents, err := fs.ReadDir(m.fsys, "status"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
for _, dent := range dents {
|
||||
name := dent.Name()
|
||||
var buf [2 * len(pkg.Checksum{})]byte
|
||||
if err = pkg.Decode(
|
||||
(*pkg.Checksum)(buf[:len(pkg.Checksum{})]),
|
||||
name,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if w, err = root.OpenFile(
|
||||
filepath.Join(dirStatus, name),
|
||||
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL,
|
||||
0444,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
err = m.writeStatus(&buf, w, nil)
|
||||
if err = errors.Join(err, w.Close()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewMirror returns a populated [Mirror] for servicing mirror requests.
|
||||
func NewMirror(
|
||||
msg message.Msg,
|
||||
fsys fs.FS,
|
||||
key ed25519.PrivateKey,
|
||||
) http.Handler {
|
||||
) Mirror {
|
||||
return Mirror{fsys, key, msg}
|
||||
}
|
||||
|
||||
// writeArtifact writes a signed dirArtifact response.
|
||||
func (m Mirror) writeArtifact(
|
||||
buf *[2 * len(pkg.Checksum{})]byte,
|
||||
w io.Writer,
|
||||
header http.Header,
|
||||
) error {
|
||||
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
|
||||
if linkname, err := fs.ReadLink(m.fsys, filepath.Join(
|
||||
"identifier",
|
||||
ids,
|
||||
)); err != nil {
|
||||
return err
|
||||
} else if err = pkg.Decode(
|
||||
(*pkg.Checksum)(buf[len(pkg.Checksum{}):]),
|
||||
filepath.Base(linkname),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
m.msg.Verbosef("serving artifact %s", ids)
|
||||
|
||||
if header != nil {
|
||||
header.Set(
|
||||
"Content-Length",
|
||||
strconv.Itoa(ed25519.SignatureSize+len(buf)),
|
||||
)
|
||||
}
|
||||
_, err := w.Write(append(ed25519.Sign(m.key, buf[:]), buf[:]...))
|
||||
return err
|
||||
}
|
||||
|
||||
// writeOutcome writes a dirOutcome response.
|
||||
func (m Mirror) writeOutcome(
|
||||
buf *pkg.Checksum,
|
||||
w io.Writer,
|
||||
header http.Header,
|
||||
) error {
|
||||
checksums := pkg.Encode(*buf)
|
||||
rel := filepath.Join("checksum", checksums)
|
||||
if _, err := fs.Lstat(m.fsys, rel); err != nil {
|
||||
return err
|
||||
}
|
||||
m.msg.Verbosef("serving outcome %s", checksums)
|
||||
|
||||
_fsys, err := fs.Sub(m.fsys, rel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var gw *gzip.Writer
|
||||
if gw, err = gzip.NewWriterLevel(w, gzip.BestCompression); err != nil {
|
||||
return err
|
||||
}
|
||||
if header != nil {
|
||||
header.Set("Content-Encoding", "gzip")
|
||||
}
|
||||
if err = pkg.Write(_fsys, ".", gw); err != nil {
|
||||
_ = gw.Close()
|
||||
return err
|
||||
}
|
||||
return gw.Close()
|
||||
}
|
||||
|
||||
// writeStatus writes a signed dirStatus response.
|
||||
func (m Mirror) writeStatus(
|
||||
buf *[2 * len(pkg.Checksum{})]byte,
|
||||
w io.Writer,
|
||||
_ http.Header,
|
||||
) error {
|
||||
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
|
||||
f, err := m.fsys.Open(filepath.Join(
|
||||
"status",
|
||||
ids,
|
||||
))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s, ok := f.(io.Seeker)
|
||||
if !ok {
|
||||
return &fs.PathError{Op: "seek", Path: ids, Err: fs.ErrInvalid}
|
||||
}
|
||||
m.msg.Verbosef("serving status %s", ids)
|
||||
|
||||
h := sha512.New384()
|
||||
if _, err = io.Copy(h, f); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
}
|
||||
h.Sum(buf[len(pkg.Checksum{}):len(pkg.Checksum{})])
|
||||
if _, err = w.Write(append(ed25519.Sign(m.key, buf[:]), buf[:]...)); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
} else if _, err = s.Seek(0, io.SeekStart); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
} else if _, err = io.Copy(w, f); err != nil {
|
||||
_ = f.Close()
|
||||
return err
|
||||
}
|
||||
return f.Close()
|
||||
}
|
||||
|
||||
// writeF is a helper for writing a mirror response with error handling.
|
||||
func writeF[B any](
|
||||
m Mirror,
|
||||
w http.ResponseWriter,
|
||||
buf B,
|
||||
f func(
|
||||
buf B,
|
||||
w io.Writer,
|
||||
header http.Header,
|
||||
) error,
|
||||
) {
|
||||
err := f(buf, w, w.Header())
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
m.msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Register configures an [http.ServeMux] for servicing mirror requests.
|
||||
func (m Mirror) Register(mux *http.ServeMux) {
|
||||
const identName = "ident"
|
||||
var mux http.ServeMux
|
||||
|
||||
mux.HandleFunc("/"+dirArtifact+"/{"+identName+"}", func(
|
||||
w http.ResponseWriter,
|
||||
@@ -222,38 +470,7 @@ func NewMirror(
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
|
||||
if linkname, err := fs.ReadLink(fsys, filepath.Join(
|
||||
"identifier",
|
||||
ids,
|
||||
)); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
} else if err = pkg.Decode(
|
||||
(*pkg.Checksum)(buf[len(pkg.Checksum{}):]),
|
||||
filepath.Base(linkname),
|
||||
); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
msg.Verbosef("serving artifact %s", ids)
|
||||
|
||||
w.Header().Set(
|
||||
"Content-Length",
|
||||
strconv.Itoa(ed25519.SignatureSize+len(buf)),
|
||||
)
|
||||
if _, err := w.Write(append(
|
||||
ed25519.Sign(key, buf[:]),
|
||||
buf[:]...,
|
||||
)); err != nil {
|
||||
msg.Verbose(err)
|
||||
}
|
||||
writeF(m, w, &buf, m.writeArtifact)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/"+dirOutcome+"/{"+identName+"}", func(
|
||||
@@ -273,40 +490,7 @@ func NewMirror(
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
checksums := pkg.Encode(buf)
|
||||
rel := filepath.Join("checksum", checksums)
|
||||
if _, err := fs.Lstat(fsys, rel); err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
msg.Verbosef("serving outcome %s", pkg.Encode(buf))
|
||||
|
||||
_fsys, err := fs.Sub(fsys, rel)
|
||||
if err != nil {
|
||||
msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var gw *gzip.Writer
|
||||
if gw, err = gzip.NewWriterLevel(w, gzip.BestCompression); err != nil {
|
||||
msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
if err = pkg.Write(_fsys, ".", gw); err != nil {
|
||||
msg.Verbose(err)
|
||||
}
|
||||
if err = gw.Close(); err != nil {
|
||||
msg.GetLogger().Println(err)
|
||||
}
|
||||
writeF(m, w, &buf, m.writeOutcome)
|
||||
})
|
||||
|
||||
mux.HandleFunc("/"+dirStatus+"/{"+identName+"}", func(
|
||||
@@ -321,47 +505,6 @@ func NewMirror(
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ids := pkg.Encode((pkg.Checksum)(buf[:len(pkg.Checksum{})]))
|
||||
f, err := fsys.Open(filepath.Join(
|
||||
"status",
|
||||
ids,
|
||||
))
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
msg.GetLogger().Println(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
s, ok := f.(io.Seeker)
|
||||
if !ok {
|
||||
msg.GetLogger().Println("backing filesystem does not support seek")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
msg.Verbosef("serving status %s", ids)
|
||||
|
||||
h := sha512.New384()
|
||||
if _, err = io.Copy(h, f); err != nil {
|
||||
_ = f.Close()
|
||||
msg.Verbose(err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
h.Sum(buf[len(pkg.Checksum{}):len(pkg.Checksum{})])
|
||||
if _, err = w.Write(append(ed25519.Sign(key, buf[:]), buf[:]...)); err != nil {
|
||||
msg.Verbose(err)
|
||||
return
|
||||
} else if _, err = s.Seek(0, io.SeekStart); err != nil {
|
||||
msg.GetLogger().Println(err)
|
||||
return
|
||||
} else if _, err = io.Copy(w, f); err != nil {
|
||||
msg.Verbose(err)
|
||||
return
|
||||
}
|
||||
writeF(m, w, &buf, m.writeStatus)
|
||||
})
|
||||
|
||||
return &mux
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"crypto/ed25519"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
@@ -30,7 +31,7 @@ func TestMirror(t *testing.T) {
|
||||
msg.SwapVerbose(testing.Verbose())
|
||||
|
||||
var c *pkg.Cache
|
||||
c, err = pkg.Open(t.Context(), msg, 0, 0, 0, base)
|
||||
c, err = pkg.Open(t.Context(), msg, base, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -52,14 +53,16 @@ func TestMirror(t *testing.T) {
|
||||
}
|
||||
wantChecksums := pkg.Encode(wantChecksum)
|
||||
|
||||
server := httptest.NewServer(rosa.NewMirror(msg, fstest.MapFS{
|
||||
var mux http.ServeMux
|
||||
rosa.NewMirror(msg, fstest.MapFS{
|
||||
"identifier/" + ids: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantChecksums)},
|
||||
"checksum/" + wantChecksums: {Mode: os.ModeDir | 0500},
|
||||
}, priv))
|
||||
}, priv).Register(&mux)
|
||||
server := httptest.NewServer(&mux)
|
||||
t.Cleanup(server.Close)
|
||||
|
||||
var extern pkg.External
|
||||
extern, err = rosa.NewRemote("http://example.com:80", pub, server.Client())
|
||||
extern, err = rosa.NewRemote(server.Client(), "http://example.com:80", pub)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
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
|
||||
@@ -1,7 +1,7 @@
|
||||
diff --git a/test/attr.test b/test/attr.test
|
||||
index 6ce2f9b..e9bde92 100644
|
||||
--- a/test/attr.test
|
||||
+++ b/test/attr.test
|
||||
diff --git a/test/attr.run b/test/attr.run
|
||||
index 27d17f6..a4d60c0 100644
|
||||
--- a/test/attr.run
|
||||
+++ b/test/attr.run
|
||||
@@ -11,7 +11,7 @@ Try various valid and invalid names
|
||||
|
||||
$ touch f
|
||||
|
||||
@@ -3,25 +3,25 @@ package attr {
|
||||
website = "https://savannah.nongnu.org/projects/attr";
|
||||
anitya = 137;
|
||||
|
||||
version# = "2.5.2";
|
||||
version# = "2.6.0";
|
||||
source = remoteTar {
|
||||
url = "https://download.savannah.nongnu.org/releases/attr/"+
|
||||
"attr-"+version+".tar.gz";
|
||||
checksum = "YWEphrz6vg1sUMmHHVr1CRo53pFXRhq_pjN-AlG8UgwZK1y6m7zuDhxqJhD0SV0l";
|
||||
checksum = "pp-NvD1cMIwZycNwZGW2ez-PbTEpHxrRnVH27csj9QdN4oEBkEbJOZX1IIvKnTWS";
|
||||
compress = gzip;
|
||||
};
|
||||
patches = [
|
||||
"libgen-basename.patch",
|
||||
"musl-errno.patch",
|
||||
];
|
||||
|
||||
early = `
|
||||
ln -s ../../system/bin/perl /usr/bin
|
||||
`;
|
||||
patches = [ "musl-errno.patch" ];
|
||||
|
||||
bin = [ "perl" ];
|
||||
populateUsrBin = true;
|
||||
exec = make {};
|
||||
|
||||
inputs = [ perl ];
|
||||
inputs = [
|
||||
perl,
|
||||
|
||||
kernel-headers,
|
||||
];
|
||||
}
|
||||
|
||||
package acl {
|
||||
@@ -29,11 +29,11 @@ package acl {
|
||||
website = "https://savannah.nongnu.org/projects/acl";
|
||||
anitya = 16;
|
||||
|
||||
version# = "2.3.2";
|
||||
version# = "2.4.0";
|
||||
source = remoteTar {
|
||||
url = "https://download.savannah.nongnu.org/releases/acl/"+
|
||||
"acl-"+version+".tar.gz";
|
||||
checksum = "-fY5nwH4K8ZHBCRXrzLdguPkqjKI6WIiGu4dBtrZ1o0t6AIU73w8wwJz_UyjIS0P";
|
||||
checksum = "U2eaAsWrhhzEfhyprwHQQG55bFPZxtsHk1Usnd9Jb_g-H__pJod4H3RTrL4ipXDw";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
@@ -42,6 +42,6 @@ package acl {
|
||||
skipCheck = true;
|
||||
};
|
||||
|
||||
inputs = [ attr ];
|
||||
inputs = [ attr, kernel-headers ];
|
||||
runtime = [ attr ];
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ package cmake {
|
||||
website = "https://cmake.org";
|
||||
anitya = 306;
|
||||
|
||||
version# = "4.3.3";
|
||||
version# = "4.3.4";
|
||||
source = remoteGitHubRelease {
|
||||
suffix = "Kitware/CMake";
|
||||
tag = "v"+version;
|
||||
name = "cmake-"+version+".tar.gz";
|
||||
checksum = "VS-b6cN4S9hfNv3JOUAbAfI9nh3EeuVwY_IVgUdgq6VKwvfchhXwvvFAUcpZG6Ez";
|
||||
checksum = "6A50pqarKDXKOCv7ffKMvWJWmNTVp_ep8KoaWwNdg-RYQRddgKbxayHveTo6jZ_7";
|
||||
compress = gzip;
|
||||
};
|
||||
patches = [
|
||||
|
||||
@@ -3,10 +3,10 @@ package curl {
|
||||
website = "https://curl.se";
|
||||
anitya = 381;
|
||||
|
||||
version# = "8.20.0";
|
||||
version# = "8.21.0";
|
||||
source = remoteTar {
|
||||
url = "https://curl.se/download/curl-"+version+".tar.bz2";
|
||||
checksum = "xyHXwrngIRGMasuzhn-I5MSCOhktwINbsWt1f_LuR-5jRVvyx_g6U1EQfDLEbr9r";
|
||||
checksum = "lJSm8bVjS0OmsarEdbvejdQdvXsb7yGarlr6oMtA9FW1EXOga8zZxa1LPtfaq_qX";
|
||||
compress = bzip2;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@ package firmware {
|
||||
website = "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git";
|
||||
anitya = 141464;
|
||||
|
||||
version# = "20260519";
|
||||
version# = "20260622";
|
||||
source = remoteGitLab {
|
||||
domain = "gitlab.com";
|
||||
suffix = "kernel-firmware/linux-firmware";
|
||||
ref = version;
|
||||
checksum = "l-wBRTWclYnJsgV4qtUV1-UL5Y4nknAPre8CMe0dH7PxtAqbaeudEIM_Fnuj0TCV";
|
||||
checksum = "gpytkDM58EVjaUuryOekcekh_rWsfuv3S7LQxopHlNlVGmMsuqNwfug4BjgTgizE";
|
||||
};
|
||||
|
||||
// dedup creates temporary file
|
||||
@@ -34,7 +34,7 @@ package firmware {
|
||||
// requires pre-commit
|
||||
skipCheck = true;
|
||||
|
||||
install = "make " + jobsFlagE + " DESTDIR=/work/system dedup";
|
||||
install = "make " + jobsFlagE + " " + loadFlagE + " DESTDIR=/work/system dedup";
|
||||
};
|
||||
|
||||
inputs = [
|
||||
|
||||
@@ -3,24 +3,25 @@ package git {
|
||||
website = "https://www.git-scm.com";
|
||||
anitya = 5350;
|
||||
|
||||
version# = "2.54.0";
|
||||
version# = "2.55.0";
|
||||
source = remoteTar {
|
||||
url = "https://www.kernel.org/pub/software/scm/git/"+
|
||||
"git-"+version+".tar.gz";
|
||||
checksum = "7vGKtFOJGqY8DO4e8UMRax7dLgImXKQz5MMalec6MlgYrsarffSJjgOughwRFpSH";
|
||||
checksum = "lOer6jb8vZQk6Nd1rLZIgsYys8whLvjJq8XbmCdTATcPFAYuQcK1Rgj1Jj6a00W8";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
early = `
|
||||
ln -s ../../system/bin/perl /usr/bin/ || true
|
||||
|
||||
# test suite assumes apache
|
||||
rm -f /system/bin/httpd
|
||||
`;
|
||||
|
||||
// uses source tree as scratch space
|
||||
enterSource = true;
|
||||
env = [ "NO_RUST=YesPlease" ];
|
||||
|
||||
bin = [ "perl" ];
|
||||
populateUsrBin = true;
|
||||
exec = make {
|
||||
inPlace = true;
|
||||
generate = "make configure";
|
||||
@@ -69,6 +70,7 @@ disable_test t5515-fetch-merge-logic
|
||||
|
||||
install = `make \
|
||||
` + jobsFlagE + ` \
|
||||
` + loadFlagE + ` \
|
||||
DESTDIR=/work \
|
||||
NO_INSTALL_HARDLINKS=1 \
|
||||
install`;
|
||||
@@ -85,6 +87,7 @@ disable_test t5515-fetch-merge-logic
|
||||
zlib,
|
||||
curl,
|
||||
libexpat,
|
||||
kernel-headers,
|
||||
];
|
||||
|
||||
runtime = [
|
||||
|
||||
@@ -3,11 +3,11 @@ package glib {
|
||||
website = "https://developer.gnome.org/glib";
|
||||
anitya = 10024;
|
||||
|
||||
version# = "2.89.0";
|
||||
version# = "2.89.1";
|
||||
source = remoteGit {
|
||||
url = "https://gitlab.gnome.org/GNOME/glib.git";
|
||||
tag = version;
|
||||
checksum = "4FXKhdS3pC98LevYa_h7piRylG86cZ_c9zAtGr78oHodU1ob8rBxGU0hoIZ4nzcA";
|
||||
checksum = "9_6Eew2KIwa1AHopjU7CqC13_nur5FPJMu-iGUd7sD_1gAM1pa_HVUuAtqExJoYU";
|
||||
};
|
||||
|
||||
files = {
|
||||
@@ -19,6 +19,8 @@ package glib {
|
||||
setup = {
|
||||
"Ddefault_library": "both";
|
||||
};
|
||||
// fails with ipv6 disabled
|
||||
skipTests = [ "gio" ];
|
||||
};
|
||||
|
||||
inputs = [
|
||||
|
||||
@@ -155,6 +155,13 @@ package sed {
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
writable = true;
|
||||
early = `
|
||||
test_disable() { chmod +w "$2" && echo "$1" > "$2"; }
|
||||
|
||||
test_disable '#!/bin/sh' testsuite/read-error-stale-errno.sh
|
||||
`;
|
||||
|
||||
exec = make {};
|
||||
|
||||
inputs = [
|
||||
@@ -363,6 +370,9 @@ test_disable() { chmod +w "$2" && echo "$1" > "$2"; }
|
||||
test_disable '#!/bin/sh' gnulib-tests/test-c32ispunct.sh
|
||||
test_disable '#!/bin/sh' tests/ls/hyperlink.sh
|
||||
test_disable '#!/bin/sh' tests/misc/user.sh
|
||||
test_disable '#!/bin/sh' tests/split/line-bytes.sh
|
||||
test_disable '#!/bin/sh' tests/ls/stat-vs-dirent.sh
|
||||
test_disable '#!/bin/sh' tests/dd/sparse.sh
|
||||
test_disable 'int main(){return 0;}' gnulib-tests/test-chown.c
|
||||
test_disable 'int main(){return 0;}' gnulib-tests/test-fchownat.c
|
||||
test_disable 'int main(){return 0;}' gnulib-tests/test-lchown.c
|
||||
@@ -504,17 +514,14 @@ package parallel {
|
||||
website = "https://www.gnu.org/software/parallel";
|
||||
anitya = 5448;
|
||||
|
||||
version# = "20260522";
|
||||
version# = "20260622";
|
||||
source = remoteTar {
|
||||
url = "https://ftpmirror.gnu.org/gnu/parallel/parallel-"+version+".tar.bz2";
|
||||
checksum = "ezg3NZMlY-q-478YXmjWmDrDlaL55T7aBCuv3B7Z3DkAlfZRQEKO8eumqbcxTIy6";
|
||||
checksum = "pEkZ_J18AvKCMoPfxEprC0Smw7zP6qXASmC1uFf_HVD_jc95H06LvzGi40-mtCUo";
|
||||
compress = bzip2;
|
||||
};
|
||||
|
||||
early = `
|
||||
ln -s ../system/bin/bash /bin/
|
||||
`;
|
||||
|
||||
bin = [ "bash" ];
|
||||
exec = make {};
|
||||
|
||||
inputs = [
|
||||
|
||||
@@ -34,7 +34,8 @@ echo 'int main(){return 0;}' > tests/mini-dtls-fragments.c
|
||||
"with-zstd": "link";
|
||||
|
||||
"": arch {
|
||||
arm64 = "disable-hardware-acceleration";
|
||||
// miscompilation on arm64
|
||||
arm64 = "--disable-hardware-acceleration";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,11 +2,11 @@ package hakurei-source {
|
||||
description = "hakurei source tree";
|
||||
exclude = true;
|
||||
|
||||
version# = "0.4.4";
|
||||
version# = "0.4.5";
|
||||
output = remoteTar {
|
||||
url = "https://git.gensokyo.uk/rosa/hakurei/archive/"+
|
||||
"v"+version+".tar.gz";
|
||||
checksum = "BCIKpRiVv2tDg8lyX1bG_VgTBBMFCByv726x6DfJ0LiRg5ma4T5fcxYUaQl8JMVB";
|
||||
checksum = "5bvbuIRcDIrtijogwqXn3y8h5f3rVS4ZSVhOig6Galfzt3g-O3Ufb-tHL1kQCQWK";
|
||||
compress = gzip;
|
||||
};
|
||||
}
|
||||
@@ -48,8 +48,13 @@ go build -trimpath -tags=rosa -o /work/system/libexec/hakurei -ldflags="-s -w
|
||||
-X hakurei.app/internal/info.buildVersion=$(cat cmd/dist/VERSION)
|
||||
-X hakurei.app/internal/info.hakureiPath=/system/bin/hakurei
|
||||
-X hakurei.app/internal/info.hsuPath=/system/bin/hsu
|
||||
" ./cmd/hakurei ./cmd/sharefs
|
||||
|
||||
echo "Building hsu for $(go env GOOS)/$(go env GOARCH)."
|
||||
CGO_ENABLED=0 go build -trimpath -tags=rosa -o /work/system/libexec/hakurei -ldflags="-s -w
|
||||
-buildid=
|
||||
-X main.hakureiPath=/system/bin/hakurei
|
||||
" ./...
|
||||
" ./cmd/hsu
|
||||
echo`;
|
||||
check = `
|
||||
echo '##### Testing hakurei.'
|
||||
|
||||
@@ -3,11 +3,11 @@ package hwdata {
|
||||
website = "https://github.com/vcrhonek/hwdata";
|
||||
anitya = 5387;
|
||||
|
||||
version# = "0.408";
|
||||
version# = "0.409";
|
||||
source = remoteGitHub {
|
||||
suffix = "vcrhonek/hwdata";
|
||||
tag = "v"+version;
|
||||
checksum = "1Rm52ovBb8sZRlA578EKgKSIea9QGgDVSBDETU872BisZTVosQy-OTKkWpzU_ddB";
|
||||
checksum = "p2qr1_Y9dpjMNnK8OPNcuHSNwZldwb6mtiJ9Nd5HgU8z3L9fixLthnixywU8dd65";
|
||||
};
|
||||
|
||||
writable = true;
|
||||
|
||||
@@ -25,7 +25,6 @@ package system-image {
|
||||
version = unversioned;
|
||||
exclude = true;
|
||||
|
||||
source = earlyinit;
|
||||
extra = [
|
||||
musl,
|
||||
mksh,
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package iana-enterprise-numbers {
|
||||
description = "IANA Enterprise Numbers";
|
||||
website = "https://www.iana.org/assignments/enterprise-numbers.txt";
|
||||
exclude = true;
|
||||
|
||||
version# = "20250113140800";
|
||||
output = remoteFile {
|
||||
url = "https://web.archive.org/web/"+version+"id_/"+
|
||||
"https://www.iana.org/assignments/enterprise-numbers.txt";
|
||||
checksum = "IplVyf7P4PDhhDovWCzL6jPGmF0T75InOCv2IOTMoR7khHUcRfki1pY93kobuXHF";
|
||||
};
|
||||
}
|
||||
|
||||
package ipmitool {
|
||||
description = "an open-source tool for controlling IPMI-enabled systems";
|
||||
website = "https://codeberg.org/IPMITool/ipmitool";
|
||||
anitya = 1390;
|
||||
|
||||
version# = "1_8_19";
|
||||
source = remoteTar {
|
||||
url = "https://codeberg.org/IPMITool/ipmitool/archive/"+
|
||||
"IPMITOOL_"+version+".tar.gz";
|
||||
checksum = "oxY5S_C2Dl4NhVWtE0BMJtAAxCUgjAwvZm7gzqEzDf0Ina6auYNKztVdM3tclfgT";
|
||||
compress = gzip;
|
||||
};
|
||||
extra = [ iana-enterprise-numbers ];
|
||||
|
||||
early = "cp ../extra/iana-enterprise-numbers enterprise-numbers\n";
|
||||
exec = make {
|
||||
generate = "./bootstrap";
|
||||
};
|
||||
|
||||
inputs = [
|
||||
automake,
|
||||
libtool,
|
||||
|
||||
readline,
|
||||
];
|
||||
runtime = [ readline ];
|
||||
}
|
||||
@@ -3,11 +3,11 @@ package json-c {
|
||||
website = "https://json-c.github.io/json-c";
|
||||
anitya = 390279;
|
||||
|
||||
version# = "0.18-20240915";
|
||||
version# = "0.19-20260627";
|
||||
source = remoteGitHub {
|
||||
suffix = "json-c/json-c";
|
||||
tag = "json-c-"+version;
|
||||
checksum = "LXY6AqXtavysCqcWrniSkgV8fv54iDowsrQ7RXM-upH-ZoJr2R34ff7coFRvOr-k";
|
||||
checksum = "_yfWLtcd185xgLJaWC63pByFpROncoX7z1kHA02sCqYv2EEKG4YhJqc-8zdgtZ0c";
|
||||
};
|
||||
|
||||
exec = cmake {
|
||||
|
||||
@@ -1,493 +0,0 @@
|
||||
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
|
||||
+869
-388
File diff suppressed because it is too large
Load Diff
+1165
-428
File diff suppressed because it is too large
Load Diff
@@ -1,606 +0,0 @@
|
||||
From f54a91f5337cd918eb86cf600320d25b6cfd8209 Mon Sep 17 00:00:00 2001
|
||||
From: Nathan Chancellor <nathan@kernel.org>
|
||||
Date: Sat, 13 Dec 2025 19:58:10 +0900
|
||||
Subject: drm/amd/display: Reduce number of arguments of dcn30's
|
||||
CalculatePrefetchSchedule()
|
||||
|
||||
After an innocuous optimization change in clang-22,
|
||||
dml30_ModeSupportAndSystemConfigurationFull() is over the 2048 byte
|
||||
stack limit for display_mode_vba_30.c.
|
||||
|
||||
drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn30/display_mode_vba_30.c:3529:6: warning: stack frame size (2096) exceeds limit (2048) in 'dml30_ModeSupportAndSystemConfigurationFull' [-Wframe-larger-than]
|
||||
3529 | void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib)
|
||||
| ^
|
||||
|
||||
With clang-21, this function was already close to the limit:
|
||||
|
||||
drivers/gpu/drm/amd/amdgpu/../display/dc/dml/dcn30/display_mode_vba_30.c:3529:6: warning: stack frame size (1912) exceeds limit (1586) in 'dml30_ModeSupportAndSystemConfigurationFull' [-Wframe-larger-than]
|
||||
3529 | void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_lib)
|
||||
| ^
|
||||
|
||||
CalculatePrefetchSchedule() 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 2096 bytes to 1912 bytes with clang-22.
|
||||
|
||||
Closes: https://github.com/ClangBuiltLinux/linux/issues/2117
|
||||
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
|
||||
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
|
||||
(cherry picked from commit b20b3fc4210f83089f835cdb91deec4b0778761a)
|
||||
---
|
||||
.../amd/display/dc/dml/dcn30/display_mode_vba_30.c | 258 ++++++---------------
|
||||
1 file changed, 73 insertions(+), 185 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 abe51cf3aab2..a244504cc1f2 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
|
||||
@@ -77,32 +77,14 @@ static unsigned int dscceComputeDelay(
|
||||
static unsigned int dscComputeDelay(
|
||||
enum output_format_class pixelFormat,
|
||||
enum output_encoder_class Output);
|
||||
-// Super monster function with some 45 argument
|
||||
static bool CalculatePrefetchSchedule(
|
||||
struct display_mode_lib *mode_lib,
|
||||
- double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData,
|
||||
- double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly,
|
||||
+ unsigned int k,
|
||||
Pipe *myPipe,
|
||||
unsigned int DSCDelay,
|
||||
- double DPPCLKDelaySubtotalPlusCNVCFormater,
|
||||
- double DPPCLKDelaySCL,
|
||||
- double DPPCLKDelaySCLLBOnly,
|
||||
- double DPPCLKDelayCNVCCursor,
|
||||
- double DISPCLKDelaySubtotal,
|
||||
unsigned int DPP_RECOUT_WIDTH,
|
||||
- enum output_format_class OutputFormat,
|
||||
- unsigned int MaxInterDCNTileRepeaters,
|
||||
unsigned int VStartup,
|
||||
unsigned int MaxVStartup,
|
||||
- unsigned int GPUVMPageTableLevels,
|
||||
- bool GPUVMEnable,
|
||||
- bool HostVMEnable,
|
||||
- unsigned int HostVMMaxNonCachedPageTableLevels,
|
||||
- double HostVMMinPageSize,
|
||||
- bool DynamicMetadataEnable,
|
||||
- bool DynamicMetadataVMEnabled,
|
||||
- int DynamicMetadataLinesBeforeActiveRequired,
|
||||
- unsigned int DynamicMetadataTransmittedBytes,
|
||||
double UrgentLatency,
|
||||
double UrgentExtraLatency,
|
||||
double TCalc,
|
||||
@@ -116,7 +98,6 @@ static bool CalculatePrefetchSchedule(
|
||||
unsigned int MaxNumSwathY,
|
||||
double PrefetchSourceLinesC,
|
||||
unsigned int SwathWidthC,
|
||||
- int BytePerPixelC,
|
||||
double VInitPreFillC,
|
||||
unsigned int MaxNumSwathC,
|
||||
long swath_width_luma_ub,
|
||||
@@ -124,9 +105,6 @@ static bool CalculatePrefetchSchedule(
|
||||
unsigned int SwathHeightY,
|
||||
unsigned int SwathHeightC,
|
||||
double TWait,
|
||||
- bool ProgressiveToInterlaceUnitInOPP,
|
||||
- double *DSTXAfterScaler,
|
||||
- double *DSTYAfterScaler,
|
||||
double *DestinationLinesForPrefetch,
|
||||
double *PrefetchBandwidth,
|
||||
double *DestinationLinesToRequestVMInVBlank,
|
||||
@@ -135,14 +113,7 @@ static bool CalculatePrefetchSchedule(
|
||||
double *VRatioPrefetchC,
|
||||
double *RequiredPrefetchPixDataBWLuma,
|
||||
double *RequiredPrefetchPixDataBWChroma,
|
||||
- bool *NotEnoughTimeForDynamicMetadata,
|
||||
- double *Tno_bw,
|
||||
- double *prefetch_vmrow_bw,
|
||||
- double *Tdmdl_vm,
|
||||
- double *Tdmdl,
|
||||
- unsigned int *VUpdateOffsetPix,
|
||||
- double *VUpdateWidthPix,
|
||||
- double *VReadyOffsetPix);
|
||||
+ bool *NotEnoughTimeForDynamicMetadata);
|
||||
static double RoundToDFSGranularityUp(double Clock, double VCOSpeed);
|
||||
static double RoundToDFSGranularityDown(double Clock, double VCOSpeed);
|
||||
static void CalculateDCCConfiguration(
|
||||
@@ -810,29 +781,12 @@ static unsigned int dscComputeDelay(enum output_format_class pixelFormat, enum o
|
||||
|
||||
static bool CalculatePrefetchSchedule(
|
||||
struct display_mode_lib *mode_lib,
|
||||
- double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData,
|
||||
- double PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly,
|
||||
+ unsigned int k,
|
||||
Pipe *myPipe,
|
||||
unsigned int DSCDelay,
|
||||
- double DPPCLKDelaySubtotalPlusCNVCFormater,
|
||||
- double DPPCLKDelaySCL,
|
||||
- double DPPCLKDelaySCLLBOnly,
|
||||
- double DPPCLKDelayCNVCCursor,
|
||||
- double DISPCLKDelaySubtotal,
|
||||
unsigned int DPP_RECOUT_WIDTH,
|
||||
- enum output_format_class OutputFormat,
|
||||
- unsigned int MaxInterDCNTileRepeaters,
|
||||
unsigned int VStartup,
|
||||
unsigned int MaxVStartup,
|
||||
- unsigned int GPUVMPageTableLevels,
|
||||
- bool GPUVMEnable,
|
||||
- bool HostVMEnable,
|
||||
- unsigned int HostVMMaxNonCachedPageTableLevels,
|
||||
- double HostVMMinPageSize,
|
||||
- bool DynamicMetadataEnable,
|
||||
- bool DynamicMetadataVMEnabled,
|
||||
- int DynamicMetadataLinesBeforeActiveRequired,
|
||||
- unsigned int DynamicMetadataTransmittedBytes,
|
||||
double UrgentLatency,
|
||||
double UrgentExtraLatency,
|
||||
double TCalc,
|
||||
@@ -846,7 +800,6 @@ static bool CalculatePrefetchSchedule(
|
||||
unsigned int MaxNumSwathY,
|
||||
double PrefetchSourceLinesC,
|
||||
unsigned int SwathWidthC,
|
||||
- int BytePerPixelC,
|
||||
double VInitPreFillC,
|
||||
unsigned int MaxNumSwathC,
|
||||
long swath_width_luma_ub,
|
||||
@@ -854,9 +807,6 @@ static bool CalculatePrefetchSchedule(
|
||||
unsigned int SwathHeightY,
|
||||
unsigned int SwathHeightC,
|
||||
double TWait,
|
||||
- bool ProgressiveToInterlaceUnitInOPP,
|
||||
- double *DSTXAfterScaler,
|
||||
- double *DSTYAfterScaler,
|
||||
double *DestinationLinesForPrefetch,
|
||||
double *PrefetchBandwidth,
|
||||
double *DestinationLinesToRequestVMInVBlank,
|
||||
@@ -865,15 +815,10 @@ static bool CalculatePrefetchSchedule(
|
||||
double *VRatioPrefetchC,
|
||||
double *RequiredPrefetchPixDataBWLuma,
|
||||
double *RequiredPrefetchPixDataBWChroma,
|
||||
- bool *NotEnoughTimeForDynamicMetadata,
|
||||
- double *Tno_bw,
|
||||
- double *prefetch_vmrow_bw,
|
||||
- double *Tdmdl_vm,
|
||||
- double *Tdmdl,
|
||||
- unsigned int *VUpdateOffsetPix,
|
||||
- double *VUpdateWidthPix,
|
||||
- double *VReadyOffsetPix)
|
||||
+ bool *NotEnoughTimeForDynamicMetadata)
|
||||
{
|
||||
+ struct vba_vars_st *v = &mode_lib->vba;
|
||||
+ double DPPCLKDelaySubtotalPlusCNVCFormater = v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater;
|
||||
bool MyError = false;
|
||||
unsigned int DPPCycles = 0, DISPCLKCycles = 0;
|
||||
double DSTTotalPixelsAfterScaler = 0;
|
||||
@@ -905,26 +850,26 @@ static bool CalculatePrefetchSchedule(
|
||||
double Tdmec = 0;
|
||||
double Tdmsks = 0;
|
||||
|
||||
- if (GPUVMEnable == true && HostVMEnable == true) {
|
||||
- HostVMInefficiencyFactor = PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData / PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly;
|
||||
- HostVMDynamicLevelsTrips = HostVMMaxNonCachedPageTableLevels;
|
||||
+ if (v->GPUVMEnable == true && v->HostVMEnable == true) {
|
||||
+ HostVMInefficiencyFactor = v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData / v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly;
|
||||
+ HostVMDynamicLevelsTrips = v->HostVMMaxNonCachedPageTableLevels;
|
||||
} else {
|
||||
HostVMInefficiencyFactor = 1;
|
||||
HostVMDynamicLevelsTrips = 0;
|
||||
}
|
||||
|
||||
CalculateDynamicMetadataParameters(
|
||||
- MaxInterDCNTileRepeaters,
|
||||
+ v->MaxInterDCNTileRepeaters,
|
||||
myPipe->DPPCLK,
|
||||
myPipe->DISPCLK,
|
||||
myPipe->DCFCLKDeepSleep,
|
||||
myPipe->PixelClock,
|
||||
myPipe->HTotal,
|
||||
myPipe->VBlank,
|
||||
- DynamicMetadataTransmittedBytes,
|
||||
- DynamicMetadataLinesBeforeActiveRequired,
|
||||
+ v->DynamicMetadataTransmittedBytes[k],
|
||||
+ v->DynamicMetadataLinesBeforeActiveRequired[k],
|
||||
myPipe->InterlaceEnable,
|
||||
- ProgressiveToInterlaceUnitInOPP,
|
||||
+ v->ProgressiveToInterlaceUnitInOPP,
|
||||
&Tsetup,
|
||||
&Tdmbf,
|
||||
&Tdmec,
|
||||
@@ -932,16 +877,16 @@ static bool CalculatePrefetchSchedule(
|
||||
|
||||
LineTime = myPipe->HTotal / myPipe->PixelClock;
|
||||
trip_to_mem = UrgentLatency;
|
||||
- Tvm_trips = UrgentExtraLatency + trip_to_mem * (GPUVMPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1);
|
||||
+ Tvm_trips = UrgentExtraLatency + trip_to_mem * (v->GPUVMMaxPageTableLevels * (HostVMDynamicLevelsTrips + 1) - 1);
|
||||
|
||||
- if (DynamicMetadataVMEnabled == true && GPUVMEnable == true) {
|
||||
- *Tdmdl = TWait + Tvm_trips + trip_to_mem;
|
||||
+ if (v->DynamicMetadataVMEnabled == true && v->GPUVMEnable == true) {
|
||||
+ v->Tdmdl[k] = TWait + Tvm_trips + trip_to_mem;
|
||||
} else {
|
||||
- *Tdmdl = TWait + UrgentExtraLatency;
|
||||
+ v->Tdmdl[k] = TWait + UrgentExtraLatency;
|
||||
}
|
||||
|
||||
- if (DynamicMetadataEnable == true) {
|
||||
- if (VStartup * LineTime < Tsetup + *Tdmdl + Tdmbf + Tdmec + Tdmsks) {
|
||||
+ if (v->DynamicMetadataEnable[k] == true) {
|
||||
+ if (VStartup * LineTime < Tsetup + v->Tdmdl[k] + Tdmbf + Tdmec + Tdmsks) {
|
||||
*NotEnoughTimeForDynamicMetadata = true;
|
||||
} else {
|
||||
*NotEnoughTimeForDynamicMetadata = false;
|
||||
@@ -949,39 +894,39 @@ static bool CalculatePrefetchSchedule(
|
||||
dml_print("DML: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n", Tdmbf);
|
||||
dml_print("DML: Tdmec: %fus - time dio takes to transfer dmd\n", Tdmec);
|
||||
dml_print("DML: Tdmsks: %fus - time before active dmd must complete transmission at dio\n", Tdmsks);
|
||||
- dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", *Tdmdl);
|
||||
+ dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", v->Tdmdl[k]);
|
||||
}
|
||||
} else {
|
||||
*NotEnoughTimeForDynamicMetadata = false;
|
||||
}
|
||||
|
||||
- *Tdmdl_vm = (DynamicMetadataEnable == true && DynamicMetadataVMEnabled == true && GPUVMEnable == true ? TWait + Tvm_trips : 0);
|
||||
+ v->Tdmdl_vm[k] = (v->DynamicMetadataEnable[k] == true && v->DynamicMetadataVMEnabled == true && v->GPUVMEnable == true ? TWait + Tvm_trips : 0);
|
||||
|
||||
if (myPipe->ScalerEnabled)
|
||||
- DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + DPPCLKDelaySCL;
|
||||
+ DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + v->DPPCLKDelaySCL;
|
||||
else
|
||||
- DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + DPPCLKDelaySCLLBOnly;
|
||||
+ DPPCycles = DPPCLKDelaySubtotalPlusCNVCFormater + v->DPPCLKDelaySCLLBOnly;
|
||||
|
||||
- DPPCycles = DPPCycles + myPipe->NumberOfCursors * DPPCLKDelayCNVCCursor;
|
||||
+ DPPCycles = DPPCycles + myPipe->NumberOfCursors * v->DPPCLKDelayCNVCCursor;
|
||||
|
||||
- DISPCLKCycles = DISPCLKDelaySubtotal;
|
||||
+ DISPCLKCycles = v->DISPCLKDelaySubtotal;
|
||||
|
||||
if (myPipe->DPPCLK == 0.0 || myPipe->DISPCLK == 0.0)
|
||||
return true;
|
||||
|
||||
- *DSTXAfterScaler = DPPCycles * myPipe->PixelClock / myPipe->DPPCLK + DISPCLKCycles * myPipe->PixelClock / myPipe->DISPCLK
|
||||
+ v->DSTXAfterScaler[k] = DPPCycles * myPipe->PixelClock / myPipe->DPPCLK + DISPCLKCycles * myPipe->PixelClock / myPipe->DISPCLK
|
||||
+ DSCDelay;
|
||||
|
||||
- *DSTXAfterScaler = *DSTXAfterScaler + ((myPipe->ODMCombineEnabled)?18:0) + (myPipe->DPPPerPlane - 1) * DPP_RECOUT_WIDTH;
|
||||
+ v->DSTXAfterScaler[k] = v->DSTXAfterScaler[k] + ((myPipe->ODMCombineEnabled)?18:0) + (myPipe->DPPPerPlane - 1) * DPP_RECOUT_WIDTH;
|
||||
|
||||
- if (OutputFormat == dm_420 || (myPipe->InterlaceEnable && ProgressiveToInterlaceUnitInOPP))
|
||||
- *DSTYAfterScaler = 1;
|
||||
+ if (v->OutputFormat[k] == dm_420 || (myPipe->InterlaceEnable && v->ProgressiveToInterlaceUnitInOPP))
|
||||
+ v->DSTYAfterScaler[k] = 1;
|
||||
else
|
||||
- *DSTYAfterScaler = 0;
|
||||
+ v->DSTYAfterScaler[k] = 0;
|
||||
|
||||
- DSTTotalPixelsAfterScaler = *DSTYAfterScaler * myPipe->HTotal + *DSTXAfterScaler;
|
||||
- *DSTYAfterScaler = dml_floor(DSTTotalPixelsAfterScaler / myPipe->HTotal, 1);
|
||||
- *DSTXAfterScaler = DSTTotalPixelsAfterScaler - ((double) (*DSTYAfterScaler * myPipe->HTotal));
|
||||
+ DSTTotalPixelsAfterScaler = v->DSTYAfterScaler[k] * myPipe->HTotal + v->DSTXAfterScaler[k];
|
||||
+ v->DSTYAfterScaler[k] = dml_floor(DSTTotalPixelsAfterScaler / myPipe->HTotal, 1);
|
||||
+ v->DSTXAfterScaler[k] = DSTTotalPixelsAfterScaler - ((double) (v->DSTYAfterScaler[k] * myPipe->HTotal));
|
||||
|
||||
MyError = false;
|
||||
|
||||
@@ -990,32 +935,32 @@ static bool CalculatePrefetchSchedule(
|
||||
Tvm_trips_rounded = dml_ceil(4.0 * Tvm_trips / LineTime, 1) / 4 * LineTime;
|
||||
Tr0_trips_rounded = dml_ceil(4.0 * Tr0_trips / LineTime, 1) / 4 * LineTime;
|
||||
|
||||
- if (GPUVMEnable) {
|
||||
- if (GPUVMPageTableLevels >= 3) {
|
||||
- *Tno_bw = UrgentExtraLatency + trip_to_mem * ((GPUVMPageTableLevels - 2) - 1);
|
||||
+ if (v->GPUVMEnable) {
|
||||
+ if (v->GPUVMMaxPageTableLevels >= 3) {
|
||||
+ v->Tno_bw[k] = UrgentExtraLatency + trip_to_mem * ((v->GPUVMMaxPageTableLevels - 2) - 1);
|
||||
} else
|
||||
- *Tno_bw = 0;
|
||||
+ v->Tno_bw[k] = 0;
|
||||
} else if (!myPipe->DCCEnable)
|
||||
- *Tno_bw = LineTime;
|
||||
+ v->Tno_bw[k] = LineTime;
|
||||
else
|
||||
- *Tno_bw = LineTime / 4;
|
||||
+ v->Tno_bw[k] = LineTime / 4;
|
||||
|
||||
- dst_y_prefetch_equ = VStartup - (Tsetup + dml_max(TWait + TCalc, *Tdmdl)) / LineTime
|
||||
- - (*DSTYAfterScaler + *DSTXAfterScaler / myPipe->HTotal);
|
||||
+ dst_y_prefetch_equ = VStartup - (Tsetup + dml_max(TWait + TCalc, v->Tdmdl[k])) / LineTime
|
||||
+ - (v->DSTYAfterScaler[k] + v->DSTXAfterScaler[k] / myPipe->HTotal);
|
||||
|
||||
Lsw_oto = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC);
|
||||
Tsw_oto = Lsw_oto * LineTime;
|
||||
|
||||
- prefetch_bw_oto = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * BytePerPixelC) / Tsw_oto;
|
||||
+ prefetch_bw_oto = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * v->BytePerPixelC[k]) / Tsw_oto;
|
||||
|
||||
- if (GPUVMEnable == true) {
|
||||
- Tvm_oto = dml_max3(*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_oto,
|
||||
+ if (v->GPUVMEnable == true) {
|
||||
+ Tvm_oto = dml_max3(v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_oto,
|
||||
Tvm_trips,
|
||||
LineTime / 4.0);
|
||||
} else
|
||||
Tvm_oto = LineTime / 4.0;
|
||||
|
||||
- if ((GPUVMEnable == true || myPipe->DCCEnable == true)) {
|
||||
+ if ((v->GPUVMEnable == true || myPipe->DCCEnable == true)) {
|
||||
Tr0_oto = dml_max3(
|
||||
(MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_oto,
|
||||
LineTime - Tvm_oto, LineTime / 4);
|
||||
@@ -1041,10 +986,10 @@ static bool CalculatePrefetchSchedule(
|
||||
dml_print("DML: Tdmbf: %fus - time for dmd transfer from dchub to dio output buffer\n", Tdmbf);
|
||||
dml_print("DML: Tdmec: %fus - time dio takes to transfer dmd\n", Tdmec);
|
||||
dml_print("DML: Tdmsks: %fus - time before active dmd must complete transmission at dio\n", Tdmsks);
|
||||
- dml_print("DML: Tdmdl_vm: %fus - time for vm stages of dmd \n", *Tdmdl_vm);
|
||||
- dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", *Tdmdl);
|
||||
- dml_print("DML: dst_x_after_scl: %f pixels - number of pixel clocks pipeline and buffer delay after scaler \n", *DSTXAfterScaler);
|
||||
- dml_print("DML: dst_y_after_scl: %d lines - number of lines of pipeline and buffer delay after scaler \n", (int)*DSTYAfterScaler);
|
||||
+ dml_print("DML: Tdmdl_vm: %fus - time for vm stages of dmd \n", v->Tdmdl_vm[k]);
|
||||
+ dml_print("DML: Tdmdl: %fus - time for fabric to become ready and fetch dmd \n", v->Tdmdl[k]);
|
||||
+ dml_print("DML: dst_x_after_scl: %f pixels - number of pixel clocks pipeline and buffer delay after scaler \n", v->DSTXAfterScaler[k]);
|
||||
+ dml_print("DML: dst_y_after_scl: %d lines - number of lines of pipeline and buffer delay after scaler \n", (int)v->DSTYAfterScaler[k]);
|
||||
|
||||
*PrefetchBandwidth = 0;
|
||||
*DestinationLinesToRequestVMInVBlank = 0;
|
||||
@@ -1058,26 +1003,26 @@ static bool CalculatePrefetchSchedule(
|
||||
double PrefetchBandwidth3 = 0;
|
||||
double PrefetchBandwidth4 = 0;
|
||||
|
||||
- if (Tpre_rounded - *Tno_bw > 0)
|
||||
+ if (Tpre_rounded - v->Tno_bw[k] > 0)
|
||||
PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte
|
||||
+ 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor
|
||||
+ PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY
|
||||
- + PrefetchSourceLinesC * swath_width_chroma_ub * BytePerPixelC)
|
||||
- / (Tpre_rounded - *Tno_bw);
|
||||
+ + PrefetchSourceLinesC * swath_width_chroma_ub * v->BytePerPixelC[k])
|
||||
+ / (Tpre_rounded - v->Tno_bw[k]);
|
||||
else
|
||||
PrefetchBandwidth1 = 0;
|
||||
|
||||
- if (VStartup == MaxVStartup && (PrefetchBandwidth1 > 4 * prefetch_bw_oto) && (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - *Tno_bw) > 0) {
|
||||
- PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor) / (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - *Tno_bw);
|
||||
+ if (VStartup == MaxVStartup && (PrefetchBandwidth1 > 4 * prefetch_bw_oto) && (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - v->Tno_bw[k]) > 0) {
|
||||
+ PrefetchBandwidth1 = (PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor + 2 * MetaRowByte + 2 * PixelPTEBytesPerRow * HostVMInefficiencyFactor) / (Tpre_rounded - Tsw_oto / 4 - 0.75 * LineTime - v->Tno_bw[k]);
|
||||
}
|
||||
|
||||
- if (Tpre_rounded - *Tno_bw - 2 * Tr0_trips_rounded > 0)
|
||||
+ if (Tpre_rounded - v->Tno_bw[k] - 2 * Tr0_trips_rounded > 0)
|
||||
PrefetchBandwidth2 = (PDEAndMetaPTEBytesFrame *
|
||||
HostVMInefficiencyFactor + PrefetchSourceLinesY *
|
||||
swath_width_luma_ub * BytePerPixelY +
|
||||
PrefetchSourceLinesC * swath_width_chroma_ub *
|
||||
- BytePerPixelC) /
|
||||
- (Tpre_rounded - *Tno_bw - 2 * Tr0_trips_rounded);
|
||||
+ v->BytePerPixelC[k]) /
|
||||
+ (Tpre_rounded - v->Tno_bw[k] - 2 * Tr0_trips_rounded);
|
||||
else
|
||||
PrefetchBandwidth2 = 0;
|
||||
|
||||
@@ -1085,7 +1030,7 @@ static bool CalculatePrefetchSchedule(
|
||||
PrefetchBandwidth3 = (2 * MetaRowByte + 2 * PixelPTEBytesPerRow *
|
||||
HostVMInefficiencyFactor + PrefetchSourceLinesY *
|
||||
swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC *
|
||||
- swath_width_chroma_ub * BytePerPixelC) / (Tpre_rounded -
|
||||
+ swath_width_chroma_ub * v->BytePerPixelC[k]) / (Tpre_rounded -
|
||||
Tvm_trips_rounded);
|
||||
else
|
||||
PrefetchBandwidth3 = 0;
|
||||
@@ -1095,7 +1040,7 @@ static bool CalculatePrefetchSchedule(
|
||||
}
|
||||
|
||||
if (Tpre_rounded - Tvm_trips_rounded - 2 * Tr0_trips_rounded > 0)
|
||||
- PrefetchBandwidth4 = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * BytePerPixelC)
|
||||
+ PrefetchBandwidth4 = (PrefetchSourceLinesY * swath_width_luma_ub * BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * v->BytePerPixelC[k])
|
||||
/ (Tpre_rounded - Tvm_trips_rounded - 2 * Tr0_trips_rounded);
|
||||
else
|
||||
PrefetchBandwidth4 = 0;
|
||||
@@ -1106,7 +1051,7 @@ static bool CalculatePrefetchSchedule(
|
||||
bool Case3OK;
|
||||
|
||||
if (PrefetchBandwidth1 > 0) {
|
||||
- if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth1
|
||||
+ if (v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth1
|
||||
>= Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth1 >= Tr0_trips_rounded) {
|
||||
Case1OK = true;
|
||||
} else {
|
||||
@@ -1117,7 +1062,7 @@ static bool CalculatePrefetchSchedule(
|
||||
}
|
||||
|
||||
if (PrefetchBandwidth2 > 0) {
|
||||
- if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth2
|
||||
+ if (v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth2
|
||||
>= Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth2 < Tr0_trips_rounded) {
|
||||
Case2OK = true;
|
||||
} else {
|
||||
@@ -1128,7 +1073,7 @@ static bool CalculatePrefetchSchedule(
|
||||
}
|
||||
|
||||
if (PrefetchBandwidth3 > 0) {
|
||||
- if (*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth3
|
||||
+ if (v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / PrefetchBandwidth3
|
||||
< Tvm_trips_rounded && (MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / PrefetchBandwidth3 >= Tr0_trips_rounded) {
|
||||
Case3OK = true;
|
||||
} else {
|
||||
@@ -1151,13 +1096,13 @@ static bool CalculatePrefetchSchedule(
|
||||
dml_print("DML: prefetch_bw_equ: %f\n", prefetch_bw_equ);
|
||||
|
||||
if (prefetch_bw_equ > 0) {
|
||||
- if (GPUVMEnable) {
|
||||
- Tvm_equ = dml_max3(*Tno_bw + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_equ, Tvm_trips, LineTime / 4);
|
||||
+ if (v->GPUVMEnable) {
|
||||
+ Tvm_equ = dml_max3(v->Tno_bw[k] + PDEAndMetaPTEBytesFrame * HostVMInefficiencyFactor / prefetch_bw_equ, Tvm_trips, LineTime / 4);
|
||||
} else {
|
||||
Tvm_equ = LineTime / 4;
|
||||
}
|
||||
|
||||
- if ((GPUVMEnable || myPipe->DCCEnable)) {
|
||||
+ if ((v->GPUVMEnable || myPipe->DCCEnable)) {
|
||||
Tr0_equ = dml_max4(
|
||||
(MetaRowByte + PixelPTEBytesPerRow * HostVMInefficiencyFactor) / prefetch_bw_equ,
|
||||
Tr0_trips,
|
||||
@@ -1226,7 +1171,7 @@ static bool CalculatePrefetchSchedule(
|
||||
}
|
||||
|
||||
*RequiredPrefetchPixDataBWLuma = (double) PrefetchSourceLinesY / LinesToRequestPrefetchPixelData * BytePerPixelY * swath_width_luma_ub / LineTime;
|
||||
- *RequiredPrefetchPixDataBWChroma = (double) PrefetchSourceLinesC / LinesToRequestPrefetchPixelData * BytePerPixelC * swath_width_chroma_ub / LineTime;
|
||||
+ *RequiredPrefetchPixDataBWChroma = (double) PrefetchSourceLinesC / LinesToRequestPrefetchPixelData * v->BytePerPixelC[k] * swath_width_chroma_ub / LineTime;
|
||||
} else {
|
||||
MyError = true;
|
||||
dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__);
|
||||
@@ -1242,9 +1187,9 @@ static bool CalculatePrefetchSchedule(
|
||||
dml_print("DML: Tr0: %fus - time to fetch first row of data pagetables and first row of meta data (done in parallel)\n", TimeForFetchingRowInVBlank);
|
||||
dml_print("DML: Tr1: %fus - time to fetch second row of data pagetables and second row of meta data (done in parallel)\n", TimeForFetchingRowInVBlank);
|
||||
dml_print("DML: Tsw: %fus = time to fetch enough pixel data and cursor data to feed the scalers init position and detile\n", (double)LinesToRequestPrefetchPixelData * LineTime);
|
||||
- dml_print("DML: To: %fus - time for propagation from scaler to optc\n", (*DSTYAfterScaler + ((*DSTXAfterScaler) / (double) myPipe->HTotal)) * LineTime);
|
||||
+ dml_print("DML: To: %fus - time for propagation from scaler to optc\n", (v->DSTYAfterScaler[k] + ((v->DSTXAfterScaler[k]) / (double) myPipe->HTotal)) * LineTime);
|
||||
dml_print("DML: Tvstartup - Tsetup - Tcalc - Twait - Tpre - To > 0\n");
|
||||
- dml_print("DML: Tslack(pre): %fus - time left over in schedule\n", VStartup * LineTime - TimeForFetchingMetaPTE - 2 * TimeForFetchingRowInVBlank - (*DSTYAfterScaler + ((*DSTXAfterScaler) / (double) myPipe->HTotal)) * LineTime - TWait - TCalc - Tsetup);
|
||||
+ dml_print("DML: Tslack(pre): %fus - time left over in schedule\n", VStartup * LineTime - TimeForFetchingMetaPTE - 2 * TimeForFetchingRowInVBlank - (v->DSTYAfterScaler[k] + ((v->DSTXAfterScaler[k]) / (double) myPipe->HTotal)) * LineTime - TWait - TCalc - Tsetup);
|
||||
dml_print("DML: row_bytes = dpte_row_bytes (per_pipe) = PixelPTEBytesPerRow = : %d\n", PixelPTEBytesPerRow);
|
||||
|
||||
} else {
|
||||
@@ -1275,7 +1220,7 @@ static bool CalculatePrefetchSchedule(
|
||||
dml_print("DML: MyErr set %s:%d\n", __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
- *prefetch_vmrow_bw = dml_max(prefetch_vm_bw, prefetch_row_bw);
|
||||
+ v->prefetch_vmrow_bw[k] = dml_max(prefetch_vm_bw, prefetch_row_bw);
|
||||
}
|
||||
|
||||
if (MyError) {
|
||||
@@ -2448,30 +2393,12 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
|
||||
|
||||
v->ErrorResult[k] = CalculatePrefetchSchedule(
|
||||
mode_lib,
|
||||
- v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData,
|
||||
- v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly,
|
||||
+ k,
|
||||
&myPipe,
|
||||
v->DSCDelay[k],
|
||||
- v->DPPCLKDelaySubtotal
|
||||
- + v->DPPCLKDelayCNVCFormater,
|
||||
- v->DPPCLKDelaySCL,
|
||||
- v->DPPCLKDelaySCLLBOnly,
|
||||
- v->DPPCLKDelayCNVCCursor,
|
||||
- v->DISPCLKDelaySubtotal,
|
||||
(unsigned int) (v->SwathWidthY[k] / v->HRatio[k]),
|
||||
- v->OutputFormat[k],
|
||||
- v->MaxInterDCNTileRepeaters,
|
||||
dml_min(v->VStartupLines, v->MaxVStartupLines[k]),
|
||||
v->MaxVStartupLines[k],
|
||||
- v->GPUVMMaxPageTableLevels,
|
||||
- v->GPUVMEnable,
|
||||
- v->HostVMEnable,
|
||||
- v->HostVMMaxNonCachedPageTableLevels,
|
||||
- v->HostVMMinPageSize,
|
||||
- v->DynamicMetadataEnable[k],
|
||||
- v->DynamicMetadataVMEnabled,
|
||||
- v->DynamicMetadataLinesBeforeActiveRequired[k],
|
||||
- v->DynamicMetadataTransmittedBytes[k],
|
||||
v->UrgentLatency,
|
||||
v->UrgentExtraLatency,
|
||||
v->TCalc,
|
||||
@@ -2485,7 +2412,6 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
|
||||
v->MaxNumSwathY[k],
|
||||
v->PrefetchSourceLinesC[k],
|
||||
v->SwathWidthC[k],
|
||||
- v->BytePerPixelC[k],
|
||||
v->VInitPreFillC[k],
|
||||
v->MaxNumSwathC[k],
|
||||
v->swath_width_luma_ub[k],
|
||||
@@ -2493,9 +2419,6 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
|
||||
v->SwathHeightY[k],
|
||||
v->SwathHeightC[k],
|
||||
TWait,
|
||||
- v->ProgressiveToInterlaceUnitInOPP,
|
||||
- &v->DSTXAfterScaler[k],
|
||||
- &v->DSTYAfterScaler[k],
|
||||
&v->DestinationLinesForPrefetch[k],
|
||||
&v->PrefetchBandwidth[k],
|
||||
&v->DestinationLinesToRequestVMInVBlank[k],
|
||||
@@ -2504,14 +2427,7 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
|
||||
&v->VRatioPrefetchC[k],
|
||||
&v->RequiredPrefetchPixDataBWLuma[k],
|
||||
&v->RequiredPrefetchPixDataBWChroma[k],
|
||||
- &v->NotEnoughTimeForDynamicMetadata[k],
|
||||
- &v->Tno_bw[k],
|
||||
- &v->prefetch_vmrow_bw[k],
|
||||
- &v->Tdmdl_vm[k],
|
||||
- &v->Tdmdl[k],
|
||||
- &v->VUpdateOffsetPix[k],
|
||||
- &v->VUpdateWidthPix[k],
|
||||
- &v->VReadyOffsetPix[k]);
|
||||
+ &v->NotEnoughTimeForDynamicMetadata[k]);
|
||||
if (v->BlendingAndTiming[k] == k) {
|
||||
double TotalRepeaterDelayTime = v->MaxInterDCNTileRepeaters * (2 / v->DPPCLK[k] + 3 / v->DISPCLK);
|
||||
v->VUpdateWidthPix[k] = (14 / v->DCFCLKDeepSleep + 12 / v->DPPCLK[k] + TotalRepeaterDelayTime) * v->PixelClock[k];
|
||||
@@ -4781,29 +4697,12 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
|
||||
|
||||
v->NoTimeForPrefetch[i][j][k] = CalculatePrefetchSchedule(
|
||||
mode_lib,
|
||||
- v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyPixelMixedWithVMData,
|
||||
- v->PercentOfIdealDRAMFabricAndSDPPortBWReceivedAfterUrgLatencyVMDataOnly,
|
||||
+ k,
|
||||
&myPipe,
|
||||
v->DSCDelayPerState[i][k],
|
||||
- v->DPPCLKDelaySubtotal + v->DPPCLKDelayCNVCFormater,
|
||||
- v->DPPCLKDelaySCL,
|
||||
- v->DPPCLKDelaySCLLBOnly,
|
||||
- v->DPPCLKDelayCNVCCursor,
|
||||
- v->DISPCLKDelaySubtotal,
|
||||
v->SwathWidthYThisState[k] / v->HRatio[k],
|
||||
- v->OutputFormat[k],
|
||||
- v->MaxInterDCNTileRepeaters,
|
||||
dml_min(v->MaxVStartup, v->MaximumVStartup[i][j][k]),
|
||||
v->MaximumVStartup[i][j][k],
|
||||
- v->GPUVMMaxPageTableLevels,
|
||||
- v->GPUVMEnable,
|
||||
- v->HostVMEnable,
|
||||
- v->HostVMMaxNonCachedPageTableLevels,
|
||||
- v->HostVMMinPageSize,
|
||||
- v->DynamicMetadataEnable[k],
|
||||
- v->DynamicMetadataVMEnabled,
|
||||
- v->DynamicMetadataLinesBeforeActiveRequired[k],
|
||||
- v->DynamicMetadataTransmittedBytes[k],
|
||||
v->UrgLatency[i],
|
||||
v->ExtraLatency,
|
||||
v->TimeCalc,
|
||||
@@ -4817,7 +4716,6 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
|
||||
v->MaxNumSwY[k],
|
||||
v->PrefetchLinesC[i][j][k],
|
||||
v->SwathWidthCThisState[k],
|
||||
- v->BytePerPixelC[k],
|
||||
v->PrefillC[k],
|
||||
v->MaxNumSwC[k],
|
||||
v->swath_width_luma_ub_this_state[k],
|
||||
@@ -4825,9 +4723,6 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
|
||||
v->SwathHeightYThisState[k],
|
||||
v->SwathHeightCThisState[k],
|
||||
v->TWait,
|
||||
- v->ProgressiveToInterlaceUnitInOPP,
|
||||
- &v->DSTXAfterScaler[k],
|
||||
- &v->DSTYAfterScaler[k],
|
||||
&v->LineTimesForPrefetch[k],
|
||||
&v->PrefetchBW[k],
|
||||
&v->LinesForMetaPTE[k],
|
||||
@@ -4836,14 +4731,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
|
||||
&v->VRatioPreC[i][j][k],
|
||||
&v->RequiredPrefetchPixelDataBWLuma[i][j][k],
|
||||
&v->RequiredPrefetchPixelDataBWChroma[i][j][k],
|
||||
- &v->NoTimeForDynamicMetadata[i][j][k],
|
||||
- &v->Tno_bw[k],
|
||||
- &v->prefetch_vmrow_bw[k],
|
||||
- &v->Tdmdl_vm[k],
|
||||
- &v->Tdmdl[k],
|
||||
- &v->VUpdateOffsetPix[k],
|
||||
- &v->VUpdateWidthPix[k],
|
||||
- &v->VReadyOffsetPix[k]);
|
||||
+ &v->NoTimeForDynamicMetadata[i][j][k]);
|
||||
}
|
||||
|
||||
for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) {
|
||||
--
|
||||
cgit 1.2.3-korg
|
||||
@@ -3,11 +3,11 @@ package kernel-source {
|
||||
website = "https://kernel.org";
|
||||
exclude = true;
|
||||
|
||||
version# = "6.12.93";
|
||||
version# = "6.18.38";
|
||||
output = remoteTar {
|
||||
url = "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/"+
|
||||
"snapshot/linux-"+version+".tar.gz";
|
||||
checksum = "cGFcgR-h4Vwv2BU78jV4HmU-3yU_ER8l8LyKF0MibEsB-kUbbrIgqxMedXZ1j8Xw";
|
||||
checksum = "y_c897Efibj3TxgJQfpfTOWHTEoBPqu-XLwl2c40THwfgiNAop3qusrGvQkThXtI";
|
||||
compress = gzip;
|
||||
};
|
||||
}
|
||||
@@ -45,9 +45,9 @@ cat \
|
||||
checksum = arch {
|
||||
default = "";
|
||||
|
||||
amd64 = "Oy3soh5GNJr4JU7lk85J49LgNw-44SGpNB6NVlPp_mFUaXxvIGt1KLPnlpU3JYcB";
|
||||
arm64 = "GKHHQepUpwQjsSiq47-HV1G_aRR12oasaO5dV2bjc3D-4UzE9-Mb92ptplQQhSEc";
|
||||
riscv64 = "YwNZiSwm6EnTyCmKe-RMLhFHD7VuJoVjD6XnqywaB3e-Vk0rEWxsAxoNkCvxbXz9";
|
||||
amd64 = "UscduTw49AOk4CL6gLS6yORPFiHO79h1kFZKXKDaUI9j0x5CySi7P2Ywf29gYBsM";
|
||||
arm64 = "FM5-YFUbkOiux1KMxU29pecCoq6kPUfSL_4JlfqRHe4ZxIiT1AELGt7liD6df3-K";
|
||||
riscv64 = "Z1jR7S3nnGYOJtOR3sOMznfmkD_TirHP7-f3tVcgkVzWzHvMXS7ElHLT1NExqcqa";
|
||||
};
|
||||
inputs = [ rsync ];
|
||||
}
|
||||
@@ -55,18 +55,14 @@ cat \
|
||||
package kernel {
|
||||
description = "the generic Rosa OS linux kernel";
|
||||
website = "https://kernel.org";
|
||||
anitya = 375621;
|
||||
anitya = 389470;
|
||||
|
||||
source = kernel-source;
|
||||
patches = [
|
||||
"f54a91f5337cd918eb86cf600320d25b6cfd8209.patch",
|
||||
"6ce6fbfddc5b127e4f57c3b5bfdcf40239a4fc2f.patch",
|
||||
];
|
||||
files = {
|
||||
".config": arch {
|
||||
amd64 = "kernel_amd64.config";
|
||||
arm64 = "kernel_arm64.config";
|
||||
riscv64 = "kernel_riscv64.config";
|
||||
amd64 = "amd64.config";
|
||||
arm64 = "arm64.config";
|
||||
riscv64 = "riscv64.config";
|
||||
};
|
||||
|
||||
".installkernel": "installkernel";
|
||||
@@ -115,6 +111,7 @@ install -Dm0500 \
|
||||
|
||||
make \
|
||||
` + jobsFlagE + ` \
|
||||
` + loadFlagE + ` \
|
||||
-f /usr/src/kernel/Makefile \
|
||||
O=/tmp/kbuild \
|
||||
LLVM=1 \
|
||||
@@ -138,6 +135,7 @@ rm -v "/work/system/lib/modules/$(make -f /usr/src/kernel/Makefile kernelversion
|
||||
gawk,
|
||||
coreutils,
|
||||
diffutils,
|
||||
bash,
|
||||
python,
|
||||
|
||||
xz,
|
||||
|
||||
+851
-317
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
#define LINUX_VERSION_CODE 396378
|
||||
#define LINUX_VERSION_CODE 397861
|
||||
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))
|
||||
#define LINUX_VERSION_MAJOR 6
|
||||
#define LINUX_VERSION_PATCHLEVEL 12
|
||||
#define LINUX_VERSION_SUBLEVEL 90
|
||||
#define LINUX_VERSION_PATCHLEVEL 18
|
||||
#define LINUX_VERSION_SUBLEVEL 37
|
||||
|
||||
@@ -3,11 +3,11 @@ package libarchive {
|
||||
website = "https://www.libarchive.org";
|
||||
anitya = 1558;
|
||||
|
||||
version# = "3.8.7";
|
||||
version# = "3.8.8";
|
||||
source = remoteGitHub {
|
||||
suffix = "libarchive/libarchive";
|
||||
tag = "v"+version;
|
||||
checksum = "CUJK4MDQmZmATClgQBH2Wt-7Ts4iiSUlg1J_TVb6-5IK3rVUgVLIMc5k-bnWB9w3";
|
||||
checksum = "MYlQdlxHX14rFL_zEYvDArKgGVIueTPzSEDgCzaZkmi0_N7WsaEpogGO3qnHpfTc";
|
||||
};
|
||||
|
||||
files = { "CTestCustom.cmake"; };
|
||||
|
||||
@@ -12,6 +12,7 @@ package libcap {
|
||||
};
|
||||
|
||||
// uses source tree as scratch space
|
||||
enterSource = true;
|
||||
writable = true;
|
||||
chmod = true;
|
||||
|
||||
@@ -20,8 +21,7 @@ package libcap {
|
||||
"lib=lib",
|
||||
];
|
||||
|
||||
early = "\nln -s ../system/bin/bash /bin/\n";
|
||||
|
||||
bin = [ "bash" ];
|
||||
exec = make {
|
||||
skipConfigure = true;
|
||||
inPlace = true;
|
||||
|
||||
@@ -3,7 +3,7 @@ package libexpat {
|
||||
website = "https://libexpat.github.io";
|
||||
anitya = 770;
|
||||
|
||||
version# = "2.8.1";
|
||||
version# = "2.8.2";
|
||||
source = remoteGitHubRelease {
|
||||
suffix = "libexpat/libexpat";
|
||||
tag = "R_"+replace {
|
||||
@@ -12,7 +12,7 @@ package libexpat {
|
||||
new = "_";
|
||||
};
|
||||
name = "expat-"+version+".tar.bz2";
|
||||
checksum = "iMEtbOJhQfGof2GxSlxffQSI1va_NDDQ9VIuqcPbNZ0291Dr8wttD5QecYyjIQap";
|
||||
checksum = "98Pdyj5QtO7QRtNFXTWsCNCixQDx701ZGql2B-JIrTDkw49J5WXXUwnS4AdMlM4L";
|
||||
compress = bzip2;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@ package libffi {
|
||||
website = "https://sourceware.org/libffi";
|
||||
anitya = 1611;
|
||||
|
||||
version# = "3.5.2";
|
||||
version# = "3.6.0";
|
||||
source = remoteGitHubRelease {
|
||||
suffix = "libffi/libffi";
|
||||
tag = "v"+version;
|
||||
name = "libffi-"+version+".tar.gz";
|
||||
checksum = "2_Q-ZNBBbVhltfL5zEr0wljxPegUimTK4VeMSiwJEGksls3n4gj3lV0Ly3vviSFH";
|
||||
checksum = "y3H_jP_eoByznlztjvni3wDfGA4CIJoOh3eRnzjnE3G3Ms3AWk53oOZxkbruvLxM";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@ package libinput {
|
||||
checksum = "GxBGPN6YybQxrD2MDsIL8gdDYImXn4NAJi6EvTx_Hb_1jcbjwCrjeyjY2upUyTMi";
|
||||
};
|
||||
|
||||
early = "ln -sf ../system/bin/bash /bin/\n";
|
||||
|
||||
bin = [ "bash" ];
|
||||
exec = meson {
|
||||
setup = {
|
||||
"Dmtdev": "false";
|
||||
|
||||
@@ -3,12 +3,12 @@ package libpsl {
|
||||
website = "https://rockdaboot.github.io/libpsl";
|
||||
anitya = 7305;
|
||||
|
||||
version# = "0.21.5";
|
||||
version# = "0.22.0";
|
||||
source = remoteGitHubRelease {
|
||||
suffix = "rockdaboot/libpsl";
|
||||
tag = version;
|
||||
name = "libpsl-"+version+".tar.gz";
|
||||
checksum = "XjfxSzh7peG2Vg4vJlL8z4JZJLcXqbuP6pLWkrGCmRxlnYUFTKNBqWGHCxEOlCad";
|
||||
checksum = "sYrq75kNAJvU5gA2gv2tFYIFbFFit6PuYuW1tYSgcsJsIUzwMJTodofsaEGq3iGf";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
@@ -21,5 +21,8 @@ test_disable 'int main(){return 0;}' tests/test-is-public-builtin.c
|
||||
|
||||
exec = make {};
|
||||
|
||||
inputs = [ python ];
|
||||
inputs = [
|
||||
pkg-config,
|
||||
python,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -3,18 +3,16 @@ package libseccomp {
|
||||
website = "https://github.com/seccomp/libseccomp";
|
||||
anitya = 13823;
|
||||
|
||||
version# = "2.6.0";
|
||||
version# = "2.6.1";
|
||||
source = remoteGitHubRelease {
|
||||
suffix = "seccomp/libseccomp";
|
||||
tag = "v"+version;
|
||||
name = "libseccomp-"+version+".tar.gz";
|
||||
checksum = "mMu-iR71guPjFbb31u-YexBaanKE_nYPjPux-vuBiPfS_0kbwJdfCGlkofaUm-EY";
|
||||
checksum = "YiiUqaQA9EUDSeC3CifYJLJHT9DwkqQtW21ek0H3HzEG7_I9Yn5-pLt5ybQqpEEt";
|
||||
compress = gzip;
|
||||
};
|
||||
patches = [ "fix-export-oob-read.patch" ];
|
||||
|
||||
early = "\nln -s ../system/bin/bash /bin/\n";
|
||||
|
||||
bin = [ "bash" ];
|
||||
exec = make {};
|
||||
|
||||
inputs = [
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/src/api.c b/src/api.c
|
||||
index adccef3..65a277a 100644
|
||||
--- a/src/api.c
|
||||
+++ b/src/api.c
|
||||
@@ -786,7 +786,7 @@ API int seccomp_export_bpf_mem(const scmp_filter_ctx ctx, void *buf,
|
||||
if (BPF_PGM_SIZE(program) > *len)
|
||||
rc = _rc_filter(-ERANGE);
|
||||
else
|
||||
- memcpy(buf, program->blks, *len);
|
||||
+ memcpy(buf, program->blks, BPF_PGM_SIZE(program));
|
||||
}
|
||||
*len = BPF_PGM_SIZE(program);
|
||||
|
||||
@@ -3,11 +3,11 @@ package libva {
|
||||
website = "https://01.org/vaapi";
|
||||
anitya = 1752;
|
||||
|
||||
version# = "2.23.0";
|
||||
version# = "2.24.0";
|
||||
source = remoteGitHub {
|
||||
suffix = "intel/libva";
|
||||
tag = version;
|
||||
checksum = "UmF5tPyWIG_w5kiR3KFpoYbF7UUcaak5tyc-RhOheNTwQlLkPlifreFYCM9FQxbq";
|
||||
checksum = "Jb5bdeHXLPPTWFlmauKDZlfAjFiXiILs17Pp7F8kAiyctFiDItpzYY0prIlnW7mu";
|
||||
};
|
||||
|
||||
exec = meson {
|
||||
|
||||
@@ -14,12 +14,8 @@ package lm_sensors {
|
||||
chmod = true;
|
||||
enterSource = true;
|
||||
|
||||
early = `
|
||||
ln -s \
|
||||
../../system/bin/perl \
|
||||
/usr/bin/
|
||||
`;
|
||||
|
||||
bin = [ "perl" ];
|
||||
populateUsrBin = true;
|
||||
exec = make {
|
||||
inPlace = true;
|
||||
skipConfigure = true;
|
||||
|
||||
@@ -4,12 +4,12 @@ package mesa {
|
||||
anitya = 1970;
|
||||
latest = anityaFallback;
|
||||
|
||||
version# = "26.1.2";
|
||||
version# = "26.1.4";
|
||||
source = remoteGitLab {
|
||||
domain = "gitlab.freedesktop.org";
|
||||
suffix = "mesa/mesa";
|
||||
ref = "mesa-"+version;
|
||||
checksum = "EcY_vsm4rjUzVj7jQraWb9i3y0I2F0oH3Tav01QszQMxNzjLbSWHrQYR1mPRU-J4";
|
||||
checksum = "E13xE-PmYKdhuh2f_7lExKSamVCnXm7qKmzZVBzMuzaMA-EGi7ZDdf2UwZrrUpK_";
|
||||
};
|
||||
|
||||
exec = meson {
|
||||
|
||||
@@ -81,13 +81,13 @@ sed -i \
|
||||
extensions/libebt_snat.txlate
|
||||
`;
|
||||
|
||||
bin = [ "bash" ];
|
||||
exec = make {
|
||||
generate = "./autogen.sh";
|
||||
configure = {
|
||||
"enable-static";
|
||||
};
|
||||
preCheck = `
|
||||
ln -s ../system/bin/bash /bin/
|
||||
chmod +w /etc/ && ln -s ../usr/src/iptables/etc/ethertypes /etc/
|
||||
`;
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ package ninja {
|
||||
"CFLAGS=-std=c++17",
|
||||
];
|
||||
|
||||
bin = [ "echo" ];
|
||||
exec = generic {
|
||||
build = `
|
||||
python3 /usr/src/ninja/configure.py \
|
||||
@@ -22,12 +23,10 @@ python3 /usr/src/ninja/configure.py \
|
||||
--bootstrap
|
||||
python3 /usr/src/ninja/configure.py \
|
||||
--gtest-source-dir=/usr/src/extra/googletest
|
||||
./ninja ` + jobsFlagE + ` all`;
|
||||
./ninja ` + jobsFlagE + ` ` + loadFlagE + ` all
|
||||
`;
|
||||
|
||||
check = `
|
||||
chmod +w /bin/
|
||||
ln -s ../system/bin/echo /bin/
|
||||
./ninja_test`;
|
||||
check = "./ninja_test";
|
||||
|
||||
install = `
|
||||
mkdir -p /work/system/bin/
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package noto {
|
||||
description = "a typeface for the world";
|
||||
website = "https://fonts.google.com/noto";
|
||||
anitya = 10671;
|
||||
|
||||
version# = "2026.07.01";
|
||||
source = remoteGitHub {
|
||||
suffix = "notofonts/notofonts.github.io";
|
||||
tag = "noto-monthly-release-"+version;
|
||||
checksum = "4DdHW0aUDkcT-b3KNSNmPl_A2n4lrIeVmqjitDgUm4blGmGQjnMOtI4J9EjjYc06";
|
||||
};
|
||||
|
||||
enterSource = true;
|
||||
exec = generic {
|
||||
inPlace = true;
|
||||
install = `
|
||||
DEST=/work/system/share/fonts/noto
|
||||
for font in $(ls -d fonts/*/); do
|
||||
if [[ -d "$font"unhinted/variable-ttf ]]; then
|
||||
install -m444 -vDt "$DEST" "$font"unhinted/variable-ttf/*.ttf
|
||||
elif [[ -d "$font"unhinted/otf ]]; then
|
||||
install -m444 -vDt "$DEST" "$font"unhinted/otf/*.otf
|
||||
else
|
||||
install -m444 -vDt "$DEST" "$font"unhinted/ttf/*.ttf
|
||||
fi
|
||||
done
|
||||
rename -v 's/\[.*\]//' $DEST/*
|
||||
`;
|
||||
};
|
||||
|
||||
inputs = [ rename ];
|
||||
}
|
||||
@@ -33,6 +33,7 @@ package openssl {
|
||||
|
||||
check = [
|
||||
"HARNESS_JOBS=" + jobsE,
|
||||
"TESTS='-test_bio_dgram'",
|
||||
"test",
|
||||
];
|
||||
};
|
||||
|
||||
@@ -3,12 +3,12 @@ package pango {
|
||||
website = "https://www.pango.org";
|
||||
anitya = 11783;
|
||||
|
||||
version# = "1.57.1";
|
||||
version# = "1.58.0";
|
||||
source = remoteGitLab {
|
||||
domain = "gitlab.gnome.org";
|
||||
suffix = "GNOME/pango";
|
||||
ref = version;
|
||||
checksum = "BzfdEym2eIyL5ownJ1LfqQwZkY3yH71YAsQF5R-sRV2pIOmc_CULAcfqVQki_Ose";
|
||||
checksum = "k-Jcw7ys4-Q5gS0Y3WCb1MzIWauweIdknf61hRXJmQFfszw7sM7v0dItOoHMZLQJ";
|
||||
};
|
||||
|
||||
exec = meson {
|
||||
|
||||
@@ -12,11 +12,8 @@ package pcre2 {
|
||||
compress = bzip2;
|
||||
};
|
||||
|
||||
early = `
|
||||
# RunGrepTest expects /bin/echo
|
||||
ln -s ../system/bin/toybox /bin/echo
|
||||
`;
|
||||
|
||||
// RunGrepTest expects /bin/echo
|
||||
bin = [ "echo" ];
|
||||
exec = make {
|
||||
configure = {
|
||||
"enable-jit";
|
||||
|
||||
@@ -78,11 +78,11 @@ package python-setuptools {
|
||||
website = "https://pypi.org/project/setuptools";
|
||||
anitya = 4021;
|
||||
|
||||
version# = "82.0.1";
|
||||
version# = "83.0.0";
|
||||
source = remoteGitHub {
|
||||
suffix = "pypa/setuptools";
|
||||
tag = "v"+version;
|
||||
checksum = "nznP46Tj539yqswtOrIM4nQgwLA1h-ApKX7z7ghazROCpyF5swtQGwsZoI93wkhc";
|
||||
checksum = "WqYSqCAvwpcIG6yXV8vVzRMNWl2CrcPOUPwlYrLV70ykHSpKxW1-XYQ4Z4n0ebAt";
|
||||
};
|
||||
|
||||
exec = pip {
|
||||
@@ -124,15 +124,15 @@ package python-vcs-versioning {
|
||||
website = "https://setuptools-scm.readthedocs.io/en/latest";
|
||||
anitya = 389421;
|
||||
|
||||
version# = "1.1.1";
|
||||
version# = "2.2.2";
|
||||
source = remoteGitHub {
|
||||
suffix = "pypa/setuptools-scm";
|
||||
tag = "vcs-versioning-v"+version;
|
||||
checksum = "rXZixTsZcRcIoUC1LvWrjySsiXSv5uhW6ng2P-yXZrbdj7FrSrDeJLCfC2b-ladV";
|
||||
checksum = "dqKZGEjxWZ5xo4BjcpFOHxlEZfqrVWM79cRWa8OhGZY7VDSdOxrg7QVIhA6jsPcB";
|
||||
};
|
||||
|
||||
env = [
|
||||
"SETUPTOOLS_SCM_PRETEND_VERSION=" + version,
|
||||
"VCS_VERSIONING_PRETEND_VERSION=" + version,
|
||||
];
|
||||
|
||||
exec = pip {
|
||||
@@ -158,11 +158,11 @@ package python-setuptools-scm {
|
||||
website = "https://setuptools-scm.readthedocs.io/en/latest";
|
||||
anitya = 7874;
|
||||
|
||||
version# = "10.0.5";
|
||||
version# = "10.2.0";
|
||||
source = remoteGitHub {
|
||||
suffix = "pypa/setuptools-scm";
|
||||
tag = "setuptools-scm-v"+version;
|
||||
checksum = "vTN_TPd-b4Wbsw5WmAcsWjrs-FNXXznOeVTDnb54NtXve9Oy-eb2HPy-RG3FzNqp";
|
||||
checksum = "vbZMqPbhScSE5gQXHIvG3pPNw7Iqsi9sEpI13wPdTNQQYOI2skfCvwSTXLq9Ncq8";
|
||||
};
|
||||
|
||||
env = [
|
||||
@@ -382,11 +382,11 @@ package python-pytest {
|
||||
website = "https://pytest.org";
|
||||
anitya = 3765;
|
||||
|
||||
version# = "9.1.0";
|
||||
version# = "9.1.1";
|
||||
source = remoteGitHub {
|
||||
suffix = "pytest-dev/pytest";
|
||||
tag = version;
|
||||
checksum = "UNd_5ArXTfdGROVW5a0Z22FE4uOLfCMW4NeAnAp9SKHLGja9Db2Xc3BF48x7Hr_l";
|
||||
checksum = "PnsF2mxJDF1d1MeYfMmlrSa_OlI92F8OPlSVA-lqsh4ggRZiAHjbTdO_jfNox065";
|
||||
};
|
||||
|
||||
env = [
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
|
||||
index be4fa627b5..d6af6a036b 100644
|
||||
--- a/tests/qtest/meson.build
|
||||
+++ b/tests/qtest/meson.build
|
||||
@@ -29,7 +29,6 @@ qtests_generic = [
|
||||
'test-hmp',
|
||||
'qos-test',
|
||||
'readconfig-test',
|
||||
- 'netdev-socket',
|
||||
]
|
||||
if enable_modules
|
||||
qtests_generic += [ 'modules-test' ]
|
||||
@@ -402,7 +401,6 @@ qtests = {
|
||||
'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'],
|
||||
'virtio-net-failover': test_migration_files,
|
||||
'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
|
||||
- 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'),
|
||||
}
|
||||
|
||||
if vnc.found()
|
||||
@@ -3,13 +3,17 @@ package qemu {
|
||||
website = "https://www.qemu.org";
|
||||
anitya = 13607;
|
||||
|
||||
version# = "11.0.1";
|
||||
version# = "11.0.2";
|
||||
source = remoteTar {
|
||||
url = "https://download.qemu.org/qemu-"+version+".tar.bz2";
|
||||
checksum = "J3j3uNpiqxEoIEngBX2objV_1tzGfEgEphp5Ph86AJQvA_XMwYUakyvRH7YKEkwV";
|
||||
checksum = "FcVvKLivqRuFg7bGJlgJxx6-MWLORgJcliHwBw_1WssI-R7epGT75JawvSYy8Ltq";
|
||||
compress = bzip2;
|
||||
};
|
||||
patches = [ "disable-mcast-test.patch" ];
|
||||
patches = [
|
||||
"disable-mcast-test.patch",
|
||||
// fails with ipv6 disabled
|
||||
"disable-netdev-socket.patch",
|
||||
];
|
||||
|
||||
// configure script uses source as scratch space
|
||||
writable = true;
|
||||
@@ -49,6 +53,10 @@ EOF
|
||||
sep = ",";
|
||||
};
|
||||
};
|
||||
|
||||
check = [
|
||||
"TIMEOUT_MULTIPLIER=5",
|
||||
];
|
||||
};
|
||||
|
||||
inputs = [
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user