use subversion::{
client::{CheckoutOptions, CommitOptions, Context, UpdateOptions},
Depth, Revision,
};
fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
println!("Conflict Resolution API Example\n");
let temp_dir = tempfile::tempdir()?;
let repo_path = temp_dir.path().join("repo");
let wc1_path = temp_dir.path().join("wc1");
let wc2_path = temp_dir.path().join("wc2");
println!("Creating repository...");
subversion::repos::Repos::create(&repo_path)?;
let mut ctx = Context::new()?;
let url = format!("file://{}", repo_path.display());
println!("Checking out working copy 1...");
ctx.checkout(
url.as_str(),
&wc1_path,
&CheckoutOptions {
peg_revision: Revision::Head,
revision: Revision::Head,
depth: Depth::Infinity,
ignore_externals: false,
allow_unver_obstructions: false,
},
)?;
println!("Creating initial file...");
let file1 = wc1_path.join("test.txt");
std::fs::write(&file1, "Line 1\nLine 2\nLine 3\n")?;
ctx.add(
&file1,
&subversion::client::AddOptions {
depth: Depth::Empty,
force: false,
no_ignore: false,
no_autoprops: false,
add_parents: false,
},
)?;
ctx.commit(
&[wc1_path.to_str().unwrap()],
&CommitOptions::default(),
std::collections::HashMap::new(),
None,
&mut |_| Ok(()),
)?;
println!("Checking out working copy 2...");
ctx.checkout(
url.as_str(),
&wc2_path,
&CheckoutOptions {
peg_revision: Revision::Head,
revision: Revision::Head,
depth: Depth::Infinity,
ignore_externals: false,
allow_unver_obstructions: false,
},
)?;
println!("Modifying file in wc1...");
std::fs::write(&file1, "Line 1\nModified by WC1\nLine 3\n")?;
ctx.commit(
&[wc1_path.to_str().unwrap()],
&CommitOptions::default(),
std::collections::HashMap::new(),
None,
&mut |_| Ok(()),
)?;
println!("Modifying file in wc2 (creating conflict)...");
let file2 = wc2_path.join("test.txt");
std::fs::write(&file2, "Line 1\nModified by WC2\nLine 3\n")?;
println!("Updating wc2 (conflict will occur)...");
let _ = ctx.update(
&[wc2_path.to_str().unwrap()],
Revision::Head,
&UpdateOptions {
depth: Depth::Infinity,
depth_is_sticky: false,
ignore_externals: false,
allow_unver_obstructions: false,
adds_as_modifications: false,
make_parents: false,
},
);
println!("\n=== Demonstrating Conflict Resolution API ===\n");
println!("1. Getting conflict information...");
let mut conflict = ctx.conflict_get(&file2)?;
let (has_text, prop_conflicts, has_tree) =
conflict.get_conflicted().map_err(|e| e.to_string())?;
let prop_conflicts: Vec<String> = prop_conflicts.iter().map(|s| s.to_string()).collect();
println!(" Text conflict: {}", has_text);
println!(" Property conflicts: {:?}", prop_conflicts);
println!(" Tree conflict: {}", has_tree);
if has_text {
println!("\n2. Examining text conflict details...");
let local_abspath = conflict.get_local_abspath();
println!(" Conflicted file: {}", local_abspath);
let mime_type = conflict.text_get_mime_type().map_err(|e| e.to_string())?;
let mime_type = mime_type.map(|s| s.to_string()); println!(" MIME type: {:?}", mime_type);
let incoming_change = conflict.get_incoming_change();
let local_change = conflict.get_local_change();
println!(" Incoming change: {:?}", incoming_change);
println!(" Local change: {:?}", local_change);
println!("\n3. Getting resolution options...");
let options = conflict
.text_get_resolution_options(&mut ctx)
.map_err(|e| e.to_string())?;
println!(" Available options:");
for (i, opt) in options.iter().enumerate() {
let id = opt.get_id();
let label = opt.get_label();
let desc = opt.get_description();
println!(" {}. {} - {} (ID: {:?})", i + 1, label, desc, id);
}
println!("\n4. Finding 'merged text' option...");
let merged_option = subversion::client::ConflictOption::find_by_id(
&options,
subversion::ClientConflictOptionId::MergedText,
);
if let Some(opt) = merged_option {
println!(" Found option: {}", opt.get_label());
println!("\n5. Resolving conflict with merged text...");
conflict
.text_resolve_by_id(subversion::TextConflictChoice::Merged, &mut ctx)
.map_err(|e| e.to_string())?;
let resolution = conflict.text_get_resolution();
println!(" Resolution applied: {:?}", resolution);
} else {
println!("\n5. Resolving conflict with working version...");
conflict
.text_resolve_by_id(subversion::TextConflictChoice::MineFull, &mut ctx)
.map_err(|e| e.to_string())?;
}
println!("\n✓ Conflict resolved successfully!");
}
println!("\n=== Property Conflict Example ===\n");
println!("Creating property conflict...");
ctx.propset(
"custom:prop",
Some(b"value1"),
file1.to_str().unwrap(),
&subversion::client::PropSetOptions::default(),
)?;
ctx.commit(
&[wc1_path.to_str().unwrap()],
&CommitOptions::default(),
std::collections::HashMap::new(),
None,
&mut |_| Ok(()),
)?;
ctx.propset(
"custom:prop",
Some(b"value2"),
file2.to_str().unwrap(),
&subversion::client::PropSetOptions::default(),
)?;
let _ = ctx.update(
&[wc2_path.to_str().unwrap()],
Revision::Head,
&UpdateOptions::default(),
);
if let Ok(mut prop_conflict) = ctx.conflict_get(&file2) {
let (_, props, _) = prop_conflict.get_conflicted().map_err(|e| e.to_string())?;
let props: Vec<String> = props.iter().map(|s| s.to_string()).collect();
if !props.is_empty() {
println!("Property conflict detected on: {:?}", props);
let propvals = prop_conflict
.prop_get_propvals(&props[0])
.map_err(|e| e.to_string())?;
println!(" Base value: {:?}", propvals.0);
println!(" Working value: {:?}", propvals.1);
println!(" Incoming old value: {:?}", propvals.2);
println!(" Incoming new value: {:?}", propvals.3);
let prop_options = prop_conflict
.prop_get_resolution_options(&mut ctx)
.map_err(|e| e.to_string())?;
println!(
" Available property resolution options: {}",
prop_options.len()
);
prop_conflict
.prop_resolve_by_id(
&props[0],
subversion::TextConflictChoice::MineFull,
&mut ctx,
)
.map_err(|e| e.to_string())?;
println!(" ✓ Property conflict resolved");
}
}
println!("\n=== Example completed successfully! ===");
println!("\nThis example demonstrated:");
println!(" • Getting conflict information with conflict_get");
println!(" • Examining conflict details and types");
println!(" • Listing available resolution options");
println!(" • Finding specific options by ID");
println!(" • Resolving text and property conflicts");
println!(" • Using prop_get_propvals to examine property values");
Ok(())
}