pathutil: replace the `skip` argument of `dirs` with a boolean
authorPierre-Yves David <pierre-yves.david@octobus.net>
Mon, 30 Aug 2021 18:45:54 +0200
changeset 47944 e02f9af7aed1
parent 47943 fea24454f919
child 47945 3337eec29d5b
pathutil: replace the `skip` argument of `dirs` with a boolean It is ever only used for `r` file. So we make it a boolean this will give use more versatility later as we will stop storing the state explicitly. Differential Revision: https://phab.mercurial-scm.org/D11383
mercurial/cext/dirs.c
mercurial/dirstatemap.py
mercurial/pathutil.py
rust/hg-core/src/dirstate/dirs_multiset.rs
rust/hg-core/src/dirstate/dirstate_map.rs
rust/hg-cpython/src/dirstate/dirs_multiset.rs
--- a/mercurial/cext/dirs.c	Thu Sep 02 00:16:37 2021 +0200
+++ b/mercurial/cext/dirs.c	Mon Aug 30 18:45:54 2021 +0200
@@ -161,7 +161,7 @@
 	return ret;
 }
 
-static int dirs_fromdict(PyObject *dirs, PyObject *source, char skipchar)
+static int dirs_fromdict(PyObject *dirs, PyObject *source, bool only_tracked)
 {
 	PyObject *key, *value;
 	Py_ssize_t pos = 0;
@@ -171,13 +171,13 @@
 			PyErr_SetString(PyExc_TypeError, "expected string key");
 			return -1;
 		}
-		if (skipchar) {
+		if (only_tracked) {
 			if (!dirstate_tuple_check(value)) {
 				PyErr_SetString(PyExc_TypeError,
 				                "expected a dirstate tuple");
 				return -1;
 			}
-			if (((dirstateItemObject *)value)->state == skipchar)
+			if (((dirstateItemObject *)value)->state == 'r')
 				continue;
 		}
 
@@ -218,15 +218,17 @@
  * Calculate a refcounted set of directory names for the files in a
  * dirstate.
  */
-static int dirs_init(dirsObject *self, PyObject *args)
+static int dirs_init(dirsObject *self, PyObject *args, PyObject *kwargs)
 {
 	PyObject *dirs = NULL, *source = NULL;
-	char skipchar = 0;
+	int only_tracked = 0;
 	int ret = -1;
+	static char *keywords_name[] = {"map", "only_tracked", NULL};
 
 	self->dict = NULL;
 
-	if (!PyArg_ParseTuple(args, "|Oc:__init__", &source, &skipchar))
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:__init__",
+	                                 keywords_name, &source, &only_tracked))
 		return -1;
 
 	dirs = PyDict_New();
@@ -237,10 +239,10 @@
 	if (source == NULL)
 		ret = 0;
 	else if (PyDict_Check(source))
-		ret = dirs_fromdict(dirs, source, skipchar);
-	else if (skipchar)
+		ret = dirs_fromdict(dirs, source, (bool)only_tracked);
+	else if (only_tracked)
 		PyErr_SetString(PyExc_ValueError,
-		                "skip character is only supported "
+		                "`only_tracked` is only supported "
 		                "with a dict source");
 	else
 		ret = dirs_fromiter(dirs, source);
--- a/mercurial/dirstatemap.py	Thu Sep 02 00:16:37 2021 +0200
+++ b/mercurial/dirstatemap.py	Mon Aug 30 18:45:54 2021 +0200
@@ -377,7 +377,7 @@
 
     @propertycache
     def _dirs(self):
-        return pathutil.dirs(self._map, b'r')
+        return pathutil.dirs(self._map, only_tracked=True)
 
     @propertycache
     def _alldirs(self):
--- a/mercurial/pathutil.py	Thu Sep 02 00:16:37 2021 +0200
+++ b/mercurial/pathutil.py	Mon Aug 30 18:45:54 2021 +0200
@@ -315,20 +315,19 @@
 class dirs(object):
     '''a multiset of directory names from a set of file paths'''
 
-    def __init__(self, map, skip=None):
+    def __init__(self, map, only_tracked=False):
         """
         a dict map indicates a dirstate while a list indicates a manifest
         """
         self._dirs = {}
         addpath = self.addpath
-        if isinstance(map, dict) and skip is not None:
+        if isinstance(map, dict) and only_tracked:
             for f, s in pycompat.iteritems(map):
-                if s.state != skip:
+                if s.state != b'r':
                     addpath(f)
-        elif skip is not None:
-            raise error.ProgrammingError(
-                b"skip character is only supported with a dict source"
-            )
+        elif only_tracked:
+            msg = b"`only_tracked` is only supported with a dict source"
+            raise error.ProgrammingError(msg)
         else:
             for f in map:
                 addpath(f)
--- a/rust/hg-core/src/dirstate/dirs_multiset.rs	Thu Sep 02 00:16:37 2021 +0200
+++ b/rust/hg-core/src/dirstate/dirs_multiset.rs	Mon Aug 30 18:45:54 2021 +0200
@@ -33,7 +33,7 @@
     /// If `skip_state` is provided, skips dirstate entries with equal state.
     pub fn from_dirstate<I, P>(
         dirstate: I,
-        skip_state: Option<EntryState>,
+        only_tracked: bool,
     ) -> Result<Self, DirstateError>
     where
         I: IntoIterator<
@@ -48,8 +48,8 @@
             let (filename, entry) = item?;
             let filename = filename.as_ref();
             // This `if` is optimized out of the loop
-            if let Some(skip) = skip_state {
-                if skip != entry.state {
+            if only_tracked {
+                if entry.state != EntryState::Removed {
                     multiset.add_path(filename)?;
                 }
             } else {
@@ -343,7 +343,7 @@
 
         let new = DirsMultiset::from_dirstate(
             StateMap::default().into_iter().map(Ok),
-            None,
+            false,
         )
         .unwrap();
         let expected = DirsMultiset {
@@ -385,7 +385,7 @@
             .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
             .collect();
 
-        let new = DirsMultiset::from_dirstate(input_map, None).unwrap();
+        let new = DirsMultiset::from_dirstate(input_map, false).unwrap();
         let expected = DirsMultiset {
             inner: expected_inner,
         };
@@ -414,14 +414,12 @@
         });
 
         // "a" incremented with "a/c" and "a/d/"
-        let expected_inner = [("", 1), ("a", 2)]
+        let expected_inner = [("", 1), ("a", 3)]
             .iter()
             .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
             .collect();
 
-        let new =
-            DirsMultiset::from_dirstate(input_map, Some(EntryState::Normal))
-                .unwrap();
+        let new = DirsMultiset::from_dirstate(input_map, true).unwrap();
         let expected = DirsMultiset {
             inner: expected_inner,
         };
--- a/rust/hg-core/src/dirstate/dirstate_map.rs	Thu Sep 02 00:16:37 2021 +0200
+++ b/rust/hg-core/src/dirstate/dirstate_map.rs	Mon Aug 30 18:45:54 2021 +0200
@@ -334,7 +334,7 @@
         if self.all_dirs.is_none() {
             self.all_dirs = Some(DirsMultiset::from_dirstate(
                 self.state_map.iter().map(|(k, v)| Ok((k, *v))),
-                None,
+                false,
             )?);
         }
         Ok(())
@@ -344,7 +344,7 @@
         if self.dirs.is_none() {
             self.dirs = Some(DirsMultiset::from_dirstate(
                 self.state_map.iter().map(|(k, v)| Ok((k, *v))),
-                Some(EntryState::Removed),
+                true,
             )?);
         }
         Ok(())
--- a/rust/hg-cpython/src/dirstate/dirs_multiset.rs	Thu Sep 02 00:16:37 2021 +0200
+++ b/rust/hg-cpython/src/dirstate/dirs_multiset.rs	Mon Aug 30 18:45:54 2021 +0200
@@ -9,19 +9,16 @@
 //! `hg-core` package.
 
 use std::cell::RefCell;
-use std::convert::TryInto;
 
 use cpython::{
-    exc, ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyObject, PyResult,
-    Python, UnsafePyLeaked,
+    exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyObject,
+    PyResult, Python, UnsafePyLeaked,
 };
 
 use crate::dirstate::extract_dirstate;
 use hg::{
-    errors::HgError,
     utils::hg_path::{HgPath, HgPathBuf},
     DirsMultiset, DirsMultisetIter, DirstateError, DirstateMapError,
-    EntryState,
 };
 
 py_class!(pub class Dirs |py| {
@@ -32,22 +29,17 @@
     def __new__(
         _cls,
         map: PyObject,
-        skip: Option<PyObject> = None
+        only_tracked: Option<PyObject> = None
     ) -> PyResult<Self> {
-        let mut skip_state: Option<EntryState> = None;
-        if let Some(skip) = skip {
-            skip_state = Some(
-                skip.extract::<PyBytes>(py)?.data(py)[0]
-                    .try_into()
-                    .map_err(|e: HgError| {
-                        PyErr::new::<exc::ValueError, _>(py, e.to_string())
-                    })?,
-            );
-        }
+        let only_tracked_b = if let Some(only_tracked) = only_tracked {
+            only_tracked.extract::<PyBool>(py)?.is_true()
+        } else {
+            false
+        };
         let inner = if let Ok(map) = map.cast_as::<PyDict>(py) {
             let dirstate = extract_dirstate(py, &map)?;
             let dirstate = dirstate.iter().map(|(k, v)| Ok((k, *v)));
-            DirsMultiset::from_dirstate(dirstate, skip_state)
+            DirsMultiset::from_dirstate(dirstate, only_tracked_b)
                 .map_err(|e: DirstateError| {
                     PyErr::new::<exc::ValueError, _>(py, e.to_string())
                 })?