use anyhow::{Context, Result};
use std::fs;
use super::super::MigrationContext;
use super::config_refs::update_config_file_references;
#[derive(Debug, Clone)]
pub struct FileMigrationOptions {
pub keep_backup: bool,
pub update_config: bool,
}
impl Default for FileMigrationOptions {
fn default() -> Self {
Self {
keep_backup: true,
update_config: true,
}
}
}
pub fn apply_file_rename(ctx: &MigrationContext, old_path: &str, new_path: &str) -> Result<()> {
let opts = FileMigrationOptions::default();
apply_file_rename_with_options(ctx, old_path, new_path, &opts)
}
pub fn apply_file_rename_with_options(
ctx: &MigrationContext,
old_path: &str,
new_path: &str,
opts: &FileMigrationOptions,
) -> Result<()> {
let old_full_path = ctx.resolve_path(old_path);
let new_full_path = ctx.resolve_path(new_path);
if !old_full_path.exists() {
anyhow::bail!("Source file does not exist: {}", old_full_path.display());
}
if new_full_path.exists() && old_full_path != new_full_path {
anyhow::bail!(
"Destination file already exists: {}",
new_full_path.display()
);
}
if let Some(parent) = new_full_path.parent() {
fs::create_dir_all(parent)
.with_context(|| format!("create parent directory {}", parent.display()))?;
}
fs::copy(&old_full_path, &new_full_path).with_context(|| {
format!(
"copy {} to {}",
old_full_path.display(),
new_full_path.display()
)
})?;
log::info!(
"Migrated file from {} to {}",
old_full_path.display(),
new_full_path.display()
);
if opts.update_config {
update_config_file_references(ctx, old_path, new_path)
.context("update config file references")?;
}
if !opts.keep_backup {
fs::remove_file(&old_full_path)
.with_context(|| format!("remove original file {}", old_full_path.display()))?;
log::debug!("Removed original file {}", old_full_path.display());
} else {
log::debug!("Kept original file {} as backup", old_full_path.display());
}
Ok(())
}
pub fn rollback_file_migration(
ctx: &MigrationContext,
old_path: &str,
new_path: &str,
) -> Result<()> {
let old_full_path = ctx.resolve_path(old_path);
let new_full_path = ctx.resolve_path(new_path);
if !old_full_path.exists() {
anyhow::bail!(
"Cannot rollback: original file {} does not exist",
old_full_path.display()
);
}
if new_full_path.exists() {
fs::remove_file(&new_full_path)
.with_context(|| format!("remove migrated file {}", new_full_path.display()))?;
}
log::info!(
"Rolled back file migration: restored {}, removed {}",
old_full_path.display(),
new_full_path.display()
);
Ok(())
}