Show More
@@ -19,7 +19,7 b' pub mod dirstate_map;' | |||
|
19 | 19 | pub mod parsers; |
|
20 | 20 | pub mod status; |
|
21 | 21 | |
|
22 | #[derive(Debug, PartialEq, Clone, BytesCast)] | |
|
22 | #[derive(Debug, PartialEq, Copy, Clone, BytesCast)] | |
|
23 | 23 | #[repr(C)] |
|
24 | 24 | pub struct DirstateParents { |
|
25 | 25 | pub p1: Node, |
@@ -1,10 +1,16 b'' | |||
|
1 | 1 | use crate::config::{Config, ConfigError, ConfigParseError}; |
|
2 | use crate::dirstate::DirstateParents; | |
|
3 | use crate::dirstate_tree::dirstate_map::DirstateMap; | |
|
4 | use crate::dirstate_tree::owning::OwningDirstateMap; | |
|
2 | 5 | use crate::errors::HgError; |
|
6 | use crate::errors::HgResultExt; | |
|
3 | 7 | use crate::exit_codes; |
|
4 | 8 | use crate::requirements; |
|
5 | 9 | use crate::utils::files::get_path_from_bytes; |
|
6 | 10 | use crate::utils::SliceExt; |
|
7 | 11 | use crate::vfs::{is_dir, is_file, Vfs}; |
|
12 | use crate::DirstateError; | |
|
13 | use std::cell::{Cell, Ref, RefCell, RefMut}; | |
|
8 | 14 | use std::collections::HashSet; |
|
9 | 15 | use std::path::{Path, PathBuf}; |
|
10 | 16 | |
@@ -15,6 +21,9 b' pub struct Repo {' | |||
|
15 | 21 | store: PathBuf, |
|
16 | 22 | requirements: HashSet<String>, |
|
17 | 23 | config: Config, |
|
24 | // None means not known/initialized yet | |
|
25 | dirstate_parents: Cell<Option<DirstateParents>>, | |
|
26 | dirstate_map: RefCell<Option<OwningDirstateMap>>, | |
|
18 | 27 | } |
|
19 | 28 | |
|
20 | 29 | #[derive(Debug, derive_more::From)] |
@@ -186,6 +195,8 b' impl Repo {' | |||
|
186 | 195 | store: store_path, |
|
187 | 196 | dot_hg, |
|
188 | 197 | config: repo_config, |
|
198 | dirstate_parents: Cell::new(None), | |
|
199 | dirstate_map: RefCell::new(None), | |
|
189 | 200 | }; |
|
190 | 201 | |
|
191 | 202 | requirements::check(&repo)?; |
@@ -228,19 +239,101 b' impl Repo {' | |||
|
228 | 239 | .contains(requirements::DIRSTATE_V2_REQUIREMENT) |
|
229 | 240 | } |
|
230 | 241 | |
|
231 | pub fn dirstate_parents( | |
|
232 |
|
|
|
233 | ) -> Result<crate::dirstate::DirstateParents, HgError> { | |
|
234 | let dirstate = self.hg_vfs().mmap_open("dirstate")?; | |
|
235 | if dirstate.is_empty() { | |
|
236 | return Ok(crate::dirstate::DirstateParents::NULL); | |
|
242 | fn dirstate_file_contents(&self) -> Result<Vec<u8>, HgError> { | |
|
243 | Ok(self | |
|
244 | .hg_vfs() | |
|
245 | .read("dirstate") | |
|
246 | .io_not_found_as_none()? | |
|
247 | .unwrap_or(Vec::new())) | |
|
248 | } | |
|
249 | ||
|
250 | pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> { | |
|
251 | if let Some(parents) = self.dirstate_parents.get() { | |
|
252 | return Ok(parents); | |
|
237 | 253 | } |
|
238 |
let |
|
|
254 | let dirstate = self.dirstate_file_contents()?; | |
|
255 | let parents = if dirstate.is_empty() { | |
|
256 | DirstateParents::NULL | |
|
257 | } else if self.has_dirstate_v2() { | |
|
239 | 258 | crate::dirstate_tree::on_disk::read_docket(&dirstate)?.parents() |
|
240 | 259 | } else { |
|
241 | 260 | crate::dirstate::parsers::parse_dirstate_parents(&dirstate)? |
|
242 | 261 | .clone() |
|
243 | 262 | }; |
|
263 | self.dirstate_parents.set(Some(parents)); | |
|
244 | 264 | Ok(parents) |
|
245 | 265 | } |
|
266 | ||
|
267 | fn new_dirstate_map(&self) -> Result<OwningDirstateMap, DirstateError> { | |
|
268 | let dirstate_file_contents = self.dirstate_file_contents()?; | |
|
269 | if dirstate_file_contents.is_empty() { | |
|
270 | self.dirstate_parents.set(Some(DirstateParents::NULL)); | |
|
271 | Ok(OwningDirstateMap::new_empty(Vec::new())) | |
|
272 | } else if self.has_dirstate_v2() { | |
|
273 | let docket = crate::dirstate_tree::on_disk::read_docket( | |
|
274 | &dirstate_file_contents, | |
|
275 | )?; | |
|
276 | self.dirstate_parents.set(Some(docket.parents())); | |
|
277 | let data_size = docket.data_size(); | |
|
278 | let metadata = docket.tree_metadata(); | |
|
279 | let mut map = if let Some(data_mmap) = self | |
|
280 | .hg_vfs() | |
|
281 | .mmap_open(docket.data_filename()) | |
|
282 | .io_not_found_as_none()? | |
|
283 | { | |
|
284 | OwningDirstateMap::new_empty(MmapWrapper(data_mmap)) | |
|
285 | } else { | |
|
286 | OwningDirstateMap::new_empty(Vec::new()) | |
|
287 | }; | |
|
288 | let (on_disk, placeholder) = map.get_mut_pair(); | |
|
289 | *placeholder = DirstateMap::new_v2(on_disk, data_size, metadata)?; | |
|
290 | Ok(map) | |
|
291 | } else { | |
|
292 | let mut map = OwningDirstateMap::new_empty(dirstate_file_contents); | |
|
293 | let (on_disk, placeholder) = map.get_mut_pair(); | |
|
294 | let (inner, parents) = DirstateMap::new_v1(on_disk)?; | |
|
295 | self.dirstate_parents | |
|
296 | .set(Some(parents.unwrap_or(DirstateParents::NULL))); | |
|
297 | *placeholder = inner; | |
|
298 | Ok(map) | |
|
299 | } | |
|
300 | } | |
|
301 | ||
|
302 | pub fn dirstate_map( | |
|
303 | &self, | |
|
304 | ) -> Result<Ref<OwningDirstateMap>, DirstateError> { | |
|
305 | let mut borrowed = self.dirstate_map.borrow(); | |
|
306 | if borrowed.is_none() { | |
|
307 | drop(borrowed); | |
|
308 | // Only use `borrow_mut` if it is really needed to avoid panic in | |
|
309 | // case there is another outstanding borrow but mutation is not | |
|
310 | // needed. | |
|
311 | *self.dirstate_map.borrow_mut() = Some(self.new_dirstate_map()?); | |
|
312 | borrowed = self.dirstate_map.borrow() | |
|
313 | } | |
|
314 | Ok(Ref::map(borrowed, |option| option.as_ref().unwrap())) | |
|
315 | } | |
|
316 | ||
|
317 | pub fn dirstate_map_mut( | |
|
318 | &self, | |
|
319 | ) -> Result<RefMut<OwningDirstateMap>, DirstateError> { | |
|
320 | let mut borrowed = self.dirstate_map.borrow_mut(); | |
|
321 | if borrowed.is_none() { | |
|
322 | *borrowed = Some(self.new_dirstate_map()?); | |
|
323 | } | |
|
324 | Ok(RefMut::map(borrowed, |option| option.as_mut().unwrap())) | |
|
325 | } | |
|
246 | 326 | } |
|
327 | ||
|
328 | // TODO: remove this when https://github.com/RazrFalcon/memmap2-rs/pull/22 is on crates.io | |
|
329 | struct MmapWrapper(memmap2::Mmap); | |
|
330 | ||
|
331 | impl std::ops::Deref for MmapWrapper { | |
|
332 | type Target = [u8]; | |
|
333 | ||
|
334 | fn deref(&self) -> &[u8] { | |
|
335 | self.0.deref() | |
|
336 | } | |
|
337 | } | |
|
338 | ||
|
339 | unsafe impl stable_deref_trait::StableDeref for MmapWrapper {} |
@@ -9,9 +9,7 b' use crate::error::CommandError;' | |||
|
9 | 9 | use crate::ui::Ui; |
|
10 | 10 | use clap::{Arg, SubCommand}; |
|
11 | 11 | use hg; |
|
12 |
use hg::dirstate_tree::di |
|
|
13 | use hg::dirstate_tree::on_disk; | |
|
14 | use hg::errors::HgResultExt; | |
|
12 | use hg::dirstate_tree::dispatch::DirstateMapMethods; | |
|
15 | 13 | use hg::errors::IoResultExt; |
|
16 | 14 | use hg::matchers::AlwaysMatcher; |
|
17 | 15 | use hg::operations::cat; |
@@ -166,40 +164,7 b' pub fn run(invocation: &crate::CliInvoca' | |||
|
166 | 164 | }; |
|
167 | 165 | |
|
168 | 166 | let repo = invocation.repo?; |
|
169 | let dirstate_data_mmap; | |
|
170 | let (mut dmap, parents) = if repo.has_dirstate_v2() { | |
|
171 | let docket_data = | |
|
172 | repo.hg_vfs().read("dirstate").io_not_found_as_none()?; | |
|
173 | let parents; | |
|
174 | let dirstate_data; | |
|
175 | let data_size; | |
|
176 | let docket; | |
|
177 | let tree_metadata; | |
|
178 | if let Some(docket_data) = &docket_data { | |
|
179 | docket = on_disk::read_docket(docket_data)?; | |
|
180 | tree_metadata = docket.tree_metadata(); | |
|
181 | parents = Some(docket.parents()); | |
|
182 | data_size = docket.data_size(); | |
|
183 | dirstate_data_mmap = repo | |
|
184 | .hg_vfs() | |
|
185 | .mmap_open(docket.data_filename()) | |
|
186 | .io_not_found_as_none()?; | |
|
187 | dirstate_data = dirstate_data_mmap.as_deref().unwrap_or(b""); | |
|
188 | } else { | |
|
189 | parents = None; | |
|
190 | tree_metadata = b""; | |
|
191 | data_size = 0; | |
|
192 | dirstate_data = b""; | |
|
193 | } | |
|
194 | let dmap = | |
|
195 | DirstateMap::new_v2(dirstate_data, data_size, tree_metadata)?; | |
|
196 | (dmap, parents) | |
|
197 | } else { | |
|
198 | dirstate_data_mmap = | |
|
199 | repo.hg_vfs().mmap_open("dirstate").io_not_found_as_none()?; | |
|
200 | let dirstate_data = dirstate_data_mmap.as_deref().unwrap_or(b""); | |
|
201 | DirstateMap::new_v1(dirstate_data)? | |
|
202 | }; | |
|
167 | let mut dmap = repo.dirstate_map_mut()?; | |
|
203 | 168 | |
|
204 | 169 | let options = StatusOptions { |
|
205 | 170 | // TODO should be provided by the dirstate parsing and |
@@ -216,8 +181,7 b' pub fn run(invocation: &crate::CliInvoca' | |||
|
216 | 181 | collect_traversed_dirs: false, |
|
217 | 182 | }; |
|
218 | 183 | let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded |
|
219 |
let (mut ds_status, pattern_warnings) = |
|
|
220 | &mut dmap, | |
|
184 | let (mut ds_status, pattern_warnings) = dmap.status( | |
|
221 | 185 | &AlwaysMatcher, |
|
222 | 186 | repo.working_directory_path().to_owned(), |
|
223 | 187 | vec![ignore_file], |
@@ -239,13 +203,7 b' pub fn run(invocation: &crate::CliInvoca' | |||
|
239 | 203 | if !ds_status.unsure.is_empty() |
|
240 | 204 | && (display_states.modified || display_states.clean) |
|
241 | 205 | { |
|
242 | let p1: Node = parents | |
|
243 | .expect( | |
|
244 | "Dirstate with no parents should not list any file to | |
|
245 | be rechecked for modifications", | |
|
246 | ) | |
|
247 | .p1 | |
|
248 | .into(); | |
|
206 | let p1: Node = repo.dirstate_parents()?.p1.into(); | |
|
249 | 207 | let p1_hex = format!("{:x}", p1); |
|
250 | 208 | for to_check in ds_status.unsure { |
|
251 | 209 | if cat_file_is_modified(repo, &to_check, &p1_hex)? { |
General Comments 0
You need to be logged in to leave comments.
Login now