@@ -493,12 +493,66 @@ def _index_mode_to_tree_index_mode(cls, index_mode):
493493 ret |= (index_mode & 0111 )
494494 return ret
495495
496- @classmethod
497- def _tree_mode_to_index_mode (cls , tree_mode ):
498- """
499- Convert a tree mode to index mode as good as possible
500- """
501496
497+ # UTILITIES
498+ def _iter_expand_paths (self , paths ):
499+ """Expand the directories in list of paths to the corresponding paths accordingly,
500+
501+ Note: git will add items multiple times even if a glob overlapped
502+ with manually specified paths or if paths where specified multiple
503+ times - we respect that and do not prune"""
504+ def raise_exc (e ):
505+ raise e
506+ r = self .repo .git .git_dir
507+ rs = r + '/'
508+ for path in paths :
509+ abs_path = path
510+ if not os .path .isabs (abs_path ):
511+ abs_path = os .path .join (r , path )
512+ # END make absolute path
513+
514+ # resolve globs if possible
515+ if '?' in path or '*' in path or '[' in path :
516+ for f in self ._iter_expand_paths (glob .glob (abs_path )):
517+ yield f .replace (rs , '' )
518+ continue
519+ # END glob handling
520+ try :
521+ for root , dirs , files in os .walk (abs_path , onerror = raise_exc ):
522+ for rela_file in files :
523+ # add relative paths only
524+ yield os .path .join (root .replace (rs , '' ), rela_file )
525+ # END for each file in subdir
526+ # END for each subdirectory
527+ except OSError :
528+ # was a file or something that could not be iterated
529+ yield path .replace (rs , '' )
530+ # END path exception handling
531+ # END for each path
532+
533+ def _write_path_to_stdin (self , proc , filepath , item , fmakeexc , fprogress , read_from_stdout = True ):
534+ """Write path to proc.stdin and make sure it processes the item, including progress.
535+ @return: stdout string
536+ @param read_from_stdout: if True, proc.stdout will be read after the item
537+ was sent to stdin. In that case, it will return None
538+ @note: There is a bug in git-update-index that prevents it from sending
539+ reports just in time. This is why we have a version that tries to
540+ read stdout and one which doesn't. In fact, the stdout is not
541+ important as the piped-in files are processed anyway and just in time"""
542+ fprogress (filepath , False , item )
543+ rval = None
544+ try :
545+ proc .stdin .write ("%s\n " % filepath )
546+ except IOError :
547+ # pipe broke, usually because some error happend
548+ raise fmakeexc ()
549+ # END write exception handling
550+ proc .stdin .flush ()
551+ if read_from_stdout :
552+ rval = proc .stdout .readline ().strip ()
553+ fprogress (filepath , True , item )
554+ return rval
555+
502556 def iter_blobs (self , predicate = lambda t : True ):
503557 """
504558 Returns
@@ -735,68 +789,6 @@ def add(self, items, force=True, fprogress=lambda *args: None):
735789 Objects that do not have a null sha will be added even if their paths
736790 do not exist.
737791 """
738- # UTILITIES
739- def iter_expand_paths (paths ):
740- """Expand the directories in list of paths to the corresponding paths accordingly,
741-
742- Note: git will add items multiple times even if a glob overlapped
743- with manually specified paths or if paths where specified multiple
744- times - we respect that and do not prune"""
745- def raise_exc (e ):
746- raise e
747- r = self .repo .git .git_dir
748- rs = r + '/'
749- for path in paths :
750- abs_path = path
751- if not os .path .isabs (abs_path ):
752- abs_path = os .path .join (r , path )
753- # END make absolute path
754-
755- # resolve globs if possible
756- if '?' in path or '*' in path or '[' in path :
757- for f in iter_expand_paths (glob .glob (abs_path )):
758- yield f .replace (rs , '' )
759- continue
760- # END glob handling
761- try :
762- for root , dirs , files in os .walk (abs_path , onerror = raise_exc ):
763- for rela_file in files :
764- # add relative paths only
765- yield os .path .join (root .replace (rs , '' ), rela_file )
766- # END for each file in subdir
767- # END for each subdirectory
768- except OSError :
769- # was a file or something that could not be iterated
770- yield path .replace (rs , '' )
771- # END path exception handling
772- # END for each path
773- # END expand helper method
774-
775- def write_path_to_stdin (proc , filepath , item , fmakeexc , read_from_stdout = True ):
776- """Write path to proc.stdin and make sure it processes the item, including progress.
777- @return: stdout string
778- @param read_from_stdout: if True, proc.stdout will be read after the item
779- was sent to stdin. In that case, it will return None
780- @note: There is a bug in git-update-index that prevents it from sending
781- reports just in time. This is why we have a version that tries to
782- read stdout and one which doesn't. In fact, the stdout is not
783- important as the piped-in files are processed anyway and just in time"""
784- fprogress (filepath , False , item )
785- rval = None
786- try :
787- proc .stdin .write ("%s\n " % filepath )
788- except IOError :
789- # pipe broke, usually because some error happend
790- raise fmakeexc ()
791- # END write exception handling
792- proc .stdin .flush ()
793- if read_from_stdout :
794- rval = proc .stdout .readline ().strip ()
795- fprogress (filepath , True , item )
796- return rval
797- # END write_path_to_stdin
798-
799-
800792 # sort the entries into strings and Entries, Blobs are converted to entries
801793 # automatically
802794 # paths can be git-added, for everything else we use git-update-index
@@ -811,8 +803,8 @@ def write_path_to_stdin(proc, filepath, item, fmakeexc, read_from_stdout=True):
811803 make_exc = lambda : GitCommandError (("git-update-index" ,)+ args , 128 , proc .stderr .readline ())
812804 added_files = list ()
813805
814- for filepath in iter_expand_paths (paths ):
815- write_path_to_stdin (proc , filepath , filepath , make_exc , read_from_stdout = False )
806+ for filepath in self . _iter_expand_paths (paths ):
807+ self . _write_path_to_stdin (proc , filepath , filepath , make_exc , fprogress , read_from_stdout = False )
816808 added_files .append (filepath )
817809 # END for each filepath
818810 self ._flush_stdin_and_wait (proc ) # ignore stdout
@@ -841,7 +833,7 @@ def write_path_to_stdin(proc, filepath, item, fmakeexc, read_from_stdout=True):
841833 obj_ids = list ()
842834 for ei in null_entries_indices :
843835 entry = entries [ei ]
844- obj_ids .append (write_path_to_stdin (proc , entry .path , entry , make_exc ))
836+ obj_ids .append (self . _write_path_to_stdin (proc , entry .path , entry , make_exc , fprogress ))
845837 # END for each entry index
846838 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 ) )
847839
@@ -1001,19 +993,23 @@ def _flush_stdin_and_wait(cls, proc):
1001993 return stdout
1002994
1003995 @default_index
1004- def checkout (self , paths = None , force = False , ** kwargs ):
996+ def checkout (self , paths = None , force = False , fprogress = lambda * args : None , ** kwargs ):
1005997 """
1006998 Checkout the given paths or all files from the version in the index.
1007999
10081000 ``paths``
10091001 If None, all paths in the index will be checked out. Otherwise an iterable
10101002 or single path of relative or absolute paths pointing to files is expected.
10111003 The command will ignore paths that do not exist.
1004+ The provided progress information will contain None as path and item.
10121005
10131006 ``force``
10141007 If True, existing files will be overwritten. If False, these will
10151008 be skipped.
10161009
1010+ ``fprogress``
1011+ see Index.add_ for signature and explanation
1012+
10171013 ``**kwargs``
10181014 Additional arguments to be pasesd to git-checkout-index
10191015
@@ -1026,15 +1022,20 @@ def checkout(self, paths=None, force=False, **kwargs):
10261022
10271023 if paths is None :
10281024 args .append ("--all" )
1025+ fprogress (None , False , None )
10291026 self .repo .git .checkout_index (* args , ** kwargs )
1027+ fprogress (None , True , None )
10301028 else :
10311029 if not isinstance (paths , (tuple ,list )):
10321030 paths = [paths ]
10331031
10341032 args .append ("--stdin" )
1035- paths = [self ._to_relative_path (p ) for p in paths ]
10361033 co_proc = self .repo .git .checkout_index (args , as_process = True , istream = subprocess .PIPE , ** kwargs )
1037- co_proc .stdin .write ('\n ' .join (paths ))
1034+ make_exc = lambda : GitCommandError (("git-checkout-index" ,)+ args , 128 , co_proc .stderr .readline ())
1035+ for path in paths :
1036+ path = self ._to_relative_path (path )
1037+ self ._write_path_to_stdin (co_proc , path , path , make_exc , fprogress , read_from_stdout = False )
1038+ # END for each path
10381039 self ._flush_stdin_and_wait (co_proc )
10391040 # END paths handling
10401041 return self
0 commit comments