Show More
@@ -19,7 +19,7 b' pub mod dirstate_map;' | |||||
19 | pub mod parsers; |
|
19 | pub mod parsers; | |
20 | pub mod status; |
|
20 | pub mod status; | |
21 |
|
21 | |||
22 | #[derive(Debug, PartialEq, Clone, BytesCast)] |
|
22 | #[derive(Debug, PartialEq, Copy, Clone, BytesCast)] | |
23 | #[repr(C)] |
|
23 | #[repr(C)] | |
24 | pub struct DirstateParents { |
|
24 | pub struct DirstateParents { | |
25 | pub p1: Node, |
|
25 | pub p1: Node, |
@@ -1,10 +1,16 b'' | |||||
1 | use crate::config::{Config, ConfigError, ConfigParseError}; |
|
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 | use crate::errors::HgError; |
|
5 | use crate::errors::HgError; | |
|
6 | use crate::errors::HgResultExt; | |||
3 | use crate::exit_codes; |
|
7 | use crate::exit_codes; | |
4 | use crate::requirements; |
|
8 | use crate::requirements; | |
5 | use crate::utils::files::get_path_from_bytes; |
|
9 | use crate::utils::files::get_path_from_bytes; | |
6 | use crate::utils::SliceExt; |
|
10 | use crate::utils::SliceExt; | |
7 | use crate::vfs::{is_dir, is_file, Vfs}; |
|
11 | use crate::vfs::{is_dir, is_file, Vfs}; | |
|
12 | use crate::DirstateError; | |||
|
13 | use std::cell::{Cell, Ref, RefCell, RefMut}; | |||
8 | use std::collections::HashSet; |
|
14 | use std::collections::HashSet; | |
9 | use std::path::{Path, PathBuf}; |
|
15 | use std::path::{Path, PathBuf}; | |
10 |
|
16 | |||
@@ -15,6 +21,9 b' pub struct Repo {' | |||||
15 | store: PathBuf, |
|
21 | store: PathBuf, | |
16 | requirements: HashSet<String>, |
|
22 | requirements: HashSet<String>, | |
17 | config: Config, |
|
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 | #[derive(Debug, derive_more::From)] |
|
29 | #[derive(Debug, derive_more::From)] | |
@@ -186,6 +195,8 b' impl Repo {' | |||||
186 | store: store_path, |
|
195 | store: store_path, | |
187 | dot_hg, |
|
196 | dot_hg, | |
188 | config: repo_config, |
|
197 | config: repo_config, | |
|
198 | dirstate_parents: Cell::new(None), | |||
|
199 | dirstate_map: RefCell::new(None), | |||
189 | }; |
|
200 | }; | |
190 |
|
201 | |||
191 | requirements::check(&repo)?; |
|
202 | requirements::check(&repo)?; | |
@@ -228,19 +239,101 b' impl Repo {' | |||||
228 | .contains(requirements::DIRSTATE_V2_REQUIREMENT) |
|
239 | .contains(requirements::DIRSTATE_V2_REQUIREMENT) | |
229 | } |
|
240 | } | |
230 |
|
241 | |||
231 | pub fn dirstate_parents( |
|
242 | fn dirstate_file_contents(&self) -> Result<Vec<u8>, HgError> { | |
232 |
|
|
243 | Ok(self | |
233 | ) -> Result<crate::dirstate::DirstateParents, HgError> { |
|
244 | .hg_vfs() | |
234 | let dirstate = self.hg_vfs().mmap_open("dirstate")?; |
|
245 | .read("dirstate") | |
235 | if dirstate.is_empty() { |
|
246 | .io_not_found_as_none()? | |
236 | return Ok(crate::dirstate::DirstateParents::NULL); |
|
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 | crate::dirstate_tree::on_disk::read_docket(&dirstate)?.parents() |
|
258 | crate::dirstate_tree::on_disk::read_docket(&dirstate)?.parents() | |
240 | } else { |
|
259 | } else { | |
241 | crate::dirstate::parsers::parse_dirstate_parents(&dirstate)? |
|
260 | crate::dirstate::parsers::parse_dirstate_parents(&dirstate)? | |
242 | .clone() |
|
261 | .clone() | |
243 | }; |
|
262 | }; | |
|
263 | self.dirstate_parents.set(Some(parents)); | |||
244 | Ok(parents) |
|
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 | use crate::ui::Ui; |
|
9 | use crate::ui::Ui; | |
10 | use clap::{Arg, SubCommand}; |
|
10 | use clap::{Arg, SubCommand}; | |
11 | use hg; |
|
11 | use hg; | |
12 |
use hg::dirstate_tree::di |
|
12 | use hg::dirstate_tree::dispatch::DirstateMapMethods; | |
13 | use hg::dirstate_tree::on_disk; |
|
|||
14 | use hg::errors::HgResultExt; |
|
|||
15 | use hg::errors::IoResultExt; |
|
13 | use hg::errors::IoResultExt; | |
16 | use hg::matchers::AlwaysMatcher; |
|
14 | use hg::matchers::AlwaysMatcher; | |
17 | use hg::operations::cat; |
|
15 | use hg::operations::cat; | |
@@ -166,40 +164,7 b' pub fn run(invocation: &crate::CliInvoca' | |||||
166 | }; |
|
164 | }; | |
167 |
|
165 | |||
168 | let repo = invocation.repo?; |
|
166 | let repo = invocation.repo?; | |
169 | let dirstate_data_mmap; |
|
167 | let mut dmap = repo.dirstate_map_mut()?; | |
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 | }; |
|
|||
203 |
|
168 | |||
204 | let options = StatusOptions { |
|
169 | let options = StatusOptions { | |
205 | // TODO should be provided by the dirstate parsing and |
|
170 | // TODO should be provided by the dirstate parsing and | |
@@ -216,8 +181,7 b' pub fn run(invocation: &crate::CliInvoca' | |||||
216 | collect_traversed_dirs: false, |
|
181 | collect_traversed_dirs: false, | |
217 | }; |
|
182 | }; | |
218 | let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded |
|
183 | let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded | |
219 |
let (mut ds_status, pattern_warnings) = |
|
184 | let (mut ds_status, pattern_warnings) = dmap.status( | |
220 | &mut dmap, |
|
|||
221 | &AlwaysMatcher, |
|
185 | &AlwaysMatcher, | |
222 | repo.working_directory_path().to_owned(), |
|
186 | repo.working_directory_path().to_owned(), | |
223 | vec![ignore_file], |
|
187 | vec![ignore_file], | |
@@ -239,13 +203,7 b' pub fn run(invocation: &crate::CliInvoca' | |||||
239 | if !ds_status.unsure.is_empty() |
|
203 | if !ds_status.unsure.is_empty() | |
240 | && (display_states.modified || display_states.clean) |
|
204 | && (display_states.modified || display_states.clean) | |
241 | { |
|
205 | { | |
242 | let p1: Node = parents |
|
206 | let p1: Node = repo.dirstate_parents()?.p1.into(); | |
243 | .expect( |
|
|||
244 | "Dirstate with no parents should not list any file to |
|
|||
245 | be rechecked for modifications", |
|
|||
246 | ) |
|
|||
247 | .p1 |
|
|||
248 | .into(); |
|
|||
249 | let p1_hex = format!("{:x}", p1); |
|
207 | let p1_hex = format!("{:x}", p1); | |
250 | for to_check in ds_status.unsure { |
|
208 | for to_check in ds_status.unsure { | |
251 | if cat_file_is_modified(repo, &to_check, &p1_hex)? { |
|
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