mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-11 18:14:03 +01:00
feat(nix): add arch parity proof-of-concept modules
This commit is contained in:
parent
cbf587c832
commit
0fa473ef0c
28
linux_configuration/nix-poc/configuration.nix
Normal file
28
linux_configuration/nix-poc/configuration.nix
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./modules/arch-parity-poc.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
linuxConfigPoc = {
|
||||||
|
enable = true;
|
||||||
|
mainUser = "kuhy";
|
||||||
|
|
||||||
|
# Turn this on when you intentionally want to run the original imperative
|
||||||
|
# shell installers during activation (hosts install + guard setup, etc.).
|
||||||
|
# Keep it off by default for safe evaluation and incremental migration.
|
||||||
|
enableImperativeBootstrap = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Minimal baseline the host config still needs while this remains a POC.
|
||||||
|
networking.hostName = "arch-parity-poc";
|
||||||
|
time.timeZone = "Europe/Warsaw";
|
||||||
|
|
||||||
|
# Convenience tools for verification/debugging during migration.
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
git
|
||||||
|
jq
|
||||||
|
];
|
||||||
|
|
||||||
|
system.stateVersion = "25.05";
|
||||||
|
}
|
||||||
24
linux_configuration/nix-poc/flake.nix
Normal file
24
linux_configuration/nix-poc/flake.nix
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
description = "NixOS proof-of-concept for linux_configuration parity";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
home-manager = {
|
||||||
|
url = "github:nix-community/home-manager";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { nixpkgs, home-manager, ... }:
|
||||||
|
let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
in {
|
||||||
|
nixosConfigurations.arch-parity-poc = nixpkgs.lib.nixosSystem {
|
||||||
|
inherit system;
|
||||||
|
modules = [
|
||||||
|
home-manager.nixosModules.home-manager
|
||||||
|
./configuration.nix
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
12
linux_configuration/nix-poc/modules/arch-parity-poc.nix
Normal file
12
linux_configuration/nix-poc/modules/arch-parity-poc.nix
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
./arch-parity/options.nix
|
||||||
|
./arch-parity/packages.nix
|
||||||
|
./arch-parity/report.nix
|
||||||
|
./arch-parity/desktop.nix
|
||||||
|
./arch-parity/system-maintenance.nix
|
||||||
|
./arch-parity/hosts-guards.nix
|
||||||
|
./arch-parity/bootstrap.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.linuxConfigPoc;
|
||||||
|
repo = toString cfg.repoPath;
|
||||||
|
in {
|
||||||
|
config = lib.mkIf (cfg.enable && cfg.enableImperativeBootstrap) {
|
||||||
|
system.activationScripts.linuxConfigImperativeBootstrap = {
|
||||||
|
text = ''
|
||||||
|
echo "[linuxConfigPoc] Running imperative bootstrap scripts"
|
||||||
|
bash ${repo}/hosts/install.sh || true
|
||||||
|
bash ${repo}/hosts/guard/setup_hosts_guard.sh || true
|
||||||
|
bash ${repo}/scripts/setup_periodic_system.sh || true
|
||||||
|
'';
|
||||||
|
deps = [ "users" "groups" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
20
linux_configuration/nix-poc/modules/arch-parity/desktop.nix
Normal file
20
linux_configuration/nix-poc/modules/arch-parity/desktop.nix
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.linuxConfigPoc;
|
||||||
|
in {
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.xserver.enable = true;
|
||||||
|
services.xserver.windowManager.i3.enable = true;
|
||||||
|
services.xserver.displayManager.startx.enable = true;
|
||||||
|
|
||||||
|
# Mirror i3 + i3blocks config deployment using Home Manager.
|
||||||
|
home-manager.useGlobalPkgs = true;
|
||||||
|
home-manager.useUserPackages = true;
|
||||||
|
home-manager.users.${cfg.mainUser} = {
|
||||||
|
xdg.configFile."i3/config".source = "${cfg.repoPath}/i3-configuration/i3/config";
|
||||||
|
xdg.configFile."i3blocks/config".source = "${cfg.repoPath}/i3-configuration/i3blocks/config";
|
||||||
|
xdg.configFile."i3blocks".recursive = true;
|
||||||
|
xdg.configFile."i3blocks".source = "${cfg.repoPath}/i3-configuration/i3blocks";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.linuxConfigPoc;
|
||||||
|
repo = toString cfg.repoPath;
|
||||||
|
commonScriptPath = with pkgs; [
|
||||||
|
bash
|
||||||
|
coreutils
|
||||||
|
findutils
|
||||||
|
gawk
|
||||||
|
gnugrep
|
||||||
|
gnused
|
||||||
|
util-linux
|
||||||
|
];
|
||||||
|
|
||||||
|
customHostsEntries = pkgs.runCommand "linux-config-custom-hosts" { } ''
|
||||||
|
sed -n '/^# Custom blocking entries$/,/^EOF$/p' ${cfg.repoPath}/hosts/install.sh \
|
||||||
|
| sed '$d' > "$out"
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
networking.extraHosts = builtins.readFile customHostsEntries;
|
||||||
|
|
||||||
|
# Protect hosts lookup ordering against bypasses.
|
||||||
|
system.nssDatabases.hosts = [ "files" "myhostname" "dns" ];
|
||||||
|
|
||||||
|
systemd.services.hosts-guard = {
|
||||||
|
description = "Enforce canonical /etc/hosts contents";
|
||||||
|
after = [ "local-fs.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${repo}/hosts/guard/enforce-hosts.sh";
|
||||||
|
Nice = "10";
|
||||||
|
IOSchedulingClass = "idle";
|
||||||
|
};
|
||||||
|
path = commonScriptPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.paths.hosts-guard = {
|
||||||
|
description = "Watch /etc/hosts and trigger enforcement";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
pathConfig = {
|
||||||
|
PathChanged = [ "/etc/hosts" ];
|
||||||
|
Unit = "hosts-guard.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.nsswitch-guard = {
|
||||||
|
description = "Enforce canonical /etc/nsswitch.conf (prevents hosts bypass)";
|
||||||
|
after = [ "local-fs.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${repo}/hosts/guard/enforce-nsswitch.sh";
|
||||||
|
Nice = "10";
|
||||||
|
IOSchedulingClass = "idle";
|
||||||
|
};
|
||||||
|
path = commonScriptPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.paths.nsswitch-guard = {
|
||||||
|
description = "Watch /etc/nsswitch.conf for tampering";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
pathConfig = {
|
||||||
|
PathChanged = [ "/etc/nsswitch.conf" ];
|
||||||
|
Unit = "nsswitch-guard.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.resolved-guard = {
|
||||||
|
description = "Enforce canonical /etc/systemd/resolved.conf (prevents hosts bypass)";
|
||||||
|
after = [ "local-fs.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${repo}/hosts/guard/enforce-resolved.sh";
|
||||||
|
Nice = "10";
|
||||||
|
IOSchedulingClass = "idle";
|
||||||
|
};
|
||||||
|
path = commonScriptPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.paths.resolved-guard = {
|
||||||
|
description = "Watch /etc/systemd/resolved.conf for tampering";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
pathConfig = {
|
||||||
|
PathChanged = [ "/etc/systemd/resolved.conf" "/etc/systemd/resolved.conf.d" ];
|
||||||
|
Unit = "resolved-guard.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
117
linux_configuration/nix-poc/modules/arch-parity/options.nix
Normal file
117
linux_configuration/nix-poc/modules/arch-parity/options.nix
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
options.linuxConfigPoc = {
|
||||||
|
enable = lib.mkEnableOption "Arch linux_configuration parity proof-of-concept";
|
||||||
|
|
||||||
|
repoPath = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
default = ../../..;
|
||||||
|
description = "Path to the linux_configuration repository root.";
|
||||||
|
};
|
||||||
|
|
||||||
|
mainUser = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "kuhy";
|
||||||
|
description = "Primary desktop username for user-scoped config (i3/i3blocks).";
|
||||||
|
};
|
||||||
|
|
||||||
|
enableImperativeBootstrap = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Run original shell installers at activation (hosts + guard + periodic setup).";
|
||||||
|
};
|
||||||
|
|
||||||
|
enableResolutionReport = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Generate a package resolution report grouped by migration category.";
|
||||||
|
};
|
||||||
|
|
||||||
|
resolutionReportEtcPath = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "linux-config-poc/package-resolution-report.txt";
|
||||||
|
description = "Path under /etc where the package resolution report is materialized.";
|
||||||
|
};
|
||||||
|
|
||||||
|
enableResolutionReportJson = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Generate a machine-readable JSON package resolution report.";
|
||||||
|
};
|
||||||
|
|
||||||
|
resolutionReportJsonEtcPath = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "linux-config-poc/package-resolution-report.json";
|
||||||
|
description = "Path under /etc where the JSON package resolution report is materialized.";
|
||||||
|
};
|
||||||
|
|
||||||
|
packageMap = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf lib.types.str;
|
||||||
|
default = {
|
||||||
|
# Fonts / desktop
|
||||||
|
"ttf-dejavu" = "dejavu_fonts";
|
||||||
|
"noto-fonts" = "noto-fonts";
|
||||||
|
"ttf-font-awesome" = "font-awesome";
|
||||||
|
"adobe-source-sans-pro-fonts" = "source-sans";
|
||||||
|
"ttf-liberation" = "liberation_ttf";
|
||||||
|
|
||||||
|
# Toolchain / language ecosystems
|
||||||
|
"go-tools" = "gotools";
|
||||||
|
"cargo" = "cargo";
|
||||||
|
"rust" = "rustc";
|
||||||
|
"nodejs" = "nodejs";
|
||||||
|
"npm" = "nodejs";
|
||||||
|
"yarn" = "yarn";
|
||||||
|
"node-gyp" = "nodePackages.node-gyp";
|
||||||
|
"lua52" = "lua5_2";
|
||||||
|
|
||||||
|
# Python package translations
|
||||||
|
"python-nose" = "python3Packages.nose";
|
||||||
|
"python-pyproject-metadata" = "python3Packages.pyproject-metadata";
|
||||||
|
"meson-python" = "python3Packages.meson-python";
|
||||||
|
"python-numpy" = "python3Packages.numpy";
|
||||||
|
"python-markdown" = "python3Packages.markdown";
|
||||||
|
"python-pyparsing" = "python3Packages.pyparsing";
|
||||||
|
"python-pyqt5" = "python3Packages.pyqt5";
|
||||||
|
"python-pefile" = "python3Packages.pefile";
|
||||||
|
"python-booleanoperations" = "python3Packages.booleanoperations";
|
||||||
|
"python-brotli" = "python3Packages.brotli";
|
||||||
|
"python-defcon" = "python3Packages.defcon";
|
||||||
|
"python-fontmath" = "python3Packages.fontmath";
|
||||||
|
"python-fontpens" = "python3Packages.fontpens";
|
||||||
|
"python-fonttools" = "python3Packages.fonttools";
|
||||||
|
"python-fs" = "python3Packages.fs";
|
||||||
|
"python-tqdm" = "python3Packages.tqdm";
|
||||||
|
"python-unicodedata2" = "python3Packages.unicodedata2";
|
||||||
|
"python-zopfli" = "python3Packages.zopfli";
|
||||||
|
"python-pyaml" = "python3Packages.pyyaml";
|
||||||
|
|
||||||
|
# Java / Perl
|
||||||
|
"java-hamcrest" = "hamcrest";
|
||||||
|
"perl-font-ttf" = "perlPackages.FontTTF";
|
||||||
|
"perl-sort-versions" = "perlPackages.SortVersions";
|
||||||
|
|
||||||
|
# Multimedia / desktop mismatches
|
||||||
|
"pavucontrol-qt" = "pavucontrol";
|
||||||
|
"qt5-wayland" = "qt5.qtwayland";
|
||||||
|
"qt6-tools" = "qt6.full";
|
||||||
|
"qt6-shadertools" = "qt6.qtshadertools";
|
||||||
|
"ffmpeg" = "ffmpeg-full";
|
||||||
|
"pyside6" = "python3Packages.pyside6";
|
||||||
|
|
||||||
|
# TeX stack consolidation
|
||||||
|
"texlive-plaingeneric" = "texliveFull";
|
||||||
|
"texlive-latexextra" = "texliveFull";
|
||||||
|
"texlive-bibtexextra" = "texliveFull";
|
||||||
|
"texlive-pictures" = "texliveFull";
|
||||||
|
"texlive-fontsextra" = "texliveFull";
|
||||||
|
"texlive-formatsextra" = "texliveFull";
|
||||||
|
"texlive-pstricks" = "texliveFull";
|
||||||
|
"texlive-games" = "texliveFull";
|
||||||
|
"texlive-humanities" = "texliveFull";
|
||||||
|
"texlive-science" = "texliveFull";
|
||||||
|
};
|
||||||
|
description = "Mapping from Arch package names to nixpkgs attributes.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
55
linux_configuration/nix-poc/modules/arch-parity/packages.nix
Normal file
55
linux_configuration/nix-poc/modules/arch-parity/packages.nix
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.linuxConfigPoc;
|
||||||
|
|
||||||
|
readList = file:
|
||||||
|
let
|
||||||
|
lines = lib.splitString "\n" (builtins.readFile file);
|
||||||
|
trimmed = map lib.strings.trim lines;
|
||||||
|
in
|
||||||
|
builtins.filter (line: line != "" && !(lib.hasPrefix "#" line)) trimmed;
|
||||||
|
|
||||||
|
pacmanPackageFile = "${toString cfg.repoPath}/fresh-install/pacman_packages.txt";
|
||||||
|
aurPackageFile = "${toString cfg.repoPath}/fresh-install/aur_packages.txt";
|
||||||
|
|
||||||
|
pacmanNamesRaw = readList pacmanPackageFile;
|
||||||
|
aurLinesRaw = readList aurPackageFile;
|
||||||
|
aurNames = map (line: builtins.head (lib.splitString " " line)) aurLinesRaw;
|
||||||
|
|
||||||
|
mappedPacmanNames = map
|
||||||
|
(name: if builtins.hasAttr name cfg.packageMap then builtins.getAttr name cfg.packageMap else name)
|
||||||
|
pacmanNamesRaw;
|
||||||
|
|
||||||
|
resolvePackage = name: lib.attrByPath (lib.splitString "." name) null pkgs;
|
||||||
|
|
||||||
|
resolvedPacmanPkgs = builtins.filter (pkg: pkg != null) (map resolvePackage mappedPacmanNames);
|
||||||
|
missingPacmanPkgs = builtins.filter (name: (resolvePackage name) == null) mappedPacmanNames;
|
||||||
|
in {
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
warnings = [
|
||||||
|
"linuxConfigPoc: ${toString (builtins.length resolvedPacmanPkgs)} pacman packages resolved to nixpkgs attrs."
|
||||||
|
"linuxConfigPoc: ${toString (builtins.length missingPacmanPkgs)} pacman packages still need mapping/overlays."
|
||||||
|
"linuxConfigPoc: ${toString (builtins.length aurNames)} AUR packages detected and not yet represented as Nix derivations."
|
||||||
|
"linuxConfigPoc: pacman-wrapper policy/challenges remain imperative scripts; full Nix-native equivalent requires dedicated policy module."
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.systemPackages =
|
||||||
|
lib.unique (
|
||||||
|
(with pkgs; [
|
||||||
|
acpi
|
||||||
|
bc
|
||||||
|
dex
|
||||||
|
i3blocks
|
||||||
|
i3lock
|
||||||
|
i3status
|
||||||
|
iw
|
||||||
|
jq
|
||||||
|
networkmanagerapplet
|
||||||
|
pavucontrol
|
||||||
|
terminator
|
||||||
|
xss-lock
|
||||||
|
])
|
||||||
|
++ resolvedPacmanPkgs
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
169
linux_configuration/nix-poc/modules/arch-parity/report.nix
Normal file
169
linux_configuration/nix-poc/modules/arch-parity/report.nix
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.linuxConfigPoc;
|
||||||
|
|
||||||
|
readList = file:
|
||||||
|
let
|
||||||
|
lines = lib.splitString "\n" (builtins.readFile file);
|
||||||
|
trimmed = map lib.strings.trim lines;
|
||||||
|
in
|
||||||
|
builtins.filter (line: line != "" && !(lib.hasPrefix "#" line)) trimmed;
|
||||||
|
|
||||||
|
pacmanPackageFile = "${toString cfg.repoPath}/fresh-install/pacman_packages.txt";
|
||||||
|
aurPackageFile = "${toString cfg.repoPath}/fresh-install/aur_packages.txt";
|
||||||
|
|
||||||
|
pacmanNamesRaw = readList pacmanPackageFile;
|
||||||
|
aurLinesRaw = readList aurPackageFile;
|
||||||
|
aurNames = map (line: builtins.head (lib.splitString " " line)) aurLinesRaw;
|
||||||
|
|
||||||
|
resolvePackage = path: lib.attrByPath (lib.splitString "." path) null pkgs;
|
||||||
|
existsPath = path: (resolvePackage path) != null;
|
||||||
|
|
||||||
|
mappedRecords = map
|
||||||
|
(original:
|
||||||
|
let
|
||||||
|
mapped = if builtins.hasAttr original cfg.packageMap then builtins.getAttr original cfg.packageMap else original;
|
||||||
|
in {
|
||||||
|
inherit original mapped;
|
||||||
|
resolved = (resolvePackage mapped) != null;
|
||||||
|
})
|
||||||
|
pacmanNamesRaw;
|
||||||
|
|
||||||
|
unresolvedRecords = builtins.filter (record: !record.resolved) mappedRecords;
|
||||||
|
|
||||||
|
sortStrings = builtins.sort (a: b: a < b);
|
||||||
|
sortRecordsByOriginal = builtins.sort (
|
||||||
|
a: b:
|
||||||
|
if a.original == b.original
|
||||||
|
then a.mapped < b.mapped
|
||||||
|
else a.original < b.original
|
||||||
|
);
|
||||||
|
|
||||||
|
candidatePaths = record:
|
||||||
|
let
|
||||||
|
pythonCandidate =
|
||||||
|
if lib.hasPrefix "python-" record.original
|
||||||
|
then "python3Packages.${lib.removePrefix "python-" record.original}"
|
||||||
|
else "";
|
||||||
|
underscoreFromOriginal = lib.replaceStrings [ "-" ] [ "_" ] record.original;
|
||||||
|
dashFromOriginal = lib.replaceStrings [ "_" ] [ "-" ] record.original;
|
||||||
|
underscoreFromMapped = lib.replaceStrings [ "-" ] [ "_" ] record.mapped;
|
||||||
|
dashFromMapped = lib.replaceStrings [ "_" ] [ "-" ] record.mapped;
|
||||||
|
candidates = [
|
||||||
|
record.original
|
||||||
|
record.mapped
|
||||||
|
underscoreFromOriginal
|
||||||
|
dashFromOriginal
|
||||||
|
underscoreFromMapped
|
||||||
|
dashFromMapped
|
||||||
|
pythonCandidate
|
||||||
|
];
|
||||||
|
in
|
||||||
|
lib.unique (builtins.filter (candidate: candidate != "") candidates);
|
||||||
|
|
||||||
|
easySuggestions = record:
|
||||||
|
builtins.filter
|
||||||
|
(candidate: existsPath candidate)
|
||||||
|
(candidatePaths record);
|
||||||
|
easySuggestionsSorted = record: sortStrings (easySuggestions record);
|
||||||
|
|
||||||
|
isAurOrOverlayLikely = record:
|
||||||
|
(builtins.elem record.original aurNames)
|
||||||
|
|| (lib.hasSuffix "-git" record.original)
|
||||||
|
|| (lib.hasPrefix "lib32-" record.original)
|
||||||
|
|| (lib.hasSuffix "-bin" record.original);
|
||||||
|
|
||||||
|
easyMapRecords = builtins.filter (record: (builtins.length (easySuggestions record)) > 0) unresolvedRecords;
|
||||||
|
needsOverlayRecords = builtins.filter
|
||||||
|
(record: ((builtins.length (easySuggestions record)) == 0) && (isAurOrOverlayLikely record))
|
||||||
|
unresolvedRecords;
|
||||||
|
likelyUnavailableRecords = builtins.filter
|
||||||
|
(record: ((builtins.length (easySuggestions record)) == 0) && !(isAurOrOverlayLikely record))
|
||||||
|
unresolvedRecords;
|
||||||
|
|
||||||
|
easyMapRecordsSorted = sortRecordsByOriginal easyMapRecords;
|
||||||
|
needsOverlayRecordsSorted = sortRecordsByOriginal needsOverlayRecords;
|
||||||
|
likelyUnavailableRecordsSorted = sortRecordsByOriginal likelyUnavailableRecords;
|
||||||
|
aurNamesSorted = sortStrings aurNames;
|
||||||
|
|
||||||
|
formatSimpleRecord = record: "- ${record.original} -> ${record.mapped}";
|
||||||
|
formatEasyRecord = record:
|
||||||
|
"- ${record.original} -> ${record.mapped} | suggestions: ${lib.concatStringsSep ", " (easySuggestionsSorted record)}";
|
||||||
|
|
||||||
|
renderLines = lines:
|
||||||
|
if (builtins.length lines) == 0
|
||||||
|
then "- none"
|
||||||
|
else lib.concatStringsSep "\n" lines;
|
||||||
|
|
||||||
|
toEasyJsonRecord = record: {
|
||||||
|
original = record.original;
|
||||||
|
mapped = record.mapped;
|
||||||
|
suggestions = easySuggestionsSorted record;
|
||||||
|
};
|
||||||
|
|
||||||
|
toSimpleJsonRecord = record: {
|
||||||
|
original = record.original;
|
||||||
|
mapped = record.mapped;
|
||||||
|
};
|
||||||
|
|
||||||
|
reportText = ''
|
||||||
|
linux_configuration nix-poc package resolution report
|
||||||
|
================================================
|
||||||
|
|
||||||
|
Source files:
|
||||||
|
- ${pacmanPackageFile}
|
||||||
|
- ${aurPackageFile}
|
||||||
|
|
||||||
|
Summary:
|
||||||
|
- Total pacman package entries: ${toString (builtins.length pacmanNamesRaw)}
|
||||||
|
- Unresolved pacman entries after current mapping: ${toString (builtins.length unresolvedRecords)}
|
||||||
|
- AUR package entries: ${toString (builtins.length aurNames)}
|
||||||
|
|
||||||
|
Category: easy-map (likely solvable by small mapping/path fixes)
|
||||||
|
---------------------------------------------------------------
|
||||||
|
${renderLines (map formatEasyRecord easyMapRecordsSorted)}
|
||||||
|
|
||||||
|
Category: needs-overlay (AUR/multilib/git/bin packages)
|
||||||
|
-------------------------------------------------------
|
||||||
|
${renderLines (map formatSimpleRecord needsOverlayRecordsSorted)}
|
||||||
|
|
||||||
|
Category: likely-unavailable (needs manual investigation)
|
||||||
|
---------------------------------------------------------
|
||||||
|
${renderLines (map formatSimpleRecord likelyUnavailableRecordsSorted)}
|
||||||
|
|
||||||
|
AUR inventory
|
||||||
|
-------------
|
||||||
|
${renderLines (map (name: "- ${name}") aurNamesSorted)}
|
||||||
|
'';
|
||||||
|
|
||||||
|
reportJson = {
|
||||||
|
schemaVersion = "1.0";
|
||||||
|
sourceFiles = {
|
||||||
|
pacman = pacmanPackageFile;
|
||||||
|
aur = aurPackageFile;
|
||||||
|
};
|
||||||
|
summary = {
|
||||||
|
pacmanEntries = builtins.length pacmanNamesRaw;
|
||||||
|
unresolvedPacmanEntries = builtins.length unresolvedRecords;
|
||||||
|
aurEntries = builtins.length aurNames;
|
||||||
|
};
|
||||||
|
categories = {
|
||||||
|
easyMap = map toEasyJsonRecord easyMapRecordsSorted;
|
||||||
|
needsOverlay = map toSimpleJsonRecord needsOverlayRecordsSorted;
|
||||||
|
likelyUnavailable = map toSimpleJsonRecord likelyUnavailableRecordsSorted;
|
||||||
|
};
|
||||||
|
aurInventory = aurNamesSorted;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
config = lib.mkIf (cfg.enable && cfg.enableResolutionReport) {
|
||||||
|
warnings = [
|
||||||
|
"linuxConfigPoc: package resolution report generated at /etc/${cfg.resolutionReportEtcPath}${lib.optionalString cfg.enableResolutionReportJson " and /etc/${cfg.resolutionReportJsonEtcPath}"}"
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.etc = {
|
||||||
|
"${cfg.resolutionReportEtcPath}".text = reportText;
|
||||||
|
} // lib.optionalAttrs cfg.enableResolutionReportJson {
|
||||||
|
"${cfg.resolutionReportJsonEtcPath}".text = builtins.toJSON reportJson;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,119 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.linuxConfigPoc;
|
||||||
|
repo = toString cfg.repoPath;
|
||||||
|
commonScriptPath = with pkgs; [
|
||||||
|
bash
|
||||||
|
coreutils
|
||||||
|
curl
|
||||||
|
findutils
|
||||||
|
gawk
|
||||||
|
gnugrep
|
||||||
|
gnused
|
||||||
|
procps
|
||||||
|
util-linux
|
||||||
|
];
|
||||||
|
in {
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
systemd.services.periodic-system-maintenance = {
|
||||||
|
description = "Periodic System Maintenance (Pacman Wrapper & Hosts File)";
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "root";
|
||||||
|
ExecStart = "${repo}/scripts/system-maintenance/bin/periodic-system-maintenance.sh";
|
||||||
|
StandardOutput = "journal";
|
||||||
|
StandardError = "journal";
|
||||||
|
TimeoutStartSec = "300";
|
||||||
|
TimeoutStopSec = "30";
|
||||||
|
Restart = "no";
|
||||||
|
};
|
||||||
|
path = commonScriptPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.timers.periodic-system-maintenance = {
|
||||||
|
description = "Run Periodic System Maintenance every hour";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "hourly";
|
||||||
|
OnBootSec = "5min";
|
||||||
|
RandomizedDelaySec = "300";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
unitConfig = {
|
||||||
|
Requires = "periodic-system-maintenance.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.periodic-system-startup = {
|
||||||
|
description = "System Maintenance on Startup (Pacman Wrapper & Hosts File)";
|
||||||
|
after = [ "network-online.target" "systemd-resolved.service" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "root";
|
||||||
|
ExecStart = "${repo}/scripts/system-maintenance/bin/periodic-system-maintenance.sh";
|
||||||
|
StandardOutput = "journal";
|
||||||
|
StandardError = "journal";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
TimeoutStartSec = "300";
|
||||||
|
TimeoutStopSec = "30";
|
||||||
|
};
|
||||||
|
path = commonScriptPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.hosts-file-monitor = {
|
||||||
|
description = "Hosts File Monitor and Auto-Restore Service";
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = "root";
|
||||||
|
ExecStart = "${repo}/scripts/system-maintenance/bin/hosts-file-monitor.sh";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = "10";
|
||||||
|
StandardOutput = "journal";
|
||||||
|
StandardError = "journal";
|
||||||
|
NoNewPrivileges = false;
|
||||||
|
PrivateTmp = true;
|
||||||
|
MemoryMax = "50M";
|
||||||
|
CPUQuota = "10%";
|
||||||
|
};
|
||||||
|
path = commonScriptPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.auto-system-update = {
|
||||||
|
description = "Automatic System Update (pacman + yay AUR)";
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "root";
|
||||||
|
ExecStart = "${repo}/scripts/system-maintenance/bin/auto-system-update.sh";
|
||||||
|
StandardOutput = "journal";
|
||||||
|
StandardError = "journal";
|
||||||
|
TimeoutStartSec = "1800";
|
||||||
|
TimeoutStopSec = "30";
|
||||||
|
Restart = "no";
|
||||||
|
};
|
||||||
|
path = commonScriptPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.timers.auto-system-update = {
|
||||||
|
description = "Run Automatic System Update daily";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "*-*-* 04:00:00";
|
||||||
|
RandomizedDelaySec = "1800";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
unitConfig = {
|
||||||
|
Requires = "auto-system-update.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user