Keep the full test suite selected without new fixture derivations. Assisted-by: SurmAgent:unknown [read] [edit] [bash]
201 lines
9.9 KiB
Nix
201 lines
9.9 KiB
Nix
{
|
|
description = "Sausage: a world of WASI programs and durable agents";
|
|
inputs = {
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
|
flake-utils.url = "github:numtide/flake-utils";
|
|
rust-overlay.url = "github:oxalica/rust-overlay";
|
|
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
|
|
crane.url = "github:ipetkov/crane";
|
|
kache = {
|
|
url = "github:kunobi-ninja/kache/stable";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
};
|
|
outputs = { nixpkgs, flake-utils, rust-overlay, crane, kache, ... }:
|
|
flake-utils.lib.eachSystem flake-utils.lib.allSystems (system:
|
|
let
|
|
pkgs = import nixpkgs { inherit system; overlays = [ rust-overlay.overlays.default ]; };
|
|
inherit (pkgs) lib;
|
|
rust = pkgs.rust-bin.stable.latest.default.override {
|
|
targets = [ "wasm32-wasip2" ];
|
|
extensions = [ "rust-src" ];
|
|
};
|
|
craneLib = (crane.mkLib pkgs).overrideToolchain rust;
|
|
src = ./. |> pkgs.nix-gitignore.gitignoreSource [];
|
|
tools = ./userland/tools.json |> builtins.readFile |> builtins.fromJSON;
|
|
commandArgs = tools |> builtins.filter (t: t.package != null)
|
|
|> map (t: t.package) |> lib.unique |> map (p: "-p ${p}") |> lib.concatStringsSep " ";
|
|
mold = lib.optionals pkgs.stdenv.hostPlatform.isLinux [ pkgs.mold ];
|
|
hostTarget = pkgs.stdenv.hostPlatform.rust.rustcTarget |> builtins.replaceStrings [ "-" ] [ "_" ] |> lib.toUpper;
|
|
moldVar = "CARGO_TARGET_${hostTarget}_RUSTFLAGS";
|
|
moldEnv = lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { ${moldVar} = "-C link-arg=-fuse-ld=mold"; };
|
|
builderTools = [ kache.packages.${system}.default pkgs.bubblewrap pkgs.nushell pkgs.wasm-tools pkgs.bash pkgs.coreutils ];
|
|
runtimePath = [ rust pkgs.stdenv.cc ] ++ builderTools ++ mold |> lib.makeBinPath;
|
|
wasiCc = pkgs.pkgsCross.wasi32.stdenv.cc;
|
|
wasiCcEnv = {
|
|
CC_wasm32_wasip2 = "${wasiCc}/bin/${wasiCc.targetPrefix}cc";
|
|
AR_wasm32_wasip2 = "${wasiCc}/bin/${wasiCc.targetPrefix}ar";
|
|
};
|
|
v8Archive = pkgs.fetchurl {
|
|
url = "https://github.com/denoland/rusty_v8/releases/download/v150.4.0/librusty_v8_simdutf_release_${pkgs.stdenv.hostPlatform.rust.rustcTarget}.a.gz";
|
|
hash = {
|
|
x86_64-linux = "sha256-9IdiyhDR8fxgWkQcWuQw7Izh6egPFNePvELLh4wwtHY=";
|
|
aarch64-linux = "sha256-U54oOBWjlqV5bzKFi0LlF7hY66rqqtBdAykO6MhkpSc=";
|
|
x86_64-darwin = "sha256-p1AnH+xrIRRX7Qpc99LqsZJLJlYhqC2oarlZ1v8II+Q=";
|
|
aarch64-darwin = "sha256-Wu/9jVoMG3msHXCvg9WxkJllX9nGRaeU3EPxAfd5g4w=";
|
|
}.${system};
|
|
};
|
|
# rusty_v8's archive hook prevents downloads inside the Nix sandbox.
|
|
v8Env = { RUSTY_V8_ARCHIVE = v8Archive; };
|
|
cwdInit = pkgs.runCommand "sausage-cwd-init" { nativeBuildInputs = [ rust pkgs.nushell pkgs.wasm-tools ]; } ''
|
|
cp -r ${./userland/cwd-init} cwd-init
|
|
chmod -R u+w cwd-init
|
|
nu cwd-init/build.nu
|
|
mkdir $out
|
|
cp cwd-init/init.o $out/
|
|
'';
|
|
linker = pkgs.runCommand "sausage-wasi-link" { nativeBuildInputs = [ pkgs.nushell ]; } ''
|
|
cp ${./userland/cwd-init/link.nu} $out
|
|
chmod +x $out
|
|
patchShebangs $out
|
|
'';
|
|
common = {
|
|
pname = "sausage";
|
|
version = "0.3.0";
|
|
inherit src;
|
|
strictDeps = true;
|
|
nativeBuildInputs = [ pkgs.pkg-config pkgs.cmake pkgs.python3 pkgs.perl pkgs.nushell pkgs.wasm-tools ];
|
|
# The WASI linker initializes each guest's cwd before main.
|
|
SAUSAGE_CWD_INIT = "${cwdInit}/init.o";
|
|
CARGO_TARGET_WASM32_WASIP2_LINKER = linker;
|
|
CARGO_TARGET_WASM32_WASIP2_RUSTFLAGS = "-C link-arg=sausage-cwd-init";
|
|
# Registry gix crates need the real APIs of the local WASI patches.
|
|
extraDummyScript = ''
|
|
chmod -R u+w $out/userland/git/vendor
|
|
cp -r ${./userland/git/vendor}/. $out/userland/git/vendor/
|
|
'';
|
|
} // wasiCcEnv;
|
|
hostArgs = common // v8Env // moldEnv // {
|
|
cargoExtraArgs = "--locked -p sausage";
|
|
buildInputs = [ pkgs.openssl ];
|
|
nativeBuildInputs = common.nativeBuildInputs ++ mold;
|
|
doCheck = false;
|
|
};
|
|
hostArtifacts = craneLib.buildDepsOnly hostArgs;
|
|
userlandArgs = common // {
|
|
pname = "sausage-userland";
|
|
CARGO_BUILD_TARGET = "wasm32-wasip2";
|
|
cargoExtraArgs = "--locked ${commandArgs}";
|
|
doCheck = false;
|
|
};
|
|
userlandArtifacts = craneLib.buildDepsOnly userlandArgs;
|
|
userland = craneLib.buildPackage (userlandArgs // { cargoArtifacts = userlandArtifacts; });
|
|
goTool = name: source: subPackages:
|
|
(pkgs.buildGoModule {
|
|
pname = "sausage-${name}";
|
|
version = "vendored";
|
|
src = source;
|
|
inherit subPackages;
|
|
vendorHash = null;
|
|
env.CGO_ENABLED = "0";
|
|
ldflags = [ "-s" "-w" ];
|
|
doCheck = false;
|
|
dontStrip = true;
|
|
postInstall = ''
|
|
mv $out/bin/wasip1_wasm/* $out/bin/${name}.wasm
|
|
rmdir $out/bin/wasip1_wasm
|
|
'';
|
|
}).overrideAttrs (old: { env = old.env // { GOOS = "wasip1"; GOARCH = "wasm"; }; });
|
|
awk = goTool "awk" ./userland/goawk/source [ "." ];
|
|
esbuild = goTool "esbuild" ./userland/esbuild/source [ "cmd/esbuild" ];
|
|
qjs = pkgs.stdenv.mkDerivation {
|
|
pname = "sausage-qjs";
|
|
version = "0.18.0";
|
|
src = ./userland/qjs/source;
|
|
nativeBuildInputs = [ pkgs.cmake pkgs.llvmPackages_21.lld ];
|
|
cmakeFlags = [ "-DCMAKE_SYSTEM_NAME=WASI" "-DCMAKE_C_COMPILER=${wasiCcEnv.CC_wasm32_wasip2}" "-DCMAKE_AR=${wasiCcEnv.AR_wasm32_wasip2}" "-DCMAKE_RANLIB=${wasiCc}/bin/${wasiCc.targetPrefix}ranlib" ];
|
|
buildFlags = [ "qjs_exe" ];
|
|
installPhase = ''
|
|
runHook preInstall
|
|
mkdir -p $out/bin
|
|
cp qjs $out/bin/qjs.wasm
|
|
runHook postInstall
|
|
'';
|
|
dontStrip = true;
|
|
};
|
|
bundle = pkgs.runCommand "sausage-bundle" {} ''
|
|
mkdir -p $out/bin $out/src/sausage $out/etc/sausage $out/etc/systemd/system/multi-user.target.wants $out/srv/www
|
|
${tools |> map (t: ''
|
|
cp ${(if t.package != null then userland else { inherit awk esbuild qjs; }.${t.binary})}/bin/${t.binary}.wasm $out/bin/
|
|
${t.names |> map (name: ''
|
|
${lib.optionalString (name != t.binary) "ln -s ${t.binary}.wasm $out/bin/${name}.wasm"}
|
|
ln -s ${t.binary}.wasm $out/bin/${name}
|
|
'') |> lib.concatStrings}
|
|
'') |> lib.concatStrings}
|
|
cp -R --no-preserve=mode ${src}/. $out/src/sausage/
|
|
cp ${./config/config.yaml} $out/etc/sausage/config.yaml
|
|
cp -R ${./config/roster} $out/etc/sausage/roster
|
|
cp ${./userland/web/web.service} $out/etc/systemd/system/web.service
|
|
touch $out/etc/systemd/system/multi-user.target.wants/web.service
|
|
cp ${./userland/web/index.html} ${./userland/web/credentials.js} ${./userland/web/credentials-view.js} $out/srv/www/
|
|
'';
|
|
sausageUnwrapped = craneLib.buildPackage (hostArgs // {
|
|
cargoArtifacts = hostArtifacts;
|
|
doNotRemoveReferencesToVendorDir = true;
|
|
});
|
|
# Keep the wrapper separate from crane's removal of toolchain references.
|
|
sausage = pkgs.symlinkJoin {
|
|
name = "sausage-${sausageUnwrapped.version}";
|
|
paths = [ sausageUnwrapped ];
|
|
nativeBuildInputs = [ pkgs.makeWrapper ];
|
|
postBuild = ''
|
|
wrapProgram $out/bin/sausage --set-default SAUSAGE_USERLAND ${bundle} \
|
|
--prefix PATH : ${runtimePath} \
|
|
--set-default CC_wasm32_wasip2 ${wasiCcEnv.CC_wasm32_wasip2} \
|
|
--set-default AR_wasm32_wasip2 ${wasiCcEnv.AR_wasm32_wasip2} \
|
|
${lib.optionalString pkgs.stdenv.hostPlatform.isLinux "--set-default ${moldVar} '-C link-arg=-fuse-ld=mold'"}
|
|
'';
|
|
meta.mainProgram = "sausage";
|
|
};
|
|
in {
|
|
packages = { default = sausage; inherit bundle userland awk esbuild qjs; };
|
|
checks.package = sausage;
|
|
checks.tests = craneLib.cargoTest (hostArgs // {
|
|
cargoArtifacts = hostArtifacts;
|
|
cargoExtraArgs = "--locked -p sausage -p sausage-vfs";
|
|
cargoTestExtraArgs = "-- --nocapture";
|
|
doCheck = true;
|
|
nativeBuildInputs = hostArgs.nativeBuildInputs ++ builderTools ++ [ pkgs.git pkgs.nodejs ];
|
|
SAUSAGE_TEST_NO_BUILDER_SANDBOX = "1";
|
|
SAUSAGE_NIX_CHECK = "1";
|
|
SAUSAGE_USERLAND = bundle;
|
|
preCheck = ''
|
|
export SAUSAGE_CACHE="$TMPDIR/sausage-cache"
|
|
export CARGO_TARGET_DIR="$PWD/target"
|
|
export RUST_BACKTRACE=1
|
|
mkdir -p target/userland
|
|
ln -s ${bundle} target/bundle
|
|
ln -s ${bundle} target/userland/bundle
|
|
'';
|
|
});
|
|
checks.shell = pkgs.runCommand "sausage-shell" {} ''
|
|
export SAUSAGE_CACHE="$TMPDIR/sausage-cache"
|
|
${sausage}/bin/sausage sh "$TMPDIR/world" -c \
|
|
'set -e; echo hi | tr a-z A-Z; git --version; rg --version; awk "BEGIN {print 42}"; echo payload > /payload; tar -cf /test.tar /payload; tar -tf /test.tar; qjs -e "console.log(42)"; cargo --help; undo list' > output
|
|
cat output
|
|
grep -qx HI output
|
|
grep -q 'git version' output
|
|
grep -q ripgrep output
|
|
grep -qx 42 output
|
|
grep -q payload output
|
|
test -d "$TMPDIR/world/world/src/sausage/extensions"
|
|
test -f "$TMPDIR/world/world/etc/sausage/roster/sausage.md"
|
|
touch $out
|
|
'';
|
|
apps.default = { type = "app"; program = "${sausage}/bin/sausage"; };
|
|
devShells.default = pkgs.mkShell (v8Env // wasiCcEnv // moldEnv // {
|
|
packages = [ rust pkgs.wasmtime pkgs.openssl pkgs.pkg-config pkgs.go pkgs.cmake pkgs.llvmPackages_21.lld ] ++ builderTools ++ mold;
|
|
});
|
|
});
|
|
}
|