chiark / gitweb /
Merge branch 'stable'
[stgit] / stgit / git.py
index 4dc4dcfef738ed3dcaef3b7c1072899af9b1c1d0..ee31ecd07a5a7d17d1a9bba364658e97c0cdaedc 100644 (file)
@@ -167,7 +167,7 @@ def exclude_files():
         files.append(user_exclude)
     return files
 
         files.append(user_exclude)
     return files
 
-def ls_files(files, tree = None, full_name = True):
+def ls_files(files, tree = 'HEAD', full_name = True):
     """Return the files known to GIT or raise an error otherwise. It also
     converts the file to the full path relative the the .git directory.
     """
     """Return the files known to GIT or raise an error otherwise. It also
     converts the file to the full path relative the the .git directory.
     """
@@ -190,8 +190,24 @@ def ls_files(files, tree = None, full_name = True):
             'Some of the given paths are either missing or not known to GIT'
     return list(fileset)
 
             'Some of the given paths are either missing or not known to GIT'
     return list(fileset)
 
+def parse_git_ls(output):
+    """Parse the output of git diff-index, diff-files, etc. Doesn't handle
+    rename/copy output, so don't feed it output generated with the -M
+    or -C flags."""
+    t = None
+    for line in output.split('\0'):
+        if not line:
+            # There's a zero byte at the end of the output, which
+            # gives us an empty string as the last "line".
+            continue
+        if t == None:
+            mode_a, mode_b, sha1_a, sha1_b, t = line.split(' ')
+        else:
+            yield (t, line)
+            t = None
+
 def tree_status(files = None, tree_id = 'HEAD', unknown = False,
 def tree_status(files = None, tree_id = 'HEAD', unknown = False,
-                  noexclude = True, verbose = False, diff_flags = []):
+                  noexclude = True, verbose = False):
     """Get the status of all changed files, or of a selected set of
     files. Returns a list of pairs - (status, filename).
 
     """Get the status of all changed files, or of a selected set of
     files. Returns a list of pairs - (status, filename).
 
@@ -206,6 +222,8 @@ def tree_status(files = None, tree_id = 'HEAD', unknown = False,
 
     refresh_index()
 
 
     refresh_index()
 
+    if files is None:
+        files = []
     cache_files = []
 
     # unknown files
     cache_files = []
 
     # unknown files
@@ -228,26 +246,37 @@ def tree_status(files = None, tree_id = 'HEAD', unknown = False,
     cache_files += [('C', filename) for filename in conflicts
                     if not files or filename in files]
     reported_files = set(conflicts)
     cache_files += [('C', filename) for filename in conflicts
                     if not files or filename in files]
     reported_files = set(conflicts)
+    files_left = [f for f in files if f not in reported_files]
 
 
-    # files in the index
-    args = diff_flags + [tree_id]
-    if files:
-        args += ['--'] + files
-    for line in GRun('diff-index', *args).output_lines():
-        fs = tuple(line.rstrip().split(' ',4)[-1].split('\t',1))
-        if fs[1] not in reported_files:
-            cache_files.append(fs)
-            reported_files.add(fs[1])
-
-    # files in the index but changed on (or removed from) disk
-    args = list(diff_flags)
-    if files:
-        args += ['--'] + files
-    for line in GRun('diff-files', *args).output_lines():
-        fs = tuple(line.rstrip().split(' ',4)[-1].split('\t',1))
-        if fs[1] not in reported_files:
-            cache_files.append(fs)
-            reported_files.add(fs[1])
+    # files in the index. Only execute this code if no files were
+    # specified when calling the function (i.e. report all files) or
+    # files were specified but already found in the previous step
+    if not files or files_left:
+        args = [tree_id]
+        if files_left:
+            args += ['--'] + files_left
+        for t, fn in parse_git_ls(GRun('diff-index', '-z', *args).raw_output()):
+            # the condition is needed in case files is emtpy and
+            # diff-index lists those already reported
+            if not fn in reported_files:
+                cache_files.append((t, fn))
+                reported_files.add(fn)
+        files_left = [f for f in files if f not in reported_files]
+
+    # files in the index but changed on (or removed from) disk. Only
+    # execute this code if no files were specified when calling the
+    # function (i.e. report all files) or files were specified but
+    # already found in the previous step
+    if not files or files_left:
+        args = []
+        if files_left:
+            args += ['--'] + files_left
+        for t, fn in parse_git_ls(GRun('diff-files', '-z', *args).raw_output()):
+            # the condition is needed in case files is empty and
+            # diff-files lists those already reported
+            if not fn in reported_files:
+                cache_files.append((t, fn))
+                reported_files.add(fn)
 
     if verbose:
         out.done()
 
     if verbose:
         out.done()
@@ -853,7 +882,6 @@ def refspec_remotepart(refspec):
         return m.group(1)
     else:
         raise GitException, 'Cannot parse refspec "%s"' % line
         return m.group(1)
     else:
         raise GitException, 'Cannot parse refspec "%s"' % line
-    
 
 def __remotes_from_config():
     return config.sections_matching(r'remote\.(.*)\.url')
 
 def __remotes_from_config():
     return config.sections_matching(r'remote\.(.*)\.url')