Show More
@@ -0,0 +1,124 b'' | |||
|
1 | use super::Operation; | |
|
2 | use std::fmt; | |
|
3 | use std::path::{Path, PathBuf}; | |
|
4 | ||
|
5 | /// Kind of error encoutered by FindRoot | |
|
6 | #[derive(Debug)] | |
|
7 | pub enum FindRootErrorKind { | |
|
8 | /// Root of the repository has not been found | |
|
9 | /// Contains the current directory used by FindRoot | |
|
10 | RootNotFound(PathBuf), | |
|
11 | /// The current directory does not exists or permissions are insufficient | |
|
12 | /// to get access to it | |
|
13 | GetCurrentDirError(std::io::Error), | |
|
14 | } | |
|
15 | ||
|
16 | /// A FindRoot error | |
|
17 | #[derive(Debug)] | |
|
18 | pub struct FindRootError { | |
|
19 | /// Kind of error encoutered by FindRoot | |
|
20 | pub kind: FindRootErrorKind, | |
|
21 | } | |
|
22 | ||
|
23 | impl std::error::Error for FindRootError {} | |
|
24 | ||
|
25 | impl fmt::Display for FindRootError { | |
|
26 | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
|
27 | unimplemented!() | |
|
28 | } | |
|
29 | } | |
|
30 | ||
|
31 | /// Find the root of the repository | |
|
32 | /// by searching for a .hg directory in the current directory and its | |
|
33 | /// ancestors | |
|
34 | pub struct FindRoot<'a> { | |
|
35 | current_dir: Option<&'a Path>, | |
|
36 | } | |
|
37 | ||
|
38 | impl<'a> FindRoot<'a> { | |
|
39 | pub fn new() -> Self { | |
|
40 | Self { current_dir: None } | |
|
41 | } | |
|
42 | ||
|
43 | pub fn new_from_path(current_dir: &'a Path) -> Self { | |
|
44 | Self { | |
|
45 | current_dir: Some(current_dir), | |
|
46 | } | |
|
47 | } | |
|
48 | } | |
|
49 | ||
|
50 | impl<'a> Operation<PathBuf> for FindRoot<'a> { | |
|
51 | type Error = FindRootError; | |
|
52 | ||
|
53 | fn run(&self) -> Result<PathBuf, Self::Error> { | |
|
54 | let current_dir = match self.current_dir { | |
|
55 | None => std::env::current_dir().or_else(|e| { | |
|
56 | Err(FindRootError { | |
|
57 | kind: FindRootErrorKind::GetCurrentDirError(e), | |
|
58 | }) | |
|
59 | })?, | |
|
60 | Some(path) => path.into(), | |
|
61 | }; | |
|
62 | ||
|
63 | if current_dir.join(".hg").exists() { | |
|
64 | return Ok(current_dir.into()); | |
|
65 | } | |
|
66 | let mut ancestors = current_dir.ancestors(); | |
|
67 | while let Some(parent) = ancestors.next() { | |
|
68 | if parent.join(".hg").exists() { | |
|
69 | return Ok(parent.into()); | |
|
70 | } | |
|
71 | } | |
|
72 | Err(FindRootError { | |
|
73 | kind: FindRootErrorKind::RootNotFound(current_dir.to_path_buf()), | |
|
74 | }) | |
|
75 | } | |
|
76 | } | |
|
77 | ||
|
78 | #[cfg(test)] | |
|
79 | mod tests { | |
|
80 | use super::*; | |
|
81 | use std::fs; | |
|
82 | use tempfile; | |
|
83 | ||
|
84 | #[test] | |
|
85 | fn dot_hg_not_found() { | |
|
86 | let tmp_dir = tempfile::tempdir().unwrap(); | |
|
87 | let path = tmp_dir.path(); | |
|
88 | ||
|
89 | let err = FindRoot::new_from_path(&path).run().unwrap_err(); | |
|
90 | ||
|
91 | // TODO do something better | |
|
92 | assert!(match err { | |
|
93 | FindRootError { kind } => match kind { | |
|
94 | FindRootErrorKind::RootNotFound(p) => p == path.to_path_buf(), | |
|
95 | _ => false, | |
|
96 | }, | |
|
97 | }) | |
|
98 | } | |
|
99 | ||
|
100 | #[test] | |
|
101 | fn dot_hg_in_current_path() { | |
|
102 | let tmp_dir = tempfile::tempdir().unwrap(); | |
|
103 | let root = tmp_dir.path(); | |
|
104 | fs::create_dir_all(root.join(".hg")).unwrap(); | |
|
105 | ||
|
106 | let result = FindRoot::new_from_path(&root).run().unwrap(); | |
|
107 | ||
|
108 | assert_eq!(result, root) | |
|
109 | } | |
|
110 | ||
|
111 | #[test] | |
|
112 | fn dot_hg_in_parent() { | |
|
113 | let tmp_dir = tempfile::tempdir().unwrap(); | |
|
114 | let root = tmp_dir.path(); | |
|
115 | fs::create_dir_all(root.join(".hg")).unwrap(); | |
|
116 | ||
|
117 | let result = | |
|
118 | FindRoot::new_from_path(&root.join("some/nested/directory")) | |
|
119 | .run() | |
|
120 | .unwrap(); | |
|
121 | ||
|
122 | assert_eq!(result, root) | |
|
123 | } | |
|
124 | } /* tests */ |
General Comments 0
You need to be logged in to leave comments.
Login now