use anyhow::Result;
use patcher::{ApplyResult, DiffAlgorithm, Differ, MultifilePatch, MultifilePatcher};
use std::fs;
use std::path::Path;
fn main() -> Result<()> {
println!("=== Multi-File Patch Example ===");
let tmp_dir = Path::new("/tmp/patcher-examples");
if !tmp_dir.exists() {
fs::create_dir_all(tmp_dir)?;
}
create_test_files(tmp_dir)?;
let patch_path = create_multi_file_patch(tmp_dir)?;
apply_patch(tmp_dir, &patch_path, false)?;
apply_patch(tmp_dir, &patch_path, true)?;
Ok(())
}
fn create_test_files(dir: &Path) -> Result<()> {
println!("Creating test files...");
let files = [
(
"config.json",
"{\n \"name\": \"patcher\",\n \"version\": \"0.1.0\",\n \"debug\": false\n}",
),
(
"README.txt",
"# Test Project\n\nThis is a test project for patcher.\n\nMore information will be added later.",
),
(
"src/main.rs",
"fn main() {\n println!(\"Hello, world!\");\n}",
),
];
for (path, content) in &files {
let file_path = dir.join(path);
if let Some(parent) = file_path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(&file_path, content)?;
println!(" Created: {}", path);
}
println!("Test files created successfully");
Ok(())
}
fn create_multi_file_patch(dir: &Path) -> Result<std::path::PathBuf> {
println!("\nCreating multi-file patch...");
let changes = [
(
"config.json",
"{\n \"name\": \"patcher\",\n \"version\": \"0.1.0\",\n \"debug\": false\n}",
"{\n \"name\": \"patcher\",\n \"version\": \"0.2.0\",\n \"debug\": true,\n \"logLevel\": \"info\"\n}",
),
(
"README.txt",
"# Test Project\n\nThis is a test project for patcher.\n\nMore information will be added later.",
"# Patcher Test\n\nThis is a test project showcasing the patcher library.\n\nSee examples for more details.",
),
(
"src/main.rs",
"fn main() {\n println!(\"Hello, world!\");\n}",
"fn main() {\n println!(\"Hello, patcher!\");\n println!(\"Version 0.2.0\");\n}",
),
];
let mut patches = Vec::new();
for (path, original, modified) in &changes {
let differ = Differ::new(original, modified);
let mut patch = differ.generate();
patch.old_file = path.to_string();
patch.new_file = path.to_string();
patches.push(patch);
println!(" Created patch for: {}", path);
}
let multi_patch = MultifilePatch::new(patches);
let patch_path = dir.join("changes.patch");
fs::write(&patch_path, multi_patch.to_string())?;
println!("Multi-file patch created at: {:?}", patch_path);
Ok(patch_path)
}
fn apply_patch(root: &Path, patch_path: &Path, reverse: bool) -> Result<()> {
let action = if reverse { "Reverting" } else { "Applying" };
println!("\n{} multi-file patch...", action);
let multi_patch = MultifilePatch::parse_from_file(patch_path)?;
println!("Patch contains {} files:", multi_patch.patches.len());
for patch in &multi_patch.patches {
println!(" - {}", patch.old_file);
}
let multi_patcher = MultifilePatcher::with_root(multi_patch, root);
let results = multi_patcher.apply_and_write(reverse)?;
println!(
"\n{} action resulted in {} outcomes:",
action,
results.len()
);
let mut success_count = 0;
for result in results {
match result {
ApplyResult::Applied(file) => {
println!(
" - Applied: {} {}",
file.path,
if file.is_new { "(new file)" } else { "" }
);
match fs::read_to_string(&file.path) {
Ok(content) => println!(
" Content (first 50 chars): {}",
content.chars().take(50).collect::<String>()
),
Err(e) => println!(" Error reading file {}: {}", file.path, e),
};
success_count += 1;
}
ApplyResult::Deleted(path) => {
println!(" - Deleted: {}", path);
success_count += 1;
}
ApplyResult::Skipped(reason) => {
println!(" - Skipped: {}", reason);
}
ApplyResult::Failed(path, error) => {
println!(" - Failed: {} - {}", path, error);
}
}
}
println!("Successfully processed {} files/patches.", success_count);
Ok(())
}