equal
deleted
inserted
replaced
4 use crate::requirements; |
4 use crate::requirements; |
5 use crate::utils::files::get_path_from_bytes; |
5 use crate::utils::files::get_path_from_bytes; |
6 use crate::utils::SliceExt; |
6 use crate::utils::SliceExt; |
7 use memmap::{Mmap, MmapOptions}; |
7 use memmap::{Mmap, MmapOptions}; |
8 use std::collections::HashSet; |
8 use std::collections::HashSet; |
|
9 use std::io::ErrorKind; |
9 use std::path::{Path, PathBuf}; |
10 use std::path::{Path, PathBuf}; |
10 |
11 |
11 /// A repository on disk |
12 /// A repository on disk |
12 pub struct Repo { |
13 pub struct Repo { |
13 working_directory: PathBuf, |
14 working_directory: PathBuf, |
49 pub fn find_repo_root() -> Result<PathBuf, RepoError> { |
50 pub fn find_repo_root() -> Result<PathBuf, RepoError> { |
50 let current_directory = crate::utils::current_dir()?; |
51 let current_directory = crate::utils::current_dir()?; |
51 // ancestors() is inclusive: it first yields `current_directory` |
52 // ancestors() is inclusive: it first yields `current_directory` |
52 // as-is. |
53 // as-is. |
53 for ancestor in current_directory.ancestors() { |
54 for ancestor in current_directory.ancestors() { |
54 if ancestor.join(".hg").is_dir() { |
55 if is_dir(ancestor.join(".hg"))? { |
55 return Ok(ancestor.to_path_buf()); |
56 return Ok(ancestor.to_path_buf()); |
56 } |
57 } |
57 } |
58 } |
58 return Err(RepoError::NotFound { |
59 return Err(RepoError::NotFound { |
59 at: current_directory, |
60 at: current_directory, |
71 pub fn find( |
72 pub fn find( |
72 config: &Config, |
73 config: &Config, |
73 explicit_path: Option<PathBuf>, |
74 explicit_path: Option<PathBuf>, |
74 ) -> Result<Self, RepoError> { |
75 ) -> Result<Self, RepoError> { |
75 if let Some(root) = explicit_path { |
76 if let Some(root) = explicit_path { |
76 if root.join(".hg").is_dir() { |
77 if is_dir(root.join(".hg"))? { |
77 Self::new_at_path(root.to_owned(), config) |
78 Self::new_at_path(root.to_owned(), config) |
78 } else if root.is_file() { |
79 } else if is_file(&root)? { |
79 Err(HgError::unsupported("bundle repository").into()) |
80 Err(HgError::unsupported("bundle repository").into()) |
80 } else { |
81 } else { |
81 Err(RepoError::NotFound { |
82 Err(RepoError::NotFound { |
82 at: root.to_owned(), |
83 at: root.to_owned(), |
83 }) |
84 }) |
128 let mut shared_path = |
129 let mut shared_path = |
129 get_path_from_bytes(bytes.trim_end_newlines()).to_owned(); |
130 get_path_from_bytes(bytes.trim_end_newlines()).to_owned(); |
130 if relative { |
131 if relative { |
131 shared_path = dot_hg.join(shared_path) |
132 shared_path = dot_hg.join(shared_path) |
132 } |
133 } |
133 if !shared_path.is_dir() { |
134 if !is_dir(&shared_path)? { |
134 return Err(HgError::corrupted(format!( |
135 return Err(HgError::corrupted(format!( |
135 ".hg/sharedpath points to nonexistent directory {}", |
136 ".hg/sharedpath points to nonexistent directory {}", |
136 shared_path.display() |
137 shared_path.display() |
137 )) |
138 )) |
138 .into()); |
139 .into()); |
284 let to = self.join(relative_to); |
285 let to = self.join(relative_to); |
285 std::fs::rename(&from, &to) |
286 std::fs::rename(&from, &to) |
286 .with_context(|| IoErrorContext::RenamingFile { from, to }) |
287 .with_context(|| IoErrorContext::RenamingFile { from, to }) |
287 } |
288 } |
288 } |
289 } |
|
290 |
|
291 fn fs_metadata( |
|
292 path: impl AsRef<Path>, |
|
293 ) -> Result<Option<std::fs::Metadata>, HgError> { |
|
294 let path = path.as_ref(); |
|
295 match std::fs::metadata(path) { |
|
296 Ok(meta) => Ok(Some(meta)), |
|
297 Err(error) => match error.kind() { |
|
298 // TODO: when we require a Rust version where `NotADirectory` is |
|
299 // stable, invert this logic and return None for it and `NotFound` |
|
300 // and propagate any other error. |
|
301 ErrorKind::PermissionDenied => Err(error).with_context(|| { |
|
302 IoErrorContext::ReadingMetadata(path.to_owned()) |
|
303 }), |
|
304 _ => Ok(None), |
|
305 }, |
|
306 } |
|
307 } |
|
308 |
|
309 fn is_dir(path: impl AsRef<Path>) -> Result<bool, HgError> { |
|
310 Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_dir())) |
|
311 } |
|
312 |
|
313 fn is_file(path: impl AsRef<Path>) -> Result<bool, HgError> { |
|
314 Ok(fs_metadata(path)?.map_or(false, |meta| meta.is_file())) |
|
315 } |