99
1010from git .utils import LazyMixin , Iterable , IterableList
1111from objects import Commit
12- from refs import Reference , RemoteReference
12+ from refs import Reference , RemoteReference , SymbolicReference , TagReference
1313import re
1414import os
1515
@@ -57,13 +57,16 @@ class FetchInfo(object):
5757 Carries information about the results of a fetch operation::
5858
5959 info = remote.fetch()[0]
60- info.remote_ref # Symbolic Reference or RemoteReference to the changed remote head or FETCH_HEAD
61- info.flags # additional flags to be & with enumeration members, i.e. info.flags & info.REJECTED
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
6265 info.note # additional notes given by git-fetch intended for the user
63- info.commit_before_forced_update # if info.flags & info.FORCED_UPDATE, field is set to the
64- # previous location of remote_ref , otherwise None
66+ info.commit_before_forced_update # if info.flags & info.FORCED_UPDATE,
67+ # field is set to the previous location of ref , otherwise None
6568 """
66- __slots__ = ('remote_ref ' ,'commit_before_forced_update' , 'flags' , 'note' )
69+ __slots__ = ('ref ' ,'commit_before_forced_update' , 'flags' , 'note' )
6770
6871 BRANCH_UPTODATE , REJECTED , FORCED_UPDATE , FAST_FORWARD , NEW_TAG , \
6972 TAG_UPDATE , NEW_BRANCH , ERROR = [ 1 << x for x in range (1 ,9 ) ]
@@ -73,11 +76,11 @@ class FetchInfo(object):
7376 _flag_map = { '!' : ERROR , '+' : FORCED_UPDATE , '-' : TAG_UPDATE , '*' : 0 ,
7477 '=' : BRANCH_UPTODATE , ' ' : FAST_FORWARD }
7578
76- def __init__ (self , remote_ref , flags , note = '' , old_commit = None ):
79+ def __init__ (self , ref , flags , note = '' , old_commit = None ):
7780 """
7881 Initialize a new instance
7982 """
80- self .remote_ref = remote_ref
83+ self .ref = ref
8184 self .flags = flags
8285 self .note = note
8386 self .commit_before_forced_update = old_commit
@@ -91,10 +94,10 @@ def name(self):
9194 Returns
9295 Name of our remote ref
9396 """
94- return self .remote_ref .name
97+ return self .ref .name
9598
9699 @classmethod
97- def _from_line (cls , repo , line ):
100+ def _from_line (cls , repo , line , fetch_line ):
98101 """
99102 Parse information from the given line as returned by git-fetch -v
100103 and return a new FetchInfo object representing this information.
@@ -109,13 +112,43 @@ def _from_line(cls, repo, line):
109112 * means birth of new branch or tag
110113 = means the head was up to date ( and not moved )
111114 ' ' means a fast-forward
115+
116+ fetch line is the corresponding line from FETCH_HEAD, like
117+ acb0fa8b94ef421ad60c8507b634759a472cd56c not-for-merge branch '0.1.7RC' of /tmp/tmpya0vairemote_repo
112118 """
113119 match = cls .re_fetch_result .match (line )
114120 if match is None :
115121 raise ValueError ("Failed to parse line: %r" % line )
122+
123+ # parse lines
116124 control_character , operation , local_remote_ref , remote_local_ref , note = match .groups ()
125+ try :
126+ new_hex_sha , fetch_operation , fetch_note = fetch_line .split ("\t " )
127+ ref_type_name , fetch_note = fetch_note .split (' ' , 1 )
128+ except ValueError : # unpack error
129+ raise ValueError ("Failed to parse FETCH__HEAD line: %r" % fetch_line )
130+
131+ # handle FETCH_HEAD and figure out ref type
132+ # If we do not specify a target branch like master:refs/remotes/origin/master,
133+ # the fetch result is stored in FETCH_HEAD which destroys the rule we usually
134+ # have. In that case we use a symbolic reference which is detached
135+ ref_type = None
136+ if remote_local_ref == "FETCH_HEAD" :
137+ ref_type = SymbolicReference
138+ elif ref_type_name == "branch" :
139+ ref_type = RemoteReference
140+ elif ref_type_name == "tag" :
141+ ref_type = TagReference
142+ else :
143+ raise TypeError ("Cannot handle reference type: %r" % ref_type_name )
144+
145+ # create ref instance
146+ if ref_type is SymbolicReference :
147+ remote_local_ref = ref_type (repo , "FETCH_HEAD" )
148+ else :
149+ remote_local_ref = Reference .from_path (repo , os .path .join (ref_type ._common_path_default , remote_local_ref .strip ()))
150+ # END create ref instance
117151
118- remote_local_ref = Reference .from_path (repo , os .path .join (RemoteReference ._common_path_default , remote_local_ref .strip ()))
119152 note = ( note and note .strip () ) or ''
120153
121154 # parse flags from control_character
@@ -126,17 +159,19 @@ def _from_line(cls, repo, line):
126159 raise ValueError ("Control character %r unknown as parsed from line %r" % (control_character , line ))
127160 # END control char exception hanlding
128161
129- # parse operation string for more info
162+ # parse operation string for more info - makes no sense for symbolic refs
130163 old_commit = None
131- if 'rejected' in operation :
132- flags |= cls .REJECTED
133- if 'new tag' in operation :
134- flags |= cls .NEW_TAG
135- if 'new branch' in operation :
136- flags |= cls .NEW_BRANCH
137- if '...' in operation :
138- old_commit = Commit (repo , operation .split ('...' )[0 ])
139- # END handle refspec
164+ if isinstance (remote_local_ref , Reference ):
165+ if 'rejected' in operation :
166+ flags |= cls .REJECTED
167+ if 'new tag' in operation :
168+ flags |= cls .NEW_TAG
169+ if 'new branch' in operation :
170+ flags |= cls .NEW_BRANCH
171+ if '...' in operation :
172+ old_commit = Commit (repo , operation .split ('...' )[0 ])
173+ # END handle refspec
174+ # END reference flag handling
140175
141176 return cls (remote_local_ref , flags , note , old_commit )
142177
@@ -316,7 +351,15 @@ def _get_fetch_info_from_stderr(self, stderr):
316351 # skip first line as it is some remote info we are not interested in
317352 print stderr
318353 output = IterableList ('name' )
319- output .extend (self .FetchInfo ._from_line (self .repo , line ) for line in stderr .splitlines ()[1 :])
354+ err_info = stderr .splitlines ()[1 :]
355+
356+ # read head information
357+ fp = open (os .path .join (self .repo .path , 'FETCH_HEAD' ),'r' )
358+ fetch_head_info = fp .readlines ()
359+ fp .close ()
360+
361+ output .extend (self .FetchInfo ._from_line (self .repo , err_line , fetch_line )
362+ for err_line ,fetch_line in zip (err_info , fetch_head_info ))
320363 return output
321364
322365 def fetch (self , refspec = None , ** kwargs ):
0 commit comments