Bug 1397406 - Add Repository method to determine if working directory clean; r=dustin
authorGregory Szorc <gps@mozilla.com>
Wed, 06 Sep 2017 12:15:12 -0700
changeset 428740 da68a5ff28d0cd132e031b1a67577a19274c01df
parent 428739 caccc7951f5bd8f0d4b840da0a7b9ea4a5d4df84
child 428741 e9416a307987f144f994dfeb6ed00b3277068279
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdustin
bugs1397406
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1397406 - Add Repository method to determine if working directory clean; r=dustin This is generally useful functionality to have. A consume will be introduced in an upcoming commit. MozReview-Commit-ID: 4arTMfJSiEC
python/mozversioncontrol/mozversioncontrol/__init__.py
--- a/python/mozversioncontrol/mozversioncontrol/__init__.py
+++ b/python/mozversioncontrol/mozversioncontrol/__init__.py
@@ -116,16 +116,28 @@ class Repository(object):
     def forget_add_remove_files(self, path):
         '''Undo the effects of a previous add_remove_files call for `path`.
         '''
 
     @abc.abstractmethod
     def get_files_in_working_directory(self):
         """Obtain a list of managed files in the working directory."""
 
+    @abc.abstractmethod
+    def working_directory_clean(self, untracked=False, ignored=False):
+        """Determine if the working directory is free of modifications.
+
+        Returns True if the working directory does not have any file
+        modifications. False otherwise.
+
+        By default, untracked and ignored files are not considered. If
+        ``untracked`` or ``ignored`` are set, they influence the clean check
+        to factor these file classes into consideration.
+        """
+
 
 class HgRepository(Repository):
     '''An implementation of `Repository` for Mercurial repositories.'''
     def __init__(self, path, hg='hg'):
         import hglib.client
 
         super(HgRepository, self).__init__(path, tool=hg)
         self._env[b'HGPLAIN'] = b'1'
@@ -202,16 +214,28 @@ class HgRepository(Repository):
         self._run('forget', path)
 
     def get_files_in_working_directory(self):
         # Can return backslashes on Windows. Normalize to forward slashes.
         return list(p.replace('\\', '/') for p in
                     self._run_in_client([b'files', b'-0']).split(b'\0')
                     if p)
 
+    def working_directory_clean(self, untracked=False, ignored=False):
+        args = [b'status', b'\0', b'--modified', b'--added', b'--removed',
+                b'--deleted']
+        if untracked:
+            args.append(b'--unknown')
+        if ignored:
+            args.append(b'--ignored')
+
+        # If output is empty, there are no entries of requested status, which
+        # means we are clean.
+        return not len(self._run_in_client(args).strip())
+
 
 class GitRepository(Repository):
     '''An implementation of `Repository` for Git repositories.'''
     def __init__(self, path, git='git'):
         super(GitRepository, self).__init__(path, tool=git)
 
     @property
     def name(self):
@@ -231,16 +255,25 @@ class GitRepository(Repository):
         self._run('add', path)
 
     def forget_add_remove_files(self, path):
         self._run('reset', path)
 
     def get_files_in_working_directory(self):
         return self._run('ls-files', '-z').split(b'\0')
 
+    def working_directory_clean(self, untracked=False, ignored=False):
+        args = ['status', '--porcelain']
+        if untracked:
+            args.append('--untracked-files')
+        if ignored:
+            args.append('--ignored')
+
+        return not len(self._run(*args).strip())
+
 
 class InvalidRepoPath(Exception):
     """Represents a failure to find a VCS repo at a specified path."""
 
 
 def get_repository_object(path, hg='hg', git='git'):
     '''Get a repository object for the repository at `path`.
     If `path` is not a known VCS repository, raise an exception.