dirstate-v2: preserve the fallback values on disk
authorPierre-Yves David <pierre-yves.david@octobus.net>
Mon, 18 Oct 2021 10:56:54 +0200
changeset 48254 b874e8d81a98
parent 48253 948570aa7630
child 48255 8c34edb1ad10
dirstate-v2: preserve the fallback values on disk When the fallback values are set, they are now read and written to disk. See format documentation for details. Differential Revision: https://phab.mercurial-scm.org/D11688
mercurial/helptext/internals/dirstate-v2.txt
mercurial/pure/parsers.py
rust/hg-core/src/dirstate/entry.rs
rust/hg-core/src/dirstate_tree/on_disk.rs
--- a/mercurial/helptext/internals/dirstate-v2.txt	Mon Oct 18 20:02:05 2021 +0200
+++ b/mercurial/helptext/internals/dirstate-v2.txt	Mon Oct 18 10:56:54 2021 +0200
@@ -386,6 +386,10 @@
     EXPECTED_STATE_IS_MODIFIED = 1 << 8
     ALL_UNKNOWN_RECORDED = 1 << 9
     ALL_IGNORED_RECORDED = 1 << 10
+    HAS_FALLBACK_EXEC = 1 << 11
+    FALLBACK_EXEC = 1 << 12
+    HAS_FALLBACK_SYMLINK = 1 << 13
+    FALLBACK_SYMLINK = 1 << 14
 
   The meaning of each bit is described below.
 
@@ -558,3 +562,33 @@
     Also note that having this flag unset does not imply that no "ignored"
     children have been recorded. Some might be present, but there is no garantee
     that is will be all of them.
+
+`HAS_FALLBACK_EXEC`
+    If this flag is set, the entry carries "fallback" information for the
+    executable bit in the `FALLBACK_EXEC` flag.
+
+    Fallback information can be stored in the dirstate to keep track of
+    filesystem attribute tracked by Mercurial when the underlying file
+    system or operating system does not support that property, (e.g.
+    Windows).
+
+`FALLBACK_EXEC`
+    Should be ignored if `HAS_FALLBACK_EXEC` is unset. If set the file for this
+    entry should be considered executable if that information cannot be
+    extracted from the file system. If unset it should be considered
+    non-executable instead.
+
+`HAS_FALLBACK_SYMLINK`
+    If this flag is set, the entry carries "fallback" information for symbolic
+    link status in the `FALLBACK_SYMLINK` flag.
+
+    Fallback information can be stored in the dirstate to keep track of
+    filesystem attribute tracked by Mercurial when the underlying file
+    system or operating system does not support that property, (e.g.
+    Windows).
+
+`FALLBACK_SYMLINK`
+    Should be ignored if `HAS_FALLBACK_SYMLINK` is unset. If set the file for
+    this entry should be considered a symlink if that information cannot be
+    extracted from the file system. If unset it should be considered a normal
+    file instead.
--- a/mercurial/pure/parsers.py	Mon Oct 18 20:02:05 2021 +0200
+++ b/mercurial/pure/parsers.py	Mon Oct 18 10:56:54 2021 +0200
@@ -56,6 +56,10 @@
 DIRSTATE_V2_EXPECTED_STATE_IS_MODIFIED = 1 << 8
 DIRSTATE_V2_ALL_UNKNOWN_RECORDED = 1 << 9
 DIRSTATE_V2_ALL_IGNORED_RECORDED = 1 << 10
+DIRSTATE_V2_HAS_FALLBACK_EXEC = 1 << 11
+DIRSTATE_V2_FALLBACK_EXEC = 1 << 12
+DIRSTATE_V2_HAS_FALLBACK_SYMLINK = 1 << 13
+DIRSTATE_V2_FALLBACK_SYMLINK = 1 << 14
 
 
 @attr.s(slots=True, init=False)
@@ -142,6 +146,14 @@
             has_mode_size = False
             has_meaningful_mtime = False
 
+        fallback_exec = None
+        if flags & DIRSTATE_V2_HAS_FALLBACK_EXEC:
+            fallback_exec = flags & DIRSTATE_V2_FALLBACK_EXEC
+
+        fallback_symlink = None
+        if flags & DIRSTATE_V2_HAS_FALLBACK_SYMLINK:
+            fallback_symlink = flags & DIRSTATE_V2_FALLBACK_SYMLINK
+
         if has_mode_size:
             assert stat.S_IXUSR == 0o100
             if flags & DIRSTATE_V2_MODE_EXEC_PERM:
@@ -159,6 +171,8 @@
             has_meaningful_data=has_mode_size,
             has_meaningful_mtime=has_meaningful_mtime,
             parentfiledata=(mode, size, mtime),
+            fallback_exec=fallback_exec,
+            fallback_symlink=fallback_symlink,
         )
 
     @classmethod
@@ -428,6 +442,17 @@
                 flags |= DIRSTATE_V2_MODE_IS_SYMLINK
         if self._mtime is not None:
             flags |= DIRSTATE_V2_HAS_FILE_MTIME
+
+        if self._fallback_exec is not None:
+            flags |= DIRSTATE_V2_HAS_FALLBACK_EXEC
+            if self._fallback_exec:
+                flags |= DIRSTATE_V2_FALLBACK_EXEC
+
+        if self._fallback_symlink is not None:
+            flags |= DIRSTATE_V2_HAS_FALLBACK_SYMLINK
+            if self._fallback_symlink:
+                flags |= DIRSTATE_V2_FALLBACK_SYMLINK
+
         # Note: we do not need to do anything regarding
         # DIRSTATE_V2_ALL_UNKNOWN_RECORDED and DIRSTATE_V2_ALL_IGNORED_RECORDED
         # since we never set _DIRSTATE_V2_HAS_DIRCTORY_MTIME
--- a/rust/hg-core/src/dirstate/entry.rs	Mon Oct 18 20:02:05 2021 +0200
+++ b/rust/hg-core/src/dirstate/entry.rs	Mon Oct 18 10:56:54 2021 +0200
@@ -339,7 +339,15 @@
     /// Returns `(wdir_tracked, p1_tracked, p2_info, mode_size, mtime)`
     pub(crate) fn v2_data(
         &self,
-    ) -> (bool, bool, bool, Option<(u32, u32)>, Option<u32>) {
+    ) -> (
+        bool,
+        bool,
+        bool,
+        Option<(u32, u32)>,
+        Option<u32>,
+        Option<bool>,
+        Option<bool>,
+    ) {
         if !self.any_tracked() {
             // TODO: return an Option instead?
             panic!("Accessing v1_state of an untracked DirstateEntry")
@@ -349,7 +357,15 @@
         let p2_info = self.flags.contains(Flags::P2_INFO);
         let mode_size = self.mode_size;
         let mtime = self.mtime;
-        (wdir_tracked, p1_tracked, p2_info, mode_size, mtime)
+        (
+            wdir_tracked,
+            p1_tracked,
+            p2_info,
+            mode_size,
+            mtime,
+            self.get_fallback_exec(),
+            self.get_fallback_symlink(),
+        )
     }
 
     fn v1_state(&self) -> EntryState {
--- a/rust/hg-core/src/dirstate_tree/on_disk.rs	Mon Oct 18 20:02:05 2021 +0200
+++ b/rust/hg-core/src/dirstate_tree/on_disk.rs	Mon Oct 18 10:56:54 2021 +0200
@@ -113,6 +113,10 @@
         const EXPECTED_STATE_IS_MODIFIED = 1 << 8;
         const ALL_UNKNOWN_RECORDED = 1 << 9;
         const ALL_IGNORED_RECORDED = 1 << 10;
+        const HAS_FALLBACK_EXEC = 1 << 11;
+        const FALLBACK_EXEC = 1 << 12;
+        const HAS_FALLBACK_SYMLINK = 1 << 13;
+        const FALLBACK_SYMLINK = 1 << 14;
     }
 }
 
@@ -420,8 +424,15 @@
     fn from_dirstate_entry(
         entry: &DirstateEntry,
     ) -> (Flags, U32Be, PackedTruncatedTimestamp) {
-        let (wdir_tracked, p1_tracked, p2_info, mode_size_opt, mtime_opt) =
-            entry.v2_data();
+        let (
+            wdir_tracked,
+            p1_tracked,
+            p2_info,
+            mode_size_opt,
+            mtime_opt,
+            fallback_exec,
+            fallback_symlink,
+        ) = entry.v2_data();
         // TODO: convert throug raw flag bits instead?
         let mut flags = Flags::empty();
         flags.set(Flags::WDIR_TRACKED, wdir_tracked);
@@ -446,6 +457,18 @@
         } else {
             PackedTruncatedTimestamp::null()
         };
+        if let Some(f_exec) = fallback_exec {
+            flags.insert(Flags::HAS_FALLBACK_EXEC);
+            if f_exec {
+                flags.insert(Flags::FALLBACK_EXEC);
+            }
+        }
+        if let Some(f_symlink) = fallback_symlink {
+            flags.insert(Flags::HAS_FALLBACK_SYMLINK);
+            if f_symlink {
+                flags.insert(Flags::FALLBACK_SYMLINK);
+            }
+        }
         (flags, size, mtime)
     }
 }