##// END OF EJS Templates
rust: Add Repo::dirstate_map and use it in `rhg status`...
Simon Sapin -
r48768:81aedf1f default
parent child Browse files
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 &self,
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 parents = if self.has_dirstate_v2() {
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::dirstate_map::DirstateMap;
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) = hg::dirstate_tree::status::status(
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