12
12
import stat
13
13
import subprocess
14
14
import glob
15
+ from cStringIO import StringIO
15
16
16
17
from typ import *
17
18
from util import (
48
49
)
49
50
50
51
52
+ from gitdb .base import (
53
+ IStream
54
+ )
55
+
51
56
__all__ = ( 'IndexFile' , 'CheckoutError' )
52
57
53
58
@@ -255,9 +260,6 @@ def write(self, file_path = None, ignore_tree_extension_data=False):
255
260
256
261
Returns
257
262
self
258
-
259
- Note
260
- Index writing based on the dulwich implementation
261
263
"""
262
264
lfd = LockedFD (file_path or self ._file_path )
263
265
stream = lfd .open (write = True , stream = True )
@@ -634,12 +636,10 @@ def _preprocess_add_items(self, items):
634
636
# END for each item
635
637
return (paths , entries )
636
638
637
-
638
639
@clear_cache
639
640
@default_index
640
641
def 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
643
643
to the index. The underlying index file will be written immediately, hence
644
644
you should provide as many items as possible to minimize the amounts of writes
645
645
@@ -695,7 +695,7 @@ def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=Non
695
695
696
696
:param fprogress:
697
697
Function 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
699
699
and once after it was added where done=True.
700
700
item is set to the actual item we handle, either a Path or a BaseIndexEntry
701
701
Please 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
713
713
:return:
714
714
List(BaseIndexEntries) representing the entries just actually added.
715
715
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
718
718
Objects that do not have a null sha will be added even if their paths
719
719
do not exist.
720
720
"""
@@ -734,28 +734,45 @@ def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=Non
734
734
del (paths [:])
735
735
# END rewrite paths
736
736
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
+
737
755
# HANDLE PATHS
738
756
if 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
743
758
added_files = list ()
744
-
745
759
for 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 ))
749
761
# 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 )
751
766
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 ()
755
769
# END path handling
756
770
771
+
757
772
# HANDLE ENTRIES
758
773
if entries :
774
+ # TODO: Add proper IndexEntries to ourselves, and write the index
775
+ # just once. Currently its done twice at least
759
776
null_mode_entries = [ e for e in entries if e .mode == 0 ]
760
777
if null_mode_entries :
761
778
raise 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
765
782
# create objects if required, otherwise go with the existing shas
766
783
null_entries_indices = [ i for i ,e in enumerate (entries ) if e .sha == Object .NULL_HEX_SHA ]
767
784
if 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 ()
774
785
for 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 ))
778
791
# 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
788
792
# END null_entry handling
789
793
790
794
# REWRITE PATHS
791
795
# If we have to rewrite the entries, do so now, after we have generated
792
796
# all object sha's
793
797
if 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 )))
797
800
# END for each entry
798
- entries = new_entries
799
801
# END handle path rewriting
800
802
801
803
# feed pure entries to stdin
@@ -821,7 +823,7 @@ def add(self, items, force=True, fprogress=lambda *args: None, path_rewriter=Non
821
823
self ._flush_stdin_and_wait (proc , ignore_stdout = True )
822
824
entries_added .extend (entries )
823
825
# END if there are base entries
824
-
826
+
825
827
return entries_added
826
828
827
829
def _items_to_rela_paths (self , items ):
0 commit comments