Skip to content

Commit

Permalink
refactor: Split main
Browse files Browse the repository at this point in the history
  • Loading branch information
VorpalBlade committed Jul 31, 2024
1 parent 9d0998a commit be4a092
Showing 1 changed file with 195 additions and 123 deletions.
318 changes: 195 additions & 123 deletions crates/konfigkoll/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use std::sync::Arc;

use ahash::AHashSet;
use anyhow::Context;
use camino::Utf8Path;
use camino::Utf8PathBuf;
use clap::Parser;
use compact_str::CompactString;
use itertools::Itertools;

use crate::fs_scan::ScanResult;
use apply::create_applicator;
use konfigkoll::cli::Cli;
use konfigkoll::cli::Commands;
Expand All @@ -17,7 +19,12 @@ use konfigkoll_core::apply::apply_files;
use konfigkoll_core::apply::apply_packages;
use konfigkoll_core::diff::show_fs_instr_diff;
use konfigkoll_core::state::DiffGoal;
use konfigkoll_core::state::FsEntries;
use konfigkoll_script::Phase;
use konfigkoll_script::ScriptEngine;
use konfigkoll_types::FsInstruction;
use konfigkoll_types::PkgIdent;
use konfigkoll_types::PkgInstruction;
#[cfg(target_env = "musl")]
use mimalloc::MiMalloc;
use paketkoll_cache::FromArchiveCache;
Expand All @@ -26,6 +33,7 @@ use paketkoll_core::backend::ConcreteBackend;
use paketkoll_core::paketkoll_types::intern::Interner;
use paketkoll_types::backend::Files;
use paketkoll_types::backend::PackageBackendMap;
use paketkoll_types::backend::PackageMapMap;
use paketkoll_types::backend::Packages;

mod apply;
Expand Down Expand Up @@ -237,9 +245,8 @@ async fn main() -> anyhow::Result<()> {
Commands::Save { filter } => {
tracing::debug!("Computing changes to save");
// Split out additions and removals
let mut fs_additions =
konfigkoll_core::state::diff(&DiffGoal::Save, script_fs, sys_fs)?.collect_vec();
fs_additions.sort();
let fs_additions = fs_state_diff_save(script_fs, sys_fs)?;

let mut pkg_additions = vec![];
let mut pkg_removals = vec![];
pkg_diff.for_each(|v| match v {
Expand All @@ -252,86 +259,20 @@ async fn main() -> anyhow::Result<()> {
}
});

if !fs_additions.is_empty() || !pkg_additions.is_empty() || !pkg_removals.is_empty() {
tracing::warn!("There are differences (saving to unsorted.rn)");
} else {
tracing::info!("No differences to save, you are up to date!");
}

// Open output file (for appending) in config dir
let output_path = config_path.join("unsorted.rn");
let mut output = BufWriter::new(
std::fs::OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(&output_path)
.with_context(|| format!("Failed to open output file {}", output_path))?,
);
output.write_all("// This file is generated by konfigkoll\n".as_bytes())?;
output.write_all(
"// You will need to merge the changes you want into your own actual config\n"
.as_bytes(),
)?;
output.write_all("pub fn unsorted_additions(props, cmds) {\n".as_bytes())?;
let prefix = script_engine.state().settings().save_prefix();
konfigkoll_core::save::save_packages(&prefix, &mut output, pkg_additions.into_iter())?;
let files_path = config_path.join("files");
let sensitive_configs: AHashSet<Utf8PathBuf> = script_engine
.state()
.settings()
.sensitive_configs()
.collect();
konfigkoll_core::save::save_fs_changes(
&prefix,
&mut output,
|path, contents| {
if sensitive_configs.contains(path) {
tracing::warn!(
"{} has changes, but it is marked sensitive, won't auto-save",
path
);
return Ok(());
}
match (cli.confirmation == Paranoia::DryRun, &filter) {
(true, _) => save::noop_file_data_saver(path),
(false, Some(filter)) => {
if path.starts_with(filter) {
save::file_data_saver(&files_path, path, contents)
} else {
save::filtered_file_data_saver(path)
}
}
(false, None) => save::file_data_saver(&files_path, path, contents),
}
},
fs_additions.iter(),
)?;
output.write_all("}\n".as_bytes())?;

output.write_all(
"\n// These are entries in your config that are not applied to the current \
system\n"
.as_bytes(),
)?;
output.write_all(
"// Note that these may not correspond *exactly* to what is in your config\n"
.as_bytes(),
cmd_save_changes(
cli.confirmation,
&config_path,
&script_engine,
&filter,
&fs_additions,
pkg_additions,
pkg_removals,
)?;
output.write_all("// (e.g. write and copy will get mixed up).\n".as_bytes())?;
output.write_all("pub fn unsorted_removals(props, cmds) {\n".as_bytes())?;
konfigkoll_core::save::save_packages(&prefix, &mut output, pkg_removals.into_iter())?;
output.write_all("}\n".as_bytes())?;
}
Commands::Apply {} => {
tracing::debug!("Computing changes to apply");
let mut fs_changes = konfigkoll_core::state::diff(
&DiffGoal::Apply(backend_files.clone(), fs_scan_result.borrow_path_map()),
sys_fs,
script_fs,
)?
.collect_vec();
fs_changes.sort();
let fs_changes =
fs_state_diff_apply(&backend_files, &fs_scan_result, script_fs, sys_fs)?;

let pkgs_changes = pkg_diff
.filter_map(|v| match v {
Expand All @@ -341,59 +282,23 @@ async fn main() -> anyhow::Result<()> {
})
.collect_vec();

if fs_changes.is_empty() && pkgs_changes.is_empty() {
tracing::info!("No system changes to apply, you are up-to-date");
} else {
tracing::warn!("Applying changes");
}

let mut applicator = create_applicator(
cmd_apply_changes(
cli.confirmation,
cli.debug_force_dry_run,
&backends_pkg,
&script_engine,
&interner,
&package_maps,
&backends_pkg,
&backend_files,
script_engine.state().settings().diff(),
script_engine.state().settings().pager(),
);

// Split into early / late file changes based on settings
let early_configs: AHashSet<Utf8PathBuf> =
script_engine.state().settings().early_configs().collect();
let mut early_fs_changes = vec![];
let mut late_fs_changes = vec![];
for change in fs_changes {
if early_configs.contains(&change.path) {
early_fs_changes.push(change);
} else {
late_fs_changes.push(change);
}
}

// Apply early file system
apply_files(applicator.as_mut(), early_fs_changes.iter())?;

// Apply packages
apply_packages(
applicator.as_mut(),
pkgs_changes.into_iter(),
&package_maps,
&interner,
fs_changes,
pkgs_changes,
)?;

// Apply rest of file system
apply_files(applicator.as_mut(), late_fs_changes.iter())?;
}
Commands::Diff { path } => {
tracing::info!("Computing diff");
let mut fs_changes = konfigkoll_core::state::diff(
&DiffGoal::Apply(backend_files.clone(), fs_scan_result.borrow_path_map()),
sys_fs,
script_fs,
)?
.collect_vec();
fs_changes.sort();
let fs_changes =
fs_state_diff_apply(&backend_files, &fs_scan_result, script_fs, sys_fs)?;

let diff_cmd = script_engine.state().settings().diff();
let pager_cmd = script_engine.state().settings().pager();
for change in fs_changes {
Expand All @@ -407,3 +312,170 @@ async fn main() -> anyhow::Result<()> {

Ok(())
}

/// Implements the actual saving for the `save` command
fn cmd_save_changes(
confirmation: Paranoia,
config_path: &Utf8Path,
script_engine: &ScriptEngine,
filter: &Option<Utf8PathBuf>,
fs_additions: &[FsInstruction],
pkg_additions: Vec<(&PkgIdent, PkgInstruction)>,
pkg_removals: Vec<(&PkgIdent, PkgInstruction)>,
) -> anyhow::Result<()> {
if !fs_additions.is_empty() || !pkg_additions.is_empty() || !pkg_removals.is_empty() {
tracing::warn!("There are differences (saving to unsorted.rn)");
} else {
tracing::info!("No differences to save, you are up to date!");
}

// Open output file (for appending) in config dir
let output_path = config_path.join("unsorted.rn");
let mut output = BufWriter::new(
std::fs::OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(&output_path)
.with_context(|| format!("Failed to open output file {}", output_path))?,
);
output.write_all("// This file is generated by konfigkoll\n".as_bytes())?;
output.write_all(
"// You will need to merge the changes you want into your own actual config\n".as_bytes(),
)?;
output.write_all("pub fn unsorted_additions(props, cmds) {\n".as_bytes())?;
let prefix = script_engine.state().settings().save_prefix();
konfigkoll_core::save::save_packages(&prefix, &mut output, pkg_additions.into_iter())?;
let files_path = config_path.join("files");
let sensitive_configs: AHashSet<Utf8PathBuf> = script_engine
.state()
.settings()
.sensitive_configs()
.collect();
konfigkoll_core::save::save_fs_changes(
&prefix,
&mut output,
|path, contents| {
if sensitive_configs.contains(path) {
tracing::warn!(
"{} has changes, but it is marked sensitive, won't auto-save",
path
);
return Ok(());
}
match (confirmation == Paranoia::DryRun, &filter) {
(true, _) => save::noop_file_data_saver(path),
(false, Some(filter)) => {
if path.starts_with(filter) {
save::file_data_saver(&files_path, path, contents)
} else {
save::filtered_file_data_saver(path)
}
}
(false, None) => save::file_data_saver(&files_path, path, contents),
}
},
fs_additions.iter(),
)?;
output.write_all("}\n".as_bytes())?;

output.write_all(
"\n// These are entries in your config that are not applied to the current system\n"
.as_bytes(),
)?;
output.write_all(
"// Note that these may not correspond *exactly* to what is in your config\n".as_bytes(),
)?;
output.write_all("// (e.g. write and copy will get mixed up).\n".as_bytes())?;
output.write_all("pub fn unsorted_removals(props, cmds) {\n".as_bytes())?;
konfigkoll_core::save::save_packages(&prefix, &mut output, pkg_removals.into_iter())?;
output.write_all("}\n".as_bytes())?;
Ok(())
}

/// Implements the actual application for the `apply` command
#[allow(clippy::too_many_arguments)]
fn cmd_apply_changes(
confirmation: Paranoia,
debug_force_dry_run: bool,
script_engine: &ScriptEngine,
interner: &Arc<Interner>,
backends_pkg: &Arc<PackageBackendMap>,
backend_files: &Arc<dyn Files>,
package_maps: &PackageMapMap,
fs_changes: Vec<FsInstruction>,
pkgs_changes: Vec<(&PkgIdent, PkgInstruction)>,
) -> anyhow::Result<()> {
if fs_changes.is_empty() && pkgs_changes.is_empty() {
tracing::info!("No system changes to apply, you are up-to-date");
} else {
tracing::warn!("Applying changes");
}

let mut applicator = create_applicator(
confirmation,
debug_force_dry_run,
backends_pkg,
interner,
package_maps,
backend_files,
script_engine.state().settings().diff(),
script_engine.state().settings().pager(),
);

// Split into early / late file changes based on settings
let early_configs: AHashSet<Utf8PathBuf> =
script_engine.state().settings().early_configs().collect();
let mut early_fs_changes = vec![];
let mut late_fs_changes = vec![];
for change in fs_changes {
if early_configs.contains(&change.path) {
early_fs_changes.push(change);
} else {
late_fs_changes.push(change);
}
}

// Apply early file system
apply_files(applicator.as_mut(), early_fs_changes.iter())?;

// Apply packages
apply_packages(
applicator.as_mut(),
pkgs_changes.into_iter(),
package_maps,
interner,
)?;

// Apply rest of file system
apply_files(applicator.as_mut(), late_fs_changes.iter())?;
Ok(())
}

/// Compute the FS changes for the save direction
fn fs_state_diff_save(
script_fs: FsEntries,
sys_fs: FsEntries,
) -> anyhow::Result<Vec<FsInstruction>> {
let mut fs_additions =
konfigkoll_core::state::diff(&DiffGoal::Save, script_fs, sys_fs)?.collect_vec();
fs_additions.sort();
Ok(fs_additions)
}

/// Compute the FS changes for the apply direction
fn fs_state_diff_apply(
backend_files: &Arc<dyn Files>,
fs_scan_result: &ScanResult,
script_fs: FsEntries,
sys_fs: FsEntries,
) -> anyhow::Result<Vec<FsInstruction>> {
let mut fs_changes = konfigkoll_core::state::diff(
&DiffGoal::Apply(backend_files.clone(), fs_scan_result.borrow_path_map()),
sys_fs,
script_fs,
)?
.collect_vec();
fs_changes.sort();
Ok(fs_changes)
}

0 comments on commit be4a092

Please sign in to comment.