[Updated] D11686: dirstate: add a concept of "fallback" flags to dirstate item
marmoute (Pierre-Yves David)
phabricator at mercurial-scm.org
Tue Oct 19 11:50:32 UTC 2021
marmoute updated this revision to Diff 30891.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D11686?vs=30885&id=30891
BRANCH
default
CHANGES SINCE LAST ACTION
https://phab.mercurial-scm.org/D11686/new/
REVISION DETAIL
https://phab.mercurial-scm.org/D11686
AFFECTED FILES
mercurial/cext/parsers.c
mercurial/cext/util.h
mercurial/dirstate.py
mercurial/pure/parsers.py
rust/hg-core/src/dirstate/entry.rs
rust/hg-cpython/src/dirstate/item.rs
CHANGE DETAILS
diff --git a/rust/hg-cpython/src/dirstate/item.rs b/rust/hg-cpython/src/dirstate/item.rs
--- a/rust/hg-cpython/src/dirstate/item.rs
+++ b/rust/hg-cpython/src/dirstate/item.rs
@@ -1,4 +1,5 @@
use cpython::exc;
+use cpython::ObjectProtocol;
use cpython::PyBytes;
use cpython::PyErr;
use cpython::PyNone;
@@ -62,6 +63,70 @@
}
@property
+ def has_fallback_exec(&self) -> PyResult<bool> {
+ match self.entry(py).get().get_fallback_exec() {
+ Some(_) => Ok(true),
+ None => Ok(false),
+ }
+ }
+
+ @property
+ def fallback_exec(&self) -> PyResult<Option<bool>> {
+ match self.entry(py).get().get_fallback_exec() {
+ Some(exec) => Ok(Some(exec)),
+ None => Ok(None),
+ }
+ }
+
+ @fallback_exec.setter
+ def set_fallback_exec(&self, value: Option<PyObject>) -> PyResult<()> {
+ match value {
+ None => {self.entry(py).get().set_fallback_exec(None);},
+ Some(value) => {
+ if value.is_none(py) {
+ self.entry(py).get().set_fallback_exec(None);
+ } else {
+ self.entry(py).get().set_fallback_exec(
+ Some(value.is_true(py)?)
+ );
+ }},
+ }
+ Ok(())
+ }
+
+ @property
+ def has_fallback_symlink(&self) -> PyResult<bool> {
+ match self.entry(py).get().get_fallback_symlink() {
+ Some(_) => Ok(true),
+ None => Ok(false),
+ }
+ }
+
+ @property
+ def fallback_symlink(&self) -> PyResult<Option<bool>> {
+ match self.entry(py).get().get_fallback_symlink() {
+ Some(symlink) => Ok(Some(symlink)),
+ None => Ok(None),
+ }
+ }
+
+ @fallback_symlink.setter
+ def set_fallback_symlink(&self, value: Option<PyObject>) -> PyResult<()> {
+ match value {
+ None => {self.entry(py).get().set_fallback_symlink(None);},
+ Some(value) => {
+ if value.is_none(py) {
+ self.entry(py).get().set_fallback_symlink(None);
+ } else {
+ self.entry(py).get().set_fallback_symlink(
+ Some(value.is_true(py)?)
+ );
+ }},
+ }
+ Ok(())
+ }
+
+ @property
def tracked(&self) -> PyResult<bool> {
Ok(self.entry(py).get().tracked())
}
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
@@ -29,6 +29,10 @@
const WDIR_TRACKED = 1 << 0;
const P1_TRACKED = 1 << 1;
const P2_INFO = 1 << 2;
+ const HAS_FALLBACK_EXEC = 1 << 3;
+ const FALLBACK_EXEC = 1 << 4;
+ const HAS_FALLBACK_SYMLINK = 1 << 5;
+ const FALLBACK_SYMLINK = 1 << 6;
}
}
@@ -421,6 +425,52 @@
self.v1_mtime()
}
+ pub fn get_fallback_exec(&self) -> Option<bool> {
+ if self.flags.contains(Flags::HAS_FALLBACK_EXEC) {
+ Some(self.flags.contains(Flags::FALLBACK_EXEC))
+ } else {
+ None
+ }
+ }
+
+ pub fn set_fallback_exec(&mut self, value: Option<bool>) {
+ match value {
+ None => {
+ self.flags.remove(Flags::HAS_FALLBACK_EXEC);
+ self.flags.remove(Flags::FALLBACK_EXEC);
+ }
+ Some(exec) => {
+ self.flags.insert(Flags::HAS_FALLBACK_EXEC);
+ if exec {
+ self.flags.insert(Flags::FALLBACK_EXEC);
+ }
+ }
+ }
+ }
+
+ pub fn get_fallback_symlink(&self) -> Option<bool> {
+ if self.flags.contains(Flags::HAS_FALLBACK_SYMLINK) {
+ Some(self.flags.contains(Flags::FALLBACK_SYMLINK))
+ } else {
+ None
+ }
+ }
+
+ pub fn set_fallback_symlink(&mut self, value: Option<bool>) {
+ match value {
+ None => {
+ self.flags.remove(Flags::HAS_FALLBACK_SYMLINK);
+ self.flags.remove(Flags::FALLBACK_SYMLINK);
+ }
+ Some(symlink) => {
+ self.flags.insert(Flags::HAS_FALLBACK_SYMLINK);
+ if symlink {
+ self.flags.insert(Flags::FALLBACK_SYMLINK);
+ }
+ }
+ }
+ }
+
pub fn drop_merge_data(&mut self) {
if self.flags.contains(Flags::P2_INFO) {
self.flags.remove(Flags::P2_INFO);
diff --git a/mercurial/pure/parsers.py b/mercurial/pure/parsers.py
--- a/mercurial/pure/parsers.py
+++ b/mercurial/pure/parsers.py
@@ -96,6 +96,8 @@
_mode = attr.ib()
_size = attr.ib()
_mtime = attr.ib()
+ _fallback_exec = attr.ib()
+ _fallback_symlink = attr.ib()
def __init__(
self,
@@ -110,6 +112,9 @@
self._p1_tracked = p1_tracked
self._p2_info = p2_info
+ self._fallback_exec = None
+ self._fallback_symlink = None
+
self._mode = None
self._size = None
self._mtime = None
@@ -282,6 +287,85 @@
return self.v1_state()
@property
+ def has_fallback_exec(self):
+ """True if "fallback" information are available for the "exec" bit
+
+ 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).
+
+ Not all version of the dirstate on-disk storage support preserving this
+ information.
+ """
+ return self._fallback_exec is not None
+
+ @property
+ def fallback_exec(self):
+ """ "fallback" information for the executable bit
+
+ True if the file should be considered executable when we cannot get
+ this information from the files system. False if it should be
+ considered non-executable.
+
+ See has_fallback_exec for details."""
+ return self._fallback_exec
+
+ @fallback_exec.setter
+ def set_fallback_exec(self, value):
+ """control "fallback" executable bit
+
+ Set to:
+ - True if the file should be considered executable,
+ - False if the file should be considered non-executable,
+ - None if we do not have valid fallback data.
+
+ See has_fallback_exec for details."""
+ if value is None:
+ self._fallback_exec = None
+ else:
+ self._fallback_exec = bool(value)
+
+ @property
+ def has_fallback_symlink(self):
+ """True if "fallback" information are available for symlink status
+
+ 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).
+
+ Not all version of the dirstate on-disk storage support preserving this
+ information."""
+ return self._fallback_symlink is not None
+
+ @property
+ def fallback_symlink(self):
+ """ "fallback" information for symlink status
+
+ True if the file should be considered executable when we cannot get
+ this information from the files system. False if it should be
+ considered non-executable.
+
+ See has_fallback_exec for details."""
+ return self._fallback_symlink
+
+ @fallback_symlink.setter
+ def set_fallback_symlink(self, value):
+ """control "fallback" symlink status
+
+ Set to:
+ - True if the file should be considered a symlink,
+ - False if the file should be considered not a symlink,
+ - None if we do not have valid fallback data.
+
+ See has_fallback_symlink for details."""
+ if value is None:
+ self._fallback_symlink = None
+ else:
+ self._fallback_symlink = bool(value)
+
+ @property
def tracked(self):
"""True is the file is tracked in the working copy"""
return self._wc_tracked
diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -259,7 +259,11 @@
def f(x):
if os.path.islink(self._join(x)):
return b'l'
- if b'x' in fallback(x):
+ entry = self.get_entry(x)
+ if entry.has_fallback_exec:
+ if entry.fallback_exec:
+ return b'x'
+ elif b'x' in fallback(x):
return b'x'
return b''
@@ -269,13 +273,28 @@
def f(x):
if b'l' in fallback(x):
return b'l'
+ entry = self.get_entry(x)
+ if entry.has_fallback_symlink:
+ if entry.fallback_symlink:
+ return b'l'
if util.isexec(self._join(x)):
return b'x'
return b''
return f
else:
- return fallback
+
+ def f(x):
+ entry = self.get_entry(x)
+ if entry.has_fallback_symlink:
+ if entry.fallback_symlink:
+ return b'l'
+ if entry.has_fallback_exec:
+ if entry.fallback_exec:
+ return b'x'
+ elif entry.has_fallback_symlink:
+ return b''
+ return fallback(x)
@propertycache
def _cwd(self):
diff --git a/mercurial/cext/util.h b/mercurial/cext/util.h
--- a/mercurial/cext/util.h
+++ b/mercurial/cext/util.h
@@ -42,6 +42,10 @@
static const int dirstate_flag_expected_state_is_modified = 1 << 8;
static const int dirstate_flag_all_unknown_recorded = 1 << 9;
static const int dirstate_flag_all_ignored_recorded = 1 << 10;
+static const int dirstate_flag_fallback_exec = 1 << 11;
+static const int dirstate_flag_has_fallback_exec = 1 << 12;
+static const int dirstate_flag_fallback_symlink = 1 << 13;
+static const int dirstate_flag_has_fallback_symlink = 1 << 14;
extern PyTypeObject dirstateItemType;
#define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateItemType)
diff --git a/mercurial/cext/parsers.c b/mercurial/cext/parsers.c
--- a/mercurial/cext/parsers.c
+++ b/mercurial/cext/parsers.c
@@ -188,6 +188,17 @@
}
}
+static inline bool dirstate_item_c_has_fallback_exec(dirstateItemObject *self)
+{
+ return (bool)self->flags & dirstate_flag_has_fallback_exec;
+}
+
+static inline bool
+dirstate_item_c_has_fallback_symlink(dirstateItemObject *self)
+{
+ return (bool)self->flags & dirstate_flag_has_fallback_symlink;
+}
+
static inline int dirstate_item_c_v1_mode(dirstateItemObject *self)
{
if (self->flags & dirstate_flag_has_meaningful_data) {
@@ -498,6 +509,83 @@
return PyBytes_FromStringAndSize(&state, 1);
};
+static PyObject *dirstate_item_get_has_fallback_exec(dirstateItemObject *self)
+{
+ if (dirstate_item_c_has_fallback_exec(self)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+};
+
+static PyObject *dirstate_item_get_fallback_exec(dirstateItemObject *self)
+{
+ if (dirstate_item_c_has_fallback_exec(self)) {
+ if (self->flags & dirstate_flag_fallback_exec) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+ } else {
+ Py_RETURN_NONE;
+ }
+};
+
+static int dirstate_item_set_fallback_exec(dirstateItemObject *self,
+ PyObject *value)
+{
+ if ((value == Py_None) || (value == NULL)) {
+ self->flags &= ~dirstate_flag_has_fallback_exec;
+ } else {
+ self->flags |= dirstate_flag_has_fallback_exec;
+ if (PyObject_IsTrue(value)) {
+ self->flags |= dirstate_flag_fallback_exec;
+ } else {
+ self->flags &= ~dirstate_flag_fallback_exec;
+ }
+ }
+ return 0;
+};
+
+static PyObject *
+dirstate_item_get_has_fallback_symlink(dirstateItemObject *self)
+{
+ if (dirstate_item_c_has_fallback_symlink(self)) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+};
+
+static PyObject *dirstate_item_get_fallback_symlink(dirstateItemObject *self)
+{
+ if (dirstate_item_c_has_fallback_symlink(self)) {
+ if (self->flags & dirstate_flag_fallback_symlink) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+ } else {
+ Py_RETURN_NONE;
+ }
+};
+
+static int dirstate_item_set_fallback_symlink(dirstateItemObject *self,
+ PyObject *value)
+{
+ if ((value == Py_None) || (value == NULL)) {
+ self->flags &= ~dirstate_flag_has_fallback_symlink;
+ } else {
+ self->flags |= dirstate_flag_has_fallback_symlink;
+ if (PyObject_IsTrue(value)) {
+ self->flags |= dirstate_flag_fallback_symlink;
+ } else {
+ self->flags &= ~dirstate_flag_fallback_symlink;
+ }
+ }
+ return 0;
+};
+
static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
{
if (dirstate_item_c_tracked(self)) {
@@ -588,6 +676,14 @@
{"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
{"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
{"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
+ {"has_fallback_exec", (getter)dirstate_item_get_has_fallback_exec, NULL,
+ "has_fallback_exec", NULL},
+ {"fallback_exec", (getter)dirstate_item_get_fallback_exec,
+ (setter)dirstate_item_set_fallback_exec, "fallback_exec", NULL},
+ {"has_fallback_symlink", (getter)dirstate_item_get_has_fallback_symlink,
+ NULL, "has_fallback_symlink", NULL},
+ {"fallback_symlink", (getter)dirstate_item_get_fallback_symlink,
+ (setter)dirstate_item_set_fallback_symlink, "fallback_symlink", NULL},
{"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
{"p1_tracked", (getter)dirstate_item_get_p1_tracked, NULL, "p1_tracked",
NULL},
To: marmoute, #hg-reviewers, Alphare
Cc: Alphare, mharbison72, mercurial-patches
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurial-scm.org/pipermail/mercurial-patches/attachments/20211019/d277f7d4/attachment-0002.html>
More information about the Mercurial-patches
mailing list