IT WORKS
This commit is contained in:
parent
da509d97c7
commit
3765e918d6
18 changed files with 348 additions and 226 deletions
20
Cargo.lock
generated
20
Cargo.lock
generated
|
|
@ -158,6 +158,8 @@ dependencies = [
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"itertools",
|
"itertools",
|
||||||
"libc",
|
"libc",
|
||||||
|
"regex",
|
||||||
|
"regex-lite",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tap",
|
"tap",
|
||||||
|
|
@ -422,6 +424,18 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-automata"
|
name = "regex-automata"
|
||||||
version = "0.4.14"
|
version = "0.4.14"
|
||||||
|
|
@ -433,6 +447,12 @@ dependencies = [
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-lite"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.9"
|
version = "0.8.9"
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,19 @@ path = "src/main.rs"
|
||||||
name = "dynix"
|
name = "dynix"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["regex-full"]
|
||||||
|
regex-full = ["dep:regex"]
|
||||||
|
regex-lite = ["dep:regex-lite"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5.54", features = ["color", "derive"] }
|
clap = { version = "4.5.54", features = ["color", "derive"] }
|
||||||
command-error = "0.8.0"
|
command-error = "0.8.0"
|
||||||
fs-err = "3.2.2"
|
fs-err = "3.2.2"
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
libc = { version = "0.2.180", features = ["extra_traits"] }
|
libc = { version = "0.2.180", features = ["extra_traits"] }
|
||||||
|
regex = { version = "1.12.3", optional = true }
|
||||||
|
regex-lite = { version = "0.1.9", optional = true }
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
tap = "1.0.1"
|
tap = "1.0.1"
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ let
|
||||||
|
|
||||||
inherit (import ./lib.nix { inherit lib; })
|
inherit (import ./lib.nix { inherit lib; })
|
||||||
typeCheck
|
typeCheck
|
||||||
convenientAttrPath
|
|
||||||
concatFoldl
|
concatFoldl
|
||||||
recUpdateFoldl
|
recUpdateFoldl
|
||||||
recUpdateFoldlAttrs
|
recUpdateFoldlAttrs
|
||||||
|
|
@ -64,6 +63,13 @@ in
|
||||||
default = { };
|
default = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
finalEnabledSubmodules = mkOption {
|
||||||
|
type = options.dynamicism.for.type;
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
default = lib.filterAttrs (lib.const (lib.getAttr "enable")) config.dynamicism.for;
|
||||||
|
};
|
||||||
|
|
||||||
finalSettings = mkOption {
|
finalSettings = mkOption {
|
||||||
type = t.attrsOf t.raw;
|
type = t.attrsOf t.raw;
|
||||||
internal = true;
|
internal = true;
|
||||||
|
|
@ -78,14 +84,6 @@ in
|
||||||
type = t.functionTo t.raw;
|
type = t.functionTo t.raw;
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
doChange = mkOption {
|
|
||||||
type = t.functionTo t.pathInStore;
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
The function to call to Do The Thing.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Assertions.
|
# Assertions.
|
||||||
|
|
@ -94,27 +92,49 @@ in
|
||||||
#
|
#
|
||||||
# Generic implementation.
|
# Generic implementation.
|
||||||
#
|
#
|
||||||
config.system.activationScripts."dynamicism-reset" = {
|
|
||||||
deps = [ "etc" "stdio" "specialfs" ];
|
config.system.activationScripts = config.dynamicism.for
|
||||||
text = ''
|
|> lib.filterAttrs (lib.const (lib.getAttr "enable"))
|
||||||
echo "DYNIX: removing existing systemd dropins"
|
|> lib.mapAttrs' (name: submod: let
|
||||||
# FIXME: do for each enabled submodule
|
forUnit = unitName: assert lib.isString unitName; let
|
||||||
if [[ -d /run/systemd/system ]]; then
|
dropinDir = "/run/systemd/system/${unitName}.d";
|
||||||
rm -v /run/systemd/system/*/dynix-*.conf || true
|
systemctl = lib.getExe' pkgs.systemd "systemctl";
|
||||||
|
in ''
|
||||||
|
if [[ -d "${dropinDir}" ]]; then
|
||||||
|
echo "Removing files in "${dropinDir}" >&2
|
||||||
|
|
||||||
|
rm -rvf "${dropinDir}/"*
|
||||||
|
rmdir "${dropinDir}"
|
||||||
|
|
||||||
|
${systemctl} daemon-reload
|
||||||
|
${systemctl} try-reload-or-restart "${unitName}"
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
|
in {
|
||||||
|
name = "dynix-reset-dynamicism-for-${name}";
|
||||||
|
value.deps = [ "etc" "stdio" "specialfs" "binsh" "usrbinenv" "var" "udevd" ];
|
||||||
|
value.text = ''
|
||||||
|
echo "Removing existing dynamic overrides for ${name}" >&2
|
||||||
|
${submod.systemd-services-updated |> lib.map forUnit |> lib.concatStringsSep "\n"}
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
config.dynamicism = {
|
config.dynamicism = {
|
||||||
|
|
||||||
applyDynamicConfiguration = {
|
applyDynamicConfiguration = {
|
||||||
baseConfiguration ? builtins.getEnv "NIXOS_CONFIG",
|
baseConfiguration ? builtins.getEnv "NIXOS_CONFIG",
|
||||||
newConfiguration ? baseConfiguration + "/dynamic.nix",
|
newConfiguration ? (lib.filesystem.dirOf baseConfiguration) + "/dynamic.nix",
|
||||||
}: let
|
}: let
|
||||||
locFor = appendage: lib.concatLists [
|
locFor = appendage: lib.concatLists [
|
||||||
opts.applyDynamicConfiguration.loc
|
opts.applyDynamicConfiguration.loc
|
||||||
[ "(function argument)" ]
|
[ "(function argument)" ]
|
||||||
(lib.toList appendage)
|
(lib.toList appendage)
|
||||||
];
|
];
|
||||||
|
in
|
||||||
|
assert seqTrue (typeCheck (locFor "baseConfiguration") t.deferredModule baseConfiguration);
|
||||||
|
assert seqTrue (typeCheck (locFor "newConfiguration") t.deferredModule newConfiguration);
|
||||||
|
let
|
||||||
|
|
||||||
_file = "«inline module in ${showOption opts.applyDynamicConfiguration.loc}»";
|
_file = "«inline module in ${showOption opts.applyDynamicConfiguration.loc}»";
|
||||||
|
|
||||||
|
|
@ -132,49 +152,25 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
submodulesChanged = lib.filter (submodName:
|
submodulesChanged = nixosAfter.config.dynamicism.finalEnabledSubmodules
|
||||||
|
|> lib.filterAttrs (submodName: _:
|
||||||
nixosBefore.config.dynamicism.for.${submodName}.finalSettings
|
nixosBefore.config.dynamicism.for.${submodName}.finalSettings
|
||||||
!=
|
!=
|
||||||
nixosAfter.config.dynamicism.for.${submodName}.finalSettings
|
nixosAfter.config.dynamicism.for.${submodName}.finalSettings
|
||||||
) (lib.attrNames config.dynamicism.for);
|
);
|
||||||
in
|
|
||||||
assert seqTrue (typeCheck (locFor "baseConfiguration") t.deferredModule baseConfiguration);
|
|
||||||
assert seqTrue (typeCheck (locFor "newConfiguration") t.deferredModule newConfiguration);
|
|
||||||
{
|
|
||||||
inherit submodulesChanged;
|
|
||||||
};
|
|
||||||
|
|
||||||
doChange = {
|
runForSubmodCalled = name: ''
|
||||||
option,
|
|
||||||
value,
|
|
||||||
configuration ? builtins.getEnv "NIXOS_CONFIG",
|
|
||||||
}: let
|
|
||||||
loc = opts.doChange.loc ++ [ "(function argument)" "value" ];
|
|
||||||
option' = typeCheck loc convenientAttrPath option;
|
|
||||||
nixosAfter = evalNixos {
|
|
||||||
configuration = { config, ... }: {
|
|
||||||
imports = [
|
|
||||||
configuration
|
|
||||||
(lib.setAttrByPath option' (lib.mkOverride (-999) value))
|
|
||||||
];
|
|
||||||
|
|
||||||
environment.systemPackages = [
|
|
||||||
config.dynamicism.for.gotosocial.activate
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
runAllActivationScripts = nixosAfter.config.dynamicism.for
|
|
||||||
|> lib.filterAttrs (lib.const (lib.getAttr "enable"))
|
|
||||||
|> lib.mapAttrsToList (name: submod: ''
|
|
||||||
echo "Activating dynamic configuration for ${name}"
|
echo "Activating dynamic configuration for ${name}"
|
||||||
${lib.getExe submod.activate}
|
${lib.getExe nixosAfter.config.dynamicism.for.${name}.activate}
|
||||||
'')
|
'';
|
||||||
|
|
||||||
|
runForChanged = submodulesChanged
|
||||||
|
|> lib.mapAttrsToList (name: _: runForSubmodCalled name)
|
||||||
|> lib.concatStringsSep "\n";
|
|> lib.concatStringsSep "\n";
|
||||||
|
|
||||||
in pkgs.writeShellApplication {
|
in pkgs.writeShellApplication {
|
||||||
name = "dynamicism-activate";
|
name = "dynamicism-activate";
|
||||||
text = runAllActivationScripts;
|
text = runForChanged;
|
||||||
passthru.configuration = nixosAfter;
|
passthru.configuration = nixosAfter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ in
|
||||||
text = ''
|
text = ''
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=
|
ExecStart=
|
||||||
ExecStart=${lib.getExe' pkgs.gotosocial "gotosocial"} --config-path ${configFile} start
|
ExecStart=${lib.getExe' pkgs.gotosocial "gotosocial"} --config-path ${configFile} server start
|
||||||
'';
|
'';
|
||||||
passthru = { inherit configFile; };
|
passthru = { inherit configFile; };
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,19 @@ in lib.fix (self: {
|
||||||
/** Either a list of strings, or a dotted string that will be split. */
|
/** Either a list of strings, or a dotted string that will be split. */
|
||||||
convenientAttrPath = t.coercedTo t.str (lib.splitString ".") (t.listOf t.str);
|
convenientAttrPath = t.coercedTo t.str (lib.splitString ".") (t.listOf t.str);
|
||||||
|
|
||||||
|
executablePathInStore = lib.mkOptionType {
|
||||||
|
name = "exepath";
|
||||||
|
description = "executable path in the Nix store";
|
||||||
|
descriptionClass = "noun";
|
||||||
|
merge = lib.mergeEqualOption;
|
||||||
|
functor = lib.defaultFunctor "exepath";
|
||||||
|
check = x: if lib.isDerivation x then (
|
||||||
|
x.meta.mainProgram or null != null
|
||||||
|
) else (
|
||||||
|
lib.pathInStore.check x
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
concatFoldl = f: list: lib.foldl' (acc: value: acc ++ (f value)) [ ] list;
|
concatFoldl = f: list: lib.foldl' (acc: value: acc ++ (f value)) [ ] list;
|
||||||
recUpdateFoldl = f: list: lib.foldl' (acc: value: lib.recursiveUpdate acc (f value)) { } list;
|
recUpdateFoldl = f: list: lib.foldl' (acc: value: lib.recursiveUpdate acc (f value)) { } list;
|
||||||
recUpdateFoldlAttrs = f: attrs: lib.foldlAttrs (acc: name: value: lib.recursiveUpdate acc (f name value)) { } attrs;
|
recUpdateFoldlAttrs = f: attrs: lib.foldlAttrs (acc: name: value: lib.recursiveUpdate acc (f name value)) { } attrs;
|
||||||
|
|
|
||||||
|
|
@ -14,32 +14,15 @@ let
|
||||||
mkEnableOption
|
mkEnableOption
|
||||||
literalExpression
|
literalExpression
|
||||||
;
|
;
|
||||||
inherit (lib.types)
|
|
||||||
mkOptionType
|
|
||||||
;
|
|
||||||
t = lib.types;
|
t = lib.types;
|
||||||
|
|
||||||
inherit (import ./lib.nix { inherit lib; })
|
inherit (import ./lib.nix { inherit lib; })
|
||||||
|
convenientAttrPath
|
||||||
|
executablePathInStore
|
||||||
recUpdateFoldl
|
recUpdateFoldl
|
||||||
;
|
;
|
||||||
|
|
||||||
pkgs = host.pkgs;
|
pkgs = host.pkgs;
|
||||||
|
|
||||||
/** Either a list of strings, or a dotted string that will be split. */
|
|
||||||
convenientAttrPath = t.coercedTo t.str (lib.splitString ".") (t.listOf t.str);
|
|
||||||
|
|
||||||
executablePathInStore = mkOptionType {
|
|
||||||
name = "exepath";
|
|
||||||
description = "executable path in the Nix store";
|
|
||||||
descriptionClass = "noun";
|
|
||||||
merge = lib.mergeEqualOption;
|
|
||||||
functor = lib.defaultFunctor "exepath";
|
|
||||||
check = x: if lib.isDerivation x then (
|
|
||||||
x.meta.mainProgram or null != null
|
|
||||||
) else (
|
|
||||||
lib.pathInStore.check x
|
|
||||||
);
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
|
|
@ -74,8 +57,9 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
configFile = mkOption {
|
configFile = mkOption {
|
||||||
type = t.pathInStore;
|
type = t.nullOr t.pathInStore;
|
||||||
internal = true;
|
internal = true;
|
||||||
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
unitDropins = mkOption {
|
unitDropins = mkOption {
|
||||||
|
|
|
||||||
|
|
@ -122,9 +122,7 @@ in {
|
||||||
fenixToolchain,
|
fenixToolchain,
|
||||||
}: let
|
}: let
|
||||||
mkShell' = mkShell.override { inherit stdenv; };
|
mkShell' = mkShell.override { inherit stdenv; };
|
||||||
pyEnv = python3Packages.python.withPackages (p: [
|
pyEnv = python3Packages.python.withPackages (p: [ p.beartype ]);
|
||||||
p.beartype
|
|
||||||
]);
|
|
||||||
in mkShell' {
|
in mkShell' {
|
||||||
name = "devshell-for-${self.name}";
|
name = "devshell-for-${self.name}";
|
||||||
inputsFrom = [ self ];
|
inputsFrom = [ self ];
|
||||||
|
|
|
||||||
34
src/args.rs
34
src/args.rs
|
|
@ -1,4 +1,7 @@
|
||||||
use std::sync::Arc;
|
use std::{
|
||||||
|
env,
|
||||||
|
sync::{Arc, LazyLock},
|
||||||
|
};
|
||||||
|
|
||||||
use clap::ColorChoice;
|
use clap::ColorChoice;
|
||||||
|
|
||||||
|
|
@ -52,6 +55,7 @@ impl FromStr for NixOsOption {
|
||||||
pub struct AppendCmd {
|
pub struct AppendCmd {
|
||||||
#[arg(required = true)]
|
#[arg(required = true)]
|
||||||
pub name: Arc<str>,
|
pub name: Arc<str>,
|
||||||
|
|
||||||
#[arg(required = true)]
|
#[arg(required = true)]
|
||||||
pub value: Arc<str>,
|
pub value: Arc<str>,
|
||||||
}
|
}
|
||||||
|
|
@ -67,6 +71,28 @@ pub enum Subcommand {
|
||||||
Delta(DeltaCmd),
|
Delta(DeltaCmd),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DEFAULT_PATH: LazyLock<Box<OsStr>> = LazyLock::new(|| {
|
||||||
|
// This has to be in a let binding to keep the storage around.
|
||||||
|
let nixos_config = env::var_os("NIXOS_CONFIG");
|
||||||
|
let nixos_config = nixos_config
|
||||||
|
.as_deref()
|
||||||
|
.map(Path::new)
|
||||||
|
.unwrap_or(Path::new("/etc/nixos/configuration.nix"));
|
||||||
|
|
||||||
|
nixos_config
|
||||||
|
.parent()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
error!(
|
||||||
|
"Your $NIXOS_CONFIG value doesn't make sense: {}. Ignoring.",
|
||||||
|
nixos_config.display(),
|
||||||
|
);
|
||||||
|
Path::new("/etc/nixos")
|
||||||
|
})
|
||||||
|
.join("dynamic.nix")
|
||||||
|
.into_os_string()
|
||||||
|
.into_boxed_os_str()
|
||||||
|
});
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, clap::Parser)]
|
#[derive(Debug, Clone, PartialEq, clap::Parser)]
|
||||||
#[command(version, about, author)]
|
#[command(version, about, author)]
|
||||||
#[command(arg_required_else_help(true), args_override_self(true))]
|
#[command(arg_required_else_help(true), args_override_self(true))]
|
||||||
|
|
@ -75,8 +101,10 @@ pub struct Args {
|
||||||
#[arg(long, global(true), default_value = "auto")]
|
#[arg(long, global(true), default_value = "auto")]
|
||||||
pub color: ColorChoice,
|
pub color: ColorChoice,
|
||||||
|
|
||||||
// FIXME: default to /etc/configuration.nix, or something?
|
/// The .nix file with dynamic overrides to modify.
|
||||||
#[arg(long, global(true), default_value = "./configuration.nix")]
|
/// [default: $(dirname ${NIXOS_CONFIG-/etc/nixos/configuration.nix})/dynamic.nix]
|
||||||
|
#[arg(long, global(true), default_value = &**DEFAULT_PATH)]
|
||||||
|
#[arg(hide_default_value(true))]
|
||||||
pub file: Arc<OsStr>,
|
pub file: Arc<OsStr>,
|
||||||
|
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
|
|
|
||||||
110
src/lib.rs
110
src/lib.rs
|
|
@ -1,4 +1,7 @@
|
||||||
use std::{iter, sync::Arc};
|
use std::{
|
||||||
|
iter,
|
||||||
|
sync::{Arc, LazyLock},
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) mod prelude {
|
pub(crate) mod prelude {
|
||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
|
|
@ -41,14 +44,38 @@ pub mod line;
|
||||||
mod nixcmd;
|
mod nixcmd;
|
||||||
pub use line::Line;
|
pub use line::Line;
|
||||||
pub mod source;
|
pub mod source;
|
||||||
pub use source::SourceLine;
|
pub use source::{SourceFile, SourceLine};
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "regex-full"), not(feature = "regex-lite")))]
|
||||||
|
compile_error!("At least one of features `regex-full` or `regex-lite` must be used");
|
||||||
|
|
||||||
|
#[cfg(feature = "regex-full")]
|
||||||
|
use regex as _regex;
|
||||||
|
|
||||||
|
// Having both `regex-full` and `regex-lite` isn't an error; it's just wasteful.
|
||||||
|
#[cfg(not(feature = "regex-full"))]
|
||||||
|
use regex_lite as _regex;
|
||||||
|
|
||||||
|
use _regex::Regex;
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::source::SourceFile;
|
|
||||||
|
|
||||||
pub const ASCII_WHITESPACE: &[char] = &['\t', '\n', '\x0C', '\r', ' '];
|
pub const ASCII_WHITESPACE: &[char] = &['\t', '\n', '\x0C', '\r', ' '];
|
||||||
|
|
||||||
|
/// Regex pattern to extract the priority in a `lib.mkOverride` call.
|
||||||
|
static MK_OVERRIDE_RE: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
|
// Named capture group: priority
|
||||||
|
// - Word boundary
|
||||||
|
// - Literal `mkOverride`
|
||||||
|
// - One or more whitespace characters
|
||||||
|
// - Literal open parenthesis
|
||||||
|
// - Named capture group "priority"
|
||||||
|
// - One or more of: digit characters, or literal `-`
|
||||||
|
// - Literal close parenthesis
|
||||||
|
Regex::new(r"(?-u)\bmkOverride\s+\((?<priority>[\d-]+)\)").unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug")]
|
#[tracing::instrument(level = "debug")]
|
||||||
pub fn do_delta(args: Arc<Args>, delta_args: DeltaCmd) -> Result<(), BoxDynError> {
|
pub fn do_delta(args: Arc<Args>, delta_args: DeltaCmd) -> Result<(), BoxDynError> {
|
||||||
todo!();
|
todo!();
|
||||||
|
|
@ -65,17 +92,15 @@ pub fn do_append(args: Arc<Args>, append_args: AppendCmd) -> Result<(), BoxDynEr
|
||||||
filepath.to_path_buf()
|
filepath.to_path_buf()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get what file that thing is defined in.
|
|
||||||
let def_path = get_where(&append_args.name, &filepath)?;
|
|
||||||
|
|
||||||
let mut opts = File::options();
|
let mut opts = File::options();
|
||||||
opts.read(true)
|
opts.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(false)
|
.create(false)
|
||||||
.custom_flags(libc::O_CLOEXEC);
|
.custom_flags(libc::O_CLOEXEC);
|
||||||
let source_file = SourceFile::open_from(Arc::from(def_path), opts)?;
|
|
||||||
|
|
||||||
let pri = get_highest_prio(&append_args.name, source_file.clone())?;
|
let source_file = SourceFile::open_from(Arc::from(filepath), opts)?;
|
||||||
|
let pri = get_where(source_file.clone())?;
|
||||||
|
|
||||||
let new_pri = pri - 1;
|
let new_pri = pri - 1;
|
||||||
|
|
||||||
let new_pri_line = get_next_prio_line(
|
let new_pri_line = get_next_prio_line(
|
||||||
|
|
@ -85,7 +110,7 @@ pub fn do_append(args: Arc<Args>, append_args: AppendCmd) -> Result<(), BoxDynEr
|
||||||
append_args.value.into(),
|
append_args.value.into(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
eprintln!("new_pri_line={new_pri_line}");
|
debug!("new_pri_line={new_pri_line}");
|
||||||
|
|
||||||
write_next_prio(source_file, new_pri_line)?;
|
write_next_prio(source_file, new_pri_line)?;
|
||||||
|
|
||||||
|
|
@ -108,35 +133,30 @@ pub fn expr_for_configuration(source_file: &Path) -> OsString {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_where(option_name: &str, configuration_nix: &Path) -> Result<Box<Path>, BoxDynError> {
|
fn maybe_extract_prio_from_line(line: &SourceLine) -> Option<i64> {
|
||||||
let expr = expr_for_configuration(configuration_nix);
|
MK_OVERRIDE_RE
|
||||||
let attrpath = format!("options.{}.definitionsWithLocations", option_name);
|
.captures(line.text_ref())
|
||||||
|
.map(|caps| caps.name("priority").unwrap().as_str())
|
||||||
let output = nixcmd::NixEvalExpr { expr, attrpath }
|
.map(|prio_str| {
|
||||||
.into_command()
|
i64::from_str(prio_str).unwrap_or_else(|e| {
|
||||||
.output_checked_utf8()?;
|
panic!(
|
||||||
let stdout = output.stdout();
|
"lib.mkOverride called with non-integer {}: {}. Nix source code is wrong!\n{}",
|
||||||
|
prio_str, e, line,
|
||||||
let definitions: Box<[DefinitionWithLocation]> = serde_json::from_str(&stdout)?;
|
);
|
||||||
let last_location = definitions.into_iter().last().unwrap();
|
})
|
||||||
|
})
|
||||||
Ok(Box::from(last_location.file))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_highest_prio(option_name: &str, source: SourceFile) -> Result<i64, BoxDynError> {
|
pub fn get_where(dynamic_nix: SourceFile) -> Result<i64, BoxDynError> {
|
||||||
// Get the current highest priority.
|
let lines = dynamic_nix.lines()?;
|
||||||
|
let prio = lines
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(maybe_extract_prio_from_line)
|
||||||
|
.sorted_unstable()
|
||||||
|
.next() // Priorities with lower integer values are "stronger" priorities.
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
let expr = expr_for_configuration(&source.path());
|
Ok(prio)
|
||||||
|
|
||||||
// Get the highest priority, and the file its defined in.
|
|
||||||
let attrpath = format!("options.{}.highestPrio", option_name);
|
|
||||||
let output = nixcmd::NixEvalExpr { expr, attrpath }
|
|
||||||
.into_command()
|
|
||||||
.output_checked_utf8()?;
|
|
||||||
let stdout = output.stdout();
|
|
||||||
let highest_prio = i64::from_str(stdout.trim())?;
|
|
||||||
|
|
||||||
Ok(highest_prio)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_next_prio_line(
|
pub fn get_next_prio_line(
|
||||||
|
|
@ -146,15 +166,19 @@ pub fn get_next_prio_line(
|
||||||
new_value: Arc<str>,
|
new_value: Arc<str>,
|
||||||
) -> Result<SourceLine, BoxDynError> {
|
) -> Result<SourceLine, BoxDynError> {
|
||||||
let source_lines = source.lines()?;
|
let source_lines = source.lines()?;
|
||||||
let last_line = source_lines.last();
|
let penultimate = source_lines.get(source_lines.len() - 2);
|
||||||
assert_eq!(last_line.map(SourceLine::text).as_deref(), Some("]"));
|
// FIXME: don't rely on whitespace lol
|
||||||
let last_line = last_line.unwrap();
|
debug_assert_eq!(penultimate.map(SourceLine::text).as_deref(), Some(" ];"));
|
||||||
|
let penultimate = penultimate.unwrap();
|
||||||
|
|
||||||
|
let new_generation = 0 - new_prio;
|
||||||
|
|
||||||
let new_line = SourceLine {
|
let new_line = SourceLine {
|
||||||
line: last_line.line,
|
line: penultimate.line,
|
||||||
path: source.path(),
|
path: source.path(),
|
||||||
text: Arc::from(format!(
|
text: Arc::from(format!(
|
||||||
" {option_name} = lib.mkOverride ({new_prio}) ({new_value});",
|
" {} = lib.mkOverride ({}) ({}); # DYNIX GENERATION {}",
|
||||||
|
option_name, new_prio, new_value, new_generation,
|
||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -165,12 +189,12 @@ pub fn write_next_prio(mut source: SourceFile, new_line: SourceLine) -> Result<(
|
||||||
let new_mod_start = SourceLine {
|
let new_mod_start = SourceLine {
|
||||||
line: new_line.line.prev(),
|
line: new_line.line.prev(),
|
||||||
path: source.path(),
|
path: source.path(),
|
||||||
text: Arc::from(" {"),
|
text: Arc::from(" {"),
|
||||||
};
|
};
|
||||||
let new_mod_end = SourceLine {
|
let new_mod_end = SourceLine {
|
||||||
line: new_line.line.next(),
|
line: new_line.line.next(),
|
||||||
path: source.path(),
|
path: source.path(),
|
||||||
text: Arc::from(" }"),
|
text: Arc::from(" }"),
|
||||||
};
|
};
|
||||||
|
|
||||||
source.insert_lines(&[new_mod_start, new_line, new_mod_end])?;
|
source.insert_lines(&[new_mod_start, new_line, new_mod_end])?;
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,17 @@
|
||||||
enable = true;
|
enable = true;
|
||||||
serviceConfig.Type = "oneshot";
|
serviceConfig.Type = "oneshot";
|
||||||
serviceConfig.RemainAfterExit = true;
|
serviceConfig.RemainAfterExit = true;
|
||||||
serviceConfig.RequisteOf = [ "multi-user.target" ];
|
|
||||||
path = [ config.system.path ];
|
path = [ config.system.path ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
requiredBy = [ "multi-user.target" ];
|
||||||
after = [ "default.target" ];
|
after = [ "default.target" ];
|
||||||
script = ''
|
script = ''
|
||||||
nix profile install -vv "${dynix.modules}" # "
|
if [[ -e /etc/nixos/hardware-configuration.nix ]]; then
|
||||||
|
echo "install-dynix: configuration already copied; nothing to do"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
nix profile install -vv "${dynix.drvPath}^*" # "
|
||||||
|
|
||||||
mkdir -vp /etc/nixos
|
mkdir -vp /etc/nixos
|
||||||
nixos-generate-config
|
nixos-generate-config
|
||||||
|
|
@ -58,6 +63,8 @@
|
||||||
|
|
||||||
passthru = { inherit options; };
|
passthru = { inherit options; };
|
||||||
|
|
||||||
|
environment.systemPackages = [ config.passthru.configurationDotNix ];
|
||||||
|
|
||||||
# Just making something in this strict in `name`,
|
# Just making something in this strict in `name`,
|
||||||
# which is only present as an argument for nodes and I don't want to
|
# which is only present as an argument for nodes and I don't want to
|
||||||
# confuse that with the test modules.
|
# confuse that with the test modules.
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import functools
|
||||||
#from pprint import pformat
|
#from pprint import pformat
|
||||||
import shlex
|
import shlex
|
||||||
import textwrap
|
import textwrap
|
||||||
from typing import cast, TYPE_CHECKING
|
from typing import Any, cast, TYPE_CHECKING
|
||||||
|
|
||||||
from beartype import beartype
|
from beartype import beartype
|
||||||
|
|
||||||
|
|
@ -68,6 +68,27 @@ def get_cli_args() -> argparse.Namespace:
|
||||||
args, rest = parser.parse_known_args(cmdline_args)
|
args, rest = parser.parse_known_args(cmdline_args)
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
@beartype
|
||||||
|
def dynix_append(option: str, value: Any):
|
||||||
|
machine.succeed(f'''
|
||||||
|
dynix append {shlex.quote(option)} {shlex.quote(str(value))}
|
||||||
|
'''.strip())
|
||||||
|
|
||||||
|
@beartype
|
||||||
|
def do_apply():
|
||||||
|
expr = textwrap.dedent("""
|
||||||
|
let
|
||||||
|
nixos = import <nixpkgs/nixos> { };
|
||||||
|
in nixos.config.dynamicism.applyDynamicConfiguration {
|
||||||
|
baseConfiguration = /etc/nixos/configuration.nix;
|
||||||
|
newConfiguration = /etc/nixos/dynamic.nix;
|
||||||
|
}
|
||||||
|
""").strip()
|
||||||
|
|
||||||
|
machine.succeed(rf"""
|
||||||
|
nix run --show-trace --log-format raw-with-logs --impure -E {shlex.quote(expr)}
|
||||||
|
""".strip())
|
||||||
|
|
||||||
machine.wait_for_unit("default.target")
|
machine.wait_for_unit("default.target")
|
||||||
assert "lix" in machine.succeed("nix --version").lower()
|
assert "lix" in machine.succeed("nix --version").lower()
|
||||||
machine.log("INIT")
|
machine.log("INIT")
|
||||||
|
|
@ -89,17 +110,8 @@ args = get_cli_args()
|
||||||
#assert int(args['max_connection_rate']) == 256, f"{args['max_connection_rate']=} != 256"
|
#assert int(args['max_connection_rate']) == 256, f"{args['max_connection_rate']=} != 256"
|
||||||
#
|
#
|
||||||
new_jobs = 4
|
new_jobs = 4
|
||||||
expr = textwrap.dedent(f"""
|
dynix_append("services.distccd.maxJobs", new_jobs)
|
||||||
let
|
do_apply()
|
||||||
nixos = import <nixpkgs/nixos> {{ }};
|
|
||||||
in nixos.config.dynamicism.doChange {{
|
|
||||||
option = "services.distccd.maxJobs";
|
|
||||||
value = {new_jobs};
|
|
||||||
}}
|
|
||||||
""").strip()
|
|
||||||
machine.succeed(rf"""
|
|
||||||
nix run --show-trace --log-format raw-with-logs --impure -E {shlex.quote(expr)}
|
|
||||||
""".strip())
|
|
||||||
|
|
||||||
args = get_cli_args()
|
args = get_cli_args()
|
||||||
|
|
||||||
|
|
@ -109,17 +121,8 @@ assert args.job_lifetime == 900, f'{args.job_lifetime} != 900'
|
||||||
assert args.log_level == 'warning', f'{args.log_level=} != warning'
|
assert args.log_level == 'warning', f'{args.log_level=} != warning'
|
||||||
|
|
||||||
new_log_level = 'error'
|
new_log_level = 'error'
|
||||||
expr = textwrap.dedent(f"""
|
dynix_append("services.distccd.logLevel", f'"{new_log_level}"')
|
||||||
let
|
do_apply()
|
||||||
nixos = import <nixpkgs/nixos> {{ }};
|
|
||||||
in nixos.config.dynamicism.doChange {{
|
|
||||||
option = "services.distccd.logLevel";
|
|
||||||
value = "{new_log_level}";
|
|
||||||
}}
|
|
||||||
""").strip()
|
|
||||||
machine.succeed(rf"""
|
|
||||||
nix run --show-trace --log-format raw-with-logs --impure -E {shlex.quote(expr)}
|
|
||||||
""".strip())
|
|
||||||
|
|
||||||
args = get_cli_args()
|
args = get_cli_args()
|
||||||
#assert args.jobs == new_jobs, f'{args.jobs=} != {new_jobs=}'
|
#assert args.jobs == new_jobs, f'{args.jobs=} != {new_jobs=}'
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
{ mkDynixConfigurationDotNix, config, ... }:
|
{ mkDynixConfigurationDotNix, config, ... }:
|
||||||
|
let
|
||||||
|
testName = config.name;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
name = "nixos-test-dynamicism-distccd";
|
name = "nixos-test-dynamicism-distccd";
|
||||||
|
|
||||||
|
|
@ -6,17 +9,13 @@
|
||||||
|
|
||||||
extraPythonPackages = p: [ p.beartype ];
|
extraPythonPackages = p: [ p.beartype ];
|
||||||
|
|
||||||
nodes.machine = { name, pkgs, ... }: {
|
nodes.machine = { ... }: {
|
||||||
imports = [ ./configuration.nix ];
|
imports = [ ./configuration.nix ];
|
||||||
|
|
||||||
environment.systemPackages = let
|
passthru.configurationDotNix = mkDynixConfigurationDotNix {
|
||||||
configFileTree = mkDynixConfigurationDotNix {
|
name = testName;
|
||||||
inherit (config) name;
|
configuration = ./configuration.nix;
|
||||||
configuration = ./configuration.nix;
|
};
|
||||||
};
|
|
||||||
in [
|
|
||||||
configFileTree
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = builtins.readFile ./test-script.py;
|
testScript = builtins.readFile ./test-script.py;
|
||||||
|
|
|
||||||
|
|
@ -46,37 +46,75 @@ def get_config_file() -> str:
|
||||||
|
|
||||||
config_file_path = machine.out_dir / config_file.name
|
config_file_path = machine.out_dir / config_file.name
|
||||||
with open(config_file_path, "r") as f:
|
with open(config_file_path, "r") as f:
|
||||||
return f.read()
|
data = f.read()
|
||||||
|
|
||||||
|
config_file_path.unlink()
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
@beartype
|
||||||
|
def dynix_append(option: str, value: str):
|
||||||
|
machine.succeed(f'''
|
||||||
|
dynix append {shlex.quote(option)} {shlex.quote(value)}
|
||||||
|
'''.strip())
|
||||||
|
|
||||||
|
@beartype
|
||||||
|
def do_apply():
|
||||||
|
expr = textwrap.dedent("""
|
||||||
|
let
|
||||||
|
nixos = import <nixpkgs/nixos> { };
|
||||||
|
in nixos.config.dynamicism.applyDynamicConfiguration {
|
||||||
|
baseConfiguration = /etc/nixos/configuration.nix;
|
||||||
|
newConfiguration = /etc/nixos/dynamic.nix;
|
||||||
|
}
|
||||||
|
""").strip()
|
||||||
|
|
||||||
|
machine.succeed(rf"""
|
||||||
|
nix run --show-trace --log-format raw-with-logs --impure -E {shlex.quote(expr)}
|
||||||
|
""".strip())
|
||||||
|
|
||||||
|
|
||||||
machine.wait_for_unit("default.target")
|
machine.wait_for_unit("default.target")
|
||||||
assert "lix" in machine.succeed("nix --version").lower()
|
assert "lix" in machine.succeed("nix --version").lower()
|
||||||
machine.log("INIT")
|
machine.wait_for_unit("install-dynix.service")
|
||||||
|
|
||||||
|
dynix_out = machine.succeed("dynix --version")
|
||||||
|
assert "dynix" in dynix_out, f"dynix not in {dynix_out=}"
|
||||||
|
|
||||||
|
machine.log("REBUILDING configuration inside VM")
|
||||||
|
machine.succeed("env PAGER= nixos-rebuild switch --log-format raw-with-logs --fallback")
|
||||||
|
machine.wait_for_unit("gotosocial.service")
|
||||||
|
|
||||||
|
# Make sure the config before any dynamic changes is what we expect.
|
||||||
|
config_text = get_config_file()
|
||||||
|
lines = config_text.splitlines()
|
||||||
|
try:
|
||||||
|
application_name = next(line for line in lines if line.startswith("application-name:"))
|
||||||
|
except StopIteration:
|
||||||
|
raise AssertionError(f"no 'application-name:' found in config file: {textwrap.indent(config_text, " ")}")
|
||||||
|
assert "gotosocial-for-machine" in application_name, f"'gotosocial-for-machine' should be in {application_name=}"
|
||||||
|
|
||||||
|
new_app_name = "yay!"
|
||||||
|
dynix_append("services.gotosocial.settings.application-name", f'"{new_app_name}"')
|
||||||
|
do_apply()
|
||||||
|
|
||||||
|
config_text = get_config_file()
|
||||||
|
lines = config_text.splitlines()
|
||||||
|
try:
|
||||||
|
application_name = next(line for line in lines if line.startswith("application-name:"))
|
||||||
|
except StopIteration:
|
||||||
|
raise AssertionError(f"no 'application-name:' found in config file: {textwrap.indent(config_text, " ")}")
|
||||||
|
assert new_app_name in application_name, f"'{new_app_name}' should be in {application_name=}"
|
||||||
|
|
||||||
machine.log("REBUILDING configuration inside VM")
|
machine.log("REBUILDING configuration inside VM")
|
||||||
machine.succeed("env PAGER= nixos-rebuild switch --log-format raw-with-logs --fallback")
|
machine.succeed("env PAGER= nixos-rebuild switch --log-format raw-with-logs --fallback")
|
||||||
|
|
||||||
|
machine.wait_for_unit("gotosocial.service")
|
||||||
|
|
||||||
config_text = get_config_file()
|
config_text = get_config_file()
|
||||||
lines = config_text.splitlines()
|
lines = config_text.splitlines()
|
||||||
application_name = next((line for line in lines if line.startswith("application-name:")), None)
|
try:
|
||||||
assert application_name is not None, f"no 'application-name:' found in config file: {textwrap.indent(config_text, "")}"
|
application_name = next(line for line in lines if line.startswith("application-name:"))
|
||||||
|
except StopIteration:
|
||||||
|
raise AssertionError(f"no 'application-name:' found in config file: {textwrap.indent(config_text, " ")}")
|
||||||
assert "gotosocial-for-machine" in application_name, f"'gotosocial-for-machine' should be in {application_name=}"
|
assert "gotosocial-for-machine" in application_name, f"'gotosocial-for-machine' should be in {application_name=}"
|
||||||
|
|
||||||
new_app_name = "yay!"
|
|
||||||
expr = textwrap.dedent(f"""
|
|
||||||
let
|
|
||||||
nixos = import <nixpkgs/nixos> {{ }};
|
|
||||||
in nixos.config.dynamicism.doChange {{
|
|
||||||
option = "services.gotosocial.settings.application-name";
|
|
||||||
value = "{new_app_name}";
|
|
||||||
}}
|
|
||||||
""").strip()
|
|
||||||
machine.succeed(rf"""
|
|
||||||
nix run --show-trace --log-format raw-with-logs --impure -E {shlex.quote(expr)}
|
|
||||||
""".strip())
|
|
||||||
|
|
||||||
config_file_new = get_config_file()
|
|
||||||
lines = config_file_new.splitlines()
|
|
||||||
|
|
||||||
application_name = next(line for line in lines if line.startswith("application-name:"))
|
|
||||||
assert new_app_name in application_name, f"'{new_app_name}' should be in {application_name=}"
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
{ mkDynixConfigurationDotNix, config, ... }:
|
{ mkDynixConfigurationDotNix, config, ... }:
|
||||||
|
let
|
||||||
|
testName = config.name;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
name = "nixos-test-dynamicism-gotosocial";
|
name = "nixos-test-dynamicism-gotosocial";
|
||||||
|
|
||||||
|
|
@ -9,21 +11,17 @@
|
||||||
p.beartype
|
p.beartype
|
||||||
];
|
];
|
||||||
|
|
||||||
nodes.machine = { pkgs, ... }: {
|
nodes.machine = { ... }: {
|
||||||
# NOTE: Anything in this `nodes.machine = ` module will not be included
|
# NOTE: Anything in this `nodes.machine = ` module will not be included
|
||||||
# in the VM's NixOS configuration once it does `nixos-rebuild switch`,
|
# in the VM's NixOS configuration once it does `nixos-rebuild switch`,
|
||||||
# except for `./configuration.nix` which will be copied to `/etc/nixos/`.
|
# except for `./configuration.nix` which will be copied to `/etc/nixos/`.
|
||||||
# dynix will also be statefully installed to root's user profile.
|
# dynix will also be statefully installed to root's user profile.
|
||||||
imports = [ ./configuration.nix ];
|
imports = [ ./configuration.nix ];
|
||||||
|
|
||||||
environment.systemPackages = let
|
passthru.configurationDotNix = mkDynixConfigurationDotNix {
|
||||||
configFileTree = mkDynixConfigurationDotNix {
|
name = testName;
|
||||||
inherit (config) name;
|
configuration = ./configuration.nix;
|
||||||
configuration = ./configuration.nix;
|
};
|
||||||
};
|
|
||||||
in [
|
|
||||||
configFileTree
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = builtins.readFile ./test-script.py;
|
testScript = builtins.readFile ./test-script.py;
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,27 @@ def get_config_file() -> dict[str, Any]:
|
||||||
config_file_path.unlink()
|
config_file_path.unlink()
|
||||||
return config_data
|
return config_data
|
||||||
|
|
||||||
|
@beartype
|
||||||
|
def dynix_append(option: str, value: Any):
|
||||||
|
machine.succeed(f'''
|
||||||
|
dynix append {shlex.quote(option)} {shlex.quote(str(value))}
|
||||||
|
'''.strip())
|
||||||
|
|
||||||
|
@beartype
|
||||||
|
def do_apply():
|
||||||
|
expr = textwrap.dedent("""
|
||||||
|
let
|
||||||
|
nixos = import <nixpkgs/nixos> { };
|
||||||
|
in nixos.config.dynamicism.applyDynamicConfiguration {
|
||||||
|
baseConfiguration = /etc/nixos/configuration.nix;
|
||||||
|
newConfiguration = /etc/nixos/dynamic.nix;
|
||||||
|
}
|
||||||
|
""").strip()
|
||||||
|
|
||||||
|
machine.succeed(rf"""
|
||||||
|
nix run --show-trace --log-format raw-with-logs --impure -E {shlex.quote(expr)}
|
||||||
|
""".strip())
|
||||||
|
|
||||||
machine.wait_for_unit("default.target")
|
machine.wait_for_unit("default.target")
|
||||||
assert "lix" in machine.succeed("nix --version").lower()
|
assert "lix" in machine.succeed("nix --version").lower()
|
||||||
machine.log("INIT")
|
machine.log("INIT")
|
||||||
|
|
@ -75,17 +96,8 @@ assert int(config_toml['workers']) == 4, f"{config_toml['workers']=} != 4"
|
||||||
assert int(config_toml['max_connection_rate']) == 256, f"{config_toml['max_connection_rate']=} != 256"
|
assert int(config_toml['max_connection_rate']) == 256, f"{config_toml['max_connection_rate']=} != 256"
|
||||||
|
|
||||||
new_workers = 20
|
new_workers = 20
|
||||||
expr = textwrap.dedent(f"""
|
dynix_append("services.harmonia.settings.workers", new_workers)
|
||||||
let
|
do_apply()
|
||||||
nixos = import <nixpkgs/nixos> {{ }};
|
|
||||||
in nixos.config.dynamicism.doChange {{
|
|
||||||
option = "services.harmonia.settings.workers";
|
|
||||||
value = {new_workers};
|
|
||||||
}}
|
|
||||||
""").strip()
|
|
||||||
machine.succeed(rf"""
|
|
||||||
nix run --show-trace --log-format raw-with-logs --impure -E {shlex.quote(expr)}
|
|
||||||
""".strip())
|
|
||||||
|
|
||||||
# Workers, but not max connection rate, should have changed.
|
# Workers, but not max connection rate, should have changed.
|
||||||
config_toml = get_config_file()
|
config_toml = get_config_file()
|
||||||
|
|
@ -94,17 +106,8 @@ assert int(config_toml['workers']) == new_workers, f"{config_toml['workers']=} !
|
||||||
assert int(config_toml['max_connection_rate']) == 256, f"{config_toml['max_connection_rate']=} != 256"
|
assert int(config_toml['max_connection_rate']) == 256, f"{config_toml['max_connection_rate']=} != 256"
|
||||||
|
|
||||||
new_max_connection_rate = 100
|
new_max_connection_rate = 100
|
||||||
expr = textwrap.dedent(f"""
|
dynix_append("services.harmonia.settings.max_connection_rate", new_max_connection_rate)
|
||||||
let
|
do_apply()
|
||||||
nixos = import <nixpkgs/nixos> {{ }};
|
|
||||||
in nixos.config.dynamicism.doChange {{
|
|
||||||
option = [ "services" "harmonia" "settings" "max_connection_rate" ];
|
|
||||||
value = {new_max_connection_rate};
|
|
||||||
}}
|
|
||||||
""").strip()
|
|
||||||
machine.succeed(rf"""
|
|
||||||
nix run --show-trace --log-format raw-with-logs --impure -E {shlex.quote(expr)}
|
|
||||||
""".strip())
|
|
||||||
|
|
||||||
# Max connection rate should have changed, but workers should have reverted.
|
# Max connection rate should have changed, but workers should have reverted.
|
||||||
config_toml = get_config_file()
|
config_toml = get_config_file()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
{ mkDynixConfigurationDotNix, config, ... }:
|
{ mkDynixConfigurationDotNix, config, ... }:
|
||||||
|
let
|
||||||
|
testName = config.name;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
name = "nixos-test-dynamicism-harmonia";
|
name = "nixos-test-dynamicism-harmonia";
|
||||||
|
|
||||||
|
|
@ -6,21 +9,13 @@
|
||||||
|
|
||||||
extraPythonPackages = p: [ p.beartype ];
|
extraPythonPackages = p: [ p.beartype ];
|
||||||
|
|
||||||
nodes.machine = { name, pkgs, ... }: {
|
nodes.machine = { ... }: {
|
||||||
imports = [ ./configuration.nix ];
|
imports = [ ./configuration.nix ];
|
||||||
|
|
||||||
environment.systemPackages = let
|
passthru.configurationDotNix = mkDynixConfigurationDotNix {
|
||||||
#configFileTree = pkgs.runCommand "${name}-configuration-dot-nix" { } ''
|
name = testName;
|
||||||
# set -euo pipefail
|
configuration = ./configuration.nix;
|
||||||
# install -Dm a=r ${./configuration.nix} "$out/share/nixos/configuration.nix"
|
};
|
||||||
#'';
|
|
||||||
configFileTree = mkDynixConfigurationDotNix {
|
|
||||||
inherit (config) name;
|
|
||||||
configuration = ./configuration.nix;
|
|
||||||
};
|
|
||||||
in [
|
|
||||||
configFileTree
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
testScript = builtins.readFile ./test-script.py;
|
testScript = builtins.readFile ./test-script.py;
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,15 @@
|
||||||
echo " ];" >> "$modulesOut/configuration.nix"
|
echo " ];" >> "$modulesOut/configuration.nix"
|
||||||
echo "}" >> "$modulesOut/configuration.nix"
|
echo "}" >> "$modulesOut/configuration.nix"
|
||||||
|
|
||||||
|
echo "/** GENERATED BY mk-test-configuration-dot-nix! */" >> "$modulesOut/dynamic.nix"
|
||||||
|
echo "{ lib, ... }:" >> "$modulesOut/dynamic.nix"
|
||||||
|
echo >> "$modulesOut/dynamic.nix"
|
||||||
|
echo >> "$modulesOut/dynamic.nix"
|
||||||
|
echo "{" >> "$modulesOut/dynamic.nix"
|
||||||
|
echo " imports = [ ./configuration.nix ];" >> "$modulesOut/dynamic.nix"
|
||||||
|
echo " config = lib.mkMerge [" >> "$modulesOut/dynamic.nix"
|
||||||
|
echo " ];" >> "$modulesOut/dynamic.nix"
|
||||||
|
echo "}" >> "$modulesOut/dynamic.nix"
|
||||||
runHook postInstall
|
runHook postInstall
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@
|
||||||
installBootLoader = true;
|
installBootLoader = true;
|
||||||
|
|
||||||
# With how much memory Nix eval uses, this is essentially required.
|
# With how much memory Nix eval uses, this is essentially required.
|
||||||
memorySize = 4096;
|
memorySize = 8192;
|
||||||
cores = 4;
|
cores = 8;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue