Show More
@@ -7,6 +7,7 b'' | |||
|
7 | 7 | |
|
8 | 8 | use crate::dirstate_tree::on_disk::DirstateV2ParseError; |
|
9 | 9 | use crate::errors::HgError; |
|
10 | use crate::revlog::node::NULL_NODE; | |
|
10 | 11 | use crate::revlog::Node; |
|
11 | 12 | use crate::utils::hg_path::{HgPath, HgPathBuf}; |
|
12 | 13 | use crate::FastHashMap; |
@@ -25,6 +26,13 b' pub struct DirstateParents {' | |||
|
25 | 26 | pub p2: Node, |
|
26 | 27 | } |
|
27 | 28 | |
|
29 | impl DirstateParents { | |
|
30 | pub const NULL: Self = Self { | |
|
31 | p1: NULL_NODE, | |
|
32 | p2: NULL_NODE, | |
|
33 | }; | |
|
34 | } | |
|
35 | ||
|
28 | 36 | /// The C implementation uses all signed types. This will be an issue |
|
29 | 37 | /// either when 4GB+ source files are commonplace or in 2038, whichever |
|
30 | 38 | /// comes first. |
@@ -2,4 +2,4 b' pub mod dirstate_map;' | |||
|
2 | 2 | pub mod dispatch; |
|
3 | 3 | pub mod on_disk; |
|
4 | 4 | pub mod path_with_basename; |
|
5 | mod status; | |
|
5 | pub mod status; |
@@ -167,6 +167,16 b' impl From<DirstateV2ParseError> for crat' | |||
|
167 | 167 | } |
|
168 | 168 | } |
|
169 | 169 | |
|
170 | fn read_header(on_disk: &[u8]) -> Result<&Header, DirstateV2ParseError> { | |
|
171 | let (header, _) = | |
|
172 | Header::from_bytes(on_disk).map_err(|_| DirstateV2ParseError)?; | |
|
173 | if header.marker == *V2_FORMAT_MARKER { | |
|
174 | Ok(header) | |
|
175 | } else { | |
|
176 | Err(DirstateV2ParseError) | |
|
177 | } | |
|
178 | } | |
|
179 | ||
|
170 | 180 | pub(super) fn read<'on_disk>( |
|
171 | 181 | on_disk: &'on_disk [u8], |
|
172 | 182 | ) -> Result< |
@@ -176,27 +186,19 b" pub(super) fn read<'on_disk>(" | |||
|
176 | 186 | if on_disk.is_empty() { |
|
177 | 187 | return Ok((DirstateMap::empty(on_disk), None)); |
|
178 | 188 | } |
|
179 | let (header, _) = | |
|
180 | Header::from_bytes(on_disk).map_err(|_| DirstateV2ParseError)?; | |
|
181 | let Header { | |
|
182 | marker, | |
|
183 | parents, | |
|
184 | root, | |
|
185 | nodes_with_entry_count, | |
|
186 | nodes_with_copy_source_count, | |
|
187 | } = header; | |
|
188 | if marker != V2_FORMAT_MARKER { | |
|
189 | return Err(DirstateV2ParseError); | |
|
190 | } | |
|
189 | let header = read_header(on_disk)?; | |
|
191 | 190 | let dirstate_map = DirstateMap { |
|
192 | 191 | on_disk, |
|
193 | 192 | root: dirstate_map::ChildNodes::OnDisk(read_slice::<Node>( |
|
194 |
on_disk, |
|
|
193 | on_disk, | |
|
194 | header.root, | |
|
195 | 195 | )?), |
|
196 | nodes_with_entry_count: nodes_with_entry_count.get(), | |
|
197 |
nodes_with_copy_source_count: |
|
|
196 | nodes_with_entry_count: header.nodes_with_entry_count.get(), | |
|
197 | nodes_with_copy_source_count: header | |
|
198 | .nodes_with_copy_source_count | |
|
199 | .get(), | |
|
198 | 200 | }; |
|
199 | let parents = Some(parents.clone()); | |
|
201 | let parents = Some(header.parents.clone()); | |
|
200 | 202 | Ok((dirstate_map, parents)) |
|
201 | 203 | } |
|
202 | 204 | |
@@ -414,6 +416,35 b' where' | |||
|
414 | 416 | .ok_or_else(|| DirstateV2ParseError) |
|
415 | 417 | } |
|
416 | 418 | |
|
419 | pub(crate) fn parse_dirstate_parents( | |
|
420 | on_disk: &[u8], | |
|
421 | ) -> Result<&DirstateParents, HgError> { | |
|
422 | Ok(&read_header(on_disk)?.parents) | |
|
423 | } | |
|
424 | ||
|
425 | pub(crate) fn for_each_tracked_path<'on_disk>( | |
|
426 | on_disk: &'on_disk [u8], | |
|
427 | mut f: impl FnMut(&'on_disk HgPath), | |
|
428 | ) -> Result<(), DirstateV2ParseError> { | |
|
429 | let header = read_header(on_disk)?; | |
|
430 | fn recur<'on_disk>( | |
|
431 | on_disk: &'on_disk [u8], | |
|
432 | nodes: Slice, | |
|
433 | f: &mut impl FnMut(&'on_disk HgPath), | |
|
434 | ) -> Result<(), DirstateV2ParseError> { | |
|
435 | for node in read_slice::<Node>(on_disk, nodes)? { | |
|
436 | if let Some(state) = node.state()? { | |
|
437 | if state.is_tracked() { | |
|
438 | f(node.full_path(on_disk)?) | |
|
439 | } | |
|
440 | } | |
|
441 | recur(on_disk, node.children, f)? | |
|
442 | } | |
|
443 | Ok(()) | |
|
444 | } | |
|
445 | recur(on_disk, header.root, &mut f) | |
|
446 | } | |
|
447 | ||
|
417 | 448 | pub(super) fn write( |
|
418 | 449 | dirstate_map: &mut DirstateMap, |
|
419 | 450 | parents: DirstateParents, |
@@ -6,6 +6,7 b'' | |||
|
6 | 6 | // GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | use crate::dirstate::parsers::parse_dirstate_entries; |
|
9 | use crate::dirstate_tree::on_disk::for_each_tracked_path; | |
|
9 | 10 | use crate::errors::HgError; |
|
10 | 11 | use crate::repo::Repo; |
|
11 | 12 | use crate::revlog::changelog::Changelog; |
@@ -13,6 +14,7 b' use crate::revlog::manifest::{Manifest, ' | |||
|
13 | 14 | use crate::revlog::node::Node; |
|
14 | 15 | use crate::revlog::revlog::RevlogError; |
|
15 | 16 | use crate::utils::hg_path::HgPath; |
|
17 | use crate::DirstateError; | |
|
16 | 18 | use rayon::prelude::*; |
|
17 | 19 | |
|
18 | 20 | /// List files under Mercurial control in the working directory |
@@ -20,25 +22,34 b' use rayon::prelude::*;' | |||
|
20 | 22 | pub struct Dirstate { |
|
21 | 23 | /// The `dirstate` content. |
|
22 | 24 | content: Vec<u8>, |
|
25 | dirstate_v2: bool, | |
|
23 | 26 | } |
|
24 | 27 | |
|
25 | 28 | impl Dirstate { |
|
26 | 29 | pub fn new(repo: &Repo) -> Result<Self, HgError> { |
|
27 | let content = repo.hg_vfs().read("dirstate")?; | |
|
28 | Ok(Self { content }) | |
|
30 | Ok(Self { | |
|
31 | content: repo.hg_vfs().read("dirstate")?, | |
|
32 | dirstate_v2: repo.has_dirstate_v2(), | |
|
33 | }) | |
|
29 | 34 | } |
|
30 | 35 | |
|
31 |
pub fn tracked_files(&self) -> Result<Vec<&HgPath>, |
|
|
36 | pub fn tracked_files(&self) -> Result<Vec<&HgPath>, DirstateError> { | |
|
32 | 37 | let mut files = Vec::new(); |
|
33 | let _parents = parse_dirstate_entries( | |
|
34 |
|
|
|
35 | |path, entry, _copy_source| { | |
|
36 | if entry.state.is_tracked() { | |
|
37 | files.push(path) | |
|
38 |
|
|
|
39 | Ok(()) | |
|
40 | }, | |
|
41 | )?; | |
|
38 | if !self.content.is_empty() { | |
|
39 | if self.dirstate_v2 { | |
|
40 | for_each_tracked_path(&self.content, |path| files.push(path))? | |
|
41 | } else { | |
|
42 | let _parents = parse_dirstate_entries( | |
|
43 | &self.content, | |
|
44 | |path, entry, _copy_source| { | |
|
45 | if entry.state.is_tracked() { | |
|
46 | files.push(path) | |
|
47 | } | |
|
48 | Ok(()) | |
|
49 | }, | |
|
50 | )?; | |
|
51 | } | |
|
52 | } | |
|
42 | 53 | files.par_sort_unstable(); |
|
43 | 54 | Ok(files) |
|
44 | 55 | } |
@@ -218,12 +218,23 b' impl Repo {' | |||
|
218 | 218 | } |
|
219 | 219 | } |
|
220 | 220 | |
|
221 | pub fn has_dirstate_v2(&self) -> bool { | |
|
222 | self.requirements | |
|
223 | .contains(requirements::DIRSTATE_V2_REQUIREMENT) | |
|
224 | } | |
|
225 | ||
|
221 | 226 | pub fn dirstate_parents( |
|
222 | 227 | &self, |
|
223 | 228 | ) -> Result<crate::dirstate::DirstateParents, HgError> { |
|
224 | 229 | let dirstate = self.hg_vfs().mmap_open("dirstate")?; |
|
225 | let parents = | |
|
226 |
crate::dirstate:: |
|
|
230 | if dirstate.is_empty() { | |
|
231 | return Ok(crate::dirstate::DirstateParents::NULL); | |
|
232 | } | |
|
233 | let parents = if self.has_dirstate_v2() { | |
|
234 | crate::dirstate_tree::on_disk::parse_dirstate_parents(&dirstate)? | |
|
235 | } else { | |
|
236 | crate::dirstate::parsers::parse_dirstate_parents(&dirstate)? | |
|
237 | }; | |
|
227 | 238 | Ok(parents.clone()) |
|
228 | 239 | } |
|
229 | 240 | } |
@@ -82,6 +82,7 b' const SUPPORTED: &[&str] = &[' | |||
|
82 | 82 | SPARSEREVLOG_REQUIREMENT, |
|
83 | 83 | RELATIVE_SHARED_REQUIREMENT, |
|
84 | 84 | REVLOG_COMPRESSION_ZSTD, |
|
85 | DIRSTATE_V2_REQUIREMENT, | |
|
85 | 86 | // As of this writing everything rhg does is read-only. |
|
86 | 87 | // When it starts writing to the repository, itβll need to either keep the |
|
87 | 88 | // persistent nodemap up to date or remove this entry: |
@@ -90,6 +91,8 b' const SUPPORTED: &[&str] = &[' | |||
|
90 | 91 | |
|
91 | 92 | // Copied from mercurial/requirements.py: |
|
92 | 93 | |
|
94 | pub(crate) const DIRSTATE_V2_REQUIREMENT: &str = "exp-dirstate-v2"; | |
|
95 | ||
|
93 | 96 | /// When narrowing is finalized and no longer subject to format changes, |
|
94 | 97 | /// we should move this to just "narrow" or similar. |
|
95 | 98 | #[allow(unused)] |
@@ -9,6 +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; | |
|
12 | 13 | use hg::errors::HgResultExt; |
|
13 | 14 | use hg::errors::IoResultExt; |
|
14 | 15 | use hg::matchers::AlwaysMatcher; |
@@ -16,7 +17,7 b' use hg::operations::cat;' | |||
|
16 | 17 | use hg::repo::Repo; |
|
17 | 18 | use hg::revlog::node::Node; |
|
18 | 19 | use hg::utils::hg_path::{hg_path_to_os_string, HgPath}; |
|
19 |
use hg:: |
|
|
20 | use hg::StatusError; | |
|
20 | 21 | use hg::{HgPathCow, StatusOptions}; |
|
21 | 22 | use log::{info, warn}; |
|
22 | 23 | use std::convert::TryInto; |
@@ -164,14 +165,17 b' pub fn run(invocation: &crate::CliInvoca' | |||
|
164 | 165 | }; |
|
165 | 166 | |
|
166 | 167 | let repo = invocation.repo?; |
|
167 | let mut dmap = DirstateMap::new(); | |
|
168 | 168 | let dirstate_data = |
|
169 | 169 | repo.hg_vfs().mmap_open("dirstate").io_not_found_as_none()?; |
|
170 | 170 | let dirstate_data = match &dirstate_data { |
|
171 | 171 | Some(mmap) => &**mmap, |
|
172 | 172 | None => b"", |
|
173 | 173 | }; |
|
174 |
let parents = |
|
|
174 | let (mut dmap, parents) = if repo.has_dirstate_v2() { | |
|
175 | DirstateMap::new_v2(dirstate_data)? | |
|
176 | } else { | |
|
177 | DirstateMap::new_v1(dirstate_data)? | |
|
178 | }; | |
|
175 | 179 | let options = StatusOptions { |
|
176 | 180 | // TODO should be provided by the dirstate parsing and |
|
177 | 181 | // hence be stored on dmap. Using a value that assumes we aren't |
@@ -187,8 +191,8 b' pub fn run(invocation: &crate::CliInvoca' | |||
|
187 | 191 | collect_traversed_dirs: false, |
|
188 | 192 | }; |
|
189 | 193 | let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded |
|
190 | let (mut ds_status, pattern_warnings) = hg::status( | |
|
191 | &dmap, | |
|
194 | let (mut ds_status, pattern_warnings) = hg::dirstate_tree::status::status( | |
|
195 | &mut dmap, | |
|
192 | 196 | &AlwaysMatcher, |
|
193 | 197 | repo.working_directory_path().to_owned(), |
|
194 | 198 | vec![ignore_file], |
General Comments 0
You need to be logged in to leave comments.
Login now