@@ -38,9 +38,87 @@ def _call_config(self, method, *args):
3838 return getattr (self ._config , method )(self ._section_name , * args )
3939
4040
41+ class PushProgress (object ):
42+ """
43+ Handler providing an interface to parse progress information emitted by git-push
44+ and to dispatch callbacks allowing subclasses to react to the progress.
45+ """
46+ BEGIN , END , COUNTING , COMPRESSING , WRITING = [ 1 << x for x in range (1 ,6 ) ]
47+ STAGE_MASK = BEGIN | END
48+ OP_MASK = COUNTING | COMPRESSING | WRITING
49+
50+ __slots__ = "_cur_line"
51+
52+ def _parse_progress_line (self , line ):
53+ """
54+ Parse progress information from the given line as retrieved by git-push
55+ """
56+ self ._cur_line = line
57+
58+ def line_dropped (self , line ):
59+ """
60+ Called whenever a line could not be understood and was therefore dropped.
61+ """
62+
63+ def update (self , op_code , cur_count , max_count = None ):
64+ """
65+ Called whenever the progress changes
66+
67+ ``op_code``
68+ Integer allowing to be compared against Operation IDs and stage IDs.
69+
70+ Stage IDs are BEGIN and END. BEGIN will only be set once for each Operation
71+ ID as well as END. It may be that BEGIN and END are set at once in case only
72+ one progress message was emitted due to the speed of the operation.
73+ Between BEGIN and END, none of these flags will be set
74+
75+ Operation IDs are all held within the OP_MASK. Only one Operation ID will
76+ be active per call.
77+
78+ ``cur_count``
79+ Current absolute count of items
80+
81+ ``max_count``
82+ The maximum count of items we expect. It may be None in case there is
83+ no maximum number of items or if it is (yet) unknown.
84+
85+ You may read the contents of the current line in self._cur_line
86+ """
87+
88+
89+ class PushInfo (object ):
90+ """
91+ Carries information about the result of a push operation of a single head::
92+ todo
93+
94+ """
95+ __slots__ = ('local_ref' , 'remote_ref' )
96+
97+ NO_MATCH , REJECTED , REMOTE_REJECTED , REMOTE_FAILURE , DELETED , \
98+ FORCED_UPDATE , FAST_FORWARD , ERROR = [ 1 << x for x in range (1 ,9 ) ]
99+
100+ _flag_map = { 'X' : NO_MATCH , '-' : DELETED , '*' : 0 ,
101+ '+' : FORCED_UPDATE , ' ' : FAST_FORWARD }
102+
103+ def __init__ (self , local_ref , remote_ref ):
104+ """
105+ Initialize a new instance
106+ """
107+ self .local_ref = local_ref
108+ self .remote_ref = remote_ref
109+
110+ @classmethod
111+ def _from_line (cls , repo , line ):
112+ """
113+ Create a new PushInfo instance as parsed from line which is expected to be like
114+ c refs/heads/master:refs/heads/master 05d2687..1d0568e
115+ """
116+ raise NotImplementedError ("todo" )
117+
118+
41119class FetchInfo (object ):
42120 """
43- Carries information about the results of a fetch operation::
121+ Carries information about the results of a fetch operation of a single head ::
44122
45123 info = remote.fetch()[0]
46124 info.ref # Symbolic Reference or RemoteReference to the changed
@@ -54,13 +132,13 @@ class FetchInfo(object):
54132 """
55133 __slots__ = ('ref' ,'commit_before_forced_update' , 'flags' , 'note' )
56134
57- BRANCH_UPTODATE , REJECTED , FORCED_UPDATE , FAST_FORWARD , NEW_TAG , \
58- TAG_UPDATE , NEW_BRANCH , ERROR = [ 1 << x for x in range (1 ,9 ) ]
135+ HEAD_UPTODATE , REJECTED , FORCED_UPDATE , FAST_FORWARD , NEW_TAG , \
136+ TAG_UPDATE , NEW_HEAD , ERROR = [ 1 << x for x in range (1 ,9 ) ]
59137 # %c %-*s %-*s -> %s (%s)
60138 re_fetch_result = re .compile ("^\s*(.) (\[?[\w\s\.]+\]?)\s+(.+) -> ([/\w_\.-]+)( \(.*\)?$)?" )
61139
62140 _flag_map = { '!' : ERROR , '+' : FORCED_UPDATE , '-' : TAG_UPDATE , '*' : 0 ,
63- '=' : BRANCH_UPTODATE , ' ' : FAST_FORWARD }
141+ '=' : HEAD_UPTODATE , ' ' : FAST_FORWARD }
64142
65143 def __init__ (self , ref , flags , note = '' , old_commit = None ):
66144 """
@@ -161,7 +239,7 @@ def _from_line(cls, repo, line, fetch_line):
161239 if 'new tag' in operation :
162240 flags |= cls .NEW_TAG
163241 if 'new branch' in operation :
164- flags |= cls .NEW_BRANCH
242+ flags |= cls .NEW_HEAD
165243 if '...' in operation :
166244 old_commit = Commit (repo , operation .split ('...' )[0 ])
167245 # END handle refspec
@@ -365,6 +443,19 @@ def _get_fetch_info_from_stderr(self, stderr):
365443 for err_line ,fetch_line in zip (err_info , fetch_head_info ))
366444 return output
367445
446+ def _get_push_info (self , proc , progress ):
447+ # read progress information from stderr
448+ # we hope stdout can hold all the data, it should ...
449+ for line in proc .stderr .readline ():
450+ progress ._parse_progress_line (line )
451+ # END for each progress line
452+
453+ output = IterableList ('name' )
454+ output .extend (PushInfo ._from_line (self .repo , line ) for line in proc .stdout .readlines ())
455+ proc .wait ()
456+ return output
457+
458+
368459 def fetch (self , refspec = None , ** kwargs ):
369460 """
370461 Fetch the latest changes for this remote
@@ -405,16 +496,21 @@ def pull(self, refspec=None, **kwargs):
405496 Returns
406497 Please see 'fetch' method
407498 """
408- status , stdout , stderr = self .repo .git .pull (self , refspec , v = True , with_extended_output = True , ** kwargs )
499+ status , stdout , stderr = self .repo .git .pull (self , refspec , with_extended_output = True , v = True , ** kwargs )
409500 return self ._get_fetch_info_from_stderr (stderr )
410501
411- def push (self , refspec = None , ** kwargs ):
502+ def push (self , refspec = None , progress = None , ** kwargs ):
412503 """
413504 Push changes from source branch in refspec to target branch in refspec.
414505
415506 ``refspec``
416507 see 'fetch' method
417508
509+ ``progress``
510+ Instance of type PushProgress allowing the caller to receive
511+ progress information until the method returns.
512+ If None, progress information will be discarded
513+
418514 ``**kwargs``
419515 Additional arguments to be passed to git-push
420516
@@ -424,12 +520,7 @@ def push(self, refspec=None, **kwargs):
424520 side
425521 """
426522 proc = self .repo .git .push (self , refspec , porcelain = True , as_process = True , ** kwargs )
427- print "stdout" * 10
428- print proc .stdout .read ()
429- print "stderr" * 10
430- print proc .stderr .read ()
431- proc .wait ()
432- return self
523+ return self ._get_push_info (proc , progress or PushProgress ())
433524
434525 @property
435526 def config_reader (self ):
0 commit comments