Mercurial > public > mercurial-scm > hg
diff rust/rhg/src/commands/status.rs @ 48422:000130cfafb6
rhg: Update the dirstate on disk after status
Differential Revision: https://phab.mercurial-scm.org/D11840
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Thu, 25 Nov 2021 18:33:51 +0100 |
parents | 005ae1a343f8 |
children | 112184713852 |
line wrap: on
line diff
--- a/rust/rhg/src/commands/status.rs Thu Dec 02 15:10:03 2021 +0100 +++ b/rust/rhg/src/commands/status.rs Thu Nov 25 18:33:51 2021 +0100 @@ -13,14 +13,18 @@ use hg; use hg::config::Config; use hg::dirstate::has_exec_bit; -use hg::errors::HgError; +use hg::dirstate::TruncatedTimestamp; +use hg::dirstate::RANGE_MASK_31BIT; +use hg::errors::{HgError, IoResultExt}; +use hg::lock::LockError; use hg::manifest::Manifest; use hg::matchers::AlwaysMatcher; use hg::repo::Repo; use hg::utils::files::get_bytes_from_os_string; -use hg::utils::hg_path::{hg_path_to_os_string, HgPath}; +use hg::utils::hg_path::{hg_path_to_path_buf, HgPath}; use hg::{HgPathCow, StatusOptions}; use log::{info, warn}; +use std::io; pub const HELP_TEXT: &str = " Show changed files in the working directory @@ -229,6 +233,7 @@ &ds_status.unsure ); } + let mut fixup = Vec::new(); if !ds_status.unsure.is_empty() && (display_states.modified || display_states.clean) { @@ -243,8 +248,9 @@ } } else { if display_states.clean { - ds_status.clean.push(to_check); + ds_status.clean.push(to_check.clone()); } + fixup.push(to_check.into_owned()) } } } @@ -318,6 +324,71 @@ b"C", )?; } + + let mut dirstate_write_needed = ds_status.dirty; + let filesystem_time_at_status_start = ds_status + .filesystem_time_at_status_start + .map(TruncatedTimestamp::from); + + if (fixup.is_empty() || filesystem_time_at_status_start.is_none()) + && !dirstate_write_needed + { + // Nothing to update + return Ok(()); + } + + // Update the dirstate on disk if we can + let with_lock_result = + repo.try_with_wlock_no_wait(|| -> Result<(), CommandError> { + if let Some(mtime_boundary) = filesystem_time_at_status_start { + for hg_path in fixup { + use std::os::unix::fs::MetadataExt; + let fs_path = hg_path_to_path_buf(&hg_path) + .expect("HgPath conversion"); + // Specifically do not reuse `fs_metadata` from + // `unsure_is_clean` which was needed before reading + // contents. Here we access metadata again after reading + // content, in case it changed in the meantime. + let fs_metadata = repo + .working_directory_vfs() + .symlink_metadata(&fs_path)?; + let mtime = TruncatedTimestamp::for_mtime_of(&fs_metadata) + .when_reading_file(&fs_path)?; + if mtime.is_reliable_mtime(&mtime_boundary) { + let mode = fs_metadata.mode(); + let size = fs_metadata.len() as u32 & RANGE_MASK_31BIT; + let mut entry = dmap + .get(&hg_path)? + .expect("ambiguous file not in dirstate"); + entry.set_clean(mode, size, mtime); + dmap.add_file(&hg_path, entry)?; + dirstate_write_needed = true + } + } + } + drop(dmap); // Avoid "already mutably borrowed" RefCell panics + if dirstate_write_needed { + repo.write_dirstate()? + } + Ok(()) + }); + match with_lock_result { + Ok(closure_result) => closure_result?, + Err(LockError::AlreadyHeld) => { + // Not updating the dirstate is not ideal but not critical: + // don’t keep our caller waiting until some other Mercurial + // process releases the lock. + } + Err(LockError::Other(HgError::IoError { error, .. })) + if error.kind() == io::ErrorKind::PermissionDenied => + { + // `hg status` on a read-only repository is fine + } + Err(LockError::Other(error)) => { + // Report other I/O errors + Err(error)? + } + } Ok(()) } @@ -368,7 +439,7 @@ hg_path: &HgPath, ) -> Result<bool, HgError> { let vfs = repo.working_directory_vfs(); - let fs_path = hg_path_to_os_string(hg_path).expect("HgPath conversion"); + let fs_path = hg_path_to_path_buf(hg_path).expect("HgPath conversion"); let fs_metadata = vfs.symlink_metadata(&fs_path)?; let is_symlink = fs_metadata.file_type().is_symlink(); // TODO: Also account for `FALLBACK_SYMLINK` and `FALLBACK_EXEC` from the @@ -399,5 +470,5 @@ } else { vfs.read(fs_path)? }; - return Ok(contents_in_p1 != &*fs_contents); + Ok(contents_in_p1 != &*fs_contents) }