Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
0ec7d89
Formatting
Noah765 Jul 4, 2024
e6382c1
Simplify eval-modules
Noah765 Jul 4, 2024
35abff0
Further simplify the codebase
Noah765 Jul 4, 2024
b6f6130
Improve the evaluation of flake inputs
Noah765 Jul 4, 2024
cb31bc0
Improve error messages for duplicate flake inputs
Noah765 Jul 4, 2024
adb7181
Simplify
Noah765 Jul 5, 2024
dd667a4
Restructuring (unfinished)
Noah765 Jul 5, 2024
20626d1
Restructuring
Noah765 Jul 5, 2024
5fa80c9
Always provide the configs arg
Noah765 Jul 5, 2024
b96d3fb
Input type (unfinished)
Noah765 Jul 5, 2024
a8d6c20
Input type (unfinished)
Noah765 Jul 6, 2024
c0fb9de
Input type (unfinished)
Noah765 Jul 6, 2024
a0dd096
Restructuring input handling
Noah765 Jul 6, 2024
c394237
Better error messages for duplicate flake inputs (unfinished)
Noah765 Jul 6, 2024
c8808a4
Better error messages for duplicate flake inputs
Noah765 Jul 7, 2024
9d9fe39
Handle mkMerge, mkIf and mkOverride in flake inputs
Noah765 Jul 7, 2024
e520363
Handle mkMerge, mkIf and mkOverride in flake inputs
Noah765 Jul 7, 2024
eea8cfe
Type check flake inputs (unfinished)
Noah765 Jul 7, 2024
61dbc26
Type check flake inputs
Noah765 Jul 7, 2024
af9edb7
Fix the nixpkgs default verion, provide osOptions, hmOptions
Noah765 Jul 7, 2024
b8b5eec
Allow referencing options of flake inputs
Noah765 Jul 7, 2024
7425f6b
Restructuring
Noah765 Jul 7, 2024
0835baa
Restructuring
Noah765 Jul 8, 2024
b889563
Patching nixpkgs (unfinished)
Noah765 Jul 8, 2024
f0b82ef
Patching nixpkgs (unfinished)
Noah765 Jul 8, 2024
5a1b8fe
Patching nixpkgs (unfinished)
Noah765 Jul 8, 2024
a100b34
Patching nixpkgs (unfinished)
Noah765 Jul 8, 2024
33a7279
Patching nixpkgs
Noah765 Jul 8, 2024
2d82413
Stop using stdenv.mkDerivation (unfinished)
Noah765 Jul 8, 2024
e41b012
Stop using stdenv.mkDerivation
Noah765 Jul 8, 2024
f18a706
Easier copying of options (unfinished)
Noah765 Jul 8, 2024
7a65ea3
Easier copying of options (unfinished)
Noah765 Jul 9, 2024
8651b99
Easier copying of options (unfinished)
Noah765 Jul 9, 2024
c0d91b0
Easier copying of options (unfinished)
Noah765 Jul 9, 2024
de37fac
Fully support osImports and hmImports
Noah765 Jul 9, 2024
b2be743
Support pure evaluation
Noah765 Jul 10, 2024
fbe19c6
Provide modules, extraModules args
Noah765 Jul 10, 2024
cc05ed2
Fixing osImports and hmImports
Noah765 Jul 10, 2024
b81722f
Pkgs arg
Noah765 Jul 10, 2024
4a4c3bd
Fixing bug
Noah765 Jul 10, 2024
cc6db5d
Fixing hmOptions, supporting assertions
Noah765 Jul 10, 2024
dcafe5f
useHm special arg
Noah765 Jul 10, 2024
1314342
Debugging
Noah765 Jul 11, 2024
e887cfc
Debugging
Noah765 Jul 11, 2024
f2c40a1
Debugging
Noah765 Jul 11, 2024
ba8f0e8
No system mkFlake arg (unfinished)
Noah765 Jul 12, 2024
77ecdc8
Finishing the osOptions module arg
Noah765 Jul 12, 2024
d832265
Refactoring
Noah765 Jul 12, 2024
fb8e4fa
Support mkMerge, osModules, hmModules
Noah765 Jul 12, 2024
7517001
nixosSystem, bug fixes
Noah765 Jul 12, 2024
662df5d
Cleanup, bug fixes
Noah765 Jul 13, 2024
0a7e9f6
Updated README.md
Noah765 Jul 13, 2024
073d05e
Updated the patch, README.md, providing combinedManagerPath
Noah765 Jul 13, 2024
225a5d9
Updated the patch, README.md
Noah765 Jul 13, 2024
6899e12
Updated templates, hashes
Noah765 Jul 13, 2024
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
206 changes: 103 additions & 103 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,140 +1,140 @@
# Combined Manager
Combined Manager provides a new structure for personal NixOS configurations.
###### Note: Requires patching `nix` to solve [this issue](https://github.com/NixOS/nix/issues/3966). See more in the [Nix Patches section](#nix-patches).

- [Introduction](#introduction-no-separation)
- [Module options](#module-options)
- [Examples](#examples)
- [Full configurations](#full-configurations)
- [Modules](#modules)
- [Current limitations](#examples)
- [Stability](#stability)
- [Setup](#setup)
- [Nix Patches](#nix-patches)
- [evaluable-flake.patch](#required-evaluable-flakepatch-2-line-diff)
- [FAQ](#faq)
- [I want to get started, but don’t know how to patch Nix.](#i-want-to-get-started-but-dont-know-how-to-patch-nix)
- [Why does Combined Manager need to evaluate inputs?](#why-does-combined-manager-need-to-evaluate-inputs)
###### Note: Requires patching `nix` to solve [this issue](https://github.com/NixOS/nix/issues/3966). See more in the [patching Nix section](#patching-nix).

- [Introduction](#introduction-no-separation)
- [Module structure](#module-structure)
- [Option copying](#option-copying)
- [Current limitations](#current-limitations)
- [Getting started](#getting-started)
- [Stability](#stability)
- [Examples](#examples)
- [Full configurations](#full-configurations)
- [Modules](#modules)
- [Patching Nix](#patching-nix)

## Introduction: No separation
Combined Manager's main feature is to break separation. If you want, you should be able to keep everything in a single module.
Most NixOS configuration structures are designed to separate related things into multiple files.
The main feature of Combined Manager is to break separation. Most NixOS configuration structures are designed to separate related things into multiple files.

Most prominent separations:
- Dividing modules into system and home categories. These categories are then further maintained in separate files.
- All flake inputs must be in the same file in flake.nix.
Most prominent separations:
- Splitting your configuration into NixOS and Home Manager modules. These modules are then put into different files, even though they may be semantically related.
- All flake inputs must be in flake.nix.

Combined Manager breaks this pattern by allowing modules to add inputs, overlays and Home Manager and Nixpkgs options as if they are simple options.
Combined Manager breaks this pattern by providing modules that can add inputs, import NixOS and Home Manager modules, and define Home Manager and NixOS options.

## Module Options
## Module structure
```nix
{
lib,
inputs,
pkgs,
useHm, # Whether the current configuration uses Home Manager
options,
osOptions,
hmOptions,
configs, # The results of all NixOS / Combined Manager configurations
config,
osConfig,
hmConfig,
inputs,
combinedManager, # Path to the root of combinedManager
configs, # The results of all NixOS/CombinedManager configurations
combinedManager, # The root of Combined Manager
combinedManagerPath, # Path to the root of Combined Manager
...
}: {
inputs = { name.url = "..."; }; # Add inputs

imports = [ ];
osImports = [ ]; # Import NixOS modules
hmImports = [ ]; # Import Home Manager modules

options = { };
options = { }; # Declare Combined Manager options

config = {
# Adding inputs.
inputs = { name.url = "..."; };

# Importing system modules.
osModules = [ ];

# Importing Home Manager modules.
hmModules = [ ];
inputs = { name.url = "..."; }; # You can also add inputs here

# Setting overlays.
os.nixpkgs.overlays = [ ];
osModules = [ ]; # You can also import NixOS modules here
hmModules = [ ]; # You can also import Home Manager modules here

# Using `os` to set Nixpkgs options.
os = { };
os = { }; # Define NixOS options

# Set Home Manager username (Required to be set in at least one of the modules).
hmUsername = "myname";
hmUsername = "myname"; # Set the Home Manager username (must be defined if Home Manager is enabled for this configuration)

# Using `hm` to set Home Manager options.
hm = { };
hm = { }; # Define Home Manager options
};
}
```

## Examples
#### Full configurations
- https://github.com/FlafyDev/nixos-config
#### Modules
- https://github.com/FlafyDev/nixos-config/blob/main/modules/display/hyprland/default.nix

## Option copying
When declaring options for your Combined Manager modules, sometimes you just want to copy a NixOS or Home Manager option. Combined Manager makes this easy and straightforward, even when working with `attrsOf` and submodules. Below is an example impermanence module that makes use of this feature. Note that the options being copied are complex, so you wouldn't want to just copy and paste them into your option declarations.
```nix
{
lib,
inputs,
osOptions,
hmOptions,
...
}:
{
inputs.impermanence.url = "github:nix-community/impermanence";

osImports = [ inputs.impermanence.nixosModules.impermanence ];
hmImports = [ inputs.impermanence.nixosModules.home-manager.impermanence ];

options.impermanence =
let
os = osOptions.environment.persistence "/persist/system";
hm = hmOptions.home.persistence "/persist/home";
in
{
enable = lib.mkEnableOption "impermanence";
os = {
inherit (os) files directories; # Copy the `files` and `directories` options that you would define at `os.environment.persistence."/persist/system"`
};
hm = {
inherit (hm) files directories; # Copy the `files` and `directories` options that you would define at `hm.home.persistence."/persist/home"`
};
};
}
```

## Current limitations
- Home Manager required and only a single user with Home Manager.
- Nix must be patched.
- Only for NixOS.

## Stability
As of the time of writing, stable _enough_.
While I'll use it for my configuraiton, I have not tested everything and cannot guarantee stability.
There might be breaking changes.

## Setup
1. Patch Nix with the patches in the `nix-patches` directory. See more in the [Nix Patches section](#nix-patches).
2. Generate a template with `nix flake init -t github:FlafyDev/combined-manager#example`.
3. Run `nix flake metadata`. You might need to run it twice if there is no `flake.lock` file(A message will appear).

##### Running
To bulid a VM: `nixos-rebuild build-vm --flake .#default`.
To swtich: `sudo nixos-rebuild switch --flake .#default`.
- Only a single user supported when using Home Manager
- Requires Nix to be patched
- For NixOS configurations with flakes only

## Getting started
1. Patch Nix with the `evaluable-flake.patch` patch. See more in the [patching nix section](#patching-nix).
2. Use one of our flake templates with `nix flake init -t github:FlafyDev/combined-manager#example`, or have a look at an example to see how to use Combined Manager.
3. Start using Combined Manager!

## Nix Patches
Combined Manager requires applying certain patches to Nix in order to work.
Alternatively, you can use [Nix Super](https://git.privatevoid.net/max/nix-super).

#### Required: evaluable-flake.patch (2 line diff)
This patch enables inputs(and the entire flake) to be evaluable. Solves [issue #3966](https://github.com/NixOS/nix/issues/3966).
Combined Manager requires this since it evaluates `inputs` from all the modules.

See [line 9 of the example flake](https://github.com/FlafyDev/combined-manager/blob/9474a2432b47c0e6fa0435eb612a32e28cbd99ea/templates/example/flake.nix#L9).
## Stability
At the time of writing, stable _enough_.
While I'm using it for my configuraiton, I haven't tested everything and can't guarantee stability.
There may be breaking changes.

## FAQ
## Examples
#### Full configurations
- https://github.com/FlafyDev/nixos-config
#### Modules
- https://github.com/FlafyDev/nixos-config/blob/main/modules/display/hyprland/default.nix

#### I want to get started, but don't know how to patch Nix.
You can add the following to your config:
## Patching Nix
Because Combined Manager allows flake inputs to be distributed across multiple modules, which [Nix doesn't support](https://github.com/NixOS/nix/issues/3966), it requires Nix to be patched.
You can use the patch provided by this project, or alternatively use [Nix Super](https://github.com/privatevoid-net/nix-super).

#### Applying the patch to Nix
To apply the Nix patch provided by this project, add the following to your NixOS configuration:
```nix
nix = {
enable = true;
package = let
combinedManager = pkgs.fetchFromGitHub {
owner = "flafydev";
repo = "combined-manager";
rev = "9474a2432b47c0e6fa0435eb612a32e28cbd99ea";
sha256 = "";
};
in
pkgs.nix.overrideAttrs (old: {
patches =
(old.patches or [])
++ (
map
(file: "${combinedManager}/nix-patches/${file}")
(lib.attrNames (lib.filterAttrs (_: type: type == "regular") (builtins.readDir "${combinedManager}/nix-patches")))
);
});
};
nix.package = pkgs.nix.overrideAttrs (old: {
patches = old.patches or [ ] ++ [
(pkgs.fetchurl {
url = "https://raw.githubusercontent.com/flafydev/combined-manager/main/evaluable-flake.patch";
hash = "sha256-UZ5hXI1w1mOEe0Bp5rSfeB4jfnwxnNEXJWir4dQGyyo=";
})
];
});
```

Once you start using Combined Manager, you'll be able to source the patches directly from your `combinedManager` module arg.

#### Why does Combined Manager need to evaluate inputs?
Each Combined Manager module has an `inputs` option. That option will eventually be merged and set as the inputs of the NixOS configuration.

Once you're using Combined Manager, you can get the patch using the `combinedManagerPath` module arg:
```nix
nix.package = pkgs.nix.overrideAttrs (old: {
patches = old.patches or [ ] ++ [ "${combinedManagerPath}/evaluable-flake.patch" ];
});
132 changes: 30 additions & 102 deletions default.nix
Original file line number Diff line number Diff line change
@@ -1,104 +1,32 @@
let
evalModules = import ./eval-modules.nix;

getLib = {lockFile}: let
inherit ((builtins.fromJSON (builtins.readFile lockFile))) nodes;
nixpkgsLock = nodes.nixpkgs.locked;
lib = import ((builtins.fetchTarball {
url = "https://github.com/NixOS/nixpkgs/archive/${nixpkgsLock.rev}.tar.gz";
sha256 = nixpkgsLock.narHash;
})
+ "/lib");
libFixed = import ((builtins.fetchTarball {
url = "https://github.com/nix-community/nixpkgs.lib/archive/4833b4eb30dfe3abad5a21775bc5460322c8d337.tar.gz";
sha256 = "sha256:1ppr46pf1glp7irxcr8w4fzfffgl34cnsb0dyy8mm8khw1bzbb5z";
})
+ "/lib");
in
if (builtins.pathExists lockFile && nodes ? nixpkgs)
then lib
else libFixed;
# else builtins.trace "Inputs need to be evaluated again." null;

evaluateConfigInputs = configuration: lib: let
configuration' = builtins.removeAttrs configuration ["inputOverrides"];
in
(evalModules (configuration'
// {
inputs = {
nixpkgs = {
inherit lib;
};
};
}))
.config
.inputs;

combinedManagerSystem = {
inputs,
configuration,
}: let
configuration' = (builtins.removeAttrs configuration ["inputOverrides"]) // {inputs = inputs // ((configuration.inputOverrides or (_: {})) inputs);};
inherit ((evalModules configuration').config) osModules;

evaluated = evalModules (configuration'
// {
inherit osModules;
});
in {inherit (evaluated) config;};

nixosSystem = args: {config = (combinedManagerSystem args).config.os;};

mkFlake = {
lockFile,
description,
initialInputs,
configurations,
outputs ? (_: {}),
}: let
lib = getLib {inherit lockFile;};

evaluatedInputs =
lib.foldl
(
allInputs: configInputs:
# This foldAttrs is basically `allInputs // configInputs` but with an assertion.
lib.foldlAttrs (
allInputs: inputName: inputValue:
assert (!(builtins.elem inputName (builtins.attrNames allInputs) && allInputs.${inputName} != inputValue)) || throw "The input \"${inputName}\" appears more than once and equals to different values!\nFirst definition: ${builtins.toJSON inputValue}\nSecond definition: ${builtins.toJSON allInputs.${inputName}}";
allInputs // {${inputName} = inputValue;}
)
allInputs
configInputs
) {}
(map (config: evaluateConfigInputs config lib)
(builtins.attrValues configurations));
in
assert builtins.elem "nixpkgs" (builtins.attrNames initialInputs) || throw "nixpkgs input not found in initialInputs" {};
assert ((builtins.any (config: config.useHomeManager or true) (builtins.attrValues configurations)) && (builtins.elem "home-manager" (builtins.attrNames initialInputs))) || throw "home-manager input not found in initialInputs" {}; {
{
# TODO Global specialArgs, modules
mkFlake =
{
description,
lockFile,
stateVersion ? null,
initialInputs ? { },
useHomeManager ? true,
configurations,
outputs ? (_: { }),
}@args:
{
inherit description;
inputs = evaluatedInputs // initialInputs;
outputs = inputs:
(outputs inputs)
// {
nixosConfigurations = let
allConfigurations = builtins.mapAttrs (_host: config: config.config) (
(lib.mapAttrs (_name: config:
combinedManagerSystem {
configuration = config // {specialArgs = (config.specialArgs or {}) // {configs = allConfigurations;};};
inherit inputs;
})
configurations)
// (outputs inputs).nixosConfigurations or {}
);
in
(lib.mapAttrs (_name: config:
nixosSystem {
configuration = config // {specialArgs = (config.specialArgs or {}) // {configs = allConfigurations;};};
inherit inputs;
})
configurations)
// (outputs inputs).nixosConfigurations or {};
};
inputs = import ./lib/eval-inputs.nix args;
outputs = import ./lib/eval-outputs.nix args;
};
in {inherit mkFlake nixosSystem;}

nixosSystem =
{
inputs,
useHomeManager ? true,
stateVersion,
prefix ? [ ],
specialArgs ? { },
modules,
osModules ? [ ],
hmModules ? [ ],
}@args:
(import ./lib/eval-outputs.nix { configurations.default = args; } inputs)
.nixosConfigurations.default;
}
Loading