[Updated] D11840: rhg: Update the dirstate on disk after status
SimonSapin
phabricator at mercurial-scm.org
Mon Dec 6 10:04:23 UTC 2021
SimonSapin updated this revision to Diff 31321.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D11840?vs=31269&id=31321
BRANCH
default
CHANGES SINCE LAST ACTION
https://phab.mercurial-scm.org/D11840/new/
REVISION DETAIL
https://phab.mercurial-scm.org/D11840
AFFECTED FILES
rust/hg-core/src/dirstate/entry.rs
rust/rhg/src/commands/status.rs
tests/test-backout.t
tests/test-dirstate-race2.t
tests/test-dirstate.t
CHANGE DETAILS
diff --git a/tests/test-dirstate.t b/tests/test-dirstate.t
--- a/tests/test-dirstate.t
+++ b/tests/test-dirstate.t
@@ -9,10 +9,6 @@
> EOF
#endif
-TODO: fix rhg bugs that make this test fail when status is enabled
- $ unset RHG_STATUS
-
-
------ Test dirstate._dirs refcounting
$ hg init t
diff --git a/tests/test-dirstate-race2.t b/tests/test-dirstate-race2.t
--- a/tests/test-dirstate-race2.t
+++ b/tests/test-dirstate-race2.t
@@ -9,9 +9,6 @@
> EOF
#endif
-TODO: fix rhg bugs that make this test fail when status is enabled
- $ unset RHG_STATUS
-
Checking the size/permissions/file-type of files stored in the
dirstate after an update where the files are changed concurrently
outside of hg's control.
diff --git a/tests/test-backout.t b/tests/test-backout.t
--- a/tests/test-backout.t
+++ b/tests/test-backout.t
@@ -172,8 +172,7 @@
$ hg status -A
C c
$ hg debugstate --no-dates
- n 644 12 set c (no-rhg !)
- n 0 -1 unset c (rhg known-bad-output !)
+ n 644 12 set c
$ hg backout -d '6 0' -m 'to be rollback-ed soon' -r .
removing c
adding b
diff --git a/rust/rhg/src/commands/status.rs b/rust/rhg/src/commands/status.rs
--- a/rust/rhg/src/commands/status.rs
+++ b/rust/rhg/src/commands/status.rs
@@ -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)
{
@@ -237,14 +242,17 @@
CommandError::from((e, &*format!("{:x}", p1.short())))
})?;
for to_check in ds_status.unsure {
- if unsure_is_modified(repo, &manifest, &to_check)? {
+ if let Some((mode, size, mtime)) =
+ unsure_is_clean(repo, &manifest, &to_check)?
+ {
+ if display_states.clean {
+ ds_status.clean.push(to_check.clone());
+ }
+ fixup.push((to_check.into_owned(), mode, size, mtime))
+ } else {
if display_states.modified {
ds_status.modified.push(to_check);
}
- } else {
- if display_states.clean {
- ds_status.clean.push(to_check);
- }
}
}
}
@@ -318,6 +326,38 @@
b"C",
)?;
}
+ if !fixup.is_empty() {
+ // Update the dirstate on disk if we can
+ let with_lock_result =
+ repo.try_with_wlock_no_wait(|| -> Result<(), CommandError> {
+ for (path, mode, size, mtime) in fixup {
+ let mut entry = dmap
+ .get(&path)?
+ .expect("ambiguous file not in dirstate");
+ entry.set_clean(mode, size, mtime);
+ dmap.add_file(&path, entry)?
+ }
+ drop(dmap); // Avoid "already mutably borrowed" RefCell panics
+ 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(())
}
@@ -362,13 +402,15 @@
///
/// This meant to be used for those that the dirstate cannot resolve, due
/// to time resolution limits.
-fn unsure_is_modified(
+///
+/// If the file is clean, return `Some((mode, size, mtime))` to update its dirstate entry.
+fn unsure_is_clean(
repo: &Repo,
manifest: &Manifest,
hg_path: &HgPath,
-) -> Result<bool, HgError> {
+) -> Result<Option<(u32, u32, TruncatedTimestamp)>, 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
@@ -385,7 +427,7 @@
.find_file(hg_path)?
.expect("ambgious file not in p1");
if entry.flags != fs_flags {
- return Ok(true);
+ return Ok(None);
}
let filelog = repo.filelog(hg_path)?;
let filelog_entry =
@@ -395,9 +437,20 @@
let contents_in_p1 = filelog_entry.data()?;
let fs_contents = if is_symlink {
- get_bytes_from_os_string(vfs.read_link(fs_path)?.into_os_string())
+ get_bytes_from_os_string(vfs.read_link(&fs_path)?.into_os_string())
+ } else {
+ vfs.read(&fs_path)?
+ };
+ if contents_in_p1 != &*fs_contents {
+ Ok(None)
} else {
- vfs.read(fs_path)?
- };
- return Ok(contents_in_p1 != &*fs_contents);
+ use std::os::unix::fs::MetadataExt;
+ // Read metadata again after reading contents, in case changes are made concurrently.
+ let new_fs_metadata = vfs.symlink_metadata(&fs_path)?;
+ let mode = new_fs_metadata.mode();
+ let size = fs_contents.len() as u32 & RANGE_MASK_31BIT;
+ let mtime = TruncatedTimestamp::for_mtime_of(&new_fs_metadata)
+ .when_reading_file(&fs_path)?;
+ Ok(Some((mode, size, mtime)))
+ }
}
diff --git a/rust/hg-core/src/dirstate/entry.rs b/rust/hg-core/src/dirstate/entry.rs
--- a/rust/hg-core/src/dirstate/entry.rs
+++ b/rust/hg-core/src/dirstate/entry.rs
@@ -191,7 +191,7 @@
}
const NSEC_PER_SEC: u32 = 1_000_000_000;
-const RANGE_MASK_31BIT: u32 = 0x7FFF_FFFF;
+pub const RANGE_MASK_31BIT: u32 = 0x7FFF_FFFF;
pub const MTIME_UNSET: i32 = -1;
To: SimonSapin, #hg-reviewers, Alphare
Cc: Alphare, mercurial-patches
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurial-scm.org/pipermail/mercurial-patches/attachments/20211206/f4dc7f56/attachment-0002.html>
More information about the Mercurial-patches
mailing list