diff --git a/checks/flake-module.nix b/checks/flake-module.nix index 04480c7e1..5e47cdccd 100644 --- a/checks/flake-module.nix +++ b/checks/flake-module.nix @@ -14,6 +14,7 @@ in ./installation/flake-module.nix ./morph/flake-module.nix ./nixos-documentation/flake-module.nix + ./sanity-checks/dont-depend-on-repo-root.nix ]; perSystem = { @@ -54,11 +55,17 @@ in syncthing = import ./syncthing nixosTestArgs; }; + packagesToBuild = lib.removeAttrs self'.packages [ + # exclude the check that checks that nothing depends on the repo root + # We might want to include this later once everything is fixed + "dont-depend-on-repo-root" + ]; + flakeOutputs = lib.mapAttrs' ( name: config: lib.nameValuePair "nixos-${name}" config.config.system.build.toplevel ) (lib.filterAttrs (n: _: !lib.hasPrefix "test-" n) self.nixosConfigurations) - // lib.mapAttrs' (n: lib.nameValuePair "package-${n}") self'.packages + // lib.mapAttrs' (n: lib.nameValuePair "package-${n}") packagesToBuild // lib.mapAttrs' (n: lib.nameValuePair "devShell-${n}") self'.devShells // lib.mapAttrs' (name: config: lib.nameValuePair "home-manager-${name}" config.activation-script) ( self'.legacyPackages.homeConfigurations or { } diff --git a/checks/sanity-checks/dont-depend-on-repo-root.nix b/checks/sanity-checks/dont-depend-on-repo-root.nix new file mode 100644 index 000000000..0bab2013e --- /dev/null +++ b/checks/sanity-checks/dont-depend-on-repo-root.nix @@ -0,0 +1,122 @@ +{ + ... +}: +{ + perSystem = + { + system, + pkgs, + self', + lib, + ... + }: + let + clanCore = self'.packages.clan-core-flake; + clanCoreHash = lib.substring 0 12 (builtins.hashString "sha256" "${clanCore}"); + /* + construct a flake for the test which contains a single check which depends + on all checks of clan-core. + */ + testFlakeFile = pkgs.writeText "flake.nix" '' + { + inputs.clan-core.url = path:///to/nowhere; + outputs = {clan-core, ...}: + let + checks = + builtins.removeAttrs + clan-core.checks.${system} + [ + "dont-depend-on-repo-root" + "package-dont-depend-on-repo-root" + "package-clan-core-flake" + ]; + checksOutPaths = map (x: "''${x}") (builtins.attrValues checks); + in + { + checks.${system}.check = builtins.derivation { + name = "all-clan-core-checks"; + system = "${system}"; + builder = "/bin/sh"; + args = ["-c" ''' + of outPath in ''${toString checksOutPaths}; do + echo "$outPath" >> $out + done + ''']; + }; + }; + } + ''; + in + lib.optionalAttrs (system == "x86_64-linux") { + packages.dont-depend-on-repo-root = + pkgs.runCommand + # append repo hash to this tests name to ensure it gets invalidated on each chain + # This is needed because this test is an FOD (due to networking) and would get cached indefinitely. + "check-dont-depend-on-repo-root-${clanCoreHash}" + { + buildInputs = [ + pkgs.nix + pkgs.cacert + pkgs.nix-diff + ]; + outputHashAlgo = "sha256"; + outputHash = "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="; + } + '' + mkdir clanCore testFlake store + clanCore=$(realpath clanCore) + testFlake=$(realpath testFlake) + + # copy clan core flake and make writable + cp -r ${clanCore}/* clanCore/ + chmod +w -R clanCore\ + + # copy test flake and make writable + cp ${testFlakeFile} testFlake/flake.nix + chmod +w -R testFlake + + # enable flakes + export NIX_CONFIG="experimental-features = nix-command flakes" + + # give nix a $HOME + export HOME=$(realpath ./store) + + # override clan-core flake input to point to $clanCore\ + echo "locking clan-core to $clanCore" + nix flake lock --override-input clan-core "path://$clanCore" "$testFlake" --store "$HOME" + + # evaluate all tests + echo "evaluating all tests for clan core" + nix eval "$testFlake"#checks.${system}.check.drvPath --store "$HOME" --raw > drvPath1 & + + # slightly modify clan core + cp -r $clanCore clanCore2 + cp -r $testFlake testFlake2 + export clanCore2=$(realpath clanCore2) + export testFlake2=$(realpath testFlake2) + touch clanCore2/fly-fpv + + # re-evaluate all tests + echo "locking clan-core to $clanCore2" + nix flake lock --override-input clan-core "path://$clanCore2" "$testFlake2" --store "$HOME" + echo "evaluating all tests for clan core with added file" + nix eval "$testFlake2"#checks.${system}.check.drvPath --store "$HOME" --raw > drvPath2 + + # wait for first nix eval to return as well + while ! grep -q drv drvPath1; do sleep 1; done + + # raise error if outputs are different + if [ "$(cat drvPath1)" != "$(cat drvPath2)" ]; then + echo -e "\n\nERROR: Something in clan-core depends on the whole repo" > /dev/stderr + echo -e "See details in the nix-diff below which shows the difference between two evaluations:" + echo -e " 1. Evaluation of clan-core checks without any changes" + echo -e " 1. Evaluation of clan-core checks after adding a file to the top-level of the repo" + echo "nix-diff:" + export NIX_REMOTE="$HOME" + nix-diff $(cat drvPath1) $(cat drvPath2) + exit 1 + fi + touch $out + ''; + }; +} diff --git a/pkgs/clan-cli/flake-module.nix b/pkgs/clan-cli/flake-module.nix index 49115ec20..e2aecaa94 100644 --- a/pkgs/clan-cli/flake-module.nix +++ b/pkgs/clan-cli/flake-module.nix @@ -12,75 +12,18 @@ ... }: let - clanCore = self.filter { - include = [ - "clanModules" - "flakeModules" - "lib" - "nixosModules" - "flake.lock" - "templates" - ]; - }; - flakeLock = lib.importJSON (clanCore + "/flake.lock"); - flakeInputs = builtins.removeAttrs inputs [ "self" ]; - flakeLockVendoredDeps = - flakeLock: - flakeLock - // { - nodes = - flakeLock.nodes - // (lib.flip lib.mapAttrs flakeInputs ( - name: _: - # remove follows and let 'nix flake lock' re-compute it later - # (lib.removeAttrs flakeLock.nodes.${name} ["inputs"]) - flakeLock.nodes.${name} - // { - locked = { - inherit (flakeLock.nodes.${name}.locked) narHash; - lastModified = - # lol, nixpkgs has a different timestamp on the fs??? - if name == "nixpkgs" then 0 else 1; - path = "${inputs.${name}}"; - type = "path"; - }; - } - )); - }; - clanCoreLock = flakeLockVendoredDeps flakeLock; - clanCoreLockFile = builtins.toFile "clan-core-flake.lock" (builtins.toJSON clanCoreLock); - - clanCoreNode = { - - inputs = lib.mapAttrs (name: _input: name) flakeInputs; - locked = { - lastModified = 1; - path = "${clanCore}"; - type = "path"; - }; - original = { - type = "tarball"; - url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz"; + clanCoreWithVendoredDeps = self'.packages.clan-core-flake.override { + clanCore = self.filter { + include = [ + "clanModules" + "flakeModules" + "lib" + "nixosModules" + "flake.lock" + "templates" + ]; }; }; - # generate a lock file that nix will accept for our flake templates, - # in order to not require internet access during tests. - templateLock = clanCoreLock // { - nodes = clanCoreLock.nodes // { - clan-core = clanCoreNode; - nixpkgs-lib = clanCoreLock.nodes.nixpkgs; # required by flake-parts - flake-parts = clanCoreLock.nodes.flake-parts; - root = clanCoreLock.nodes.root // { - inputs = clanCoreLock.nodes.root.inputs // { - clan-core = "clan-core"; - nixpkgs = "nixpkgs"; - clan = "clan-core"; - flake-parts = "flake-parts"; - }; - }; - }; - }; - templateLockFile = builtins.toFile "template-flake.lock" (builtins.toJSON templateLock); # We need to add the paths of the templates to the nix store such that they are available # only adding clanCoreWithVendoredDeps to the nix store is not enough @@ -89,41 +32,6 @@ builtins.attrValues (self.clanLib.select "clan.templates.clan.*.path" self) ++ builtins.attrValues (self.clanLib.select "clan.templates.machine.*.path" self); }; - - clanCoreWithVendoredDeps = - pkgs.runCommand "clan-core-with-vendored-deps" - { - buildInputs = [ - pkgs.findutils - pkgs.git - pkgs.jq - pkgs.nix - ]; - } - '' - set -e - export HOME=$(realpath .) - export NIX_STATE_DIR=$HOME - export NIX_STORE_DIR=$HOME - cp -r ${clanCore} $out - chmod +w -R $out - cp ${clanCoreLockFile} $out/flake.lock - nix flake lock $out --extra-experimental-features 'nix-command flakes' - clanCoreHash=$(nix hash path ${clanCore} --extra-experimental-features 'nix-command') - - ## ==> We need this to make nix flake update work on the templates - ## however then we have to re-add the clan templates to the nix store - ## which is not possible (or I don't know how) - # for templateDir in $(find $out/templates/clan -mindepth 1 -maxdepth 1 -type d); do - # if ! [ -e "$templateDir/flake.nix" ]; then - # continue - # fi - # cp ${templateLockFile} $templateDir/flake.lock - # cat $templateDir/flake.lock | jq ".nodes.\"clan-core\".locked.narHash = \"$clanCoreHash\"" > $templateDir/flake.lock.final - # mv $templateDir/flake.lock.final $templateDir/flake.lock - # nix flake lock $templateDir --extra-experimental-features 'nix-command flakes' - # done - ''; in { devShells.clan-cli = pkgs.callPackage ./shell.nix { diff --git a/pkgs/clan-core-flake/flake-module.nix b/pkgs/clan-core-flake/flake-module.nix new file mode 100644 index 000000000..fc5007468 --- /dev/null +++ b/pkgs/clan-core-flake/flake-module.nix @@ -0,0 +1,75 @@ +{ self, inputs, ... }: +{ + perSystem = + { + lib, + pkgs, + ... + }: + let + # A flake lock for offline use. + # All flake inputs are locked to an existing store path + clanCoreLockFile = + clanCore: + let + flakeLock = lib.importJSON (clanCore + "/flake.lock"); + flakeInputs = builtins.removeAttrs inputs [ "self" ]; + flakeLockVendoredDeps = + flakeLock: + flakeLock + // { + nodes = + flakeLock.nodes + // (lib.flip lib.mapAttrs flakeInputs ( + name: _: + # remove follows and let 'nix flake lock' re-compute it later + # (lib.removeAttrs flakeLock.nodes.${name} ["inputs"]) + flakeLock.nodes.${name} + // { + locked = { + inherit (flakeLock.nodes.${name}.locked) narHash; + lastModified = + # lol, nixpkgs has a different timestamp on the fs??? + if name == "nixpkgs" then 0 else 1; + path = "${inputs.${name}}"; + type = "path"; + }; + } + )); + }; + clanCoreLock = flakeLockVendoredDeps flakeLock; + clanCoreLockFile = builtins.toFile "clan-core-flake.lock" (builtins.toJSON clanCoreLock); + in + clanCoreLockFile; + in + { + packages.clan-core-flake = + let + package = + { + clanCore, + }: + pkgs.runCommand "clan-core-flake" + { + buildInputs = [ + pkgs.findutils + pkgs.git + pkgs.jq + pkgs.nix + ]; + } + '' + set -e + export HOME=$(realpath .) + export NIX_STATE_DIR=$HOME + export NIX_STORE_DIR=$HOME + cp -r ${clanCore} $out + chmod +w -R $out + cp ${clanCoreLockFile clanCore} $out/flake.lock + nix flake lock $out --extra-experimental-features 'nix-command flakes' + clanCoreHash=$(nix hash path ${clanCore} --extra-experimental-features 'nix-command') + ''; + in + pkgs.callPackage package { clanCore = self; }; + }; +} diff --git a/pkgs/flake-module.nix b/pkgs/flake-module.nix index fd2e59fd2..4eade68c7 100644 --- a/pkgs/flake-module.nix +++ b/pkgs/flake-module.nix @@ -10,6 +10,7 @@ ./distro-packages/flake-module.nix ./icon-update/flake-module.nix ./generate-test-vars/flake-module.nix + ./clan-core-flake/flake-module.nix ]; flake.packages.x86_64-linux =