1
1
import base
2
+ from cStringIO import StringIO
3
+ from git .config import GitConfigParser
4
+ from git .util import join_path_native
5
+ from git .exc import InvalidGitRepositoryError , NoSuchPathError
2
6
3
7
__all__ = ("Submodule" , )
4
8
@@ -7,10 +11,115 @@ class Submodule(base.IndexObject):
7
11
represents a commit in the submodule's repository which is to be checked out
8
12
at the path of this instance.
9
13
The submodule type does not have a string type associated with it, as it exists
10
- solely as a marker in the tree and index"""
14
+ solely as a marker in the tree and index.
15
+
16
+ All methods work in bare and non-bare repositories."""
17
+
18
+ kModulesFile = '.gitmodules'
11
19
12
20
# this is a bogus type for base class compatability
13
21
type = 'submodule'
14
22
15
- # TODO: Add functions to retrieve a repo for the submodule, to allow
16
- # its initiailization and handling
23
+ __slots__ = ('_root_tree' , '_url' , '_ref' )
24
+
25
+ def _set_cache_ (self , attr ):
26
+ if attr == 'size' :
27
+ raise ValueError ("Submodules do not have a size as they do not refer to anything in this repository" )
28
+ elif attr == '_root_tree' :
29
+ # set a default value, which is the root tree of the current head
30
+ self ._root_tree = self .repo .tree ()
31
+ elif attr in ('path' , '_url' , '_ref' ):
32
+ reader = self .config_reader ()
33
+ # default submodule values
34
+ self ._path = reader .get_value ('path' )
35
+ self ._url = reader .get_value ('url' )
36
+ # git-python extension values - optional
37
+ self ._ref = reader .get_value ('ref' , 'master' )
38
+ else :
39
+ super (Submodule , self )._set_cache_ (attr )
40
+ # END handle attribute name
41
+
42
+ def _fp_config (self ):
43
+ """:return: Configuration file as StringIO - we only access it through the respective blob's data"""
44
+ return StringIO (self ._root_tree [self .kModulesFile ].datastream .read ())
45
+
46
+ def _config_parser (self , read_only ):
47
+ """:return: Config Parser constrained to our submodule in read or write mode"""
48
+ parser = GitConfigParser (self ._fp_config (), read_only = read_only )
49
+ return SectionConstraint (parser , 'submodule "%s"' % self .path )
50
+
51
+ #{ Edit Interface
52
+
53
+ @classmethod
54
+ def add (cls , repo , path , url , skip_init = False ):
55
+ """Add a new submodule to the given repository. This will alter the index
56
+ as well as the .gitmodules file, but will not create a new commit.
57
+ :param repo: Repository instance which should receive the submodule
58
+ :param path: repository-relative path at which the submodule should be located
59
+ It will be created as required during the repository initialization.
60
+ :param url: git-clone compatible URL, see git-clone reference for more information
61
+ :param skip_init: if True, the new repository will not be cloned to its location.
62
+ :return: The newly created submodule instance"""
63
+
64
+ def set_root_tree (self , root_tree ):
65
+ """Set this instance to use the given tree which is supposed to contain the
66
+ .gitmodules blob.
67
+ :param root_tree: Tree'ish reference pointing at the root_tree
68
+ :raise ValueError: if the root_tree didn't contain the .gitmodules blob."""
69
+ tree = self .repo .tree (root_tree )
70
+ if self .kModulesFile not in tree :
71
+ raise ValueError ("Tree %s did not contain the %s file" % (root_tree , self .kModulesFile ))
72
+ # END handle exceptions
73
+ self ._root_tree = tree
74
+
75
+ # clear the possibly changing values
76
+ del (self .path )
77
+ del (self ._ref )
78
+ del (self ._url )
79
+
80
+ def config_writer (self ):
81
+ """:return: a config writer instance allowing you to read and write the data
82
+ belonging to this submodule into the .gitmodules file."""
83
+ return self ._config_parser (read_only = False )
84
+
85
+ #} END edit interface
86
+
87
+ #{ Query Interface
88
+
89
+ def module (self ):
90
+ """:return: Repo instance initialized from the repository at our submodule path
91
+ :raise InvalidGitRepositoryError: if a repository was not available"""
92
+ if self .repo .bare :
93
+ raise InvalidGitRepositoryError ("Cannot retrieve module repository in bare parent repositories" )
94
+ # END handle bare mode
95
+
96
+ repo_path = join_path_native (self .repo .working_tree_dir , self .path )
97
+ try :
98
+ return Repo (repo_path )
99
+ except (InvalidGitRepositoryError , NoSuchPathError ):
100
+ raise InvalidGitRepositoryError ("No valid repository at %s" % self .path )
101
+ # END handle exceptions
102
+
103
+ def ref (self ):
104
+ """:return: The reference's name that we are to checkout"""
105
+ return self ._ref
106
+
107
+ def url (self ):
108
+ """:return: The url to the repository which our module-repository refers to"""
109
+ return self ._url
110
+
111
+ def root_tree (self ):
112
+ """:return: Tree instance referring to the tree which contains the .gitmodules file
113
+ we are to use
114
+ :note: will always point to the current head's root tree if it was not set explicitly"""
115
+ return self ._root_tree
116
+
117
+ def config_reader (self ):
118
+ """:return: ConfigReader instance which allows you to qurey the configuration values
119
+ of this submodule, as provided by the .gitmodules file
120
+ :note: The config reader will actually read the data directly from the repository
121
+ and thus does not need nor care about your working tree.
122
+ :note: Should be cached by the caller and only kept as long as needed"""
123
+ return self ._config_parser .read_only (read_only = True )
124
+
125
+ #} END query interface
0 commit comments