1212import stat
1313import subprocess
1414import glob
15+ from cStringIO import StringIO
1516
1617from typ import *
1718from util import (
4849)
4950
5051
52+ from gitdb .base import (
53+ IStream
54+ )
55+
5156__all__ = ('IndexFile' ,'CheckoutError' )
5257
5358
@@ -255,9 +260,6 @@ def write(self, file_path = None, ignore_tree_extension_data=False):
255260
256261Returns
257262self
258-
259- Note
260- Index writing based on the dulwich implementation
261263"""
262264lfd = LockedFD (file_path or self ._file_path )
263265stream = lfd .open (write = True ,stream = True )
@@ -634,12 +636,10 @@ def _preprocess_add_items(self, items):
634636# END for each item
635637return (paths ,entries )
636638
637-
638639@clear_cache
639640@default_index
640641def add (self ,items ,force = True ,fprogress = lambda * args :None ,path_rewriter = None ):
641- """
642- Add files from the working tree, specific blobs or BaseIndexEntries
642+ """Add files from the working tree, specific blobs or BaseIndexEntries
643643to the index. The underlying index file will be written immediately, hence
644644you should provide as many items as possible to minimize the amounts of writes
645645
@@ -695,7 +695,7 @@ def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=Non
695695
696696:param fprogress:
697697Function with signature f(path, done=False, item=item) called for each
698- path to be added,once once it is about to be added where done==False
698+ path to be added,one time once it is about to be added where done==False
699699and once after it was added where done=True.
700700item is set to the actual item we handle, either a Path or a BaseIndexEntry
701701Please note that the processed path is not guaranteed to be present
@@ -713,8 +713,8 @@ def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=Non
713713:return:
714714List(BaseIndexEntries) representing the entries just actually added.
715715
716- Raises
717- GitCommandError if a supplied Path did not exist. Please note that BaseIndexEntry
716+ :raise OSError:
717+ if a supplied Path did not exist. Please note that BaseIndexEntry
718718Objects that do not have a null sha will be added even if their paths
719719do not exist.
720720"""
@@ -734,28 +734,45 @@ def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=Non
734734del (paths [:])
735735# END rewrite paths
736736
737+
738+ def store_path (filepath ):
739+ """Store file at filepath in the database and return the base index entry"""
740+ st = os .lstat (filepath )# handles non-symlinks as well
741+ stream = None
742+ if stat .S_ISLNK (st .st_mode ):
743+ stream = StringIO (os .readlink (filepath ))
744+ else :
745+ stream = open (filepath ,'rb' )
746+ # END handle stream
747+ fprogress (filepath ,False ,filepath )
748+ istream = self .repo .odb .store (IStream (Blob .type ,st .st_size ,stream ))
749+ fprogress (filepath ,True ,filepath )
750+
751+ return BaseIndexEntry ((st .st_mode ,istream .sha ,0 ,filepath ))
752+ # END utility method
753+
754+
737755# HANDLE PATHS
738756if paths :
739- # to get suitable progress information, pipe paths to stdin
740- args = ("--add" ,"--replace" ,"--verbose" ,"--stdin" )
741- proc = self .repo .git .update_index (* args ,** {'as_process' :True ,'istream' :subprocess .PIPE })
742- make_exc = lambda :GitCommandError (("git-update-index" ,)+ args ,128 ,proc .stderr .read ())
757+ assert len (entries_added )== 0
743758added_files = list ()
744-
745759for filepath in self ._iter_expand_paths (paths ):
746- self ._write_path_to_stdin (proc ,filepath ,filepath ,make_exc ,
747- fprogress ,read_from_stdout = False )
748- added_files .append (filepath )
760+ entries_added .append (store_path (filepath ))
749761# END for each filepath
750- self ._flush_stdin_and_wait (proc ,ignore_stdout = True )# ignore stdout
762+
763+ # add the new entries to this instance, and write it
764+ for entry in entries_added :
765+ self .entries [(entry .path ,0 )]= IndexEntry .from_base (entry )
751766
752- # force rereading our entries once it is all done
753- self ._delete_entries_cache ()
754- entries_added .extend (self .entries [(f ,0 )]for f in added_files )
767+ # finally write the changed index
768+ self .write ()
755769# END path handling
756770
771+
757772# HANDLE ENTRIES
758773if entries :
774+ # TODO: Add proper IndexEntries to ourselves, and write the index
775+ # just once. Currently its done twice at least
759776null_mode_entries = [e for e in entries if e .mode == 0 ]
760777if null_mode_entries :
761778raise ValueError ("At least one Entry has a null-mode - please use index.remove to remove files for clarity" )
@@ -765,37 +782,22 @@ def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=Non
765782# create objects if required, otherwise go with the existing shas
766783null_entries_indices = [i for i ,e in enumerate (entries )if e .sha == Object .NULL_HEX_SHA ]
767784if null_entries_indices :
768- # creating object ids is the time consuming part. Hence we will
769- # send progress for these now.
770- args = ("-w" ,"--stdin-paths" )
771- proc = self .repo .git .hash_object (* args ,** {'istream' :subprocess .PIPE ,'as_process' :True })
772- make_exc = lambda :GitCommandError (("git-hash-object" ,)+ args ,128 ,proc .stderr .read ())
773- obj_ids = list ()
774785for ei in null_entries_indices :
775- entry = entries [ei ]
776- obj_ids .append (self ._write_path_to_stdin (proc ,entry .path ,entry ,
777- make_exc ,fprogress ,read_from_stdout = True ))
786+ null_entry = entries [ei ]
787+ new_entry = store_path (null_entry .path )
788+
789+ # update null entry
790+ entries [ei ]= BaseIndexEntry ((null_entry .mode ,new_entry .sha ,null_entry .stage ,null_entry .path ))
778791# END for each entry index
779- assert len (obj_ids )== len (null_entries_indices ),"git-hash-object did not produce all requested objects: want %i, got %i" % (len (null_entries_indices ),len (obj_ids ) )
780-
781- # update IndexEntries with new object id
782- for i ,new_sha in zip (null_entries_indices ,obj_ids ):
783- e = entries [i ]
784-
785- new_entry = BaseIndexEntry ((e .mode ,new_sha ,e .stage ,e .path ))
786- entries [i ]= new_entry
787- # END for each index
788792# END null_entry handling
789793
790794# REWRITE PATHS
791795# If we have to rewrite the entries, do so now, after we have generated
792796# all object sha's
793797if path_rewriter :
794- new_entries = list ()
795- for e in entries :
796- new_entries .append (BaseIndexEntry ((e .mode ,e .sha ,e .stage ,path_rewriter (e ))))
798+ for i ,e in enumerate (entries ):
799+ entries [i ]= BaseIndexEntry ((e .mode ,e .sha ,e .stage ,path_rewriter (e )))
797800# END for each entry
798- entries = new_entries
799801# END handle path rewriting
800802
801803# feed pure entries to stdin
@@ -821,7 +823,7 @@ def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=Non
821823self ._flush_stdin_and_wait (proc ,ignore_stdout = True )
822824entries_added .extend (entries )
823825# END if there are base entries
824-
826+
825827return entries_added
826828
827829def _items_to_rela_paths (self ,items ):