1 use crate::errors::{HgError, IoResultExt}; |
1 use crate::errors::{HgError, IoResultExt}; |
2 use crate::operations::{find_root, FindRootError}; |
|
3 use crate::requirements; |
2 use crate::requirements; |
4 use memmap::{Mmap, MmapOptions}; |
3 use memmap::{Mmap, MmapOptions}; |
5 use std::path::{Path, PathBuf}; |
4 use std::path::{Path, PathBuf}; |
6 |
5 |
7 /// A repository on disk |
6 /// A repository on disk |
9 working_directory: PathBuf, |
8 working_directory: PathBuf, |
10 dot_hg: PathBuf, |
9 dot_hg: PathBuf, |
11 store: PathBuf, |
10 store: PathBuf, |
12 } |
11 } |
13 |
12 |
|
13 #[derive(Debug, derive_more::From)] |
|
14 pub enum RepoFindError { |
|
15 NotFoundInCurrentDirectoryOrAncestors { |
|
16 current_directory: PathBuf, |
|
17 }, |
|
18 #[from] |
|
19 Other(HgError), |
|
20 } |
|
21 |
14 /// Filesystem access abstraction for the contents of a given "base" diretory |
22 /// Filesystem access abstraction for the contents of a given "base" diretory |
15 #[derive(Clone, Copy)] |
23 #[derive(Clone, Copy)] |
16 pub(crate) struct Vfs<'a> { |
24 pub(crate) struct Vfs<'a> { |
17 base: &'a Path, |
25 base: &'a Path, |
18 } |
26 } |
19 |
27 |
20 impl Repo { |
28 impl Repo { |
21 /// Returns `None` if the given path doesn’t look like a repository |
29 /// Search the current directory and its ancestores for a repository: |
22 /// (doesn’t contain a `.hg` sub-directory). |
30 /// a working directory that contains a `.hg` sub-directory. |
23 pub fn for_path(root: impl Into<PathBuf>) -> Self { |
31 pub fn find() -> Result<Self, RepoFindError> { |
24 let working_directory = root.into(); |
32 let current_directory = crate::utils::current_dir()?; |
25 let dot_hg = working_directory.join(".hg"); |
33 // ancestors() is inclusive: it first yields `current_directory` as-is. |
26 Self { |
34 for ancestor in current_directory.ancestors() { |
27 store: dot_hg.join("store"), |
35 let dot_hg = ancestor.join(".hg"); |
28 dot_hg, |
36 if dot_hg.is_dir() { |
29 working_directory, |
37 let repo = Self { |
|
38 store: dot_hg.join("store"), |
|
39 dot_hg, |
|
40 working_directory: ancestor.to_owned(), |
|
41 }; |
|
42 requirements::check(&repo)?; |
|
43 return Ok(repo); |
|
44 } |
30 } |
45 } |
31 } |
46 Err(RepoFindError::NotFoundInCurrentDirectoryOrAncestors { |
32 |
47 current_directory, |
33 pub fn find() -> Result<Self, FindRootError> { |
48 }) |
34 find_root().map(Self::for_path) |
|
35 } |
|
36 |
|
37 pub fn check_requirements(&self) -> Result<(), HgError> { |
|
38 requirements::check(self) |
|
39 } |
49 } |
40 |
50 |
41 pub fn working_directory_path(&self) -> &Path { |
51 pub fn working_directory_path(&self) -> &Path { |
42 &self.working_directory |
52 &self.working_directory |
43 } |
53 } |
63 } |
73 } |
64 } |
74 } |
65 } |
75 } |
66 |
76 |
67 impl Vfs<'_> { |
77 impl Vfs<'_> { |
|
78 pub(crate) fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf { |
|
79 self.base.join(relative_path) |
|
80 } |
|
81 |
68 pub(crate) fn read( |
82 pub(crate) fn read( |
69 &self, |
83 &self, |
70 relative_path: impl AsRef<Path>, |
84 relative_path: impl AsRef<Path>, |
71 ) -> Result<Vec<u8>, HgError> { |
85 ) -> Result<Vec<u8>, HgError> { |
72 let path = self.base.join(relative_path); |
86 let path = self.join(relative_path); |
73 std::fs::read(&path).for_file(&path) |
87 std::fs::read(&path).for_file(&path) |
74 } |
88 } |
75 |
89 |
76 pub(crate) fn mmap_open( |
90 pub(crate) fn mmap_open( |
77 &self, |
91 &self, |