Mercurial > public > mercurial-scm > hg
comparison rust/hg-core/src/repo.rs @ 46486:d7685105e504
rhg: Parse per-repository configuration
Differential Revision: https://phab.mercurial-scm.org/D9964
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Thu, 04 Feb 2021 15:04:53 +0100 |
parents | f031fe1c6ede |
children | d8730ff51d5a |
comparison
equal
deleted
inserted
replaced
46485:f031fe1c6ede | 46486:d7685105e504 |
---|---|
1 use crate::config::Config; | 1 use crate::config::{Config, ConfigError, ConfigParseError}; |
2 use crate::errors::{HgError, IoResultExt}; | 2 use crate::errors::{HgError, IoResultExt}; |
3 use crate::requirements; | 3 use crate::requirements; |
4 use crate::utils::files::get_path_from_bytes; | 4 use crate::utils::files::get_path_from_bytes; |
5 use memmap::{Mmap, MmapOptions}; | 5 use memmap::{Mmap, MmapOptions}; |
6 use std::collections::HashSet; | 6 use std::collections::HashSet; |
10 pub struct Repo { | 10 pub struct Repo { |
11 working_directory: PathBuf, | 11 working_directory: PathBuf, |
12 dot_hg: PathBuf, | 12 dot_hg: PathBuf, |
13 store: PathBuf, | 13 store: PathBuf, |
14 requirements: HashSet<String>, | 14 requirements: HashSet<String>, |
15 config: Config, | |
15 } | 16 } |
16 | 17 |
17 #[derive(Debug, derive_more::From)] | 18 #[derive(Debug, derive_more::From)] |
18 pub enum RepoFindError { | 19 pub enum RepoError { |
19 NotFoundInCurrentDirectoryOrAncestors { | 20 NotFound { |
20 current_directory: PathBuf, | 21 current_directory: PathBuf, |
21 }, | 22 }, |
22 #[from] | 23 #[from] |
24 ConfigParseError(ConfigParseError), | |
25 #[from] | |
23 Other(HgError), | 26 Other(HgError), |
27 } | |
28 | |
29 impl From<ConfigError> for RepoError { | |
30 fn from(error: ConfigError) -> Self { | |
31 match error { | |
32 ConfigError::Parse(error) => error.into(), | |
33 ConfigError::Other(error) => error.into(), | |
34 } | |
35 } | |
24 } | 36 } |
25 | 37 |
26 /// Filesystem access abstraction for the contents of a given "base" diretory | 38 /// Filesystem access abstraction for the contents of a given "base" diretory |
27 #[derive(Clone, Copy)] | 39 #[derive(Clone, Copy)] |
28 pub(crate) struct Vfs<'a> { | 40 pub(crate) struct Vfs<'a> { |
30 } | 42 } |
31 | 43 |
32 impl Repo { | 44 impl Repo { |
33 /// Search the current directory and its ancestores for a repository: | 45 /// Search the current directory and its ancestores for a repository: |
34 /// a working directory that contains a `.hg` sub-directory. | 46 /// a working directory that contains a `.hg` sub-directory. |
35 pub fn find(config: &Config) -> Result<Self, RepoFindError> { | 47 pub fn find(config: &Config) -> Result<Self, RepoError> { |
36 let current_directory = crate::utils::current_dir()?; | 48 let current_directory = crate::utils::current_dir()?; |
37 // ancestors() is inclusive: it first yields `current_directory` as-is. | 49 // ancestors() is inclusive: it first yields `current_directory` as-is. |
38 for ancestor in current_directory.ancestors() { | 50 for ancestor in current_directory.ancestors() { |
39 if ancestor.join(".hg").is_dir() { | 51 if ancestor.join(".hg").is_dir() { |
40 return Ok(Self::new_at_path(ancestor.to_owned(), config)?); | 52 return Ok(Self::new_at_path(ancestor.to_owned(), config)?); |
41 } | 53 } |
42 } | 54 } |
43 Err(RepoFindError::NotFoundInCurrentDirectoryOrAncestors { | 55 Err(RepoError::NotFound { current_directory }) |
44 current_directory, | |
45 }) | |
46 } | 56 } |
47 | 57 |
48 /// To be called after checking that `.hg` is a sub-directory | 58 /// To be called after checking that `.hg` is a sub-directory |
49 fn new_at_path( | 59 fn new_at_path( |
50 working_directory: PathBuf, | 60 working_directory: PathBuf, |
51 config: &Config, | 61 config: &Config, |
52 ) -> Result<Self, HgError> { | 62 ) -> Result<Self, RepoError> { |
53 let dot_hg = working_directory.join(".hg"); | 63 let dot_hg = working_directory.join(".hg"); |
64 | |
65 let mut repo_config_files = Vec::new(); | |
66 repo_config_files.push(dot_hg.join("hgrc")); | |
67 repo_config_files.push(dot_hg.join("hgrc-not-shared")); | |
54 | 68 |
55 let hg_vfs = Vfs { base: &dot_hg }; | 69 let hg_vfs = Vfs { base: &dot_hg }; |
56 let mut reqs = requirements::load_if_exists(hg_vfs)?; | 70 let mut reqs = requirements::load_if_exists(hg_vfs)?; |
57 let relative = | 71 let relative = |
58 reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT); | 72 reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT); |
87 } | 101 } |
88 if !shared_path.is_dir() { | 102 if !shared_path.is_dir() { |
89 return Err(HgError::corrupted(format!( | 103 return Err(HgError::corrupted(format!( |
90 ".hg/sharedpath points to nonexistent directory {}", | 104 ".hg/sharedpath points to nonexistent directory {}", |
91 shared_path.display() | 105 shared_path.display() |
92 ))); | 106 )) |
107 .into()); | |
93 } | 108 } |
94 | 109 |
95 store_path = shared_path.join("store"); | 110 store_path = shared_path.join("store"); |
96 | 111 |
97 let source_is_share_safe = | 112 let source_is_share_safe = |
98 requirements::load(Vfs { base: &shared_path })? | 113 requirements::load(Vfs { base: &shared_path })? |
99 .contains(requirements::SHARESAFE_REQUIREMENT); | 114 .contains(requirements::SHARESAFE_REQUIREMENT); |
100 | 115 |
101 if share_safe && !source_is_share_safe { | 116 if share_safe && !source_is_share_safe { |
102 return Err(match config.get(b"safe-mismatch", b"source-not-safe") { | 117 return Err(match config |
118 .get(b"safe-mismatch", b"source-not-safe") | |
119 { | |
103 Some(b"abort") | None => HgError::abort( | 120 Some(b"abort") | None => HgError::abort( |
104 "share source does not support share-safe requirement" | 121 "share source does not support share-safe requirement", |
105 ), | 122 ), |
106 _ => HgError::unsupported("share-safe downgrade") | 123 _ => HgError::unsupported("share-safe downgrade"), |
107 }); | 124 } |
125 .into()); | |
108 } else if source_is_share_safe && !share_safe { | 126 } else if source_is_share_safe && !share_safe { |
109 return Err( | 127 return Err( |
110 match config.get(b"safe-mismatch", b"source-safe") { | 128 match config.get(b"safe-mismatch", b"source-safe") { |
111 Some(b"abort") | None => HgError::abort( | 129 Some(b"abort") | None => HgError::abort( |
112 "version mismatch: source uses share-safe \ | 130 "version mismatch: source uses share-safe \ |
113 functionality while the current share does not", | 131 functionality while the current share does not", |
114 ), | 132 ), |
115 _ => HgError::unsupported("share-safe upgrade"), | 133 _ => HgError::unsupported("share-safe upgrade"), |
116 }, | 134 } |
135 .into(), | |
117 ); | 136 ); |
118 } | 137 } |
119 } | 138 |
139 if share_safe { | |
140 repo_config_files.insert(0, shared_path.join("hgrc")) | |
141 } | |
142 } | |
143 | |
144 let repo_config = config.combine_with_repo(&repo_config_files)?; | |
120 | 145 |
121 let repo = Self { | 146 let repo = Self { |
122 requirements: reqs, | 147 requirements: reqs, |
123 working_directory, | 148 working_directory, |
124 store: store_path, | 149 store: store_path, |
125 dot_hg, | 150 dot_hg, |
151 config: repo_config, | |
126 }; | 152 }; |
127 | 153 |
128 requirements::check(&repo)?; | 154 requirements::check(&repo)?; |
129 | 155 |
130 Ok(repo) | 156 Ok(repo) |
134 &self.working_directory | 160 &self.working_directory |
135 } | 161 } |
136 | 162 |
137 pub fn requirements(&self) -> &HashSet<String> { | 163 pub fn requirements(&self) -> &HashSet<String> { |
138 &self.requirements | 164 &self.requirements |
165 } | |
166 | |
167 pub fn config(&self) -> &Config { | |
168 &self.config | |
139 } | 169 } |
140 | 170 |
141 /// For accessing repository files (in `.hg`), except for the store | 171 /// For accessing repository files (in `.hg`), except for the store |
142 /// (`.hg/store`). | 172 /// (`.hg/store`). |
143 pub(crate) fn hg_vfs(&self) -> Vfs<'_> { | 173 pub(crate) fn hg_vfs(&self) -> Vfs<'_> { |