Mercurial > public > mercurial-scm > hg
comparison rust/hg-core/src/operations/find_root.rs @ 44980:5965efb609b6
hg-core: add FindRoot operation to find repository root path
Differential Revision: https://phab.mercurial-scm.org/D8609
author | Antoine Cezar <antoine.cezar@octobus.net> |
---|---|
date | Fri, 05 Jun 2020 08:48:09 +0200 |
parents | |
children | 452ece5654c5 |
comparison
equal
deleted
inserted
replaced
44974:a46e36b82461 | 44980:5965efb609b6 |
---|---|
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 */ |