##// END OF EJS Templates
hg-core: add FindRoot operation to find repository root path...
Antoine Cezar -
r45502:5965efb6 default
parent child Browse files
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 */
@@ -1,3 +1,6 b''
1 mod find_root;
2 pub use find_root::{FindRoot, FindRootError, FindRootErrorKind};
3
1 /// An interface for high-level hg operations.
4 /// An interface for high-level hg operations.
2 ///
5 ///
3 /// A distinction is made between operation and commands.
6 /// A distinction is made between operation and commands.
General Comments 0
You need to be logged in to leave comments. Login now