summaryrefslogtreecommitdiff
path: root/lib/git/index.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/git/index.py')
-rw-r--r--lib/git/index.py83
1 files changed, 69 insertions, 14 deletions
diff --git a/lib/git/index.py b/lib/git/index.py
index 6485ff11..fa6bf185 100644
--- a/lib/git/index.py
+++ b/lib/git/index.py
@@ -24,6 +24,20 @@ from git.objects import Blob, Tree, Object, Commit
from git.utils import SHA1Writer, LazyMixin, ConcurrentWriteOperation, join_path_native
+class CheckoutError( Exception ):
+ """Thrown if a file could not be checked out from the index as it contained
+ changes.
+
+ The .failed_files attribute contains a list of relative paths that failed
+ to be checked out as they contained changes that did not exist in the index"""
+ def __init__(self, message, failed_files):
+ super(CheckoutError, self).__init__(message)
+ self.failed_files = failed_files
+
+ def __str__(self):
+ return super(CheckoutError, self).__str__() + ":%s" % self.failed_files
+
+
class _TemporaryFileSwap(object):
"""
Utility class moving a file to a temporary location within the same directory
@@ -800,7 +814,7 @@ class IndexFile(LazyMixin, diff.Diffable):
# to get suitable progress information, pipe paths to stdin
args = ("--add", "--replace", "--verbose", "--stdin")
proc = self.repo.git.update_index(*args, **{'as_process':True, 'istream':subprocess.PIPE})
- make_exc = lambda : GitCommandError(("git-update-index",)+args, 128, proc.stderr.readline())
+ make_exc = lambda : GitCommandError(("git-update-index",)+args, 128, proc.stderr.read())
added_files = list()
for filepath in self._iter_expand_paths(paths):
@@ -829,7 +843,7 @@ class IndexFile(LazyMixin, diff.Diffable):
# send progress for these now.
args = ("-w", "--stdin-paths")
proc = self.repo.git.hash_object(*args, **{'istream':subprocess.PIPE, 'as_process':True})
- make_exc = lambda : GitCommandError(("git-hash-object",)+args, 128, proc.stderr.readline())
+ make_exc = lambda : GitCommandError(("git-hash-object",)+args, 128, proc.stderr.read())
obj_ids = list()
for ei in null_entries_indices:
entry = entries[ei]
@@ -999,13 +1013,16 @@ class IndexFile(LazyMixin, diff.Diffable):
``paths``
If None, all paths in the index will be checked out. Otherwise an iterable
- or single path of relative or absolute paths pointing to files is expected.
- The command will ignore paths that do not exist.
- The provided progress information will contain None as path and item.
+ of relative or absolute paths or a single path pointing to files in the index
+ is expected.
+ The command will raise of files do not exist in the index ( as opposed to the
+ original git command who ignores them )
+ The provided progress information will contain None as path and item if no
+ explicit paths are given.
``force``
- If True, existing files will be overwritten. If False, these will
- be skipped.
+ If True, existing files will be overwritten even if they contain local modifications.
+ If False, these will trigger a CheckoutError.
``fprogress``
see Index.add_ for signature and explanation
@@ -1015,28 +1032,66 @@ class IndexFile(LazyMixin, diff.Diffable):
Returns
self
+
+ Raise CheckoutError
+ If at least one file failed to be checked out. This is a summary,
+ hence it will checkout as many files as it can anyway.
+ Raise GitCommandError if error lines could not be parsed - this truly is
+ an exceptional state
"""
args = ["--index"]
if force:
args.append("--force")
+ def handle_stderr(proc):
+ stderr = proc.stderr.read()
+ if not stderr:
+ return
+ # line contents:
+ # git-checkout-index: this already exists
+ failed_files = list()
+ unknown_lines = list()
+ endings = (' already exists', ' is not in the cache', ' does not exist at stage', ' is unmerged')
+ for line in stderr.splitlines():
+ if not line.startswith("git checkout-index: ") and not line.startswith("git-checkout-index: "):
+ unknown_lines.append(line)
+ continue
+ # END unkown lines parsing
+
+ for e in endings:
+ if line.endswith(e):
+ failed_files.append(line[20:-len(e)])
+ break
+ # END if ending matches
+ # END for each possible ending
+ # END for each line
+ if unknown_lines:
+ raise GitCommandError(("git-checkout-index", ), 128, stderr)
+ if failed_files:
+ raise CheckoutError("Some files could not be checked out from the index due to local modifications", failed_files)
+ # END stderr handler
+
if paths is None:
args.append("--all")
+ kwargs['as_process'] = 1
fprogress(None, False, None)
- self.repo.git.checkout_index(*args, **kwargs)
+ proc = self.repo.git.checkout_index(*args, **kwargs)
+ proc.wait()
fprogress(None, True, None)
+ handle_stderr(proc)
else:
- if not isinstance(paths, (tuple,list)):
+ if isinstance(paths, basestring):
paths = [paths]
args.append("--stdin")
- co_proc = self.repo.git.checkout_index(args, as_process=True, istream=subprocess.PIPE, **kwargs)
- make_exc = lambda : GitCommandError(("git-checkout-index",)+args, 128, co_proc.stderr.readline())
+ proc = self.repo.git.checkout_index(args, as_process=True, istream=subprocess.PIPE, **kwargs)
+ make_exc = lambda : GitCommandError(("git-checkout-index",)+args, 128, proc.stderr.read())
for path in paths:
path = self._to_relative_path(path)
- self._write_path_to_stdin(co_proc, path, path, make_exc, fprogress, read_from_stdout=False)
- # END for each path
- self._flush_stdin_and_wait(co_proc)
+ self._write_path_to_stdin(proc, path, path, make_exc, fprogress, read_from_stdout=False)
+ # END for each path
+ self._flush_stdin_and_wait(proc)
+ handle_stderr(proc)
# END paths handling
return self