This moves low-level dirstate wrangling out of the status command and into
a more reusable location.
The open dirstate map is lazily initialized and kept on the Repo object,
for reuse by sub-sequent calls.
( )
Alphare |
hg-reviewers |
This moves low-level dirstate wrangling out of the status command and into
a more reusable location.
The open dirstate map is lazily initialized and kept on the Repo object,
for reuse by sub-sequent calls.
Automatic diff as part of commit; lint not applicable. |
Automatic diff as part of commit; unit tests not applicable. |
rust/hg-core/src/repo.rs | ||
---|---|---|
270 | Indeed! Done. (Though it’s not critical, it just saves the dirstate_parents getter from opening on trying to open the .hg/dirstate file again.) |
Path | Packages | |||
---|---|---|---|---|
M | rust/hg-core/src/dirstate.rs (2 lines) | |||
M | rust/hg-core/src/repo.rs (107 lines) | |||
M | rust/rhg/src/commands/status.rs (50 lines) |
Status | Author | Revision | |
---|---|---|---|
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin |
use bytes_cast::{unaligned, BytesCast}; | use bytes_cast::{unaligned, BytesCast}; | ||||
use std::convert::TryFrom; | use std::convert::TryFrom; | ||||
pub mod dirs_multiset; | pub mod dirs_multiset; | ||||
pub mod dirstate_map; | pub mod dirstate_map; | ||||
pub mod parsers; | pub mod parsers; | ||||
pub mod status; | pub mod status; | ||||
#[derive(Debug, PartialEq, Clone, BytesCast)] | #[derive(Debug, PartialEq, Copy, Clone, BytesCast)] | ||||
#[repr(C)] | #[repr(C)] | ||||
pub struct DirstateParents { | pub struct DirstateParents { | ||||
pub p1: Node, | pub p1: Node, | ||||
pub p2: Node, | pub p2: Node, | ||||
} | } | ||||
impl DirstateParents { | impl DirstateParents { | ||||
pub const NULL: Self = Self { | pub const NULL: Self = Self { |
// status.rs | // status.rs | ||||
// | // | ||||
// Copyright 2020, Georges Racinet <georges.racinets@octobus.net> | // Copyright 2020, Georges Racinet <georges.racinets@octobus.net> | ||||
// | // | ||||
// This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
use crate::error::CommandError; | use crate::error::CommandError; | ||||
use crate::ui::Ui; | use crate::ui::Ui; | ||||
use clap::{Arg, SubCommand}; | use clap::{Arg, SubCommand}; | ||||
use hg; | use hg; | ||||
use hg::dirstate_tree::dirstate_map::DirstateMap; | use hg::dirstate_tree::dispatch::DirstateMapMethods; | ||||
use hg::dirstate_tree::on_disk; | |||||
use hg::errors::HgResultExt; | |||||
use hg::errors::IoResultExt; | use hg::errors::IoResultExt; | ||||
use hg::matchers::AlwaysMatcher; | use hg::matchers::AlwaysMatcher; | ||||
use hg::operations::cat; | use hg::operations::cat; | ||||
use hg::repo::Repo; | use hg::repo::Repo; | ||||
use hg::revlog::node::Node; | use hg::revlog::node::Node; | ||||
use hg::utils::hg_path::{hg_path_to_os_string, HgPath}; | use hg::utils::hg_path::{hg_path_to_os_string, HgPath}; | ||||
use hg::StatusError; | use hg::StatusError; | ||||
use hg::{HgPathCow, StatusOptions}; | use hg::{HgPathCow, StatusOptions}; | ||||
if requested.is_empty() { | if requested.is_empty() { | ||||
DEFAULT_DISPLAY_STATES | DEFAULT_DISPLAY_STATES | ||||
} else { | } else { | ||||
requested | requested | ||||
} | } | ||||
}; | }; | ||||
let repo = invocation.repo?; | let repo = invocation.repo?; | ||||
let dirstate_data_mmap; | let mut dmap = repo.dirstate_map_mut()?; | ||||
let (mut dmap, parents) = if repo.has_dirstate_v2() { | |||||
let docket_data = | |||||
repo.hg_vfs().read("dirstate").io_not_found_as_none()?; | |||||
let parents; | |||||
let dirstate_data; | |||||
let data_size; | |||||
let docket; | |||||
let tree_metadata; | |||||
if let Some(docket_data) = &docket_data { | |||||
docket = on_disk::read_docket(docket_data)?; | |||||
tree_metadata = docket.tree_metadata(); | |||||
parents = Some(docket.parents()); | |||||
data_size = docket.data_size(); | |||||
dirstate_data_mmap = repo | |||||
.hg_vfs() | |||||
.mmap_open(docket.data_filename()) | |||||
.io_not_found_as_none()?; | |||||
dirstate_data = dirstate_data_mmap.as_deref().unwrap_or(b""); | |||||
} else { | |||||
parents = None; | |||||
tree_metadata = b""; | |||||
data_size = 0; | |||||
dirstate_data = b""; | |||||
} | |||||
let dmap = | |||||
DirstateMap::new_v2(dirstate_data, data_size, tree_metadata)?; | |||||
(dmap, parents) | |||||
} else { | |||||
dirstate_data_mmap = | |||||
repo.hg_vfs().mmap_open("dirstate").io_not_found_as_none()?; | |||||
let dirstate_data = dirstate_data_mmap.as_deref().unwrap_or(b""); | |||||
DirstateMap::new_v1(dirstate_data)? | |||||
}; | |||||
let options = StatusOptions { | let options = StatusOptions { | ||||
// TODO should be provided by the dirstate parsing and | // TODO should be provided by the dirstate parsing and | ||||
// hence be stored on dmap. Using a value that assumes we aren't | // hence be stored on dmap. Using a value that assumes we aren't | ||||
// below the time resolution granularity of the FS and the | // below the time resolution granularity of the FS and the | ||||
// dirstate. | // dirstate. | ||||
last_normal_time: 0, | last_normal_time: 0, | ||||
// we're currently supporting file systems with exec flags only | // we're currently supporting file systems with exec flags only | ||||
// anyway | // anyway | ||||
check_exec: true, | check_exec: true, | ||||
list_clean: display_states.clean, | list_clean: display_states.clean, | ||||
list_unknown: display_states.unknown, | list_unknown: display_states.unknown, | ||||
list_ignored: display_states.ignored, | list_ignored: display_states.ignored, | ||||
collect_traversed_dirs: false, | collect_traversed_dirs: false, | ||||
}; | }; | ||||
let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded | let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded | ||||
let (mut ds_status, pattern_warnings) = hg::dirstate_tree::status::status( | let (mut ds_status, pattern_warnings) = dmap.status( | ||||
&mut dmap, | |||||
&AlwaysMatcher, | &AlwaysMatcher, | ||||
repo.working_directory_path().to_owned(), | repo.working_directory_path().to_owned(), | ||||
vec![ignore_file], | vec![ignore_file], | ||||
options, | options, | ||||
)?; | )?; | ||||
if !pattern_warnings.is_empty() { | if !pattern_warnings.is_empty() { | ||||
warn!("Pattern warnings: {:?}", &pattern_warnings); | warn!("Pattern warnings: {:?}", &pattern_warnings); | ||||
} | } | ||||
if !ds_status.bad.is_empty() { | if !ds_status.bad.is_empty() { | ||||
warn!("Bad matches {:?}", &(ds_status.bad)) | warn!("Bad matches {:?}", &(ds_status.bad)) | ||||
} | } | ||||
if !ds_status.unsure.is_empty() { | if !ds_status.unsure.is_empty() { | ||||
info!( | info!( | ||||
"Files to be rechecked by retrieval from filelog: {:?}", | "Files to be rechecked by retrieval from filelog: {:?}", | ||||
&ds_status.unsure | &ds_status.unsure | ||||
); | ); | ||||
} | } | ||||
if !ds_status.unsure.is_empty() | if !ds_status.unsure.is_empty() | ||||
&& (display_states.modified || display_states.clean) | && (display_states.modified || display_states.clean) | ||||
{ | { | ||||
let p1: Node = parents | let p1: Node = repo.dirstate_parents()?.p1.into(); | ||||
.expect( | |||||
"Dirstate with no parents should not list any file to | |||||
be rechecked for modifications", | |||||
) | |||||
.p1 | |||||
.into(); | |||||
let p1_hex = format!("{:x}", p1); | let p1_hex = format!("{:x}", p1); | ||||
for to_check in ds_status.unsure { | for to_check in ds_status.unsure { | ||||
if cat_file_is_modified(repo, &to_check, &p1_hex)? { | if cat_file_is_modified(repo, &to_check, &p1_hex)? { | ||||
if display_states.modified { | if display_states.modified { | ||||
ds_status.modified.push(to_check); | ds_status.modified.push(to_check); | ||||
} | } | ||||
} else { | } else { | ||||
if display_states.clean { | if display_states.clean { |
Should we set the parents to DirstateParents::NULL here?