Initial commit

This commit is contained in:
kirbara 2025-12-01 13:23:24 +07:00
commit cfcc57a8bd
Signed by: exp
GPG key ID: D7E63AD0019E75D9
353 changed files with 18756 additions and 0 deletions

View file

@ -0,0 +1,5 @@
User TODO: REMOVE this directory (or disable its import from den.nix)
It is used to implement tests for all den features so we can validate at CI.
Use it as reference to see how den features are used, however, be aware that this might not be the best practices for file/aspect organization.

View file

@ -0,0 +1,6 @@
# this is a non-dendritic darwin class module file.
# automatically discovered by `den.import-tree` as enabled in auto-imports.nix
{ ... }:
{
# see nix-darwin options.
}

View file

@ -0,0 +1,14 @@
# this is a non-dendritic nix class module file.
# automatically discovered by `den.import-tree` as enabled in auto-imports.nix
#
# USER TODO: Remove this file.
# suppose this file was auto-generated by nixos-generate-config or some other hardware tooling.
{ lib, ... }:
{
# used in CI to test this file was actually imported.
options.auto-imported = lib.mkOption {
readOnly = true;
type = lib.types.bool;
default = true;
};
}

View file

@ -0,0 +1,27 @@
# Adds some checks for CI
{
perSystem =
{
pkgs,
checkFile,
rockhopper,
honeycrisp,
cam,
bob,
...
}:
let
checks.x86_64-linux = {
vm = checkFile "vm-builds" "${rockhopper.config.system.build.vm}/bin/run-rockhopper-vm";
hosts-rockhopper = checkFile "nixos-builds" rockhopper.config.system.build.toplevel;
homes-cam = checkFile "home-builds" cam.activation-script;
};
checks.aarch64-darwin = {
hosts-honeycrisp = checkFile "darwin-builds" honeycrisp.config.system.build.toplevel;
homes-bob = checkFile "darwin-home-builds" bob.activation-script;
};
in
{
checks = checks.${pkgs.system} or { };
};
}

View file

@ -0,0 +1,30 @@
{
# Including an static aspect should not cause duplicate definitions
den.aspects.alice.includes = [
{
homeManager =
{ pkgs, ... }:
{
programs.emacs.enable = true;
programs.emacs.package = pkgs.emacs30-nox;
};
}
];
perSystem =
{
checkCond,
alice-at-rockhopper,
lib,
...
}:
{
checks.alice-custom-emacs = checkCond "set uniquely via a static includes" (
let
expr = lib.getName alice-at-rockhopper.programs.emacs.package;
expected = "emacs-nox";
in
expr == expected
);
};
}

View file

@ -0,0 +1,35 @@
{ lib, ... }:
let
# A custom `nixos` class module that defines an option `names`.
# Used to test that we are not duplicating values from owned configs.
nixosNames = names: { options.${names} = lib.mkOption { type = lib.types.listOf lib.types.str; }; };
in
{
den.default.nixos.imports = [ (nixosNames "people") ];
den.default.includes = [
(
{ user, ... }:
{
nixos.people = [ user.name ];
}
)
];
den.aspects.rockhopper.includes = [
# Example: importing a third-party nixos module.
{ nixos.imports = [ (nixosNames "names") ]; }
];
den.aspects.rockhopper.nixos.names = [ "tux" ];
perSystem =
{ checkCond, rockhopper, ... }:
{
checks.rockhopper-default-people = checkCond "set from den.default for each user" (
rockhopper.config.people == [ "alice" ]
);
checks.rockhopper-names-single-entry = checkCond "custom nixos array option set once" (
rockhopper.config.names == [ "tux" ]
);
};
}

View file

@ -0,0 +1,27 @@
{ den, ... }:
{
den.default.includes = [
# Example: parametric over many contexts: { home }, { host, user }, { fromUser, toHost }
den.provides.define-user
];
perSystem =
{
checkCond,
rockhopper,
adelie,
...
}:
{
checks.alice-exists-on-rockhopper = checkCond "den.default.user.includes defines user on host" (
rockhopper.config.users.users.alice.isNormalUser
);
checks.alice-not-exists-on-adelie = checkCond "den.default.user.includes defines user on host" (
!adelie.config.users.users ? alice
);
checks.will-exists-on-adelie = checkCond "den.default.user.includes defines user on host" (
adelie.config.users.users.will.isNormalUser
);
};
}

View file

@ -0,0 +1,8 @@
{ inputs, ... }:
{
# Example: adelie host using github:nix-community/NixOS-WSL
den.aspects.adelie.nixos = {
imports = [ inputs.nixos-wsl.nixosModules.default ];
wsl.enable = true;
};
}

View file

@ -0,0 +1,37 @@
{ self, ... }:
{
perSystem =
{ pkgs, ... }:
let
checkFile =
name: file:
pkgs.runCommandLocal name { } ''
ls -la ${file} | tee $out
'';
checkCond =
name: cond:
let
code = if cond then "touch $out" else ''echo "Cond-Failed: ${name}"'';
in
pkgs.runCommandLocal name { } code;
rockhopper = self.nixosConfigurations.rockhopper;
honeycrisp = self.darwinConfigurations.honeycrisp;
adelie = self.wslConfigurations.adelie;
cam = self.homeConfigurations.cam;
bob = self.homeConfigurations.bob;
luke = self.homeConfigurations.luke;
alice-at-rockhopper = rockhopper.config.home-manager.users.alice;
alice-at-honeycrisp = honeycrisp.config.home-manager.users.alice;
in
{
_module.args = {
inherit checkCond checkFile;
inherit rockhopper honeycrisp adelie;
inherit cam bob luke;
inherit alice-at-rockhopper alice-at-honeycrisp;
};
};
}

View file

@ -0,0 +1,13 @@
{
# Example: host provides static config to all its users hm.
den.aspects.rockhopper.homeManager.programs.direnv.enable = true;
perSystem =
{ checkCond, alice-at-rockhopper, ... }:
{
checks.host-contributes-to-user = checkCond "rockhopper contributes to all its users" (
alice-at-rockhopper.programs.direnv.enable
);
};
}

View file

@ -0,0 +1,42 @@
{ lib, ... }:
let
# Example: configuration that depends on both host and user. provides only to HM.
host-to-user-conditional =
{
user,
host,
...
}:
if user.userName == "alice" && !lib.hasSuffix "darwin" host.system then
{
homeManager.programs.git.enable = true;
}
else
{ };
in
{
den.aspects.rockhopper.includes = [
# Example: host provides parametric user configuration.
host-to-user-conditional
];
perSystem =
{
checkCond,
alice-at-rockhopper,
alice-at-honeycrisp,
...
}:
{
checks.alice-hm-git-enabled-on = checkCond "home-managed git for alice at rockhopper" (
alice-at-rockhopper.programs.git.enable
);
checks.alice-hm-git-enabled-off = checkCond "home-managed git for alice at honeycrisp" (
!alice-at-honeycrisp.programs.git.enable
);
};
}

View file

@ -0,0 +1,28 @@
# configures class-automatic module auto imports for hosts/users/homes.
# See documentation at modules/aspects/provides/import-tree.nix
{
# deadnix: skip
__findFile ? __findFile,
...
}:
{
# alice imports non-dendritic <class> modules from _non_dendritic/alice/_<class>/*.nix
den.aspects.alice.includes = [ (<den/import-tree> ./_non_dendritic/alice) ];
# See the documentation at batteries/import-tree.nix
den.default.includes = [
(<den/import-tree/host> ./_non_dendritic/hosts)
(<den/import-tree/user> ./_non_dendritic/users)
(<den/import-tree/home> ./_non_dendritic/homes)
];
# tests
perSystem =
{ checkCond, rockhopper, ... }:
{
checks.import-tree = checkCond "auto-imported from rockhopper/_nixos" (
rockhopper.config.auto-imported
);
};
}

View file

@ -0,0 +1,5 @@
{ inputs, den, ... }:
{
imports = [ (inputs.den.namespace "eg" false) ];
_module.args.__findFile = den.lib.__findFile;
}

View file

@ -0,0 +1,41 @@
let
# Example: adds hello into each user. provides only to OS.
hello-package-for-user =
{
user,
host,
...
}:
{
${host.class} =
{ pkgs, ... }:
{
users.users.${user.userName}.packages = [ pkgs.hello ];
};
};
in
{
den.default.includes = [ hello-package-for-user ];
perSystem =
{
checkCond,
rockhopper,
lib,
...
}:
{
checks.alice-hello-enabled-by-default = checkCond "added hello at user packages" (
let
progs = rockhopper.config.users.users.alice.packages;
expr = map lib.getName progs;
expected = [ "hello" ];
in
expr == expected
);
};
}

View file

@ -0,0 +1,29 @@
{ den, ... }:
{
den.aspects.alice.includes = [
# alice is always admin in all its hosts
den._.primary-user
];
den.aspects.will.includes = [
# will is primary user in WSL NixOS.
den._.primary-user
];
perSystem =
{
checkCond,
honeycrisp,
adelie,
...
}:
{
checks.alice-primary-on-macos = checkCond "den._.primary-user sets macos primary" (
honeycrisp.config.system.primaryUser == "alice"
);
checks.will-is-wsl-default = checkCond "wsl.defaultUser defined" (
adelie.config.wsl.defaultUser == "will"
);
};
}

View file

@ -0,0 +1,29 @@
{
den.default.includes =
let
# Example: parametric host aspect to automatically set hostName on any host.
set-host-name =
{ host, ... }:
{
${host.class}.networking.hostName = host.name;
};
in
[ set-host-name ];
perSystem =
{
checkCond,
rockhopper,
honeycrisp,
...
}:
{
checks.rockhopper-hostname = checkCond "den.default.host.includes sets hostName" (
rockhopper.config.networking.hostName == "rockhopper"
);
checks.honeycrisp-hostname = checkCond "den.default.host.includes sets hostName" (
honeycrisp.config.networking.hostName == "honeycrisp"
);
};
}

View file

@ -0,0 +1,31 @@
let
# Example: luke standalone home-manager has access to rockhopper osConfig specialArg.
os-conditional-hm =
{ home, ... }:
{
# access osConfig, wired via extraSpecialArgs in homes.nix.
homeManager =
{ osConfig, ... }:
{
programs.bat.enable = osConfig.programs.${home.programToDependOn}.enable;
};
};
in
{
# Example: standalone-hm config depends on osConfig (non-recursive)
# NOTE: this will only work for standalone hm, and not for hosted hm
# since a hosted hm configuration cannot depend on the os configuration.
den.aspects.luke.includes = [
os-conditional-hm
];
perSystem =
{ checkCond, luke, ... }:
{
checks.luke-hm-depends-on-osConfig = checkCond "standalone hm can depend on osConfig" (
luke.config.programs.bat.enable
);
};
}

View file

@ -0,0 +1,47 @@
# it is possible for top-level aspects directly under
# den.aspects to take a context argument.
{ den, lib, ... }:
let
# A module to test that toplevel had context.
topLevel = name: {
config.tops = name;
options.tops = lib.mkOption { type = lib.types.str; };
};
in
{
den.aspects.toplevel-user =
{ user, ... }:
{
nixos.imports = [ (topLevel user.name) ];
};
den.aspects.toplevel-host =
{ host, ... }:
{
homeManager.imports = [ (topLevel host.name) ];
};
den.aspects.alice.includes = [
den.aspects.toplevel-host
den.aspects.toplevel-user
];
perSystem =
{
checkCond,
alice-at-rockhopper,
rockhopper,
...
}:
{
checks.alice-toplevel-user = checkCond "alice toplevel param aspect" (
rockhopper.config.tops == "alice"
);
checks.alice-toplevel-host = checkCond "alice toplevel param aspect" (
alice-at-rockhopper.tops == "rockhopper"
);
};
}

View file

@ -0,0 +1,6 @@
{ den, ... }:
{
# cam uses unfree vscode.
den.aspects.cam.homeManager.programs.vscode.enable = true;
den.aspects.cam.includes = [ (den._.unfree [ "vscode" ]) ];
}

View file

@ -0,0 +1,12 @@
{
# Example: user provides static config to all its nixos hosts.
den.aspects.alice.nixos.users.users.alice.description = "Alice Q. User";
perSystem =
{ checkCond, rockhopper, ... }:
{
checks.user-contributes-to-host = checkCond "alice.nixos sets on rockhopper host" (
rockhopper.config.users.users.alice.description == "Alice Q. User"
);
};
}

View file

@ -0,0 +1,12 @@
{
# globally enable fish on all homes ever.
den.default.homeManager.programs.fish.enable = true;
perSystem =
{ checkCond, alice-at-rockhopper, ... }:
{
checks.alice-hm-fish-enabled-by-default = checkCond "home-managed fish for alice" (
alice-at-rockhopper.programs.fish.enable
);
};
}

View file

@ -0,0 +1,38 @@
{ lib, ... }:
let
# Example: configuration that depends on both host and user. provides anytime { user, host } is in context.
user-to-host-conditional =
{ user, host, ... }:
if user.userName == "alice" && !lib.hasSuffix "darwin" host.system then
{
nixos.programs.tmux.enable = true;
}
else
{ };
in
{
# Example: user provides parametric host configuration.
den.aspects.alice.includes = [
user-to-host-conditional
];
perSystem =
{
checkCond,
rockhopper,
honeycrisp,
...
}:
{
checks.alice-os-tmux-enabled-on = checkCond "os tmux for hosts having alice" (
rockhopper.config.programs.tmux.enable
);
checks.alice-os-tmux-enabled-off = checkCond "os tmux for hosts having alice" (
!honeycrisp.config.programs.tmux.enable
);
};
}

View file

@ -0,0 +1,17 @@
{ den, lib, ... }:
{
den.aspects.will.includes = [
# will has always loved red snappers
(den._.user-shell "fish")
];
perSystem =
{ checkCond, adelie, ... }:
{
checks.will-always-love-you = checkCond "red-snapper fish is default shell" (
"fish" == lib.getName adelie.config.users.users.will.shell
);
};
}

View file

@ -0,0 +1,13 @@
{
# Example: enable helix for alice on all its home-managed hosts.
den.aspects.alice.homeManager.programs.helix.enable = true;
perSystem =
{ checkCond, alice-at-rockhopper, ... }:
{
checks.alice-hm-helix-enabled-by-user = checkCond "home-managed helix for alice" (
alice-at-rockhopper.programs.helix.enable
);
};
}

View file

@ -0,0 +1,16 @@
let
# Example: A static aspect for vm installers.
vm-bootable = {
nixos =
{ modulesPath, ... }:
{
imports = [ (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") ];
};
};
in
{
den.default.includes = [
# Example: static aspect
vm-bootable
];
}

View file

@ -0,0 +1,14 @@
# User TODO: Remove this file.
{
# default aspect can be used for global static settings.
den.default = {
# static values.
darwin.system.stateVersion = 6;
nixos.system.stateVersion = "25.05";
homeManager.home.stateVersion = "25.05";
# these defaults are set for checking with CI.
nixos.programs.vim.enable = true;
darwin.programs.zsh.enable = true;
};
}

View file

@ -0,0 +1,12 @@
{ den, ... }:
{
# see batteries/home-manager.nix
den.default.includes = [ den._.home-manager ];
# enable home-manager dependency.
flake-file.inputs.home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
}

View file

@ -0,0 +1,31 @@
# Example standalone home-manager configurations.
# These are independent of any host configuration.
# See documentation at <den>/nix/types.nix
{ inputs, ... }:
{
den.homes.x86_64-linux.cam = { };
den.homes.aarch64-darwin.bob = {
userName = "robert";
aspect = "developer";
};
# Example: custom home-manager instantiate for passing extraSpecialArgs.
den.homes.x86_64-linux.luke =
let
osConfig = inputs.self.nixosConfigurations.rockhopper.config;
in
{
# Example: luke standalone-homemanager needs access to rockhopper osConfig.
instantiate =
{ pkgs, modules }:
inputs.home-manager.lib.homeManagerConfiguration {
inherit pkgs modules;
extraSpecialArgs.osConfig = osConfig;
};
# Example: custom attribute instead of specialArgs
programToDependOn = "vim";
};
}

View file

@ -0,0 +1,50 @@
# This is a fully working example configuration.
# Feel free to remove it, adapt or split into several modules.
# See documentation at <den>/nix/types.nix
{ inputs, ... }:
{
den.hosts.aarch64-darwin.honeycrisp.users.alice = { };
den.hosts.aarch64-linux.emperor.users.alice = { };
den.hosts.x86_64-linux = {
rockhopper = {
description = "rockhopper is a kind of penguin";
users.alice = { };
};
adelie = {
description = "wsl on windows";
users.will = { };
intoAttr = "wslConfigurations";
# custom nixpkgs channel.
instantiate = inputs.nixpkgs-stable.lib.nixosSystem;
# custom attribute (see home-manager.nix)
hm-module = inputs.home-manager-stable.nixosModules.home-manager;
# custom attribute (see primary-user.nix)
wsl = { };
};
};
# move these inputs to any module you want.
# they are here for all our examples to work on CI.
flake-file.inputs = {
# these stable inputs are for wsl
nixpkgs-stable.url = "github:nixos/nixpkgs/release-25.05";
home-manager-stable.url = "github:nix-community/home-manager/release-25.05";
home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable";
nixos-wsl = {
url = "github:nix-community/nixos-wsl";
inputs.nixpkgs.follows = "nixpkgs-stable";
inputs.flake-compat.follows = "";
};
darwin = {
url = "github:nix-darwin/nix-darwin";
inputs.nixpkgs.follows = "nixpkgs";
};
};
}