Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ source by.
| `flake-parts` | `flake-parts` | flake outputs |
| `nixpkgs` | `nixpkgs` | package sets and overlays |
| `nixos` | `nixpkgs` | NixOS configurations |
| `darwin` | `nix-darwin` | macOS machines, evaluated with nix-darwin and published as the `darwinConfigurations` that `darwin-rebuild` reads |
| `darwin` | `nix-darwin` | macOS machines, evaluated with nix-darwin and published as the `darwinConfigurations` that `darwin-rebuild` reads; they activate the homes and hjem configurations declared inside them |
| `nixos-minimal` | `nixpkgs` | the `nixos` class under the minimal evaluator (no NixOS base modules); a second integration over the class `nixos` owns |
| `home-manager` | `home-manager` | Home Manager configurations |
| `home-manager-minimal` | `home-manager` | the `homeManager` class with Home Manager's necessary modules alone, the configuration importing what it uses from `modulesPath`; a second integration over the class `home-manager` owns |
Expand Down
23 changes: 19 additions & 4 deletions configs/flake/caisson/partitions/checks.nix
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,26 @@
# same machine on any host; building it needs a darwin builder,
# so the darwin job of the workflow builds it on a macOS runner.
flake.checks.aarch64-darwin.darwin-system =
(import (self.outPath + "/tests/darwin-system") {
inputs = inputs // {
caisson = self;
let
probe = import (self.outPath + "/tests/darwin-system") {
inputs = inputs // {
caisson = self;
};
};
}).toplevel;
in
# The bare machine, and the machine with a home and an hjem
# configuration inside it, whose system holds the activation
# of the home and the launchd agents of hjem.
probe.pkgs.linkFarm "darwin-system" [
{
name = "probe";
path = probe.toplevel;
}
{
name = "family";
path = probe.family.system;
}
];
};
};

Expand Down
2 changes: 1 addition & 1 deletion docs/development/testing-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,6 @@ The checks partition merges outputs from all test and example flakes into the
| `debug-disabled` | `checks.nix` (inline) | `self.debug` is not exposed in production |
| `pinned-world` | `checks.nix` + `tests/pinned-world/` | caisson composed with the pinned upstream world (nixpkgs, home-manager, colmena, disko, nix-darwin, hjem, terranix, system-manager) evaluates end to end; the `drift` workflow runs the same check against advanced pins |
| `hjem-system` | `checks.nix` + `tests/hjem-system/` | The manifest file of an hjem configuration inside a NixOS machine builds, which checks it against hjem's schema with `cue vet`, and so do the units that activate it, which runs shellcheck on their scripts |
| `darwin-system` (aarch64-darwin) | `checks.nix` + `tests/darwin-system/` | The macOS machine of the pinned-world suite, declared through the darwin integration, builds; the `darwin-build` job of the check workflow builds it on a macOS runner |
| `darwin-system` (aarch64-darwin) | `checks.nix` + `tests/darwin-system/` | The two macOS machines of the pinned-world suite, declared through the darwin integration, build: the bare machine, and the machine with a home and an hjem configuration inside it; the `darwin-build` job of the check workflow builds them on a macOS runner |
| `argument-errors` | `checks.nix` + `tests/argument-errors/` | The argument error of every entry point comes from Nix itself, raised at the call site with no frame of caisson |
| `eval-weight` | `checks.nix` + `tests/eval-weight/` | Framework evaluation cost held to committed ceilings ([guide](https://nix-caisson.github.io/docs/eval-weight.html)) |
7 changes: 4 additions & 3 deletions docs/development/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ plumbing works.
terranix, system-manager) and exercised end to end: a home
configuration, a NixOS system with homes declared inside it, a
colmena hive, disk layouts with the machines installed onto them, a
darwin machine evaluated at aarch64-darwin, hjem configurations on
darwin machine evaluated at aarch64-darwin with and without a home
and an hjem configuration inside it, hjem configurations on
their own and inside a NixOS machine, a terranix and a system-manager
configuration, and the composition guarantees of the real exported
overlays. The `hjem-system` check builds the manifest file of the hjem
configuration inside the machine, which checks it against hjem's
schema, and the units that activate it, which runs shellcheck on
their scripts. The darwin machine of the suite is also the one check at
aarch64-darwin, `checks.aarch64-darwin.darwin-system`, which the
their scripts. The two darwin machines of the suite are also the one
check at aarch64-darwin, `checks.aarch64-darwin.darwin-system`, which the
`darwin-build` job of the check workflow builds on a macOS runner. Every upstream expectation caisson relies on is a probe here.
- **Location:** `tests/pinned-world/default.nix`; the pins in
`tests/dependencies/flake.lock`.
Expand Down
19 changes: 13 additions & 6 deletions lib-overlays/hjem/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,13 @@
null;

# The machine the configuration is declared inside, when there
# is one: the childless evaluation of the nearest NixOS
# configuration above it, which hjem's modules receive as
# `osConfig`, null when there is none.
machine = manifest.nearest.nixos or null;
# is one: the childless evaluation of the nearest NixOS or
# darwin configuration above it, which hjem's modules receive
# as `osConfig`, null when there is none.
machine = selection.nearestOf [
"nixos"
"darwin"
] manifest;
osConfig = if machine != null then machine.value.config else null;

# A user hjem's NixOS module embeds also imports hjem's
Expand All @@ -143,7 +146,7 @@
# a NixOS machine that has `utils` gets the same; the minimal
# NixOS evaluator gives none.
machineArgs = if machine != null then (machine.value._module or { }).args or { } else { };
nixosUser = machineArgs ? utils;
nixosUser = machine != null && machine.type == "nixos" && machineArgs ? utils;

# What hjem's OS modules set on a user that caisson sets too:
# the user's name from the name the configuration is declared
Expand All @@ -169,9 +172,13 @@
hjem-lib = hjemLib;
name = if name != null then name else "hjem";
}
# hjem's OS modules hand a user the options of the machine
# as `osOptions`, and the NixOS module also hands it `utils`.
// lib.optionalAttrs (machine != null) {
osOptions = machine.value.options;
}
// lib.optionalAttrs nixosUser {
inherit (machineArgs) utils;
osOptions = machine.value.options;
}
// (if (args.specialArgs or null) != null then args.specialArgs else { });
modules = [
Expand Down
44 changes: 28 additions & 16 deletions lib-overlays/home-manager/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,14 @@
home.username = lib.mkDefault name;
};

# The NixOS configuration the home is declared inside, when
# there is one. It is the nearest NixOS configuration above
# the home, so a structural configuration between the two
# changes nothing. The manifest holds the childless
# evaluation of that NixOS configuration, which is the
# evaluation that leaves out the configurations declared
# inside it. The home is one of those, so the full
# The machine the home is declared inside, when there is one:
# the nearest NixOS or darwin configuration above the home, so
# a structural configuration between the two changes nothing.
# The manifest holds the childless evaluation of that machine,
# which is the evaluation that leaves out the configurations
# declared inside it. The home is one of those, so the full
# evaluation would depend on the home.
machine = manifest.nearest.nixos or null;
machine = selection.nearestOf machineTypes manifest;

# home-manager hands a home the configuration of its machine
# as the module argument `osConfig`, and null when the home
Expand Down Expand Up @@ -287,14 +286,17 @@
# home-manager also hands a home inside a machine the class
# of the machine, as `osClass`. A home with no machine gets
# no such argument from home-manager, so none is added here.
# home-manager's nix-darwin module also hands a home the
# machine as `darwinConfig`.
#
# home-manager's legacy argument `nixosConfig` is left at
# null, the value home-manager gives it in a home with no
# machine. home-manager's fontconfig module reads
# `nixosConfig.home-manager`, an option that only
# home-manager's NixOS module declares, and caisson does not
# use that module.
// (if machine != null then { osClass = "nixos"; } else { })
// (if machine != null then { osClass = machine.type; } else { })
// (if machine != null && machine.type == "darwin" then { darwinConfig = osConfig; } else { })
// (if (args.specialArgs or null) != null then args.specialArgs else { });
# The module tree the evaluation reads: home-manager's
# module list, its module files and the `modulesPath` special
Expand Down Expand Up @@ -469,27 +471,37 @@
};
};

# The integrations whose configurations are machines a home can
# be declared inside.
machineTypes = [
"nixos"
"darwin"
];

# A home is published as `homeConfigurations.<name>`, the
# evaluated home, which is what the home-manager CLI reads. A
# home beneath a NixOS configuration is named `<user>@<host>`,
# the name it is passed up under and the name that NixOS
# configuration is declared under, which is where the CLI looks
# (`$USER@$(hostname)`); a home with no NixOS configuration above
# it keeps its name.
# home beneath a NixOS or darwin configuration is named
# `<user>@<host>`, the name it is passed up under and the name
# that machine is declared under, which is where the CLI looks
# (`$USER@$(hostname)`); a home with no machine above it keeps
# its name.
exportsTo = {
attrset = "homeConfigurations";
value = manifest: manifest.value;
name =
{ name, manifest }:
let
host = (manifest.nearest.nixos or { }).name or null;
machine = final.caisson.integrations.nearestOf machineTypes manifest;
host = if machine == null then null else machine.name or null;
in
if host == null then
{ value = name; }
else
{
value = "${name}@${host}";
description = "named ${name}@${host} from its name and the name of the NixOS configuration it is under";
description = "named ${name}@${host} from its name and the name of the ${
{ nixos = "NixOS"; }.${machine.type} or machine.type
} configuration it is under";
};
};

Expand Down
21 changes: 21 additions & 0 deletions lib-overlays/integrations/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,26 @@
genAttrs declaring (name: config.caisson.${name}.configurations)
);

# The nearest configuration above `manifest` whose integration is
# one of `types`, null when there is none. The manifest records
# the nearest ancestor of each integration; of those, the nearest
# is the one with the most ancestors itself. A home reads its
# machine this way, which is a NixOS or a darwin configuration.
nearestOf =
types: manifest:
builtins.foldl' (
found: type:
let
candidate = (manifest.nearest or { }).${type} or null;
in
if candidate == null then
found
else if found == null || builtins.length candidate.ancestors > builtins.length found.ancestors then
candidate
else
found
) null types;

isManifest = value: builtins.isAttrs value && (value._type or null) == "caisson-manifest";

# How a configuration is published: the `exportsTo` its
Expand Down Expand Up @@ -811,6 +831,7 @@
entriesOf
configurationsModuleFor
integrationsIn
nearestOf
mkEvaluation
publish
topValue
Expand Down
13 changes: 13 additions & 0 deletions modules/darwin/default/caisson/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# SPDX-License-Identifier: MIT
#
# The `caisson.*` part of the default darwin module.
{ closure-lib, ... }:
{ ... }:
{
imports = [
# `forChildren.nix` sets options under `caisson.forChildren`. The
# core module declares those options.
closure-lib.caisson.modules.darwin.core
(import ./forChildren.nix { inherit closure-lib; })
];
}
32 changes: 32 additions & 0 deletions modules/darwin/default/caisson/forChildren.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# SPDX-License-Identifier: MIT
#
# What a darwin configuration gives the homes and the hjem
# configurations declared inside it.
#
# A configuration gives things to the configurations declared inside
# it through the options under `caisson.forChildren`. This file adds
# the home-manager module `darwin-parent` to the modules that a home
# declared inside this darwin configuration imports by default, and
# the hjem module `darwin-parent` to those of an hjem configuration
# declared inside it. Each sets the options that come from the machine:
# the home directory from the account of the user, and for a home the
# user ID and the Nix of the machine.
#
# A darwin configuration that passes `moduleImports` selects its
# modules itself, and then nothing inside it gets these modules from
# here. A home or hjem configuration that passes `moduleImports`
# selects its modules itself, and gets the module only if it lists it.
#
# `closure-lib` is the library of caisson, where the modules are
# registered.
{ closure-lib }:
{ ... }:
{
caisson.forChildren.extraDefaultModuleImports.homeManager = _lib: [
closure-lib.caisson.modules.homeManager.darwin-parent
];

caisson.forChildren.extraDefaultModuleImports.hjem = _lib: [
closure-lib.caisson.modules.hjem.darwin-parent
];
}
34 changes: 34 additions & 0 deletions modules/darwin/default/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# SPDX-License-Identifier: MIT
#
# The `default` darwin module caisson registers. A darwin configuration
# imports every registered module named `default` unless it passes
# `moduleImports`, so this is what a darwin configuration gets from
# caisson when it does not select its modules itself.
#
# It holds what a macOS machine does for the homes and the hjem
# configurations declared inside it:
#
# - `./caisson/forChildren.nix` gives each home the home-manager module
# `darwin-parent`, and each hjem configuration the hjem module
# `darwin-parent`. Both set the options that come from the machine.
# - The registered module `home-manager-activation` activates the homes
# when the machine is activated.
# - The registered module `hjem-activation` writes the launchd agents
# that apply the hjem configurations.
#
# The parts read options of caisson's core module. The core module
# leaves its options out when the library of the evaluation is not a
# caisson composition, so the parts are left out in the same case.
{ closure-lib, mkModule, ... }:
{ lib, ... }:
{
imports =
if lib ? caisson && lib ? caisson-core then
[
(mkModule ./caisson)
closure-lib.caisson.modules.darwin.home-manager-activation
closure-lib.caisson.modules.darwin.hjem-activation
]
else
[ ];
}
Loading
Loading