diff --git a/doc/manual/rl-next/flakes-eval-system.md b/doc/manual/rl-next/flakes-eval-system.md new file mode 100644 index 000000000..7899afb49 --- /dev/null +++ b/doc/manual/rl-next/flakes-eval-system.md @@ -0,0 +1,18 @@ +--- +synopsis: 'Flakes follow `--eval-system` where it makes sense' +issues: [fj#673, fj#692, gh#11359] +cls: [2657] +category: Fixes +credits: [jade] +--- + +Most flake commands now follow `--eval-system` when choosing attributes to build/evaluate/etc. + +The exceptions are commands that actually run something on the local machine: +- nix develop +- nix run +- nix upgrade-nix +- nix fmt +- nix bundle + +This is not a principled approach to cross compilation or anything, flakes still impede rather than support cross compilation, but this unbreaks many remote build use cases. diff --git a/lix/libcmd/installables.cc b/lix/libcmd/installables.cc index a46863a43..6f595b3f0 100644 --- a/lix/libcmd/installables.cc +++ b/lix/libcmd/installables.cc @@ -185,8 +185,8 @@ MixReadOnlyOption::MixReadOnlyOption() Strings SourceExprCommand::getDefaultFlakeAttrPaths() { return { - "packages." + settings.thisSystem.get() + ".default", - "defaultPackage." + settings.thisSystem.get() + "packages." + evalSettings.getCurrentSystem() + ".default", + "defaultPackage." + evalSettings.getCurrentSystem() }; } @@ -195,10 +195,10 @@ Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes() return { // As a convenience, look for the attribute in // 'outputs.packages'. - "packages." + settings.thisSystem.get() + ".", + "packages." + evalSettings.getCurrentSystem() + ".", // As a temporary hack until Nixpkgs is properly converted // to provide a clean 'packages' set, look in 'legacyPackages'. - "legacyPackages." + settings.thisSystem.get() + "." + "legacyPackages." + evalSettings.getCurrentSystem() + "." }; } diff --git a/lix/nix/bundle.cc b/lix/nix/bundle.cc index 261cd8416..25cd89ab9 100644 --- a/lix/nix/bundle.cc +++ b/lix/nix/bundle.cc @@ -1,5 +1,6 @@ #include "lix/libcmd/installable-flake.hh" #include "lix/libcmd/command.hh" +#include "lix/libexpr/eval-settings.hh" #include "lix/libmain/common-args.hh" #include "lix/libmain/shared.hh" #include "lix/libstore/store-api.hh" @@ -54,9 +55,10 @@ struct CmdBundle : InstallableCommand // FIXME: cut&paste from CmdRun. Strings getDefaultFlakeAttrPaths() override { + // eval-system, since the app could be remote built and then bundled locally Strings res{ - "apps." + settings.thisSystem.get() + ".default", - "defaultApp." + settings.thisSystem.get() + "apps." + evalSettings.getCurrentSystem() + ".default", + "defaultApp." + evalSettings.getCurrentSystem() }; for (auto & s : SourceExprCommand::getDefaultFlakeAttrPaths()) res.push_back(s); @@ -65,7 +67,8 @@ struct CmdBundle : InstallableCommand Strings getDefaultFlakeAttrPathPrefixes() override { - Strings res{"apps." + settings.thisSystem.get() + "."}; + // eval-system, since the app could be remote built and then bundled locally + Strings res{"apps." + evalSettings.getCurrentSystem() + "."}; for (auto & s : SourceExprCommand::getDefaultFlakeAttrPathPrefixes()) res.push_back(s); return res; @@ -82,6 +85,7 @@ struct CmdBundle : InstallableCommand auto [bundlerFlakeRef, bundlerName, extendedOutputsSpec] = parseFlakeRefWithFragmentAndExtendedOutputsSpec(bundler, absPath(".")); const flake::LockFlags lockFlags{ .writeLockFile = false }; + // Current system, since it needs to run locally InstallableFlake bundler{this, evaluator, std::move(bundlerFlakeRef), bundlerName, std::move(extendedOutputsSpec), {"bundlers." + settings.thisSystem.get() + ".default", diff --git a/lix/nix/develop.cc b/lix/nix/develop.cc index 2ea3aacce..76e0f0a98 100644 --- a/lix/nix/develop.cc +++ b/lix/nix/develop.cc @@ -427,6 +427,7 @@ struct Common : InstallableCommand, MixProfile Strings getDefaultFlakeAttrPaths() override { + // These are current system since they have to run locally from inside the shell Strings paths{ "devShells." + settings.thisSystem.get() + ".default", "devShell." + settings.thisSystem.get(), @@ -621,6 +622,7 @@ struct CmdDevelop : Common, MixEnvironment "bashInteractive", ExtendedOutputsSpec::Default(), Strings{}, + // `system` not `eval-system` since we are actually executing it on the local machine Strings{"legacyPackages." + settings.thisSystem.get() + "."}, nixpkgsLockFlags); diff --git a/lix/nix/flake.cc b/lix/nix/flake.cc index f8419f910..aec484416 100644 --- a/lix/nix/flake.cc +++ b/lix/nix/flake.cc @@ -365,7 +365,7 @@ struct CmdFlakeCheck : FlakeCommand lockFlags.applyNixConfig = true; auto flake = lockFlake(*state); - auto localSystem = std::string(settings.thisSystem.get()); + auto localSystem = std::string(evalSettings.getCurrentSystem()); bool hasErrors = false; auto reportError = [&](const Error & e) { @@ -613,7 +613,7 @@ struct CmdFlakeCheck : FlakeCommand auto drvPath = checkDerivation( fmt("%s.%s.%s", name, attr_name, evaluator->symbols[attr2.name]), *attr2.value, attr2.pos); - if (drvPath && attr_name == settings.thisSystem.get()) { + if (drvPath && attr_name == evalSettings.getCurrentSystem()) { drvPaths.push_back(DerivedPath::Built { .drvPath = makeConstantStorePathRef(*drvPath), .outputs = OutputsSpec::All { }, @@ -1129,7 +1129,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON auto evaluator = getEvaluator(); auto state = evaluator->begin(aio()); auto flake = std::make_shared(lockFlake(*state)); - auto localSystem = std::string(settings.thisSystem.get()); + auto localSystem = std::string(evalSettings.getCurrentSystem()); std::function $flakeDir/flake.nix <&1 && fail "nix flake check --all-systems should have failed" || true) echo "$checkRes" | grepQuiet "packages.system-1.default" diff --git a/tests/functional/flakes/flakes.sh b/tests/functional/flakes/flakes.sh index 85ffacf70..5f102e183 100644 --- a/tests/functional/flakes/flakes.sh +++ b/tests/functional/flakes/flakes.sh @@ -126,6 +126,11 @@ nix build -o $TEST_ROOT/result git+file://$flake1Dir nix build -o $flake1Dir/result git+file://$flake1Dir nix path-info $flake1Dir/result +# Ensure that eval-system affects the chosen attribute +cp -r "$flake1Dir" "$flake1Dir.kittified" +sed -i "s#$system#kitty-kitty#" "$flake1Dir.kittified/flake.nix" +nix build --eval-system kitty-kitty "$flake1Dir.kittified" + # 'getFlake' on an unlocked flakeref should fail in pure mode, but # succeed in impure mode. (! nix build -o $TEST_ROOT/result --expr "(builtins.getFlake \"$flake1Dir\").packages.$system.default") diff --git a/tests/functional/flakes/show.sh b/tests/functional/flakes/show.sh index 3461597ee..53e849a40 100644 --- a/tests/functional/flakes/show.sh +++ b/tests/functional/flakes/show.sh @@ -7,6 +7,8 @@ writeSimpleFlake "$flakeDir" cd "$flakeDir" +# FIXME(jade): the following is rather absurd. we have jq! + # By default: Only show the packages content for the current system and no # legacyPackages at all nix flake show --json > show-output.json @@ -19,6 +21,11 @@ assert show_output.legacyPackages.${builtins.currentSystem} == {}; true ' +# Follow --eval-system for determining the system for flakes +nix flake show --eval-system someOtherSystem --json > show-output.json +drvTitle=$(jq -r '.packages.someOtherSystem.default.name' show-output.json) +[[ $drvTitle == 'simple' ]] + # With `--all-systems`, show the packages for all systems nix flake show --json --all-systems > show-output.json nix eval --impure --expr '