summaryrefslogtreecommitdiff
path: root/git
diff options
context:
space:
mode:
Diffstat (limited to 'git')
-rw-r--r--git/remote.py101
-rw-r--r--git/repo/base.py28
-rw-r--r--git/util.py8
3 files changed, 86 insertions, 51 deletions
diff --git a/git/remote.py b/git/remote.py
index d3639f7b..0920a7c4 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -24,7 +24,7 @@ from refs import (
TagReference
)
-from git.util import join_path
+from git.util import join_path
from gitdb.util import join
import re
@@ -33,6 +33,58 @@ import sys
__all__ = ('RemoteProgress', 'PushInfo', 'FetchInfo', 'Remote')
+#{ Utilities
+
+def digest_process_messages(fh, progress):
+ """Read progress messages from file-like object fh, supplying the respective
+ progress messages to the progress instance.
+
+ :param fh: File handle to read from
+ :return: list(line, ...) list of lines without linebreaks that did
+ not contain progress information"""
+ line_so_far = ''
+ dropped_lines = list()
+ while True:
+ char = fh.read(1)
+ if not char:
+ break
+
+ if char in ('\r', '\n'):
+ dropped_lines.extend(progress._parse_progress_line(line_so_far))
+ line_so_far = ''
+ else:
+ line_so_far += char
+ # END process parsed line
+ # END while file is not done reading
+ return dropped_lines
+
+def finalize_process(proc):
+ """Wait for the process (clone, fetch, pull or push) and handle its errors accordingly"""
+ try:
+ proc.wait()
+ except GitCommandError,e:
+ # if a push has rejected items, the command has non-zero return status
+ # a return status of 128 indicates a connection error - reraise the previous one
+ if proc.poll() == 128:
+ raise
+ pass
+ # END exception handling
+
+def add_progress(kwargs, git, progress):
+ """Add the --progress flag to the given kwargs dict if supported by the
+ git command. If the actual progress in the given progress instance is not
+ given, we do not request any progress
+ :return: possibly altered kwargs"""
+ if progress is not None:
+ v = git.version_info
+ if v[0] > 1 or v[1] > 7 or v[2] > 0 or v[3] > 3:
+ kwargs['progress'] = True
+ #END handle --progress
+ #END handle progress
+ return kwargs
+
+#} END utilities
+
class PushInfo(object):
"""
@@ -432,42 +484,6 @@ class Remote(LazyMixin, Iterable):
self.repo.git.remote("update", self.name)
return self
- def _digest_process_messages(self, fh, progress):
- """Read progress messages from file-like object fh, supplying the respective
- progress messages to the progress instance.
-
- :return: list(line, ...) list of lines without linebreaks that did
- not contain progress information"""
- line_so_far = ''
- dropped_lines = list()
- while True:
- char = fh.read(1)
- if not char:
- break
-
- if char in ('\r', '\n'):
- dropped_lines.extend(progress._parse_progress_line(line_so_far))
- line_so_far = ''
- else:
- line_so_far += char
- # END process parsed line
- # END while file is not done reading
- return dropped_lines
-
-
- def _finalize_proc(self, proc):
- """Wait for the process (fetch, pull or push) and handle its errors accordingly"""
- try:
- proc.wait()
- except GitCommandError,e:
- # if a push has rejected items, the command has non-zero return status
- # a return status of 128 indicates a connection error - reraise the previous one
- if proc.poll() == 128:
- raise
- pass
- # END exception handling
-
-
def _get_fetch_info_from_stderr(self, proc, progress):
# skip first line as it is some remote info we are not interested in
output = IterableList('name')
@@ -477,7 +493,7 @@ class Remote(LazyMixin, Iterable):
# this also waits for the command to finish
# Skip some progress lines that don't provide relevant information
fetch_info_lines = list()
- for line in self._digest_process_messages(proc.stderr, progress):
+ for line in digest_process_messages(proc.stderr, progress):
if line.startswith('From') or line.startswith('remote: Total'):
continue
elif line.startswith('warning:'):
@@ -499,7 +515,7 @@ class Remote(LazyMixin, Iterable):
output.extend(FetchInfo._from_line(self.repo, err_line, fetch_line)
for err_line,fetch_line in zip(fetch_info_lines, fetch_head_info))
- self._finalize_proc(proc)
+ finalize_process(proc)
return output
def _get_push_info(self, proc, progress):
@@ -507,7 +523,7 @@ class Remote(LazyMixin, Iterable):
# we hope stdout can hold all the data, it should ...
# read the lines manually as it will use carriage returns between the messages
# to override the previous one. This is why we read the bytes manually
- self._digest_process_messages(proc.stderr, progress)
+ digest_process_messages(proc.stderr, progress)
output = IterableList('name')
for line in proc.stdout.readlines():
@@ -519,7 +535,7 @@ class Remote(LazyMixin, Iterable):
# END exception handling
# END for each line
- self._finalize_proc(proc)
+ finalize_process(proc)
return output
@@ -546,6 +562,7 @@ class Remote(LazyMixin, Iterable):
:note:
As fetch does not provide progress information to non-ttys, we cannot make
it available here unfortunately as in the 'push' method."""
+ kwargs = add_progress(kwargs, self.repo.git, progress)
proc = self.repo.git.fetch(self, refspec, with_extended_output=True, as_process=True, v=True, **kwargs)
return self._get_fetch_info_from_stderr(proc, progress or RemoteProgress())
@@ -557,6 +574,7 @@ class Remote(LazyMixin, Iterable):
:param progress: see 'push' method
:param kwargs: Additional arguments to be passed to git-pull
:return: Please see 'fetch' method """
+ kwargs = add_progress(kwargs, self.repo.git, progress)
proc = self.repo.git.pull(self, refspec, with_extended_output=True, as_process=True, v=True, **kwargs)
return self._get_fetch_info_from_stderr(proc, progress or RemoteProgress())
@@ -578,6 +596,7 @@ class Remote(LazyMixin, Iterable):
in their flags.
If the operation fails completely, the length of the returned IterableList will
be null."""
+ kwargs = add_progress(kwargs, self.repo.git, progress)
proc = self.repo.git.push(self, refspec, porcelain=True, as_process=True, **kwargs)
return self._get_push_info(proc, progress or RemoteProgress())
diff --git a/git/repo/base.py b/git/repo/base.py
index 0405a5f9..14efabdc 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -11,13 +11,18 @@ from git.refs import *
from git.index import IndexFile
from git.objects import *
from git.config import GitConfigParser
-from git.remote import Remote
+from git.remote import (
+ Remote,
+ digest_process_messages,
+ finalize_process,
+ add_progress
+ )
+
from git.db import (
GitCmdObjectDB,
GitDB
)
-
from gitdb.util import (
join,
isfile,
@@ -652,7 +657,7 @@ class Repo(object):
return Repo(path)
@classmethod
- def _clone(cls, git, url, path, odb_default_type, **kwargs):
+ def _clone(cls, git, url, path, odb_default_type, progress, **kwargs):
# special handling for windows for path at which the clone should be
# created.
# tilde '~' will be expanded to the HOME no matter where the ~ occours. Hence
@@ -679,7 +684,11 @@ class Repo(object):
# END windows handling
try:
- git.clone(url, path, **kwargs)
+ proc = git.clone(url, path, with_extended_output=True, as_process=True, v=True, **add_progress(kwargs, git, progress))
+ if progress:
+ digest_process_messages(proc.stderr, progress)
+ #END handle progress
+ finalize_process(proc)
finally:
if prev_cwd is not None:
os.chdir(prev_cwd)
@@ -703,11 +712,13 @@ class Repo(object):
# END handle remote repo
return repo
- def clone(self, path, **kwargs):
+ def clone(self, path, progress=None, **kwargs):
"""Create a clone from this repository.
:param path:
is the full path of the new repo (traditionally ends with ./<name>.git).
+ :param progress: See 'git.remote.Remote.push'.
+
:param kwargs:
odbt = ObjectDatabase Type, allowing to determine the object database
implementation used by the returned Repo instance
@@ -715,16 +726,17 @@ class Repo(object):
All remaining keyword arguments are given to the git-clone command
:return: ``git.Repo`` (the newly cloned repo)"""
- return self._clone(self.git, self.git_dir, path, type(self.odb), **kwargs)
+ return self._clone(self.git, self.git_dir, path, type(self.odb), progress, **kwargs)
@classmethod
- def clone_from(cls, url, to_path, **kwargs):
+ def clone_from(cls, url, to_path, progress=None, **kwargs):
"""Create a clone from the given URL
:param url: valid git url, see http://www.kernel.org/pub/software/scm/git/docs/git-clone.html#URLS
:param to_path: Path to which the repository should be cloned to
+ :param progress: See 'git.remote.Remote.push'.
:param kwargs: see the ``clone`` method
:return: Repo instance pointing to the cloned directory"""
- return cls._clone(Git(os.getcwd()), url, to_path, GitCmdObjectDB, **kwargs)
+ return cls._clone(Git(os.getcwd()), url, to_path, GitCmdObjectDB, progress, **kwargs)
def archive(self, ostream, treeish=None, prefix=None, **kwargs):
"""Archive the tree at the given revision.
diff --git a/git/util.py b/git/util.py
index 7cbef07f..0492b63c 100644
--- a/git/util.py
+++ b/git/util.py
@@ -109,8 +109,8 @@ class RemoteProgress(object):
Handler providing an interface to parse progress information emitted by git-push
and git-fetch and to dispatch callbacks allowing subclasses to react to the progress.
"""
- _num_op_codes = 5
- BEGIN, END, COUNTING, COMPRESSING, WRITING = [1 << x for x in range(_num_op_codes)]
+ _num_op_codes = 7
+ BEGIN, END, COUNTING, COMPRESSING, WRITING, RECEIVING, RESOLVING = [1 << x for x in range(_num_op_codes)]
STAGE_MASK = BEGIN|END
OP_MASK = ~STAGE_MASK
@@ -168,6 +168,10 @@ class RemoteProgress(object):
op_code |= self.COMPRESSING
elif op_name == "Writing objects":
op_code |= self.WRITING
+ elif op_name == 'Receiving objects':
+ op_code |= self.RECEIVING
+ elif op_name == 'Resolving deltas':
+ op_code |= self.RESOLVING
else:
raise ValueError("Operation name %r unknown" % op_name)