Patchwork D11320: dirstate-item: feed more information to `__init__`

login
register
mail settings
Submitter phabricator
Date Aug. 21, 2021, 9:57 a.m.
Message ID <differential-rev-PHID-DREV-dsqjnf6l2cy4rd6cfx4b-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49636/
State Superseded
Headers show

Comments

phabricator - Aug. 21, 2021, 9:57 a.m.
marmoute created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  Instead of processing the "rich" value at the `dirstatemap` level, we can now directly pass them to the DirstateItem object. This will make the object free to store whatever its want and to implements it logic whatever its want.
  
  For now… we simply process the flag and store the same good old value. However
  this pave the way for doing things differently once the rest of dirstatemap
  code is updated.
  
  Nobody call this code yet.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D11320

AFFECTED FILES
  mercurial/cext/parsers.c
  mercurial/pure/parsers.py

CHANGE DETAILS




To: marmoute, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/mercurial/pure/parsers.py b/mercurial/pure/parsers.py
--- a/mercurial/pure/parsers.py
+++ b/mercurial/pure/parsers.py
@@ -61,11 +61,62 @@ 
     _size = attr.ib()
     _mtime = attr.ib()
 
-    def __init__(self, state, mode, size, mtime):
-        self._state = state
-        self._mode = mode
-        self._size = size
-        self._mtime = mtime
+    def __init__(
+        self,
+        wc_tracked=False,
+        p1_tracked=False,
+        p2_tracked=False,
+        merged=False,
+        clean_p1=False,
+        clean_p2=False,
+        possibly_dirty=False,
+        parentfiledata=None,
+    ):
+        if merged and (clean_p1 or clean_p2):
+            msg = b'`merged` argument incompatible with `clean_p1`/`clean_p2`'
+            raise error.ProgrammingError(msg)
+
+        self._state = None
+        self._mode = 0
+        self._size = NONNORMAL
+        self._mtime = AMBIGUOUS_TIME
+        if not (p1_tracked or p2_tracked or wc_tracked):
+            pass  # the object has no state to record
+        elif merged:
+            self._state = b'm'
+            self._size = FROM_P2
+            self._mtime = AMBIGUOUS_TIME
+        elif not (p1_tracked or p2_tracked) and wc_tracked:
+            self._state = b'a'
+            self._size = NONNORMAL
+            self._mtime = AMBIGUOUS_TIME
+        elif (p1_tracked or p2_tracked) and not wc_tracked:
+            self._state = b'r'
+            self._size = 0
+            self._mtime = 0
+        elif clean_p2 and wc_tracked:
+            self._state = b'n'
+            self._size = FROM_P2
+            self._mtime = AMBIGUOUS_TIME
+        elif not p1_tracked and p2_tracked and wc_tracked:
+            self._state = b'n'
+            self._size = FROM_P2
+            self._mtime = AMBIGUOUS_TIME
+        elif possibly_dirty:
+            self._state = b'n'
+            self._size = NONNORMAL
+            self._mtime = AMBIGUOUS_TIME
+        elif wc_tracked:
+            # this is a "normal" file
+            if parentfiledata is None:
+                msg = b'failed to pass parentfiledata for a normal file'
+                raise error.ProgrammingError(msg)
+            self._state = b'n'
+            self._mode = parentfiledata[0]
+            self._size = parentfiledata[1]
+            self._mtime = parentfiledata[2]
+        else:
+            assert False, 'unreachable'
 
     @classmethod
     def from_v1_data(cls, state, mode, size, mtime):
@@ -74,12 +125,12 @@ 
         Since the dirstate-v1 format is frozen, the signature of this function
         is not expected to change, unlike the __init__ one.
         """
-        return cls(
-            state=state,
-            mode=mode,
-            size=size,
-            mtime=mtime,
-        )
+        instance = cls()
+        instance._state = state
+        instance._mode = mode
+        instance._size = size
+        instance._mtime = mtime
+        return instance
 
     def set_possibly_dirty(self):
         """Mark a file as "possibly dirty"
diff --git a/mercurial/cext/parsers.c b/mercurial/cext/parsers.c
--- a/mercurial/cext/parsers.c
+++ b/mercurial/cext/parsers.c
@@ -65,21 +65,100 @@ 
 	/* We do all the initialization here and not a tp_init function because
 	 * dirstate_item is immutable. */
 	dirstateItemObject *t;
-	char state;
-	int size, mode, mtime;
-	if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
+	int wc_tracked;
+	int p1_tracked;
+	int p2_tracked;
+	int merged;
+	int clean_p1;
+	int clean_p2;
+	int possibly_dirty;
+	PyObject *parentfiledata;
+	static char *keywords_name[] = {
+	    "wc_tracked",     "p1_tracked",     "p2_tracked",
+	    "merged",         "clean_p1",       "clean_p2",
+	    "possibly_dirty", "parentfiledata", NULL,
+	};
+	wc_tracked = 0;
+	p1_tracked = 0;
+	p2_tracked = 0;
+	merged = 0;
+	clean_p1 = 0;
+	clean_p2 = 0;
+	possibly_dirty = 0;
+	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`");
+		return NULL;
+	}
 	t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
 	if (!t) {
 		return NULL;
 	}
-	t->state = state;
-	t->mode = mode;
-	t->size = size;
-	t->mtime = mtime;
-
+	t->state = 'r';
+	t->mode = 0;
+	t->size = dirstate_v1_nonnormal;
+	t->mtime = ambiguous_time;
+	if (!(p1_tracked || p2_tracked || wc_tracked)) {
+		/* Nothing special to do, file is untracked */
+	} else if (merged) {
+		t->state = 'm';
+		t->size = dirstate_v1_from_p2;
+		t->mtime = ambiguous_time;
+	} else if (!(p1_tracked || p2_tracked) && wc_tracked) {
+		t->state = 'a';
+		t->size = dirstate_v1_nonnormal;
+		t->mtime = ambiguous_time;
+	} else if ((p1_tracked || p2_tracked) && !wc_tracked) {
+		t->state = 'r';
+		t->size = 0;
+		t->mtime = 0;
+	} else if (clean_p2 && wc_tracked) {
+		t->state = 'n';
+		t->size = dirstate_v1_from_p2;
+		t->mtime = ambiguous_time;
+	} else if (!p1_tracked && p2_tracked && wc_tracked) {
+		t->state = 'n';
+		t->size = dirstate_v1_from_p2;
+		t->mtime = ambiguous_time;
+	} else if (possibly_dirty) {
+		t->state = 'n';
+		t->size = dirstate_v1_nonnormal;
+		t->mtime = ambiguous_time;
+	} else if (wc_tracked) {
+		/* this is a "normal" file */
+		if (parentfiledata == Py_None) {
+			PyErr_SetString(
+			    PyExc_RuntimeError,
+			    "failed to pass parentfiledata for a normal file");
+			return NULL;
+		}
+		if (!PyTuple_CheckExact(parentfiledata)) {
+			PyErr_SetString(
+			    PyExc_TypeError,
+			    "parentfiledata should be a Tuple or None");
+			return NULL;
+		}
+		t->state = 'n';
+		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));
+	} else {
+		PyErr_SetString(PyExc_RuntimeError, "unreachable");
+		return NULL;
+	}
 	return (PyObject *)t;
 }