mars_agents/cli/
resolve_cmd.rs1use std::path::PathBuf;
4
5use crate::error::MarsError;
6use crate::hash;
7use crate::types::{ContentHash, DestPath};
8
9use super::output;
10
11#[derive(Debug, clap::Args)]
13pub struct ResolveArgs {
14 pub file: Option<PathBuf>,
16}
17
18pub fn run(args: &ResolveArgs, ctx: &super::MarsContext, json: bool) -> Result<i32, MarsError> {
20 let mars_dir = ctx.project_root.join(".mars");
21 let lock_path = mars_dir.join("sync.lock");
22 let _sync_lock = crate::fs::FileLock::acquire(&lock_path)?;
23
24 let mut lock = crate::lock::load(&ctx.project_root)?;
25 let mut resolved_files = Vec::new();
26 let mut still_conflicted = Vec::new();
27
28 let items_to_check: Vec<DestPath> = if let Some(file) = &args.file {
29 let rel = DestPath::from(file.as_path());
31 if lock.items.contains_key(&rel) {
32 vec![rel]
33 } else {
34 return Err(MarsError::Source {
35 source_name: "resolve".to_string(),
36 message: format!("{} is not a managed item", file.display()),
37 });
38 }
39 } else {
40 lock.items.keys().cloned().collect()
42 };
43
44 for dest_path_str in &items_to_check {
45 let disk_path = mars_dir.join(dest_path_str);
46 if !disk_path.exists() {
47 continue;
48 }
49
50 if crate::merge::file_has_conflict_markers(&disk_path) {
52 still_conflicted.push(dest_path_str.clone());
53 continue;
54 }
55
56 if let Some(item) = lock.items.get_mut(dest_path_str) {
58 let new_hash = hash::compute_hash(&disk_path, item.kind)?;
59 if new_hash != item.installed_checksum {
60 item.installed_checksum = ContentHash::from(new_hash);
61 resolved_files.push(dest_path_str.to_string());
62 }
63 }
64 }
65
66 if !resolved_files.is_empty() {
68 crate::lock::write(&ctx.project_root, &lock)?;
69 }
70
71 if json {
72 output::print_json(&serde_json::json!({
73 "resolved": resolved_files,
74 "still_conflicted": still_conflicted,
75 }));
76 } else {
77 for file in &resolved_files {
78 output::print_success(&format!("resolved {file}"));
79 }
80 for file in &still_conflicted {
81 eprintln!(" ! {file} still has conflict markers");
82 }
83 if resolved_files.is_empty() && still_conflicted.is_empty() {
84 output::print_info("no conflicts to resolve");
85 }
86 }
87
88 if still_conflicted.is_empty() {
89 Ok(0)
90 } else {
91 Ok(1)
92 }
93}