@@ -6,7 +6,6 @@
use cpython::PyResult;
use cpython::Python;
use cpython::PythonObject;
-use hg::dirstate::entry::Flags;
use hg::dirstate::DirstateEntry;
use hg::dirstate::EntryState;
use std::cell::Cell;
@@ -19,23 +18,25 @@
_cls,
wc_tracked: bool = false,
p1_tracked: bool = false,
- p2_tracked: bool = false,
- merged: bool = false,
- clean_p1: bool = false,
- clean_p2: bool = false,
- possibly_dirty: bool = false,
+ p2_info: bool = false,
+ has_meaningful_data: bool = true,
+ has_meaningful_mtime: bool = true,
parentfiledata: Option<(i32, i32, i32)> = None,
) -> PyResult<DirstateItem> {
- let mut flags = Flags::empty();
- flags.set(Flags::WDIR_TRACKED, wc_tracked);
- flags.set(Flags::P1_TRACKED, p1_tracked);
- flags.set(Flags::P2_TRACKED, p2_tracked);
- flags.set(Flags::MERGED, merged);
- flags.set(Flags::CLEAN_P1, clean_p1);
- flags.set(Flags::CLEAN_P2, clean_p2);
- flags.set(Flags::POSSIBLY_DIRTY, possibly_dirty);
- let entry = DirstateEntry::new(flags, parentfiledata);
+ let mut mode_size_opt = None;
+ let mut mtime_opt = None;
+ if let Some((mode, size, mtime)) = parentfiledata {
+ if has_meaningful_data {
+ mode_size_opt = Some((mode, size))
+ }
+ if has_meaningful_mtime {
+ mtime_opt = Some(mtime)
+ }
+ }
+ let entry = DirstateEntry::new(
+ wc_tracked, p1_tracked, p2_info, mode_size_opt, mtime_opt,
+ );
DirstateItem::create_instance(py, Cell::new(entry))
}
@@ -695,7 +695,7 @@
path.as_ref(),
)? {
if let NodeData::Entry(entry) = &mut node.data {
- entry.clear_mtime();
+ entry.set_possibly_dirty();
}
}
}
@@ -16,21 +16,15 @@
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct DirstateEntry {
flags: Flags,
- mode: i32,
- size: i32,
- mtime: i32,
+ mode_size: Option<(i32, i32)>,
+ mtime: Option<i32>,
}
bitflags! {
- pub struct Flags: u8 {
+ struct Flags: u8 {
const WDIR_TRACKED = 1 << 0;
const P1_TRACKED = 1 << 1;
- const P2_TRACKED = 1 << 2;
- const POSSIBLY_DIRTY = 1 << 3;
- const MERGED = 1 << 4;
- const CLEAN_P1 = 1 << 5;
- const CLEAN_P2 = 1 << 6;
- const ENTRYLESS_TREE_NODE = 1 << 7;
+ const P2_INFO = 1 << 2;
}
}
@@ -48,15 +42,19 @@
impl DirstateEntry {
pub fn new(
- flags: Flags,
- mode_size_mtime: Option<(i32, i32, i32)>,
+ wdir_tracked: bool,
+ p1_tracked: bool,
+ p2_info: bool,
+ mode_size: Option<(i32, i32)>,
+ mtime: Option<i32>,
) -> Self {
- let (mode, size, mtime) =
- mode_size_mtime.unwrap_or((0, SIZE_NON_NORMAL, MTIME_UNSET));
+ let mut flags = Flags::empty();
+ flags.set(Flags::WDIR_TRACKED, wdir_tracked);
+ flags.set(Flags::P1_TRACKED, p1_tracked);
+ flags.set(Flags::P2_INFO, p2_info);
Self {
flags,
- mode,
- size,
+ mode_size,
mtime,
}
}
@@ -75,12 +73,9 @@
Self::new_possibly_dirty()
} else if mtime == MTIME_UNSET {
Self {
- flags: Flags::WDIR_TRACKED
- | Flags::P1_TRACKED
- | Flags::POSSIBLY_DIRTY,
- mode,
- size,
- mtime: 0,
+ flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED,
+ mode_size: Some((mode, size)),
+ mtime: None,
}
} else {
Self::new_normal(mode, size, mtime)
@@ -89,18 +84,15 @@
EntryState::Added => Self::new_added(),
EntryState::Removed => Self {
flags: if size == SIZE_NON_NORMAL {
- Flags::P1_TRACKED // might not be true because of rename ?
- | Flags::P2_TRACKED // might not be true because of rename ?
- | Flags::MERGED
+ Flags::P1_TRACKED | Flags::P2_INFO
} else if size == SIZE_FROM_OTHER_PARENT {
// We don’t know if P1_TRACKED should be set (file history)
- Flags::P2_TRACKED | Flags::CLEAN_P2
+ Flags::P2_INFO
} else {
Flags::P1_TRACKED
},
- mode: 0,
- size: 0,
- mtime: 0,
+ mode_size: None,
+ mtime: None,
},
EntryState::Merged => Self::new_merged(),
}
@@ -109,30 +101,25 @@
pub fn new_from_p2() -> Self {
Self {
// might be missing P1_TRACKED
- flags: Flags::WDIR_TRACKED | Flags::P2_TRACKED | Flags::CLEAN_P2,
- mode: 0,
- size: SIZE_FROM_OTHER_PARENT,
- mtime: MTIME_UNSET,
+ flags: Flags::WDIR_TRACKED | Flags::P2_INFO,
+ mode_size: None,
+ mtime: None,
}
}
pub fn new_possibly_dirty() -> Self {
Self {
- flags: Flags::WDIR_TRACKED
- | Flags::P1_TRACKED
- | Flags::POSSIBLY_DIRTY,
- mode: 0,
- size: SIZE_NON_NORMAL,
- mtime: MTIME_UNSET,
+ flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED,
+ mode_size: None,
+ mtime: None,
}
}
pub fn new_added() -> Self {
Self {
flags: Flags::WDIR_TRACKED,
- mode: 0,
- size: SIZE_NON_NORMAL,
- mtime: MTIME_UNSET,
+ mode_size: None,
+ mtime: None,
}
}
@@ -140,20 +127,17 @@
Self {
flags: Flags::WDIR_TRACKED
| Flags::P1_TRACKED // might not be true because of rename ?
- | Flags::P2_TRACKED // might not be true because of rename ?
- | Flags::MERGED,
- mode: 0,
- size: SIZE_NON_NORMAL,
- mtime: MTIME_UNSET,
+ | Flags::P2_INFO, // might not be true because of rename ?
+ mode_size: None,
+ mtime: None,
}
}
pub fn new_normal(mode: i32, size: i32, mtime: i32) -> Self {
Self {
flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED,
- mode,
- size,
- mtime,
+ mode_size: Some((mode, size)),
+ mtime: Some(mtime),
}
}
@@ -169,36 +153,34 @@
self.flags.contains(Flags::WDIR_TRACKED)
}
- fn tracked_in_any_parent(&self) -> bool {
- self.flags.intersects(Flags::P1_TRACKED | Flags::P2_TRACKED)
+ fn in_either_parent(&self) -> bool {
+ self.flags.intersects(Flags::P1_TRACKED | Flags::P2_INFO)
}
pub fn removed(&self) -> bool {
- self.tracked_in_any_parent()
- && !self.flags.contains(Flags::WDIR_TRACKED)
+ self.in_either_parent() && !self.flags.contains(Flags::WDIR_TRACKED)
}
pub fn merged(&self) -> bool {
- self.flags.contains(Flags::WDIR_TRACKED | Flags::MERGED)
+ self.flags
+ .contains(Flags::WDIR_TRACKED | Flags::P1_TRACKED | Flags::P2_INFO)
}
pub fn added(&self) -> bool {
- self.flags.contains(Flags::WDIR_TRACKED)
- && !self.tracked_in_any_parent()
+ self.flags.contains(Flags::WDIR_TRACKED) && !self.in_either_parent()
}
pub fn from_p2(&self) -> bool {
- self.flags.contains(Flags::WDIR_TRACKED | Flags::CLEAN_P2)
+ self.flags.contains(Flags::WDIR_TRACKED | Flags::P2_INFO)
+ && !self.flags.contains(Flags::P1_TRACKED)
}
pub fn maybe_clean(&self) -> bool {
if !self.flags.contains(Flags::WDIR_TRACKED) {
false
- } else if self.added() {
+ } else if !self.flags.contains(Flags::P1_TRACKED) {
false
- } else if self.flags.contains(Flags::MERGED) {
- false
- } else if self.flags.contains(Flags::CLEAN_P2) {
+ } else if self.flags.contains(Flags::P2_INFO) {
false
} else {
true
@@ -207,11 +189,15 @@
pub fn any_tracked(&self) -> bool {
self.flags.intersects(
- Flags::WDIR_TRACKED | Flags::P1_TRACKED | Flags::P2_TRACKED,
+ Flags::WDIR_TRACKED | Flags::P1_TRACKED | Flags::P2_INFO,
)
}
- pub fn state(&self) -> EntryState {
+ fn v1_state(&self) -> EntryState {
+ if !self.any_tracked() {
+ // TODO: return an Option instead?
+ panic!("Accessing v1_state of an untracked DirstateEntry")
+ }
if self.removed() {
EntryState::Removed
} else if self.merged() {
@@ -223,14 +209,24 @@
}
}
- pub fn mode(&self) -> i32 {
- self.mode
+ fn v1_mode(&self) -> i32 {
+ if let Some((mode, _size)) = self.mode_size {
+ mode
+ } else {
+ 0
+ }
}
- pub fn size(&self) -> i32 {
- if self.removed() && self.flags.contains(Flags::MERGED) {
+ fn v1_size(&self) -> i32 {
+ if !self.any_tracked() {
+ // TODO: return an Option instead?
+ panic!("Accessing v1_size of an untracked DirstateEntry")
+ }
+ if self.removed()
+ && self.flags.contains(Flags::P1_TRACKED | Flags::P2_INFO)
+ {
SIZE_NON_NORMAL
- } else if self.removed() && self.flags.contains(Flags::CLEAN_P2) {
+ } else if self.removed() && self.flags.contains(Flags::P2_INFO) {
SIZE_FROM_OTHER_PARENT
} else if self.removed() {
0
@@ -240,60 +236,73 @@
SIZE_NON_NORMAL
} else if self.from_p2() {
SIZE_FROM_OTHER_PARENT
- } else if self.flags.contains(Flags::POSSIBLY_DIRTY) {
- self.size // TODO: SIZE_NON_NORMAL ?
+ } else if let Some((_mode, size)) = self.mode_size {
+ size
} else {
- self.size
+ SIZE_NON_NORMAL
+ }
+ }
+
+ fn v1_mtime(&self) -> i32 {
+ if !self.any_tracked() {
+ // TODO: return an Option instead?
+ panic!("Accessing v1_mtime of an untracked DirstateEntry")
+ }
+ if self.removed() {
+ 0
+ } else if self.flags.contains(Flags::P2_INFO) {
+ MTIME_UNSET
+ } else if !self.flags.contains(Flags::P1_TRACKED) {
+ MTIME_UNSET
+ } else {
+ self.mtime.unwrap_or(MTIME_UNSET)
}
}
+ // TODO: return `Option<EntryState>`? None when `!self.any_tracked`
+ pub fn state(&self) -> EntryState {
+ self.v1_state()
+ }
+
+ // TODO: return Option?
+ pub fn mode(&self) -> i32 {
+ self.v1_mode()
+ }
+
+ // TODO: return Option?
+ pub fn size(&self) -> i32 {
+ self.v1_size()
+ }
+
+ // TODO: return Option?
pub fn mtime(&self) -> i32 {
- if self.removed() {
- 0
- } else if self.flags.contains(Flags::POSSIBLY_DIRTY) {
- MTIME_UNSET
- } else if self.merged() {
- MTIME_UNSET
- } else if self.added() {
- MTIME_UNSET
- } else if self.from_p2() {
- MTIME_UNSET
- } else {
- self.mtime
- }
+ self.v1_mtime()
}
pub fn set_possibly_dirty(&mut self) {
- self.flags.insert(Flags::POSSIBLY_DIRTY)
+ self.mtime = None
}
pub fn set_clean(&mut self, mode: i32, size: i32, mtime: i32) {
self.flags.insert(Flags::WDIR_TRACKED | Flags::P1_TRACKED);
- self.flags.remove(
- Flags::P2_TRACKED // This might be wrong
- | Flags::MERGED
- | Flags::CLEAN_P2
- | Flags::POSSIBLY_DIRTY,
- );
- self.mode = mode;
- self.size = size;
- self.mtime = mtime;
+ self.mode_size = Some((mode, size));
+ self.mtime = Some(mtime);
}
pub fn set_tracked(&mut self) {
- self.flags
- .insert(Flags::WDIR_TRACKED | Flags::POSSIBLY_DIRTY);
- // size = None on the python size turn into size = NON_NORMAL when
- // accessed. So the next line is currently required, but a some future
- // clean up would be welcome.
- self.size = SIZE_NON_NORMAL;
+ self.flags.insert(Flags::WDIR_TRACKED);
+ // `set_tracked` is replacing various `normallookup` call. So we mark
+ // the files as needing lookup
+ //
+ // Consider dropping this in the future in favor of something less
+ // broad.
+ self.mtime = None;
}
pub fn set_untracked(&mut self) {
self.flags.remove(Flags::WDIR_TRACKED);
- self.mode = 0;
- self.size = 0;
- self.mtime = 0;
+ self.mode_size = None;
+ self.mtime = None;
}
/// Returns `(state, mode, size, mtime)` for the puprose of serialization
@@ -303,7 +312,12 @@
/// want to not represent these cases that way in memory, but serialization
/// will need to keep the same format.
pub fn v1_data(&self) -> (u8, i32, i32, i32) {
- (self.state().into(), self.mode(), self.size(), self.mtime())
+ (
+ self.v1_state().into(),
+ self.v1_mode(),
+ self.v1_size(),
+ self.v1_mtime(),
+ )
}
pub(crate) fn is_from_other_parent(&self) -> bool {
@@ -327,12 +341,7 @@
/// Returns a `(state, mode, size, mtime)` tuple as for
/// `DirstateMapMethods::debug_iter`.
pub fn debug_tuple(&self) -> (u8, i32, i32, i32) {
- let state = if self.flags.contains(Flags::ENTRYLESS_TREE_NODE) {
- b' '
- } else {
- self.state().into()
- };
- (state, self.mode(), self.size(), self.mtime())
+ (self.state().into(), self.mode(), self.size(), self.mtime())
}
pub fn mtime_is_ambiguous(&self, now: i32) -> bool {
@@ -351,14 +360,10 @@
// dirstate, forcing future 'status' calls to compare the
// contents of the file if the size is the same. This prevents
// mistakenly treating such files as clean.
- self.clear_mtime()
+ self.set_possibly_dirty()
}
ambiguous
}
-
- pub fn clear_mtime(&mut self) {
- self.mtime = -1;
- }
}
impl EntryState {
@@ -53,36 +53,32 @@
# about file tracking
- wc_tracked: is the file tracked by the working copy
- p1_tracked: is the file tracked in working copy first parent
- - p2_tracked: is the file tracked in working copy second parent
-
- # about what possible merge action related to this file
- - clean_p1: merge picked the file content from p1
- - clean_p2: merge picked the file content from p2
- - merged: file gather changes from both side.
+ - p2_info: the file has been involved in some merge operation. Either
+ because it was actually merged, or because the p2 version was
+ ahead, or because some renamed moved it there. In either case
+ `hg status` will want it displayed as modified.
# about the file state expected from p1 manifest:
- mode: the file mode in p1
- size: the file size in p1
+ These value can be set to None, which mean we don't have a meaningful value
+ to compare with. Either because we don't really care about them as there
+ `status` is known without having to look at the disk or because we don't
+ know these right now and a full comparison will be needed to find out if
+ the file is clean.
+
# about the file state on disk last time we saw it:
- mtime: the last known clean mtime for the file.
- The last three item (mode, size and mtime) can be None if no meaningful (or
- trusted) value exists.
-
+ This value can be set to None if no cachable state exist. Either because we
+ do not care (see previous section) or because we could not cache something
+ yet.
"""
_wc_tracked = attr.ib()
_p1_tracked = attr.ib()
- _p2_tracked = attr.ib()
- # the three item above should probably be combined
- #
- # However it is unclear if they properly cover some of the most advanced
- # merge case. So we should probably wait on this to be settled.
- _merged = attr.ib()
- _clean_p1 = attr.ib()
- _clean_p2 = attr.ib()
- _possibly_dirty = attr.ib()
+ _p2_info = attr.ib()
_mode = attr.ib()
_size = attr.ib()
_mtime = attr.ib()
@@ -91,32 +87,25 @@
self,
wc_tracked=False,
p1_tracked=False,
- p2_tracked=False,
- merged=False,
- clean_p1=False,
- clean_p2=False,
- possibly_dirty=False,
+ p2_info=False,
+ has_meaningful_data=True,
+ has_meaningful_mtime=True,
parentfiledata=None,
):
- if merged and (clean_p1 or clean_p2):
- msg = b'`merged` argument incompatible with `clean_p1`/`clean_p2`'
- raise error.ProgrammingError(msg)
-
- assert not (merged and not p1_tracked)
self._wc_tracked = wc_tracked
self._p1_tracked = p1_tracked
- self._p2_tracked = p2_tracked
- self._merged = merged
- self._clean_p1 = clean_p1
- self._clean_p2 = clean_p2
- self._possibly_dirty = possibly_dirty
+ self._p2_info = p2_info
+
+ self._mode = None
+ self._size = None
+ self._mtime = None
if parentfiledata is None:
- self._mode = None
- self._size = None
- self._mtime = None
- else:
+ has_meaningful_mtime = False
+ has_meaningful_data = False
+ if has_meaningful_data:
self._mode = parentfiledata[0]
self._size = parentfiledata[1]
+ if has_meaningful_mtime:
self._mtime = parentfiledata[2]
@classmethod
@@ -125,11 +114,7 @@
Should eventually be removed
"""
- instance = cls()
- instance._wc_tracked = True
- instance._p1_tracked = False
- instance._p2_tracked = False
- return instance
+ return cls(wc_tracked=True)
@classmethod
def new_merged(cls):
@@ -137,12 +122,7 @@
Should eventually be removed
"""
- instance = cls()
- instance._wc_tracked = True
- instance._p1_tracked = True # might not be True because of rename ?
- instance._p2_tracked = True # might not be True because of rename ?
- instance._merged = True
- return instance
+ return cls(wc_tracked=True, p1_tracked=True, p2_info=True)
@classmethod
def new_from_p2(cls):
@@ -150,12 +130,7 @@
Should eventually be removed
"""
- instance = cls()
- instance._wc_tracked = True
- instance._p1_tracked = False # might actually be True
- instance._p2_tracked = True
- instance._clean_p2 = True
- return instance
+ return cls(wc_tracked=True, p2_info=True)
@classmethod
def new_possibly_dirty(cls):
@@ -163,11 +138,7 @@
Should eventually be removed
"""
- instance = cls()
- instance._wc_tracked = True
- instance._p1_tracked = True
- instance._possibly_dirty = True
- return instance
+ return cls(wc_tracked=True, p1_tracked=True)
@classmethod
def new_normal(cls, mode, size, mtime):
@@ -177,13 +148,11 @@
"""
assert size != FROM_P2
assert size != NONNORMAL
- instance = cls()
- instance._wc_tracked = True
- instance._p1_tracked = True
- instance._mode = mode
- instance._size = size
- instance._mtime = mtime
- return instance
+ return cls(
+ wc_tracked=True,
+ p1_tracked=True,
+ parentfiledata=(mode, size, mtime),
+ )
@classmethod
def from_v1_data(cls, state, mode, size, mtime):
@@ -197,25 +166,16 @@
elif state == b'a':
return cls.new_added()
elif state == b'r':
- instance = cls()
- instance._wc_tracked = False
if size == NONNORMAL:
- instance._merged = True
- instance._p1_tracked = (
- True # might not be True because of rename ?
- )
- instance._p2_tracked = (
- True # might not be True because of rename ?
- )
+ p1_tracked = True
+ p2_info = True
elif size == FROM_P2:
- instance._clean_p2 = True
- instance._p1_tracked = (
- False # We actually don't know (file history)
- )
- instance._p2_tracked = True
+ p1_tracked = False
+ p2_info = True
else:
- instance._p1_tracked = True
- return instance
+ p1_tracked = True
+ p2_info = False
+ return cls(p1_tracked=p1_tracked, p2_info=p2_info)
elif state == b'n':
if size == FROM_P2:
return cls.new_from_p2()
@@ -224,7 +184,6 @@
elif mtime == AMBIGUOUS_TIME:
instance = cls.new_normal(mode, size, 42)
instance._mtime = None
- instance._possibly_dirty = True
return instance
else:
return cls.new_normal(mode, size, mtime)
@@ -237,7 +196,7 @@
This means the next status call will have to actually check its content
to make sure it is correct.
"""
- self._possibly_dirty = True
+ self._mtime = None
def set_clean(self, mode, size, mtime):
"""mark a file as "clean" cancelling potential "possibly dirty call"
@@ -249,10 +208,6 @@
"""
self._wc_tracked = True
self._p1_tracked = True
- self._p2_tracked = False # this might be wrong
- self._merged = False
- self._clean_p2 = False
- self._possibly_dirty = False
self._mode = mode
self._size = size
self._mtime = mtime
@@ -263,11 +218,11 @@
This will ultimately be called by command like `hg add`.
"""
self._wc_tracked = True
- # `set_tracked` is replacing various `normallookup` call. So we set
- # "possibly dirty" to stay on the safe side.
+ # `set_tracked` is replacing various `normallookup` call. So we mark
+ # the files as needing lookup
#
# Consider dropping this in the future in favor of something less broad.
- self._possibly_dirty = True
+ self._mtime = None
def set_untracked(self):
"""mark a file as untracked in the working copy
@@ -284,18 +239,11 @@
This is to be call by the dirstatemap code when the second parent is dropped
"""
- if not (self.merged or self.from_p2):
- return
- self._p1_tracked = self.merged # why is this not already properly set ?
-
- self._merged = False
- self._clean_p1 = False
- self._clean_p2 = False
- self._p2_tracked = False
- self._possibly_dirty = True
- self._mode = None
- self._size = None
- self._mtime = None
+ if self._p2_info:
+ self._p2_info = False
+ self._mode = None
+ self._size = None
+ self._mtime = None
@property
def mode(self):
@@ -334,23 +282,21 @@
@property
def any_tracked(self):
"""True is the file is tracked anywhere (wc or parents)"""
- return self._wc_tracked or self._p1_tracked or self._p2_tracked
+ return self._wc_tracked or self._p1_tracked or self._p2_info
@property
def added(self):
"""True if the file has been added"""
- return self._wc_tracked and not (self._p1_tracked or self._p2_tracked)
+ return self._wc_tracked and not (self._p1_tracked or self._p2_info)
@property
def maybe_clean(self):
"""True if the file has a chance to be in the "clean" state"""
if not self._wc_tracked:
return False
- elif self.added:
+ elif not self._p1_tracked:
return False
- elif self._merged:
- return False
- elif self._clean_p2:
+ elif self._p2_info:
return False
return True
@@ -360,7 +306,7 @@
Should only be set if a merge is in progress in the dirstate
"""
- return self._wc_tracked and self._merged
+ return self._wc_tracked and self._p1_tracked and self._p2_info
@property
def from_p2(self):
@@ -370,18 +316,16 @@
Should only be set if a merge is in progress in the dirstate
"""
- if not self._wc_tracked:
- return False
- return self._clean_p2
+ return self._wc_tracked and (not self._p1_tracked) and self._p2_info
@property
def removed(self):
"""True if the file has been removed"""
- return not self._wc_tracked and (self._p1_tracked or self._p2_tracked)
+ return not self._wc_tracked and (self._p1_tracked or self._p2_info)
def v1_state(self):
"""return a "state" suitable for v1 serialization"""
- if not (self._p1_tracked or self._p2_tracked or self._wc_tracked):
+ if not self.any_tracked:
# the object has no state to record, this is -currently-
# unsupported
raise RuntimeError('untracked item')
@@ -404,9 +348,9 @@
# the object has no state to record, this is -currently-
# unsupported
raise RuntimeError('untracked item')
- elif self.removed and self._merged:
+ elif self.removed and self._p1_tracked and self._p2_info:
return NONNORMAL
- elif self.removed and self._clean_p2:
+ elif self.removed and self._p2_info:
return FROM_P2
elif self.removed:
return 0
@@ -416,8 +360,8 @@
return NONNORMAL
elif self.from_p2:
return FROM_P2
- elif self._possibly_dirty:
- return self._size if self._size is not None else NONNORMAL
+ elif self._size is None:
+ return NONNORMAL
else:
return self._size
@@ -429,16 +373,14 @@
raise RuntimeError('untracked item')
elif self.removed:
return 0
- elif self._possibly_dirty:
- return AMBIGUOUS_TIME
- elif self.merged:
+ elif self._mtime is None:
return AMBIGUOUS_TIME
- elif self.added:
+ elif self._p2_info:
return AMBIGUOUS_TIME
- elif self.from_p2:
+ elif not self._p1_tracked:
return AMBIGUOUS_TIME
else:
- return self._mtime if self._mtime is not None else 0
+ return self._mtime
def need_delay(self, now):
"""True if the stored mtime would be ambiguous with the current time"""
@@ -211,37 +211,20 @@
self._dirs_decr(filename, old_entry=old_entry)
self.copymap.pop(filename, None)
return
- elif merged:
- pass
- elif not (p1_tracked or p2_tracked) and wc_tracked:
- pass # file is added, nothing special to adjust
- elif (p1_tracked or p2_tracked) and not wc_tracked:
- pass
- elif clean_p2 and wc_tracked:
- pass
- elif not p1_tracked and p2_tracked and wc_tracked:
- clean_p2 = True
- elif possibly_dirty:
- pass
- elif wc_tracked:
- # this is a "normal" file
- if parentfiledata is None:
- msg = b'failed to pass parentfiledata for a normal file: %s'
- msg %= filename
- raise error.ProgrammingError(msg)
- else:
- assert False, 'unreachable'
+
+ p2_info = merged or clean_p2
+ if merged:
+ assert p1_tracked
+
+ has_meaningful_mtime = not possibly_dirty
old_entry = self._map.get(filename)
self._dirs_incr(filename, old_entry)
entry = DirstateItem(
wc_tracked=wc_tracked,
p1_tracked=p1_tracked,
- p2_tracked=p2_tracked,
- merged=merged,
- clean_p1=clean_p1,
- clean_p2=clean_p2,
- possibly_dirty=possibly_dirty,
+ p2_info=p2_info,
+ has_meaningful_mtime=has_meaningful_mtime,
parentfiledata=parentfiledata,
)
self._map[filename] = entry
@@ -251,16 +234,7 @@
entry = self.get(filename)
if entry is None:
self._dirs_incr(filename)
- entry = DirstateItem(
- p1_tracked=False,
- p2_tracked=False,
- wc_tracked=True,
- merged=False,
- clean_p1=False,
- clean_p2=False,
- possibly_dirty=False,
- parentfiledata=None,
- )
+ entry = DirstateItem(wc_tracked=True)
self._map[filename] = entry
new = True
elif not entry.tracked:
@@ -33,11 +33,9 @@
static const unsigned char dirstate_flag_wc_tracked = 1;
static const unsigned char dirstate_flag_p1_tracked = 1 << 1;
-static const unsigned char dirstate_flag_p2_tracked = 1 << 2;
-static const unsigned char dirstate_flag_possibly_dirty = 1 << 3;
-static const unsigned char dirstate_flag_merged = 1 << 4;
-static const unsigned char dirstate_flag_clean_p1 = 1 << 5;
-static const unsigned char dirstate_flag_clean_p2 = 1 << 6;
+static const unsigned char dirstate_flag_p2_info = 1 << 2;
+static const unsigned char dirstate_flag_has_meaningful_data = 1 << 3;
+static const unsigned char dirstate_flag_has_meaningful_mtime = 1 << 4;
extern PyTypeObject dirstateItemType;
#define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateItemType)
@@ -52,37 +52,32 @@
dirstateItemObject *t;
int wc_tracked;
int p1_tracked;
- int p2_tracked;
- int merged;
- int clean_p1;
- int clean_p2;
- int possibly_dirty;
+ int p2_info;
+ int has_meaningful_data;
+ int has_meaningful_mtime;
+ int mode;
+ int size;
+ int mtime;
PyObject *parentfiledata;
static char *keywords_name[] = {
- "wc_tracked", "p1_tracked", "p2_tracked",
- "merged", "clean_p1", "clean_p2",
- "possibly_dirty", "parentfiledata", NULL,
+ "wc_tracked",
+ "p1_tracked",
+ "p2_info",
+ "has_meaningful_data",
+ "has_meaningful_mtime",
+ "parentfiledata",
+ NULL,
};
wc_tracked = 0;
p1_tracked = 0;
- p2_tracked = 0;
- merged = 0;
- clean_p1 = 0;
- clean_p2 = 0;
- possibly_dirty = 0;
+ p2_info = 0;
+ has_meaningful_mtime = 1;
+ has_meaningful_data = 1;
parentfiledata = Py_None;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiiiiiiO", keywords_name,
- &wc_tracked, &p1_tracked, &p2_tracked,
- &merged, &clean_p1, &clean_p2,
- &possibly_dirty, &parentfiledata
-
- )) {
- return NULL;
- }
- if (merged && (clean_p1 || clean_p2)) {
- PyErr_SetString(PyExc_RuntimeError,
- "`merged` argument incompatible with "
- "`clean_p1`/`clean_p2`");
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "|iiiiiO", keywords_name, &wc_tracked, &p1_tracked,
+ &p2_info, &has_meaningful_data, &has_meaningful_mtime,
+ &parentfiledata)) {
return NULL;
}
t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
@@ -97,24 +92,10 @@
if (p1_tracked) {
t->flags |= dirstate_flag_p1_tracked;
}
- if (p2_tracked) {
- t->flags |= dirstate_flag_p2_tracked;
- }
- if (possibly_dirty) {
- t->flags |= dirstate_flag_possibly_dirty;
- }
- if (merged) {
- t->flags |= dirstate_flag_merged;
+ if (p2_info) {
+ t->flags |= dirstate_flag_p2_info;
}
- if (clean_p1) {
- t->flags |= dirstate_flag_clean_p1;
- }
- if (clean_p2) {
- t->flags |= dirstate_flag_clean_p2;
- }
- t->mode = 0;
- t->size = dirstate_v1_nonnormal;
- t->mtime = ambiguous_time;
+
if (parentfiledata != Py_None) {
if (!PyTuple_CheckExact(parentfiledata)) {
PyErr_SetString(
@@ -122,12 +103,26 @@
"parentfiledata should be a Tuple or None");
return NULL;
}
- t->mode =
- (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 0));
- t->size =
- (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 1));
- t->mtime =
- (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 2));
+ mode = (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 0));
+ size = (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 1));
+ mtime = (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 2));
+ } else {
+ has_meaningful_data = 0;
+ has_meaningful_mtime = 0;
+ }
+ if (has_meaningful_data) {
+ t->flags |= dirstate_flag_has_meaningful_data;
+ t->mode = mode;
+ t->size = size;
+ } else {
+ t->mode = 0;
+ t->size = 0;
+ }
+ if (has_meaningful_mtime) {
+ t->flags |= dirstate_flag_has_meaningful_mtime;
+ t->mtime = mtime;
+ } else {
+ t->mtime = 0;
}
return (PyObject *)t;
}
@@ -142,12 +137,20 @@
return (self->flags & dirstate_flag_wc_tracked);
}
+static inline bool dirstate_item_c_any_tracked(dirstateItemObject *self)
+{
+ const unsigned char mask = dirstate_flag_wc_tracked |
+ dirstate_flag_p1_tracked |
+ dirstate_flag_p2_info;
+ return (self->flags & mask);
+}
+
static inline bool dirstate_item_c_added(dirstateItemObject *self)
{
- unsigned char mask =
+ const unsigned char mask =
(dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
- dirstate_flag_p2_tracked);
- unsigned char target = dirstate_flag_wc_tracked;
+ dirstate_flag_p2_info);
+ const unsigned char target = dirstate_flag_wc_tracked;
return (self->flags & mask) == target;
}
@@ -157,21 +160,21 @@
return false;
}
return (self->flags &
- (dirstate_flag_p1_tracked | dirstate_flag_p2_tracked));
+ (dirstate_flag_p1_tracked | dirstate_flag_p2_info));
}
static inline bool dirstate_item_c_merged(dirstateItemObject *self)
{
return ((self->flags & dirstate_flag_wc_tracked) &&
- (self->flags & dirstate_flag_merged));
+ (self->flags & dirstate_flag_p1_tracked) &&
+ (self->flags & dirstate_flag_p2_info));
}
static inline bool dirstate_item_c_from_p2(dirstateItemObject *self)
{
- if (!dirstate_item_c_tracked(self)) {
- return false;
- }
- return (self->flags & dirstate_flag_clean_p2);
+ return ((self->flags & dirstate_flag_wc_tracked) &&
+ !(self->flags & dirstate_flag_p1_tracked) &&
+ (self->flags & dirstate_flag_p2_info));
}
static inline char dirstate_item_c_v1_state(dirstateItemObject *self)
@@ -189,29 +192,32 @@
static inline int dirstate_item_c_v1_mode(dirstateItemObject *self)
{
- return self->mode;
+ if (self->flags & dirstate_flag_has_meaningful_data) {
+ return self->mode;
+ } else {
+ return 0;
+ }
}
static inline int dirstate_item_c_v1_size(dirstateItemObject *self)
{
- if (dirstate_item_c_removed(self) &&
- (self->flags & dirstate_flag_merged)) {
- return dirstate_v1_nonnormal;
- } else if (dirstate_item_c_removed(self) &&
- (self->flags & dirstate_flag_clean_p2)) {
- return dirstate_v1_from_p2;
+ if (!(self->flags & dirstate_flag_wc_tracked) &&
+ (self->flags & dirstate_flag_p2_info)) {
+ if (self->flags & dirstate_flag_p1_tracked) {
+ return dirstate_v1_nonnormal;
+ } else {
+ return dirstate_v1_from_p2;
+ }
} else if (dirstate_item_c_removed(self)) {
return 0;
- } else if (dirstate_item_c_merged(self)) {
+ } else if (self->flags & dirstate_flag_p2_info) {
return dirstate_v1_from_p2;
} else if (dirstate_item_c_added(self)) {
return dirstate_v1_nonnormal;
- } else if (dirstate_item_c_from_p2(self)) {
- return dirstate_v1_from_p2;
- } else if (self->flags & dirstate_flag_possibly_dirty) {
- return self->size; /* NON NORMAL ? */
+ } else if (self->flags & dirstate_flag_has_meaningful_data) {
+ return self->size;
} else {
- return self->size;
+ return dirstate_v1_nonnormal;
}
}
@@ -219,13 +225,10 @@
{
if (dirstate_item_c_removed(self)) {
return 0;
- } else if (self->flags & dirstate_flag_possibly_dirty) {
- return ambiguous_time;
- } else if (dirstate_item_c_merged(self)) {
- return ambiguous_time;
- } else if (dirstate_item_c_added(self)) {
- return ambiguous_time;
- } else if (dirstate_item_c_from_p2(self)) {
+ } else if (!(self->flags & dirstate_flag_has_meaningful_mtime) ||
+ !(self->flags & dirstate_flag_p1_tracked) ||
+ !(self->flags & dirstate_flag_wc_tracked) ||
+ (self->flags & dirstate_flag_p2_info)) {
return ambiguous_time;
} else {
return self->mtime;
@@ -278,58 +281,43 @@
if (!t) {
return NULL;
}
+ t->flags = 0;
+ t->mode = 0;
+ t->size = 0;
+ t->mtime = 0;
if (state == 'm') {
- t->flags =
- (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
- dirstate_flag_p2_tracked | dirstate_flag_merged);
- t->mode = 0;
- t->size = dirstate_v1_from_p2;
- t->mtime = ambiguous_time;
+ t->flags = (dirstate_flag_wc_tracked |
+ dirstate_flag_p1_tracked | dirstate_flag_p2_info);
} else if (state == 'a') {
t->flags = dirstate_flag_wc_tracked;
- t->mode = 0;
- t->size = dirstate_v1_nonnormal;
- t->mtime = ambiguous_time;
} else if (state == 'r') {
- t->mode = 0;
- t->size = 0;
- t->mtime = 0;
if (size == dirstate_v1_nonnormal) {
t->flags =
- (dirstate_flag_p1_tracked |
- dirstate_flag_p2_tracked | dirstate_flag_merged);
+ dirstate_flag_p1_tracked | dirstate_flag_p2_info;
} else if (size == dirstate_v1_from_p2) {
- t->flags =
- (dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
+ t->flags = dirstate_flag_p2_info;
} else {
t->flags = dirstate_flag_p1_tracked;
}
} else if (state == 'n') {
if (size == dirstate_v1_from_p2) {
t->flags =
- (dirstate_flag_wc_tracked |
- dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
- t->mode = 0;
- t->size = dirstate_v1_from_p2;
- t->mtime = ambiguous_time;
+ dirstate_flag_wc_tracked | dirstate_flag_p2_info;
} else if (size == dirstate_v1_nonnormal) {
- t->flags = (dirstate_flag_wc_tracked |
- dirstate_flag_p1_tracked |
- dirstate_flag_possibly_dirty);
- t->mode = 0;
- t->size = dirstate_v1_nonnormal;
- t->mtime = ambiguous_time;
+ t->flags =
+ dirstate_flag_wc_tracked | dirstate_flag_p1_tracked;
} else if (mtime == ambiguous_time) {
t->flags = (dirstate_flag_wc_tracked |
dirstate_flag_p1_tracked |
- dirstate_flag_possibly_dirty);
+ dirstate_flag_has_meaningful_data);
t->mode = mode;
t->size = size;
- t->mtime = 0;
} else {
t->flags = (dirstate_flag_wc_tracked |
- dirstate_flag_p1_tracked);
+ dirstate_flag_p1_tracked |
+ dirstate_flag_has_meaningful_data |
+ dirstate_flag_has_meaningful_mtime);
t->mode = mode;
t->size = size;
t->mtime = mtime;
@@ -371,8 +359,8 @@
}
t->flags = dirstate_flag_wc_tracked;
t->mode = 0;
- t->size = dirstate_v1_nonnormal;
- t->mtime = ambiguous_time;
+ t->size = 0;
+ t->mtime = 0;
return (PyObject *)t;
};
@@ -387,10 +375,10 @@
return NULL;
}
t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
- dirstate_flag_p2_tracked | dirstate_flag_merged);
+ dirstate_flag_p2_info);
t->mode = 0;
- t->size = dirstate_v1_from_p2;
- t->mtime = ambiguous_time;
+ t->size = 0;
+ t->mtime = 0;
return (PyObject *)t;
};
@@ -406,11 +394,10 @@
if (!t) {
return NULL;
}
- t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p2_tracked |
- dirstate_flag_clean_p2);
+ t->flags = dirstate_flag_wc_tracked | dirstate_flag_p2_info;
t->mode = 0;
- t->size = dirstate_v1_from_p2;
- t->mtime = ambiguous_time;
+ t->size = 0;
+ t->mtime = 0;
return (PyObject *)t;
};
@@ -426,11 +413,10 @@
if (!t) {
return NULL;
}
- t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
- dirstate_flag_possibly_dirty);
+ t->flags = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked;
t->mode = 0;
- t->size = dirstate_v1_nonnormal;
- t->mtime = ambiguous_time;
+ t->size = 0;
+ t->mtime = 0;
return (PyObject *)t;
};
@@ -462,7 +448,7 @@
to make sure it is correct. */
static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
{
- self->flags |= dirstate_flag_possibly_dirty;
+ self->flags &= ~dirstate_flag_has_meaningful_mtime;
Py_RETURN_NONE;
}
@@ -474,7 +460,9 @@
if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
return NULL;
}
- self->flags = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked;
+ self->flags = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
+ dirstate_flag_has_meaningful_data |
+ dirstate_flag_has_meaningful_mtime;
self->mode = mode;
self->size = size;
self->mtime = mtime;
@@ -484,11 +472,7 @@
static PyObject *dirstate_item_set_tracked(dirstateItemObject *self)
{
self->flags |= dirstate_flag_wc_tracked;
- self->flags |= dirstate_flag_possibly_dirty;
- /* size = None on the python size turn into size = NON_NORMAL when
- * accessed. So the next line is currently required, but a some future
- * clean up would be welcome. */
- self->size = dirstate_v1_nonnormal;
+ self->flags &= ~dirstate_flag_has_meaningful_mtime;
Py_RETURN_NONE;
}
@@ -503,22 +487,13 @@
static PyObject *dirstate_item_drop_merge_data(dirstateItemObject *self)
{
- if (dirstate_item_c_merged(self) || dirstate_item_c_from_p2(self)) {
- if (dirstate_item_c_merged(self)) {
- self->flags |= dirstate_flag_p1_tracked;
- } else {
- self->flags &= ~dirstate_flag_p1_tracked;
- }
- self->flags &=
- ~(dirstate_flag_merged | dirstate_flag_clean_p1 |
- dirstate_flag_clean_p2 | dirstate_flag_p2_tracked);
- self->flags |= dirstate_flag_possibly_dirty;
+ if (self->flags & dirstate_flag_p2_info) {
+ self->flags &= ~(dirstate_flag_p2_info |
+ dirstate_flag_has_meaningful_data |
+ dirstate_flag_has_meaningful_mtime);
self->mode = 0;
self->mtime = 0;
- /* size = None on the python size turn into size = NON_NORMAL
- * when accessed. So the next line is currently required, but a
- * some future clean up would be welcome. */
- self->size = dirstate_v1_nonnormal;
+ self->size = 0;
}
Py_RETURN_NONE;
}
@@ -624,11 +599,9 @@
{
if (!(self->flags & dirstate_flag_wc_tracked)) {
Py_RETURN_FALSE;
- } else if (dirstate_item_c_added(self)) {
+ } else if (!(self->flags & dirstate_flag_p1_tracked)) {
Py_RETURN_FALSE;
- } else if (self->flags & dirstate_flag_merged) {
- Py_RETURN_FALSE;
- } else if (self->flags & dirstate_flag_clean_p2) {
+ } else if (self->flags & dirstate_flag_p2_info) {
Py_RETURN_FALSE;
} else {
Py_RETURN_TRUE;
@@ -637,10 +610,7 @@
static PyObject *dirstate_item_get_any_tracked(dirstateItemObject *self)
{
- unsigned char mask = dirstate_flag_wc_tracked |
- dirstate_flag_p1_tracked |
- dirstate_flag_p2_tracked;
- if ((self->flags & mask) != 0) {
+ if (dirstate_item_c_any_tracked(self)) {
Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;