Mercurial > public > mercurial-scm > hg-stable
diff rust/rhg/src/commands/status.rs @ 48493:473af5cbc209
rhg: Add support for `rhg status --copies`
Copy sources are collected during `status()` rather than after the fact like
in Python, because `status()` takes a `&mut` exclusive reference to the dirstate map
(in order to potentially mutate it for directory mtimes) and returns `Cow<'_, HgPath>`
that borrow the dirstate map.
Even though with `Cow` only some shared borrows remain, the still extend the same
lifetime of the initial `&mut` so the dirstate map cannot be borrowed again
to access copy sources after the fact:
https://doc.rust-lang.org/nomicon/lifetime-mismatch.html#limits-of-lifetimes
Additionally, collecting copy sources during the dirstate tree traversal that
`status()` already does avoids the cost of another traversal or other lookups
(though I haven?t benchmarked that cost).
Differential Revision: https://phab.mercurial-scm.org/D11899
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Fri, 10 Dec 2021 16:18:58 +0100 |
parents | 9b0e1f64656f |
children | 0c408831b2f1 |
line wrap: on
line diff
--- a/rust/rhg/src/commands/status.rs Fri Dec 10 16:57:39 2021 +0100 +++ b/rust/rhg/src/commands/status.rs Fri Dec 10 16:18:58 2021 +0100 @@ -13,6 +13,7 @@ use hg; use hg::config::Config; use hg::dirstate::has_exec_bit; +use hg::dirstate::status::StatusPath; use hg::dirstate::TruncatedTimestamp; use hg::dirstate::RANGE_MASK_31BIT; use hg::errors::{HgError, IoResultExt}; @@ -23,7 +24,7 @@ use hg::utils::files::get_bytes_from_os_string; use hg::utils::files::get_path_from_bytes; use hg::utils::hg_path::{hg_path_to_path_buf, HgPath}; -use hg::{HgPathCow, StatusOptions}; +use hg::StatusOptions; use log::{info, warn}; use std::io; use std::path::PathBuf; @@ -89,6 +90,12 @@ .long("--ignored"), ) .arg( + Arg::with_name("copies") + .help("show source of copied files (DEFAULT: ui.statuscopies)") + .short("-C") + .long("--copies"), + ) + .arg( Arg::with_name("no-status") .help("hide status prefix") .short("-n") @@ -174,7 +181,8 @@ let ui = invocation.ui; let config = invocation.config; let args = invocation.subcommand_args; - let display_states = if args.is_present("all") { + let all = args.is_present("all"); + let display_states = if all { // TODO when implementing `--quiet`: it excludes clean files // from `--all` ALL_DISPLAY_STATES @@ -195,6 +203,9 @@ } }; let no_status = args.is_present("no-status"); + let list_copies = all + || args.is_present("copies") + || config.get_bool(b"ui", b"statuscopies")?; let repo = invocation.repo?; @@ -213,6 +224,7 @@ list_clean: display_states.clean, list_unknown: display_states.unknown, list_ignored: display_states.ignored, + list_copies, collect_traversed_dirs: false, }; let (mut ds_status, pattern_warnings) = dmap.status( @@ -231,7 +243,7 @@ if !ds_status.unsure.is_empty() { info!( "Files to be rechecked by retrieval from filelog: {:?}", - &ds_status.unsure + ds_status.unsure.iter().map(|s| &s.path).collect::<Vec<_>>() ); } let mut fixup = Vec::new(); @@ -243,7 +255,7 @@ CommandError::from((e, &*format!("{:x}", p1.short()))) })?; for to_check in ds_status.unsure { - if unsure_is_modified(repo, &manifest, &to_check)? { + if unsure_is_modified(repo, &manifest, &to_check.path)? { if display_states.modified { ds_status.modified.push(to_check); } @@ -251,7 +263,7 @@ if display_states.clean { ds_status.clean.push(to_check.clone()); } - fixup.push(to_check.into_owned()) + fixup.push(to_check.path.into_owned()) } } } @@ -392,10 +404,10 @@ fn display( &self, status_prefix: &[u8], - mut paths: Vec<HgPathCow>, + mut paths: Vec<StatusPath<'_>>, ) -> Result<(), CommandError> { paths.sort_unstable(); - for path in paths { + for StatusPath { path, copy_source } in paths { let relative; let path = if let Some(relativize) = &self.relativize { relative = relativize.relativize(&path); @@ -414,6 +426,12 @@ path ))? } + if let Some(source) = copy_source { + self.ui.write_stdout(&format_bytes!( + b" {}\n", + source.as_bytes() + ))? + } } Ok(()) }