Merge pull request #289 from hercules-ci/formatter-and-touchups
Fix `formatter` laziness and add touchups module
This commit is contained in:
commit
df81a1bf51
17 changed files with 1061 additions and 375 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use flake
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -4,3 +4,6 @@ result-*
|
||||||
|
|
||||||
# pre-commit-hooks.nix
|
# pre-commit-hooks.nix
|
||||||
.pre-commit-config.yaml
|
.pre-commit-config.yaml
|
||||||
|
|
||||||
|
# direnv
|
||||||
|
.direnv/
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
imports = [
|
imports = [
|
||||||
inputs.pre-commit-hooks-nix.flakeModule
|
inputs.pre-commit-hooks-nix.flakeModule
|
||||||
inputs.hercules-ci-effects.flakeModule # herculesCI attr
|
inputs.hercules-ci-effects.flakeModule # herculesCI attr
|
||||||
|
inputs.nix-unit.modules.flake.default
|
||||||
];
|
];
|
||||||
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
||||||
|
|
||||||
|
|
@ -21,6 +22,7 @@
|
||||||
|
|
||||||
devShells.default = pkgs.mkShell {
|
devShells.default = pkgs.mkShell {
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
|
config.nix-unit.package
|
||||||
pkgs.nixpkgs-fmt
|
pkgs.nixpkgs-fmt
|
||||||
pkgs.hci
|
pkgs.hci
|
||||||
];
|
];
|
||||||
|
|
@ -36,9 +38,15 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
checks.eval-tests =
|
checks.perSystem-memoize = pkgs.callPackage ./tests/perSystem-memoize.nix {
|
||||||
let tests = import ./tests/eval-tests.nix { flake-parts = self; };
|
flake-parts = self;
|
||||||
in tests.runTests pkgs.emptyFile // { internals = tests; };
|
};
|
||||||
|
|
||||||
|
nix-unit.tests = import ./tests/nix-unit.nix { flake-parts = self; };
|
||||||
|
|
||||||
|
# nix-unit evaluates the flake, which triggers the dev partition via
|
||||||
|
# flake-compat, requiring network to fetch dev inputs.
|
||||||
|
nix-unit.allowNetwork = true;
|
||||||
|
|
||||||
};
|
};
|
||||||
flake = {
|
flake = {
|
||||||
|
|
|
||||||
65
dev/flake.lock
generated
65
dev/flake.lock
generated
|
|
@ -76,6 +76,49 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nix-github-actions": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-unit",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1737420293,
|
||||||
|
"narHash": "sha256-F1G5ifvqTpJq7fdkT34e/Jy9VCyzd5XfJ9TO8fHhJWE=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-github-actions",
|
||||||
|
"rev": "f4158fa080ef4503c8f4c820967d946c2af31ec9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-github-actions",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nix-unit": {
|
||||||
|
"inputs": {
|
||||||
|
"nix-github-actions": "nix-github-actions",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1777114263,
|
||||||
|
"narHash": "sha256-vZfRXBDC9FTO2Vpz8TroVMqOYqp+hcVk6Nwx6+kRN1Q=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-unit",
|
||||||
|
"rev": "02e6597889281382303cbb7973748f04f2940e1a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nix-unit",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1775710090,
|
"lastModified": 1775710090,
|
||||||
|
|
@ -132,9 +175,31 @@
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"hercules-ci-effects": "hercules-ci-effects",
|
"hercules-ci-effects": "hercules-ci-effects",
|
||||||
|
"nix-unit": "nix-unit",
|
||||||
"nixpkgs": "nixpkgs_2",
|
"nixpkgs": "nixpkgs_2",
|
||||||
"pre-commit-hooks-nix": "pre-commit-hooks-nix"
|
"pre-commit-hooks-nix": "pre-commit-hooks-nix"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"treefmt-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-unit",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1775636079,
|
||||||
|
"narHash": "sha256-pc20NRoMdiar8oPQceQT47UUZMBTiMdUuWrYu2obUP0=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "790751ff7fd3801feeaf96d7dc416a8d581265ba",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
pre-commit-hooks-nix.url = "github:cachix/pre-commit-hooks.nix";
|
pre-commit-hooks-nix.url = "github:cachix/pre-commit-hooks.nix";
|
||||||
pre-commit-hooks-nix.inputs.nixpkgs.follows = "nixpkgs";
|
pre-commit-hooks-nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
hercules-ci-effects.url = "github:hercules-ci/hercules-ci-effects";
|
hercules-ci-effects.url = "github:hercules-ci/hercules-ci-effects";
|
||||||
|
nix-unit.url = "github:nix-community/nix-unit";
|
||||||
|
nix-unit.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { ... }:
|
outputs = { ... }:
|
||||||
|
|
|
||||||
|
|
@ -1,361 +0,0 @@
|
||||||
# Run with
|
|
||||||
#
|
|
||||||
# nix build .#checks.x86_64-linux.eval-tests
|
|
||||||
|
|
||||||
{ flake-parts }:
|
|
||||||
rec {
|
|
||||||
nixpkgs = flake-parts.inputs.nixpkgs;
|
|
||||||
f-p-lib = flake-parts.lib;
|
|
||||||
inherit (f-p-lib) mkFlake;
|
|
||||||
inherit (flake-parts.inputs.nixpkgs-lib) lib;
|
|
||||||
|
|
||||||
pkg = system: name:
|
|
||||||
derivation
|
|
||||||
{
|
|
||||||
name = name;
|
|
||||||
builder = "no-builder";
|
|
||||||
system = system;
|
|
||||||
}
|
|
||||||
// {
|
|
||||||
meta = {
|
|
||||||
mainProgram = name;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
empty = mkFlake
|
|
||||||
{ inputs.self = { }; }
|
|
||||||
{
|
|
||||||
systems = [ ];
|
|
||||||
};
|
|
||||||
|
|
||||||
emptyExposeArgs = mkFlake
|
|
||||||
{ inputs.self = { outPath = "the self outpath"; }; }
|
|
||||||
({ config, moduleLocation, ... }: {
|
|
||||||
flake = {
|
|
||||||
inherit moduleLocation;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
emptyExposeArgsNoSelf = mkFlake
|
|
||||||
{ inputs.self = throw "self won't be available in case of some errors"; }
|
|
||||||
({ config, moduleLocation, ... }: {
|
|
||||||
flake = {
|
|
||||||
inherit moduleLocation;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
example1 = mkFlake
|
|
||||||
{ inputs.self = { }; }
|
|
||||||
{
|
|
||||||
systems = [ "a" "b" ];
|
|
||||||
perSystem = { config, system, ... }: {
|
|
||||||
packages.hello = pkg system "hello";
|
|
||||||
apps.hello.program = config.packages.hello;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
packagesNonStrictInDevShells = mkFlake
|
|
||||||
{ inputs.self = packagesNonStrictInDevShells; /* approximation */ }
|
|
||||||
{
|
|
||||||
systems = [ "a" "b" ];
|
|
||||||
perSystem = { system, self', ... }: {
|
|
||||||
packages.hello = pkg system "hello";
|
|
||||||
packages.default = self'.packages.hello;
|
|
||||||
devShells = throw "can't be strict in perSystem.devShells!";
|
|
||||||
};
|
|
||||||
flake.devShells = throw "can't be strict in devShells!";
|
|
||||||
};
|
|
||||||
|
|
||||||
easyOverlay = mkFlake
|
|
||||||
{ inputs.self = { }; }
|
|
||||||
{
|
|
||||||
imports = [ flake-parts.flakeModules.easyOverlay ];
|
|
||||||
systems = [ "a" "aarch64-linux" ];
|
|
||||||
perSystem = { system, config, final, pkgs, ... }: {
|
|
||||||
packages.default = config.packages.hello;
|
|
||||||
packages.hello = pkg system "hello";
|
|
||||||
packages.hello_new = final.hello;
|
|
||||||
overlayAttrs = {
|
|
||||||
hello = config.packages.hello;
|
|
||||||
hello_old = pkgs.hello;
|
|
||||||
hello_new = config.packages.hello_new;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
bundlersExample = mkFlake
|
|
||||||
{ inputs.self = { }; }
|
|
||||||
{
|
|
||||||
imports = [ flake-parts.flakeModules.bundlers ];
|
|
||||||
systems = [ "a" "b" ];
|
|
||||||
perSystem = { system, ... }: {
|
|
||||||
packages.hello = pkg system "hello";
|
|
||||||
bundlers.toTarball = drv: pkg system "tarball-${drv.name}";
|
|
||||||
bundlers.toAppImage = drv: pkg system "appimage-${drv.name}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
modulesFlake =
|
|
||||||
mkFlake
|
|
||||||
{
|
|
||||||
inputs.self = { };
|
|
||||||
moduleLocation = "modulesFlake";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
imports = [ flake-parts.flakeModules.modules ];
|
|
||||||
options = {
|
|
||||||
# Test option that uses plain types.submodule
|
|
||||||
flake.fooConfiguration = lib.mkOption {
|
|
||||||
type = lib.types.submoduleWith {
|
|
||||||
# Just Like types.submodule;
|
|
||||||
shorthandOnlyDefinesConfig = true;
|
|
||||||
class = "foo";
|
|
||||||
modules = [ ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config = {
|
|
||||||
systems = [ ];
|
|
||||||
flake = {
|
|
||||||
modules.generic.example =
|
|
||||||
{ lib, ... }:
|
|
||||||
{
|
|
||||||
options.generic.example = lib.mkOption { default = "works in any module system application"; };
|
|
||||||
};
|
|
||||||
modules.foo.example =
|
|
||||||
{ lib, ... }:
|
|
||||||
{
|
|
||||||
options.foo.example = lib.mkOption { default = "works in foo application"; };
|
|
||||||
};
|
|
||||||
fooConfiguration = modulesFlake.modules.foo.example;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
flakeModulesDeclare = mkFlake
|
|
||||||
{ inputs.self = { outPath = ./.; }; }
|
|
||||||
({ config, ... }: {
|
|
||||||
imports = [ flake-parts.flakeModules.flakeModules ];
|
|
||||||
systems = [ ];
|
|
||||||
flake.flakeModules.default = { lib, ... }: {
|
|
||||||
options.flake.test123 = lib.mkOption { default = "option123"; };
|
|
||||||
imports = [ config.flake.flakeModules.extra ];
|
|
||||||
};
|
|
||||||
flake.flakeModules.extra = {
|
|
||||||
flake.test123 = "123test";
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
flakeModulesImport = mkFlake
|
|
||||||
{ inputs.self = { }; }
|
|
||||||
{
|
|
||||||
imports = [ flakeModulesDeclare.flakeModules.default ];
|
|
||||||
};
|
|
||||||
|
|
||||||
flakeModulesDisable = mkFlake
|
|
||||||
{ inputs.self = { }; }
|
|
||||||
{
|
|
||||||
imports = [ flakeModulesDeclare.flakeModules.default ];
|
|
||||||
disabledModules = [ flakeModulesDeclare.flakeModules.extra ];
|
|
||||||
};
|
|
||||||
|
|
||||||
nixpkgsWithoutEasyOverlay = import nixpkgs {
|
|
||||||
system = "x86_64-linux";
|
|
||||||
overlays = [ ];
|
|
||||||
config = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
nixpkgsWithEasyOverlay = import nixpkgs {
|
|
||||||
# non-memoized
|
|
||||||
system = "x86_64-linux";
|
|
||||||
overlays = [ easyOverlay.overlays.default ];
|
|
||||||
config = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
nixpkgsWithEasyOverlayMemoized = import nixpkgs {
|
|
||||||
# memoized
|
|
||||||
system = "aarch64-linux";
|
|
||||||
overlays = [ easyOverlay.overlays.default ];
|
|
||||||
config = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
specialArgFlake = mkFlake
|
|
||||||
{
|
|
||||||
inputs.self = { };
|
|
||||||
specialArgs.soSpecial = true;
|
|
||||||
}
|
|
||||||
({ soSpecial, ... }: {
|
|
||||||
imports = assert soSpecial; [ ];
|
|
||||||
flake.foo = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
partitionWithoutExtraInputsFlake = mkFlake
|
|
||||||
{
|
|
||||||
inputs.self = { };
|
|
||||||
}
|
|
||||||
({ config, ... }: {
|
|
||||||
imports = [ flake-parts.flakeModules.partitions ];
|
|
||||||
systems = [ "x86_64-linux" ];
|
|
||||||
partitions.dev.module = { inputs, ... }: builtins.seq inputs { };
|
|
||||||
partitionedAttrs.devShells = "dev";
|
|
||||||
});
|
|
||||||
|
|
||||||
nixosModulesFlake = mkFlake
|
|
||||||
{
|
|
||||||
inputs.self = { outPath = "/test/path"; };
|
|
||||||
}
|
|
||||||
{
|
|
||||||
systems = [ ];
|
|
||||||
flake.nixosModules.example = { lib, ... }: {
|
|
||||||
options.test.option = lib.mkOption { default = "nixos-test"; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
This one is for manual testing. Should look like:
|
|
||||||
|
|
||||||
```
|
|
||||||
nix-repl> checks.x86_64-linux.eval-tests.internals.printSystem.withSystem "foo" ({ config, ... }: null)
|
|
||||||
trace: Evaluating perSystem for foo
|
|
||||||
null
|
|
||||||
|
|
||||||
nix-repl> checks.x86_64-linux.eval-tests.internals.printSystem.withSystem "foo" ({ config, ... }: null)
|
|
||||||
null
|
|
||||||
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
printSystem = mkFlake
|
|
||||||
{ inputs.self = { }; }
|
|
||||||
({ withSystem, ... }: {
|
|
||||||
systems = [ ];
|
|
||||||
perSystem = { config, system, ... }:
|
|
||||||
builtins.trace "Evaluating perSystem for ${system}" { };
|
|
||||||
flake.withSystem = withSystem;
|
|
||||||
});
|
|
||||||
|
|
||||||
dogfoodProvider = mkFlake
|
|
||||||
{ inputs.self = { }; }
|
|
||||||
({ flake-parts-lib, ... }: {
|
|
||||||
imports = [
|
|
||||||
(flake-parts-lib.importAndPublish "dogfood" { flake.marker = "dogfood"; })
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
dogfoodConsumer = mkFlake
|
|
||||||
{ inputs.self = { }; }
|
|
||||||
({ flake-parts-lib, ... }: {
|
|
||||||
imports = [
|
|
||||||
dogfoodProvider.modules.flake.dogfood
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
runTests = ok:
|
|
||||||
|
|
||||||
assert empty == {
|
|
||||||
apps = { };
|
|
||||||
checks = { };
|
|
||||||
devShells = { };
|
|
||||||
formatter = { };
|
|
||||||
legacyPackages = { };
|
|
||||||
nixosConfigurations = { };
|
|
||||||
nixosModules = { };
|
|
||||||
overlays = { };
|
|
||||||
packages = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
assert example1 == {
|
|
||||||
apps = {
|
|
||||||
a = {
|
|
||||||
hello = {
|
|
||||||
program = "${pkg "a" "hello"}/bin/hello";
|
|
||||||
type = "app";
|
|
||||||
meta = { };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
b = {
|
|
||||||
hello = {
|
|
||||||
program = "${pkg "b" "hello"}/bin/hello";
|
|
||||||
type = "app";
|
|
||||||
meta = { };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
checks = { a = { }; b = { }; };
|
|
||||||
devShells = { a = { }; b = { }; };
|
|
||||||
formatter = { };
|
|
||||||
legacyPackages = { a = { }; b = { }; };
|
|
||||||
nixosConfigurations = { };
|
|
||||||
nixosModules = { };
|
|
||||||
overlays = { };
|
|
||||||
packages = {
|
|
||||||
a = { hello = pkg "a" "hello"; };
|
|
||||||
b = { hello = pkg "b" "hello"; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
assert bundlersExample.bundlers.a.toTarball (pkg "a" "hello") == pkg "a" "tarball-hello";
|
|
||||||
assert bundlersExample.bundlers.b.toAppImage (pkg "b" "hello") == pkg "b" "appimage-hello";
|
|
||||||
|
|
||||||
# - exported package becomes part of overlay.
|
|
||||||
# - perSystem is invoked for the right system, when system is non-memoized
|
|
||||||
assert nixpkgsWithEasyOverlay.hello == pkg "x86_64-linux" "hello";
|
|
||||||
|
|
||||||
# - perSystem is invoked for the right system, when system is memoized
|
|
||||||
assert nixpkgsWithEasyOverlayMemoized.hello == pkg "aarch64-linux" "hello";
|
|
||||||
|
|
||||||
# - Non-exported package does not become part of overlay.
|
|
||||||
assert nixpkgsWithEasyOverlay.default or null != pkg "x86_64-linux" "hello";
|
|
||||||
|
|
||||||
# - hello_old comes from super
|
|
||||||
assert nixpkgsWithEasyOverlay.hello_old == nixpkgsWithoutEasyOverlay.hello;
|
|
||||||
|
|
||||||
# - `hello_new` shows that the `final` wiring works
|
|
||||||
assert nixpkgsWithEasyOverlay.hello_new == nixpkgsWithEasyOverlay.hello;
|
|
||||||
|
|
||||||
assert flakeModulesImport.test123 == "123test";
|
|
||||||
|
|
||||||
assert flakeModulesDisable.test123 == "option123";
|
|
||||||
|
|
||||||
assert packagesNonStrictInDevShells.packages.a.default == pkg "a" "hello";
|
|
||||||
|
|
||||||
assert emptyExposeArgs.moduleLocation == "the self outpath/flake.nix";
|
|
||||||
|
|
||||||
assert (lib.evalModules {
|
|
||||||
class = "barrr";
|
|
||||||
modules = [
|
|
||||||
modulesFlake.modules.generic.example
|
|
||||||
];
|
|
||||||
}).config.generic.example == "works in any module system application";
|
|
||||||
|
|
||||||
assert (lib.evalModules {
|
|
||||||
class = "foo";
|
|
||||||
modules = [
|
|
||||||
modulesFlake.modules.foo.example
|
|
||||||
];
|
|
||||||
}).config.foo.example == "works in foo application";
|
|
||||||
|
|
||||||
# Test that modules can be loaded into plain submodules with shorthandOnlyDefinesConfig = true
|
|
||||||
assert modulesFlake.fooConfiguration.foo.example == "works in foo application";
|
|
||||||
|
|
||||||
assert specialArgFlake.foo;
|
|
||||||
|
|
||||||
assert builtins.isAttrs partitionWithoutExtraInputsFlake.devShells.x86_64-linux;
|
|
||||||
|
|
||||||
assert nixosModulesFlake.nixosModules.example._class == "nixos";
|
|
||||||
|
|
||||||
assert nixosModulesFlake.nixosModules.example._file == "/test/path/flake.nix#nixosModules.example";
|
|
||||||
|
|
||||||
assert (lib.evalModules {
|
|
||||||
class = "nixos";
|
|
||||||
modules = [
|
|
||||||
nixosModulesFlake.nixosModules.example
|
|
||||||
];
|
|
||||||
}).config.test.option == "nixos-test";
|
|
||||||
|
|
||||||
assert dogfoodProvider.marker == "dogfood";
|
|
||||||
assert dogfoodConsumer.marker == "dogfood";
|
|
||||||
|
|
||||||
ok;
|
|
||||||
|
|
||||||
result = runTests "ok";
|
|
||||||
}
|
|
||||||
633
dev/tests/nix-unit.nix
Normal file
633
dev/tests/nix-unit.nix
Normal file
|
|
@ -0,0 +1,633 @@
|
||||||
|
# Tests in nix-unit format
|
||||||
|
# Run with:
|
||||||
|
# nix-unit --flake .#tests
|
||||||
|
# or:
|
||||||
|
# nix build .#checks.x86_64-linux.nix-unit
|
||||||
|
#
|
||||||
|
# NOTE: Derivation comparison
|
||||||
|
# nix-unit deeply forces both `expr` and `expected` (via forceValueDeep) before
|
||||||
|
# comparing. The attrsets returned by `derivation` are self-referential, so
|
||||||
|
# this causes stack overflow. We compare `.drvPath` instead where needed, like
|
||||||
|
# `==` does when `.type == "derivation"`.
|
||||||
|
|
||||||
|
{ flake-parts }:
|
||||||
|
let
|
||||||
|
nixpkgs = flake-parts.inputs.nixpkgs;
|
||||||
|
f-p-lib = flake-parts.lib;
|
||||||
|
inherit (f-p-lib) mkFlake;
|
||||||
|
inherit (flake-parts.inputs.nixpkgs-lib) lib;
|
||||||
|
|
||||||
|
pkg = system: name:
|
||||||
|
derivation
|
||||||
|
{
|
||||||
|
name = name;
|
||||||
|
builder = "no-builder";
|
||||||
|
system = system;
|
||||||
|
}
|
||||||
|
// {
|
||||||
|
meta = {
|
||||||
|
mainProgram = name;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Replace derivations with a simple attrset so nix-unit can compare without
|
||||||
|
# hitting stack overflow on self-referential derivation attrsets.
|
||||||
|
# See NOTE: Derivation comparison
|
||||||
|
canon = v:
|
||||||
|
if v.type or null == "derivation" then { type = "derivation"; inherit (v) drvPath outPath name system; }
|
||||||
|
else if builtins.isAttrs v then builtins.mapAttrs (_: canon) v
|
||||||
|
else v;
|
||||||
|
|
||||||
|
empty = mkFlake
|
||||||
|
{ inputs.self = { }; }
|
||||||
|
{
|
||||||
|
systems = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
emptyExposeArgs = mkFlake
|
||||||
|
{ inputs.self = { outPath = "the self outpath"; }; }
|
||||||
|
({ config, moduleLocation, ... }: {
|
||||||
|
flake = {
|
||||||
|
inherit moduleLocation;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
# Originally tested errorLocation (removed in c8c8e56). Repurposed to test
|
||||||
|
# that mkFlake can produce standard outputs without forcing self.
|
||||||
|
emptyExposeArgsNoSelf = mkFlake
|
||||||
|
{ inputs.self = throw "self won't be available in case of some errors"; }
|
||||||
|
{
|
||||||
|
systems = [ ];
|
||||||
|
};
|
||||||
|
|
||||||
|
example1 = mkFlake
|
||||||
|
{ inputs.self = { }; }
|
||||||
|
{
|
||||||
|
systems = [ "a" "b" ];
|
||||||
|
perSystem = { config, system, ... }: {
|
||||||
|
packages.hello = pkg system "hello";
|
||||||
|
apps.hello.program = config.packages.hello;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
packagesNonStrictInDevShells = mkFlake
|
||||||
|
{ inputs.self = packagesNonStrictInDevShells; /* approximation */ }
|
||||||
|
{
|
||||||
|
systems = [ "a" "b" ];
|
||||||
|
perSystem = { system, self', ... }: {
|
||||||
|
packages.hello = pkg system "hello";
|
||||||
|
packages.default = self'.packages.hello;
|
||||||
|
devShells = throw "can't be strict in perSystem.devShells!";
|
||||||
|
};
|
||||||
|
flake.devShells = throw "can't be strict in devShells!";
|
||||||
|
};
|
||||||
|
|
||||||
|
easyOverlay = mkFlake
|
||||||
|
{ inputs.self = { }; }
|
||||||
|
{
|
||||||
|
imports = [ flake-parts.flakeModules.easyOverlay ];
|
||||||
|
systems = [ "a" "aarch64-linux" ];
|
||||||
|
perSystem = { system, config, final, pkgs, ... }: {
|
||||||
|
packages.default = config.packages.hello;
|
||||||
|
packages.hello = pkg system "hello";
|
||||||
|
packages.hello_new = final.hello;
|
||||||
|
overlayAttrs = {
|
||||||
|
hello = config.packages.hello;
|
||||||
|
hello_old = pkgs.hello;
|
||||||
|
hello_new = config.packages.hello_new;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
bundlersExample = mkFlake
|
||||||
|
{ inputs.self = { }; }
|
||||||
|
{
|
||||||
|
imports = [ flake-parts.flakeModules.bundlers ];
|
||||||
|
systems = [ "a" "b" ];
|
||||||
|
perSystem = { system, ... }: {
|
||||||
|
packages.hello = pkg system "hello";
|
||||||
|
bundlers.toTarball = drv: pkg system "tarball-${drv.name}";
|
||||||
|
bundlers.toAppImage = drv: pkg system "appimage-${drv.name}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
modulesFlake =
|
||||||
|
mkFlake
|
||||||
|
{
|
||||||
|
inputs.self = { };
|
||||||
|
moduleLocation = "modulesFlake";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
imports = [ flake-parts.flakeModules.modules ];
|
||||||
|
options = {
|
||||||
|
# Test option that uses plain types.submodule
|
||||||
|
flake.fooConfiguration = lib.mkOption {
|
||||||
|
type = lib.types.submoduleWith {
|
||||||
|
# Just Like types.submodule;
|
||||||
|
shorthandOnlyDefinesConfig = true;
|
||||||
|
class = "foo";
|
||||||
|
modules = [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
systems = [ ];
|
||||||
|
flake = {
|
||||||
|
modules.generic.example =
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
options.generic.example = lib.mkOption { default = "works in any module system application"; };
|
||||||
|
};
|
||||||
|
modules.foo.example =
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
options.foo.example = lib.mkOption { default = "works in foo application"; };
|
||||||
|
};
|
||||||
|
fooConfiguration = modulesFlake.modules.foo.example;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
flakeModulesDeclare = mkFlake
|
||||||
|
{ inputs.self = { outPath = ./.; }; }
|
||||||
|
({ config, ... }: {
|
||||||
|
imports = [ flake-parts.flakeModules.flakeModules ];
|
||||||
|
systems = [ ];
|
||||||
|
flake.flakeModules.default = { lib, ... }: {
|
||||||
|
options.flake.test123 = lib.mkOption { default = "option123"; };
|
||||||
|
imports = [ config.flake.flakeModules.extra ];
|
||||||
|
};
|
||||||
|
flake.flakeModules.extra = {
|
||||||
|
flake.test123 = "123test";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
flakeModulesImport = mkFlake
|
||||||
|
{ inputs.self = { }; }
|
||||||
|
{
|
||||||
|
imports = [ flakeModulesDeclare.flakeModules.default ];
|
||||||
|
};
|
||||||
|
|
||||||
|
flakeModulesDisable = mkFlake
|
||||||
|
{ inputs.self = { }; }
|
||||||
|
{
|
||||||
|
imports = [ flakeModulesDeclare.flakeModules.default ];
|
||||||
|
disabledModules = [ flakeModulesDeclare.flakeModules.extra ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgsWithoutEasyOverlay = import nixpkgs {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
overlays = [ ];
|
||||||
|
config = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgsWithEasyOverlay = import nixpkgs {
|
||||||
|
# non-memoized
|
||||||
|
system = "x86_64-linux";
|
||||||
|
overlays = [ easyOverlay.overlays.default ];
|
||||||
|
config = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgsWithEasyOverlayMemoized = import nixpkgs {
|
||||||
|
# memoized
|
||||||
|
system = "aarch64-linux";
|
||||||
|
overlays = [ easyOverlay.overlays.default ];
|
||||||
|
config = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
specialArgFlake = mkFlake
|
||||||
|
{
|
||||||
|
inputs.self = { };
|
||||||
|
specialArgs.soSpecial = true;
|
||||||
|
}
|
||||||
|
({ soSpecial, ... }: {
|
||||||
|
imports = assert soSpecial; [ ];
|
||||||
|
flake.foo = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
partitionWithoutExtraInputsFlake = mkFlake
|
||||||
|
{
|
||||||
|
inputs.self = { };
|
||||||
|
}
|
||||||
|
({ config, ... }: {
|
||||||
|
imports = [ flake-parts.flakeModules.partitions ];
|
||||||
|
systems = [ "x86_64-linux" ];
|
||||||
|
partitions.dev.module = { inputs, ... }: builtins.seq inputs { };
|
||||||
|
partitionedAttrs.devShells = "dev";
|
||||||
|
});
|
||||||
|
|
||||||
|
nixosModulesFlake = mkFlake
|
||||||
|
{
|
||||||
|
inputs.self = { outPath = "/test/path"; };
|
||||||
|
}
|
||||||
|
{
|
||||||
|
systems = [ ];
|
||||||
|
flake.nixosModules.example = { lib, ... }: {
|
||||||
|
options.test.option = lib.mkOption { default = "nixos-test"; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
dogfoodProvider = mkFlake
|
||||||
|
{ inputs.self = { }; }
|
||||||
|
({ flake-parts-lib, ... }: {
|
||||||
|
imports = [
|
||||||
|
(flake-parts-lib.importAndPublish "dogfood" { flake.marker = "dogfood"; })
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
dogfoodConsumer = mkFlake
|
||||||
|
{ inputs.self = { }; }
|
||||||
|
({ flake-parts-lib, ... }: {
|
||||||
|
imports = [
|
||||||
|
dogfoodProvider.modules.flake.dogfood
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
withSystemFlake = mkFlake
|
||||||
|
{ inputs.self = { }; }
|
||||||
|
({ withSystem, ... }: {
|
||||||
|
systems = [ "a" "b" ];
|
||||||
|
perSystem = { system, ... }: {
|
||||||
|
packages.hello = pkg system "hello";
|
||||||
|
};
|
||||||
|
flake.withSystem = withSystem;
|
||||||
|
});
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"test: mkFlake does not force self" = {
|
||||||
|
expr = emptyExposeArgsNoSelf;
|
||||||
|
expected = {
|
||||||
|
apps = { };
|
||||||
|
checks = { };
|
||||||
|
devShells = { };
|
||||||
|
formatter = { };
|
||||||
|
legacyPackages = { };
|
||||||
|
nixosConfigurations = { };
|
||||||
|
nixosModules = { };
|
||||||
|
overlays = { };
|
||||||
|
packages = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
withSystem = {
|
||||||
|
"test: withSystem provides the right system for undeclared system" = {
|
||||||
|
expr = withSystemFlake.withSystem "foo" ({ system, ... }: system);
|
||||||
|
expected = "foo";
|
||||||
|
};
|
||||||
|
"test: withSystem provides perSystem config for undeclared system" = {
|
||||||
|
expr = withSystemFlake.withSystem "foo" ({ config, ... }: config.packages.hello);
|
||||||
|
expected = pkg "foo" "hello";
|
||||||
|
};
|
||||||
|
"test: withSystem provides the right system for declared system" = {
|
||||||
|
expr = withSystemFlake.withSystem "a" ({ system, ... }: system);
|
||||||
|
expected = "a";
|
||||||
|
};
|
||||||
|
"test: withSystem provides perSystem config for declared system" = {
|
||||||
|
expr = withSystemFlake.withSystem "a" ({ config, ... }: config.packages.hello);
|
||||||
|
expected = pkg "a" "hello";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
empty = {
|
||||||
|
"test: empty flake outputs" = {
|
||||||
|
expr = empty;
|
||||||
|
expected = {
|
||||||
|
apps = { };
|
||||||
|
checks = { };
|
||||||
|
devShells = { };
|
||||||
|
formatter = { };
|
||||||
|
legacyPackages = { };
|
||||||
|
nixosConfigurations = { };
|
||||||
|
nixosModules = { };
|
||||||
|
overlays = { };
|
||||||
|
packages = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
example1 = {
|
||||||
|
"test: full flake output with two systems" = {
|
||||||
|
expr = example1;
|
||||||
|
expected = {
|
||||||
|
apps = {
|
||||||
|
a = {
|
||||||
|
hello = {
|
||||||
|
program = "${pkg "a" "hello"}/bin/hello";
|
||||||
|
type = "app";
|
||||||
|
meta = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
b = {
|
||||||
|
hello = {
|
||||||
|
program = "${pkg "b" "hello"}/bin/hello";
|
||||||
|
type = "app";
|
||||||
|
meta = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
checks = { a = { }; b = { }; };
|
||||||
|
devShells = { a = { }; b = { }; };
|
||||||
|
formatter = { };
|
||||||
|
legacyPackages = { a = { }; b = { }; };
|
||||||
|
nixosConfigurations = { };
|
||||||
|
nixosModules = { };
|
||||||
|
overlays = { };
|
||||||
|
packages = {
|
||||||
|
a = { hello = pkg "a" "hello"; };
|
||||||
|
b = { hello = pkg "b" "hello"; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
bundlers = {
|
||||||
|
"test: toTarball bundler" = {
|
||||||
|
expr = bundlersExample.bundlers.a.toTarball (pkg "a" "hello");
|
||||||
|
expected = pkg "a" "tarball-hello";
|
||||||
|
};
|
||||||
|
"test: toAppImage bundler" = {
|
||||||
|
expr = bundlersExample.bundlers.b.toAppImage (pkg "b" "hello");
|
||||||
|
expected = pkg "b" "appimage-hello";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
easyOverlay = {
|
||||||
|
"test: exported package in overlay, perSystem invoked for non-memoized system" = {
|
||||||
|
expr = nixpkgsWithEasyOverlay.hello;
|
||||||
|
expected = pkg "x86_64-linux" "hello";
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: exported package in overlay, perSystem invoked for memoized system" = {
|
||||||
|
expr = nixpkgsWithEasyOverlayMemoized.hello;
|
||||||
|
expected = pkg "aarch64-linux" "hello";
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: non-exported package not in overlay" = {
|
||||||
|
expr = nixpkgsWithEasyOverlay.default or null != pkg "x86_64-linux" "hello";
|
||||||
|
expected = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: hello_old comes from super" = {
|
||||||
|
expr = nixpkgsWithEasyOverlay.hello_old.drvPath;
|
||||||
|
# See NOTE: Derivation comparison
|
||||||
|
expected = nixpkgsWithoutEasyOverlay.hello.drvPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: hello_new uses final wiring" = {
|
||||||
|
expr = nixpkgsWithEasyOverlay.hello_new.drvPath;
|
||||||
|
# See NOTE: Derivation comparison
|
||||||
|
expected = nixpkgsWithEasyOverlay.hello.drvPath;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
flakeModules = {
|
||||||
|
"test: import flakeModule" = {
|
||||||
|
expr = flakeModulesImport.test123;
|
||||||
|
expected = "123test";
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: disable flakeModule" = {
|
||||||
|
expr = flakeModulesDisable.test123;
|
||||||
|
expected = "option123";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: packages not strict in devShells" = {
|
||||||
|
expr = packagesNonStrictInDevShells.packages.a.default;
|
||||||
|
expected = pkg "a" "hello";
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: moduleLocation from self outPath" = {
|
||||||
|
expr = emptyExposeArgs.moduleLocation;
|
||||||
|
expected = "the self outpath/flake.nix";
|
||||||
|
};
|
||||||
|
|
||||||
|
modules = {
|
||||||
|
"test: generic module in arbitrary class" = {
|
||||||
|
expr = (lib.evalModules {
|
||||||
|
class = "barrr";
|
||||||
|
modules = [
|
||||||
|
modulesFlake.modules.generic.example
|
||||||
|
];
|
||||||
|
}).config.generic.example;
|
||||||
|
expected = "works in any module system application";
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: foo module in foo class" = {
|
||||||
|
expr = (lib.evalModules {
|
||||||
|
class = "foo";
|
||||||
|
modules = [
|
||||||
|
modulesFlake.modules.foo.example
|
||||||
|
];
|
||||||
|
}).config.foo.example;
|
||||||
|
expected = "works in foo application";
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: modules in submodule with shorthandOnlyDefinesConfig" = {
|
||||||
|
expr = modulesFlake.fooConfiguration.foo.example;
|
||||||
|
expected = "works in foo application";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: specialArgs passed to module" = {
|
||||||
|
expr = specialArgFlake.foo;
|
||||||
|
expected = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: partition without extra inputs" = {
|
||||||
|
expr = builtins.isAttrs partitionWithoutExtraInputsFlake.devShells.x86_64-linux;
|
||||||
|
expected = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
nixosModules = {
|
||||||
|
"test: nixosModule has _class nixos" = {
|
||||||
|
expr = nixosModulesFlake.nixosModules.example._class;
|
||||||
|
expected = "nixos";
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: nixosModule has correct _file" = {
|
||||||
|
expr = nixosModulesFlake.nixosModules.example._file;
|
||||||
|
expected = "/test/path/flake.nix#nixosModules.example";
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: nixosModule evaluates correctly" = {
|
||||||
|
expr = (lib.evalModules {
|
||||||
|
class = "nixos";
|
||||||
|
modules = [
|
||||||
|
nixosModulesFlake.nixosModules.example
|
||||||
|
];
|
||||||
|
}).config.test.option;
|
||||||
|
expected = "nixos-test";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
dogfood = {
|
||||||
|
"test: importAndPublish provider" = {
|
||||||
|
expr = dogfoodProvider.marker;
|
||||||
|
expected = "dogfood";
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: importAndPublish consumer" = {
|
||||||
|
expr = dogfoodConsumer.marker;
|
||||||
|
expected = "dogfood";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
touchup = {
|
||||||
|
"test: any filter keeps only matching attrs" = {
|
||||||
|
expr =
|
||||||
|
let
|
||||||
|
result = mkFlake { inputs.self = { }; } {
|
||||||
|
imports = [ flake-parts.flakeModules.touchup ];
|
||||||
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
||||||
|
touchup.any = { attrName, ... }: { enable = attrName == "overlays"; };
|
||||||
|
perSystem = { ... }: {
|
||||||
|
packages.default = throw "packages.default should not be evaluated";
|
||||||
|
packages.hello = throw "packages.hello should not be evaluated";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result;
|
||||||
|
expected = {
|
||||||
|
overlays = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: any with mkDefault, attr override" = {
|
||||||
|
expr =
|
||||||
|
let
|
||||||
|
result = mkFlake { inputs.self = { }; } {
|
||||||
|
imports = [ flake-parts.flakeModules.touchup ];
|
||||||
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
||||||
|
touchup.any = { ... }: { enable = lib.mkDefault false; };
|
||||||
|
touchup.attr.overlays = { enable = true; };
|
||||||
|
perSystem = { ... }: {
|
||||||
|
packages.default = throw "packages.default should not be evaluated";
|
||||||
|
packages.hello = throw "packages.hello should not be evaluated";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result;
|
||||||
|
expected = {
|
||||||
|
overlays = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: nested attr filtering per system" = {
|
||||||
|
expr =
|
||||||
|
let
|
||||||
|
result = mkFlake { inputs.self = { }; } {
|
||||||
|
imports = [ flake-parts.flakeModules.touchup ];
|
||||||
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
||||||
|
touchup.attr.packages.attr.aarch64-darwin.attr.bar.enable = false;
|
||||||
|
perSystem = { system, ... }: {
|
||||||
|
packages.foo = pkg system "foo";
|
||||||
|
# This assertion proves the filtered value is never evaluated for darwin
|
||||||
|
packages.bar = assert system == "x86_64-linux"; pkg system "bar";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
canon result.packages;
|
||||||
|
expected = canon {
|
||||||
|
aarch64-darwin = { foo = pkg "aarch64-darwin" "foo"; };
|
||||||
|
x86_64-linux = { foo = pkg "x86_64-linux" "foo"; bar = pkg "x86_64-linux" "bar"; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: finish and attr composition" = {
|
||||||
|
expr =
|
||||||
|
mkFlake { inputs.self = { }; } {
|
||||||
|
imports = [ flake-parts.flakeModules.touchup ];
|
||||||
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
||||||
|
touchup.any = { ... }: { enable = lib.mkDefault false; };
|
||||||
|
touchup.attr.overlays = { enable = true; finish = x: "hoi"; };
|
||||||
|
touchup.finish = x: x // { foo = "bar"; };
|
||||||
|
};
|
||||||
|
expected = {
|
||||||
|
overlays = "hoi";
|
||||||
|
foo = "bar";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: assert that the error context ("while touching up attribute 'broken'")
|
||||||
|
# appears in the trace. nix-unit's expectedError.msg only matches the thrown
|
||||||
|
# message, not addErrorContext frames.
|
||||||
|
"test: error context when enabled attr throws" = {
|
||||||
|
expr =
|
||||||
|
let
|
||||||
|
result = mkFlake { inputs.self = { }; } {
|
||||||
|
imports = [ flake-parts.flakeModules.touchup ];
|
||||||
|
systems = [ "x86_64-linux" ];
|
||||||
|
flake.broken = throw "the value is broken";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result.broken;
|
||||||
|
expectedError.type = "ThrownError";
|
||||||
|
expectedError.msg = "the value is broken";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
formatter = {
|
||||||
|
"test: conditional null throws helpful error" = {
|
||||||
|
expr =
|
||||||
|
let
|
||||||
|
result = mkFlake { inputs.self = { }; } {
|
||||||
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
||||||
|
perSystem = { system, ... }: {
|
||||||
|
formatter =
|
||||||
|
if system == "x86_64-linux" then
|
||||||
|
derivation { name = "fmt"; builder = "x"; system = system; }
|
||||||
|
else null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result.formatter.aarch64-darwin;
|
||||||
|
expectedError.type = "ThrownError";
|
||||||
|
expectedError.msg = "could not determine statically(.|\n)*touchup\\.attr\\.formatter\\.enable = false";
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: empty when never defined" = {
|
||||||
|
expr =
|
||||||
|
let
|
||||||
|
result = mkFlake { inputs.self = { }; } {
|
||||||
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
||||||
|
perSystem = { ... }: { };
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result.formatter == { };
|
||||||
|
expected = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: present for all systems" = {
|
||||||
|
expr =
|
||||||
|
let
|
||||||
|
result = mkFlake { inputs.self = { }; } {
|
||||||
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
||||||
|
perSystem = { system, ... }: {
|
||||||
|
formatter = derivation { name = "fmt"; builder = "x"; inherit system; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result ? formatter && result.formatter ? x86_64-linux && result.formatter ? aarch64-darwin;
|
||||||
|
expected = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
"test: lazy per-system" = {
|
||||||
|
expr =
|
||||||
|
let
|
||||||
|
result = mkFlake { inputs.self = { }; } {
|
||||||
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
||||||
|
perSystem = { system, ... }: {
|
||||||
|
formatter =
|
||||||
|
if system == "x86_64-linux" then
|
||||||
|
derivation { name = "fmt"; builder = "x"; system = system; }
|
||||||
|
else
|
||||||
|
throw "should not evaluate aarch64-darwin formatter";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
result.formatter.x86_64-linux.name;
|
||||||
|
expected = "fmt";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
32
dev/tests/perSystem-memoize.nix
Normal file
32
dev/tests/perSystem-memoize.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Test that perSystem evaluation is memoized: calling withSystem twice for the
|
||||||
|
# same undeclared system should only evaluate perSystem once.
|
||||||
|
# Run with:
|
||||||
|
# nix build .#checks.x86_64-linux.perSystem-memoize
|
||||||
|
|
||||||
|
{ flake-parts, runCommand, nix }:
|
||||||
|
runCommand "perSystem-memoize" { nativeBuildInputs = [ nix ]; } ''
|
||||||
|
export HOME="$(realpath .)"
|
||||||
|
unset NIX_STORE
|
||||||
|
export NIX_STORE_DIR=${builtins.storeDir}
|
||||||
|
export NIX_REMOTE="$HOME/storedata"
|
||||||
|
|
||||||
|
nix eval \
|
||||||
|
--extra-experimental-features 'nix-command flakes' \
|
||||||
|
--no-write-lock-file \
|
||||||
|
--offline \
|
||||||
|
--substituters "" \
|
||||||
|
--override-input flake-parts ${flake-parts} \
|
||||||
|
--override-input flake-parts/nixpkgs-lib ${flake-parts.inputs.nixpkgs-lib} \
|
||||||
|
"${./perSystem-memoize}#result" \
|
||||||
|
2>eval-stderr
|
||||||
|
|
||||||
|
count=$(grep -c "Evaluating perSystem for foo" eval-stderr || true)
|
||||||
|
cat eval-stderr >&2
|
||||||
|
echo "Trace count: $count"
|
||||||
|
if [ "$count" -ne 1 ]; then
|
||||||
|
echo "FAIL: expected perSystem to be evaluated exactly once, but it was evaluated $count times"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "PASS: perSystem evaluated exactly once"
|
||||||
|
touch $out
|
||||||
|
''
|
||||||
15
dev/tests/perSystem-memoize/flake.nix
Normal file
15
dev/tests/perSystem-memoize/flake.nix
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
inputs.flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
|
outputs = inputs:
|
||||||
|
inputs.flake-parts.lib.mkFlake { inherit inputs; } ({ withSystem, ... }: {
|
||||||
|
systems = [ ];
|
||||||
|
perSystem = { system, ... }:
|
||||||
|
builtins.trace "Evaluating perSystem for ${system}" { };
|
||||||
|
flake.result =
|
||||||
|
let
|
||||||
|
a = withSystem "foo" ({ config, ... }: null);
|
||||||
|
b = withSystem "foo" ({ config, ... }: "ok");
|
||||||
|
in
|
||||||
|
builtins.seq a b;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Tests in: ../dev/tests/eval-tests.nix (bundlersExample)
|
# Tests in: ../dev/tests/nix-unit.nix (bundlersExample)
|
||||||
|
|
||||||
{ lib
|
{ lib
|
||||||
, flake-parts-lib
|
, flake-parts-lib
|
||||||
|
|
|
||||||
57
extras/touchup.nix
Normal file
57
extras/touchup.nix
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
touchup = mkOption {
|
||||||
|
description = ''
|
||||||
|
Controls which attributes appear in [`processedFlake`](flake-parts.md#opt-processedFlake) and how they are transformed.
|
||||||
|
|
||||||
|
The touchup configuration forms a tree that mirrors the flake output structure.
|
||||||
|
At each level, [`attr`](#opt-touchup.attr) targets specific attributes by name,
|
||||||
|
and [`any`](#opt-touchup.any) applies to all attributes at that level.
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
|
||||||
|
Only output explicitly listed flake output attributes:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
touchup = {
|
||||||
|
any = {
|
||||||
|
enable = lib.mkDefault false;
|
||||||
|
};
|
||||||
|
attr.packages.enable = true;
|
||||||
|
attr.checks.enable = true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Hide a package from users, but not from your own modules:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
touchup = {
|
||||||
|
attr.packages.any.attr.hello.enable = false;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Hide a package on a set of systems:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
touchup = {
|
||||||
|
attr.packages.any = { attrName, ... }: { attr.hello.enable = ! lib.strings.hasSuffix "-darwin" attrName; }
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
'';
|
||||||
|
type = types.submoduleWith {
|
||||||
|
modules = [ ./touchup/attrs.nix ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
processedFlake = config.touchup.touchupApply config.flake;
|
||||||
|
};
|
||||||
|
}
|
||||||
20
extras/touchup/attr.nix
Normal file
20
extras/touchup/attr.nix
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
{ lib, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [ ./attrs.nix ];
|
||||||
|
options = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to include the attribute in the output.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
_module.args.docsVisible = "shallow";
|
||||||
|
};
|
||||||
|
}
|
||||||
131
extras/touchup/attrs.nix
Normal file
131
extras/touchup/attrs.nix
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
{ config, lib, options, docsVisible, ... }:
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
addErrorContext
|
||||||
|
concatMapAttrs
|
||||||
|
evalModules
|
||||||
|
mkOption
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
|
unNull = v:
|
||||||
|
if v == null then
|
||||||
|
{ }
|
||||||
|
else
|
||||||
|
v;
|
||||||
|
|
||||||
|
touchupAttrs =
|
||||||
|
v:
|
||||||
|
concatMapAttrs
|
||||||
|
(name: value:
|
||||||
|
let
|
||||||
|
eval = evalModules {
|
||||||
|
prefix = lib.lists.init options.attr.loc; # arbitrary pick
|
||||||
|
specialArgs = {
|
||||||
|
attrName = name;
|
||||||
|
};
|
||||||
|
modules = [
|
||||||
|
(config.attr.${name} or ./attr.nix)
|
||||||
|
(unNull config.any)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
in
|
||||||
|
if addErrorContext "while figuring out whether to enable '${name}'" eval.config.enable then
|
||||||
|
# Apply the touchup configuration to the value.
|
||||||
|
{
|
||||||
|
"${name}" =
|
||||||
|
addErrorContext "while touching up attribute '${name}'" (
|
||||||
|
(addErrorContext "while evaluating the touchup configuration for '${name}'" eval.config.touchupApply)
|
||||||
|
(addErrorContext "while evaluating the original value of '${name}'" value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ }
|
||||||
|
)
|
||||||
|
v;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
attr = mkOption {
|
||||||
|
type = types.lazyAttrsOf (types.deferredModuleWith {
|
||||||
|
staticModules = [ ./attr.nix ];
|
||||||
|
});
|
||||||
|
default = { };
|
||||||
|
visible = docsVisible;
|
||||||
|
description =
|
||||||
|
if docsVisible == "shallow" then ''
|
||||||
|
Touchup configuration for the next level of nesting.
|
||||||
|
Same structure as [`attr`](#opt-touchup.attr); see its description.
|
||||||
|
''
|
||||||
|
else ''
|
||||||
|
Per-attribute touchup configuration. Each value is a module that controls
|
||||||
|
whether and how the corresponding attribute appears in the output.
|
||||||
|
|
||||||
|
Each module contains the full touchup option set (`enable`, `attr`, `any`, `finish`),
|
||||||
|
so nested attributes can be configured to arbitrary depth.
|
||||||
|
|
||||||
|
This module is called with module argument `attrName`, which is the name of the attribute being touched up.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
any = mkOption {
|
||||||
|
type = types.nullOr (types.deferredModuleWith {
|
||||||
|
staticModules = [ ./attr.nix ];
|
||||||
|
});
|
||||||
|
default = null;
|
||||||
|
visible = docsVisible;
|
||||||
|
description =
|
||||||
|
if docsVisible == "shallow" then ''
|
||||||
|
Default configuration for all attributes at the next level.
|
||||||
|
Same structure as [`any`](#opt-touchup.any); see its description.
|
||||||
|
''
|
||||||
|
else ''
|
||||||
|
A module whose options are merged into every attribute's touchup configuration.
|
||||||
|
For example, `any.enable = false` disables all attributes by default.
|
||||||
|
Override specific ones via `attr.<name>`.
|
||||||
|
|
||||||
|
Only applies to immediate children — does not recurse into nested attributes automatically.
|
||||||
|
|
||||||
|
This module is called with module argument `attrName`, which is the name of the attribute being touched up.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
type = mkOption {
|
||||||
|
type = types.raw;
|
||||||
|
default = types.raw;
|
||||||
|
defaultText = "raw";
|
||||||
|
description = ''
|
||||||
|
The type used for merging multiple definitions of ${options.finish}.
|
||||||
|
Override this if multiple modules need to compose their ${options.finish} functions.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
finish = mkOption {
|
||||||
|
type = types.functionTo config.type;
|
||||||
|
default = v: v;
|
||||||
|
defaultText = lib.literalMD "`v: v`, the identity function";
|
||||||
|
description = ''
|
||||||
|
A function applied after filtering and transforming (e.g. by ${options.attr} and ${options.any} at this level).
|
||||||
|
It receives the resulting attribute set and must return the value to use in its place.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
touchupApply = mkOption {
|
||||||
|
internal = true;
|
||||||
|
description = ''
|
||||||
|
A generated function that applies the touchups that are configured with the other options in this module.
|
||||||
|
'';
|
||||||
|
type = types.functionTo types.raw;
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
_module.args.docsVisible = lib.mkDefault true;
|
||||||
|
touchupApply = v:
|
||||||
|
config.finish
|
||||||
|
(if config.attr != { } || config.any != null
|
||||||
|
then
|
||||||
|
addErrorContext "while applying touchups from ${options.attr}: ${lib.options.showDefs options.attr.definitionsWithLocations}\n and from ${options.any}: ${lib.options.showDefs options.any.definitionsWithLocations}"
|
||||||
|
(touchupAttrs v)
|
||||||
|
else v);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
modules = ./extras/modules.nix;
|
modules = ./extras/modules.nix;
|
||||||
partitions = ./extras/partitions.nix;
|
partitions = ./extras/partitions.nix;
|
||||||
bundlers = ./extras/bundlers.nix;
|
bundlers = ./extras/bundlers.nix;
|
||||||
|
touchup = ./extras/touchup.nix;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
lib.mkFlake { inherit inputs; } {
|
lib.mkFlake { inherit inputs; } {
|
||||||
|
|
@ -59,6 +60,7 @@
|
||||||
partitionedAttrs.checks = "dev";
|
partitionedAttrs.checks = "dev";
|
||||||
partitionedAttrs.devShells = "dev";
|
partitionedAttrs.devShells = "dev";
|
||||||
partitionedAttrs.herculesCI = "dev";
|
partitionedAttrs.herculesCI = "dev";
|
||||||
|
partitionedAttrs.tests = "dev";
|
||||||
partitions.dev.extraInputsFlake = ./dev;
|
partitions.dev.extraInputsFlake = ./dev;
|
||||||
partitions.dev.module = {
|
partitions.dev.module = {
|
||||||
imports = [ ./dev/flake-module.nix ];
|
imports = [ ./dev/flake-module.nix ];
|
||||||
|
|
|
||||||
2
lib.nix
2
lib.nix
|
|
@ -159,7 +159,7 @@ let
|
||||||
let
|
let
|
||||||
eval = flake-parts-lib.evalFlakeModule args module;
|
eval = flake-parts-lib.evalFlakeModule args module;
|
||||||
in
|
in
|
||||||
eval.config.flake;
|
eval.config.processedFlake;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Deprecated. Declare options directly, e.g. `options.foo.bar = mkOption { ... }`,
|
Deprecated. Declare options directly, e.g. `options.foo.bar = mkOption { ... }`,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ lib, ... }:
|
{ config, lib, options, ... }:
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
mkOption
|
mkOption
|
||||||
|
|
@ -33,6 +33,27 @@ in
|
||||||
Raw flake output attributes. Any attribute can be set here, but some
|
Raw flake output attributes. Any attribute can be set here, but some
|
||||||
attributes are represented by options, to provide appropriate
|
attributes are represented by options, to provide appropriate
|
||||||
configuration merging.
|
configuration merging.
|
||||||
|
|
||||||
|
Further processing may be applied to these attributes. See [`processedFlake`](flake-parts.md#opt-processedFlake) for more information.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
processedFlake = mkOption {
|
||||||
|
type = types.raw;
|
||||||
|
readOnly = true;
|
||||||
|
apply =
|
||||||
|
if options.processedFlake.isDefined
|
||||||
|
then x: x
|
||||||
|
else x: config.flake;
|
||||||
|
description = ''
|
||||||
|
The final flake output, as returned by `mkFlake`.
|
||||||
|
|
||||||
|
This separates two concerns:
|
||||||
|
|
||||||
|
- [`flake`](#opt-flake): the internal representation, where all attributes are available for use by other modules, regardless of whether they evaluate successfully for all configurations.
|
||||||
|
- `processedFlake`: the external output, which may have attributes removed or transformed to satisfy tools like `nix flake check`.
|
||||||
|
|
||||||
|
By default, `processedFlake` equals `flake` (no processing).
|
||||||
|
Import a module such as [`flakeModules.touchup`](#opt-touchup) to define it, or set it directly.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
{ config, lib, flake-parts-lib, ... }:
|
{ config, lib, flake-parts-lib, ... }:
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
filterAttrs
|
|
||||||
mapAttrs
|
mapAttrs
|
||||||
mkOption
|
mkOption
|
||||||
optionalAttrs
|
optionalAttrs
|
||||||
|
|
@ -10,11 +9,41 @@ let
|
||||||
inherit (flake-parts-lib)
|
inherit (flake-parts-lib)
|
||||||
mkPerSystemOption
|
mkPerSystemOption
|
||||||
;
|
;
|
||||||
|
|
||||||
|
# Do not copy this pattern! (probe, haveFormatterProbably, optionalAttrs)
|
||||||
|
# It kind of works somewhat for `formatter`, but it is bad.
|
||||||
|
# Nothing critical must rely on this!
|
||||||
|
# - `tryEval` makes debugging harder and more annoying
|
||||||
|
# - There's a performance cost to this otherwise useless evaluation
|
||||||
|
# - We only use it *in `formatter`* because the effects are limited to that
|
||||||
|
# particular attribute. This makes the risk somewhat manageable.
|
||||||
|
probe =
|
||||||
|
config.perSystem
|
||||||
|
# Elaborate error message that users should never see.
|
||||||
|
# The reason to even do this, is that we can sidestep
|
||||||
|
# https://github.com/hercules-ci/flake-parts/issues/288 in many cases,
|
||||||
|
# without flake author intervention to keep `nix flake check` happy.
|
||||||
|
(throw ''
|
||||||
|
For the purpose of finding out whether an option may be unset for all systems, flake-parts probes the perSystem module without a valid `system` argument, and tries to catch this exception if it finds that `system` is required for this determination. If you see this message, it means that for some reason, flake-parts was unable to catch this exception.
|
||||||
|
|
||||||
|
This may be a bug in Nix or in flake-parts, but ultimately this is due to the quirky requirement of flakes that the "system" attribute does not come first.
|
||||||
|
Flake-parts tries its best to correct that UX, but ultimately, this needs to be solved in Nix.
|
||||||
|
'');
|
||||||
|
|
||||||
|
haveFormatterProbably =
|
||||||
|
let
|
||||||
|
ev =
|
||||||
|
builtins.tryEval
|
||||||
|
probe.formatter;
|
||||||
|
in
|
||||||
|
# If it fails, we can't assume that we don't have a formatter, because it may well evaluate for a real system.
|
||||||
|
!ev.success
|
||||||
|
|| ev.value != null;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
flake.formatter = mkOption {
|
flake.formatter = mkOption {
|
||||||
type = types.lazyAttrsOf types.package;
|
type = types.lazyAttrsOf (types.nullOr types.package);
|
||||||
default = { };
|
default = { };
|
||||||
description = ''
|
description = ''
|
||||||
An attribute set of per system a package used by [`nix fmt`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-fmt.html).
|
An attribute set of per system a package used by [`nix fmt`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-fmt.html).
|
||||||
|
|
@ -36,12 +65,40 @@ in
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
flake.formatter =
|
flake.formatter =
|
||||||
mapAttrs
|
# Work around `nix flake check` not allowing `null` values in output attributes.
|
||||||
(k: v: v.formatter)
|
optionalAttrs
|
||||||
(filterAttrs
|
haveFormatterProbably
|
||||||
(k: v: v.formatter != null)
|
(mapAttrs
|
||||||
config.allSystems
|
(k: v:
|
||||||
);
|
if v.formatter != null then v.formatter
|
||||||
|
else
|
||||||
|
throw ''
|
||||||
|
flake-parts could not determine statically that no formatter is defined for *all* systems.
|
||||||
|
|
||||||
|
What happened?
|
||||||
|
|
||||||
|
1. For performance reasons, flake-parts must not query `perSystem` for every system, so it uses a heuristic to determine whether a formatter is defined for all systems.
|
||||||
|
2. Unfortunately, this heuristic is not perfect, and it wasn't able to determine for your flake that `perSystem.formatter` is always `null` (if it even is always `null`).
|
||||||
|
As a consequence of (1), flake-parts had to provide the output attribute `formatter.${k}`, but as a consequence of (2), you're seeing this error.
|
||||||
|
|
||||||
|
What to do?
|
||||||
|
|
||||||
|
This whole situation should be temporary. `nix flake check`/`show` can be changed to allow `null` values, which gives flake-parts and other frameworks a way to avoid this situation.
|
||||||
|
|
||||||
|
To change the `formatter` output attribute, you can control it precisely with the `touchup` module, for example:
|
||||||
|
|
||||||
|
imports = [ inputs.flake-parts.flakeModules.touchup ];
|
||||||
|
|
||||||
|
# Remove it
|
||||||
|
touchup.attr.formatter.enable = false;
|
||||||
|
|
||||||
|
# ... or only have it for listed systems
|
||||||
|
touchup.attr.formatter.any.enable = lib.mkDefault false;
|
||||||
|
touchup.attr.formatter.attr.x86_64-linux.enable = true;
|
||||||
|
touchup.attr.formatter.attr.aarch64-darwin.enable = true;
|
||||||
|
|
||||||
|
'')
|
||||||
|
config.allSystems);
|
||||||
|
|
||||||
perInput = system: flake:
|
perInput = system: flake:
|
||||||
optionalAttrs (flake?formatter.${system}) {
|
optionalAttrs (flake?formatter.${system}) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue