diff --git a/src/cli/src/cmd/add.rs b/src/cli/src/cmd/add.rs index dfb9ae081..ccc49ef55 100644 --- a/src/cli/src/cmd/add.rs +++ b/src/cli/src/cmd/add.rs @@ -48,7 +48,7 @@ impl RunCmd for AddCmd { OxenError::basic_str(format!("Failed to get current directory: {}", e)) })?; let joined_path = current_dir.join(p); - joined_path.canonicalize().or_else(|_| Ok(joined_path)) + dunce::canonicalize(&joined_path).or_else(|_| Ok(joined_path)) }) .collect::, OxenError>>()?; diff --git a/src/cli/src/cmd/rm.rs b/src/cli/src/cmd/rm.rs index a68d8fa20..ff99fac29 100644 --- a/src/cli/src/cmd/rm.rs +++ b/src/cli/src/cmd/rm.rs @@ -52,7 +52,7 @@ impl RunCmd for RmCmd { OxenError::basic_str(format!("Failed to get current directory: {}", e)) })?; let joined_path = current_dir.join(p); - joined_path.canonicalize().or_else(|_| Ok(joined_path)) + dunce::canonicalize(&joined_path).or_else(|_| Ok(joined_path)) }) .collect::, OxenError>>()?; diff --git a/src/lib/src/core/v0_19_0/add.rs b/src/lib/src/core/v0_19_0/add.rs index c1d3fd93b..20fbd19ad 100644 --- a/src/lib/src/core/v0_19_0/add.rs +++ b/src/lib/src/core/v0_19_0/add.rs @@ -190,7 +190,7 @@ pub fn process_add_dir( let path = path.clone(); let repo = repo.clone(); let maybe_head_commit = maybe_head_commit.clone(); - let repo_path = repo.path.clone(); + let repo_path = &repo.path.clone(); use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; @@ -314,7 +314,7 @@ fn add_file_inner( path: &Path, staged_db: &DBWithThreadMode, ) -> Result, OxenError> { - let repo_path = repo.path.clone(); + let repo_path = &repo.path.clone(); let versions_path = util::fs::oxen_hidden_dir(&repo.path) .join(VERSIONS_DIR) .join(FILES_DIR); @@ -360,17 +360,31 @@ pub fn process_add_file( seen_dirs: &Arc>>, ) -> Result, OxenError> { log::debug!("process_add_file {:?}", path); - let relative_path = util::fs::path_relative_to_dir(path, repo_path)?; - let full_path = repo_path.join(&relative_path); + let mut relative_path = util::fs::path_relative_to_dir(path, repo_path)?; + let mut full_path = repo_path.join(&relative_path); if !full_path.is_file() { - // If it's not a file - no need to add it - // We handle directories by traversing the parents of files below - log::debug!("file is not a file - skipping add on {:?}", full_path); - return Ok(Some(StagedMerkleTreeNode { - status: StagedEntryStatus::Added, - node: MerkleTreeNode::default_dir(), - })); + + // Fix for Windows CLI + // util::fs::path_relative_to_dir can fail if the capitalization of the input path differs from what it is in the working directory + // TODO: is there ever a situation where process_add_file will be called on a path that doesn't exist? That will be propogated as an error here + log::debug!("file {:?} was not found. Checking for Windows CLI path", full_path); + let canon_repo_path = dunce::canonicalize(repo_path)?; + let cli_path = util::fs::path_relative_to_dir(path, &canon_repo_path)?; + + if cli_path.is_file() { + relative_path = cli_path; + full_path = canon_repo_path.join(&relative_path); + } else { + + // If it's not a file - no need to add it + // We handle directories by traversing the parents of files below + log::debug!("file is not a file - skipping add on {:?}", full_path); + return Ok(Some(StagedMerkleTreeNode { + status: StagedEntryStatus::Added, + node: MerkleTreeNode::default_dir(), + })); + } } // Check if the file is already in the head commit diff --git a/src/lib/src/util/fs.rs b/src/lib/src/util/fs.rs index e1c536382..a8375d6e0 100644 --- a/src/lib/src/util/fs.rs +++ b/src/lib/src/util/fs.rs @@ -1351,7 +1351,38 @@ pub fn path_relative_to_dir( let mut mut_path = path.to_path_buf(); let mut components: Vec = vec![]; while mut_path.parent().is_some() { - // println!("Comparing {:?} => {:?} => {:?}", path, mut_path.parent(), dir); + log::debug!("Comparing {:?} => {:?} => {:?}", path, mut_path.parent(), dir); + if let Some(filename) = mut_path.file_name() { + if mut_path != dir { + components.push(PathBuf::from(filename)); + } else { + break; + } + } + + mut_path.pop(); + } + components.reverse(); + + let mut result = PathBuf::new(); + for component in components.iter() { + result = result.join(component); + } + + Ok(result) +} + +pub fn path_relative_to_canon_dir( + path: impl AsRef, + dir: impl AsRef, +) -> Result { + let path = path.as_ref(); + let dir = dunce::canonicalize(dir.as_ref())?; + + let mut mut_path = path.to_path_buf(); + let mut components: Vec = vec![]; + while mut_path.parent().is_some() { + log::debug!("Comparing {:?} => {:?} => {:?}", path, mut_path.parent(), dir); if let Some(filename) = mut_path.file_name() { if mut_path != dir { components.push(PathBuf::from(filename));