aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2019-10-15 17:52:10 +0200
committerEelco Dolstra <edolstra@gmail.com>2019-10-15 18:16:29 +0200
commit7d38060a0da2698052e84a0cfee422d409a38187 (patch)
treeb81347894cd8c8468e24d2262f4e226a48598575 /src
parent0bc8f1669d542ef65fbfa80ea3728f4dd36d63f2 (diff)
Support non-x86_64-linux system types in flakes
A command like $ nix run nixpkgs#hello will now build the attribute 'packages.${system}.hello' rather than 'packages.hello'. Note that this does mean that the flake needs to export an attribute for every system type it supports, and you can't build on unsupported systems. So 'packages' typically looks like this: packages = nixpkgs.lib.genAttrs ["x86_64-linux" "i686-linux"] (system: { hello = ...; }); The 'checks', 'defaultPackage', 'devShell', 'apps' and 'defaultApp' outputs similarly are now attrsets that map system types to derivations/apps. 'nix flake check' checks that the derivations for all platforms evaluate correctly, but only builds the derivations in 'checks.${system}'. Fixes #2861. (That issue also talks about access to ~/.config/nixpkgs and --arg, but I think it's reasonable to say that flakes shouldn't support those.) The alternative to attribute selection is to pass the system type as an argument to the flake's 'outputs' function, e.g. 'outputs = { self, nixpkgs, system }: ...'. However, that approach would be at odds with hermetic evaluation and make it impossible to enumerate the packages provided by a flake.
Diffstat (limited to 'src')
-rw-r--r--src/nix/command.hh17
-rw-r--r--src/nix/flake.cc80
-rw-r--r--src/nix/installables.cc17
-rw-r--r--src/nix/run.cc4
-rw-r--r--src/nix/shell.cc2
5 files changed, 83 insertions, 37 deletions
diff --git a/src/nix/command.hh b/src/nix/command.hh
index 802dd9828..93f324071 100644
--- a/src/nix/command.hh
+++ b/src/nix/command.hh
@@ -64,22 +64,9 @@ struct SourceExprCommand : virtual Args, EvalCommand, MixFlakeOptions
std::shared_ptr<Installable> parseInstallable(
ref<Store> store, const std::string & installable);
- virtual Strings getDefaultFlakeAttrPaths()
- {
- return {"defaultPackage"};
- }
+ virtual Strings getDefaultFlakeAttrPaths();
- virtual Strings getDefaultFlakeAttrPathPrefixes()
- {
- return {
- // As a convenience, look for the attribute in
- // 'outputs.packages'.
- "packages.",
- // As a temporary hack until Nixpkgs is properly converted
- // to provide a clean 'packages' set, look in 'legacyPackages'.
- "legacyPackages."
- };
- }
+ virtual Strings getDefaultFlakeAttrPathPrefixes();
};
enum RealiseMode { Build, NoBuild, DryRun };
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index e6dc5680f..d928af3b9 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -251,6 +251,12 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
auto state = getEvalState();
auto flake = resolveFlake();
+ auto checkSystemName = [&](const std::string & system, const Pos & pos) {
+ // FIXME: what's the format of "system"?
+ if (system.find('-') == std::string::npos)
+ throw Error("'%s' is not a valid system type, at %s", system, pos);
+ };
+
auto checkDerivation = [&](const std::string & attrPath, Value & v, const Pos & pos) {
try {
auto drvInfo = getDerivation(*state, v, false);
@@ -374,34 +380,70 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
if (name == "checks") {
state->forceAttrs(vOutput, pos);
- for (auto & attr : *vOutput.attrs)
- drvPaths.insert(checkDerivation(
- name + "." + (std::string) attr.name, *attr.value, *attr.pos));
+ for (auto & attr : *vOutput.attrs) {
+ checkSystemName(attr.name, *attr.pos);
+ state->forceAttrs(*attr.value, *attr.pos);
+ for (auto & attr2 : *attr.value->attrs) {
+ auto drvPath = checkDerivation(
+ fmt("%s.%s.%s", name, attr.name, attr2.name),
+ *attr2.value, *attr2.pos);
+ if ((std::string) attr.name == settings.thisSystem.get())
+ drvPaths.insert(drvPath);
+ }
+ }
}
else if (name == "packages") {
state->forceAttrs(vOutput, pos);
- for (auto & attr : *vOutput.attrs)
- checkDerivation(
- name + "." + (std::string) attr.name, *attr.value, *attr.pos);
+ for (auto & attr : *vOutput.attrs) {
+ checkSystemName(attr.name, *attr.pos);
+ state->forceAttrs(*attr.value, *attr.pos);
+ for (auto & attr2 : *attr.value->attrs)
+ checkDerivation(
+ fmt("%s.%s.%s", name, attr.name, attr2.name),
+ *attr2.value, *attr2.pos);
+ }
}
else if (name == "apps") {
state->forceAttrs(vOutput, pos);
- for (auto & attr : *vOutput.attrs)
- checkApp(
- name + "." + (std::string) attr.name, *attr.value, *attr.pos);
+ for (auto & attr : *vOutput.attrs) {
+ checkSystemName(attr.name, *attr.pos);
+ state->forceAttrs(*attr.value, *attr.pos);
+ for (auto & attr2 : *attr.value->attrs)
+ checkApp(
+ fmt("%s.%s.%s", name, attr.name, attr2.name),
+ *attr2.value, *attr2.pos);
+ }
}
- else if (name == "defaultPackage" || name == "devShell")
- checkDerivation(name, vOutput, pos);
+ else if (name == "defaultPackage" || name == "devShell") {
+ state->forceAttrs(vOutput, pos);
+ for (auto & attr : *vOutput.attrs) {
+ checkSystemName(attr.name, *attr.pos);
+ checkDerivation(
+ fmt("%s.%s", name, attr.name),
+ *attr.value, *attr.pos);
+ }
+ }
- else if (name == "defaultApp")
- checkApp(name, vOutput, pos);
+ else if (name == "defaultApp") {
+ state->forceAttrs(vOutput, pos);
+ for (auto & attr : *vOutput.attrs) {
+ checkSystemName(attr.name, *attr.pos);
+ checkApp(
+ fmt("%s.%s", name, attr.name),
+ *attr.value, *attr.pos);
+ }
+ }
- else if (name == "legacyPackages")
- // FIXME: do getDerivations?
- ;
+ else if (name == "legacyPackages") {
+ state->forceAttrs(vOutput, pos);
+ for (auto & attr : *vOutput.attrs) {
+ checkSystemName(attr.name, *attr.pos);
+ // FIXME: do getDerivations?
+ }
+ }
else if (name == "overlay")
checkOverlay(name, vOutput, pos);
@@ -409,7 +451,7 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
else if (name == "overlays") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
- checkOverlay(name + "." + (std::string) attr.name,
+ checkOverlay(fmt("%s.%s", name, attr.name),
*attr.value, *attr.pos);
}
@@ -419,14 +461,14 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
else if (name == "nixosModules") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
- checkModule(name + "." + (std::string) attr.name,
+ checkModule(fmt("%s.%s", name, attr.name),
*attr.value, *attr.pos);
}
else if (name == "nixosConfigurations") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs)
- checkNixOSConfiguration(name + "." + (std::string) attr.name,
+ checkNixOSConfiguration(fmt("%s.%s", name, attr.name),
*attr.value, *attr.pos);
}
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index 93509955a..bc8fbeb8f 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -55,6 +55,23 @@ SourceExprCommand::SourceExprCommand()
.dest(&file);
}
+Strings SourceExprCommand::getDefaultFlakeAttrPaths()
+{
+ return {"defaultPackage." + settings.thisSystem.get()};
+}
+
+Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes()
+{
+ return {
+ // As a convenience, look for the attribute in
+ // 'outputs.packages'.
+ "packages." + settings.thisSystem.get() + ".",
+ // As a temporary hack until Nixpkgs is properly converted
+ // to provide a clean 'packages' set, look in 'legacyPackages'.
+ "legacyPackages." + settings.thisSystem.get() + "."
+ };
+}
+
ref<EvalState> EvalCommand::getEvalState()
{
if (!evalState) {
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 01ec9a6f8..d444fd2eb 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -215,12 +215,12 @@ struct CmdApp : InstallableCommand, RunCommon
Strings getDefaultFlakeAttrPaths() override
{
- return {"defaultApp"};
+ return {"defaultApp." + settings.thisSystem.get()};
}
Strings getDefaultFlakeAttrPathPrefixes() override
{
- return {"apps."};
+ return {"apps." + settings.thisSystem.get() + "."};
}
void run(ref<Store> store) override
diff --git a/src/nix/shell.cc b/src/nix/shell.cc
index a4488b229..50d0f9c88 100644
--- a/src/nix/shell.cc
+++ b/src/nix/shell.cc
@@ -198,7 +198,7 @@ struct Common : InstallableCommand, MixProfile
Strings getDefaultFlakeAttrPaths() override
{
- return {"devShell", "defaultPackage"};
+ return {"devShell." + settings.thisSystem.get(), "defaultPackage." + settings.thisSystem.get()};
}
Path getShellOutPath(ref<Store> store)