Add a build for the yubikey management raspberry pi image.
This commit is contained in:
parent
3d9513f2c5
commit
3733e76d18
@ -87,6 +87,9 @@ in
|
||||
];
|
||||
maxJobs = 1;
|
||||
supportedFeatures = [
|
||||
"gccarch-armv6"
|
||||
"gccarch-aarch64"
|
||||
"gccarch-riscv64"
|
||||
"nixos-test"
|
||||
"benchmark"
|
||||
"big-parallel"
|
||||
|
||||
@ -26,6 +26,14 @@
|
||||
# TODO: Should "x86_64-linux" be in this list or should this list be dependent on the host CPU?
|
||||
"armv6l-linux" # Raspberry Pi gen 1
|
||||
];
|
||||
|
||||
me.optimizations = {
|
||||
system_features = [
|
||||
"gccarch-armv6"
|
||||
"gccarch-aarch64"
|
||||
"gccarch-riscv64"
|
||||
];
|
||||
};
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
1
nix/yubipi/.gitignore
vendored
Normal file
1
nix/yubipi/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
result
|
||||
177
nix/yubipi/configuration.nix
Normal file
177
nix/yubipi/configuration.nix
Normal file
@ -0,0 +1,177 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
modulesPath,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
imports = [
|
||||
"${modulesPath}/installer/sd-card/sd-image.nix"
|
||||
./roles/image_based_appliance
|
||||
./roles/optimized_build
|
||||
./roles/raspberry_pi_sd_image
|
||||
./roles/reset
|
||||
# ./util/install_files
|
||||
./util/unfree_polyfill
|
||||
];
|
||||
|
||||
nix.settings.experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
nix.settings.trusted-users = [ "@wheel" ];
|
||||
|
||||
hardware.enableRedistributableFirmware = true;
|
||||
|
||||
# Keep outputs so we can build offline.
|
||||
nix.extraOptions = ''
|
||||
keep-outputs = true
|
||||
keep-derivations = true
|
||||
substitute = false
|
||||
'';
|
||||
|
||||
# Technically only needed when building the ISO because nix detects ZFS in the filesystem list normally. I basically always want this so I'm just setting it to always be on.
|
||||
boot.supportedFilesystems.zfs = true;
|
||||
# TODO: Is this different from boot.supportedFilesystems = [ "zfs" ]; ?
|
||||
|
||||
services.getty = {
|
||||
autologinUser = "talexander";
|
||||
autologinOnce = true;
|
||||
};
|
||||
users.mutableUsers = false;
|
||||
users.users.talexander = {
|
||||
isNormalUser = true;
|
||||
createHome = true; # https://github.com/NixOS/nixpkgs/issues/6481
|
||||
group = "talexander";
|
||||
extraGroups = [ "wheel" ];
|
||||
uid = 11235;
|
||||
packages = with pkgs; [
|
||||
tree
|
||||
];
|
||||
# Generate with `mkpasswd -m scrypt`
|
||||
hashedPassword = "$7$CU..../....VXvNQ8za3wSGpdzGXNT50/$HcFtn/yvwPMCw4888BelpiAPLAxe/zU87fD.d/N6U48";
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID0+4zi26M3eYWnIrciR54kOlGxzfgCXG+o4ea1zpzrk openpgp:0x7FF123C8"
|
||||
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIEI6mu6I5Jp+Ib0vJxapGHbEShZjyvzV8jz5DnzDrI39AAAABHNzaDo="
|
||||
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIAFNcSXwvy+brYTOGo56G93Ptuq2MmZsjvRWAfMqbmMLAAAABHNzaDo="
|
||||
];
|
||||
};
|
||||
users.groups.talexander.gid = 11235;
|
||||
|
||||
# Automatic garbage collection
|
||||
nix.gc = lib.mkIf (!config.me.image_based_appliance.enable) {
|
||||
# Runs nix-collect-garbage --delete-older-than 5d
|
||||
automatic = true;
|
||||
persistent = true;
|
||||
dates = "monthly";
|
||||
# randomizedDelaySec = "14m";
|
||||
options = "--delete-older-than 30d";
|
||||
};
|
||||
nix.settings.auto-optimise-store = true;
|
||||
nix.settings.substituters = lib.mkForce [ ];
|
||||
|
||||
# Use doas instead of sudo
|
||||
security.doas.enable = true;
|
||||
security.doas.wheelNeedsPassword = false;
|
||||
security.sudo.enable = false;
|
||||
security.doas.extraRules = [
|
||||
{
|
||||
# Retain environment (for example NIX_PATH)
|
||||
keepEnv = true;
|
||||
persist = true; # Only ask for a password the first time.
|
||||
}
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
# wget
|
||||
# mg
|
||||
# rsync
|
||||
# libinput
|
||||
# htop
|
||||
# tmux
|
||||
# file
|
||||
# usbutils # for lsusb
|
||||
# pciutils # for lspci
|
||||
# ripgrep
|
||||
# strace
|
||||
# # ltrace # Disabled because it uses more than 48GB of /tmp space during test phase.
|
||||
# trace-cmd # ftrace
|
||||
# tcpdump
|
||||
# git-crypt
|
||||
# gnumake
|
||||
# ncdu
|
||||
# nix-tree
|
||||
# libarchive # bsdtar
|
||||
# lsof
|
||||
# doas-sudo-shim # To support --sudo for remote builds
|
||||
# dmidecode # Read SMBIOS information.
|
||||
# ipcalc
|
||||
# gptfdisk # for cgdisk
|
||||
# nix-output-monitor # For better view into nixos-rebuild
|
||||
# nix-serve-ng # Serve nix store over http
|
||||
];
|
||||
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PasswordAuthentication = false;
|
||||
KbdInteractiveAuthentication = false;
|
||||
};
|
||||
hostKeys = [
|
||||
{
|
||||
path = "/persist/ssh/ssh_host_ed25519_key";
|
||||
type = "ed25519";
|
||||
}
|
||||
{
|
||||
path = "/persist/ssh/ssh_host_rsa_key";
|
||||
type = "rsa";
|
||||
bits = 4096;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
boot.initrd.kernelModules = [
|
||||
# "vc4"
|
||||
# "bcm2835_dma"
|
||||
# "i2c_bcm2835"
|
||||
];
|
||||
# Compressing through emulation is slow and we're just going to decompress the image anyway.
|
||||
sdImage.compressImage = false;
|
||||
|
||||
# Write a list of the currently installed packages to /etc/current-system-packages
|
||||
environment.etc."current-system-packages".text =
|
||||
let
|
||||
packages = builtins.map (p: "${p.name}") config.environment.systemPackages;
|
||||
sortedUnique = builtins.sort builtins.lessThan (lib.unique packages);
|
||||
formatted = builtins.concatStringsSep "\n" sortedUnique;
|
||||
in
|
||||
formatted;
|
||||
|
||||
nixpkgs.overlays = [
|
||||
(final: prev: {
|
||||
efivar = throw "foo";
|
||||
})
|
||||
];
|
||||
|
||||
# This option defines the first version of NixOS you have installed on this particular machine,
|
||||
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
||||
#
|
||||
# Most users should NEVER change this value after the initial install, for any reason,
|
||||
# even if you've upgraded your system to a new NixOS release.
|
||||
#
|
||||
# This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
|
||||
# so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
|
||||
# to actually do that.
|
||||
#
|
||||
# This value being lower than the current NixOS release does NOT mean your system is
|
||||
# out of date, out of support, or vulnerable.
|
||||
#
|
||||
# Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
|
||||
# and migrated your data accordingly.
|
||||
#
|
||||
# For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
|
||||
system.stateVersion = "25.11"; # Did you read the comment?
|
||||
|
||||
}
|
||||
44
nix/yubipi/flake.lock
generated
Normal file
44
nix/yubipi/flake.lock
generated
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1759381078,
|
||||
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-unoptimized": {
|
||||
"locked": {
|
||||
"lastModified": 1759381078,
|
||||
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-unoptimized": "nixpkgs-unoptimized"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
43
nix/yubipi/flake.nix
Normal file
43
nix/yubipi/flake.nix
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
description = "My system configuration";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
nixpkgs-unoptimized.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
nixpkgs-unoptimized,
|
||||
...
|
||||
}@inputs:
|
||||
let
|
||||
base_armv6l_linux = rec {
|
||||
system = "armv6l-linux-linux";
|
||||
specialArgs = {
|
||||
pkgs-unoptimized = import nixpkgs-unoptimized {
|
||||
inherit system;
|
||||
hostPlatform.gcc.arch = "default";
|
||||
hostPlatform.gcc.tune = "default";
|
||||
};
|
||||
};
|
||||
modules = [
|
||||
./configuration.nix
|
||||
];
|
||||
};
|
||||
systems = {
|
||||
yubipi = rec {
|
||||
main = base_armv6l_linux // {
|
||||
modules = base_armv6l_linux.modules ++ [
|
||||
./hosts/yubipi
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
nixosConfigurations.yubipi = nixpkgs.lib.nixosSystem systems.yubipi.main;
|
||||
};
|
||||
}
|
||||
9
nix/yubipi/hosts/yubipi/ISO
Executable file
9
nix/yubipi/hosts/yubipi/ISO
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
: "${JOBS:="1"}"
|
||||
|
||||
nix build --extra-experimental-features nix-command --extra-experimental-features flakes "$DIR/../..#nixosConfigurations.yubipi.config.system.build.sdImage" --max-jobs "$JOBS" --log-format internal-json -v "${@}" |& nom --json
|
||||
46
nix/yubipi/hosts/yubipi/default.nix
Normal file
46
nix/yubipi/hosts/yubipi/default.nix
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
./wrapped-disk-config.nix
|
||||
];
|
||||
|
||||
config = {
|
||||
# Generate with `head -c4 /dev/urandom | od -A none -t x4`
|
||||
networking.hostId = "61f81c12";
|
||||
|
||||
networking.hostName = "yubipi"; # Define your hostname.
|
||||
|
||||
time.timeZone = "America/New_York";
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
|
||||
me.optimizations = {
|
||||
enable = true;
|
||||
arch = "armv6";
|
||||
system_features = [
|
||||
"gccarch-armv6l"
|
||||
"benchmark"
|
||||
"big-parallel"
|
||||
"kvm"
|
||||
"nixos-test"
|
||||
];
|
||||
};
|
||||
|
||||
# Early KMS
|
||||
boot.initrd.kernelModules = [ ];
|
||||
|
||||
# Mount tmpfs at /tmp
|
||||
boot.tmp.useTmpfs = true;
|
||||
|
||||
# Enable TRIM
|
||||
services.fstrim.enable = lib.mkDefault true;
|
||||
|
||||
me.image_based_appliance.enable = true;
|
||||
me.raspberry_pi_sd_image.enable = true;
|
||||
};
|
||||
}
|
||||
12
nix/yubipi/hosts/yubipi/disk-config.nix
Normal file
12
nix/yubipi/hosts/yubipi/disk-config.nix
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "/dev/disk/by-label/NIXOS_SD";
|
||||
fsType = "ext4";
|
||||
options = [
|
||||
"noatime"
|
||||
"norelatime"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
28
nix/yubipi/hosts/yubipi/hardware-configuration.nix
Normal file
28
nix/yubipi/hosts/yubipi/hardware-configuration.nix
Normal file
@ -0,0 +1,28 @@
|
||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
modulesPath,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
imports = [
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [
|
||||
"nvme"
|
||||
"xhci_pci"
|
||||
"thunderbolt"
|
||||
];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "armv6l-linux";
|
||||
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
}
|
||||
8
nix/yubipi/hosts/yubipi/wrapped-disk-config.nix
Normal file
8
nix/yubipi/hosts/yubipi/wrapped-disk-config.nix
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
(import ./disk-config.nix)
|
||||
30
nix/yubipi/roles/blank/default.nix
Normal file
30
nix/yubipi/roles/blank/default.nix
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
imports = [ ];
|
||||
|
||||
options.me = {
|
||||
blank.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = "Whether we want to install blank.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf config.me.blank.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
];
|
||||
}
|
||||
(lib.mkIf config.me.graphical {
|
||||
})
|
||||
]
|
||||
);
|
||||
}
|
||||
30
nix/yubipi/roles/image_based_appliance/default.nix
Normal file
30
nix/yubipi/roles/image_based_appliance/default.nix
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
imports = [ ];
|
||||
|
||||
options.me = {
|
||||
image_based_appliance.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = "Whether we want to install image_based_appliance.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf config.me.image_based_appliance.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
# Do not install nix. A full new image must be built to update
|
||||
# the machine.
|
||||
nix.enable = false;
|
||||
system.switch.enable = false;
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
78
nix/yubipi/roles/optimized_build/default.nix
Normal file
78
nix/yubipi/roles/optimized_build/default.nix
Normal file
@ -0,0 +1,78 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
pkgs-unoptimized,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
imports = [ ];
|
||||
|
||||
options.me = {
|
||||
optimizations.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = "Whether we want to enable CPU optimizations (will trigger a rebuild from source).";
|
||||
};
|
||||
|
||||
optimizations.arch = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = null;
|
||||
example = "znver4";
|
||||
description = "The CPU arch for which programs should be optimized.";
|
||||
};
|
||||
|
||||
optimizations.system_features = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [
|
||||
"gccarch-armv6l"
|
||||
"benchmark"
|
||||
"big-parallel"
|
||||
"kvm"
|
||||
"nixos-test"
|
||||
];
|
||||
description = "The list of CPU features that should be enabled on this machine.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
(lib.mkIf (!config.me.optimizations.enable) (
|
||||
lib.mkMerge [
|
||||
{
|
||||
}
|
||||
]
|
||||
))
|
||||
(lib.mkIf config.me.optimizations.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
nixpkgs.config.allowUnsupportedSystem = true;
|
||||
|
||||
nixpkgs.hostPlatform = {
|
||||
gcc.arch = config.me.optimizations.arch;
|
||||
gcc.tune = config.me.optimizations.arch;
|
||||
system = "armv6l-linux";
|
||||
};
|
||||
|
||||
# Uncomment on of these to enable cross compiling:
|
||||
# nixpkgs.buildPlatform = builtins.currentSystem;
|
||||
# nixpkgs.buildPlatform = {
|
||||
# gcc.arch = "znver4";
|
||||
# gcc.tune = "znver4";
|
||||
# system = "x86_64-linux";
|
||||
# };
|
||||
}
|
||||
]
|
||||
))
|
||||
(lib.mkIf (config.me.optimizations.system_features != [ ]) (
|
||||
lib.mkMerge [
|
||||
{
|
||||
nix.settings.system-features = lib.mkForce config.me.optimizations.system_features;
|
||||
}
|
||||
]
|
||||
))
|
||||
|
||||
];
|
||||
}
|
||||
62
nix/yubipi/roles/raspberry_pi_sd_image/default.nix
Normal file
62
nix/yubipi/roles/raspberry_pi_sd_image/default.nix
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
imports = [ ];
|
||||
|
||||
options.me = {
|
||||
raspberry_pi_sd_image.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = "Whether we want to install raspberry_pi_sd_image.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf config.me.raspberry_pi_sd_image.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
boot.loader.grub.enable = false;
|
||||
boot.loader.generic-extlinux-compatible.enable = true;
|
||||
|
||||
boot.consoleLogLevel = lib.mkDefault 7;
|
||||
boot.kernelPackages = pkgs.linuxKernel.packages.linux_rpi1;
|
||||
|
||||
sdImage = {
|
||||
populateFirmwareCommands =
|
||||
let
|
||||
configTxt = pkgs.writeText "config.txt" ''
|
||||
# u-boot refuses to start (gets stuck at rainbow polygon) without this,
|
||||
# at least on Raspberry Pi 0.
|
||||
enable_uart=1
|
||||
|
||||
# Prevent the firmware from smashing the framebuffer setup done by the mainline kernel
|
||||
# when attempting to show low-voltage or overtemperature warnings.
|
||||
avoid_warnings=1
|
||||
|
||||
[pi0]
|
||||
kernel=u-boot-rpi0.bin
|
||||
|
||||
[pi1]
|
||||
kernel=u-boot-rpi1.bin
|
||||
'';
|
||||
in
|
||||
''
|
||||
(cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf *.dtb $NIX_BUILD_TOP/firmware/)
|
||||
cp ${pkgs.ubootRaspberryPiZero}/u-boot.bin firmware/u-boot-rpi0.bin
|
||||
cp ${pkgs.ubootRaspberryPi}/u-boot.bin firmware/u-boot-rpi1.bin
|
||||
cp ${configTxt} firmware/config.txt
|
||||
'';
|
||||
populateRootCommands = ''
|
||||
mkdir -p ./files/boot
|
||||
${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot
|
||||
'';
|
||||
};
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
16
nix/yubipi/roles/reset/default.nix
Normal file
16
nix/yubipi/roles/reset/default.nix
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
imports = [ ];
|
||||
|
||||
# Reset some defaults to start from a minimal more-arch-linux-like state. Think of this like a CSS reset sheet.
|
||||
config = {
|
||||
# Do not use default packages (nixos includes some defaults like nano)
|
||||
environment.defaultPackages = lib.mkForce [ ];
|
||||
};
|
||||
}
|
||||
333
nix/yubipi/util/install_files/default.nix
Normal file
333
nix/yubipi/util/install_files/default.nix
Normal file
@ -0,0 +1,333 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.me.install;
|
||||
inherit (lib)
|
||||
filter
|
||||
attrNames
|
||||
;
|
||||
|
||||
get_shell_values =
|
||||
target:
|
||||
let
|
||||
homedir = config.users.users."${target.username}".home;
|
||||
group = config.users.users."${target.username}".group;
|
||||
in
|
||||
{
|
||||
source = lib.strings.escapeShellArg "${target.source}";
|
||||
destination = lib.strings.escapeShellArg "${homedir}/${target.target}";
|
||||
mode = lib.strings.escapeShellArg "${target.mode}";
|
||||
dir_mode = lib.strings.escapeShellArg "${target.dir_mode}";
|
||||
username = lib.strings.escapeShellArg "${target.username}";
|
||||
group = lib.strings.escapeShellArg "${group}";
|
||||
};
|
||||
install_user_file =
|
||||
let
|
||||
constructors = {
|
||||
"overwrite" = install_user_file_overwrite;
|
||||
"symlink" = install_user_file_symlink;
|
||||
};
|
||||
in
|
||||
stage: target: (constructors."${target.method}"."${stage}" target);
|
||||
install_user_file_overwrite = {
|
||||
"check" = (target: "");
|
||||
"install" = (
|
||||
target:
|
||||
let
|
||||
inherit (get_shell_values target)
|
||||
source
|
||||
destination
|
||||
mode
|
||||
dir_mode
|
||||
username
|
||||
group
|
||||
;
|
||||
flags = lib.strings.concatStringsSep " " [
|
||||
(if mode != "" then "-m ${mode}" else "")
|
||||
(if username != "" then "-o ${username}" else "")
|
||||
(if group != "" then "-g ${group}" else "")
|
||||
];
|
||||
dir_flags = lib.strings.concatStringsSep " " [
|
||||
(if dir_mode != "" then "-m ${dir_mode}" else "")
|
||||
(if username != "" then "-o ${username}" else "")
|
||||
(if group != "" then "-g ${group}" else "")
|
||||
];
|
||||
in
|
||||
if target.recursive then
|
||||
[
|
||||
''
|
||||
find ${source} -type f -print0 | while read -r -d "" file; do
|
||||
relative_path=$(realpath -s --relative-to ${source} "$file")
|
||||
full_dest=${destination}/"$relative_path"
|
||||
create_containing_directories "$full_dest" ${dir_flags}
|
||||
$DRY_RUN_CMD install $VERBOSE_ARG --compare ${flags} "$file" "$full_dest"
|
||||
done
|
||||
''
|
||||
]
|
||||
else
|
||||
[
|
||||
''
|
||||
create_containing_directories ${destination} ${dir_flags}
|
||||
$DRY_RUN_CMD install $VERBOSE_ARG --compare ${flags} ${source} ${destination}
|
||||
''
|
||||
]
|
||||
);
|
||||
"uninstall" = (
|
||||
target:
|
||||
let
|
||||
inherit (get_shell_values target)
|
||||
source
|
||||
destination
|
||||
;
|
||||
in
|
||||
if target.recursive then
|
||||
[
|
||||
''
|
||||
find ${source} -type f -print0 | while read -r -d "" file; do
|
||||
relative_path=$(realpath -s --relative-to ${source} "$file")
|
||||
full_dest=${destination}/"$relative_path"
|
||||
$DRY_RUN_CMD echo rm -f "$full_dest"
|
||||
done
|
||||
''
|
||||
]
|
||||
else
|
||||
[
|
||||
''
|
||||
$DRY_RUN_CMD echo rm -f ${destination}
|
||||
''
|
||||
]
|
||||
);
|
||||
};
|
||||
install_user_file_symlink = {
|
||||
"check" = (target: "");
|
||||
"install" = (
|
||||
target:
|
||||
let
|
||||
inherit (get_shell_values target)
|
||||
source
|
||||
destination
|
||||
mode
|
||||
dir_mode
|
||||
username
|
||||
group
|
||||
;
|
||||
owner = lib.strings.concatStringsSep ":" (
|
||||
filter (val: val != "") [
|
||||
username
|
||||
group
|
||||
]
|
||||
);
|
||||
dir_flags = lib.strings.concatStringsSep " " [
|
||||
(if dir_mode != "" then "-m ${dir_mode}" else "")
|
||||
(if username != "" then "-o ${username}" else "")
|
||||
(if group != "" then "-g ${group}" else "")
|
||||
];
|
||||
in
|
||||
if target.recursive then
|
||||
[
|
||||
''
|
||||
find ${source} -type f -print0 | while read -r -d "" file; do
|
||||
relative_path=$(realpath -s --relative-to ${source} "$file")
|
||||
full_dest=${destination}/"$relative_path"
|
||||
create_containing_directories "$full_dest" ${dir_flags}
|
||||
$DRY_RUN_CMD ln $VERBOSE_ARG -s "$file" "$full_dest"
|
||||
$DRY_RUN_CMD chown $VERBOSE_ARG -h ${owner} "$full_dest"
|
||||
done
|
||||
''
|
||||
]
|
||||
else
|
||||
[
|
||||
''
|
||||
create_containing_directories ${destination} ${dir_flags}
|
||||
$DRY_RUN_CMD ln $VERBOSE_ARG -s ${source} ${destination}
|
||||
$DRY_RUN_CMD chown $VERBOSE_ARG -h ${owner} ${destination}
|
||||
''
|
||||
]
|
||||
);
|
||||
"uninstall" = (
|
||||
target:
|
||||
let
|
||||
inherit (get_shell_values target)
|
||||
source
|
||||
destination
|
||||
;
|
||||
in
|
||||
if target.recursive then
|
||||
[
|
||||
''
|
||||
find ${source} -type f -print0 | while read -r -d "" file; do
|
||||
relative_path=$(realpath -s --relative-to ${source} "$file")
|
||||
full_dest=${destination}/"$relative_path"
|
||||
$DRY_RUN_CMD echo rm -f "$full_dest"
|
||||
done
|
||||
''
|
||||
]
|
||||
else
|
||||
[
|
||||
''
|
||||
$DRY_RUN_CMD echo rm -f ${destination}
|
||||
''
|
||||
]
|
||||
);
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [ ];
|
||||
|
||||
options.me.install = {
|
||||
user = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ name, config, ... }:
|
||||
let
|
||||
username = name;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
defaultText = "enable";
|
||||
example = lib.literalExpression false;
|
||||
description = "Whether we want to install files in this user's home directory.";
|
||||
};
|
||||
|
||||
file = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ name, config, ... }:
|
||||
let
|
||||
path = name;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
defaultText = "enable";
|
||||
example = lib.literalExpression false;
|
||||
description = "Whether we want to install this file in this user's home directory.";
|
||||
};
|
||||
username = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
defaultText = "username";
|
||||
example = "root";
|
||||
description = "The username for the user whose home directory will contain the file.";
|
||||
};
|
||||
target = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
defaultText = "target";
|
||||
example = ".local/share/foo/bar.txt";
|
||||
description = "The path where the file should be written.";
|
||||
};
|
||||
method = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"symlink"
|
||||
"overwrite"
|
||||
# "bind_mount" TODO: for directories?
|
||||
];
|
||||
default = "symlink";
|
||||
defaultText = "me.install.file.‹path›.method";
|
||||
example = "overwrite";
|
||||
description = "The way in which the file should be installed.";
|
||||
};
|
||||
mode = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "0444";
|
||||
defaultText = "me.install.file.‹path›.mode";
|
||||
example = "0750";
|
||||
description = "The read, write, execute permission flags.";
|
||||
};
|
||||
dir_mode = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "0755";
|
||||
defaultText = "dir_mode";
|
||||
example = "0755";
|
||||
description = "The read, write, execute permission flags for any parent directories that need to be created.";
|
||||
};
|
||||
source = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
defaultText = "me.install.file.‹path›.source";
|
||||
example = ./files/foo.txt;
|
||||
description = "The source file to install into the destination.";
|
||||
};
|
||||
recursive = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
defaultText = "recursive";
|
||||
example = lib.literalExpression false;
|
||||
description = "Whether we want to recurse through the directory doing individual installs for each file.";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
username = lib.mkDefault username;
|
||||
target = lib.mkDefault path;
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
all_users = builtins.map (username: cfg.user."${username}") (attrNames cfg.user);
|
||||
enabled_users = filter (user: user.enable) all_users;
|
||||
all_file_targets = lib.flatten (
|
||||
builtins.map (user: (builtins.map (path: user.file."${path}") (attrNames user.file))) enabled_users
|
||||
);
|
||||
enabled_file_targets = filter (target: target.enable) all_file_targets;
|
||||
check_commands = lib.flatten (builtins.map (install_user_file "check") enabled_file_targets);
|
||||
install_commands = lib.flatten (builtins.map (install_user_file "install") enabled_file_targets);
|
||||
uninstall_commands = lib.flatten (
|
||||
builtins.map (install_user_file "uninstall") enabled_file_targets
|
||||
);
|
||||
in
|
||||
{
|
||||
systemd.services.me-install-file = {
|
||||
enable = true;
|
||||
description = "me-install-file";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "multi-user.target" ];
|
||||
before = [ "multi-user.target" ];
|
||||
# path = with pkgs; [
|
||||
# zfs
|
||||
# ];
|
||||
unitConfig.DefaultDependencies = "no";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = "yes";
|
||||
};
|
||||
script =
|
||||
''
|
||||
set -o pipefail
|
||||
IFS=$'\n\t'
|
||||
source ${./files/lib.bash}
|
||||
''
|
||||
+ (lib.strings.concatStringsSep "\n" (
|
||||
[
|
||||
]
|
||||
++ check_commands
|
||||
++ install_commands
|
||||
));
|
||||
preStop =
|
||||
''
|
||||
set -o pipefail
|
||||
IFS=$'\n\t'
|
||||
source ${./files/lib.bash}
|
||||
''
|
||||
+ (lib.strings.concatStringsSep "\n" uninstall_commands);
|
||||
};
|
||||
};
|
||||
}
|
||||
38
nix/yubipi/util/install_files/files/lib.bash
Normal file
38
nix/yubipi/util/install_files/files/lib.bash
Normal file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
|
||||
############## Setup #########################
|
||||
|
||||
function die {
|
||||
local status_code="$1"
|
||||
shift
|
||||
(>&2 echo "${@}")
|
||||
exit "$status_code"
|
||||
}
|
||||
|
||||
function log {
|
||||
(>&2 echo "${@}")
|
||||
}
|
||||
|
||||
############## Program #########################
|
||||
|
||||
function create_containing_directories {
|
||||
local full_dest="$1"
|
||||
shift 1
|
||||
local dirs_to_create=()
|
||||
local containing_directory="$full_dest"
|
||||
while true; do
|
||||
containing_directory=$(dirname "$containing_directory")
|
||||
if [ -e "$containing_directory" ] || [ "$containing_directory" = "/" ]; then
|
||||
break
|
||||
fi
|
||||
dirs_to_create+=($containing_directory)
|
||||
done
|
||||
|
||||
for (( idx=${#dirs_to_create[@]}-1 ; idx>=0 ; idx-- )) ; do
|
||||
local containing_directory="${dirs_to_create[idx]}"
|
||||
log "Creating $containing_directory"
|
||||
$DRY_RUN_CMD install $VERBOSE_ARG -d "${@}" "$containing_directory"
|
||||
done
|
||||
|
||||
}
|
||||
15
nix/yubipi/util/unfree_polyfill/default.nix
Normal file
15
nix/yubipi/util/unfree_polyfill/default.nix
Normal file
@ -0,0 +1,15 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (builtins) elem;
|
||||
inherit (lib) getName mkOption;
|
||||
inherit (lib.types) listOf str;
|
||||
in
|
||||
{
|
||||
# Pending https://github.com/NixOS/nixpkgs/issues/55674
|
||||
options.allowedUnfree = mkOption {
|
||||
type = listOf str;
|
||||
default = [ ];
|
||||
};
|
||||
config.nixpkgs.config.allowUnfreePredicate = p: elem (getName p) config.allowedUnfree;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user