Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
42c93a57a4
|
|||
|
b1b14810ac
|
|||
|
de117ef365
|
|||
|
5e4bf23e0c
|
|||
|
d4519e2075
|
|||
|
7f1e4cf43c
|
|||
|
d021621fba
|
|||
|
56567307ec
|
|||
|
0264a1ef09
|
|||
|
0123bbee3d
|
|||
|
771adad603
|
|||
|
178305cb22
|
|||
|
c2456e252c
|
|||
|
273068b90c
|
|||
|
16b20e1d34
|
|||
|
b983917a6e
|
|||
|
e1b8f40add
|
|||
|
6df0d37c5a
|
|||
|
1619b06541
|
|||
|
e335d99c6b
|
|||
|
d888d09b6d
|
|||
|
54176e7315
|
|||
|
3bfe99d3d8
|
|||
|
149dfbb6af
|
|||
|
58801b44d4
|
|||
|
e065bbf792
|
|||
|
a883e57e7d
|
|||
|
ef9bd8ecbf
|
|||
|
a40527dcb2
|
|||
|
88d9a6163e
|
|||
|
47860b0387
|
|||
|
50c9da8b6d
|
|||
|
16966043c7
|
|||
|
a3515a6ef5
|
|||
|
7f05baab28
|
|||
|
d4d5e631ae
|
|||
|
1df3bcc3b9
|
|||
|
1809b53e52
|
|||
|
67b2914c94
|
|||
|
74dee11822
|
|||
|
a58c9258cc
|
|||
|
710b164c91
|
|||
|
93911d6015
|
|||
|
bb097536d4
|
|||
|
49b6526a38
|
|||
|
f9c31df94d
|
|||
|
4f570cc5c9
|
|||
|
5828631e79
|
|||
|
4f9f4875d7
|
|||
|
d49e654482
|
|||
|
b746e352e5
|
|||
|
c620d88dce
|
|||
|
7cd14b8865
|
|||
|
3e18a4b397
|
|||
|
1791b604b5
|
|||
|
59ff6db7ec
|
|||
|
430e099556
|
|||
|
17b64bb42c
|
|||
|
dbb89dfb0f
|
|||
|
de06ea2be4
|
|||
|
1ef7bedfb5
|
|||
|
05a828c474
|
|||
|
0061d11f93
|
|||
|
fb101a02f2
|
|||
|
3dbd67d113
|
|||
|
f511f0a9e9
|
|||
|
47995137b3
|
|||
|
e1b8607101
|
|||
|
3d3bd45b95
|
181
README.md
181
README.md
@@ -15,164 +15,51 @@
|
||||
<a href="https://hakurei.app"><img src="https://img.shields.io/website?url=https%3A%2F%2Fhakurei.app" alt="Website" /></a>
|
||||
</p>
|
||||
|
||||
Hakurei is a tool for running sandboxed graphical applications as dedicated subordinate users on the Linux kernel.
|
||||
It implements the application container of [planterette (WIP)](https://git.gensokyo.uk/security/planterette),
|
||||
a self-contained Android-like package manager with modern security features.
|
||||
Hakurei is a tool for running sandboxed desktop applications as dedicated
|
||||
subordinate users on the Linux kernel. It implements the application container
|
||||
of [planterette (WIP)](https://git.gensokyo.uk/security/planterette), a
|
||||
self-contained Android-like package manager with modern security features.
|
||||
|
||||
## NixOS Module usage
|
||||
Interaction with hakurei happens entirely through structures described by
|
||||
package [hst](https://pkg.go.dev/hakurei.app/hst). No native API is available
|
||||
due to internal details of uid isolation.
|
||||
|
||||
The NixOS module currently requires home-manager to configure subordinate users. Full module documentation can be found [here](options.md).
|
||||
## Notable Packages
|
||||
|
||||
To use the module, import it into your configuration with
|
||||
Package [container](https://pkg.go.dev/hakurei.app/container) is general purpose
|
||||
container tooling. It is used by the hakurei shim process running as the target
|
||||
subordinate user to set up the application container. It has a single dependency,
|
||||
[libseccomp](https://github.com/seccomp/libseccomp), to create BPF programs
|
||||
for the [system call filter](https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html).
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
|
||||
Package [internal/pkg](https://pkg.go.dev/hakurei.app/internal/pkg) provides
|
||||
infrastructure for hermetic builds. This replaces the legacy nix-based testing
|
||||
framework and serves as the build system of Rosa OS, currently developed under
|
||||
package [internal/rosa](https://pkg.go.dev/hakurei.app/internal/rosa).
|
||||
|
||||
hakurei = {
|
||||
url = "git+https://git.gensokyo.uk/security/hakurei";
|
||||
## Dependencies
|
||||
|
||||
# Optional but recommended to limit the size of your system closure.
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
`container` depends on:
|
||||
|
||||
outputs = { self, nixpkgs, hakurei, ... }:
|
||||
{
|
||||
nixosConfigurations.hakurei = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
hakurei.nixosModules.hakurei
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
- [libseccomp](https://github.com/seccomp/libseccomp) to generate BPF programs.
|
||||
|
||||
This adds the `environment.hakurei` option:
|
||||
`cmd/hakurei` depends on:
|
||||
|
||||
```nix
|
||||
{ pkgs, ... }:
|
||||
- [acl](https://savannah.nongnu.org/projects/acl/) to export sockets to
|
||||
subordinate users.
|
||||
- [wayland](https://gitlab.freedesktop.org/wayland/wayland) to set up
|
||||
[security-context-v1](https://wayland.app/protocols/security-context-v1).
|
||||
- [xcb](https://xcb.freedesktop.org/) to grant and revoke subordinate users
|
||||
access to the X server.
|
||||
|
||||
{
|
||||
environment.hakurei = {
|
||||
enable = true;
|
||||
stateDir = "/var/lib/hakurei";
|
||||
users = {
|
||||
alice = 0;
|
||||
nixos = 10;
|
||||
};
|
||||
`cmd/sharefs` depends on:
|
||||
|
||||
commonPaths = [
|
||||
{
|
||||
src = "/sdcard";
|
||||
write = true;
|
||||
}
|
||||
];
|
||||
- [fuse](https://github.com/libfuse/libfuse) to implement the filesystem.
|
||||
|
||||
extraHomeConfig = {
|
||||
home.stateVersion = "23.05";
|
||||
};
|
||||
New dependencies will generally not be added. Patches adding new dependencies
|
||||
are very likely to be rejected.
|
||||
|
||||
apps = {
|
||||
"org.chromium.Chromium" = {
|
||||
name = "chromium";
|
||||
identity = 1;
|
||||
packages = [ pkgs.chromium ];
|
||||
userns = true;
|
||||
mapRealUid = true;
|
||||
dbus = {
|
||||
system = {
|
||||
filter = true;
|
||||
talk = [
|
||||
"org.bluez"
|
||||
"org.freedesktop.Avahi"
|
||||
"org.freedesktop.UPower"
|
||||
];
|
||||
};
|
||||
session =
|
||||
f:
|
||||
f {
|
||||
talk = [
|
||||
"org.freedesktop.FileManager1"
|
||||
"org.freedesktop.Notifications"
|
||||
"org.freedesktop.ScreenSaver"
|
||||
"org.freedesktop.secrets"
|
||||
"org.kde.kwalletd5"
|
||||
"org.kde.kwalletd6"
|
||||
];
|
||||
own = [
|
||||
"org.chromium.Chromium.*"
|
||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*"
|
||||
"org.mpris.MediaPlayer2.chromium.*"
|
||||
];
|
||||
call = { };
|
||||
broadcast = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
## NixOS Module (deprecated)
|
||||
|
||||
"org.claws_mail.Claws-Mail" = {
|
||||
name = "claws-mail";
|
||||
identity = 2;
|
||||
packages = [ pkgs.claws-mail ];
|
||||
gpu = false;
|
||||
capability.pulse = false;
|
||||
};
|
||||
|
||||
"org.weechat" = {
|
||||
name = "weechat";
|
||||
identity = 3;
|
||||
shareUid = true;
|
||||
packages = [ pkgs.weechat ];
|
||||
capability = {
|
||||
wayland = false;
|
||||
x11 = false;
|
||||
dbus = true;
|
||||
pulse = false;
|
||||
};
|
||||
};
|
||||
|
||||
"dev.vencord.Vesktop" = {
|
||||
name = "discord";
|
||||
identity = 3;
|
||||
shareUid = true;
|
||||
packages = [ pkgs.vesktop ];
|
||||
share = pkgs.vesktop;
|
||||
command = "vesktop --ozone-platform-hint=wayland";
|
||||
userns = true;
|
||||
mapRealUid = true;
|
||||
capability.x11 = true;
|
||||
dbus = {
|
||||
session =
|
||||
f:
|
||||
f {
|
||||
talk = [ "org.kde.StatusNotifierWatcher" ];
|
||||
own = [ ];
|
||||
call = { };
|
||||
broadcast = { };
|
||||
};
|
||||
system.filter = true;
|
||||
};
|
||||
};
|
||||
|
||||
"io.looking-glass" = {
|
||||
name = "looking-glass-client";
|
||||
identity = 4;
|
||||
useCommonPaths = false;
|
||||
groups = [ "plugdev" ];
|
||||
extraPaths = [
|
||||
{
|
||||
src = "/dev/shm/looking-glass";
|
||||
write = true;
|
||||
}
|
||||
];
|
||||
extraConfig = {
|
||||
programs.looking-glass-client.enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
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).
|
||||
267
cmd/mbf/main.go
267
cmd/mbf/main.go
@@ -10,11 +10,15 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"time"
|
||||
"unique"
|
||||
|
||||
"hakurei.app/command"
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/check"
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/std"
|
||||
"hakurei.app/internal/pkg"
|
||||
"hakurei.app/internal/rosa"
|
||||
"hakurei.app/message"
|
||||
@@ -55,6 +59,11 @@ func main() {
|
||||
c := command.New(os.Stderr, log.Printf, "mbf", func([]string) (err error) {
|
||||
msg.SwapVerbose(!flagQuiet)
|
||||
|
||||
flagBase = os.ExpandEnv(flagBase)
|
||||
if flagBase == "" {
|
||||
flagBase = "cache"
|
||||
}
|
||||
|
||||
var base *check.Absolute
|
||||
if flagBase, err = filepath.Abs(flagBase); err != nil {
|
||||
return
|
||||
@@ -81,7 +90,7 @@ func main() {
|
||||
"Maximum number of dependencies to cure at any given time",
|
||||
).Flag(
|
||||
&flagBase,
|
||||
"d", command.StringFlag("cache"),
|
||||
"d", command.StringFlag("$MBF_CACHE_DIR"),
|
||||
"Directory to store cured artifacts",
|
||||
).Flag(
|
||||
&flagTShift,
|
||||
@@ -109,46 +118,92 @@ func main() {
|
||||
)
|
||||
}
|
||||
|
||||
c.NewCommand(
|
||||
"stage3",
|
||||
"Check for toolchain 3-stage non-determinism",
|
||||
func(args []string) (err error) {
|
||||
_, _, _, stage1 := (rosa.Std - 2).NewLLVM()
|
||||
_, _, _, stage2 := (rosa.Std - 1).NewLLVM()
|
||||
_, _, _, stage3 := rosa.Std.NewLLVM()
|
||||
var (
|
||||
pathname *check.Absolute
|
||||
checksum [2]unique.Handle[pkg.Checksum]
|
||||
)
|
||||
{
|
||||
var (
|
||||
flagGentoo string
|
||||
flagChecksum string
|
||||
|
||||
if pathname, _, err = cache.Cure(stage1); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println("stage1:", pathname)
|
||||
flagStage0 bool
|
||||
)
|
||||
c.NewCommand(
|
||||
"stage3",
|
||||
"Check for toolchain 3-stage non-determinism",
|
||||
func(args []string) (err error) {
|
||||
t := rosa.Std
|
||||
if flagGentoo != "" {
|
||||
t -= 3 // magic number to discourage misuse
|
||||
|
||||
if pathname, checksum[0], err = cache.Cure(stage2); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println("stage2:", pathname)
|
||||
if pathname, checksum[1], err = cache.Cure(stage3); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println("stage3:", pathname)
|
||||
|
||||
if checksum[0] != checksum[1] {
|
||||
err = &pkg.ChecksumMismatchError{
|
||||
Got: checksum[0].Value(),
|
||||
Want: checksum[1].Value(),
|
||||
var checksum pkg.Checksum
|
||||
if len(flagChecksum) != 0 {
|
||||
if err = pkg.Decode(&checksum, flagChecksum); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
rosa.SetGentooStage3(flagGentoo, checksum)
|
||||
}
|
||||
} else {
|
||||
log.Println(
|
||||
"stage2 is identical to stage3",
|
||||
"("+pkg.Encode(checksum[0].Value())+")",
|
||||
|
||||
_, _, _, stage1 := (t - 2).NewLLVM()
|
||||
_, _, _, stage2 := (t - 1).NewLLVM()
|
||||
_, _, _, stage3 := t.NewLLVM()
|
||||
var (
|
||||
pathname *check.Absolute
|
||||
checksum [2]unique.Handle[pkg.Checksum]
|
||||
)
|
||||
}
|
||||
return
|
||||
},
|
||||
)
|
||||
|
||||
if pathname, _, err = cache.Cure(stage1); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println("stage1:", pathname)
|
||||
|
||||
if pathname, checksum[0], err = cache.Cure(stage2); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println("stage2:", pathname)
|
||||
if pathname, checksum[1], err = cache.Cure(stage3); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println("stage3:", pathname)
|
||||
|
||||
if checksum[0] != checksum[1] {
|
||||
err = &pkg.ChecksumMismatchError{
|
||||
Got: checksum[0].Value(),
|
||||
Want: checksum[1].Value(),
|
||||
}
|
||||
} else {
|
||||
log.Println(
|
||||
"stage2 is identical to stage3",
|
||||
"("+pkg.Encode(checksum[0].Value())+")",
|
||||
)
|
||||
}
|
||||
|
||||
if flagStage0 {
|
||||
if pathname, _, err = cache.Cure(
|
||||
t.Load(rosa.Stage0),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println(pathname)
|
||||
}
|
||||
|
||||
return
|
||||
},
|
||||
).
|
||||
Flag(
|
||||
&flagGentoo,
|
||||
"gentoo", command.StringFlag(""),
|
||||
"Bootstrap from a Gentoo stage3 tarball",
|
||||
).
|
||||
Flag(
|
||||
&flagChecksum,
|
||||
"checksum", command.StringFlag(""),
|
||||
"Checksum of Gentoo stage3 tarball",
|
||||
).
|
||||
Flag(
|
||||
&flagStage0,
|
||||
"stage0", command.BoolFlag(false),
|
||||
"Create bootstrap stage0 tarball",
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
var (
|
||||
@@ -162,7 +217,7 @@ func main() {
|
||||
return errors.New("cure requires 1 argument")
|
||||
}
|
||||
if p, ok := rosa.ResolveName(args[0]); !ok {
|
||||
return fmt.Errorf("unsupported artifact %q", args[0])
|
||||
return fmt.Errorf("unknown artifact %q", args[0])
|
||||
} else if flagDump == "" {
|
||||
pathname, _, err := cache.Cure(rosa.Std.Load(p))
|
||||
if err == nil {
|
||||
@@ -195,6 +250,142 @@ func main() {
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
var (
|
||||
flagNet bool
|
||||
flagSession bool
|
||||
|
||||
flagWithToolchain bool
|
||||
)
|
||||
c.NewCommand(
|
||||
"shell",
|
||||
"Interactive shell in the specified Rosa OS environment",
|
||||
func(args []string) error {
|
||||
root := make([]pkg.Artifact, 0, 6+len(args))
|
||||
for _, arg := range args {
|
||||
p, ok := rosa.ResolveName(arg)
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown artifact %q", arg)
|
||||
}
|
||||
root = append(root, rosa.Std.Load(p))
|
||||
}
|
||||
|
||||
musl, compilerRT, runtimes, clang := rosa.Std.NewLLVM()
|
||||
root = append(root, musl)
|
||||
if flagWithToolchain {
|
||||
root = append(root, compilerRT, runtimes, clang)
|
||||
}
|
||||
root = append(root,
|
||||
rosa.Std.Load(rosa.Mksh),
|
||||
rosa.Std.Load(rosa.Toybox),
|
||||
)
|
||||
|
||||
type cureRes struct {
|
||||
pathname *check.Absolute
|
||||
checksum unique.Handle[pkg.Checksum]
|
||||
}
|
||||
cured := make(map[pkg.Artifact]cureRes)
|
||||
for _, a := range root {
|
||||
pathname, checksum, err := cache.Cure(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cured[a] = cureRes{pathname, checksum}
|
||||
}
|
||||
|
||||
layers := pkg.PromoteLayers(root, func(a pkg.Artifact) (
|
||||
*check.Absolute,
|
||||
unique.Handle[pkg.Checksum],
|
||||
) {
|
||||
res := cured[a]
|
||||
return res.pathname, res.checksum
|
||||
}, func(i int, d pkg.Artifact) {
|
||||
r := pkg.Encode(cache.Ident(d).Value())
|
||||
if s, ok := d.(fmt.Stringer); ok {
|
||||
if name := s.String(); name != "" {
|
||||
r += "-" + name
|
||||
}
|
||||
}
|
||||
msg.Verbosef("promoted layer %d as %s", i, r)
|
||||
})
|
||||
|
||||
z := container.New(ctx, msg)
|
||||
z.WaitDelay = 3 * time.Second
|
||||
z.SeccompPresets = pkg.SeccompPresets
|
||||
z.SeccompFlags |= seccomp.AllowMultiarch
|
||||
z.ParentPerm = 0700
|
||||
z.HostNet = flagNet
|
||||
z.RetainSession = flagSession
|
||||
z.Hostname = "localhost"
|
||||
z.Uid, z.Gid = (1<<10)-1, (1<<10)-1
|
||||
z.Stdin, z.Stdout, z.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
|
||||
var tempdir *check.Absolute
|
||||
if s, err := filepath.Abs(os.TempDir()); err != nil {
|
||||
return err
|
||||
} else if tempdir, err = check.NewAbs(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
z.Dir = fhs.AbsRoot
|
||||
z.Env = []string{
|
||||
"SHELL=/system/bin/mksh",
|
||||
"PATH=/system/bin",
|
||||
"HOME=/",
|
||||
}
|
||||
z.Path = rosa.AbsSystem.Append("bin", "mksh")
|
||||
z.Args = []string{"mksh"}
|
||||
z.
|
||||
OverlayEphemeral(fhs.AbsRoot, layers...).
|
||||
Place(
|
||||
fhs.AbsEtc.Append("hosts"),
|
||||
[]byte("127.0.0.1 localhost\n"),
|
||||
).
|
||||
Place(
|
||||
fhs.AbsEtc.Append("passwd"),
|
||||
[]byte("media_rw:x:1023:1023::/:/system/bin/sh\n"+
|
||||
"nobody:x:65534:65534::/proc/nonexistent:/system/bin/false\n"),
|
||||
).
|
||||
Place(
|
||||
fhs.AbsEtc.Append("group"),
|
||||
[]byte("media_rw:x:1023:\nnobody:x:65534:\n"),
|
||||
).
|
||||
Bind(tempdir, fhs.AbsTmp, std.BindWritable).
|
||||
Proc(fhs.AbsProc).Dev(fhs.AbsDev, true)
|
||||
|
||||
if err := z.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := z.Serve(); err != nil {
|
||||
return err
|
||||
}
|
||||
return z.Wait()
|
||||
},
|
||||
).
|
||||
Flag(
|
||||
&flagNet,
|
||||
"net", command.BoolFlag(false),
|
||||
"Share host net namespace",
|
||||
).
|
||||
Flag(
|
||||
&flagSession,
|
||||
"session", command.BoolFlag(false),
|
||||
"Retain session",
|
||||
).
|
||||
Flag(
|
||||
&flagWithToolchain,
|
||||
"with-toolchain", command.BoolFlag(false),
|
||||
"Include the stage3 LLVM toolchain",
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
c.Command(
|
||||
"help",
|
||||
"Show this help message",
|
||||
func([]string) error { c.PrintHelp(); return nil },
|
||||
)
|
||||
|
||||
c.MustParse(os.Args[1:], func(err error) {
|
||||
if cache != nil {
|
||||
cache.Close()
|
||||
|
||||
@@ -238,8 +238,11 @@ func sliceAddr[S any](s []S) *[]S { return &s }
|
||||
|
||||
func newCheckedFile(t *testing.T, name, wantData string, closeErr error) osFile {
|
||||
f := &checkedOsFile{t: t, name: name, want: wantData, closeErr: closeErr}
|
||||
// check happens in Close, and cleanup is not guaranteed to run, so relying on it for sloppy implementations will cause sporadic test results
|
||||
f.cleanup = runtime.AddCleanup(f, func(name string) { f.t.Fatalf("checkedOsFile %s became unreachable without a call to Close", name) }, f.name)
|
||||
// check happens in Close, and cleanup is not guaranteed to run, so relying
|
||||
// on it for sloppy implementations will cause sporadic test results
|
||||
f.cleanup = runtime.AddCleanup(f, func(name string) {
|
||||
panic("checkedOsFile " + name + " became unreachable without a call to Close")
|
||||
}, name)
|
||||
return f
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ func TestTmpfileOp(t *testing.T) {
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []stub.Call{
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), stub.UniqueError(5)),
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, (*checkedOsFile)(nil), stub.UniqueError(5)),
|
||||
}, stub.UniqueError(5)},
|
||||
|
||||
{"Write", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
@@ -35,14 +35,14 @@ func TestTmpfileOp(t *testing.T) {
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []stub.Call{
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, stub.UniqueError(3)), nil),
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.Close", sampleDataString, stub.UniqueError(3)), nil),
|
||||
}, stub.UniqueError(3)},
|
||||
|
||||
{"ensureFile", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []stub.Call{
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil),
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.ensureFile", sampleDataString, nil), nil),
|
||||
call("ensureFile", stub.ExpectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, stub.UniqueError(2)),
|
||||
}, stub.UniqueError(2)},
|
||||
|
||||
@@ -50,29 +50,29 @@ func TestTmpfileOp(t *testing.T) {
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []stub.Call{
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil),
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.bindMount", sampleDataString, nil), nil),
|
||||
call("ensureFile", stub.ExpectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, nil),
|
||||
call("bindMount", stub.ExpectArgs{"tmp.32768", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, stub.UniqueError(1)),
|
||||
call("bindMount", stub.ExpectArgs{"tmp.bindMount", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, stub.UniqueError(1)),
|
||||
}, stub.UniqueError(1)},
|
||||
|
||||
{"remove", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []stub.Call{
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil),
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.remove", sampleDataString, nil), nil),
|
||||
call("ensureFile", stub.ExpectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, nil),
|
||||
call("bindMount", stub.ExpectArgs{"tmp.32768", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, nil),
|
||||
call("remove", stub.ExpectArgs{"tmp.32768"}, nil, stub.UniqueError(0)),
|
||||
call("bindMount", stub.ExpectArgs{"tmp.remove", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, nil),
|
||||
call("remove", stub.ExpectArgs{"tmp.remove"}, nil, stub.UniqueError(0)),
|
||||
}, stub.UniqueError(0)},
|
||||
|
||||
{"success", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []stub.Call{
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), nil),
|
||||
call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.success", sampleDataString, nil), nil),
|
||||
call("ensureFile", stub.ExpectArgs{"/sysroot/etc/passwd", os.FileMode(0444), os.FileMode(0700)}, nil, nil),
|
||||
call("bindMount", stub.ExpectArgs{"tmp.32768", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, nil),
|
||||
call("remove", stub.ExpectArgs{"tmp.32768"}, nil, nil),
|
||||
call("bindMount", stub.ExpectArgs{"tmp.success", "/sysroot/etc/passwd", uintptr(0x5), false}, nil, nil),
|
||||
call("remove", stub.ExpectArgs{"tmp.success"}, nil, nil),
|
||||
}, nil},
|
||||
})
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
package filelock
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
@@ -74,10 +73,3 @@ func (lt lockType) String() string {
|
||||
return "Unlock"
|
||||
}
|
||||
}
|
||||
|
||||
// IsNotSupported returns a boolean indicating whether the error is known to
|
||||
// report that a function is not supported (possibly for a specific input).
|
||||
// It is satisfied by errors.ErrUnsupported as well as some syscall errors.
|
||||
func IsNotSupported(err error) bool {
|
||||
return errors.Is(err, errors.ErrUnsupported)
|
||||
}
|
||||
|
||||
@@ -94,6 +94,11 @@ func (f *File) Close() error {
|
||||
|
||||
err := closeFile(f.osFile.File)
|
||||
f.cleanup.Stop()
|
||||
// f may be dead at the moment after we access f.cleanup,
|
||||
// so the cleanup can fire before Stop completes. Keep f
|
||||
// alive while we call Stop. See the documentation for
|
||||
// runtime.Cleanup.Stop.
|
||||
runtime.KeepAlive(f)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -39,22 +39,20 @@ type ExecPath struct {
|
||||
W bool
|
||||
}
|
||||
|
||||
// layers returns pathnames collected from A deduplicated by checksum.
|
||||
func (p *ExecPath) layers(f *FContext) []*check.Absolute {
|
||||
msg := f.GetMessage()
|
||||
|
||||
layers := make([]*check.Absolute, 0, len(p.A))
|
||||
checksums := make(map[unique.Handle[Checksum]]struct{}, len(p.A))
|
||||
for i := range p.A {
|
||||
d := p.A[len(p.A)-1-i]
|
||||
pathname, checksum := f.GetArtifact(d)
|
||||
// PromoteLayers returns artifacts with identical-by-content layers promoted to
|
||||
// the highest priority instance, as if mounted via [ExecPath].
|
||||
func PromoteLayers(
|
||||
artifacts []Artifact,
|
||||
getArtifact func(Artifact) (*check.Absolute, unique.Handle[Checksum]),
|
||||
report func(i int, d Artifact),
|
||||
) []*check.Absolute {
|
||||
layers := make([]*check.Absolute, 0, len(artifacts))
|
||||
checksums := make(map[unique.Handle[Checksum]]struct{}, len(artifacts))
|
||||
for i := range artifacts {
|
||||
d := artifacts[len(artifacts)-1-i]
|
||||
pathname, checksum := getArtifact(d)
|
||||
if _, ok := checksums[checksum]; ok {
|
||||
if msg.IsVerbose() {
|
||||
msg.Verbosef(
|
||||
"promoted layer %d as %s",
|
||||
len(p.A)-1-i, reportName(d, f.cache.Ident(d)),
|
||||
)
|
||||
}
|
||||
report(len(artifacts)-1-i, d)
|
||||
continue
|
||||
}
|
||||
checksums[checksum] = struct{}{}
|
||||
@@ -64,6 +62,19 @@ func (p *ExecPath) layers(f *FContext) []*check.Absolute {
|
||||
return layers
|
||||
}
|
||||
|
||||
// layers returns pathnames collected from A deduplicated via [PromoteLayers].
|
||||
func (p *ExecPath) layers(f *FContext) []*check.Absolute {
|
||||
msg := f.GetMessage()
|
||||
return PromoteLayers(p.A, f.GetArtifact, func(i int, d Artifact) {
|
||||
if msg.IsVerbose() {
|
||||
msg.Verbosef(
|
||||
"promoted layer %d as %s",
|
||||
i, reportName(d, f.cache.Ident(d)),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Path returns a populated [ExecPath].
|
||||
func Path(pathname *check.Absolute, writable bool, a ...Artifact) ExecPath {
|
||||
return ExecPath{pathname, a, writable}
|
||||
@@ -365,6 +376,10 @@ func scanVerbose(
|
||||
}
|
||||
}
|
||||
|
||||
// SeccompPresets is the [seccomp] presets used by exec artifacts.
|
||||
const SeccompPresets = std.PresetStrict &
|
||||
^(std.PresetDenyNS | std.PresetDenyDevel)
|
||||
|
||||
// cure is like Cure but allows optional host net namespace. This is used for
|
||||
// the [KnownChecksum] variant where networking is allowed.
|
||||
func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
||||
@@ -388,7 +403,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
|
||||
|
||||
z := container.New(ctx, f.GetMessage())
|
||||
z.WaitDelay = execWaitDelay
|
||||
z.SeccompPresets |= std.PresetStrict & ^std.PresetDenyNS
|
||||
z.SeccompPresets = SeccompPresets
|
||||
z.SeccompFlags |= seccomp.AllowMultiarch
|
||||
z.ParentPerm = 0700
|
||||
z.HostNet = hostNet
|
||||
|
||||
@@ -310,6 +310,13 @@ type (
|
||||
// verbose logging is enabled. Artifacts may only depend on artifacts
|
||||
// previously described in the IR stream.
|
||||
//
|
||||
// IRDecoder rejects an IR stream on the first decoding error, it does not
|
||||
// check against nonzero reserved ancillary data or incorrectly ordered or
|
||||
// redundant unstructured dependencies. An invalid IR stream as such will
|
||||
// yield [Artifact] values with identifiers disagreeing with those computed
|
||||
// by IRDecoder. For this reason, IRDecoder does not access the ident cache
|
||||
// to avoid putting [Cache] into an inconsistent state.
|
||||
//
|
||||
// Methods of IRDecoder are not safe for concurrent use.
|
||||
IRDecoder struct {
|
||||
// Address of underlying [Cache], must not be exposed directly.
|
||||
|
||||
@@ -65,18 +65,23 @@ func MustDecode(s string) (checksum Checksum) {
|
||||
return
|
||||
}
|
||||
|
||||
// common holds elements and receives methods shared between different contexts.
|
||||
type common struct {
|
||||
// Address of underlying [Cache], should be zeroed or made unusable after
|
||||
// Cure returns and must not be exposed directly.
|
||||
cache *Cache
|
||||
}
|
||||
|
||||
// TContext is passed to [TrivialArtifact.Cure] and provides information and
|
||||
// methods required for curing the [TrivialArtifact].
|
||||
//
|
||||
// Methods of TContext are safe for concurrent use. TContext is valid
|
||||
// until [TrivialArtifact.Cure] returns.
|
||||
type TContext struct {
|
||||
// Address of underlying [Cache], should be zeroed or made unusable after
|
||||
// [TrivialArtifact.Cure] returns and must not be exposed directly.
|
||||
cache *Cache
|
||||
|
||||
// Populated during [Cache.Cure].
|
||||
work, temp *check.Absolute
|
||||
|
||||
common
|
||||
}
|
||||
|
||||
// destroy destroys the temporary directory and joins its errors with the error
|
||||
@@ -104,10 +109,10 @@ func (t *TContext) destroy(errP *error) {
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying [context.Context].
|
||||
func (t *TContext) Unwrap() context.Context { return t.cache.ctx }
|
||||
func (c *common) Unwrap() context.Context { return c.cache.ctx }
|
||||
|
||||
// GetMessage returns [message.Msg] held by the underlying [Cache].
|
||||
func (t *TContext) GetMessage() message.Msg { return t.cache.msg }
|
||||
func (c *common) GetMessage() message.Msg { return c.cache.msg }
|
||||
|
||||
// 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]
|
||||
@@ -126,13 +131,13 @@ func (t *TContext) GetTempDir() *check.Absolute { return t.temp }
|
||||
// If err is nil, the caller must close the resulting [io.ReadCloser] and return
|
||||
// its error, if any. Failure to read r to EOF may result in a spurious
|
||||
// [ChecksumMismatchError], or the underlying implementation may block on Close.
|
||||
func (t *TContext) Open(a Artifact) (r io.ReadCloser, err error) {
|
||||
func (c *common) Open(a Artifact) (r io.ReadCloser, err error) {
|
||||
if f, ok := a.(FileArtifact); ok {
|
||||
return t.cache.openFile(f)
|
||||
return c.cache.openFile(f)
|
||||
}
|
||||
|
||||
var pathname *check.Absolute
|
||||
if pathname, _, err = t.cache.Cure(a); err != nil {
|
||||
if pathname, _, err = c.cache.Cure(a); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -191,14 +196,7 @@ func (f *FContext) GetArtifact(a Artifact) (
|
||||
//
|
||||
// Methods of RContext are safe for concurrent use. RContext is valid
|
||||
// until [FileArtifact.Cure] returns.
|
||||
type RContext struct {
|
||||
// Address of underlying [Cache], should be zeroed or made unusable after
|
||||
// [FileArtifact.Cure] returns and must not be exposed directly.
|
||||
cache *Cache
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying [context.Context].
|
||||
func (r *RContext) Unwrap() context.Context { return r.cache.ctx }
|
||||
type RContext struct{ common }
|
||||
|
||||
// An Artifact is a read-only reference to a piece of data that may be created
|
||||
// deterministically but might not currently be available in memory or on the
|
||||
@@ -466,7 +464,7 @@ type Cache struct {
|
||||
// Synchronises entry into exclusive artifacts for the cure method.
|
||||
exclMu sync.Mutex
|
||||
// Buffered I/O free list, must not be accessed directly.
|
||||
bufioPool sync.Pool
|
||||
brPool, bwPool sync.Pool
|
||||
|
||||
// Unlocks the on-filesystem cache. Must only be called from Close.
|
||||
unlock func()
|
||||
@@ -548,6 +546,26 @@ func (c *Cache) unsafeIdent(a Artifact, encodeKind bool) (
|
||||
return
|
||||
}
|
||||
|
||||
// getReader is like [bufio.NewReader] but for brPool.
|
||||
func (c *Cache) getReader(r io.Reader) *bufio.Reader {
|
||||
br := c.brPool.Get().(*bufio.Reader)
|
||||
br.Reset(r)
|
||||
return br
|
||||
}
|
||||
|
||||
// putReader adds br to brPool.
|
||||
func (c *Cache) putReader(br *bufio.Reader) { c.brPool.Put(br) }
|
||||
|
||||
// getWriter is like [bufio.NewWriter] but for bwPool.
|
||||
func (c *Cache) getWriter(w io.Writer) *bufio.Writer {
|
||||
bw := c.bwPool.Get().(*bufio.Writer)
|
||||
bw.Reset(w)
|
||||
return bw
|
||||
}
|
||||
|
||||
// putWriter adds bw to bwPool.
|
||||
func (c *Cache) putWriter(bw *bufio.Writer) { c.bwPool.Put(bw) }
|
||||
|
||||
// A ChecksumMismatchError describes an [Artifact] with unexpected content.
|
||||
type ChecksumMismatchError struct {
|
||||
// Actual and expected checksums.
|
||||
@@ -927,14 +945,14 @@ func (c *Cache) openFile(f FileArtifact) (r io.ReadCloser, err error) {
|
||||
}
|
||||
if c.msg.IsVerbose() {
|
||||
rn := reportName(f, c.Ident(f))
|
||||
c.msg.Verbosef("curing %s to memory...", rn)
|
||||
c.msg.Verbosef("curing %s in memory...", rn)
|
||||
defer func() {
|
||||
if err == nil {
|
||||
c.msg.Verbosef("cured %s to memory", rn)
|
||||
c.msg.Verbosef("opened %s for reading", rn)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return f.Cure(&RContext{c})
|
||||
return f.Cure(&RContext{common{c}})
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1131,6 +1149,9 @@ type DependencyCureError []*CureError
|
||||
// unwrapM recursively expands underlying errors into a caller-supplied map.
|
||||
func (e *DependencyCureError) unwrapM(me map[unique.Handle[ID]]*CureError) {
|
||||
for _, err := range *e {
|
||||
if _, ok := me[err.Ident]; ok {
|
||||
continue
|
||||
}
|
||||
if _e, ok := err.Err.(*DependencyCureError); ok {
|
||||
_e.unwrapM(me)
|
||||
continue
|
||||
@@ -1214,13 +1235,6 @@ func (c *Cache) exitCure(a Artifact, curesExempt bool) {
|
||||
<-c.cures
|
||||
}
|
||||
|
||||
// getWriter is like [bufio.NewWriter] but for bufioPool.
|
||||
func (c *Cache) getWriter(w io.Writer) *bufio.Writer {
|
||||
bw := c.bufioPool.Get().(*bufio.Writer)
|
||||
bw.Reset(w)
|
||||
return bw
|
||||
}
|
||||
|
||||
// measuredReader implements [io.ReadCloser] and measures the checksum during
|
||||
// Close. If the underlying reader is not read to EOF, Close blocks until all
|
||||
// remaining data is consumed and validated.
|
||||
@@ -1303,9 +1317,6 @@ func (r *RContext) NewMeasuredReader(
|
||||
return r.cache.newMeasuredReader(rc, checksum)
|
||||
}
|
||||
|
||||
// putWriter adds bw to bufioPool.
|
||||
func (c *Cache) putWriter(bw *bufio.Writer) { c.bufioPool.Put(bw) }
|
||||
|
||||
// cure implements Cure without checking the full dependency graph.
|
||||
func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
pathname *check.Absolute,
|
||||
@@ -1437,7 +1448,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
if err = c.enterCure(a, curesExempt); err != nil {
|
||||
return
|
||||
}
|
||||
r, err = f.Cure(&RContext{c})
|
||||
r, err = f.Cure(&RContext{common{c}})
|
||||
if err == nil {
|
||||
if checksumPathname == nil || c.IsStrict() {
|
||||
h := sha512.New384()
|
||||
@@ -1513,7 +1524,11 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
|
||||
return
|
||||
}
|
||||
|
||||
t := TContext{c, c.base.Append(dirWork, ids), c.base.Append(dirTemp, ids)}
|
||||
t := TContext{
|
||||
c.base.Append(dirWork, ids),
|
||||
c.base.Append(dirTemp, ids),
|
||||
common{c},
|
||||
}
|
||||
switch ca := a.(type) {
|
||||
case TrivialArtifact:
|
||||
defer t.destroy(&err)
|
||||
@@ -1713,13 +1728,16 @@ func open(
|
||||
msg: msg,
|
||||
base: base,
|
||||
|
||||
identPool: sync.Pool{New: func() any { return new(extIdent) }},
|
||||
|
||||
ident: make(map[unique.Handle[ID]]unique.Handle[Checksum]),
|
||||
identErr: make(map[unique.Handle[ID]]error),
|
||||
identPending: make(map[unique.Handle[ID]]<-chan struct{}),
|
||||
|
||||
brPool: sync.Pool{New: func() any { return new(bufio.Reader) }},
|
||||
bwPool: sync.Pool{New: func() any { return new(bufio.Writer) }},
|
||||
}
|
||||
c.ctx, c.cancel = context.WithCancel(ctx)
|
||||
c.identPool.New = func() any { return new(extIdent) }
|
||||
c.bufioPool.New = func() any { return new(bufio.Writer) }
|
||||
|
||||
if lock || !testing.Testing() {
|
||||
if unlock, err := lockedfile.MutexAt(
|
||||
|
||||
@@ -10,8 +10,7 @@ import (
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"hakurei.app/container/check"
|
||||
"path"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -100,7 +99,6 @@ func (e DisallowedTypeflagError) Error() string {
|
||||
|
||||
// Cure cures the [Artifact], producing a directory located at work.
|
||||
func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
temp := t.GetTempDir()
|
||||
var tr io.ReadCloser
|
||||
if tr, err = t.Open(a.f); err != nil {
|
||||
return
|
||||
@@ -116,7 +114,9 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
err = closeErr
|
||||
}
|
||||
}(tr)
|
||||
tr = io.NopCloser(tr)
|
||||
br := t.cache.getReader(tr)
|
||||
defer t.cache.putReader(br)
|
||||
tr = io.NopCloser(br)
|
||||
|
||||
switch a.compression {
|
||||
case TarUncompressed:
|
||||
@@ -137,14 +137,24 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
}
|
||||
|
||||
type dirTargetPerm struct {
|
||||
path *check.Absolute
|
||||
path string
|
||||
mode fs.FileMode
|
||||
}
|
||||
var madeDirectories []dirTargetPerm
|
||||
|
||||
if err = os.MkdirAll(temp.String(), 0700); err != nil {
|
||||
if err = os.MkdirAll(t.GetTempDir().String(), 0700); err != nil {
|
||||
return
|
||||
}
|
||||
var root *os.Root
|
||||
if root, err = os.OpenRoot(t.GetTempDir().String()); err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
closeErr := root.Close()
|
||||
if err == nil {
|
||||
err = closeErr
|
||||
}
|
||||
}()
|
||||
|
||||
var header *tar.Header
|
||||
r := tar.NewReader(tr)
|
||||
@@ -158,9 +168,8 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
pathname := temp.Append(header.Name)
|
||||
if typeflag >= '0' && typeflag <= '9' && typeflag != tar.TypeDir {
|
||||
if err = os.MkdirAll(pathname.Dir().String(), 0700); err != nil {
|
||||
if err = root.MkdirAll(path.Dir(header.Name), 0700); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -168,8 +177,8 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
switch typeflag {
|
||||
case tar.TypeReg:
|
||||
var f *os.File
|
||||
if f, err = os.OpenFile(
|
||||
pathname.String(),
|
||||
if f, err = root.OpenFile(
|
||||
header.Name,
|
||||
os.O_CREATE|os.O_EXCL|os.O_WRONLY,
|
||||
header.FileInfo().Mode()&0500,
|
||||
); err != nil {
|
||||
@@ -184,26 +193,29 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
break
|
||||
|
||||
case tar.TypeLink:
|
||||
if err = os.Link(
|
||||
temp.Append(header.Linkname).String(),
|
||||
pathname.String(),
|
||||
if err = root.Link(
|
||||
header.Linkname,
|
||||
header.Name,
|
||||
); err != nil {
|
||||
return
|
||||
}
|
||||
break
|
||||
|
||||
case tar.TypeSymlink:
|
||||
if err = os.Symlink(header.Linkname, pathname.String()); err != nil {
|
||||
if err = root.Symlink(
|
||||
header.Linkname,
|
||||
header.Name,
|
||||
); err != nil {
|
||||
return
|
||||
}
|
||||
break
|
||||
|
||||
case tar.TypeDir:
|
||||
madeDirectories = append(madeDirectories, dirTargetPerm{
|
||||
path: pathname,
|
||||
path: header.Name,
|
||||
mode: header.FileInfo().Mode(),
|
||||
})
|
||||
if err = os.MkdirAll(pathname.String(), 0700); err != nil {
|
||||
if err = root.MkdirAll(header.Name, 0700); err != nil {
|
||||
return
|
||||
}
|
||||
break
|
||||
@@ -220,7 +232,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
}
|
||||
if err == nil {
|
||||
for _, e := range madeDirectories {
|
||||
if err = os.Chmod(e.path.String(), e.mode&0500); err != nil {
|
||||
if err = root.Chmod(e.path, e.mode&0500); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -228,6 +240,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
temp := t.GetTempDir()
|
||||
if err = os.Chmod(temp.String(), 0700); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -43,14 +43,14 @@ index 6ce2f9b..e9bde92 100644
|
||||
--- a/test/attr.test
|
||||
+++ b/test/attr.test
|
||||
@@ -11,7 +11,7 @@ Try various valid and invalid names
|
||||
|
||||
$ touch f
|
||||
$ setfattr -n user -v value f
|
||||
- > setfattr: f: Operation not supported
|
||||
+ > setfattr: f: Not supported
|
||||
|
||||
$ setfattr -n user. -v value f
|
||||
> setfattr: f: Invalid argument
|
||||
|
||||
$ touch f
|
||||
$ setfattr -n user -v value f
|
||||
- > setfattr: f: Operation not supported
|
||||
+ > setfattr: f: Not supported
|
||||
|
||||
$ setfattr -n user. -v value f
|
||||
> setfattr: f: Invalid argument
|
||||
`},
|
||||
), &MakeAttr{
|
||||
ScriptEarly: `
|
||||
|
||||
@@ -11,19 +11,27 @@ type PArtifact int
|
||||
|
||||
const (
|
||||
ACL PArtifact = iota
|
||||
ArgpStandalone
|
||||
Attr
|
||||
Autoconf
|
||||
Automake
|
||||
BC
|
||||
Bash
|
||||
Binutils
|
||||
Bison
|
||||
Bzip2
|
||||
CMake
|
||||
Coreutils
|
||||
Curl
|
||||
DTC
|
||||
Diffutils
|
||||
Elfutils
|
||||
Findutils
|
||||
Flex
|
||||
Fuse
|
||||
Gawk
|
||||
GMP
|
||||
GLib
|
||||
Gawk
|
||||
Gettext
|
||||
Git
|
||||
Go
|
||||
@@ -33,9 +41,13 @@ const (
|
||||
Hakurei
|
||||
HakureiDist
|
||||
IniConfig
|
||||
Kernel
|
||||
KernelHeaders
|
||||
KernelSource
|
||||
Kmod
|
||||
LibXau
|
||||
Libexpat
|
||||
Libiconv
|
||||
Libpsl
|
||||
Libffi
|
||||
Libgd
|
||||
@@ -49,25 +61,35 @@ const (
|
||||
Make
|
||||
Meson
|
||||
Mksh
|
||||
MuslFts
|
||||
MuslObstack
|
||||
NSS
|
||||
NSSCACert
|
||||
Ncurses
|
||||
Ninja
|
||||
OpenSSL
|
||||
PCRE2
|
||||
Packaging
|
||||
Patch
|
||||
Perl
|
||||
PkgConfig
|
||||
Pluggy
|
||||
Procps
|
||||
PyTest
|
||||
Pygments
|
||||
Python
|
||||
QEMU
|
||||
Rsync
|
||||
Sed
|
||||
Setuptools
|
||||
SquashfsTools
|
||||
TamaGo
|
||||
Tar
|
||||
Texinfo
|
||||
Toybox
|
||||
toyboxEarly
|
||||
Unzip
|
||||
utilMacros
|
||||
UtilLinux
|
||||
Wayland
|
||||
WaylandProtocols
|
||||
XCB
|
||||
@@ -75,13 +97,19 @@ const (
|
||||
Xproto
|
||||
XZ
|
||||
Zlib
|
||||
Zstd
|
||||
|
||||
buildcatrust
|
||||
utilMacros
|
||||
|
||||
// gcc is a hacked-to-pieces GCC toolchain meant for use in intermediate
|
||||
// stages only. This preset and its direct output must never be exposed.
|
||||
gcc
|
||||
|
||||
// Stage0 is a tarball containing all compile-time dependencies of artifacts
|
||||
// part of the [Std] toolchain.
|
||||
Stage0
|
||||
|
||||
// _presetEnd is the total number of presets and does not denote a preset.
|
||||
_presetEnd
|
||||
)
|
||||
@@ -108,19 +136,27 @@ func (t Toolchain) Load(p PArtifact) pkg.Artifact {
|
||||
func ResolveName(name string) (p PArtifact, ok bool) {
|
||||
p, ok = map[string]PArtifact{
|
||||
"acl": ACL,
|
||||
"argp-standalone": ArgpStandalone,
|
||||
"attr": Attr,
|
||||
"autoconf": Autoconf,
|
||||
"automake": Automake,
|
||||
"bc": BC,
|
||||
"bash": Bash,
|
||||
"binutils": Binutils,
|
||||
"bison": Bison,
|
||||
"bzip2": Bzip2,
|
||||
"cmake": CMake,
|
||||
"coreutils": Coreutils,
|
||||
"curl": Curl,
|
||||
"dtc": DTC,
|
||||
"diffutils": Diffutils,
|
||||
"elfutils": Elfutils,
|
||||
"findutils": Findutils,
|
||||
"flex": Flex,
|
||||
"fuse": Fuse,
|
||||
"gawk": Gawk,
|
||||
"gmp": GMP,
|
||||
"glib": GLib,
|
||||
"gawk": Gawk,
|
||||
"gettext": Gettext,
|
||||
"git": Git,
|
||||
"go": Go,
|
||||
@@ -130,9 +166,13 @@ func ResolveName(name string) (p PArtifact, ok bool) {
|
||||
"hakurei": Hakurei,
|
||||
"hakurei-dist": HakureiDist,
|
||||
"iniconfig": IniConfig,
|
||||
"kernel": Kernel,
|
||||
"kernel-headers": KernelHeaders,
|
||||
"kernel-source": KernelSource,
|
||||
"kmod": Kmod,
|
||||
"libXau": LibXau,
|
||||
"libexpat": Libexpat,
|
||||
"libiconv": Libiconv,
|
||||
"libpsl": Libpsl,
|
||||
"libseccomp": Libseccomp,
|
||||
"libucontext": Libucontext,
|
||||
@@ -146,23 +186,34 @@ func ResolveName(name string) (p PArtifact, ok bool) {
|
||||
"make": Make,
|
||||
"meson": Meson,
|
||||
"mksh": Mksh,
|
||||
"musl-fts": MuslFts,
|
||||
"musl-obstack": MuslObstack,
|
||||
"nss": NSS,
|
||||
"nss-cacert": NSSCACert,
|
||||
"ncurses": Ncurses,
|
||||
"ninja": Ninja,
|
||||
"openssl": OpenSSL,
|
||||
"pcre2": PCRE2,
|
||||
"packaging": Packaging,
|
||||
"patch": Patch,
|
||||
"perl": Perl,
|
||||
"pkg-config": PkgConfig,
|
||||
"pluggy": Pluggy,
|
||||
"procps": Procps,
|
||||
"pytest": PyTest,
|
||||
"pygments": Pygments,
|
||||
"python": Python,
|
||||
"qemu": QEMU,
|
||||
"rsync": Rsync,
|
||||
"sed": Sed,
|
||||
"setuptools": Setuptools,
|
||||
"squashfs-tools": SquashfsTools,
|
||||
"tamago": TamaGo,
|
||||
"tar": Tar,
|
||||
"texinfo": Texinfo,
|
||||
"toybox": Toybox,
|
||||
"unzip": Unzip,
|
||||
"util-linux": UtilLinux,
|
||||
"wayland": Wayland,
|
||||
"wayland-protocols": WaylandProtocols,
|
||||
"xcb": XCB,
|
||||
@@ -170,6 +221,7 @@ func ResolveName(name string) (p PArtifact, ok bool) {
|
||||
"xproto": Xproto,
|
||||
"xz": XZ,
|
||||
"zlib": Zlib,
|
||||
"zstd": Zstd,
|
||||
}[name]
|
||||
return
|
||||
}
|
||||
|
||||
27
internal/rosa/argp-standalone.go
Normal file
27
internal/rosa/argp-standalone.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newArgpStandalone() pkg.Artifact {
|
||||
const (
|
||||
version = "1.3"
|
||||
checksum = "vtW0VyO2pJ-hPyYmDI2zwSLS8QL0sPAUKC1t3zNYbwN2TmsaE-fADhaVtNd3eNFl"
|
||||
)
|
||||
return t.NewViaMake("argp-standalone", version, pkg.NewHTTPGetTar(
|
||||
nil, "http://www.lysator.liu.se/~nisse/misc/"+
|
||||
"argp-standalone-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &MakeAttr{
|
||||
Env: []string{
|
||||
"CC=cc -std=gnu89 -fPIC",
|
||||
},
|
||||
ScriptInstall: `
|
||||
install -D -m644 /usr/src/argp-standalone/argp.h /work/system/include/argp.h
|
||||
install -D -m755 libargp.a /work/system/lib/libargp.a
|
||||
`,
|
||||
},
|
||||
t.Load(Diffutils),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[ArgpStandalone] = Toolchain.newArgpStandalone }
|
||||
27
internal/rosa/bzip2.go
Normal file
27
internal/rosa/bzip2.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newBzip2() pkg.Artifact {
|
||||
const (
|
||||
version = "1.0.8"
|
||||
checksum = "cTLykcco7boom-s05H1JVsQi1AtChYL84nXkg_92Dm1Xt94Ob_qlMg_-NSguIK-c"
|
||||
)
|
||||
return t.NewViaMake("bzip2", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://sourceware.org/pub/bzip2/bzip2-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &MakeAttr{
|
||||
Writable: true,
|
||||
SkipConfigure: true,
|
||||
SkipCheck: true,
|
||||
InPlace: true,
|
||||
|
||||
ScriptEarly: "cd /usr/src/bzip2",
|
||||
Make: []string{
|
||||
"CC=cc",
|
||||
},
|
||||
ScriptInstall: "make PREFIX=/work/system install",
|
||||
})
|
||||
}
|
||||
func init() { artifactsF[Bzip2] = Toolchain.newBzip2 }
|
||||
@@ -13,19 +13,7 @@ func (t Toolchain) newCMake() pkg.Artifact {
|
||||
version = "4.2.1"
|
||||
checksum = "Y3OdbMsob6Xk2y1DCME6z4Fryb5_TkFD7knRT8dTNIRtSqbiCJyyDN9AxggN_I75"
|
||||
)
|
||||
return t.New("cmake-"+version, 0, []pkg.Artifact{
|
||||
t.Load(Make),
|
||||
t.Load(KernelHeaders),
|
||||
}, nil, nil, `
|
||||
cd "$(mktemp -d)"
|
||||
/usr/src/cmake/bootstrap \
|
||||
--prefix=/system \
|
||||
--parallel="$(nproc)" \
|
||||
-- \
|
||||
-DCMAKE_USE_OPENSSL=OFF
|
||||
make "-j$(nproc)"
|
||||
make DESTDIR=/work install
|
||||
`, pkg.Path(AbsUsrSrc.Append("cmake"), true, t.NewPatchedSource(
|
||||
return t.NewViaMake("cmake", version, t.NewPatchedSource(
|
||||
// expected to be writable in the copy made during bootstrap
|
||||
"cmake", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/Kitware/CMake/releases/download/"+
|
||||
@@ -33,13 +21,30 @@ make DESTDIR=/work install
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), false,
|
||||
)))
|
||||
), &MakeAttr{
|
||||
OmitDefaults: true,
|
||||
|
||||
SkipConfigure: true,
|
||||
ScriptConfigured: `
|
||||
/usr/src/cmake/bootstrap \
|
||||
--prefix=/system \
|
||||
--parallel="$(nproc)" \
|
||||
-- \
|
||||
-DCMAKE_USE_OPENSSL=OFF
|
||||
`,
|
||||
SkipCheck: true,
|
||||
},
|
||||
t.Load(KernelHeaders),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[CMake] = Toolchain.newCMake }
|
||||
|
||||
// CMakeAttr holds the project-specific attributes that will be applied to a new
|
||||
// [pkg.Artifact] compiled via [CMake].
|
||||
type CMakeAttr struct {
|
||||
// Joined with name with a dash if non-empty.
|
||||
Variant string
|
||||
|
||||
// Path elements joined with source.
|
||||
Append []string
|
||||
// Use source tree as scratch space.
|
||||
@@ -67,12 +72,12 @@ type CMakeAttr struct {
|
||||
|
||||
// NewViaCMake returns a [pkg.Artifact] for compiling and installing via [CMake].
|
||||
func (t Toolchain) NewViaCMake(
|
||||
name, version, variant string,
|
||||
name, version string,
|
||||
source pkg.Artifact,
|
||||
attr *CMakeAttr,
|
||||
extra ...pkg.Artifact,
|
||||
) pkg.Artifact {
|
||||
if name == "" || version == "" || variant == "" {
|
||||
if name == "" || version == "" {
|
||||
panic("names must be non-empty")
|
||||
}
|
||||
if attr == nil {
|
||||
@@ -96,8 +101,13 @@ func (t Toolchain) NewViaCMake(
|
||||
prefix = AbsSystem
|
||||
}
|
||||
|
||||
rname := name
|
||||
if attr.Variant != "" {
|
||||
rname += "-" + attr.Variant
|
||||
}
|
||||
|
||||
sourcePath := AbsUsrSrc.Append(name)
|
||||
return t.New(name+"-"+variant+"-"+version, attr.Flag, stage3Concat(t, extra,
|
||||
return t.New(rname+"-"+version, attr.Flag, stage0Concat(t, extra,
|
||||
t.Load(CMake),
|
||||
t.Load(Ninja),
|
||||
), nil, slices.Concat([]string{
|
||||
|
||||
34
internal/rosa/dtc.go
Normal file
34
internal/rosa/dtc.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newDTC() pkg.Artifact {
|
||||
const (
|
||||
version = "1.7.2"
|
||||
checksum = "vUoiRynPyYRexTpS6USweT5p4SVHvvVJs8uqFkkVD-YnFjwf6v3elQ0-Etrh00Dt"
|
||||
)
|
||||
return t.NewViaMeson("dtc", version, t.NewPatchedSource(
|
||||
"dtc", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://git.kernel.org/pub/scm/utils/dtc/dtc.git/snapshot/"+
|
||||
"dtc-v"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), false,
|
||||
), &MesonAttr{
|
||||
// works around buggy test:
|
||||
// fdtdump-runtest.sh /usr/src/dtc/tests/fdtdump.dts
|
||||
Writable: true,
|
||||
|
||||
Configure: [][2]string{
|
||||
{"Dyaml", "disabled"},
|
||||
{"Dstatic-build", "true"},
|
||||
},
|
||||
},
|
||||
t.Load(Flex),
|
||||
t.Load(Bison),
|
||||
t.Load(M4),
|
||||
t.Load(Coreutils),
|
||||
t.Load(Diffutils),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[DTC] = Toolchain.newDTC }
|
||||
41
internal/rosa/elfutils.go
Normal file
41
internal/rosa/elfutils.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newElfutils() pkg.Artifact {
|
||||
const (
|
||||
version = "0.194"
|
||||
checksum = "Q3XUygUPv9vR1TkWucwUsQ8Kb1_F6gzk-KMPELr3cC_4AcTrprhVPMvN0CKkiYRa"
|
||||
)
|
||||
return t.NewViaMake("elfutils", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://sourceware.org/elfutils/ftp/"+
|
||||
version+"/elfutils-"+version+".tar.bz2",
|
||||
mustDecode(checksum),
|
||||
pkg.TarBzip2,
|
||||
), &MakeAttr{
|
||||
Env: []string{
|
||||
"CC=cc" +
|
||||
// nonstandard glibc extension
|
||||
" -DFNM_EXTMATCH=0",
|
||||
},
|
||||
|
||||
// nonstandard glibc extension
|
||||
SkipCheck: true,
|
||||
|
||||
Configure: [][2]string{
|
||||
{"enable-deterministic-archives"},
|
||||
},
|
||||
},
|
||||
t.Load(M4),
|
||||
t.Load(PkgConfig),
|
||||
|
||||
t.Load(Zlib),
|
||||
t.Load(Bzip2),
|
||||
t.Load(Zstd),
|
||||
t.Load(ArgpStandalone),
|
||||
t.Load(MuslFts),
|
||||
t.Load(MuslObstack),
|
||||
t.Load(KernelHeaders),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Elfutils] = Toolchain.newElfutils }
|
||||
21
internal/rosa/flex.go
Normal file
21
internal/rosa/flex.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
func (t Toolchain) newFlex() pkg.Artifact {
|
||||
const (
|
||||
version = "2.6.4"
|
||||
checksum = "p9POjQU7VhgOf3x5iFro8fjhy0NOanvA7CTeuWS_veSNgCixIJshTrWVkc5XLZkB"
|
||||
)
|
||||
return t.NewViaMake("flex", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/westes/flex/releases/download/"+
|
||||
"v"+version+"/flex-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), nil,
|
||||
t.Load(M4),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Flex] = Toolchain.newFlex }
|
||||
@@ -7,11 +7,23 @@ func (t Toolchain) newFuse() pkg.Artifact {
|
||||
version = "3.18.1"
|
||||
checksum = "COb-BgJRWXLbt9XUkNeuiroQizpMifXqxgieE1SlkMXhs_WGSyJStrmyewAw2hd6"
|
||||
)
|
||||
return t.New("fuse-"+version, 0, []pkg.Artifact{
|
||||
t.Load(Python),
|
||||
t.Load(Meson),
|
||||
t.Load(Ninja),
|
||||
return t.NewViaMeson("fuse", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/libfuse/libfuse/releases/download/"+
|
||||
"fuse-"+version+"/fuse-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &MesonAttr{
|
||||
Configure: [][2]string{
|
||||
{"Ddefault_library", "both"},
|
||||
{"Dtests", "true"},
|
||||
{"Duseroot", "false"},
|
||||
{"Dinitscriptdir", "/system/init.d"},
|
||||
},
|
||||
|
||||
ScriptCompiled: "python3 -m pytest test/",
|
||||
// this project uses pytest
|
||||
SkipCheck: true,
|
||||
},
|
||||
t.Load(IniConfig),
|
||||
t.Load(Packaging),
|
||||
t.Load(Pluggy),
|
||||
@@ -19,27 +31,6 @@ func (t Toolchain) newFuse() pkg.Artifact {
|
||||
t.Load(PyTest),
|
||||
|
||||
t.Load(KernelHeaders),
|
||||
}, nil, nil, `
|
||||
cd "$(mktemp -d)"
|
||||
meson setup \
|
||||
--reconfigure \
|
||||
--buildtype=release \
|
||||
--prefix=/system \
|
||||
--prefer-static \
|
||||
-Dtests=true \
|
||||
-Duseroot=false \
|
||||
-Dinitscriptdir=/system/init.d \
|
||||
-Ddefault_library=both \
|
||||
. /usr/src/fuse
|
||||
meson compile
|
||||
python3 -m pytest test/
|
||||
meson install \
|
||||
--destdir=/work
|
||||
`, pkg.Path(AbsUsrSrc.Append("fuse"), false, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/libfuse/libfuse/releases/download/"+
|
||||
"fuse-"+version+"/fuse-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
)))
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Fuse] = Toolchain.newFuse }
|
||||
|
||||
@@ -23,6 +23,23 @@ chmod +w tests/test-c32ispunct.sh && echo '#!/bin/sh' > tests/test-c32ispunct.sh
|
||||
}
|
||||
func init() { artifactsF[M4] = Toolchain.newM4 }
|
||||
|
||||
func (t Toolchain) newBison() pkg.Artifact {
|
||||
const (
|
||||
version = "3.8.2"
|
||||
checksum = "BhRM6K7URj1LNOkIDCFDctSErLS-Xo5d9ba9seg10o6ACrgC1uNhED7CQPgIY29Y"
|
||||
)
|
||||
return t.NewViaMake("bison", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://ftpmirror.gnu.org/gnu/bison/bison-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), nil,
|
||||
t.Load(M4),
|
||||
t.Load(Diffutils),
|
||||
t.Load(Sed),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Bison] = Toolchain.newBison }
|
||||
|
||||
func (t Toolchain) newSed() pkg.Artifact {
|
||||
const (
|
||||
version = "4.9"
|
||||
@@ -266,6 +283,24 @@ test_disable 'int main(){return 0;}' gnulib-tests/test-lchown.c
|
||||
}
|
||||
func init() { artifactsF[Coreutils] = Toolchain.newCoreutils }
|
||||
|
||||
func (t Toolchain) newTexinfo() pkg.Artifact {
|
||||
const (
|
||||
version = "7.2"
|
||||
checksum = "9EelM5b7QGMAY5DKrAm_El8lofBGuFWlaBPSBhh7l_VQE8054MBmC0KBvGrABqjv"
|
||||
)
|
||||
return t.NewViaMake("texinfo", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://ftpmirror.gnu.org/gnu/texinfo/texinfo-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &MakeAttr{
|
||||
// nonstandard glibc extension
|
||||
SkipCheck: true,
|
||||
},
|
||||
t.Load(Perl),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Texinfo] = Toolchain.newTexinfo }
|
||||
|
||||
func (t Toolchain) newGperf() pkg.Artifact {
|
||||
const (
|
||||
version = "3.3"
|
||||
@@ -351,6 +386,71 @@ echo 'int main(){return 0;}' > tests/xargs/test-sigusr.c
|
||||
}
|
||||
func init() { artifactsF[Findutils] = Toolchain.newFindutils }
|
||||
|
||||
func (t Toolchain) newBC() pkg.Artifact {
|
||||
const (
|
||||
version = "1.08.2"
|
||||
checksum = "8h6f3hjV80XiFs6v9HOPF2KEyg1kuOgn5eeFdVspV05ODBVQss-ey5glc8AmneLy"
|
||||
)
|
||||
return t.NewViaMake("bc", version, t.NewPatchedSource(
|
||||
"bc", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://ftpmirror.gnu.org/gnu/bc/bc-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), false,
|
||||
), &MakeAttr{
|
||||
Writable: true,
|
||||
},
|
||||
t.Load(Perl),
|
||||
t.Load(Texinfo),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[BC] = Toolchain.newBC }
|
||||
|
||||
func (t Toolchain) newLibiconv() pkg.Artifact {
|
||||
const (
|
||||
version = "1.18"
|
||||
checksum = "iV5q3VxP5VPdJ-X7O5OQI4fGm8VjeYb5viLd1L3eAHg26bbHb2_Qn63XPF3ucVZr"
|
||||
)
|
||||
return t.NewViaMake("libiconv", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://ftpmirror.gnu.org/gnu/libiconv/libiconv-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), nil)
|
||||
}
|
||||
func init() { artifactsF[Libiconv] = Toolchain.newLibiconv }
|
||||
|
||||
func (t Toolchain) newTar() pkg.Artifact {
|
||||
const (
|
||||
version = "1.35"
|
||||
checksum = "zSaoSlVUDW0dSfm4sbL4FrXLFR8U40Fh3zY5DWhR5NCIJ6GjU6Kc4VZo2-ZqpBRA"
|
||||
)
|
||||
return t.NewViaMake("tar", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://ftpmirror.gnu.org/gnu/tar/tar-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &MakeAttr{
|
||||
Env: []string{
|
||||
// very expensive
|
||||
"TARTEST_SKIP_LARGE_FILES=1",
|
||||
},
|
||||
Configure: [][2]string{
|
||||
{"disable-acl"},
|
||||
{"without-posix-acls"},
|
||||
{"without-xattrs"},
|
||||
},
|
||||
Make: []string{
|
||||
`TESTSUITEFLAGS="-j$(nproc)"`,
|
||||
},
|
||||
},
|
||||
t.Load(Diffutils),
|
||||
|
||||
t.Load(Gzip),
|
||||
t.Load(Bzip2),
|
||||
t.Load(Zstd),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Tar] = Toolchain.newTar }
|
||||
|
||||
func (t Toolchain) newBinutils() pkg.Artifact {
|
||||
const (
|
||||
version = "2.45"
|
||||
|
||||
@@ -143,7 +143,7 @@ sed -i \
|
||||
go125 := t.newGo(
|
||||
"1.25.7",
|
||||
"fyylHdBVRUobnBjYj3NKBaYPUw3kGmo2mEELiZonOYurPfbarNU1x77B99Fjut7Q",
|
||||
finalEnv, `
|
||||
[]string{"CGO_ENABLED=0"}, `
|
||||
sed -i \
|
||||
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
|
||||
cmd/link/internal/`+runtime.GOARCH+`/obj.go
|
||||
@@ -153,6 +153,17 @@ rm \
|
||||
`, go123,
|
||||
)
|
||||
|
||||
return go125
|
||||
return t.newGo(
|
||||
"1.26.0",
|
||||
"uHLcrgBc0NMcyTMDLRNAZIcOx0RyQlyekSl9xbWSwj3esEFWJysYLfLa3S8p39Nh",
|
||||
finalEnv, `
|
||||
sed -i \
|
||||
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
|
||||
cmd/link/internal/`+runtime.GOARCH+`/obj.go
|
||||
|
||||
rm \
|
||||
os/root_unix_test.go
|
||||
`, go125,
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Go] = Toolchain.newGoLatest }
|
||||
|
||||
55
internal/rosa/gtk.go
Normal file
55
internal/rosa/gtk.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"hakurei.app/container/fhs"
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
func (t Toolchain) newGLib() pkg.Artifact {
|
||||
const (
|
||||
version = "2.86.4"
|
||||
checksum = "AfTjBrrxtXXPL6dFa1LfTe40PyPSth62CoIkM5m_VJTUngGLOFHw6I4XE7RGQE8G"
|
||||
)
|
||||
return t.NewViaMeson("glib", version, pkg.NewHTTPGet(
|
||||
nil, "https://download.gnome.org/sources/glib/"+
|
||||
strings.Join(strings.SplitN(version, ".", 3)[:2], ".")+
|
||||
"/glib-"+version+".tar.xz",
|
||||
mustDecode(checksum),
|
||||
), &MesonAttr{
|
||||
SourceSuffix: ".tar.xz",
|
||||
ScriptEarly: `
|
||||
cd /usr/src/
|
||||
tar xf glib.tar.xz
|
||||
mv glib-` + version + ` glib
|
||||
`,
|
||||
Configure: [][2]string{
|
||||
{"Ddefault_library", "both"},
|
||||
},
|
||||
|
||||
Paths: []pkg.ExecPath{
|
||||
pkg.Path(fhs.AbsEtc.Append(
|
||||
"machine-id",
|
||||
), false, pkg.NewFile(
|
||||
"glib-machine-id",
|
||||
[]byte("ffffffffffffffffffffffffffffffff\n"),
|
||||
)),
|
||||
pkg.Path(AbsSystem.Append(
|
||||
"var/lib/dbus/machine-id",
|
||||
), false, pkg.NewFile(
|
||||
"glib-machine-id",
|
||||
[]byte("fefefefefefefefefefefefefefefefe\n"),
|
||||
)),
|
||||
},
|
||||
},
|
||||
t.Load(XZ),
|
||||
t.Load(Packaging),
|
||||
t.Load(Bash),
|
||||
|
||||
t.Load(PCRE2),
|
||||
t.Load(Libffi),
|
||||
t.Load(Zlib),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[GLib] = Toolchain.newGLib }
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
func (t Toolchain) newHakurei(suffix, script string) pkg.Artifact {
|
||||
const (
|
||||
version = "0.3.4"
|
||||
checksum = "wVwSLo75a2OnH5tgxNWXR_YhiOJUFnYM_9-sJtxAEOKhcPE0BJafs6PU8o5JzyCT"
|
||||
version = "0.3.5"
|
||||
checksum = "6Tn38NLezRD2d3aGdFg5qFfqn8_KvC6HwMKwJMPvaHmVw8xRgxn8B0PObswl2mOk"
|
||||
)
|
||||
return t.New("hakurei"+suffix+"-"+version, 0, []pkg.Artifact{
|
||||
t.Load(Go),
|
||||
@@ -44,213 +44,45 @@ chmod -R +w /usr/src/hakurei
|
||||
cd /usr/src/hakurei
|
||||
|
||||
HAKUREI_VERSION='v`+version+`'
|
||||
`+script, pkg.Path(AbsUsrSrc.Append("hakurei"), true, t.NewPatchedSource("hakurei", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://git.gensokyo.uk/security/hakurei/archive/"+
|
||||
"v"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), true, [2]string{"dist-00-tests", `From 67e453f5c4de915de23ecbe5980e595758f0f2fb Mon Sep 17 00:00:00 2001
|
||||
From: Ophestra <cat@gensokyo.uk>
|
||||
Date: Tue, 27 Jan 2026 06:49:48 +0900
|
||||
Subject: [PATCH] dist: run tests
|
||||
`+script, pkg.Path(AbsUsrSrc.Append("hakurei"), true, t.NewPatchedSource(
|
||||
"hakurei", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://git.gensokyo.uk/security/hakurei/archive/"+
|
||||
"v"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), true, [2]string{"createTemp-error-injection", `diff --git a/container/dispatcher_test.go b/container/dispatcher_test.go
|
||||
index 5de37fc..fe0c4db 100644
|
||||
--- a/container/dispatcher_test.go
|
||||
+++ b/container/dispatcher_test.go
|
||||
@@ -238,8 +238,11 @@ func sliceAddr[S any](s []S) *[]S { return &s }
|
||||
|
||||
This used to be impossible due to nix jank which has been addressed.
|
||||
func newCheckedFile(t *testing.T, name, wantData string, closeErr error) osFile {
|
||||
f := &checkedOsFile{t: t, name: name, want: wantData, closeErr: closeErr}
|
||||
- // check happens in Close, and cleanup is not guaranteed to run, so relying on it for sloppy implementations will cause sporadic test results
|
||||
- f.cleanup = runtime.AddCleanup(f, func(name string) { f.t.Fatalf("checkedOsFile %s became unreachable without a call to Close", name) }, f.name)
|
||||
+ // check happens in Close, and cleanup is not guaranteed to run, so relying
|
||||
+ // on it for sloppy implementations will cause sporadic test results
|
||||
+ f.cleanup = runtime.AddCleanup(f, func(name string) {
|
||||
+ panic("checkedOsFile " + name + " became unreachable without a call to Close")
|
||||
+ }, name)
|
||||
return f
|
||||
}
|
||||
|
||||
Signed-off-by: Ophestra <cat@gensokyo.uk>
|
||||
---
|
||||
dist/release.sh | 21 ++++++++++++++++-----
|
||||
flake.nix | 32 ++++++++++++++++++++------------
|
||||
internal/acl/acl_test.go | 2 +-
|
||||
package.nix | 2 +-
|
||||
4 files changed, 38 insertions(+), 19 deletions(-)
|
||||
diff --git a/container/initplace_test.go b/container/initplace_test.go
|
||||
index afeddbe..1c2f20b 100644
|
||||
--- a/container/initplace_test.go
|
||||
+++ b/container/initplace_test.go
|
||||
@@ -21,7 +21,7 @@ func TestTmpfileOp(t *testing.T) {
|
||||
Path: samplePath,
|
||||
Data: sampleData,
|
||||
}, nil, nil, []stub.Call{
|
||||
- call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, newCheckedFile(t, "tmp.32768", sampleDataString, nil), stub.UniqueError(5)),
|
||||
+ call("createTemp", stub.ExpectArgs{"/", "tmp.*"}, (*checkedOsFile)(nil), stub.UniqueError(5)),
|
||||
}, stub.UniqueError(5)},
|
||||
|
||||
diff --git a/dist/release.sh b/dist/release.sh
|
||||
index 4dcb278..0ba9104 100755
|
||||
--- a/dist/release.sh
|
||||
+++ b/dist/release.sh
|
||||
@@ -2,19 +2,30 @@
|
||||
cd "$(dirname -- "$0")/.."
|
||||
VERSION="${HAKUREI_VERSION:-untagged}"
|
||||
pname="hakurei-${VERSION}"
|
||||
-out="dist/${pname}"
|
||||
+out="${DESTDIR:-dist}/${pname}"
|
||||
|
||||
+echo '# Preparing distribution files.'
|
||||
mkdir -p "${out}"
|
||||
cp -v "README.md" "dist/hsurc.default" "dist/install.sh" "${out}"
|
||||
cp -rv "dist/comp" "${out}"
|
||||
+echo
|
||||
|
||||
+echo '# Building hakurei.'
|
||||
go generate ./...
|
||||
-go build -trimpath -v -o "${out}/bin/" -ldflags "-s -w -buildid= -extldflags '-static'
|
||||
+go build -trimpath -v -o "${out}/bin/" -ldflags "-s -w
|
||||
+ -buildid= -extldflags '-static'
|
||||
-X hakurei.app/internal/info.buildVersion=${VERSION}
|
||||
-X hakurei.app/internal/info.hakureiPath=/usr/bin/hakurei
|
||||
-X hakurei.app/internal/info.hsuPath=/usr/bin/hsu
|
||||
-X main.hakureiPath=/usr/bin/hakurei" ./...
|
||||
+echo
|
||||
|
||||
-rm -f "./${out}.tar.gz" && tar -C dist -czf "${out}.tar.gz" "${pname}"
|
||||
-rm -rf "./${out}"
|
||||
-(cd dist && sha512sum "${pname}.tar.gz" > "${pname}.tar.gz.sha512")
|
||||
+echo '# Testing hakurei.'
|
||||
+go test -ldflags='-buildid= -extldflags=-static' ./...
|
||||
+echo
|
||||
+
|
||||
+echo '# Creating distribution.'
|
||||
+rm -f "${out}.tar.gz" && tar -C "${out}/.." -vczf "${out}.tar.gz" "${pname}"
|
||||
+rm -rf "${out}"
|
||||
+(cd "${out}/.." && sha512sum "${pname}.tar.gz" > "${pname}.tar.gz.sha512")
|
||||
+echo
|
||||
diff --git a/flake.nix b/flake.nix
|
||||
index 9e09c61..2340b92 100644
|
||||
--- a/flake.nix
|
||||
+++ b/flake.nix
|
||||
@@ -143,19 +143,27 @@
|
||||
"bin/mount.fuse.sharefs" = "${hakurei}/libexec/sharefs";
|
||||
};
|
||||
|
||||
- dist = pkgs.runCommand "${hakurei.name}-dist" { buildInputs = hakurei.targetPkgs ++ [ pkgs.pkgsStatic.musl ]; } ''
|
||||
- # go requires XDG_CACHE_HOME for the build cache
|
||||
- export XDG_CACHE_HOME="$(mktemp -d)"
|
||||
+ dist =
|
||||
+ pkgs.runCommand "${hakurei.name}-dist"
|
||||
+ {
|
||||
+ buildInputs = hakurei.targetPkgs ++ [
|
||||
+ pkgs.pkgsStatic.musl
|
||||
+ ];
|
||||
+ }
|
||||
+ ''
|
||||
+ cd $(mktemp -d) \
|
||||
+ && cp -r ${hakurei.src}/. . \
|
||||
+ && chmod +w cmd && cp -r ${hsu.src}/. cmd/hsu/ \
|
||||
+ && chmod -R +w .
|
||||
|
||||
- # get a different workdir as go does not like /build
|
||||
- cd $(mktemp -d) \
|
||||
- && cp -r ${hakurei.src}/. . \
|
||||
- && chmod +w cmd && cp -r ${hsu.src}/. cmd/hsu/ \
|
||||
- && chmod -R +w .
|
||||
-
|
||||
- export HAKUREI_VERSION="v${hakurei.version}"
|
||||
- CC="clang -O3 -Werror" ./dist/release.sh && mkdir $out && cp -v "dist/hakurei-$HAKUREI_VERSION.tar.gz"* $out
|
||||
- '';
|
||||
+ CC="musl-clang -O3 -Werror -Qunused-arguments" \
|
||||
+ GOCACHE="$(mktemp -d)" \
|
||||
+ HAKUREI_TEST_SKIP_ACL=1 \
|
||||
+ PATH="${pkgs.pkgsStatic.musl.bin}/bin:$PATH" \
|
||||
+ DESTDIR="$out" \
|
||||
+ HAKUREI_VERSION="v${hakurei.version}" \
|
||||
+ ./dist/release.sh
|
||||
+ '';
|
||||
}
|
||||
);
|
||||
|
||||
diff --git a/internal/acl/acl_test.go b/internal/acl/acl_test.go
|
||||
index af6da55..19ce45a 100644
|
||||
--- a/internal/acl/acl_test.go
|
||||
+++ b/internal/acl/acl_test.go
|
||||
@@ -24,7 +24,7 @@ var (
|
||||
)
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
- if os.Getenv("GO_TEST_SKIP_ACL") == "1" {
|
||||
+ if os.Getenv("HAKUREI_TEST_SKIP_ACL") == "1" {
|
||||
t.Skip("acl test skipped")
|
||||
}
|
||||
|
||||
diff --git a/package.nix b/package.nix
|
||||
index 00c4401..2eaa2ec 100644
|
||||
--- a/package.nix
|
||||
+++ b/package.nix
|
||||
@@ -89,7 +89,7 @@ buildGoModule rec {
|
||||
CC = "clang -O3 -Werror";
|
||||
|
||||
# nix build environment does not allow acls
|
||||
- GO_TEST_SKIP_ACL = 1;
|
||||
+ HAKUREI_TEST_SKIP_ACL = 1;
|
||||
};
|
||||
|
||||
buildInputs = [`}, [2]string{"container-tests", `From bf14a412e47344fff2681f4b24d1ecc7415bfcb0 Mon Sep 17 00:00:00 2001
|
||||
From: Ophestra <cat@gensokyo.uk>
|
||||
Date: Sat, 31 Jan 2026 10:59:56 +0900
|
||||
Subject: [PATCH] container: fix host-dependent test cases
|
||||
|
||||
These are not fully controlled by hakurei and may change depending on host configuration.
|
||||
|
||||
Signed-off-by: Ophestra <cat@gensokyo.uk>
|
||||
---
|
||||
container/container_test.go | 27 +++++++++++++++------------
|
||||
1 file changed, 15 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/container/container_test.go b/container/container_test.go
|
||||
index d737a18..98713cb 100644
|
||||
--- a/container/container_test.go
|
||||
+++ b/container/container_test.go
|
||||
@@ -275,12 +275,12 @@ var containerTestCases = []struct {
|
||||
),
|
||||
earlyMnt(
|
||||
ent("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", ignore),
|
||||
- ent("/null", "/dev/null", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
- ent("/zero", "/dev/zero", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
- ent("/full", "/dev/full", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
- ent("/random", "/dev/random", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
- ent("/urandom", "/dev/urandom", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
- ent("/tty", "/dev/tty", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/null", "/dev/null", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/zero", "/dev/zero", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/full", "/dev/full", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/random", "/dev/random", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/urandom", "/dev/urandom", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/tty", "/dev/tty", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
ent("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
|
||||
ent("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"),
|
||||
ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
|
||||
@@ -293,12 +293,12 @@ var containerTestCases = []struct {
|
||||
),
|
||||
earlyMnt(
|
||||
ent("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", ignore),
|
||||
- ent("/null", "/dev/null", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
- ent("/zero", "/dev/zero", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
- ent("/full", "/dev/full", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
- ent("/random", "/dev/random", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
- ent("/urandom", "/dev/urandom", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
- ent("/tty", "/dev/tty", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/null", "/dev/null", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/zero", "/dev/zero", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/full", "/dev/full", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/random", "/dev/random", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/urandom", "/dev/urandom", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
+ ent("/tty", "/dev/tty", ignore, "devtmpfs", "devtmpfs", ignore),
|
||||
ent("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
|
||||
ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
|
||||
),
|
||||
@@ -696,6 +696,9 @@ func init() {
|
||||
mnt[i].VfsOptstr = strings.TrimSuffix(mnt[i].VfsOptstr, ",relatime")
|
||||
mnt[i].VfsOptstr = strings.TrimSuffix(mnt[i].VfsOptstr, ",noatime")
|
||||
|
||||
+ cur.FsOptstr = strings.Replace(cur.FsOptstr, ",seclabel", "", 1)
|
||||
+ mnt[i].FsOptstr = strings.Replace(mnt[i].FsOptstr, ",seclabel", "", 1)
|
||||
+
|
||||
if !cur.EqualWithIgnore(mnt[i], "\x00") {
|
||||
fail = true
|
||||
log.Printf("[FAIL] %s", cur)`}, [2]string{"dist-01-tarball-name", `diff --git a/dist/release.sh b/dist/release.sh
|
||||
index 0ba9104..2990ee1 100755
|
||||
--- a/dist/release.sh
|
||||
+++ b/dist/release.sh
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh -e
|
||||
cd "$(dirname -- "$0")/.."
|
||||
VERSION="${HAKUREI_VERSION:-untagged}"
|
||||
-pname="hakurei-${VERSION}"
|
||||
+pname="hakurei-${VERSION}-$(go env GOARCH)"
|
||||
out="${DESTDIR:-dist}/${pname}"
|
||||
|
||||
echo '# Preparing distribution files.'
|
||||
`}),
|
||||
), pkg.Path(AbsUsrSrc.Append("hostname", "main.go"), false, pkg.NewFile(
|
||||
{"Write", &Params{ParentPerm: 0700}, &TmpfileOp{
|
||||
`},
|
||||
)), pkg.Path(AbsUsrSrc.Append("hostname", "main.go"), false, pkg.NewFile(
|
||||
"hostname.go",
|
||||
[]byte(`
|
||||
package main
|
||||
|
||||
@@ -1,44 +1,123 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"slices"
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
const kernelVersion = "6.12.73"
|
||||
|
||||
var kernelSource = pkg.NewHTTPGetTar(
|
||||
nil, "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/"+
|
||||
"snapshot/linux-"+kernelVersion+".tar.gz",
|
||||
mustDecode("29oUBJKF1ULIv1-XQLpEUUc3LgjUSmyvOSskG37MYUcBlBjMk7RcbCTLrD7UfSM6"),
|
||||
pkg.TarGzip,
|
||||
)
|
||||
|
||||
// newKernel is a helper for interacting with Kbuild.
|
||||
func (t Toolchain) newKernel(
|
||||
flag int,
|
||||
patches [][2]string,
|
||||
script string,
|
||||
extra ...pkg.Artifact,
|
||||
) pkg.Artifact {
|
||||
const (
|
||||
version = "6.18.5"
|
||||
checksum = "-V1e1WWl7HuePkmm84sSKF7nLuHfUs494uNMzMqXEyxcNE_PUE0FICL0oGWn44mM"
|
||||
)
|
||||
return t.New("kernel-"+version, flag, slices.Concat([]pkg.Artifact{
|
||||
t.Load(Make),
|
||||
}, extra), nil, nil, `
|
||||
export LLVM=1
|
||||
export HOSTLDFLAGS="${LDFLAGS}"
|
||||
cd /usr/src/linux
|
||||
`+script, pkg.Path(AbsUsrSrc.Append("linux"), true, t.NewPatchedSource(
|
||||
"kernel", version, pkg.NewHTTPGetTar(
|
||||
nil,
|
||||
"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/"+
|
||||
"snapshot/linux-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), false, patches...,
|
||||
)))
|
||||
func (t Toolchain) newKernelSource() pkg.Artifact {
|
||||
return t.New("kernel-"+kernelVersion+"-src", 0, nil, nil, nil, `
|
||||
mkdir -p /work/usr/src/
|
||||
cp -r /usr/src/linux /work/usr/src/
|
||||
chmod -R +w /work/usr/src/linux/
|
||||
`, pkg.Path(AbsUsrSrc.Append("linux"), false, kernelSource))
|
||||
}
|
||||
func init() { artifactsF[KernelSource] = Toolchain.newKernelSource }
|
||||
|
||||
func (t Toolchain) newKernelHeaders() pkg.Artifact {
|
||||
return t.newKernel(TEarly, nil, `
|
||||
make "-j$(nproc)" \
|
||||
INSTALL_HDR_PATH=/work/system \
|
||||
headers_install
|
||||
`, t.Load(Rsync))
|
||||
return t.NewViaMake("kernel-headers", kernelVersion, kernelSource, &MakeAttr{
|
||||
SkipConfigure: true,
|
||||
|
||||
SkipCheck: true,
|
||||
Make: []string{
|
||||
"-f /usr/src/kernel-headers/Makefile",
|
||||
"O=/tmp/kbuild",
|
||||
"LLVM=1",
|
||||
`HOSTLDFLAGS="${LDFLAGS}"`,
|
||||
"INSTALL_HDR_PATH=/work/system",
|
||||
"headers_install",
|
||||
},
|
||||
ScriptInstall: "\n",
|
||||
|
||||
Flag: TEarly,
|
||||
},
|
||||
t.Load(Rsync),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[KernelHeaders] = Toolchain.newKernelHeaders }
|
||||
|
||||
func (t Toolchain) newKernel() pkg.Artifact {
|
||||
return t.NewViaMake("kernel", kernelVersion, kernelSource, &MakeAttr{
|
||||
OmitDefaults: true,
|
||||
SkipConfigure: true,
|
||||
|
||||
// Build, install, and boot kernel before running kselftest on it.
|
||||
SkipCheck: true,
|
||||
|
||||
Env: []string{
|
||||
"PATH=/system/sbin",
|
||||
},
|
||||
ScriptEarly: `
|
||||
install -Dm0400 \
|
||||
/usr/src/.config \
|
||||
/tmp/kbuild/.config
|
||||
install -Dm0500 \
|
||||
/usr/src/.installkernel \
|
||||
/sbin/installkernel
|
||||
`,
|
||||
Make: []string{
|
||||
"-f /usr/src/kernel/Makefile",
|
||||
"O=/tmp/kbuild",
|
||||
|
||||
"LLVM=1",
|
||||
"KBUILD_BUILD_VERSION='1-Rosa'",
|
||||
"KBUILD_BUILD_TIMESTAMP='2106-02-07 06:28:15 UTC'",
|
||||
"KBUILD_BUILD_USER=kbuild",
|
||||
"KBUILD_BUILD_HOST=localhost",
|
||||
"all",
|
||||
},
|
||||
ScriptInstall: `
|
||||
make \
|
||||
"-j$(nproc)" \
|
||||
-f /usr/src/kernel/Makefile \
|
||||
O=/tmp/kbuild \
|
||||
LLVM=1 \
|
||||
INSTALL_PATH=/work \
|
||||
install \
|
||||
INSTALL_MOD_PATH=/work \
|
||||
modules_install
|
||||
rm -v /work/lib/modules/` + kernelVersion + `/build
|
||||
`,
|
||||
|
||||
Paths: []pkg.ExecPath{
|
||||
pkg.Path(AbsUsrSrc.Append(
|
||||
".config",
|
||||
), false, pkg.NewFile(".config", kernelConfig)),
|
||||
pkg.Path(AbsUsrSrc.Append(
|
||||
".installkernel",
|
||||
), false, pkg.NewFile("installkernel", []byte(`#!/bin/sh -e
|
||||
echo "Installing linux $1..."
|
||||
cp -av "$2" "$4"
|
||||
cp -av "$3" "$4"
|
||||
`))),
|
||||
},
|
||||
},
|
||||
t.Load(Flex),
|
||||
t.Load(Bison),
|
||||
t.Load(M4),
|
||||
t.Load(Tar),
|
||||
t.Load(Perl),
|
||||
t.Load(BC),
|
||||
t.Load(Sed),
|
||||
t.Load(Gawk),
|
||||
t.Load(Coreutils),
|
||||
t.Load(Diffutils),
|
||||
|
||||
t.Load(XZ),
|
||||
t.Load(Zlib),
|
||||
t.Load(Gzip),
|
||||
t.Load(Bzip2),
|
||||
t.Load(Zstd),
|
||||
t.Load(Kmod),
|
||||
t.Load(Elfutils),
|
||||
t.Load(OpenSSL),
|
||||
t.Load(KernelHeaders),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Kernel] = Toolchain.newKernel }
|
||||
|
||||
12512
internal/rosa/kernel_amd64.config
Normal file
12512
internal/rosa/kernel_amd64.config
Normal file
File diff suppressed because it is too large
Load Diff
6
internal/rosa/kernel_amd64.go
Normal file
6
internal/rosa/kernel_amd64.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package rosa
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed kernel_amd64.config
|
||||
var kernelConfig []byte
|
||||
33
internal/rosa/kmod.go
Normal file
33
internal/rosa/kmod.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newKmod() pkg.Artifact {
|
||||
const (
|
||||
version = "34.2"
|
||||
checksum = "0K7POeTKxMhExsaTsnKAC6LUNsRSfe6sSZxWONPbOu-GI_pXOw3toU_BIoqfBhJV"
|
||||
)
|
||||
return t.NewViaMeson("kmod", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://www.kernel.org/pub/linux/utils/kernel/"+
|
||||
"kmod/kmod-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &MesonAttr{
|
||||
Configure: [][2]string{
|
||||
{"Dsysconfdir", "/system/etc"},
|
||||
{"Dbashcompletiondir", "no"},
|
||||
{"Dfishcompletiondir", "no"},
|
||||
{"Dxz", "disabled"},
|
||||
{"Dmanpages", "false"},
|
||||
},
|
||||
|
||||
// makes assumptions about the running kernel
|
||||
SkipCheck: true,
|
||||
},
|
||||
t.Load(Zlib),
|
||||
t.Load(Zstd),
|
||||
t.Load(OpenSSL),
|
||||
t.Load(KernelHeaders),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Kmod] = Toolchain.newKmod }
|
||||
@@ -7,34 +7,24 @@ func (t Toolchain) newLibucontext() pkg.Artifact {
|
||||
version = "1.5"
|
||||
checksum = "Ggk7FMmDNBdCx1Z9PcNWWW6LSpjGYssn2vU0GK5BLXJYw7ZxZbA2m_eSgT9TFnIG"
|
||||
)
|
||||
return t.New("libucontext", 0, []pkg.Artifact{
|
||||
t.Load(Make),
|
||||
}, nil, []string{
|
||||
"ARCH=" + linuxArch(),
|
||||
}, `
|
||||
cd /usr/src/libucontext
|
||||
make check
|
||||
make DESTDIR=/work install
|
||||
`, pkg.Path(AbsUsrSrc.Append("libucontext"), true,
|
||||
t.NewPatchedSource("libucontext", version, pkg.NewHTTPGetTar(
|
||||
return t.NewViaMake("libucontext", version, t.NewPatchedSource(
|
||||
"libucontext", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/kaniini/libucontext/archive/refs/tags/"+
|
||||
"libucontext-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), true, [2]string{"rosa-prefix", `diff --git a/Makefile b/Makefile
|
||||
index c80e574..4a8c1d3 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -17,7 +17,7 @@ ifeq ($(ARCH),$(filter $(ARCH),arm64))
|
||||
override ARCH = aarch64
|
||||
endif
|
||||
), false,
|
||||
), &MakeAttr{
|
||||
Writable: true,
|
||||
OmitDefaults: true,
|
||||
SkipConfigure: true,
|
||||
InPlace: true,
|
||||
|
||||
-prefix = /usr
|
||||
+prefix = /system
|
||||
libdir = ${prefix}/lib
|
||||
shared_libdir = ${libdir}
|
||||
static_libdir = ${libdir}
|
||||
`}),
|
||||
))
|
||||
ScriptEarly: "cd /usr/src/libucontext",
|
||||
Make: []string{
|
||||
"ARCH=" + linuxArch(),
|
||||
},
|
||||
ScriptInstall: "make prefix=/system DESTDIR=/work install",
|
||||
})
|
||||
}
|
||||
func init() { artifactsF[Libucontext] = Toolchain.newLibucontext }
|
||||
|
||||
@@ -159,15 +159,6 @@ ln -s ld.lld /work/system/bin/ld
|
||||
[2]string{"LIBCXX_HAS_MUSL_LIBC", "ON"},
|
||||
[2]string{"LIBCXX_USE_COMPILER_RT", "ON"},
|
||||
)
|
||||
|
||||
if t > toolchainStage3 {
|
||||
// libcxxabi fails to compile if c++ headers not prefixed in /usr
|
||||
// is found by the compiler, and doing this is easier than
|
||||
// overriding CXXFLAGS; not using mv here to avoid chown failures
|
||||
scriptEarly += `
|
||||
cp -r /system/include /usr/include && rm -rf /system/include
|
||||
`
|
||||
}
|
||||
}
|
||||
if attr.flags&llvmRuntimeLibcxxABI != 0 {
|
||||
cache = append(cache,
|
||||
@@ -176,7 +167,7 @@ cp -r /system/include /usr/include && rm -rf /system/include
|
||||
)
|
||||
}
|
||||
|
||||
return t.NewViaCMake("llvm", version, variant, t.NewPatchedSource(
|
||||
return t.NewViaCMake("llvm", version, t.NewPatchedSource(
|
||||
"llvmorg", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/llvm/llvm-project/archive/refs/tags/"+
|
||||
"llvmorg-"+version+".tar.gz",
|
||||
@@ -184,6 +175,8 @@ cp -r /system/include /usr/include && rm -rf /system/include
|
||||
pkg.TarGzip,
|
||||
), true, attr.patches...,
|
||||
), &CMakeAttr{
|
||||
Variant: variant,
|
||||
|
||||
Cache: slices.Concat(cache, attr.cmake),
|
||||
Append: cmakeAppend,
|
||||
Prefix: attr.prefix,
|
||||
@@ -199,7 +192,7 @@ cp -r /system/include /usr/include && rm -rf /system/include
|
||||
|
||||
Paths: attr.paths,
|
||||
Flag: TExclusive,
|
||||
}, stage3Concat(t, attr.extra,
|
||||
}, stage0Concat(t, attr.extra,
|
||||
t.Load(Libffi),
|
||||
t.Load(Python),
|
||||
t.Load(Perl),
|
||||
@@ -233,7 +226,7 @@ func (t Toolchain) newLLVM() (musl, compilerRT, runtimes, clang pkg.Artifact) {
|
||||
}
|
||||
|
||||
compilerRT = t.newLLVMVariant("compiler-rt", &llvmAttr{
|
||||
env: stage3ExclConcat(t, []string{},
|
||||
env: stage0ExclConcat(t, []string{},
|
||||
"LDFLAGS="+earlyLDFLAGS(false),
|
||||
),
|
||||
cmake: [][2]string{
|
||||
@@ -253,11 +246,8 @@ func (t Toolchain) newLLVM() (musl, compilerRT, runtimes, clang pkg.Artifact) {
|
||||
{"COMPILER_RT_BUILD_XRAY", "OFF"},
|
||||
},
|
||||
append: []string{"compiler-rt"},
|
||||
extra: []pkg.Artifact{t.NewMusl(&MuslAttr{
|
||||
Headers: true,
|
||||
Env: []string{
|
||||
"CC=clang",
|
||||
},
|
||||
extra: []pkg.Artifact{t.newMusl(true, []string{
|
||||
"CC=clang",
|
||||
})},
|
||||
script: `
|
||||
mkdir -p "${ROSA_INSTALL_PREFIX}/lib/clang/21/lib/"
|
||||
@@ -274,21 +264,18 @@ ln -s \
|
||||
`,
|
||||
})
|
||||
|
||||
musl = t.NewMusl(&MuslAttr{
|
||||
Extra: []pkg.Artifact{compilerRT},
|
||||
Env: stage3ExclConcat(t, []string{
|
||||
"CC=clang",
|
||||
"LIBCC=/system/lib/clang/21/lib/" +
|
||||
triplet() + "/libclang_rt.builtins.a",
|
||||
"AR=ar",
|
||||
"RANLIB=ranlib",
|
||||
},
|
||||
"LDFLAGS="+earlyLDFLAGS(false),
|
||||
),
|
||||
})
|
||||
musl = t.newMusl(false, stage0ExclConcat(t, []string{
|
||||
"CC=clang",
|
||||
"LIBCC=/system/lib/clang/21/lib/" +
|
||||
triplet() + "/libclang_rt.builtins.a",
|
||||
"AR=ar",
|
||||
"RANLIB=ranlib",
|
||||
},
|
||||
"LDFLAGS="+earlyLDFLAGS(false),
|
||||
), compilerRT)
|
||||
|
||||
runtimes = t.newLLVMVariant("runtimes", &llvmAttr{
|
||||
env: stage3ExclConcat(t, []string{},
|
||||
env: stage0ExclConcat(t, []string{},
|
||||
"LDFLAGS="+earlyLDFLAGS(false),
|
||||
),
|
||||
flags: llvmRuntimeLibunwind | llvmRuntimeLibcxx | llvmRuntimeLibcxxABI,
|
||||
@@ -308,7 +295,7 @@ ln -s \
|
||||
|
||||
clang = t.newLLVMVariant("clang", &llvmAttr{
|
||||
flags: llvmProjectClang | llvmProjectLld,
|
||||
env: stage3ExclConcat(t, []string{},
|
||||
env: stage0ExclConcat(t, []string{},
|
||||
"CFLAGS="+earlyCFLAGS,
|
||||
"CXXFLAGS="+earlyCXXFLAGS(),
|
||||
"LDFLAGS="+earlyLDFLAGS(false),
|
||||
@@ -336,7 +323,7 @@ index 657f4230379e..12c305756184 100644
|
||||
--- a/llvm/include/llvm/TargetParser/Triple.h
|
||||
+++ b/llvm/include/llvm/TargetParser/Triple.h
|
||||
@@ -185,6 +185,7 @@ public:
|
||||
|
||||
|
||||
Apple,
|
||||
PC,
|
||||
+ Rosa,
|
||||
@@ -362,7 +349,7 @@ index 0584c941d2e6..e4d6ef963cc7 100644
|
||||
+ .Case("rosa", Triple::Rosa)
|
||||
.Default(Triple::UnknownVendor);
|
||||
}
|
||||
|
||||
|
||||
`},
|
||||
|
||||
{"xfail-broken-tests", `diff --git a/clang/test/Modules/timestamps.c b/clang/test/Modules/timestamps.c
|
||||
@@ -374,14 +361,14 @@ index 50fdce630255..4b4465a75617 100644
|
||||
+
|
||||
/// Verify timestamps that gets embedded in the module
|
||||
#include <c-header.h>
|
||||
|
||||
|
||||
`},
|
||||
|
||||
{"path-system-include", `diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
|
||||
index cdbf21fb9026..dd052858700d 100644
|
||||
index 8ac8d4eb9181..e46b04a898ca 100644
|
||||
--- a/clang/lib/Driver/ToolChains/Linux.cpp
|
||||
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
|
||||
@@ -773,6 +773,12 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
|
||||
@@ -671,6 +671,12 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
|
||||
addExternCSystemInclude(
|
||||
DriverArgs, CC1Args,
|
||||
concat(SysRoot, "/usr/include", MultiarchIncludeDir));
|
||||
@@ -391,15 +378,15 @@ index cdbf21fb9026..dd052858700d 100644
|
||||
+ DriverArgs, CC1Args,
|
||||
+ concat(SysRoot, "/system/include", MultiarchIncludeDir));
|
||||
+
|
||||
|
||||
|
||||
if (getTriple().getOS() == llvm::Triple::RTEMS)
|
||||
return;
|
||||
@@ -783,6 +789,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
|
||||
@@ -681,6 +687,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
|
||||
addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/include"));
|
||||
|
||||
|
||||
addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/include"));
|
||||
+ addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/system/include"));
|
||||
|
||||
|
||||
if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl())
|
||||
addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
|
||||
`},
|
||||
@@ -413,13 +400,13 @@ index 8ac8d4eb9181..f4d1347ab64d 100644
|
||||
const bool IsRISCV = Triple.isRISCV();
|
||||
const bool IsCSKY = Triple.isCSKY();
|
||||
+ const bool IsRosa = Triple.getVendor() == llvm::Triple::Rosa;
|
||||
|
||||
|
||||
if (IsCSKY && !SelectedMultilibs.empty())
|
||||
SysRoot = SysRoot + SelectedMultilibs.back().osSuffix();
|
||||
@@ -318,12 +319,23 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
|
||||
const std::string OSLibDir = std::string(getOSLibDir(Triple, Args));
|
||||
const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot);
|
||||
|
||||
|
||||
+ if (IsRosa) {
|
||||
+ ExtraOpts.push_back("-rpath");
|
||||
+ ExtraOpts.push_back("/system/lib");
|
||||
@@ -441,11 +428,11 @@ index 8ac8d4eb9181..f4d1347ab64d 100644
|
||||
+ }
|
||||
}
|
||||
Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths);
|
||||
|
||||
|
||||
@@ -341,18 +353,30 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
|
||||
Paths);
|
||||
}
|
||||
|
||||
|
||||
- addPathIfExists(D, concat(SysRoot, "/usr/lib", MultiarchTriple), Paths);
|
||||
- addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir), Paths);
|
||||
+ if (!IsRosa) {
|
||||
@@ -464,9 +451,9 @@ index 8ac8d4eb9181..f4d1347ab64d 100644
|
||||
+ else
|
||||
+ addPathIfExists(D, concat(SysRoot, "/system", OSLibDir, ABIName), Paths);
|
||||
}
|
||||
|
||||
|
||||
Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir, Paths);
|
||||
|
||||
|
||||
- addPathIfExists(D, concat(SysRoot, "/lib"), Paths);
|
||||
- addPathIfExists(D, concat(SysRoot, "/usr/lib"), Paths);
|
||||
+ if (!IsRosa) {
|
||||
@@ -476,7 +463,7 @@ index 8ac8d4eb9181..f4d1347ab64d 100644
|
||||
+ addPathIfExists(D, concat(SysRoot, "/system/lib"), Paths);
|
||||
+ }
|
||||
}
|
||||
|
||||
|
||||
ToolChain::RuntimeLibType Linux::GetDefaultRuntimeLibType() const {
|
||||
@@ -457,6 +481,9 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const {
|
||||
return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker";
|
||||
@@ -487,20 +474,20 @@ index 8ac8d4eb9181..f4d1347ab64d 100644
|
||||
+
|
||||
std::string ArchName;
|
||||
bool IsArm = false;
|
||||
|
||||
|
||||
diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp
|
||||
index 64324a3f8b01..15ce70b68217 100644
|
||||
--- a/clang/tools/clang-installapi/Options.cpp
|
||||
+++ b/clang/tools/clang-installapi/Options.cpp
|
||||
@@ -515,7 +515,7 @@ bool Options::processFrontendOptions(InputArgList &Args) {
|
||||
FEOpts.FwkPaths = std::move(FrameworkPaths);
|
||||
|
||||
|
||||
// Add default framework/library paths.
|
||||
- PathSeq DefaultLibraryPaths = {"/usr/lib", "/usr/local/lib"};
|
||||
+ PathSeq DefaultLibraryPaths = {"/usr/lib", "/system/lib", "/usr/local/lib"};
|
||||
PathSeq DefaultFrameworkPaths = {"/Library/Frameworks",
|
||||
"/System/Library/Frameworks"};
|
||||
|
||||
|
||||
`},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -36,8 +36,8 @@ type MakeAttr struct {
|
||||
|
||||
// Do not include default extras.
|
||||
OmitDefaults bool
|
||||
// Dependencies not provided by stage3.
|
||||
NonStage3 []pkg.Artifact
|
||||
// Dependencies not provided by stage0.
|
||||
NonStage0 []pkg.Artifact
|
||||
|
||||
// Additional environment variables.
|
||||
Env []string
|
||||
@@ -51,20 +51,28 @@ type MakeAttr struct {
|
||||
// Remain in working directory set up during ScriptEarly.
|
||||
InPlace bool
|
||||
|
||||
// Whether to skip running the configure script.
|
||||
SkipConfigure bool
|
||||
// Flags passed to the configure script.
|
||||
Configure [][2]string
|
||||
// Extra make targets.
|
||||
Make []string
|
||||
// Host target triple, zero value is equivalent to the Rosa OS triple.
|
||||
Host string
|
||||
// Target triple, zero value is equivalent to the Rosa OS triple.
|
||||
Build string
|
||||
// Whether to skip the check target.
|
||||
SkipCheck bool
|
||||
// Name of the check target, zero value is equivalent to "check".
|
||||
CheckName string
|
||||
// Replaces the default install command.
|
||||
ScriptInstall string
|
||||
|
||||
// Suffix appended to the source pathname.
|
||||
SourceSuffix string
|
||||
|
||||
// Passed through to [Toolchain.New], before source.
|
||||
Paths []pkg.ExecPath
|
||||
// Passed through to [Toolchain.New].
|
||||
Flag int
|
||||
}
|
||||
@@ -82,39 +90,53 @@ func (t Toolchain) NewViaMake(
|
||||
if attr == nil {
|
||||
attr = new(MakeAttr)
|
||||
}
|
||||
|
||||
host := `"${ROSA_TRIPLE}"`
|
||||
if attr.Host != "" {
|
||||
host = attr.Host
|
||||
}
|
||||
build := `"${ROSA_TRIPLE}"`
|
||||
if attr.Build != "" {
|
||||
build = attr.Build
|
||||
}
|
||||
|
||||
var configureFlags string
|
||||
if len(attr.Configure) > 0 {
|
||||
const sep = " \\\n\t"
|
||||
configureFlags += sep + strings.Join(
|
||||
slices.Collect(func(yield func(string) bool) {
|
||||
for _, v := range attr.Configure {
|
||||
s := v[0]
|
||||
if v[1] == "" || (v[0] != "" &&
|
||||
v[0][0] >= 'a' &&
|
||||
v[0][0] <= 'z') {
|
||||
s = "--" + s
|
||||
}
|
||||
if v[1] != "" {
|
||||
s += "=" + v[1]
|
||||
}
|
||||
if !yield(s) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}),
|
||||
sep,
|
||||
)
|
||||
}
|
||||
var configure string
|
||||
if !attr.SkipConfigure {
|
||||
configure += `
|
||||
/usr/src/` + name + `/configure \
|
||||
--prefix=/system`
|
||||
|
||||
var buildFlag string
|
||||
if attr.Build != `""` {
|
||||
buildFlag = ` \
|
||||
if attr.Host != `""` {
|
||||
configure += ` \
|
||||
--host=` + host
|
||||
}
|
||||
if attr.Build != `""` {
|
||||
configure += ` \
|
||||
--build=` + build
|
||||
}
|
||||
|
||||
if len(attr.Configure) > 0 {
|
||||
const sep = " \\\n\t"
|
||||
configure += sep + strings.Join(
|
||||
slices.Collect(func(yield func(string) bool) {
|
||||
for _, v := range attr.Configure {
|
||||
s := v[0]
|
||||
if v[1] == "" || (v[0] != "" &&
|
||||
v[0][0] >= 'a' &&
|
||||
v[0][0] <= 'z') {
|
||||
s = "--" + s
|
||||
}
|
||||
if v[1] != "" {
|
||||
s += "=" + v[1]
|
||||
}
|
||||
if !yield(s) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}),
|
||||
sep,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
makeTargets := make([]string, 1, 2+len(attr.Make))
|
||||
@@ -148,15 +170,20 @@ func (t Toolchain) NewViaMake(
|
||||
panic("cannot remain in root")
|
||||
}
|
||||
|
||||
return t.New(name+"-"+version, attr.Flag, stage3Concat(t,
|
||||
attr.NonStage3,
|
||||
scriptInstall := attr.ScriptInstall
|
||||
if scriptInstall == "" {
|
||||
scriptInstall = "make DESTDIR=/work install"
|
||||
}
|
||||
scriptInstall += "\n"
|
||||
|
||||
return t.New(name+"-"+version, attr.Flag, stage0Concat(t,
|
||||
attr.NonStage0,
|
||||
finalExtra...,
|
||||
), nil, attr.Env, scriptEarly+`
|
||||
/usr/src/`+name+`/configure \
|
||||
--prefix=/system`+buildFlag+configureFlags+attr.ScriptConfigured+`
|
||||
), nil, attr.Env, scriptEarly+configure+attr.ScriptConfigured+`
|
||||
make "-j$(nproc)"`+strings.Join(makeTargets, " ")+`
|
||||
make DESTDIR=/work install
|
||||
`+attr.Script, pkg.Path(AbsUsrSrc.Append(
|
||||
name+attr.SourceSuffix,
|
||||
), attr.Writable, source))
|
||||
`+scriptInstall+attr.Script, slices.Concat(attr.Paths, []pkg.ExecPath{
|
||||
pkg.Path(AbsUsrSrc.Append(
|
||||
name+attr.SourceSuffix,
|
||||
), attr.Writable, source),
|
||||
})...)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
func (t Toolchain) newMeson() pkg.Artifact {
|
||||
const (
|
||||
@@ -25,3 +30,96 @@ python3 setup.py \
|
||||
)))
|
||||
}
|
||||
func init() { artifactsF[Meson] = Toolchain.newMeson }
|
||||
|
||||
// MesonAttr holds the project-specific attributes that will be applied to a new
|
||||
// [pkg.Artifact] compiled via [Meson].
|
||||
type MesonAttr struct {
|
||||
// Mount the source tree writable.
|
||||
Writable bool
|
||||
|
||||
// Additional environment variables.
|
||||
Env []string
|
||||
// Runs before setup.
|
||||
ScriptEarly string
|
||||
// Runs after configure.
|
||||
ScriptCompiled string
|
||||
// Runs after install.
|
||||
Script string
|
||||
|
||||
// Flags passed to the setup command.
|
||||
Configure [][2]string
|
||||
// Whether to skip meson test.
|
||||
SkipCheck bool
|
||||
// Appended after the test command.
|
||||
AppendTest string
|
||||
|
||||
// Suffix appended to the source pathname.
|
||||
SourceSuffix string
|
||||
|
||||
// Passed through to [Toolchain.New], before source.
|
||||
Paths []pkg.ExecPath
|
||||
// Passed through to [Toolchain.New].
|
||||
Flag int
|
||||
}
|
||||
|
||||
// NewViaMeson returns a [pkg.Artifact] for compiling and installing via [Meson].
|
||||
func (t Toolchain) NewViaMeson(
|
||||
name, version string,
|
||||
source pkg.Artifact,
|
||||
attr *MesonAttr,
|
||||
extra ...pkg.Artifact,
|
||||
) pkg.Artifact {
|
||||
if name == "" || version == "" {
|
||||
panic("names must be non-empty")
|
||||
}
|
||||
if attr == nil {
|
||||
attr = new(MesonAttr)
|
||||
}
|
||||
|
||||
scriptCompiled := attr.ScriptCompiled
|
||||
if len(scriptCompiled) > 0 && scriptCompiled[0] != '\n' {
|
||||
scriptCompiled = "\n" + scriptCompiled
|
||||
}
|
||||
|
||||
var check string
|
||||
if !attr.SkipCheck {
|
||||
check = "\nmeson test \\\n\t--print-errorlogs" + attr.AppendTest
|
||||
}
|
||||
|
||||
return t.New(name+"-"+version, attr.Flag, slices.Concat([]pkg.Artifact{
|
||||
t.Load(Python),
|
||||
t.Load(Meson),
|
||||
t.Load(Ninja),
|
||||
|
||||
t.Load(PkgConfig),
|
||||
t.Load(CMake),
|
||||
}, extra), nil, attr.Env, attr.ScriptEarly+`
|
||||
cd "$(mktemp -d)"
|
||||
meson setup \
|
||||
`+strings.Join(slices.Collect(func(yield func(string) bool) {
|
||||
for _, v := range append([][2]string{
|
||||
{"prefix", "/system"},
|
||||
{"buildtype", "release"},
|
||||
}, attr.Configure...) {
|
||||
s := "-" + v[0]
|
||||
if len(v[0]) > 0 && v[0][0] != 'D' {
|
||||
s = "-" + s
|
||||
}
|
||||
if v[1] != "" {
|
||||
s += "=" + v[1]
|
||||
}
|
||||
if !yield(s) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}), " \\\n\t")+` \
|
||||
. /usr/src/`+name+`
|
||||
meson compile`+scriptCompiled+check+`
|
||||
meson install \
|
||||
--destdir=/work
|
||||
`+attr.Script, slices.Concat(attr.Paths, []pkg.ExecPath{
|
||||
pkg.Path(AbsUsrSrc.Append(
|
||||
name+attr.SourceSuffix,
|
||||
), attr.Writable, source),
|
||||
})...)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ func (t Toolchain) newMksh() pkg.Artifact {
|
||||
version = "59c"
|
||||
checksum = "0Zj-k4nXEu3IuJY4lvwD2OrC2t27GdZj8SPy4DoaeuBRH1padWb7oREpYgwY8JNq"
|
||||
)
|
||||
return t.New("mksh-"+version, 0, stage3Concat(t, []pkg.Artifact{},
|
||||
return t.New("mksh-"+version, 0, stage0Concat(t, []pkg.Artifact{},
|
||||
t.Load(Perl),
|
||||
t.Load(Coreutils),
|
||||
), nil, []string{
|
||||
|
||||
33
internal/rosa/musl-fts.go
Normal file
33
internal/rosa/musl-fts.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newMuslFts() pkg.Artifact {
|
||||
const (
|
||||
version = "1.2.7"
|
||||
checksum = "N_p_ZApX3eHt7xoDCw1hLf6XdJOw7ZSx7xPvpvAP0knG2zgU0zeN5w8tt5Pg60XJ"
|
||||
)
|
||||
return t.NewViaMake("musl-fts", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/void-linux/musl-fts/archive/refs/tags/"+
|
||||
"v"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &MakeAttr{
|
||||
Writable: true,
|
||||
Env: []string{
|
||||
"CC=cc -fPIC",
|
||||
},
|
||||
ScriptEarly: `
|
||||
cd /usr/src/musl-fts
|
||||
./bootstrap.sh
|
||||
`,
|
||||
},
|
||||
t.Load(M4),
|
||||
t.Load(Perl),
|
||||
t.Load(Autoconf),
|
||||
t.Load(Automake),
|
||||
t.Load(Libtool),
|
||||
t.Load(PkgConfig),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[MuslFts] = Toolchain.newMuslFts }
|
||||
33
internal/rosa/musl-obstack.go
Normal file
33
internal/rosa/musl-obstack.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newMuslObstack() pkg.Artifact {
|
||||
const (
|
||||
version = "1.2.3"
|
||||
checksum = "tVRY_KjIlkkMszcaRlkKdBVQHIXTT_T_TiMxbwErlILXrOBosocg8KklppZhNdCG"
|
||||
)
|
||||
return t.NewViaMake("musl-obstack", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/void-linux/musl-obstack/archive/refs/tags/"+
|
||||
"v"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &MakeAttr{
|
||||
Writable: true,
|
||||
Env: []string{
|
||||
"CC=cc -fPIC",
|
||||
},
|
||||
ScriptEarly: `
|
||||
cd /usr/src/musl-obstack
|
||||
./bootstrap.sh
|
||||
`,
|
||||
},
|
||||
t.Load(M4),
|
||||
t.Load(Perl),
|
||||
t.Load(Autoconf),
|
||||
t.Load(Automake),
|
||||
t.Load(Libtool),
|
||||
t.Load(PkgConfig),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[MuslObstack] = Toolchain.newMuslObstack }
|
||||
@@ -1,34 +1,24 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"slices"
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
// MuslAttr holds the attributes that will be applied to musl.
|
||||
type MuslAttr struct {
|
||||
// Install headers only.
|
||||
Headers bool
|
||||
// Environment variables concatenated with defaults.
|
||||
Env []string
|
||||
// Dependencies concatenated with defaults.
|
||||
Extra []pkg.Artifact
|
||||
}
|
||||
|
||||
// NewMusl returns a [pkg.Artifact] containing an installation of musl libc.
|
||||
func (t Toolchain) NewMusl(attr *MuslAttr) pkg.Artifact {
|
||||
func (t Toolchain) newMusl(
|
||||
headers bool,
|
||||
env []string,
|
||||
extra ...pkg.Artifact,
|
||||
) pkg.Artifact {
|
||||
const (
|
||||
version = "1.2.5"
|
||||
checksum = "y6USdIeSdHER_Fw2eT2CNjqShEye85oEg2jnOur96D073ukmIpIqDOLmECQroyDb"
|
||||
)
|
||||
|
||||
if attr == nil {
|
||||
attr = new(MuslAttr)
|
||||
}
|
||||
name := "musl"
|
||||
attr := MakeAttr{
|
||||
OmitDefaults: true,
|
||||
SkipCheck: true,
|
||||
|
||||
target := "install"
|
||||
script := `
|
||||
Env: env,
|
||||
Script: `
|
||||
mkdir -p /work/system/bin
|
||||
COMPAT_LINKER_NAME="ld-musl-` + linuxArch() + `.so.1"
|
||||
ln -vs ../lib/libc.so /work/system/bin/linker
|
||||
@@ -36,29 +26,23 @@ ln -vs ../lib/libc.so /work/system/bin/ldd
|
||||
ln -vs libc.so "/work/system/lib/${COMPAT_LINKER_NAME}"
|
||||
rm -v "/work/lib/${COMPAT_LINKER_NAME}"
|
||||
rmdir -v /work/lib
|
||||
`
|
||||
if attr.Headers {
|
||||
target = "install-headers"
|
||||
script = ""
|
||||
`,
|
||||
}
|
||||
|
||||
return t.New("musl-"+version, 0, stage3Concat(t, attr.Extra,
|
||||
t.Load(Make),
|
||||
t.Load(Coreutils),
|
||||
), nil, slices.Concat([]string{
|
||||
"ROSA_MUSL_TARGET=" + target,
|
||||
}, attr.Env), `
|
||||
cd "$(mktemp -d)"
|
||||
/usr/src/musl/configure \
|
||||
--prefix=/system \
|
||||
--target="${ROSA_TRIPLE}"
|
||||
make "-j$(nproc)" DESTDIR=/work "${ROSA_MUSL_TARGET}"
|
||||
`+script, pkg.Path(AbsUsrSrc.Append("musl"), false, t.NewPatchedSource(
|
||||
if headers {
|
||||
name += "-headers"
|
||||
attr.ScriptInstall = "make DESTDIR=/work install-headers"
|
||||
attr.Script = ""
|
||||
}
|
||||
|
||||
return t.NewViaMake(name, version, t.NewPatchedSource(
|
||||
// expected to be writable in copies
|
||||
"musl", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://musl.libc.org/releases/musl-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), false,
|
||||
)))
|
||||
), &attr, stage0Concat(t, extra,
|
||||
t.Load(Coreutils),
|
||||
)...)
|
||||
}
|
||||
|
||||
26
internal/rosa/ncurses.go
Normal file
26
internal/rosa/ncurses.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newNcurses() pkg.Artifact {
|
||||
const (
|
||||
version = "6.6"
|
||||
checksum = "XvWp4xi6hR_hH8XUoGY26L_pqBSDapJYulhzZqPuR0KNklqypqNc1yNXU-nOjf5w"
|
||||
)
|
||||
return t.NewViaMake("ncurses", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://ftpmirror.gnu.org/gnu/ncurses/ncurses-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &MakeAttr{
|
||||
// "tests" are actual demo programs, not a test suite.
|
||||
SkipCheck: true,
|
||||
|
||||
Configure: [][2]string{
|
||||
{"with-pkg-config"},
|
||||
{"enable-pc-files"},
|
||||
},
|
||||
},
|
||||
t.Load(PkgConfig),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Ncurses] = Toolchain.newNcurses }
|
||||
@@ -7,30 +7,33 @@ func (t Toolchain) newOpenSSL() pkg.Artifact {
|
||||
version = "3.5.5"
|
||||
checksum = "I2Hp1LxcTR8j4G6LFEQMVy6EJH-Na1byI9Ti-ThBot6EMLNRnjGXGq-WXrim3Fkz"
|
||||
)
|
||||
return t.New("openssl-"+version, 0, []pkg.Artifact{
|
||||
t.Load(Perl),
|
||||
t.Load(Make),
|
||||
|
||||
t.Load(Zlib),
|
||||
t.Load(KernelHeaders),
|
||||
}, nil, []string{
|
||||
"CC=cc",
|
||||
}, `
|
||||
cd "$(mktemp -d)"
|
||||
/usr/src/openssl/Configure \
|
||||
--prefix=/system \
|
||||
--libdir=lib \
|
||||
--openssldir=etc/ssl
|
||||
make \
|
||||
"-j$(nproc)" \
|
||||
HARNESS_JOBS=256 \
|
||||
test
|
||||
make DESTDIR=/work install
|
||||
`, pkg.Path(AbsUsrSrc.Append("openssl"), false, pkg.NewHTTPGetTar(
|
||||
return t.NewViaMake("openssl", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/openssl/openssl/releases/download/"+
|
||||
"openssl-"+version+"/openssl-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
)))
|
||||
), &MakeAttr{
|
||||
OmitDefaults: true,
|
||||
SkipConfigure: true,
|
||||
|
||||
Env: []string{
|
||||
"CC=cc",
|
||||
},
|
||||
ScriptConfigured: `
|
||||
/usr/src/openssl/Configure \
|
||||
--prefix=/system \
|
||||
--libdir=lib \
|
||||
--openssldir=etc/ssl
|
||||
`,
|
||||
CheckName: "test",
|
||||
Make: []string{
|
||||
`HARNESS_JOBS="$(expr "$(nproc)" '*' 2)"`,
|
||||
},
|
||||
},
|
||||
t.Load(Perl),
|
||||
|
||||
t.Load(Zlib),
|
||||
t.Load(KernelHeaders),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[OpenSSL] = Toolchain.newOpenSSL }
|
||||
|
||||
33
internal/rosa/pcre2.go
Normal file
33
internal/rosa/pcre2.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
func (t Toolchain) newPCRE2() pkg.Artifact {
|
||||
const (
|
||||
version = "10.43"
|
||||
checksum = "iyNw-POPSJwiZVJfUK5qACA6q2uMzP-84WieimN_CskaEkuw5fRnRTZhEv6ry2Yo"
|
||||
)
|
||||
return t.NewViaMake("pcre2", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/PCRE2Project/pcre2/releases/download/"+
|
||||
"pcre2-"+version+"/pcre2-"+version+".tar.bz2",
|
||||
mustDecode(checksum),
|
||||
pkg.TarBzip2,
|
||||
), &MakeAttr{
|
||||
ScriptEarly: `
|
||||
# RunGrepTest expects /bin/echo
|
||||
ln -s ../system/bin/toybox /bin/echo
|
||||
`,
|
||||
|
||||
Configure: [][2]string{
|
||||
{"enable-jit"},
|
||||
{"enable-pcre2-8"},
|
||||
{"enable-pcre2-16"},
|
||||
{"enable-pcre2-32"},
|
||||
},
|
||||
},
|
||||
t.Load(Diffutils),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[PCRE2] = Toolchain.newPCRE2 }
|
||||
@@ -27,7 +27,7 @@ make \
|
||||
"-j$(nproc)" \
|
||||
TEST_JOBS=256 \
|
||||
test_harness
|
||||
make DESTDIR=/work install
|
||||
./perl -Ilib -I. installperl --destdir=/work
|
||||
`, pkg.Path(AbsUsrSrc.Append("perl"), true, t.NewPatchedSource(
|
||||
"perl", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://www.cpan.org/src/5.0/perl-"+version+".tar.gz",
|
||||
|
||||
37
internal/rosa/procps.go
Normal file
37
internal/rosa/procps.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newProcps() pkg.Artifact {
|
||||
const (
|
||||
version = "4.0.6"
|
||||
checksum = "pl_fZLvDlv6iZTkm8l_tHFpzTDVFGCiSJEs3eu0zAX6u36AV36P_En8K7JPScRWM"
|
||||
)
|
||||
return t.NewViaMake("procps", version, t.NewPatchedSource(
|
||||
"procps", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://gitlab.com/procps-ng/procps/-/archive/"+
|
||||
"v"+version+"/procps-v"+version+".tar.bz2",
|
||||
mustDecode(checksum),
|
||||
pkg.TarBzip2,
|
||||
), false,
|
||||
), &MakeAttr{
|
||||
Writable: true,
|
||||
ScriptEarly: `
|
||||
cd /usr/src/procps
|
||||
./autogen.sh
|
||||
`,
|
||||
Configure: [][2]string{
|
||||
{"without-ncurses"},
|
||||
},
|
||||
},
|
||||
t.Load(M4),
|
||||
t.Load(Perl),
|
||||
t.Load(Autoconf),
|
||||
t.Load(Automake),
|
||||
t.Load(Gettext),
|
||||
t.Load(Libtool),
|
||||
t.Load(Gzip),
|
||||
t.Load(PkgConfig),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Procps] = Toolchain.newProcps }
|
||||
@@ -57,6 +57,11 @@ export HOME="$(mktemp -d)"
|
||||
},
|
||||
t.Load(Zlib),
|
||||
t.Load(Libffi),
|
||||
|
||||
t.Load(PkgConfig),
|
||||
t.Load(OpenSSL),
|
||||
t.Load(Bzip2),
|
||||
t.Load(XZ),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Python] = Toolchain.newPython }
|
||||
|
||||
102
internal/rosa/qemu.go
Normal file
102
internal/rosa/qemu.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
func (t Toolchain) newQEMU() pkg.Artifact {
|
||||
const (
|
||||
version = "10.2.1"
|
||||
checksum = "rjLTSgHJd3X3Vgpxrsus_ZZiaYLiNix1YhcHaGbLd_odYixwZjCcAIt8CVQPJGdZ"
|
||||
)
|
||||
return t.NewViaMake("qemu", version, t.NewPatchedSource(
|
||||
"qemu", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://download.qemu.org/qemu-"+version+".tar.bz2",
|
||||
mustDecode(checksum),
|
||||
pkg.TarBzip2,
|
||||
), false, [2]string{"disable-mcast-test", `diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c
|
||||
index b731af0ad9..b5cbed4801 100644
|
||||
--- a/tests/qtest/netdev-socket.c
|
||||
+++ b/tests/qtest/netdev-socket.c
|
||||
@@ -401,7 +401,7 @@ static void test_dgram_inet(void)
|
||||
qtest_quit(qts0);
|
||||
}
|
||||
|
||||
-#if !defined(_WIN32) && !defined(CONFIG_DARWIN)
|
||||
+#if 0
|
||||
static void test_dgram_mcast(void)
|
||||
{
|
||||
QTestState *qts;
|
||||
@@ -513,7 +513,7 @@ int main(int argc, char **argv)
|
||||
if (has_ipv4) {
|
||||
qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4);
|
||||
qtest_add_func("/netdev/dgram/inet", test_dgram_inet);
|
||||
-#if !defined(_WIN32) && !defined(CONFIG_DARWIN)
|
||||
+#if 0
|
||||
qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast);
|
||||
#endif
|
||||
}
|
||||
`},
|
||||
), &MakeAttr{
|
||||
// configure script uses source as scratch space
|
||||
Writable: true,
|
||||
|
||||
ScriptEarly: `
|
||||
# tests expect /var/tmp/ to be available
|
||||
mkdir -p /var/tmp/
|
||||
|
||||
# https://gitlab.com/qemu-project/qemu/-/issues/3145
|
||||
(cd /usr/src/qemu && sed -i \
|
||||
's,Input/output error,I/O error,g' \
|
||||
tests/qemu-iotests/[0-9][0-9][0-9]* \
|
||||
tests/qemu-iotests/tests/copy-before-write \
|
||||
tests/qemu-iotests/tests/file-io-error.out &&
|
||||
cat << EOF > tests/qemu-iotests/150
|
||||
#!/bin/sh
|
||||
_notrun 'appears to spuriously fail on zfs'
|
||||
EOF
|
||||
)
|
||||
`,
|
||||
|
||||
Configure: [][2]string{
|
||||
{"disable-download"},
|
||||
{"disable-docs"},
|
||||
|
||||
{"target-list-exclude", "" +
|
||||
// fails to load firmware
|
||||
"ppc-linux-user," +
|
||||
"ppc64-linux-user," +
|
||||
"ppc64le-linux-user," +
|
||||
"ppc-softmmu," +
|
||||
"ppc64-softmmu"},
|
||||
},
|
||||
|
||||
ScriptConfigured: `
|
||||
make "-j$(nproc)"
|
||||
`,
|
||||
},
|
||||
t.Load(Bash),
|
||||
t.Load(Python),
|
||||
t.Load(Ninja),
|
||||
t.Load(Bzip2),
|
||||
t.Load(PkgConfig),
|
||||
t.Load(Diffutils),
|
||||
|
||||
t.Load(OpenSSL),
|
||||
t.Load(Bzip2),
|
||||
t.Load(XZ),
|
||||
|
||||
t.Load(Flex),
|
||||
t.Load(Bison),
|
||||
t.Load(M4),
|
||||
|
||||
t.Load(PCRE2),
|
||||
t.Load(Libffi),
|
||||
t.Load(Zlib),
|
||||
t.Load(GLib),
|
||||
t.Load(Zstd),
|
||||
t.Load(DTC),
|
||||
t.Load(KernelHeaders),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[QEMU] = Toolchain.newQEMU }
|
||||
@@ -2,6 +2,7 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"runtime"
|
||||
"slices"
|
||||
@@ -82,11 +83,11 @@ func earlyLDFLAGS(static bool) string {
|
||||
return s
|
||||
}
|
||||
|
||||
// earlyCFLAGS is reference CFLAGS for the stage3 toolchain.
|
||||
// earlyCFLAGS is reference CFLAGS for the stage0 toolchain.
|
||||
const earlyCFLAGS = "-Qunused-arguments " +
|
||||
"-isystem/system/include"
|
||||
|
||||
// earlyCXXFLAGS returns reference CXXFLAGS for the stage3 toolchain
|
||||
// earlyCXXFLAGS returns reference CXXFLAGS for the stage0 toolchain
|
||||
// corresponding to [runtime.GOARCH].
|
||||
func earlyCXXFLAGS() string {
|
||||
return "--start-no-unused-arguments " +
|
||||
@@ -98,19 +99,33 @@ func earlyCXXFLAGS() string {
|
||||
}
|
||||
|
||||
// Toolchain denotes the infrastructure to compile a [pkg.Artifact] on.
|
||||
type Toolchain uintptr
|
||||
type Toolchain uint32
|
||||
|
||||
const (
|
||||
// toolchainBusybox denotes a busybox installation from the busyboxBin
|
||||
// binary distribution. This is for decompressing unsupported formats.
|
||||
toolchainBusybox Toolchain = iota
|
||||
// _toolchainBusybox denotes a busybox installation from the busyboxBin
|
||||
// binary distribution. This is defined as a toolchain to make use of the
|
||||
// toolchain abstractions to preprocess toolchainGentoo and is not a real,
|
||||
// functioning toolchain. It does not contain any compilers.
|
||||
_toolchainBusybox Toolchain = iota
|
||||
|
||||
// toolchainStage3 denotes the Gentoo stage3 toolchain. Special care must be
|
||||
// taken to compile correctly against this toolchain.
|
||||
toolchainStage3
|
||||
// toolchainGentoo denotes the toolchain in a Gentoo stage3 tarball. Special
|
||||
// care must be taken to compile correctly against this toolchain.
|
||||
toolchainGentoo
|
||||
|
||||
// toolchainIntermediateGentoo is like to toolchainIntermediate, but
|
||||
// compiled against toolchainGentoo.
|
||||
toolchainIntermediateGentoo
|
||||
|
||||
// toolchainStdGentoo is like Std, but bootstrapped from toolchainGentoo.
|
||||
// This toolchain creates the first [Stage0] distribution.
|
||||
toolchainStdGentoo
|
||||
|
||||
// toolchainStage0 denotes the stage0 toolchain. Special care must be taken
|
||||
// to compile correctly against this toolchain.
|
||||
toolchainStage0
|
||||
|
||||
// toolchainIntermediate denotes the intermediate toolchain compiled against
|
||||
// toolchainStage3. This toolchain should be functionally identical to [Std]
|
||||
// toolchainStage0. This toolchain should be functionally identical to [Std]
|
||||
// and is used to bootstrap [Std].
|
||||
toolchainIntermediate
|
||||
|
||||
@@ -122,19 +137,49 @@ const (
|
||||
_toolchainEnd
|
||||
)
|
||||
|
||||
// stage3Concat concatenates s and values. If the current toolchain is
|
||||
// toolchainStage3, stage3Concat returns s as is.
|
||||
func stage3Concat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
|
||||
if t == toolchainStage3 {
|
||||
// isStage0 returns whether t is a stage0 toolchain.
|
||||
func (t Toolchain) isStage0() bool {
|
||||
switch t {
|
||||
case toolchainGentoo, toolchainStage0:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// isIntermediate returns whether t is an intermediate toolchain.
|
||||
func (t Toolchain) isIntermediate() bool {
|
||||
switch t {
|
||||
case toolchainIntermediateGentoo, toolchainIntermediate:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// isStd returns whether t is considered functionally equivalent to [Std].
|
||||
func (t Toolchain) isStd() bool {
|
||||
switch t {
|
||||
case toolchainStdGentoo, Std:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// stage0Concat concatenates s and values. If the current toolchain is
|
||||
// toolchainStage0, stage0Concat returns s as is.
|
||||
func stage0Concat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
|
||||
if t.isStage0() {
|
||||
return s
|
||||
}
|
||||
return slices.Concat(s, values)
|
||||
}
|
||||
|
||||
// stage3ExclConcat concatenates s and values. If the current toolchain is not
|
||||
// toolchainStage3, stage3ExclConcat returns s as is.
|
||||
func stage3ExclConcat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
|
||||
if t == toolchainStage3 {
|
||||
// stage0ExclConcat concatenates s and values. If the current toolchain is not
|
||||
// toolchainStage0, stage0ExclConcat returns s as is.
|
||||
func stage0ExclConcat[S ~[]E, E any](t Toolchain, s S, values ...E) S {
|
||||
if t.isStage0() {
|
||||
return slices.Concat(s, values)
|
||||
}
|
||||
return s
|
||||
@@ -173,7 +218,7 @@ func fixupEnviron(env, extras []string, paths ...string) []string {
|
||||
|
||||
// absCureScript is the absolute pathname [Toolchain.New] places the fixed-up
|
||||
// build script under.
|
||||
var absCureScript = fhs.AbsUsrBin.Append(".cure-script")
|
||||
var absCureScript = AbsSystem.Append("bin", ".cure-script")
|
||||
|
||||
const (
|
||||
// TExclusive denotes an exclusive [pkg.Artifact].
|
||||
@@ -182,12 +227,31 @@ const (
|
||||
TEarly
|
||||
)
|
||||
|
||||
var (
|
||||
// gentooStage3 is the url of a Gentoo stage3 tarball.
|
||||
gentooStage3 string
|
||||
// gentooStage3Checksum is the expected checksum of gentooStage3.
|
||||
gentooStage3Checksum pkg.Checksum
|
||||
)
|
||||
|
||||
// SetGentooStage3 sets the Gentoo stage3 tarball url and checksum. It panics
|
||||
// if given zero values or if these values have already been set.
|
||||
func SetGentooStage3(url string, checksum pkg.Checksum) {
|
||||
if gentooStage3 != "" {
|
||||
panic(errors.New("attempting to set Gentoo stage3 url twice"))
|
||||
}
|
||||
if url == "" {
|
||||
panic(errors.New("attempting to set Gentoo stage3 url to the zero value"))
|
||||
}
|
||||
gentooStage3, gentooStage3Checksum = url, checksum
|
||||
}
|
||||
|
||||
// New returns a [pkg.Artifact] compiled on this toolchain.
|
||||
func (t Toolchain) New(
|
||||
name string,
|
||||
flag int,
|
||||
extra []pkg.Artifact,
|
||||
checksum *pkg.Checksum,
|
||||
knownChecksum *pkg.Checksum,
|
||||
env []string,
|
||||
script string,
|
||||
|
||||
@@ -195,57 +259,47 @@ func (t Toolchain) New(
|
||||
) pkg.Artifact {
|
||||
const lcMessages = "LC_MESSAGES=C.UTF-8"
|
||||
|
||||
var (
|
||||
path = AbsSystem.Append("bin", "sh")
|
||||
args = []string{"sh", absCureScript.String()}
|
||||
support []pkg.Artifact
|
||||
)
|
||||
var support []pkg.Artifact
|
||||
switch t {
|
||||
case toolchainBusybox:
|
||||
case _toolchainBusybox:
|
||||
name += "-early"
|
||||
support = slices.Concat([]pkg.Artifact{newBusyboxBin()}, extra)
|
||||
path = AbsSystem.Append("bin", "busybox")
|
||||
args[0] = "hush"
|
||||
env = fixupEnviron(env, nil, "/system/bin")
|
||||
|
||||
case toolchainStage3:
|
||||
case toolchainGentoo, toolchainStage0:
|
||||
name += "-boot"
|
||||
var seed string
|
||||
switch runtime.GOARCH {
|
||||
case "amd64":
|
||||
seed = "c5_FwMnRN8RZpTdBLGYkL4RR8ampdaZN2JbkgrFLe8-QHQAVQy08APVvIL6eT7KW"
|
||||
case "arm64":
|
||||
seed = "79uRbRI44PyknQQ9RlFUQrwqplup7vImiIk6klefL8TN-fT42TXMS_v4XszwexCb"
|
||||
|
||||
default:
|
||||
panic("unsupported target " + runtime.GOARCH)
|
||||
}
|
||||
path = fhs.AbsRoot.Append("bin", "bash")
|
||||
args[0] = "bash"
|
||||
support = slices.Concat([]pkg.Artifact{
|
||||
cureEtc{},
|
||||
toolchainBusybox.New("stage3", 0, nil, nil, nil, `
|
||||
support = append(support, cureEtc{})
|
||||
if t == toolchainStage0 {
|
||||
support = append(support, NewStage0())
|
||||
} else {
|
||||
support = append(support, _toolchainBusybox.New("gentoo", 0, nil, nil, nil, `
|
||||
tar -C /work -xf /usr/src/stage3.tar.xz
|
||||
rm -rf /work/dev/ /work/proc/
|
||||
ln -vs ../usr/bin /work/bin
|
||||
mkdir -vp /work/system/bin
|
||||
(cd /work/system/bin && ln -vs \
|
||||
../../bin/sh \
|
||||
../../usr/lib/llvm/*/bin/* \
|
||||
.)
|
||||
`, pkg.Path(AbsUsrSrc.Append("stage3.tar.xz"), false,
|
||||
pkg.NewHTTPGet(
|
||||
nil, "https://basement.gensokyo.uk/seed/"+seed,
|
||||
mustDecode(seed),
|
||||
nil, gentooStage3,
|
||||
gentooStage3Checksum,
|
||||
),
|
||||
)),
|
||||
}, extra)
|
||||
)))
|
||||
}
|
||||
support = slices.Concat(support, extra)
|
||||
env = fixupEnviron(env, []string{
|
||||
EnvTriplet + "=" + triplet(),
|
||||
lcMessages,
|
||||
"LDFLAGS=" + earlyLDFLAGS(true),
|
||||
}, "/system/bin",
|
||||
"/usr/bin",
|
||||
"/usr/lib/llvm/21/bin",
|
||||
)
|
||||
|
||||
case toolchainIntermediate, Std:
|
||||
if t < Std {
|
||||
case toolchainIntermediateGentoo, toolchainStdGentoo,
|
||||
toolchainIntermediate, Std:
|
||||
if t.isIntermediate() {
|
||||
name += "-std"
|
||||
}
|
||||
|
||||
@@ -279,9 +333,10 @@ ln -vs ../usr/bin /work/bin
|
||||
}
|
||||
|
||||
return pkg.NewExec(
|
||||
name, checksum, pkg.ExecTimeoutMax, flag&TExclusive != 0,
|
||||
name, knownChecksum, pkg.ExecTimeoutMax, flag&TExclusive != 0,
|
||||
fhs.AbsRoot, env,
|
||||
path, args,
|
||||
AbsSystem.Append("bin", "sh"),
|
||||
[]string{"sh", absCureScript.String()},
|
||||
|
||||
slices.Concat([]pkg.ExecPath{pkg.Path(
|
||||
fhs.AbsRoot, true,
|
||||
@@ -328,7 +383,7 @@ cat /usr/src/` + name + `-patches/* | \
|
||||
`
|
||||
aname += "-patched"
|
||||
}
|
||||
return t.New(aname, 0, stage3Concat(t, []pkg.Artifact{},
|
||||
return t.New(aname, 0, stage0Concat(t, []pkg.Artifact{},
|
||||
t.Load(Patch),
|
||||
), nil, nil, script, paths...)
|
||||
}
|
||||
|
||||
41
internal/rosa/squashfs.go
Normal file
41
internal/rosa/squashfs.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newSquashfsTools() pkg.Artifact {
|
||||
const (
|
||||
version = "4.7.4"
|
||||
checksum = "pG0E_wkRJFS6bvPYF-hTKZT-cWnvo5BbIzCDZrJZVQDgJOx2Vc3ZfNSEV7Di7cSW"
|
||||
)
|
||||
return t.NewViaMake("squashfs-tools", version, t.NewPatchedSource(
|
||||
"squashfs-tools", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/plougher/squashfs-tools/releases/"+
|
||||
"download/"+version+"/squashfs-tools-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), false,
|
||||
), &MakeAttr{
|
||||
Writable: true,
|
||||
SkipConfigure: true,
|
||||
InPlace: true,
|
||||
|
||||
Env: []string{
|
||||
"CONFIG=1",
|
||||
"XZ_SUPPORT=0",
|
||||
"LZO_SUPPORT=0",
|
||||
"LZ4_SUPPORT=0",
|
||||
"COMP_DEFAULT=zstd",
|
||||
"USE_PREBUILT_MANPAGES=y",
|
||||
},
|
||||
ScriptEarly: "cd /usr/src/squashfs-tools/squashfs-tools",
|
||||
SkipCheck: true,
|
||||
ScriptInstall: "make INSTALL_PREFIX=/work/system install",
|
||||
},
|
||||
t.Load(Sed),
|
||||
|
||||
t.Load(Zstd),
|
||||
t.Load(Gzip),
|
||||
t.Load(Zlib),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[SquashfsTools] = Toolchain.newSquashfsTools }
|
||||
@@ -12,45 +12,57 @@ func (t Toolchain) newNSS() pkg.Artifact {
|
||||
version0 = "4_38_2"
|
||||
checksum0 = "25x2uJeQnOHIiq_zj17b4sYqKgeoU8-IsySUptoPcdHZ52PohFZfGuIisBreWzx0"
|
||||
)
|
||||
return t.New("nss-"+version, 0, []pkg.Artifact{
|
||||
t.Load(Perl),
|
||||
t.Load(Python),
|
||||
t.Load(Unzip),
|
||||
t.Load(Make),
|
||||
t.Load(Gawk),
|
||||
t.Load(Coreutils),
|
||||
|
||||
t.Load(Zlib),
|
||||
t.Load(KernelHeaders),
|
||||
}, nil, nil, `
|
||||
unzip /usr/src/nspr.zip -d /usr/src
|
||||
mv '/usr/src/nspr-NSPR_`+version0+`_RTM' /usr/src/nspr
|
||||
cd /usr/src/nss
|
||||
|
||||
make \
|
||||
"-j$(nproc)" \
|
||||
CCC="clang++" \
|
||||
NSDISTMODE=copy \
|
||||
BUILD_OPT=1 \
|
||||
USE_64=1 \
|
||||
nss_build_all
|
||||
mkdir -p /work/system/nss
|
||||
cp -r \
|
||||
/usr/src/dist/. \
|
||||
lib/ckfw/builtins/certdata.txt \
|
||||
/work/system/nss
|
||||
`, pkg.Path(AbsUsrSrc.Append("nss"), true, t.NewPatchedSource(
|
||||
return t.NewViaMake("nss", version, t.NewPatchedSource(
|
||||
"nss", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/nss-dev/nss/archive/refs/tags/"+
|
||||
"NSS_"+version+"_RTM.tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), false,
|
||||
)), pkg.Path(AbsUsrSrc.Append("nspr.zip"), false, pkg.NewHTTPGet(
|
||||
nil, "https://hg-edge.mozilla.org/projects/nspr/archive/"+
|
||||
"NSPR_"+version0+"_RTM.zip",
|
||||
mustDecode(checksum0),
|
||||
)))
|
||||
), &MakeAttr{
|
||||
Paths: []pkg.ExecPath{
|
||||
pkg.Path(AbsUsrSrc.Append("nspr.zip"), false, pkg.NewHTTPGet(
|
||||
nil, "https://hg-edge.mozilla.org/projects/nspr/archive/"+
|
||||
"NSPR_"+version0+"_RTM.zip",
|
||||
mustDecode(checksum0),
|
||||
)),
|
||||
},
|
||||
|
||||
Writable: true,
|
||||
OmitDefaults: true,
|
||||
SkipConfigure: true,
|
||||
InPlace: true,
|
||||
|
||||
ScriptEarly: `
|
||||
unzip /usr/src/nspr.zip -d /usr/src
|
||||
mv '/usr/src/nspr-NSPR_` + version0 + `_RTM' /usr/src/nspr
|
||||
cd /usr/src/nss
|
||||
`,
|
||||
SkipCheck: true,
|
||||
Make: []string{
|
||||
"CCC=clang++",
|
||||
"NSDISTMODE=copy",
|
||||
"BUILD_OPT=1",
|
||||
"USE_64=1",
|
||||
"nss_build_all",
|
||||
},
|
||||
ScriptInstall: `
|
||||
mkdir -p /work/system/nss
|
||||
cp -r \
|
||||
/usr/src/dist/. \
|
||||
lib/ckfw/builtins/certdata.txt \
|
||||
/work/system/nss
|
||||
`,
|
||||
},
|
||||
t.Load(Perl),
|
||||
t.Load(Python),
|
||||
t.Load(Unzip),
|
||||
t.Load(Gawk),
|
||||
t.Load(Coreutils),
|
||||
|
||||
t.Load(Zlib),
|
||||
t.Load(KernelHeaders),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[NSS] = Toolchain.newNSS }
|
||||
|
||||
|
||||
75
internal/rosa/stage0.go
Normal file
75
internal/rosa/stage0.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
func (t Toolchain) newStage0() pkg.Artifact {
|
||||
musl, compilerRT, runtimes, clang := t.NewLLVM()
|
||||
return t.New("rosa-stage0", 0, []pkg.Artifact{
|
||||
musl,
|
||||
compilerRT,
|
||||
runtimes,
|
||||
clang,
|
||||
|
||||
t.Load(Bzip2),
|
||||
|
||||
t.Load(Patch),
|
||||
t.Load(Make),
|
||||
t.Load(CMake),
|
||||
t.Load(Ninja),
|
||||
|
||||
t.Load(Libffi),
|
||||
t.Load(Python),
|
||||
t.Load(Perl),
|
||||
t.Load(Diffutils),
|
||||
t.Load(Bash),
|
||||
t.Load(Gawk),
|
||||
t.Load(Coreutils),
|
||||
t.Load(Findutils),
|
||||
|
||||
t.Load(KernelHeaders),
|
||||
}, nil, nil, `
|
||||
umask 377
|
||||
tar \
|
||||
-vjc \
|
||||
-C / \
|
||||
-f /work/stage0-`+triplet()+`.tar.bz2 \
|
||||
system bin usr/bin/env
|
||||
`)
|
||||
}
|
||||
func init() { artifactsF[Stage0] = Toolchain.newStage0 }
|
||||
|
||||
var (
|
||||
// stage0 stores the tarball unpack artifact.
|
||||
stage0 pkg.Artifact
|
||||
// stage0Once is for lazy initialisation of stage0.
|
||||
stage0Once sync.Once
|
||||
)
|
||||
|
||||
// NewStage0 returns a stage0 distribution created from curing [Stage0].
|
||||
func NewStage0() pkg.Artifact {
|
||||
stage0Once.Do(func() {
|
||||
var seed string
|
||||
switch runtime.GOARCH {
|
||||
case "amd64":
|
||||
seed = "tqM1Li15BJ-uFG8zU-XjgFxoN_kuzh1VxrSDVUVa0vGmo-NeWapSftH739sY8EAg"
|
||||
case "arm64":
|
||||
seed = "CJj3ZSnRyLmFHlWIQtTPQD9oikOZY4cD_mI3v_-LIYc2hhg-cq_CZFBLzQBAkFIn"
|
||||
|
||||
default:
|
||||
panic("unsupported target " + runtime.GOARCH)
|
||||
}
|
||||
|
||||
stage0 = pkg.NewHTTPGetTar(
|
||||
nil, "https://hakurei.app/seed/20260210/"+
|
||||
"stage0-"+triplet()+".tar.bz2",
|
||||
mustDecode(seed),
|
||||
pkg.TarBzip2,
|
||||
)
|
||||
})
|
||||
return stage0
|
||||
}
|
||||
40
internal/rosa/tamago.go
Normal file
40
internal/rosa/tamago.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
func (t Toolchain) newTamaGo() pkg.Artifact {
|
||||
const (
|
||||
version = "1.26.0"
|
||||
checksum = "5XkfbpTpSdPJfwtTfUegfdu4LUy8nuZ7sCondiRIxTJI9eQONi8z_O_dq9yDkjw8"
|
||||
)
|
||||
return t.New("tamago-go"+version, 0, []pkg.Artifact{
|
||||
t.Load(Bash),
|
||||
t.Load(Go),
|
||||
}, nil, []string{
|
||||
"CC=cc",
|
||||
"GOCACHE=/tmp/gocache",
|
||||
}, `
|
||||
mkdir /work/system # "${TMPDIR}"
|
||||
cp -r /usr/src/tamago /work/system
|
||||
cd /work/system/tamago/src
|
||||
chmod -R +w ..
|
||||
|
||||
sed -i \
|
||||
's,/lib/ld-musl-`+linuxArch()+`.so.1,/system/bin/linker,' \
|
||||
cmd/link/internal/`+runtime.GOARCH+`/obj.go
|
||||
rm \
|
||||
os/root_unix_test.go
|
||||
|
||||
./all.bash
|
||||
`, pkg.Path(AbsUsrSrc.Append("tamago"), false, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/usbarmory/tamago-go/archive/refs/tags/"+
|
||||
"tamago-go"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
)))
|
||||
}
|
||||
func init() { artifactsF[TamaGo] = Toolchain.newTamaGo }
|
||||
@@ -7,16 +7,18 @@ func (t Toolchain) newToybox(suffix, script string) pkg.Artifact {
|
||||
version = "0.8.13"
|
||||
checksum = "rZ1V1ATDte2WeQZanxLVoiRGdfPXhMlEo5-exX-e-ml8cGn9qOv0ABEUVZpX3wTI"
|
||||
)
|
||||
return t.New("toybox-"+version+suffix, TEarly, stage3Concat(t, []pkg.Artifact{},
|
||||
return t.New("toybox-"+version+suffix, TEarly, stage0Concat(t, []pkg.Artifact{},
|
||||
t.Load(Make),
|
||||
t.Load(Bash),
|
||||
t.Load(Gzip),
|
||||
|
||||
t.Load(KernelHeaders),
|
||||
), nil, stage3Concat(t, []string{},
|
||||
), nil, stage0Concat(t, []string{},
|
||||
"ROSA_CHECK=make USER=cure tests",
|
||||
), `
|
||||
ln -s ../system/bin/bash /bin/ || true
|
||||
chmod +w /bin/
|
||||
ln -rs "$(which bash)" /bin/ || true
|
||||
|
||||
cd /usr/src/toybox
|
||||
chmod +w kconfig tests
|
||||
rm \
|
||||
|
||||
49
internal/rosa/util-linux.go
Normal file
49
internal/rosa/util-linux.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package rosa
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"hakurei.app/internal/pkg"
|
||||
)
|
||||
|
||||
func (t Toolchain) newUtilLinux() pkg.Artifact {
|
||||
const (
|
||||
version = "2.41.3"
|
||||
checksum = "gPTd5JJ2ho_Rd0qainuogcLiiWwKSXEZPXN3yCCRl0m0KBgMaqwFuMjYgu9z8zCH"
|
||||
)
|
||||
return t.NewViaMake("util-linux", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://www.kernel.org/pub/linux/utils/util-linux/"+
|
||||
"v"+strings.Join(strings.SplitN(version, ".", 3)[:2], ".")+
|
||||
"/util-linux-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &MakeAttr{
|
||||
ScriptEarly: `
|
||||
ln -s ../system/bin/bash /bin/
|
||||
`,
|
||||
|
||||
Configure: [][2]string{
|
||||
{"disable-use-tty-group"},
|
||||
{"disable-makeinstall-setuid"},
|
||||
{"disable-makeinstall-chown"},
|
||||
{"enable-fs-paths-default", "" +
|
||||
"/system/sbin:" +
|
||||
"/system/sbin/fs.d:" +
|
||||
"/system/sbin/fs"},
|
||||
|
||||
{"disable-su"},
|
||||
{"disable-liblastlog2"},
|
||||
{"disable-pam-lastlog2"},
|
||||
},
|
||||
|
||||
// check script claims:
|
||||
// For development purpose only.
|
||||
// Don't execute on production system!
|
||||
SkipCheck: true,
|
||||
},
|
||||
t.Load(Bash),
|
||||
|
||||
t.Load(KernelHeaders),
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[UtilLinux] = Toolchain.newUtilLinux }
|
||||
@@ -7,43 +7,31 @@ func (t Toolchain) newWayland() pkg.Artifact {
|
||||
version = "1.24.0"
|
||||
checksum = "JxgLiFRRGw2D3uhVw8ZeDbs3V7K_d4z_ypDog2LBqiA_5y2vVbUAk5NT6D5ozm0m"
|
||||
)
|
||||
return t.New("wayland-"+version, 0, []pkg.Artifact{
|
||||
t.Load(Python),
|
||||
t.Load(Meson),
|
||||
t.Load(PkgConfig),
|
||||
t.Load(CMake),
|
||||
t.Load(Ninja),
|
||||
return t.NewViaMeson("wayland", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://gitlab.freedesktop.org/wayland/wayland/"+
|
||||
"-/archive/"+version+"/wayland-"+version+".tar.bz2",
|
||||
mustDecode(checksum),
|
||||
pkg.TarBzip2,
|
||||
), &MesonAttr{
|
||||
Writable: true,
|
||||
ScriptEarly: `
|
||||
cd /usr/src/wayland
|
||||
chmod +w tests tests/sanity-test.c
|
||||
echo 'int main(){}' > tests/sanity-test.c
|
||||
`,
|
||||
Configure: [][2]string{
|
||||
{"Ddefault_library", "both"},
|
||||
{"Ddocumentation", "false"},
|
||||
{"Dtests", "true"},
|
||||
},
|
||||
},
|
||||
t.Load(Gawk),
|
||||
t.Load(Diffutils),
|
||||
|
||||
t.Load(Libffi),
|
||||
t.Load(Libexpat),
|
||||
t.Load(Libxml2),
|
||||
}, nil, nil, `
|
||||
cd /usr/src/wayland
|
||||
chmod +w tests tests/sanity-test.c
|
||||
echo 'int main(){}' > tests/sanity-test.c
|
||||
|
||||
cd "$(mktemp -d)"
|
||||
meson setup \
|
||||
--reconfigure \
|
||||
--buildtype=release \
|
||||
--prefix=/system \
|
||||
--prefer-static \
|
||||
-Ddocumentation=false \
|
||||
-Dtests=true \
|
||||
-Ddefault_library=both \
|
||||
. /usr/src/wayland
|
||||
meson compile
|
||||
meson test
|
||||
meson install \
|
||||
--destdir=/work
|
||||
`, pkg.Path(AbsUsrSrc.Append("wayland"), true, pkg.NewHTTPGetTar(
|
||||
nil, "https://gitlab.freedesktop.org/wayland/wayland/"+
|
||||
"-/archive/"+version+"/wayland-"+version+".tar.bz2",
|
||||
mustDecode(checksum),
|
||||
pkg.TarBzip2,
|
||||
)))
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[Wayland] = Toolchain.newWayland }
|
||||
|
||||
@@ -52,33 +40,68 @@ func (t Toolchain) newWaylandProtocols() pkg.Artifact {
|
||||
version = "1.47"
|
||||
checksum = "B_NodZ7AQfCstcx7kgbaVjpkYOzbAQq0a4NOk-SA8bQixAE20FY3p1-6gsbPgHn9"
|
||||
)
|
||||
return t.New("wayland-protocols-"+version, 0, []pkg.Artifact{
|
||||
t.Load(Python),
|
||||
t.Load(Meson),
|
||||
t.Load(PkgConfig),
|
||||
t.Load(CMake),
|
||||
t.Load(Ninja),
|
||||
return t.NewViaMeson("wayland-protocols", version, t.NewPatchedSource(
|
||||
"wayland-protocols", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://gitlab.freedesktop.org/wayland/wayland-protocols/"+
|
||||
"-/archive/"+version+"/wayland-protocols-"+version+".tar.bz2",
|
||||
mustDecode(checksum),
|
||||
pkg.TarBzip2,
|
||||
), false, [2]string{"build-only", `From 8b4c76275fa1b6e0a99a53494151d9a2c907144d Mon Sep 17 00:00:00 2001
|
||||
From: "A. Wilcox" <AWilcox@Wilcox-Tech.com>
|
||||
Date: Fri, 8 Nov 2024 11:27:25 -0600
|
||||
Subject: [PATCH] tests: Make build-only tests actually build-only
|
||||
|
||||
The goal behind the pedantic compiler tests are to ensure that the code
|
||||
that wayland-scanner is generating can be compiled in pedantic mode by
|
||||
the system C compiler.
|
||||
|
||||
Trying to execute the built tests may fail because of undefined symbols.
|
||||
This affects certain platforms more than others; Linux/musl and Darwin
|
||||
are examples of platforms that cannot execute binaries with undefined
|
||||
symbols. This meant tests needlessly failed on these platforms.
|
||||
|
||||
Signed-off-by: A. Wilcox <AWilcox@Wilcox-Tech.com>
|
||||
Closes: #48, #228
|
||||
---
|
||||
tests/meson.build | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/tests/meson.build b/tests/meson.build
|
||||
index aa216ec2..5a93bb36 100644
|
||||
--- a/tests/meson.build
|
||||
+++ b/tests/meson.build
|
||||
@@ -1,4 +1,5 @@
|
||||
prog_scan_sh = find_program('scan.sh')
|
||||
+prog_true = find_program('true')
|
||||
|
||||
libwayland = [
|
||||
dependency('wayland-client'),
|
||||
@@ -100,7 +101,7 @@ foreach protocol_file : protocol_files
|
||||
test_source,
|
||||
client_header,
|
||||
server_header,
|
||||
- code
|
||||
+ code,
|
||||
],
|
||||
link_args: extra_linker_flags,
|
||||
dependencies: libwayland,
|
||||
@@ -111,7 +112,7 @@ foreach protocol_file : protocol_files
|
||||
'-Werror' ],
|
||||
install: false,
|
||||
)
|
||||
- test(test_name, pedantic_test_executable)
|
||||
+ test(test_name, prog_true, depends : [pedantic_test_executable])
|
||||
|
||||
# Check that the header
|
||||
if not protocol_file.contains('xdg-foreign-unstable-v1')
|
||||
--
|
||||
GitLab
|
||||
`},
|
||||
), nil,
|
||||
t.Load(Wayland),
|
||||
t.Load(Libffi),
|
||||
t.Load(Libexpat),
|
||||
t.Load(Libxml2),
|
||||
}, nil, nil, `
|
||||
cd "$(mktemp -d)"
|
||||
meson setup \
|
||||
--reconfigure \
|
||||
--buildtype=release \
|
||||
--prefix=/system \
|
||||
--prefer-static \
|
||||
. /usr/src/wayland-protocols
|
||||
meson compile
|
||||
meson install \
|
||||
--destdir=/work
|
||||
`, pkg.Path(AbsUsrSrc.Append("wayland-protocols"), false, pkg.NewHTTPGetTar(
|
||||
nil, "https://gitlab.freedesktop.org/wayland/wayland-protocols/"+
|
||||
"-/archive/"+version+"/wayland-protocols-"+version+".tar.bz2",
|
||||
mustDecode(checksum),
|
||||
pkg.TarBzip2,
|
||||
)))
|
||||
)
|
||||
}
|
||||
func init() { artifactsF[WaylandProtocols] = Toolchain.newWaylandProtocols }
|
||||
|
||||
@@ -16,6 +16,7 @@ func (t Toolchain) newZlib() pkg.Artifact {
|
||||
Env: []string{
|
||||
"CC=clang -fPIC",
|
||||
},
|
||||
Host: `""`,
|
||||
Build: `""`,
|
||||
})
|
||||
}
|
||||
|
||||
23
internal/rosa/zstd.go
Normal file
23
internal/rosa/zstd.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package rosa
|
||||
|
||||
import "hakurei.app/internal/pkg"
|
||||
|
||||
func (t Toolchain) newZstd() pkg.Artifact {
|
||||
const (
|
||||
version = "1.5.7"
|
||||
checksum = "4XhfR7DwVkwo1R-TmYDAJOcx9YXv9WSFhcFUe3hWEAMmdMLPhFaznCqYIA19_xxV"
|
||||
)
|
||||
return t.NewViaCMake("zstd", version, pkg.NewHTTPGetTar(
|
||||
nil, "https://github.com/facebook/zstd/releases/download/"+
|
||||
"v"+version+"/zstd-"+version+".tar.gz",
|
||||
mustDecode(checksum),
|
||||
pkg.TarGzip,
|
||||
), &CMakeAttr{
|
||||
Append: []string{"build", "cmake"},
|
||||
Cache: [][2]string{
|
||||
{"CMAKE_BUILD_TYPE", "Release"},
|
||||
{"CMAKE_INSTALL_LIBDIR", "lib"},
|
||||
},
|
||||
})
|
||||
}
|
||||
func init() { artifactsF[Zstd] = Toolchain.newZstd }
|
||||
@@ -95,6 +95,9 @@
|
||||
];
|
||||
};
|
||||
|
||||
# Disk image is too small for some tests:
|
||||
boot.tmp.useTmpfs = true;
|
||||
|
||||
environment.hakurei = {
|
||||
enable = true;
|
||||
stateDir = "/var/lib/hakurei";
|
||||
|
||||
Reference in New Issue
Block a user