@@ -126,6 +126,16 @@ def stage(self):
126126 @property
127127 def path (self ):
128128 return self [10 ]
129+
130+
131+ @classmethod
132+ def from_blob (cls , blob ):
133+ """
134+ Returns
135+ Minimal entry resembling the given blob objecft
136+ """
137+ time = struct .pack (">LL" , 0 , 0 )
138+ return IndexEntry ((time , time , 0 , 0 , blob .mode , 0 , 0 , blob .size , blob .id , 0 , blob .path ))
129139
130140
131141class Index (object ):
@@ -402,6 +412,61 @@ def iter_blobs(self, predicate = lambda t: True):
402412 yield output
403413 # END for each entry
404414
415+ def unmerged_blobs (self ):
416+ """
417+ Returns
418+ Iterator yielding dict(path : list( tuple( stage, Blob, ...))), being
419+ a dictionary associating a path in the index with a list containing
420+ stage/blob pairs
421+
422+ Note:
423+ Blobs that have been removed in one side simply do not exist in the
424+ given stage. I.e. a file removed on the 'other' branch whose entries
425+ are at stage 3 will not have a stage 3 entry.
426+ """
427+ is_unmerged_blob = lambda t : t [0 ] != 0
428+ path_map = dict ()
429+ for stage , blob in self .iter_blobs (is_unmerged_blob ):
430+ path_map .setdefault (blob .path , list ()).append ((stage , blob ))
431+ # END for each unmerged blob
432+
433+ return path_map
434+
435+ def resolve_blobs (self , iter_blobs ):
436+ """
437+ Resolve the blobs given in blob iterator. This will effectively remove the
438+ index entries of the respective path at all non-null stages and add the given
439+ blob as new stage null blob.
440+
441+ For each path there may only be one blob, otherwise a ValueError will be raised
442+ claiming the path is already at stage 0.
443+
444+ Raise
445+ ValueError if one of the blobs already existed at stage 0
446+
447+ Returns:
448+ self
449+ """
450+ for blob in iter_blobs :
451+ stage_null_key = (blob .path , 0 )
452+ if stage_null_key in self .entries :
453+ raise ValueError ( "Blob %r already at stage 0" % blob )
454+ # END assert blob is not stage 0 already
455+
456+ # delete all possible stages
457+ for stage in (1 , 2 , 3 ):
458+ try :
459+ del ( self .entries [(blob .path , stage )] )
460+ except KeyError :
461+ pass
462+ # END ignore key errors
463+ # END for each possible stage
464+
465+ self .entries [stage_null_key ] = IndexEntry .from_blob (blob )
466+ # END for each blob
467+
468+ return self
469+
405470 def write_tree (self ):
406471 """
407472 Writes the Index in self to a corresponding Tree file into the repository
@@ -414,11 +479,16 @@ def write_tree(self):
414479 tmp_index_mover = _TemporaryFileSwap (index_path )
415480
416481 self .to_file (self , index_path )
417- tree_sha = self .repo .git .write_tree ()
418482
419- # remove our index file so that the original index can move back into place
420- # On linux it will silently overwrite, on windows it won't
421- os .remove (index_path )
483+ try :
484+ tree_sha = self .repo .git .write_tree ()
485+ finally :
486+ # remove our index file so that the original index can move back into place
487+ # On linux it will silently overwrite, on windows it won't
488+ if os .path .isfile (index_path ):
489+ os .remove (index_path )
490+ # END remove our own index file beforehand
491+ # END write tree handling
422492 return Tree (self .repo , tree_sha , 0 , '' )
423493
424494
0 commit comments