Compare commits

..

1 Commits

Author SHA1 Message Date
d449fc8dcf dkl apply-config --dry-run 2026-02-21 18:15:39 +01:00
5 changed files with 56 additions and 13 deletions

View File

@ -5,25 +5,59 @@ use tokio::fs;
use crate::base64_decode; use crate::base64_decode;
pub async fn files(files: &[crate::File], root: &str) -> Result<()> { pub async fn files(files: &[crate::File], root: &str, dry_run: bool) -> Result<()> {
for file in files { for file in files {
let path = chroot(root, &file.path); let path = chroot(root, &file.path);
let path = Path::new(&path); let path = Path::new(&path);
if let Some(parent) = path.parent() { if !dry_run && let Some(parent) = path.parent() {
fs::create_dir_all(parent).await?; fs::create_dir_all(parent).await?;
} }
use crate::FileKind as K; use crate::FileKind as K;
match &file.kind { match &file.kind {
K::Content(content) => fs::write(path, content.as_bytes()).await?, K::Content(content) => {
if dry_run {
info!(
"would create {} ({} bytes from content)",
file.path,
content.len()
);
} else {
fs::write(path, content.as_bytes()).await?;
}
}
K::Content64(content) => { K::Content64(content) => {
let content = base64_decode(content)?; let content = base64_decode(content)?;
if dry_run {
info!(
"would create {} ({} bytes from content64)",
file.path,
content.len()
);
} else {
fs::write(path, content).await? fs::write(path, content).await?
} }
K::Dir(true) => fs::create_dir(path).await?, }
K::Dir(true) => {
if dry_run {
info!("would create {} (directory)", file.path);
} else {
fs::create_dir(path).await?;
}
}
K::Dir(false) => {} // shouldn't happen, but semantic is to ignore K::Dir(false) => {} // shouldn't happen, but semantic is to ignore
K::Symlink(tgt) => fs::symlink(tgt, path).await?, K::Symlink(tgt) => {
if dry_run {
info!("would create {} (symlink to {})", file.path, tgt);
} else {
fs::symlink(tgt, path).await?;
}
}
}
if dry_run {
continue;
} }
match file.kind { match file.kind {

View File

@ -24,6 +24,9 @@ enum Command {
/// path prefix (aka chroot) /// path prefix (aka chroot)
#[arg(short = 'P', long, default_value = "/")] #[arg(short = 'P', long, default_value = "/")]
prefix: String, prefix: String,
/// don't really write files
#[arg(long)]
dry_run: bool,
}, },
Logger { Logger {
/// Path where the logs are stored /// Path where the logs are stored
@ -97,9 +100,10 @@ async fn main() -> Result<()> {
config, config,
filters, filters,
prefix, prefix,
dry_run,
} => { } => {
let filters = parse_globs(&filters)?; let filters = parse_globs(&filters)?;
apply_config(&config, &filters, &prefix).await apply_config(&config, &filters, &prefix, dry_run).await
} }
C::Logger { C::Logger {
ref log_path, ref log_path,
@ -156,7 +160,12 @@ async fn main() -> Result<()> {
} }
} }
async fn apply_config(config_file: &str, filters: &[glob::Pattern], chroot: &str) -> Result<()> { async fn apply_config(
config_file: &str,
filters: &[glob::Pattern],
chroot: &str,
dry_run: bool,
) -> Result<()> {
let config = fs::read_to_string(config_file).await?; let config = fs::read_to_string(config_file).await?;
let config: dkl::Config = serde_yaml::from_str(&config)?; let config: dkl::Config = serde_yaml::from_str(&config)?;
@ -168,7 +177,7 @@ async fn apply_config(config_file: &str, filters: &[glob::Pattern], chroot: &str
.collect() .collect()
}; };
dkl::apply::files(&files, chroot).await dkl::apply::files(&files, chroot, dry_run).await
} }
#[derive(Subcommand)] #[derive(Subcommand)]

View File

@ -1,4 +1,4 @@
use eyre::{format_err, Result}; use eyre::{Result, format_err};
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use std::path::PathBuf; use std::path::PathBuf;
use tokio::{fs, io::AsyncWriteExt, process::Command}; use tokio::{fs, io::AsyncWriteExt, process::Command};

View File

@ -83,6 +83,6 @@ impl Config {
} }
pub fn base64_decode(s: &str) -> Result<Vec<u8>, base64::DecodeError> { pub fn base64_decode(s: &str) -> Result<Vec<u8>, base64::DecodeError> {
use base64::{prelude::BASE64_STANDARD_NO_PAD as B64, Engine}; use base64::{Engine, prelude::BASE64_STANDARD_NO_PAD as B64};
B64.decode(s.trim_end_matches('=')) B64.decode(s.trim_end_matches('='))
} }

View File

@ -1,6 +1,6 @@
use async_compression::tokio::write::{ZstdDecoder, ZstdEncoder}; use async_compression::tokio::write::{ZstdDecoder, ZstdEncoder};
use chrono::{DurationRound, TimeDelta, Utc}; use chrono::{DurationRound, TimeDelta, Utc};
use eyre::{format_err, Result}; use eyre::{Result, format_err};
use log::{debug, error, warn}; use log::{debug, error, warn};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Stdio; use std::process::Stdio;
@ -9,7 +9,7 @@ use tokio::{
io::{self, AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter}, io::{self, AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, BufWriter},
process, process,
sync::mpsc, sync::mpsc,
time::{sleep, Duration}, time::{Duration, sleep},
}; };
pub type Timestamp = chrono::DateTime<Utc>; pub type Timestamp = chrono::DateTime<Utc>;