summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2009-11-22 14:44:30 +0100
committerSebastian Thiel <byronimo@gmail.com>2009-11-22 14:44:30 +0100
commit331ddc27a22bde33542f8c1a00b6b56da32e5033 (patch)
tree5f6e54b38b61d9759b3da19417a1c702a1ea0803
parent2c0dcc6fb3dfd39df5970d6da340a949902ae629 (diff)
downloadgitpython-331ddc27a22bde33542f8c1a00b6b56da32e5033.tar.gz
index.checkout: Added progress function and made adjustments to test
-rw-r--r--lib/git/index.py147
-rw-r--r--test/git/test_index.py64
2 files changed, 108 insertions, 103 deletions
diff --git a/lib/git/index.py b/lib/git/index.py
index 37dcd041..6485ff11 100644
--- a/lib/git/index.py
+++ b/lib/git/index.py
@@ -493,12 +493,66 @@ class IndexFile(LazyMixin, diff.Diffable):
ret |= (index_mode & 0111)
return ret
- @classmethod
- def _tree_mode_to_index_mode(cls, tree_mode):
- """
- Convert a tree mode to index mode as good as possible
- """
+ # UTILITIES
+ def _iter_expand_paths(self, paths):
+ """Expand the directories in list of paths to the corresponding paths accordingly,
+
+ Note: git will add items multiple times even if a glob overlapped
+ with manually specified paths or if paths where specified multiple
+ times - we respect that and do not prune"""
+ def raise_exc(e):
+ raise e
+ r = self.repo.git.git_dir
+ rs = r + '/'
+ for path in paths:
+ abs_path = path
+ if not os.path.isabs(abs_path):
+ abs_path = os.path.join(r, path)
+ # END make absolute path
+
+ # resolve globs if possible
+ if '?' in path or '*' in path or '[' in path:
+ for f in self._iter_expand_paths(glob.glob(abs_path)):
+ yield f.replace(rs, '')
+ continue
+ # END glob handling
+ try:
+ for root, dirs, files in os.walk(abs_path, onerror=raise_exc):
+ for rela_file in files:
+ # add relative paths only
+ yield os.path.join(root.replace(rs, ''), rela_file)
+ # END for each file in subdir
+ # END for each subdirectory
+ except OSError:
+ # was a file or something that could not be iterated
+ yield path.replace(rs, '')
+ # END path exception handling
+ # END for each path
+
+ def _write_path_to_stdin(self, proc, filepath, item, fmakeexc, fprogress, read_from_stdout=True):
+ """Write path to proc.stdin and make sure it processes the item, including progress.
+ @return: stdout string
+ @param read_from_stdout: if True, proc.stdout will be read after the item
+ was sent to stdin. In that case, it will return None
+ @note: There is a bug in git-update-index that prevents it from sending
+ reports just in time. This is why we have a version that tries to
+ read stdout and one which doesn't. In fact, the stdout is not
+ important as the piped-in files are processed anyway and just in time"""
+ fprogress(filepath, False, item)
+ rval = None
+ try:
+ proc.stdin.write("%s\n" % filepath)
+ except IOError:
+ # pipe broke, usually because some error happend
+ raise fmakeexc()
+ # END write exception handling
+ proc.stdin.flush()
+ if read_from_stdout:
+ rval = proc.stdout.readline().strip()
+ fprogress(filepath, True, item)
+ return rval
+
def iter_blobs(self, predicate = lambda t: True):
"""
Returns
@@ -735,68 +789,6 @@ class IndexFile(LazyMixin, diff.Diffable):
Objects that do not have a null sha will be added even if their paths
do not exist.
"""
- # UTILITIES
- def iter_expand_paths(paths):
- """Expand the directories in list of paths to the corresponding paths accordingly,
-
- Note: git will add items multiple times even if a glob overlapped
- with manually specified paths or if paths where specified multiple
- times - we respect that and do not prune"""
- def raise_exc(e):
- raise e
- r = self.repo.git.git_dir
- rs = r + '/'
- for path in paths:
- abs_path = path
- if not os.path.isabs(abs_path):
- abs_path = os.path.join(r, path)
- # END make absolute path
-
- # resolve globs if possible
- if '?' in path or '*' in path or '[' in path:
- for f in iter_expand_paths(glob.glob(abs_path)):
- yield f.replace(rs, '')
- continue
- # END glob handling
- try:
- for root, dirs, files in os.walk(abs_path, onerror=raise_exc):
- for rela_file in files:
- # add relative paths only
- yield os.path.join(root.replace(rs, ''), rela_file)
- # END for each file in subdir
- # END for each subdirectory
- except OSError:
- # was a file or something that could not be iterated
- yield path.replace(rs, '')
- # END path exception handling
- # END for each path
- # END expand helper method
-
- def write_path_to_stdin(proc, filepath, item, fmakeexc, read_from_stdout=True):
- """Write path to proc.stdin and make sure it processes the item, including progress.
- @return: stdout string
- @param read_from_stdout: if True, proc.stdout will be read after the item
- was sent to stdin. In that case, it will return None
- @note: There is a bug in git-update-index that prevents it from sending
- reports just in time. This is why we have a version that tries to
- read stdout and one which doesn't. In fact, the stdout is not
- important as the piped-in files are processed anyway and just in time"""
- fprogress(filepath, False, item)
- rval = None
- try:
- proc.stdin.write("%s\n" % filepath)
- except IOError:
- # pipe broke, usually because some error happend
- raise fmakeexc()
- # END write exception handling
- proc.stdin.flush()
- if read_from_stdout:
- rval = proc.stdout.readline().strip()
- fprogress(filepath, True, item)
- return rval
- # END write_path_to_stdin
-
-
# sort the entries into strings and Entries, Blobs are converted to entries
# automatically
# paths can be git-added, for everything else we use git-update-index
@@ -811,8 +803,8 @@ class IndexFile(LazyMixin, diff.Diffable):
make_exc = lambda : GitCommandError(("git-update-index",)+args, 128, proc.stderr.readline())
added_files = list()
- for filepath in iter_expand_paths(paths):
- write_path_to_stdin(proc, filepath, filepath, make_exc, read_from_stdout=False)
+ for filepath in self._iter_expand_paths(paths):
+ self._write_path_to_stdin(proc, filepath, filepath, make_exc, fprogress, read_from_stdout=False)
added_files.append(filepath)
# END for each filepath
self._flush_stdin_and_wait(proc) # ignore stdout
@@ -841,7 +833,7 @@ class IndexFile(LazyMixin, diff.Diffable):
obj_ids = list()
for ei in null_entries_indices:
entry = entries[ei]
- obj_ids.append(write_path_to_stdin(proc, entry.path, entry, make_exc))
+ obj_ids.append(self._write_path_to_stdin(proc, entry.path, entry, make_exc, fprogress))
# END for each entry index
assert len(obj_ids) == len(null_entries_indices), "git-hash-object did not produce all requested objects: want %i, got %i" % ( len(null_entries_indices), len(obj_ids) )
@@ -1001,7 +993,7 @@ class IndexFile(LazyMixin, diff.Diffable):
return stdout
@default_index
- def checkout(self, paths=None, force=False, **kwargs):
+ def checkout(self, paths=None, force=False, fprogress=lambda *args: None, **kwargs):
"""
Checkout the given paths or all files from the version in the index.
@@ -1009,11 +1001,15 @@ class IndexFile(LazyMixin, diff.Diffable):
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.
``force``
If True, existing files will be overwritten. If False, these will
be skipped.
+ ``fprogress``
+ see Index.add_ for signature and explanation
+
``**kwargs``
Additional arguments to be pasesd to git-checkout-index
@@ -1026,15 +1022,20 @@ class IndexFile(LazyMixin, diff.Diffable):
if paths is None:
args.append("--all")
+ fprogress(None, False, None)
self.repo.git.checkout_index(*args, **kwargs)
+ fprogress(None, True, None)
else:
if not isinstance(paths, (tuple,list)):
paths = [paths]
args.append("--stdin")
- paths = [self._to_relative_path(p) for p in paths]
co_proc = self.repo.git.checkout_index(args, as_process=True, istream=subprocess.PIPE, **kwargs)
- co_proc.stdin.write('\n'.join(paths))
+ make_exc = lambda : GitCommandError(("git-checkout-index",)+args, 128, co_proc.stderr.readline())
+ 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)
# END paths handling
return self
diff --git a/test/git/test_index.py b/test/git/test_index.py
index 26bc44c2..2a07ae97 100644
--- a/test/git/test_index.py
+++ b/test/git/test_index.py
@@ -20,27 +20,30 @@ class TestTree(TestBase):
super(TestTree, self).__init__(*args)
self._reset_progress()
- def _assert_add_progress(self, entries):
- assert len(entries) == len(self._add_progress_map)
- for path, call_count in self._add_progress_map.iteritems():
+ def _assert_fprogress(self, entries):
+ assert len(entries) == len(self._fprogress_map)
+ for path, call_count in self._fprogress_map.iteritems():
assert call_count == 2
self._reset_progress()
- def _add_progress(self, path, done, item):
- """Called as progress func - we keep track of the proper
- call order"""
- assert item is not None
- self._add_progress_map.setdefault(path, 0)
- curval = self._add_progress_map[path]
+ def _fprogress(self, path, done, item):
+ self._fprogress_map.setdefault(path, 0)
+ curval = self._fprogress_map[path]
if curval == 0:
assert not done
if curval == 1:
assert done
- self._add_progress_map[path] = curval + 1
+ self._fprogress_map[path] = curval + 1
+
+ def _fprogress_add(self, path, done, item):
+ """Called as progress func - we keep track of the proper
+ call order"""
+ assert item is not None
+ self._fprogress(path, done, item)
def _reset_progress(self):
# maps paths to the count of calls
- self._add_progress_map = dict()
+ self._fprogress_map = dict()
def test_index_file_base(self):
# read from file
@@ -207,22 +210,23 @@ class TestTree(TestBase):
# test full checkout
test_file = os.path.join(rw_repo.git.git_dir, "CHANGES")
os.remove(test_file)
- index.checkout(None, force=True)
+ index.checkout(None, force=True, fprogress=self._fprogress)
+ self._assert_fprogress([None])
assert os.path.isfile(test_file)
os.remove(test_file)
- index.checkout(None, force=False)
+ index.checkout(None, force=False, fprogress=self._fprogress)
+ self._assert_fprogress([None])
assert os.path.isfile(test_file)
# individual file
os.remove(test_file)
- index.checkout(test_file)
+ index.checkout(test_file, fprogress=self._fprogress)
+ self._assert_fprogress([test_file])
assert os.path.exists(test_file)
# checking out non-existing file is ignored/doesn't raise
index.checkout("doesnt_exist_ever.txt.that")
-
- # currently it ignore non-existing paths
index.checkout(paths=["doesnt/exist"])
@@ -324,19 +328,19 @@ class TestTree(TestBase):
assert os.path.isfile(os.path.join(rw_repo.git.git_dir, lib_file_path))
# directory
- entries = index.add(['lib'], fprogress=self._add_progress)
- self._assert_add_progress(entries)
+ entries = index.add(['lib'], fprogress=self._fprogress_add)
+ self._assert_fprogress(entries)
assert len(entries)>1
# glob
- entries = index.reset(new_commit).add(['lib/git/*.py'], fprogress=self._add_progress)
- self._assert_add_progress(entries)
+ entries = index.reset(new_commit).add(['lib/git/*.py'], fprogress=self._fprogress_add)
+ self._assert_fprogress(entries)
assert len(entries) == 14
# same file
- entries = index.reset(new_commit).add(['lib/git/head.py']*2, fprogress=self._add_progress)
+ entries = index.reset(new_commit).add(['lib/git/head.py']*2, fprogress=self._fprogress_add)
# would fail, test is too primitive to handle this case
- # self._assert_add_progress(entries)
+ # self._assert_fprogress(entries)
self._reset_progress()
assert len(entries) == 2
@@ -345,8 +349,8 @@ class TestTree(TestBase):
# blob from older revision overrides current index revision
old_blob = new_commit.parents[0].tree.blobs[0]
- entries = index.reset(new_commit).add([old_blob], fprogress=self._add_progress)
- self._assert_add_progress(entries)
+ entries = index.reset(new_commit).add([old_blob], fprogress=self._fprogress_add)
+ self._assert_fprogress(entries)
assert index.entries[(old_blob.path,0)].sha == old_blob.sha and len(entries) == 1
# mode 0 not allowed
@@ -356,16 +360,16 @@ class TestTree(TestBase):
# add new file
new_file_relapath = "my_new_file"
new_file_path = self._make_file(new_file_relapath, "hello world", rw_repo)
- entries = index.reset(new_commit).add([BaseIndexEntry((010644, null_sha, 0, new_file_relapath))], fprogress=self._add_progress)
- self._assert_add_progress(entries)
+ entries = index.reset(new_commit).add([BaseIndexEntry((010644, null_sha, 0, new_file_relapath))], fprogress=self._fprogress_add)
+ self._assert_fprogress(entries)
assert len(entries) == 1 and entries[0].sha != null_sha
# add symlink
if sys.platform != "win32":
link_file = os.path.join(rw_repo.git.git_dir, "my_real_symlink")
os.symlink("/etc/that", link_file)
- entries = index.reset(new_commit).add([link_file], fprogress=self._add_progress)
- self._assert_add_progress(entries)
+ entries = index.reset(new_commit).add([link_file], fprogress=self._fprogress_add)
+ self._assert_fprogress(entries)
assert len(entries) == 1 and S_ISLNK(entries[0].mode)
print "%o" % entries[0].mode
# END real symlink test
@@ -375,8 +379,8 @@ class TestTree(TestBase):
link_target = "/etc/that"
fake_symlink_path = self._make_file(fake_symlink_relapath, link_target, rw_repo)
fake_entry = BaseIndexEntry((0120000, null_sha, 0, fake_symlink_relapath))
- entries = index.reset(new_commit).add([fake_entry], fprogress=self._add_progress)
- self._assert_add_progress(entries)
+ entries = index.reset(new_commit).add([fake_entry], fprogress=self._fprogress_add)
+ self._assert_fprogress(entries)
assert entries[0].sha != null_sha
assert len(entries) == 1 and S_ISLNK(entries[0].mode)