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.
This commit is contained in:
parent
0bc8f1669d
commit
7d38060a0d
7 changed files with 109 additions and 61 deletions
26
flake.nix
26
flake.nix
|
@ -13,8 +13,10 @@
|
||||||
|
|
||||||
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ];
|
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ];
|
||||||
|
|
||||||
|
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
|
||||||
|
|
||||||
# Memoize nixpkgs for different platforms for efficiency.
|
# Memoize nixpkgs for different platforms for efficiency.
|
||||||
nixpkgsFor = nixpkgs.lib.genAttrs systems (system:
|
nixpkgsFor = forAllSystems (system:
|
||||||
import nixpkgs {
|
import nixpkgs {
|
||||||
inherit system;
|
inherit system;
|
||||||
overlays = [ self.overlay ];
|
overlays = [ self.overlay ];
|
||||||
|
@ -427,19 +429,19 @@
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
checks = {
|
checks = forAllSystems (system: {
|
||||||
binaryTarball = self.hydraJobs.binaryTarball.x86_64-linux;
|
binaryTarball = self.hydraJobs.binaryTarball.${system};
|
||||||
perlBindings = self.hydraJobs.perlBindings.x86_64-linux;
|
perlBindings = self.hydraJobs.perlBindings.${system};
|
||||||
};
|
});
|
||||||
|
|
||||||
packages = {
|
packages = forAllSystems (system: {
|
||||||
inherit (nixpkgsFor.x86_64-linux) nix;
|
inherit (nixpkgsFor.${system}) nix;
|
||||||
};
|
});
|
||||||
|
|
||||||
defaultPackage = self.packages.nix;
|
defaultPackage = forAllSystems (system: self.packages.${system}.nix);
|
||||||
|
|
||||||
devShell =
|
devShell = forAllSystems (system:
|
||||||
with nixpkgsFor.x86_64-linux;
|
with nixpkgsFor.${system};
|
||||||
with commonDeps pkgs;
|
with commonDeps pkgs;
|
||||||
|
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
|
@ -461,7 +463,7 @@
|
||||||
PATH=$prefix/bin:$PATH
|
PATH=$prefix/bin:$PATH
|
||||||
unset PYTHONPATH
|
unset PYTHONPATH
|
||||||
'';
|
'';
|
||||||
};
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,22 +64,9 @@ struct SourceExprCommand : virtual Args, EvalCommand, MixFlakeOptions
|
||||||
std::shared_ptr<Installable> parseInstallable(
|
std::shared_ptr<Installable> parseInstallable(
|
||||||
ref<Store> store, const std::string & installable);
|
ref<Store> store, const std::string & installable);
|
||||||
|
|
||||||
virtual Strings getDefaultFlakeAttrPaths()
|
virtual Strings getDefaultFlakeAttrPaths();
|
||||||
{
|
|
||||||
return {"defaultPackage"};
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Strings getDefaultFlakeAttrPathPrefixes()
|
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."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RealiseMode { Build, NoBuild, DryRun };
|
enum RealiseMode { Build, NoBuild, DryRun };
|
||||||
|
|
|
@ -251,6 +251,12 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
|
||||||
auto state = getEvalState();
|
auto state = getEvalState();
|
||||||
auto flake = resolveFlake();
|
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) {
|
auto checkDerivation = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
||||||
try {
|
try {
|
||||||
auto drvInfo = getDerivation(*state, v, false);
|
auto drvInfo = getDerivation(*state, v, false);
|
||||||
|
@ -374,34 +380,70 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
|
||||||
|
|
||||||
if (name == "checks") {
|
if (name == "checks") {
|
||||||
state->forceAttrs(vOutput, pos);
|
state->forceAttrs(vOutput, pos);
|
||||||
for (auto & attr : *vOutput.attrs)
|
for (auto & attr : *vOutput.attrs) {
|
||||||
drvPaths.insert(checkDerivation(
|
checkSystemName(attr.name, *attr.pos);
|
||||||
name + "." + (std::string) attr.name, *attr.value, *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") {
|
else if (name == "packages") {
|
||||||
state->forceAttrs(vOutput, pos);
|
state->forceAttrs(vOutput, pos);
|
||||||
for (auto & attr : *vOutput.attrs)
|
for (auto & attr : *vOutput.attrs) {
|
||||||
checkDerivation(
|
checkSystemName(attr.name, *attr.pos);
|
||||||
name + "." + (std::string) attr.name, *attr.value, *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") {
|
else if (name == "apps") {
|
||||||
state->forceAttrs(vOutput, pos);
|
state->forceAttrs(vOutput, pos);
|
||||||
for (auto & attr : *vOutput.attrs)
|
for (auto & attr : *vOutput.attrs) {
|
||||||
checkApp(
|
checkSystemName(attr.name, *attr.pos);
|
||||||
name + "." + (std::string) attr.name, *attr.value, *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")
|
else if (name == "defaultPackage" || name == "devShell") {
|
||||||
checkDerivation(name, vOutput, pos);
|
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")
|
else if (name == "defaultApp") {
|
||||||
checkApp(name, vOutput, pos);
|
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")
|
else if (name == "legacyPackages") {
|
||||||
// FIXME: do getDerivations?
|
state->forceAttrs(vOutput, pos);
|
||||||
;
|
for (auto & attr : *vOutput.attrs) {
|
||||||
|
checkSystemName(attr.name, *attr.pos);
|
||||||
|
// FIXME: do getDerivations?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (name == "overlay")
|
else if (name == "overlay")
|
||||||
checkOverlay(name, vOutput, pos);
|
checkOverlay(name, vOutput, pos);
|
||||||
|
@ -409,7 +451,7 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
|
||||||
else if (name == "overlays") {
|
else if (name == "overlays") {
|
||||||
state->forceAttrs(vOutput, pos);
|
state->forceAttrs(vOutput, pos);
|
||||||
for (auto & attr : *vOutput.attrs)
|
for (auto & attr : *vOutput.attrs)
|
||||||
checkOverlay(name + "." + (std::string) attr.name,
|
checkOverlay(fmt("%s.%s", name, attr.name),
|
||||||
*attr.value, *attr.pos);
|
*attr.value, *attr.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,14 +461,14 @@ struct CmdFlakeCheck : FlakeCommand, MixJSON
|
||||||
else if (name == "nixosModules") {
|
else if (name == "nixosModules") {
|
||||||
state->forceAttrs(vOutput, pos);
|
state->forceAttrs(vOutput, pos);
|
||||||
for (auto & attr : *vOutput.attrs)
|
for (auto & attr : *vOutput.attrs)
|
||||||
checkModule(name + "." + (std::string) attr.name,
|
checkModule(fmt("%s.%s", name, attr.name),
|
||||||
*attr.value, *attr.pos);
|
*attr.value, *attr.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (name == "nixosConfigurations") {
|
else if (name == "nixosConfigurations") {
|
||||||
state->forceAttrs(vOutput, pos);
|
state->forceAttrs(vOutput, pos);
|
||||||
for (auto & attr : *vOutput.attrs)
|
for (auto & attr : *vOutput.attrs)
|
||||||
checkNixOSConfiguration(name + "." + (std::string) attr.name,
|
checkNixOSConfiguration(fmt("%s.%s", name, attr.name),
|
||||||
*attr.value, *attr.pos);
|
*attr.value, *attr.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,23 @@ SourceExprCommand::SourceExprCommand()
|
||||||
.dest(&file);
|
.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()
|
ref<EvalState> EvalCommand::getEvalState()
|
||||||
{
|
{
|
||||||
if (!evalState) {
|
if (!evalState) {
|
||||||
|
|
|
@ -215,12 +215,12 @@ struct CmdApp : InstallableCommand, RunCommon
|
||||||
|
|
||||||
Strings getDefaultFlakeAttrPaths() override
|
Strings getDefaultFlakeAttrPaths() override
|
||||||
{
|
{
|
||||||
return {"defaultApp"};
|
return {"defaultApp." + settings.thisSystem.get()};
|
||||||
}
|
}
|
||||||
|
|
||||||
Strings getDefaultFlakeAttrPathPrefixes() override
|
Strings getDefaultFlakeAttrPathPrefixes() override
|
||||||
{
|
{
|
||||||
return {"apps."};
|
return {"apps." + settings.thisSystem.get() + "."};
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(ref<Store> store) override
|
void run(ref<Store> store) override
|
||||||
|
|
|
@ -198,7 +198,7 @@ struct Common : InstallableCommand, MixProfile
|
||||||
|
|
||||||
Strings getDefaultFlakeAttrPaths() override
|
Strings getDefaultFlakeAttrPaths() override
|
||||||
{
|
{
|
||||||
return {"devShell", "defaultPackage"};
|
return {"devShell." + settings.thisSystem.get(), "defaultPackage." + settings.thisSystem.get()};
|
||||||
}
|
}
|
||||||
|
|
||||||
Path getShellOutPath(ref<Store> store)
|
Path getShellOutPath(ref<Store> store)
|
||||||
|
|
|
@ -34,8 +34,8 @@ cat > $flake1Dir/flake.nix <<EOF
|
||||||
description = "Bla bla";
|
description = "Bla bla";
|
||||||
|
|
||||||
outputs = inputs: rec {
|
outputs = inputs: rec {
|
||||||
packages.foo = import ./simple.nix;
|
packages.$system.foo = import ./simple.nix;
|
||||||
defaultPackage = packages.foo;
|
defaultPackage.$system = packages.$system.foo;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
@ -51,7 +51,7 @@ cat > $flake2Dir/flake.nix <<EOF
|
||||||
description = "Fnord";
|
description = "Fnord";
|
||||||
|
|
||||||
outputs = { self, flake1 }: rec {
|
outputs = { self, flake1 }: rec {
|
||||||
packages.bar = flake1.packages.foo;
|
packages.$system.bar = flake1.packages.$system.foo;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
@ -66,10 +66,10 @@ cat > $flake3Dir/flake.nix <<EOF
|
||||||
description = "Fnord";
|
description = "Fnord";
|
||||||
|
|
||||||
outputs = { self, flake2 }: rec {
|
outputs = { self, flake2 }: rec {
|
||||||
packages.xyzzy = flake2.packages.bar;
|
packages.$system.xyzzy = flake2.packages.$system.bar;
|
||||||
|
|
||||||
checks = {
|
checks = {
|
||||||
xyzzy = packages.xyzzy;
|
xyzzy = packages.$system.xyzzy;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -182,8 +182,8 @@ cat > $flake3Dir/flake.nix <<EOF
|
||||||
description = "Fnord";
|
description = "Fnord";
|
||||||
|
|
||||||
outputs = { self, flake1, flake2 }: rec {
|
outputs = { self, flake1, flake2 }: rec {
|
||||||
packages.xyzzy = flake2.packages.bar;
|
packages.$system.xyzzy = flake2.packages.$system.bar;
|
||||||
packages."sth sth" = flake1.packages.foo;
|
packages.$system."sth sth" = flake1.packages.$system.foo;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
@ -242,9 +242,9 @@ cat > $flake3Dir/flake.nix <<EOF
|
||||||
description = "Fnord";
|
description = "Fnord";
|
||||||
|
|
||||||
outputs = inputs: rec {
|
outputs = inputs: rec {
|
||||||
packages.xyzzy = inputs.flake2.packages.bar;
|
packages.$system.xyzzy = inputs.flake2.packages.$system.bar;
|
||||||
packages.sth = inputs.flake1.packages.foo;
|
packages.$system.sth = inputs.flake1.packages.$system.foo;
|
||||||
packages.fnord =
|
packages.$system.fnord =
|
||||||
with import ./config.nix;
|
with import ./config.nix;
|
||||||
mkDerivation {
|
mkDerivation {
|
||||||
inherit system;
|
inherit system;
|
||||||
|
@ -307,8 +307,8 @@ cat > $flake3Dir/flake.nix <<EOF
|
||||||
description = "Fnord";
|
description = "Fnord";
|
||||||
|
|
||||||
outputs = { self, flake1, flake2, nonFlake }: rec {
|
outputs = { self, flake1, flake2, nonFlake }: rec {
|
||||||
packages.sth = flake1.packages.foo;
|
packages.$system.sth = flake1.packages.$system.foo;
|
||||||
packages.fnord =
|
packages.$system.fnord =
|
||||||
with import ./config.nix;
|
with import ./config.nix;
|
||||||
mkDerivation {
|
mkDerivation {
|
||||||
inherit system;
|
inherit system;
|
||||||
|
|
Loading…
Reference in a new issue