From b0fc0debc99964f7741f6d61c9ed3de7e28353ca Mon Sep 17 00:00:00 2001 From: Qyriad Date: Wed, 1 Apr 2026 14:51:15 +0200 Subject: [PATCH] add init command --- Cargo.lock | 16 ++++++++++++ Cargo.toml | 1 + src/args.rs | 9 +++++++ src/lib.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/main.rs | 1 + 5 files changed, 92 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f87015c..3617d71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -339,6 +339,7 @@ dependencies = [ "fs-err", "humantime", "iddqd", + "indoc", "itertools", "libc", "mio", @@ -685,6 +686,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + [[package]] name = "is-terminal" version = "0.4.17" @@ -1045,6 +1055,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "ryu" version = "1.0.23" diff --git a/Cargo.toml b/Cargo.toml index 08e1974..cbc0c6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ displaydoc = "0.2.5" fs-err = "3.2.2" humantime = "2.3.0" iddqd = "0.3.17" +indoc = "2.0.7" itertools = "0.14.0" libc = { version = "0.2.180", features = ["extra_traits"] } #macro_rules_attribute = { version = "0.2.2", features = ["better-docs", "verbose-expansions"] } diff --git a/src/args.rs b/src/args.rs index 985c646..fb77cba 100644 --- a/src/args.rs +++ b/src/args.rs @@ -32,9 +32,18 @@ pub struct DaemonCmd { pub bind: SocketAddr, } +#[derive(Debug, Clone, PartialEq, clap::Parser)] +#[command(long_about = None)] +pub struct InitCmd { + /// Overwrite existing files. + #[arg(long)] + pub force: bool, +} + #[derive(Debug, Clone, PartialEq, clap::Subcommand)] pub enum Subcommand { Append(AppendCmd), + Init(InitCmd), Daemon(DaemonCmd), OpenApiDocs, } diff --git a/src/lib.rs b/src/lib.rs index dfb175d..c365f0f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ pub mod prelude { use prelude::*; pub mod args; -pub use args::{AppendCmd, Args}; +pub use args::{AppendCmd, Args, InitCmd}; mod boxext; mod color; pub use color::{_CLI_ENABLE_COLOR, SHOULD_COLOR}; @@ -107,11 +107,6 @@ pub(crate) fn open_source_file(path: Arc) -> Result { .tap_err(|e| error!("couldn't open source file at {}: {e}", path.display())) } -pub(crate) fn get_line_to_insert() -> SourceLine { - // - todo!(); -} - #[tracing::instrument(level = "debug")] pub fn do_append(args: Arc, append_args: AppendCmd) -> Result<(), BoxDynError> { let filepath = &args.file; @@ -165,6 +160,70 @@ pub fn do_daemon(args: Arc, daemon_args: DaemonCmd) -> Result<(), BoxDynEr Ok(()) } +const DYNAMIC_NIX_INIT: &str = indoc::indoc! {" + /** GENERATED BY DYNIX */ + { lib, ... }: + + { + imports = [ + ./configuration.nix + ]; + config = lib.mkMerge [ + ]; + } +"}; + +fn open_for_init(path: &Path, init_args: &InitCmd) -> Result { + let mut opts = File::options(); + opts.write(true).create_new(true); + let file = match opts.open(path) { + Ok(file) => file, + Err(e) if e.kind() == IoErrorKind::AlreadyExists => { + if !init_args.force { + error!( + "Refusing to overwrite existing file at '{}' without --force", + path.display(), + ); + return Err(e); + } + info!("Overwriting existing file at '{}'", path.display()); + File::options() + .write(true) + .create(true) + .open(path) + .inspect_err(|e| { + error!( + "Failed to open path at '{}' for overwriting: {e}", + path.display(), + ) + })? + }, + Err(e) => { + error!( + "Failed to open path at '{}' for creation: {e}", + path.display() + ); + return Err(e); + }, + }; + + Ok(file) +} + +pub fn do_init(args: Arc, init_args: InitCmd) -> Result<(), BoxDynError> { + let path = &*args.file; + let mut file = open_for_init(path, &init_args)?; + + write!(&mut file, "{}", DYNAMIC_NIX_INIT) + .inspect_err(|e| error!("Failed to write to file at '{}': {e}", path.display()))?; + file.flush() + .inspect_err(|e| warn!("Failed to flush file at '{}': {e}", path.display()))?; + + info!("Initialized Dynix file at '{}'", path.display()); + + Ok(()) +} + #[derive(Debug, Clone, PartialEq, Hash, Serialize, Deserialize)] pub struct DefinitionWithLocation { pub file: Box, diff --git a/src/main.rs b/src/main.rs index c4d0e58..46ac99b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,7 @@ fn main_wrapped() -> Result<(), Box> { match &args.subcommand { Append(append_args) => dynix::do_append(args.clone(), append_args.clone())?, Daemon(daemon_args) => dynix::do_daemon(args.clone(), daemon_args.clone())?, + Init(init_args) => dynix::do_init(args.clone(), init_args.clone())?, OpenApiDocs => { //let api = dynix::ApiDoc::openapi(); //dbg!(api);