Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
33b855123e
|
|||
|
58ce134718
|
|||
|
2066093343
|
|||
|
07509b3ba2
|
|||
|
a7485d587a
|
|||
|
4892beefc1
|
|||
|
7ab54b8c94
|
|||
|
a4fab67811
|
|||
|
ed5cdd38a4
|
|||
|
f6318304ee
|
|||
|
cb618093d5
|
|||
|
b0b2471c0c
|
|||
|
344d2b8207
|
|||
|
3938e8bce5
|
|||
|
aee15b4f2a
|
|||
|
18b1103fdc
|
|||
|
c5a02da0f0
|
|||
|
c0c2f3233a
|
|||
|
bda00ac90e
|
+39
-16
@@ -35,6 +35,10 @@ func parse(id string, base *check.Absolute, r io.Reader) (*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 +55,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,19 +68,13 @@ 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",
|
||||
Shell: shell,
|
||||
Home: home,
|
||||
Path: shell,
|
||||
Args: []string{"zsh", "-c"},
|
||||
Args: []string{"zsh", "-ic"},
|
||||
|
||||
Flags: hst.FCoverRun,
|
||||
},
|
||||
@@ -102,16 +94,19 @@ 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 {
|
||||
c.Identity = v
|
||||
root.Upper = base.Append("template", template, "upper")
|
||||
}
|
||||
|
||||
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
|
||||
flags := map[string]*bool{
|
||||
@@ -200,6 +195,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 +223,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
|
||||
|
||||
+5
-10
@@ -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", "upper"),
|
||||
}},
|
||||
{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,
|
||||
@@ -118,8 +112,9 @@ talk com.canonical.Unity
|
||||
Home: hst.AbsPrivateTmp.Append("home"),
|
||||
Path: fhs.AbsRoot.Append("bin", "zsh"),
|
||||
Args: []string{
|
||||
"zsh", "-c",
|
||||
"zsh", "-ic",
|
||||
"exec Discord --ozone-platform-hint=wayland",
|
||||
"",
|
||||
},
|
||||
|
||||
Flags: hst.FCoverRun | hst.FUserns | hst.FHostNet | hst.FMapRealUID |
|
||||
|
||||
+89
-32
@@ -7,6 +7,8 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -34,7 +36,7 @@ func main() {
|
||||
flagVerbose bool
|
||||
flagBase string
|
||||
|
||||
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,7 +59,7 @@ func main() {
|
||||
"Increase log verbosity",
|
||||
).Flag(
|
||||
&flagBase,
|
||||
"d", command.StringFlag("$HAKUREI_APP_PATH"),
|
||||
"d", command.StringFlag("$ROSA_APP_PATH"),
|
||||
"Configuration and state directory",
|
||||
)
|
||||
|
||||
@@ -70,17 +70,31 @@ func main() {
|
||||
)
|
||||
c.NewCommand(
|
||||
"enter", "Enter mutable state template",
|
||||
func([]string) error {
|
||||
func(args []string) error {
|
||||
if len(args) != 1 {
|
||||
dents, err := os.ReadDir(template.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, dent := range dents {
|
||||
if !dent.IsDir() {
|
||||
continue
|
||||
}
|
||||
fmt.Println(dent.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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], "upper"),
|
||||
Work: template.Append(args[0], "work"),
|
||||
}},
|
||||
{FilesystemConfig: &hst.FSEphemeral{
|
||||
Target: fhs.AbsTmp,
|
||||
@@ -89,7 +103,8 @@ func main() {
|
||||
}},
|
||||
},
|
||||
Username: "chronos",
|
||||
Flags: hst.FMultiarch |
|
||||
Flags: hst.FNoPlace |
|
||||
hst.FMultiarch |
|
||||
hst.FDevel |
|
||||
hst.FUserns |
|
||||
hst.FHostNet |
|
||||
@@ -126,29 +141,71 @@ 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 {
|
||||
dents, err := os.ReadDir(base.Append("app").String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, dent := range dents {
|
||||
if dent.IsDir() {
|
||||
continue
|
||||
}
|
||||
fmt.Println(dent.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
config, err = parse(args[0], base, r)
|
||||
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
|
||||
}
|
||||
|
||||
return run(ctx, msg, 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 {
|
||||
|
||||
+7
-1
@@ -12,7 +12,12 @@ 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,
|
||||
config *hst.Config,
|
||||
args ...string,
|
||||
) error {
|
||||
c, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
@@ -25,6 +30,7 @@ func run(ctx context.Context, msg message.Msg, config *hst.Config) error {
|
||||
cmd.Args = append(cmd.Args, "-v")
|
||||
}
|
||||
cmd.Args = append(cmd.Args, "run", "3")
|
||||
cmd.Args = append(cmd.Args, args...)
|
||||
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
|
||||
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",
|
||||
"./...",
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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].
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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 {
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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 {
|
||||
@@ -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() {}
|
||||
|
||||
@@ -485,6 +485,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
|
||||
@@ -1892,6 +1902,10 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
}
|
||||
}()
|
||||
|
||||
if _, ok := a.(CuresExempt); ok {
|
||||
curesExempt = true
|
||||
}
|
||||
|
||||
var (
|
||||
ctx context.Context
|
||||
done chan<- struct{}
|
||||
|
||||
@@ -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
|
||||
@@ -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() {}
|
||||
|
||||
@@ -190,8 +190,8 @@ ln -s \
|
||||
})
|
||||
|
||||
const (
|
||||
version = "22.1.7"
|
||||
checksum = "GFjsoTzJ72YWQuAaNmlO67IIkoZ8Z12u3n0dOEMSpltmyXUJp8e3cccWDrscXILZ"
|
||||
version = "22.1.8"
|
||||
checksum = "_QzoDE0W6cv0vfIWeLPDvqG_vKhz6IGWl1nqUUvhlKWiRzf5dMGqeC3tyS2XgI6j"
|
||||
)
|
||||
|
||||
native.MustRegister("llvm-project", func(t Toolchain) (*Metadata, pkg.Artifact) {
|
||||
|
||||
@@ -2,11 +2,11 @@ package hakurei-source {
|
||||
description = "hakurei source tree";
|
||||
exclude = true;
|
||||
|
||||
version# = "0.4.3";
|
||||
version# = "0.4.4";
|
||||
output = remoteTar {
|
||||
url = "https://git.gensokyo.uk/rosa/hakurei/archive/"+
|
||||
"v"+version+".tar.gz";
|
||||
checksum = "1LqBJIcYcAFTVfydCahOm4hjjKhY953X9ars0eQj32hnpNncWFefuT6OJpZzIlZv";
|
||||
checksum = "BCIKpRiVv2tDg8lyX1bG_VgTBBMFCByv726x6DfJ0LiRg5ma4T5fcxYUaQl8JMVB";
|
||||
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 python {
|
||||
website = "https://www.python.org";
|
||||
anitya = 13254;
|
||||
|
||||
version# = "3.14.5";
|
||||
version# = "3.14.6";
|
||||
source = remoteTar {
|
||||
url = "https://www.python.org/ftp/python/"+version+
|
||||
"/Python-"+version+".tgz";
|
||||
checksum = "zYIpDlk2ftZ-UVGCQS1rthle2OHoyXV653ztWiopKV1NhmIJf1K2hHbkwM4DozQ9";
|
||||
checksum = "yynwXnElUvlAweA_RkBKQY35P59Gu5YU6ickJs6Z-blIoHgw5KgKXROY1gq2w0ez";
|
||||
compress = gzip;
|
||||
};
|
||||
patches = [ "zipfile-no-default-strict_timestamps.patch" ];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/Lib/zipfile/__init__.py b/Lib/zipfile/__init__.py
|
||||
index 19aea290b58..51603ba9510 100644
|
||||
index 2b6e6163b96..180b1bdb42a 100644
|
||||
--- a/Lib/zipfile/__init__.py
|
||||
+++ b/Lib/zipfile/__init__.py
|
||||
@@ -617,7 +617,7 @@ def _decodeExtra(self, filename_crc):
|
||||
@@ -621,7 +621,7 @@ def _decodeExtra(self, filename_crc):
|
||||
extra = extra[ln+4:]
|
||||
|
||||
@classmethod
|
||||
@@ -10,13 +10,13 @@ index 19aea290b58..51603ba9510 100644
|
||||
+ def from_file(cls, filename, arcname=None, *, strict_timestamps=False):
|
||||
"""Construct an appropriate ZipInfo for a file on the filesystem.
|
||||
|
||||
filename should be the path to a file or directory on the filesystem.
|
||||
@@ -1412,7 +1412,7 @@ class ZipFile:
|
||||
_windows_illegal_name_trans_table = None
|
||||
filename should be the path to a file or directory on the
|
||||
@@ -1421,7 +1421,7 @@ class ZipFile:
|
||||
_ignore_invalid_names = False
|
||||
|
||||
def __init__(self, file, mode="r", compression=ZIP_STORED, allowZip64=True,
|
||||
- compresslevel=None, *, strict_timestamps=True, metadata_encoding=None):
|
||||
+ compresslevel=None, *, strict_timestamps=False, metadata_encoding=None):
|
||||
"""Open the ZIP file with mode read 'r', write 'w', exclusive create 'x',
|
||||
or append 'a'."""
|
||||
"""Open the ZIP file with mode read 'r', write 'w', exclusive create
|
||||
'x', or append 'a'."""
|
||||
if mode not in ('r', 'w', 'x', 'a'):
|
||||
|
||||
@@ -5,11 +5,11 @@ package spirv-headers {
|
||||
// upstream changed version scheme, anitya incapable of filtering them
|
||||
latest = anityaFilterSPIRV;
|
||||
|
||||
version# = "1.4.350.0";
|
||||
version# = "1.4.350.1";
|
||||
source = remoteGitHub {
|
||||
suffix = "KhronosGroup/SPIRV-Headers";
|
||||
tag = "vulkan-sdk-"+version;
|
||||
checksum = "wFCZquDVL4HoE-kWbS_BHHb_d71EYR2A2kVp08oDutektpnQzhDP89wo821GgcpG";
|
||||
checksum = "6cmvMCH5aiHykXcozckfMOVA0nm0am4Xr2g9swBB9FtOV1vYBHgats5aRv4uQ9Kq";
|
||||
};
|
||||
|
||||
exec = cmake {
|
||||
|
||||
@@ -5,7 +5,7 @@ package util-linux {
|
||||
// release candidates confuse Anitya
|
||||
latest = anityaFallback;
|
||||
|
||||
version# = "2.42.1";
|
||||
version# = "2.42.2";
|
||||
source = remoteTar {
|
||||
url = "https://www.kernel.org/pub/linux/utils/util-linux/"+
|
||||
"v"+join {
|
||||
@@ -19,7 +19,7 @@ package util-linux {
|
||||
};
|
||||
sep = ".";
|
||||
}+"/util-linux-"+version+".tar.gz";
|
||||
checksum = "f1c006mnFL9jTEsqnJn08hHqwcL8TpjCJNIToZNuGEPsLmEdNL87r8RzBT-nl9QB";
|
||||
checksum = "Z4IZapPCKQP37aeWMDhxcvuOCy-IR_aHZvfUEMZ0T7trwC1znZACKH_3ddqXwBCg";
|
||||
compress = gzip;
|
||||
};
|
||||
|
||||
|
||||
+12
-1
@@ -7,6 +7,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"iter"
|
||||
@@ -1255,6 +1256,16 @@ func (s *S) RegisterFS(fsys fs.FS) error {
|
||||
// The resulting IR is curable on the daemon. Must not be used concurrently with
|
||||
// any other method.
|
||||
func (s *S) SetSource(fsys fs.FS) error {
|
||||
var version string
|
||||
if p, err := fs.ReadFile(fsys, "cmd/dist/VERSION"); err != nil {
|
||||
return err
|
||||
} else if len(p) < 2 {
|
||||
return fmt.Errorf("invalid version string %q", string(p))
|
||||
} else {
|
||||
version = unsafe.String(unsafe.SliceData(p), len(p))
|
||||
}
|
||||
version = version[1:len(version)-1] + "-CURRENT"
|
||||
|
||||
var buf bytes.Buffer
|
||||
w, err := gzip.NewWriterLevel(&buf, gzip.BestSpeed)
|
||||
if err != nil {
|
||||
@@ -1326,7 +1337,7 @@ func (s *S) SetSource(fsys fs.FS) error {
|
||||
return &Metadata{
|
||||
Name: name,
|
||||
Description: "hakurei source tree (current)",
|
||||
Version: "1.0.0-CURRENT",
|
||||
Version: version,
|
||||
Exclude: true,
|
||||
}, pkg.NewTar(pkg.NewDecompress(a, pkg.Gzip))
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user