@@ -37,6 +37,138 @@ def _call_config(self, method, *args):
3737 as first argument"""
3838 return getattr (self ._config , method )(self ._section_name , * args )
3939
40+
41+ class FetchInfo (object ):
42+ """
43+ Carries information about the results of a fetch operation::
44+
45+ info = remote.fetch()[0]
46+ info.ref # Symbolic Reference or RemoteReference to the changed
47+ # remote head or FETCH_HEAD
48+ info.flags # additional flags to be & with enumeration members,
49+ # i.e. info.flags & info.REJECTED
50+ # is 0 if ref is SymbolicReference
51+ info.note # additional notes given by git-fetch intended for the user
52+ info.commit_before_forced_update # if info.flags & info.FORCED_UPDATE,
53+ # field is set to the previous location of ref, otherwise None
54+ """
55+ __slots__ = ('ref' ,'commit_before_forced_update' , 'flags' , 'note' )
56+
57+ BRANCH_UPTODATE , REJECTED , FORCED_UPDATE , FAST_FORWARD , NEW_TAG , \
58+ TAG_UPDATE , NEW_BRANCH , ERROR = [ 1 << x for x in range (1 ,9 ) ]
59+ # %c %-*s %-*s -> %s (%s)
60+ re_fetch_result = re .compile ("^\s*(.) (\[?[\w\s\.]+\]?)\s+(.+) -> ([/\w_\.-]+)( \(.*\)?$)?" )
61+
62+ _flag_map = { '!' : ERROR , '+' : FORCED_UPDATE , '-' : TAG_UPDATE , '*' : 0 ,
63+ '=' : BRANCH_UPTODATE , ' ' : FAST_FORWARD }
64+
65+ def __init__ (self , ref , flags , note = '' , old_commit = None ):
66+ """
67+ Initialize a new instance
68+ """
69+ self .ref = ref
70+ self .flags = flags
71+ self .note = note
72+ self .commit_before_forced_update = old_commit
73+
74+ def __str__ (self ):
75+ return self .name
76+
77+ @property
78+ def name (self ):
79+ """
80+ Returns
81+ Name of our remote ref
82+ """
83+ return self .ref .name
84+
85+ @property
86+ def commit (self ):
87+ """
88+ Returns
89+ Commit of our remote ref
90+ """
91+ return self .ref .commit
92+
93+ @classmethod
94+ def _from_line (cls , repo , line , fetch_line ):
95+ """
96+ Parse information from the given line as returned by git-fetch -v
97+ and return a new FetchInfo object representing this information.
98+
99+ We can handle a line as follows
100+ "%c %-*s %-*s -> %s%s"
101+
102+ Where c is either ' ', !, +, -, *, or =
103+ ! means error
104+ + means success forcing update
105+ - means a tag was updated
106+ * means birth of new branch or tag
107+ = means the head was up to date ( and not moved )
108+ ' ' means a fast-forward
109+
110+ fetch line is the corresponding line from FETCH_HEAD, like
111+ acb0fa8b94ef421ad60c8507b634759a472cd56c not-for-merge branch '0.1.7RC' of /tmp/tmpya0vairemote_repo
112+ """
113+ match = cls .re_fetch_result .match (line )
114+ if match is None :
115+ raise ValueError ("Failed to parse line: %r" % line )
116+
117+ # parse lines
118+ control_character , operation , local_remote_ref , remote_local_ref , note = match .groups ()
119+ try :
120+ new_hex_sha , fetch_operation , fetch_note = fetch_line .split ("\t " )
121+ ref_type_name , fetch_note = fetch_note .split (' ' , 1 )
122+ except ValueError : # unpack error
123+ raise ValueError ("Failed to parse FETCH__HEAD line: %r" % fetch_line )
124+
125+ # handle FETCH_HEAD and figure out ref type
126+ # If we do not specify a target branch like master:refs/remotes/origin/master,
127+ # the fetch result is stored in FETCH_HEAD which destroys the rule we usually
128+ # have. In that case we use a symbolic reference which is detached
129+ ref_type = None
130+ if remote_local_ref == "FETCH_HEAD" :
131+ ref_type = SymbolicReference
132+ elif ref_type_name == "branch" :
133+ ref_type = RemoteReference
134+ elif ref_type_name == "tag" :
135+ ref_type = TagReference
136+ else :
137+ raise TypeError ("Cannot handle reference type: %r" % ref_type_name )
138+
139+ # create ref instance
140+ if ref_type is SymbolicReference :
141+ remote_local_ref = ref_type (repo , "FETCH_HEAD" )
142+ else :
143+ remote_local_ref = Reference .from_path (repo , os .path .join (ref_type ._common_path_default , remote_local_ref .strip ()))
144+ # END create ref instance
145+
146+ note = ( note and note .strip () ) or ''
147+
148+ # parse flags from control_character
149+ flags = 0
150+ try :
151+ flags |= cls ._flag_map [control_character ]
152+ except KeyError :
153+ raise ValueError ("Control character %r unknown as parsed from line %r" % (control_character , line ))
154+ # END control char exception hanlding
155+
156+ # parse operation string for more info - makes no sense for symbolic refs
157+ old_commit = None
158+ if isinstance (remote_local_ref , Reference ):
159+ if 'rejected' in operation :
160+ flags |= cls .REJECTED
161+ if 'new tag' in operation :
162+ flags |= cls .NEW_TAG
163+ if 'new branch' in operation :
164+ flags |= cls .NEW_BRANCH
165+ if '...' in operation :
166+ old_commit = Commit (repo , operation .split ('...' )[0 ])
167+ # END handle refspec
168+ # END reference flag handling
169+
170+ return cls (remote_local_ref , flags , note , old_commit )
171+
40172
41173class Remote (LazyMixin , Iterable ):
42174 """
@@ -52,140 +184,6 @@ class Remote(LazyMixin, Iterable):
52184 __slots__ = ( "repo" , "name" , "_config_reader" )
53185 _id_attribute_ = "name"
54186
55- class FetchInfo (object ):
56- """
57- Carries information about the results of a fetch operation::
58-
59- info = remote.fetch()[0]
60- info.ref # Symbolic Reference or RemoteReference to the changed
61- # remote head or FETCH_HEAD
62- info.flags # additional flags to be & with enumeration members,
63- # i.e. info.flags & info.REJECTED
64- # is 0 if ref is SymbolicReference
65- info.note # additional notes given by git-fetch intended for the user
66- info.commit_before_forced_update # if info.flags & info.FORCED_UPDATE,
67- # field is set to the previous location of ref, otherwise None
68- """
69- __slots__ = ('ref' ,'commit_before_forced_update' , 'flags' , 'note' )
70-
71- BRANCH_UPTODATE , REJECTED , FORCED_UPDATE , FAST_FORWARD , NEW_TAG , \
72- TAG_UPDATE , NEW_BRANCH , ERROR = [ 1 << x for x in range (1 ,9 ) ]
73- # %c %-*s %-*s -> %s (%s)
74- re_fetch_result = re .compile ("^\s*(.) (\[?[\w\s\.]+\]?)\s+(.+) -> ([/\w_\.-]+)( \(.*\)?$)?" )
75-
76- _flag_map = { '!' : ERROR , '+' : FORCED_UPDATE , '-' : TAG_UPDATE , '*' : 0 ,
77- '=' : BRANCH_UPTODATE , ' ' : FAST_FORWARD }
78-
79- def __init__ (self , ref , flags , note = '' , old_commit = None ):
80- """
81- Initialize a new instance
82- """
83- self .ref = ref
84- self .flags = flags
85- self .note = note
86- self .commit_before_forced_update = old_commit
87-
88- def __str__ (self ):
89- return self .name
90-
91- @property
92- def name (self ):
93- """
94- Returns
95- Name of our remote ref
96- """
97- return self .ref .name
98-
99- @property
100- def commit (self ):
101- """
102- Returns
103- Commit of our remote ref
104- """
105- return self .ref .commit
106-
107- @classmethod
108- def _from_line (cls , repo , line , fetch_line ):
109- """
110- Parse information from the given line as returned by git-fetch -v
111- and return a new FetchInfo object representing this information.
112-
113- We can handle a line as follows
114- "%c %-*s %-*s -> %s%s"
115-
116- Where c is either ' ', !, +, -, *, or =
117- ! means error
118- + means success forcing update
119- - means a tag was updated
120- * means birth of new branch or tag
121- = means the head was up to date ( and not moved )
122- ' ' means a fast-forward
123-
124- fetch line is the corresponding line from FETCH_HEAD, like
125- acb0fa8b94ef421ad60c8507b634759a472cd56c not-for-merge branch '0.1.7RC' of /tmp/tmpya0vairemote_repo
126- """
127- match = cls .re_fetch_result .match (line )
128- if match is None :
129- raise ValueError ("Failed to parse line: %r" % line )
130-
131- # parse lines
132- control_character , operation , local_remote_ref , remote_local_ref , note = match .groups ()
133- try :
134- new_hex_sha , fetch_operation , fetch_note = fetch_line .split ("\t " )
135- ref_type_name , fetch_note = fetch_note .split (' ' , 1 )
136- except ValueError : # unpack error
137- raise ValueError ("Failed to parse FETCH__HEAD line: %r" % fetch_line )
138-
139- # handle FETCH_HEAD and figure out ref type
140- # If we do not specify a target branch like master:refs/remotes/origin/master,
141- # the fetch result is stored in FETCH_HEAD which destroys the rule we usually
142- # have. In that case we use a symbolic reference which is detached
143- ref_type = None
144- if remote_local_ref == "FETCH_HEAD" :
145- ref_type = SymbolicReference
146- elif ref_type_name == "branch" :
147- ref_type = RemoteReference
148- elif ref_type_name == "tag" :
149- ref_type = TagReference
150- else :
151- raise TypeError ("Cannot handle reference type: %r" % ref_type_name )
152-
153- # create ref instance
154- if ref_type is SymbolicReference :
155- remote_local_ref = ref_type (repo , "FETCH_HEAD" )
156- else :
157- remote_local_ref = Reference .from_path (repo , os .path .join (ref_type ._common_path_default , remote_local_ref .strip ()))
158- # END create ref instance
159-
160- note = ( note and note .strip () ) or ''
161-
162- # parse flags from control_character
163- flags = 0
164- try :
165- flags |= cls ._flag_map [control_character ]
166- except KeyError :
167- raise ValueError ("Control character %r unknown as parsed from line %r" % (control_character , line ))
168- # END control char exception hanlding
169-
170- # parse operation string for more info - makes no sense for symbolic refs
171- old_commit = None
172- if isinstance (remote_local_ref , Reference ):
173- if 'rejected' in operation :
174- flags |= cls .REJECTED
175- if 'new tag' in operation :
176- flags |= cls .NEW_TAG
177- if 'new branch' in operation :
178- flags |= cls .NEW_BRANCH
179- if '...' in operation :
180- old_commit = Commit (repo , operation .split ('...' )[0 ])
181- # END handle refspec
182- # END reference flag handling
183-
184- return cls (remote_local_ref , flags , note , old_commit )
185-
186- # END FetchInfo definition
187-
188-
189187 def __init__ (self , repo , name ):
190188 """
191189 Initialize a remote instance
@@ -370,7 +368,7 @@ def _get_fetch_info_from_stderr(self, stderr):
370368 fetch_head_info = fp .readlines ()
371369 fp .close ()
372370
373- output .extend (self . FetchInfo ._from_line (self .repo , err_line , fetch_line )
371+ output .extend (FetchInfo ._from_line (self .repo , err_line , fetch_line )
374372 for err_line ,fetch_line in zip (err_info , fetch_head_info ))
375373 return output
376374
@@ -428,8 +426,10 @@ def push(self, refspec=None, **kwargs):
428426 Additional arguments to be passed to git-push
429427
430428 Returns
431- self
432- """
429+ IterableList(PushInfo, ...) iterable list of PushInfo instances, each
430+ one informing about an individual head which had been updated on the remote
431+ side
432+ """
433433 proc = self .repo .git .push (self , refspec , porcelain = True , as_process = True , ** kwargs )
434434 print "stdout" * 10
435435 print proc .stdout .read ()
0 commit comments