/ nix / flakebox.nix
flakebox.nix
  1  { pkgs, flakeboxLib, toolchains, advisory-db, profiles, craneMultiBuild, replaceGitHash }:
  2  let
  3    lib = pkgs.lib;
  4  
  5    # `moreutils/bin/parallel` and `parallel/bin/parallel` conflict, so just use
  6    # the binary we need from `moreutils`
  7    moreutils-ts = pkgs.writeShellScriptBin "ts" "exec ${pkgs.moreutils}/bin/ts \"$@\"";
  8  
  9    # placeholder we use to avoid actually needing to detect hash via running `git`
 10    # 012345... for easy recognizability (in case something went wrong),
 11    # rest randomized to avoid accidentally overwriting innocent bytes in the binary
 12    gitHashPlaceholderValue = "01234569abcdef7afa1d2683a099c7af48a523c1";
 13  
 14    filterWorkspaceDepsBuildFilesRegex = [ "Cargo.lock" "Cargo.toml" ".cargo" ".cargo/.*" ".config" ".config/.*" ".*/Cargo.toml" ".*/proto/.*" ];
 15  
 16    commonSrc = builtins.path { path = ./..; name = "fedimint"; };
 17  
 18    filterSrcWithRegexes = regexes: src:
 19      let
 20        basePath = toString src + "/";
 21      in
 22      lib.cleanSourceWith {
 23        filter = (path: type:
 24          let
 25            relPath = lib.removePrefix basePath (toString path);
 26            includePath =
 27              (type == "directory") ||
 28              lib.any
 29                (re: builtins.match re relPath != null)
 30                regexes;
 31          in
 32          # uncomment to debug:
 33            # builtins.trace "${relPath}: ${lib.boolToString includePath}"
 34          includePath
 35        );
 36        inherit src;
 37      };
 38  
 39    # Filter only files needed to build project dependencies
 40    #
 41    # To get good build times it's vitally important to not have to
 42    # rebuild derivation needlessly. The way Nix caches things
 43    # is very simple: if any input file changed, derivation needs to
 44    # be rebuild.
 45    #
 46    # For this reason this filter function strips the `src` from
 47    # any files that are not relevant to the build.
 48    #
 49    # Lile `filterWorkspaceFiles` but doesn't even need *.rs files
 50    # (because they are not used for building dependencies)
 51    filterWorkspaceDepsBuildFiles = src: filterSrcWithRegexes filterWorkspaceDepsBuildFilesRegex src;
 52  
 53    # Filter only files relevant to building the workspace
 54    filterWorkspaceBuildFiles = src: filterSrcWithRegexes (filterWorkspaceDepsBuildFilesRegex ++ [ ".*\.rs" ".*\.html" ".*/proto/.*" "db/migrations/.*" "devimint/src/cfg/.*" "docs/.*\.md" ]) src;
 55  
 56    # Like `filterWorkspaceFiles` but with `./scripts/` included
 57    filterWorkspaceTestFiles = src: filterSrcWithRegexes (filterWorkspaceDepsBuildFilesRegex ++ [ ".*\.rs" ".*\.html" ".*/proto/.*" "db/migrations/.*" "devimint/src/cfg/.*" "scripts/.*" "docs/.*\.md" ]) src;
 58  
 59    filterWorkspaceAuditFiles = src: filterSrcWithRegexes (filterWorkspaceDepsBuildFilesRegex ++ [ "deny.toml" ]) src;
 60  
 61    # env vars for linking rocksdb
 62    commonEnvsShellRocksdbLink =
 63      let
 64        target_underscores = lib.strings.replaceStrings [ "-" ] [ "_" ] pkgs.stdenv.buildPlatform.config;
 65      in
 66      {
 67        ROCKSDB_STATIC = "true";
 68        ROCKSDB_LIB_DIR = "${pkgs.rocksdb}/lib/";
 69  
 70        "ROCKSDB_${target_underscores}_STATIC" = "true";
 71        "ROCKSDB_${target_underscores}_LIB_DIR" = "${pkgs.rocksdb}/lib/";
 72      } // pkgs.lib.optionalAttrs (!(pkgs.stdenv.isDarwin && pkgs.stdenv.isx86_64)) {
 73        # FIX: error: don't yet have a `targetPackages.darwin.LibsystemCross for x86_64-apple-darwin`
 74        SNAPPY_LIB_DIR = "${pkgs.pkgsStatic.snappy}/lib/";
 75        "SNAPPY_${target_underscores}_LIB_DIR" = "${pkgs.pkgsStatic.snappy}/lib/";
 76      } // pkgs.lib.optionalAttrs (!pkgs.stdenv.isDarwin) {
 77        # macos can't static libraries
 78        SNAPPY_STATIC = "true";
 79        "SNAPPY_${target_underscores}_STATIC" = "true";
 80      };
 81  
 82    commonEnvsShellRocksdbLinkCross = commonEnvsShellRocksdbLink // pkgs.lib.optionalAttrs (!pkgs.stdenv.isDarwin) {
 83      # TODO: could we used the android-nixpkgs toolchain instead of another one?
 84      # ROCKSDB_aarch64_linux_android_STATIC = "true";
 85      # SNAPPY_aarch64_linux_android_STATIC = "true";
 86      # ROCKSDB_aarch64_linux_android_LIB_DIR = "${pkgs-unstable.pkgsCross.aarch64-android-prebuilt.rocksdb}/lib/";
 87      # SNAPPY_aarch64_linux_android_LIB_DIR = "${pkgs-unstable.pkgsCross.aarch64-android-prebuilt.pkgsStatic.snappy}/lib/";
 88  
 89      # BROKEN
 90      # error: "No timer implementation for this platform"
 91      # ROCKSDB_armv7_linux_androideabi_STATIC = "true";
 92      # SNAPPY_armv7_linux_androideabi_STATIC = "true";
 93      # ROCKSDB_armv7_linux_androideabi_LIB_DIR = "${pkgs-unstable.pkgsCross.armv7a-android-prebuilt.rocksdb}/lib/";
 94      # SNAPPY_armv7_linux_androideabi_LIB_DIR = "${pkgs-unstable.pkgsCross.armv7a-android-prebuilt.pkgsStatic.snappy}/lib/";
 95  
 96      # x86-64-linux-android doesn't have a toolchain in nixpkgs
 97    } // pkgs.lib.optionalAttrs pkgs.stdenv.isDarwin {
 98      # broken: fails to compile with:
 99      # `linux-headers-android-common> sh: line 1: gcc: command not found`
100      # ROCKSDB_aarch64_linux_android_STATIC = "true";
101      # SNAPPY_aarch64_linux_android_STATIC = "true";
102      # ROCKSDB_aarch64_linux_android_LIB_DIR = "${pkgs-unstable.pkgsCross.aarch64-android.rocksdb}/lib/";
103      # SNAPPY_aarch64_linux_android_LIB_DIR = "${pkgs-unstable.pkgsCross.aarch64-android.pkgsStatic.snappy}/lib/";
104  
105      # requires downloading Xcode manually and adding to /nix/store
106      # then running with `env NIXPKGS_ALLOW_UNFREE=1 nix develop -L --impure`
107      # maybe we could live with it?
108      # ROCKSDB_aarch64_apple_ios_STATIC = "true";
109      # SNAPPY_aarch64_apple_ios_STATIC = "true";
110      # ROCKSDB_aarch64_apple_ios_LIB_DIR = "${pkgs-unstable.pkgsCross.iphone64.rocksdb}/lib/";
111      # SNAPPY_aarch64_apple_ios_LIB_DIR = "${pkgs-unstable.pkgsCross.iphone64.pkgsStatic.snappy}/lib/";
112    };
113  
114    # env variables we want to set in all nix derivations & nix develop shell
115    commonEnvsShell = commonEnvsShellRocksdbLink // {
116      PROTOC = "${pkgs.protobuf}/bin/protoc";
117      PROTOC_INCLUDE = "${pkgs.protobuf}/include";
118    };
119  
120    # env variables we want to set in all nix derivations (but NOT the nix develop shell)
121    commonEnvsBuild = commonEnvsShell // {
122      FEDIMINT_BUILD_FORCE_GIT_HASH = gitHashPlaceholderValue;
123      HOME = "/tmp";
124    };
125  
126    commonArgs = {
127      pname = "fedimint";
128  
129      buildInputs = with pkgs; [
130        openssl
131        pkg-config
132        protobuf
133      ] ++ lib.optionals (!stdenv.isDarwin) [
134        util-linux
135        iproute2
136      ] ++ lib.optionals stdenv.isDarwin [
137        libiconv
138        darwin.apple_sdk.frameworks.Security
139        darwin.apple_sdk.frameworks.SystemConfiguration
140      ];
141  
142      nativeBuildInputs = with pkgs; [
143        pkg-config
144        moreutils-ts
145  
146        # tests
147        (hiPrio pkgs.bashInteractive)
148        bc
149        bitcoind
150        clightning
151        electrs
152        jq
153        lnd
154        netcat
155        perl
156        esplora-electrs
157        procps
158        which
159        cargo-nextest
160        moreutils-ts
161        parallel
162        time
163      ] ++ builtins.attrValues {
164        inherit (pkgs) cargo-nextest;
165      } ++ [
166        # add a command that can be used to lower both CPU and IO priority
167        # of a command to help make it more friendly to other things
168        # potentially sharing the CI or dev machine
169        (if pkgs.stdenv.isLinux then [
170          pkgs.util-linux
171  
172          (pkgs.writeShellScriptBin "runLowPrio" ''
173            set -euo pipefail
174  
175            cmd=()
176            if ${pkgs.which}/bin/which chrt 1>/dev/null 2>/dev/null ; then
177              cmd+=(chrt -i 0)
178            fi
179            if ${pkgs.which}/bin/which ionice 1>/dev/null 2>/dev/null ; then
180              cmd+=(ionice -c 3)
181            fi
182  
183            >&2 echo "Lowering IO priority with ''${cmd[@]}"
184            exec "''${cmd[@]}" "$@"
185          ''
186          )
187        ] else [
188  
189          (pkgs.writeShellScriptBin "runLowPrio" ''
190            exec "$@"
191          ''
192          )
193        ])
194      ]
195  
196      ;
197  
198      # we carefully optimize our debug symbols on cargo level,
199      # and in case of errors and panics, would like to see the
200      # line numbers etc.
201      dontStrip = true;
202    };
203  
204    commonCliTestArgs = commonArgs // {
205      pname = "fedimint-test";
206      # there's no point saving the `./target/` dir
207      doInstallCargoArtifacts = false;
208      # the build command will be the test
209      doCheck = true;
210    };
211  
212  in
213  (flakeboxLib.craneMultiBuild { inherit toolchains profiles; }) (craneLib':
214  let
215    craneLib =
216      (craneLib'.overrideArgs (commonEnvsBuild // commonArgs // {
217        src = filterWorkspaceBuildFiles commonSrc;
218      })).overrideArgs'' (craneLib: args:
219        pkgs.lib.optionalAttrs (!(builtins.elem (craneLib.toolchainName or null) [ null "default" "stable" "nightly" ])) commonEnvsShellRocksdbLinkCross
220      );
221  
222  
223    craneLibTests = craneLib.overrideArgs (commonEnvsBuild // commonCliTestArgs // {
224      src = filterWorkspaceTestFiles commonSrc;
225      # there's no point saving the `./target/` dir
226      doInstallCargoArtifacts = false;
227    });
228  
229  
230    # copied and modified from flakebox, to add `runLowPrio`, due to mistake in flakebox
231    rawBuildPackageGroup = { pname ? null, packages, mainProgram ? null, ... }@origArgs:
232      let
233        args = builtins.removeAttrs origArgs [ "mainProgram" "pname" "packages" ];
234        pname = if builtins.hasAttr "pname" origArgs then "${origArgs.pname}-group" else if builtins.hasAttr "pname" craneLib.args then "${craneLib.args.pname}-group" else null;
235        # "--package x --package y" args passed to cargo
236        pkgsArgs = lib.strings.concatStringsSep " " (builtins.map (name: "--package ${name}") packages);
237  
238        deps = craneLib.buildDepsOnly (args // (lib.optionalAttrs (pname != null) {
239          inherit pname;
240        }) // {
241          buildPhaseCargoCommand = "runLowPrio cargo build --profile $CARGO_PROFILE ${pkgsArgs}";
242        });
243      in
244      craneLib.buildPackage (args // (lib.optionalAttrs (pname != null) {
245        inherit pname;
246      }) // {
247        cargoArtifacts = deps;
248        meta = { inherit mainProgram; };
249        cargoBuildCommand = "runLowPrio cargo build --profile $CARGO_PROFILE";
250        cargoExtraArgs = "${pkgsArgs}";
251      });
252  
253    fedimintBuildPackageGroup = args: replaceGitHash {
254      name = args.pname;
255      package =
256        # ideally this should work:
257        # craneLib.buildPackageGroup (args // { cargoBuildCommand = "runLowPrio cargo build --profile $CARGO_PROFILE"; });
258        rawBuildPackageGroup args;
259      placeholder = gitHashPlaceholderValue;
260    };
261  in
262  rec {
263    inherit commonArgs;
264    inherit commonEnvsShell;
265    inherit commonEnvsShellRocksdbLink;
266    inherit commonEnvsShellRocksdbLinkCross;
267    inherit gitHashPlaceholderValue;
268    commonArgsBase = commonArgs;
269  
270    workspaceDeps = craneLib.buildWorkspaceDepsOnly {
271      buildPhaseCargoCommand = "runLowPrio cargo doc --profile $CARGO_PROFILE --locked ; runLowPrio cargo check --profile $CARGO_PROFILE --all-targets --locked ; runLowPrio cargo build --profile $CARGO_PROFILE --locked --all-targets";
272    };
273  
274    # like `workspaceDeps` but don't run `cargo doc`
275    workspaceDepsNoDocs = craneLib.buildWorkspaceDepsOnly {
276      buildPhaseCargoCommand = "runLowPrio cargo check --profile $CARGO_PROFILE --all-targets --locked ; runLowPrio cargo build --profile $CARGO_PROFILE --locked --all-targets";
277    };
278  
279    workspaceBuild = craneLib.buildWorkspace {
280      cargoArtifacts = workspaceDeps;
281      buildPhaseCargoCommand = "runLowPrio cargo doc --profile $CARGO_PROFILE --locked ; runLowPrio cargo check --profile $CARGO_PROFILE --all-targets --locked ; runLowPrio cargo build --profile $CARGO_PROFILE --locked --all-targets";
282    };
283  
284    workspaceDepsWasmTest = craneLib.buildWorkspaceDepsOnly {
285      pname = "${commonArgs.pname}-wasm-test";
286      buildPhaseCargoCommand = "runLowPrio cargo build --profile $CARGO_PROFILE --locked --tests -p fedimint-wasm-tests";
287    };
288  
289    workspaceBuildWasmTest = craneLib.buildWorkspace {
290      pnameSuffix = "-workspace-wasm-test";
291      cargoArtifacts = workspaceDepsWasmTest;
292      buildPhaseCargoCommand = "runLowPrio cargo build --profile $CARGO_PROFILE --locked --tests -p fedimint-wasm-tests";
293    };
294  
295    workspaceTest = craneLib.cargoNextest {
296      cargoArtifacts = workspaceBuild;
297      cargoExtraArgs = "--workspace --all-targets --locked";
298  
299      FM_DISCOVER_API_VERSION_TIMEOUT = "10";
300      FM_CARGO_DENY_COMPILATION = "1";
301    };
302  
303    workspaceTestDoc = craneLib.cargoTest {
304      # can't use nextest due to: https://github.com/nextest-rs/nextest/issues/16
305      cargoTestExtraArgs = "--doc";
306      cargoArtifacts = workspaceBuild;
307  
308      # workaround: `cargo test --doc` started to ignore CARGO_TARGET_<native-target>_RUSTFLAGS
309      # out of the blue
310      stdenv = pkgs.clangStdenv;
311    };
312  
313    workspaceClippy = craneLib.cargoClippy {
314      cargoArtifacts = workspaceDeps;
315  
316      cargoClippyExtraArgs = "--workspace --all-targets --no-deps -- --deny warnings --allow deprecated";
317      doInstallCargoArtifacts = false;
318    };
319  
320    workspaceDoc = craneLibTests.mkCargoDerivation {
321      pnameSuffix = "-workspace-docs";
322      cargoArtifacts = workspaceDeps;
323      buildPhaseCargoCommand = ''
324        patchShebangs ./scripts
325        export FM_RUSTDOC_INDEX_MD=${../docs/rustdoc-index.md}
326        ./scripts/dev/build-docs.sh
327      '';
328      doInstallCargoArtifacts = false;
329      postInstall = ''
330        mkdir $out/share
331        cp -a target/doc $out/share/doc
332      '';
333      doCheck = false;
334      dontFixup = true;
335      dontStrip = true;
336    };
337  
338    # version of `workspaceDocs` for public consumption (uploaded to https://docs.fedimint.org/)
339    workspaceDocExport = workspaceDoc.overrideAttrs (final: prev: {
340      # we actually don't want to have docs for dependencies in exported documentation
341      cargoArtifacts = workspaceDepsNoDocs;
342      nativeBuildInputs = prev.nativeBuildInputs or [ ] ++ [ pkgs.pandoc ];
343    });
344  
345    workspaceCargoUdepsDeps = craneLib.buildDepsOnly {
346      pname = "${commonArgs.pname}-udeps-deps";
347      nativeBuildInputs = commonArgs.nativeBuildInputs ++ [ pkgs.cargo-udeps ];
348      # since we filtered all the actual project source, everything will definitely fail
349      # but we only run this step to cache the build artifacts, so we ignore failure with `|| true`
350      buildPhaseCargoCommand = "cargo udeps --workspace --all-targets --profile $CARGO_PROFILE || true";
351      doCheck = false;
352    };
353  
354    workspaceCargoUdeps = craneLib.mkCargoDerivation {
355      pname = "fedimint-udeps";
356      cargoArtifacts = workspaceCargoUdepsDeps;
357      nativeBuildInputs = commonArgs.nativeBuildInputs ++ [ pkgs.cargo-udeps ];
358      buildPhaseCargoCommand = "cargo udeps --workspace --all-targets --profile $CARGO_PROFILE";
359      doInstallCargoArtifacts = false;
360      doCheck = false;
361    };
362  
363    cargoAudit = craneLib.cargoAudit {
364      inherit advisory-db;
365      src = filterWorkspaceAuditFiles commonSrc;
366    };
367  
368    cargoDeny = craneLib.cargoDeny {
369      src = filterWorkspaceAuditFiles commonSrc;
370    };
371  
372    # Build only deps, but with llvm-cov so `workspaceCov` can reuse them cached
373    workspaceDepsCov = craneLib.buildDepsOnly {
374      pname = "fedimint-workspace-lcov";
375      buildPhaseCargoCommand = "source <(cargo llvm-cov show-env --export-prefix); runLowPrio cargo build --locked --workspace --all-targets --profile $CARGO_PROFILE";
376      cargoBuildCommand = "dontuse";
377      cargoCheckCommand = "dontuse";
378      nativeBuildInputs = [ pkgs.cargo-llvm-cov ];
379      doCheck = false;
380    };
381  
382    workspaceCov = craneLib.buildWorkspace {
383      pname = "fedimint-workspace-lcov";
384      cargoArtifacts = workspaceDepsCov;
385      buildPhaseCargoCommand = "source <(cargo llvm-cov show-env --export-prefix); runLowPrio cargo build --locked --workspace --all-targets --profile $CARGO_PROFILE;";
386      nativeBuildInputs = [ pkgs.cargo-llvm-cov ];
387      doCheck = false;
388    };
389  
390    workspaceTestCovBase = { times }: craneLib.buildPackage {
391      pname = "fedimint-workspace-lcov";
392      cargoArtifacts = workspaceCov;
393  
394      FM_DISCOVER_API_VERSION_TIMEOUT = "10";
395  
396      buildPhaseCargoCommand = (''
397        source <(cargo llvm-cov show-env --export-prefix)
398      '' +
399      lib.concatStringsSep "\n"
400        (
401          lib.replicate times ''
402            env RUST_BACKTRACE=1 RUST_LOG=info,timing=debug cargo nextest run --locked --workspace --all-targets --cargo-profile $CARGO_PROFILE --profile nix-ccov --test-threads=$(($(nproc) * 2))
403          ''
404        ) + ''
405        mkdir -p $out
406        cargo llvm-cov report --profile $CARGO_PROFILE --lcov --output-path $out/lcov.info
407      ''
408      );
409      installPhaseCommand = "true";
410      nativeBuildInputs = [ pkgs.cargo-llvm-cov ];
411      doCheck = false;
412    };
413  
414    workspaceTestCov = workspaceTestCovBase { times = 1; };
415    workspaceTest5TimesCov = workspaceTestCovBase { times = 5; };
416    workspaceTest10TimesCov = workspaceTestCovBase { times = 10; };
417  
418    reconnectTest = craneLibTests.mkCargoDerivation {
419      pname = "${commonCliTestArgs.pname}-reconnect";
420      cargoArtifacts = workspaceBuild;
421      buildPhaseCargoCommand = "patchShebangs ./scripts ; ./scripts/tests/reconnect-test.sh";
422    };
423  
424    latencyTest = craneLibTests.mkCargoDerivation {
425      pname = "${commonCliTestArgs.pname}-latency";
426      cargoArtifacts = workspaceBuild;
427      buildPhaseCargoCommand = "patchShebangs ./scripts ; ./scripts/tests/latency-test.sh";
428    };
429  
430    guardianBackupTest = craneLibTests.mkCargoDerivation {
431      pname = "${commonCliTestArgs.pname}-guardian-backp";
432      cargoArtifacts = workspaceBuild;
433      buildPhaseCargoCommand = "patchShebangs ./scripts ; ./scripts/tests/guardian-backup.sh";
434    };
435  
436    devimintCliTest = craneLibTests.mkCargoDerivation {
437      pname = "${commonCliTestArgs.pname}-cli";
438      cargoArtifacts = workspaceBuild;
439      buildPhaseCargoCommand = "patchShebangs ./scripts ; ./scripts/tests/devimint-cli-test.sh";
440    };
441  
442    devimintCliTestSingle = craneLibTests.mkCargoDerivation {
443      pname = "${commonCliTestArgs.pname}-cli";
444      cargoArtifacts = workspaceBuild;
445      buildPhaseCargoCommand = "patchShebangs ./scripts ; ./scripts/tests/devimint-cli-test-single.sh";
446    };
447  
448    cliLoadTestToolTest = craneLibTests.mkCargoDerivation {
449      pname = "${commonCliTestArgs.pname}-cli";
450      cargoArtifacts = workspaceBuild;
451      buildPhaseCargoCommand = "patchShebangs ./scripts ; ./scripts/tests/load-test-tool-test.sh";
452    };
453  
454    backendTest = craneLibTests.mkCargoDerivation {
455      pname = "${commonCliTestArgs.pname}-backend-test";
456      cargoArtifacts = workspaceBuild;
457      buildPhaseCargoCommand = "patchShebangs ./scripts ; ./scripts/test/backend-test.sh";
458    };
459  
460    ciTestAllBase = { times }: craneLibTests.mkCargoDerivation {
461      pname = "${commonCliTestArgs.pname}-all";
462      cargoArtifacts = craneMultiBuild.default.${craneLib.cargoProfile or "release"}.workspaceBuild;
463  
464      FM_DISCOVER_API_VERSION_TIMEOUT = "10";
465  
466      # One normal run, then if succeeded, modify the "always success test" to fail,
467      # and make sure we detect it (happened too many times that we didn't).
468      # Thanks to early termination, this should be all very quick, as we actually
469      # won't start other tests.
470      buildPhaseCargoCommand = ''
471        # when running on a wasm32-unknown toolchain...
472        if [ "$CARGO_BUILD_TARGET" == "wasm32-unknown-unknown" ]; then
473          # import pre-built wasm32-unknown wasm test artifacts
474          # notably, they are extracted to target's sub-directory, where wasm-test.sh expects them
475          inheritCargoArtifacts ${craneMultiBuild.wasm32-unknown.${craneLib.cargoProfile or "release"}.workspaceBuildWasmTest} "target/pkgs/fedimint-wasm-tests"
476        fi
477        # default to building for native; running test for cross-compilation targets
478        # here doesn't make any sense, and `wasm32-unknown-unknown` toolchain is used
479        # mostly to opt-in into wasm tests
480        unset CARGO_BUILD_TARGET
481  
482        patchShebangs ./scripts
483        export FM_CARGO_DENY_COMPILATION=1
484        export FM_TEST_CI_ALL_TIMES=${builtins.toString times}
485        export FM_TEST_CI_ALL_DISABLE_ETA=1
486        ./scripts/tests/test-ci-all.sh || exit 1
487        cp scripts/tests/always-success-test.sh scripts/tests/always-success-test.sh.bck
488        sed -i -e 's/exit 0/exit 1/g' scripts/tests/always-success-test.sh
489        echo "Verifying failure detection..."
490        ./scripts/tests/test-ci-all.sh 1>/dev/null 2>/dev/null && exit 1
491        cp -f scripts/tests/always-success-test.sh.bck scripts/tests/always-success-test.sh
492      '';
493    };
494  
495    ciTestAll = ciTestAllBase { times = 1; };
496    ciTestAll5Times = ciTestAllBase { times = 5; };
497  
498    alwaysFailTest = craneLibTests.mkCargoDerivation {
499      pname = "${commonCliTestArgs.pname}-always-fail";
500      cargoArtifacts = workspaceBuild;
501      buildPhaseCargoCommand = "patchShebangs ./scripts ; ./scripts/tests/always-fail-test.sh";
502    };
503  
504  
505    wasmTest = craneLibTests.mkCargoDerivation {
506      pname = "wasm-test";
507      # TODO: https://github.com/ipetkov/crane/issues/416
508      cargoArtifacts = craneMultiBuild.default.${craneLib.cargoProfile or "release"}.workspaceBuild;
509      nativeBuildInputs = commonCliTestArgs.nativeBuildInputs ++ [ pkgs.firefox pkgs.wasm-bindgen-cli pkgs.geckodriver pkgs.wasm-pack ];
510      buildPhaseCargoCommand = ''
511        inheritCargoArtifacts ${craneMultiBuild.wasm32-unknown.${craneLib.cargoProfile or "release"}.workspaceBuildWasmTest} "target/pkgs/fedimint-wasm-tests"
512        patchShebangs ./scripts; SKIP_CARGO_BUILD=1 ./scripts/tests/wasm-test.sh'';
513    };
514  
515    fedimint-pkgs = fedimintBuildPackageGroup {
516      pname = "fedimint-pkgs";
517  
518      packages = [
519        "fedimintd"
520        "fedimint-cli"
521        "fedimint-dbtool"
522      ];
523    };
524  
525    gateway-pkgs = fedimintBuildPackageGroup {
526      pname = "gateway-pkgs";
527  
528      packages = [
529        "fedimint-ln-gateway"
530        "fedimint-gateway-cli"
531      ];
532    };
533  
534    client-pkgs = fedimintBuildPackageGroup {
535      pname = "client-pkgs";
536  
537      packages = [
538        "fedimint-client"
539      ];
540    };
541  
542    devimint = fedimintBuildPackageGroup {
543      pname = "devimint";
544      packages = [
545        "devimint"
546      ];
547    };
548  
549    fedimint-load-test-tool = fedimintBuildPackageGroup {
550      pname = "fedimint-load-test-tool";
551      packages = [ "fedimint-load-test-tool" ];
552    };
553  
554  
555    fedimintd = flakeboxLib.pickBinary
556      {
557        pkg = fedimint-pkgs;
558        bin = "fedimintd";
559      };
560  
561    fedimint-cli = flakeboxLib.pickBinary
562      {
563        pkg = fedimint-pkgs;
564        bin = "fedimint-cli";
565      };
566    fedimint-dbtool = flakeboxLib.pickBinary
567      {
568        pkg = fedimint-pkgs;
569        bin = "fedimint-dbtool";
570      };
571    gatewayd = flakeboxLib.pickBinary
572      {
573        pkg = gateway-pkgs;
574        bin = "gatewayd";
575      };
576    gateway-cli = flakeboxLib.pickBinary
577      {
578        pkg = gateway-pkgs;
579        bin = "gateway-cli";
580      };
581  
582    gateway-cln-extension = flakeboxLib.pickBinary
583      {
584        pkg = gateway-pkgs;
585        bin = "gateway-cln-extension";
586      };
587  
588    container =
589      let
590        entrypointScript =
591          pkgs.writeShellScriptBin "entrypoint" ''
592            exec bash "${../misc/fedimintd-container-entrypoint.sh}" "$@"
593          '';
594      in
595      {
596        fedimintd = pkgs.dockerTools.buildLayeredImage {
597          name = "fedimintd";
598          contents = [
599            fedimint-pkgs
600            pkgs.bash
601            pkgs.coreutils
602          ];
603          config = {
604            Cmd = [ ]; # entrypoint will handle empty vs non-empty cmd
605            Env = [
606              "FM_DATA_DIR=/data"
607            ];
608            Entrypoint = [
609              "${entrypointScript}/bin/entrypoint"
610            ];
611            WorkDir = "/data";
612            Volumes = {
613              "/data" = { };
614            };
615            ExposedPorts = {
616              "${builtins.toString 8173}/tcp" = { };
617              "${builtins.toString 8174}/tcp" = { };
618            };
619          };
620        };
621  
622        fedimint-cli = pkgs.dockerTools.buildLayeredImage {
623          name = "fedimint-cli";
624          contents = [ fedimint-pkgs pkgs.bash pkgs.coreutils ];
625          config = {
626            Cmd = [
627              "${fedimint-pkgs}/bin/fedimint-cli"
628            ];
629          };
630        };
631  
632        gatewayd = pkgs.dockerTools.buildLayeredImage {
633          name = "gatewayd";
634          contents = [ gateway-pkgs pkgs.bash pkgs.coreutils ];
635          config = {
636            Cmd = [
637              "${gateway-pkgs}/bin/gatewayd"
638            ];
639          };
640        };
641  
642        gateway-cli = pkgs.dockerTools.buildLayeredImage {
643          name = "gateway-cli";
644          contents = [ gateway-pkgs pkgs.bash pkgs.coreutils ];
645          config = {
646            Cmd = [
647              "${gateway-pkgs}/bin/gateway-cli"
648            ];
649          };
650        };
651  
652        devtools =
653          pkgs.dockerTools.buildLayeredImage
654            {
655              name = "fedimint-devtools";
656              contents = [ devimint fedimint-dbtool fedimint-load-test-tool pkgs.bash pkgs.coreutils ];
657              config = {
658                Cmd = [
659                  "${pkgs.bash}/bin/bash"
660                ];
661              };
662            };
663      };
664  })