44# This module is part of GitPython and is released under
55# the BSD License: http://www.opensource.org/licenses/bsd-license.php
66
7- from exc import InvalidGitRepositoryError , NoSuchPathError
8- from cmd import Git
9- from objects import Actor
10- from refs import *
11- from index import IndexFile
12- from objects import *
13- from config import GitConfigParser
14- from remote import Remote
15- from string import digits
16- from db import (
7+ from git .exc import InvalidGitRepositoryError , NoSuchPathError
8+ from git .cmd import Git
9+ from git .objects import Actor
10+ from git .refs import *
11+ from git .index import IndexFile
12+ from git .objects import *
13+ from git .config import GitConfigParser
14+ from git .remote import Remote
15+ from git .db import (
1716 GitCmdObjectDB ,
1817 GitDB
1918 )
2019
21- from gitdb . exc import BadObject
20+
2221from gitdb .util import (
2322 join ,
24- isdir ,
2523 isfile ,
26- join ,
2724 hex_to_bin
2825 )
26+
27+ from fun import (
28+ rev_parse ,
29+ is_git_dir ,
30+ touch
31+ )
32+
2933import os
3034import sys
3135import re
3236
3337
3438__all__ = ('Repo' , )
3539
36- def touch (filename ):
37- fp = open (filename , "a" )
38- fp .close ()
39-
40- def is_git_dir (d ):
41- """ This is taken from the git setup.c:is_git_directory
42- function."""
43-
44- if isdir (d ) and \
45- isdir (join (d , 'objects' )) and \
46- isdir (join (d , 'refs' )):
47- headref = join (d , 'HEAD' )
48- return isfile (headref ) or \
49- (os .path .islink (headref ) and
50- os .readlink (headref ).startswith ('refs' ))
51- return False
52-
5340
5441class Repo (object ):
5542 """Represents a git repository and allows you to query references,
@@ -112,7 +99,7 @@ def __init__(self, path=None, odbt = GitDB):
11299 self .git_dir = curpath
113100 self ._working_tree_dir = os .path .dirname (curpath )
114101 break
115- gitpath = os . path . join (curpath , '.git' )
102+ gitpath = join (curpath , '.git' )
116103 if is_git_dir (gitpath ):
117104 self .git_dir = gitpath
118105 self ._working_tree_dir = curpath
@@ -142,7 +129,7 @@ def __init__(self, path=None, odbt = GitDB):
142129 self .git = Git (self .working_dir )
143130
144131 # special handling, in special times
145- args = [os . path . join (self .git_dir , 'objects' )]
132+ args = [join (self .git_dir , 'objects' )]
146133 if issubclass (odbt , GitCmdObjectDB ):
147134 args .append (self .git )
148135 self .odb = odbt (* args )
@@ -163,11 +150,11 @@ def __repr__(self):
163150
164151 # Description property
165152 def _get_description (self ):
166- filename = os . path . join (self .git_dir , 'description' )
153+ filename = join (self .git_dir , 'description' )
167154 return file (filename ).read ().rstrip ()
168155
169156 def _set_description (self , descr ):
170- filename = os . path . join (self .git_dir , 'description' )
157+ filename = join (self .git_dir , 'description' )
171158 file (filename , 'w' ).write (descr + '\n ' )
172159
173160 description = property (_get_description , _set_description ,
@@ -396,11 +383,11 @@ def iter_commits(self, rev=None, paths='', **kwargs):
396383 return Commit .iter_items (self , rev , paths , ** kwargs )
397384
398385 def _get_daemon_export (self ):
399- filename = os . path . join (self .git_dir , self .DAEMON_EXPORT_FILE )
386+ filename = join (self .git_dir , self .DAEMON_EXPORT_FILE )
400387 return os .path .exists (filename )
401388
402389 def _set_daemon_export (self , value ):
403- filename = os . path . join (self .git_dir , self .DAEMON_EXPORT_FILE )
390+ filename = join (self .git_dir , self .DAEMON_EXPORT_FILE )
404391 fileexists = os .path .exists (filename )
405392 if value and not fileexists :
406393 touch (filename )
@@ -416,7 +403,7 @@ def _get_alternates(self):
416403 """The list of alternates for this repo from which objects can be retrieved
417404
418405 :return: list of strings being pathnames of alternates"""
419- alternates_path = os . path . join (self .git_dir , 'objects' , 'info' , 'alternates' )
406+ alternates_path = join (self .git_dir , 'objects' , 'info' , 'alternates' )
420407
421408 if os .path .exists (alternates_path ):
422409 try :
@@ -439,9 +426,9 @@ def _set_alternates(self, alts):
439426 :note:
440427 The method does not check for the existance of the paths in alts
441428 as the caller is responsible."""
442- alternates_path = os . path . join (self .git_dir , 'objects' , 'info' , 'alternates' )
429+ alternates_path = join (self .git_dir , 'objects' , 'info' , 'alternates' )
443430 if not alts :
444- if os . path . isfile (alternates_path ):
431+ if isfile (alternates_path ):
445432 os .remove (alternates_path )
446433 else :
447434 try :
@@ -469,7 +456,7 @@ def is_dirty(self, index=True, working_tree=True, untracked_files=False):
469456 default_args = ('--abbrev=40' , '--full-index' , '--raw' )
470457 if index :
471458 # diff index against HEAD
472- if os . path . isfile (self .index .path ) and self .head .is_valid () and \
459+ if isfile (self .index .path ) and self .head .is_valid () and \
473460 len (self .git .diff ('HEAD' , '--cached' , * default_args )):
474461 return True
475462 # END index handling
@@ -677,7 +664,7 @@ def clone(self, path, **kwargs):
677664 # our git command could have a different working dir than our actual
678665 # environment, hence we prepend its working dir if required
679666 if not os .path .isabs (path ) and self .git .working_dir :
680- path = os . path . join (self .git ._working_dir , path )
667+ path = join (self .git ._working_dir , path )
681668 return Repo (os .path .abspath (path ), odbt = odbt )
682669
683670
@@ -696,203 +683,13 @@ def archive(self, ostream, treeish=None, prefix=None, **kwargs):
696683 if treeish is None :
697684 treeish = self .active_branch
698685 if prefix and 'prefix' not in kwargs :
699- kwargs ['prefix' ] = prefix
686+ kwargs ['prefix' ] = prefix
700687 kwargs ['output_stream' ] = ostream
701688
702689 self .git .archive (treeish , ** kwargs )
703690 return self
691+
692+ rev_parse = rev_parse
704693
705- def rev_parse (self , rev ):
706- """
707- :return: Object at the given revision, either Commit, Tag, Tree or Blob
708- :param rev: git-rev-parse compatible revision specification, please see
709- http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html
710- for details
711- :note: Currently there is no access to the rev-log, rev-specs may only contain
712- topological tokens such ~ and ^.
713- :raise BadObject: if the given revision could not be found"""
714- if '@' in rev :
715- raise ValueError ("There is no rev-log support yet" )
716-
717-
718- # colon search mode ?
719- if rev .startswith (':/' ):
720- # colon search mode
721- raise NotImplementedError ("commit by message search ( regex )" )
722- # END handle search
723-
724- # return object specified by the given name
725- def name_to_object (name ):
726- hexsha = None
727-
728- # is it a hexsha ? Try the most common ones, which is 7 to 40
729- if self .re_hexsha_shortened .match (name ):
730- if len (name ) != 40 :
731- # find long sha for short sha
732- raise NotImplementedError ("short sha parsing" )
733- else :
734- hexsha = name
735- # END handle short shas
736- else :
737- for base in ('%s' , 'refs/%s' , 'refs/tags/%s' , 'refs/heads/%s' , 'refs/remotes/%s' , 'refs/remotes/%s/HEAD' ):
738- try :
739- hexsha = SymbolicReference .dereference_recursive (self , base % name )
740- break
741- except ValueError :
742- pass
743- # END for each base
744- # END handle hexsha
745-
746- # tried everything ? fail
747- if hexsha is None :
748- # it could also be a very short ( less than 7 ) hexsha, which
749- # wasnt tested in the first run
750- if len (name ) < 7 and self .re_hexsha_domain .match (name ):
751- raise NotImplementedError ()
752- # END try short name
753- raise BadObject (name )
754- # END assert hexsha was found
755-
756- return Object .new_from_sha (self , hex_to_bin (hexsha ))
757- # END object by name
758-
759- def deref_tag (tag ):
760- while True :
761- try :
762- tag = tag .object
763- except AttributeError :
764- break
765- # END dereference tag
766- return tag
767-
768- def to_commit (obj ):
769- if obj .type == 'tag' :
770- obj = deref_tag (obj )
771-
772- if obj .type != "commit" :
773- raise ValueError ("Cannot convert object %r to type commit" % obj )
774- # END verify type
775- return obj
776- # END commit converter
777-
778- obj = None
779- output_type = "commit"
780- start = 0
781- parsed_to = 0
782- lr = len (rev )
783- while start < lr :
784- if rev [start ] not in "^~:" :
785- start += 1
786- continue
787- # END handle start
788-
789- if obj is None :
790- # token is a rev name
791- obj = name_to_object (rev [:start ])
792- # END initialize obj on first token
793-
794- token = rev [start ]
795- start += 1
796-
797- # try to parse {type}
798- if start < lr and rev [start ] == '{' :
799- end = rev .find ('}' , start )
800- if end == - 1 :
801- raise ValueError ("Missing closing brace to define type in %s" % rev )
802- output_type = rev [start + 1 :end ] # exclude brace
803-
804- # handle type
805- if output_type == 'commit' :
806- pass # default
807- elif output_type == 'tree' :
808- try :
809- obj = to_commit (obj ).tree
810- except (AttributeError , ValueError ):
811- pass # error raised later
812- # END exception handling
813- elif output_type in ('' , 'blob' ):
814- if obj .type == 'tag' :
815- obj = deref_tag (obj )
816- else :
817- # cannot do anything for non-tags
818- pass
819- # END handle tag
820- else :
821- raise ValueError ("Invalid output type: %s ( in %s )" % (output_type , rev ))
822- # END handle output type
823-
824- # empty output types don't require any specific type, its just about dereferencing tags
825- if output_type and obj .type != output_type :
826- raise ValueError ("Could not accomodate requested object type %r, got %s" % (output_type , obj .type ))
827- # END verify ouput type
828-
829- start = end + 1 # skip brace
830- parsed_to = start
831- continue
832- # END parse type
833-
834- # try to parse a number
835- num = 0
836- if token != ":" :
837- found_digit = False
838- while start < lr :
839- if rev [start ] in digits :
840- num = num * 10 + int (rev [start ])
841- start += 1
842- found_digit = True
843- else :
844- break
845- # END handle number
846- # END number parse loop
847-
848- # no explicit number given, 1 is the default
849- # It could be 0 though
850- if not found_digit :
851- num = 1
852- # END set default num
853- # END number parsing only if non-blob mode
854-
855-
856- parsed_to = start
857- # handle hiererarchy walk
858- try :
859- if token == "~" :
860- obj = to_commit (obj )
861- for item in xrange (num ):
862- obj = obj .parents [0 ]
863- # END for each history item to walk
864- elif token == "^" :
865- obj = to_commit (obj )
866- # must be n'th parent
867- if num :
868- obj = obj .parents [num - 1 ]
869- elif token == ":" :
870- if obj .type != "tree" :
871- obj = obj .tree
872- # END get tree type
873- obj = obj [rev [start :]]
874- parsed_to = lr
875- else :
876- raise ValueError ("Invalid token: %r" % token )
877- # END end handle tag
878- except (IndexError , AttributeError ):
879- raise BadObject ("Invalid Revision in %s" % rev )
880- # END exception handling
881- # END parse loop
882-
883- # still no obj ? Its probably a simple name
884- if obj is None :
885- obj = name_to_object (rev )
886- parsed_to = lr
887- # END handle simple name
888-
889- if obj is None :
890- raise ValueError ("Revision specifier could not be parsed: %s" % rev )
891-
892- if parsed_to != lr :
893- raise ValueError ("Didn't consume complete rev spec %s, consumed part: %s" % (rev , rev [:parsed_to ]))
894-
895- return obj
896-
897694 def __repr__ (self ):
898695 return '<git.Repo "%s">' % self .git_dir
0 commit comments