4
4
# This module is part of GitPython and is released under
5
5
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
6
6
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 (
17
16
GitCmdObjectDB ,
18
17
GitDB
19
18
)
20
19
21
- from gitdb . exc import BadObject
20
+
22
21
from gitdb .util import (
23
22
join ,
24
- isdir ,
25
23
isfile ,
26
- join ,
27
24
hex_to_bin
28
25
)
26
+
27
+ from fun import (
28
+ rev_parse ,
29
+ is_git_dir ,
30
+ touch
31
+ )
32
+
29
33
import os
30
34
import sys
31
35
import re
32
36
33
37
34
38
__all__ = ('Repo' , )
35
39
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
-
53
40
54
41
class Repo (object ):
55
42
"""Represents a git repository and allows you to query references,
@@ -112,7 +99,7 @@ def __init__(self, path=None, odbt = GitDB):
112
99
self .git_dir = curpath
113
100
self ._working_tree_dir = os .path .dirname (curpath )
114
101
break
115
- gitpath = os . path . join (curpath , '.git' )
102
+ gitpath = join (curpath , '.git' )
116
103
if is_git_dir (gitpath ):
117
104
self .git_dir = gitpath
118
105
self ._working_tree_dir = curpath
@@ -142,7 +129,7 @@ def __init__(self, path=None, odbt = GitDB):
142
129
self .git = Git (self .working_dir )
143
130
144
131
# special handling, in special times
145
- args = [os . path . join (self .git_dir , 'objects' )]
132
+ args = [join (self .git_dir , 'objects' )]
146
133
if issubclass (odbt , GitCmdObjectDB ):
147
134
args .append (self .git )
148
135
self .odb = odbt (* args )
@@ -163,11 +150,11 @@ def __repr__(self):
163
150
164
151
# Description property
165
152
def _get_description (self ):
166
- filename = os . path . join (self .git_dir , 'description' )
153
+ filename = join (self .git_dir , 'description' )
167
154
return file (filename ).read ().rstrip ()
168
155
169
156
def _set_description (self , descr ):
170
- filename = os . path . join (self .git_dir , 'description' )
157
+ filename = join (self .git_dir , 'description' )
171
158
file (filename , 'w' ).write (descr + '\n ' )
172
159
173
160
description = property (_get_description , _set_description ,
@@ -396,11 +383,11 @@ def iter_commits(self, rev=None, paths='', **kwargs):
396
383
return Commit .iter_items (self , rev , paths , ** kwargs )
397
384
398
385
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 )
400
387
return os .path .exists (filename )
401
388
402
389
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 )
404
391
fileexists = os .path .exists (filename )
405
392
if value and not fileexists :
406
393
touch (filename )
@@ -416,7 +403,7 @@ def _get_alternates(self):
416
403
"""The list of alternates for this repo from which objects can be retrieved
417
404
418
405
: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' )
420
407
421
408
if os .path .exists (alternates_path ):
422
409
try :
@@ -439,9 +426,9 @@ def _set_alternates(self, alts):
439
426
:note:
440
427
The method does not check for the existance of the paths in alts
441
428
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' )
443
430
if not alts :
444
- if os . path . isfile (alternates_path ):
431
+ if isfile (alternates_path ):
445
432
os .remove (alternates_path )
446
433
else :
447
434
try :
@@ -469,7 +456,7 @@ def is_dirty(self, index=True, working_tree=True, untracked_files=False):
469
456
default_args = ('--abbrev=40' , '--full-index' , '--raw' )
470
457
if index :
471
458
# 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 \
473
460
len (self .git .diff ('HEAD' , '--cached' , * default_args )):
474
461
return True
475
462
# END index handling
@@ -677,7 +664,7 @@ def clone(self, path, **kwargs):
677
664
# our git command could have a different working dir than our actual
678
665
# environment, hence we prepend its working dir if required
679
666
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 )
681
668
return Repo (os .path .abspath (path ), odbt = odbt )
682
669
683
670
@@ -696,203 +683,13 @@ def archive(self, ostream, treeish=None, prefix=None, **kwargs):
696
683
if treeish is None :
697
684
treeish = self .active_branch
698
685
if prefix and 'prefix' not in kwargs :
699
- kwargs ['prefix' ] = prefix
686
+ kwargs ['prefix' ] = prefix
700
687
kwargs ['output_stream' ] = ostream
701
688
702
689
self .git .archive (treeish , ** kwargs )
703
690
return self
691
+
692
+ rev_parse = rev_parse
704
693
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
-
897
694
def __repr__ (self ):
898
695
return '<git.Repo "%s">' % self .git_dir
0 commit comments