@@ -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())
}
@@ -22,6 +22,8 @@
pub(crate) flags: Flags,
mode_size: Option<(u32, u32)>,
mtime: Option<u32>,
+ fallback_exec: Option<bool>,
+ fallback_symlink: Option<bool>,
}
bitflags! {
@@ -196,6 +198,8 @@
flags,
mode_size,
mtime,
+ fallback_exec: None,
+ fallback_symlink: None,
}
}
@@ -213,12 +217,16 @@
flags: Flags::WDIR_TRACKED | Flags::P2_INFO,
mode_size: None,
mtime: None,
+ fallback_exec: None,
+ fallback_symlink: None,
}
} else if size == SIZE_NON_NORMAL {
Self {
flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED,
mode_size: None,
mtime: None,
+ fallback_exec: None,
+ fallback_symlink: None,
}
} else if mtime == MTIME_UNSET {
// TODO: return an error for negative values?
@@ -228,6 +236,8 @@
flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED,
mode_size: Some((mode, size)),
mtime: None,
+ fallback_exec: None,
+ fallback_symlink: None,
}
} else {
// TODO: return an error for negative values?
@@ -238,6 +248,8 @@
flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED,
mode_size: Some((mode, size)),
mtime: Some(mtime),
+ fallback_exec: None,
+ fallback_symlink: None,
}
}
}
@@ -245,6 +257,8 @@
flags: Flags::WDIR_TRACKED,
mode_size: None,
mtime: None,
+ fallback_exec: None,
+ fallback_symlink: None,
},
EntryState::Removed => Self {
flags: if size == SIZE_NON_NORMAL {
@@ -257,6 +271,8 @@
},
mode_size: None,
mtime: None,
+ fallback_exec: None,
+ fallback_symlink: None,
},
EntryState::Merged => Self {
flags: Flags::WDIR_TRACKED
@@ -264,6 +280,8 @@
| Flags::P2_INFO, // might not be true because of rename ?
mode_size: None,
mtime: None,
+ fallback_exec: None,
+ fallback_symlink: None,
},
}
}
@@ -421,6 +439,22 @@
self.v1_mtime()
}
+ pub fn get_fallback_exec(&self) -> Option<bool> {
+ self.fallback_exec
+ }
+
+ pub fn set_fallback_exec(&mut self, value: Option<bool>) {
+ self.fallback_exec = value;
+ }
+
+ pub fn get_fallback_symlink(&self) -> Option<bool> {
+ self.fallback_exec
+ }
+
+ pub fn set_fallback_symlink(&mut self, value: Option<bool>) {
+ self.fallback_exec = value;
+ }
+
pub fn drop_merge_data(&mut self) {
if self.flags.contains(Flags::P2_INFO) {
self.flags.remove(Flags::P2_INFO);
@@ -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,79 @@
return self.v1_state()
@property
+ def has_fallback_exec(self):
+ """True is "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."""
+ self._fallback_exec = bool(value)
+
+ @property
+ def has_fallback_symlink(self):
+ """True is "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."""
+ self._fallback_symlink = bool(value)
+
+ @property
def tracked(self):
"""True is the file is tracked in the working copy"""
return self._wc_tracked
@@ -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):
@@ -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_unrecorded_ignored = 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)
@@ -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},