factor out do_append in prep for delta subcommands
This commit is contained in:
parent
8477c73067
commit
9ae0630db4
8 changed files with 237 additions and 56 deletions
36
configuration.nix
Normal file
36
configuration.nix
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{ pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./dynamic.nix
|
||||
./dynamic-options.nix
|
||||
"${modulesPath}/profiles/qemu-guest.nix"
|
||||
];
|
||||
|
||||
dynamicism.for.gotosocial.enable = true;
|
||||
|
||||
# Just an example system.
|
||||
users.mutableUsers = false;
|
||||
users.users.root = {
|
||||
password = "root";
|
||||
};
|
||||
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PermitRootLogin = "yes";
|
||||
};
|
||||
};
|
||||
|
||||
environment.shellAliases = {
|
||||
ls = "eza --long --header --group --group-directories-first --classify --binary";
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
eza
|
||||
fd
|
||||
ripgrep
|
||||
];
|
||||
|
||||
system.stateVersion = "25.11";
|
||||
}
|
||||
12
default.nix
12
default.nix
|
|
@ -15,6 +15,14 @@
|
|||
});
|
||||
in dynix') qpkgs.validStdenvs;
|
||||
|
||||
in dynix.overrideAttrs (prev: lib.recursiveUpdate prev {
|
||||
passthru = { inherit byStdenv; };
|
||||
in dynix.overrideAttrs (final: prev: let
|
||||
self = final.finalPackage;
|
||||
in lib.recursiveUpdate prev {
|
||||
passthru = {
|
||||
inherit byStdenv;
|
||||
nixos = import (pkgs.path + "/nixos") {
|
||||
configuration = ./configuration.nix;
|
||||
};
|
||||
nixos-vm = self.nixos.config.system.build.vm;
|
||||
};
|
||||
})
|
||||
|
|
|
|||
61
dynamic-options.nix
Normal file
61
dynamic-options.nix
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{ pkgs, lib, config, ... }:
|
||||
let
|
||||
inherit (lib.modules)
|
||||
mkIf
|
||||
;
|
||||
inherit (lib.options)
|
||||
mkOption
|
||||
mkEnableOption
|
||||
literalExpression
|
||||
showOption
|
||||
;
|
||||
t = lib.types;
|
||||
cfg = config.dynamicism;
|
||||
|
||||
settingsFormat = pkgs.formats.yaml { };
|
||||
|
||||
assertionFor = submodName: unitName: let
|
||||
optName = [ "dynamicism" "for" submodName "systemd-services-updated" ];
|
||||
in {
|
||||
assertion = config.systemd.units.${unitName}.enable or false;
|
||||
message = "'${showOption optName}' specified non-existentant unit '${unitName}'";
|
||||
};
|
||||
|
||||
assertionsFor =
|
||||
submodName:
|
||||
submod:
|
||||
lib.map (assertionFor submodName) submod.systemd-services-updated;
|
||||
in
|
||||
{
|
||||
options.dynamicism.for = mkOption {
|
||||
type = t.attrsOf (t.submoduleWith {
|
||||
modules = [ ./dynamic-submodule.nix ];
|
||||
shorthandOnlyDefinesConfig = false;
|
||||
});
|
||||
default = { };
|
||||
};
|
||||
|
||||
options.dynamicism.finalSettings = mkOption {
|
||||
type = t.attrsOf t.raw;
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
};
|
||||
|
||||
config.assertions = lib.foldlAttrs (acc: name: submod: let
|
||||
next = lib.optionals submod.enable (assertionsFor name submod);
|
||||
in acc ++ next) [ ] cfg.for;
|
||||
|
||||
config.dynamicism.for = {
|
||||
gotosocial = {
|
||||
source-parameters = [ "services" "gotosocial" "settings" ];
|
||||
systemd-services-updated = [ "gotosocial.service" ];
|
||||
};
|
||||
};
|
||||
|
||||
# FIXME: this should be a fold.
|
||||
config.dynamicism.finalSettings = lib.mapAttrs (name: submod: let
|
||||
#optValue = lib.getAttrFromPath submod.
|
||||
# FIXME: this should be a fold.
|
||||
optValue = lib.getAttrFromPath submod.source-parameters config;
|
||||
in optValue) cfg.for;
|
||||
}
|
||||
45
dynamic-submodule.nix
Normal file
45
dynamic-submodule.nix
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
name,
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib.modules)
|
||||
mkIf
|
||||
;
|
||||
inherit (lib.options)
|
||||
mkOption
|
||||
mkEnableOption
|
||||
literalExpression
|
||||
;
|
||||
t = lib.types;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
enable = mkEnableOption "Dynamicism for ${name}";
|
||||
|
||||
source-parameters = mkOption {
|
||||
type = t.listOf t.str;
|
||||
description = "An attrpath of the NixOS option this dynamicism uses";
|
||||
example = literalExpression ''
|
||||
[ "services" "gotosocial" "settings" ]
|
||||
'';
|
||||
};
|
||||
|
||||
systemd-services-updated = mkOption {
|
||||
type = t.listOf t.str;
|
||||
description = ''
|
||||
A list of systemd unit names (including the suffix, e.g. `.service`) that need to be updated.
|
||||
'';
|
||||
example = literalExpression ''
|
||||
"gotosocial.service"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.enable {
|
||||
|
||||
};
|
||||
}
|
||||
15
dynamic.nix
Normal file
15
dynamic.nix
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Managed by dynix.
|
||||
{ lib, ... }:
|
||||
|
||||
lib.mkMerge [
|
||||
{
|
||||
services.gotosocial = {
|
||||
enable = true;
|
||||
setupPostgresqlDB = true;
|
||||
settings = {
|
||||
application-name = "example!";
|
||||
host = "yuki.local";
|
||||
};
|
||||
};
|
||||
}
|
||||
]
|
||||
28
src/args.rs
28
src/args.rs
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use clap::ColorChoice;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
|
@ -46,19 +48,32 @@ impl FromStr for NixOsOption {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, clap::Parser)]
|
||||
pub struct AppendCmd {
|
||||
#[arg(required = true)]
|
||||
pub name: Arc<str>,
|
||||
#[arg(required = true)]
|
||||
pub value: Arc<str>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, clap::Subcommand)]
|
||||
pub enum Subcommand {
|
||||
Append(AppendCmd),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, clap::Parser)]
|
||||
#[command(version, about, author, arg_required_else_help(true))]
|
||||
pub struct Parser {
|
||||
#[command(propagate_version = true)]
|
||||
pub struct Args {
|
||||
#[arg(long, default_value = "auto")]
|
||||
pub color: ColorChoice,
|
||||
|
||||
#[arg(long)]
|
||||
pub file: Box<OsStr>,
|
||||
pub file: Arc<OsStr>,
|
||||
|
||||
#[arg(required = true)]
|
||||
pub name: Box<str>,
|
||||
#[arg(required = true)]
|
||||
pub value: Box<str>,
|
||||
#[command(subcommand)]
|
||||
pub subcommand: Subcommand,
|
||||
}
|
||||
///// Flakeref to a base configuration to modify.
|
||||
//#[arg(group = "config", long, default_value("."))]
|
||||
//#[arg(long, default_value(Some(".")))]
|
||||
|
|
@ -66,7 +81,6 @@ pub struct Parser {
|
|||
//
|
||||
//#[arg(group = "config", long)]
|
||||
//expr: Option<String>,
|
||||
}
|
||||
|
||||
//impl Parser {
|
||||
// fn eval_cmd(&self) {
|
||||
|
|
|
|||
41
src/lib.rs
41
src/lib.rs
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::Arc;
|
||||
use std::{iter, sync::Arc};
|
||||
|
||||
pub(crate) mod prelude {
|
||||
#![allow(unused_imports)]
|
||||
|
|
@ -32,7 +32,7 @@ pub(crate) mod prelude {
|
|||
use prelude::*;
|
||||
|
||||
pub mod args;
|
||||
pub use args::Parser;
|
||||
pub use args::{AppendCmd, Args};
|
||||
mod color;
|
||||
pub use color::{CLI_ENABLE_COLOR, SHOULD_COLOR};
|
||||
pub mod line;
|
||||
|
|
@ -47,6 +47,43 @@ use crate::source::SourceFile;
|
|||
|
||||
pub const ASCII_WHITESPACE: &[char] = &['\t', '\n', '\x0C', '\r', ' '];
|
||||
|
||||
pub fn do_append(args: Arc<Args>, append_args: AppendCmd) -> Result<(), BoxDynError> {
|
||||
let filepath = Path::new(&args.file);
|
||||
let filepath: PathBuf = if filepath.is_relative() && !filepath.starts_with("./") {
|
||||
iter::once(OsStr::new("./"))
|
||||
.chain(filepath.iter())
|
||||
.collect()
|
||||
} else {
|
||||
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();
|
||||
opts.read(true)
|
||||
.write(true)
|
||||
.create(false)
|
||||
.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 new_pri = pri - 1;
|
||||
|
||||
let new_pri_line = get_next_prio_line(
|
||||
source_file.clone(),
|
||||
append_args.name.into(),
|
||||
new_pri,
|
||||
append_args.value.into(),
|
||||
)?;
|
||||
|
||||
eprintln!("new_pri_line={new_pri_line}");
|
||||
|
||||
write_next_prio(source_file, new_pri_line)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Hash, Serialize, Deserialize)]
|
||||
pub struct DefinitionWithLocation {
|
||||
pub file: Box<Path>,
|
||||
|
|
|
|||
43
src/main.rs
43
src/main.rs
|
|
@ -1,17 +1,11 @@
|
|||
use std::ffi::OsStr;
|
||||
use std::io::{self, IsTerminal};
|
||||
use std::iter;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::ExitCode;
|
||||
use std::{error::Error as StdError, sync::Arc};
|
||||
|
||||
use dynix::source::SourceFile;
|
||||
use clap::{ColorChoice, Parser as _};
|
||||
use fs_err::File;
|
||||
use fs_err::os::unix::fs::OpenOptionsExt;
|
||||
|
||||
fn main_wrapped() -> Result<(), Box<dyn StdError + Send + Sync + 'static>> {
|
||||
let args = dynix::Parser::parse();
|
||||
let args = Arc::new(dynix::Args::parse());
|
||||
|
||||
dbg!(&args);
|
||||
|
||||
|
|
@ -24,40 +18,11 @@ fn main_wrapped() -> Result<(), Box<dyn StdError + Send + Sync + 'static>> {
|
|||
success.expect("logic error in CLI_ENABLE_COLOR");
|
||||
}
|
||||
|
||||
let filepath = Path::new(&args.file);
|
||||
let filepath: PathBuf = if filepath.is_relative() && !filepath.starts_with("./") {
|
||||
iter::once(OsStr::new("./"))
|
||||
.chain(filepath.iter())
|
||||
.collect()
|
||||
} else {
|
||||
filepath.to_path_buf()
|
||||
use dynix::args::Subcommand::*;
|
||||
match &args.subcommand {
|
||||
Append(append_args) => dynix::do_append(args.clone(), append_args.clone())?,
|
||||
};
|
||||
|
||||
// Get what file that thing is defined in.
|
||||
let def_path = dynix::get_where(&args.name, &filepath)?;
|
||||
dbg!(&def_path);
|
||||
let def_path = Arc::from(def_path);
|
||||
let mut opts = File::options();
|
||||
opts.read(true)
|
||||
.write(true)
|
||||
.create(false)
|
||||
.custom_flags(libc::O_CLOEXEC);
|
||||
let source_file = SourceFile::open_from(Arc::clone(&def_path), opts)?;
|
||||
|
||||
let pri = dynix::get_highest_prio(&args.name, source_file.clone())?;
|
||||
let new_pri = pri - 1;
|
||||
|
||||
let new_pri_line = dynix::get_next_prio_line(
|
||||
source_file.clone(),
|
||||
args.name.into(),
|
||||
new_pri,
|
||||
args.value.into(),
|
||||
)?;
|
||||
|
||||
eprintln!("new_pri_line={new_pri_line}");
|
||||
|
||||
dynix::write_next_prio(source_file, new_pri_line)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue