6
6
7
7
__all__ = ("Submodule" , )
8
8
9
+ class SubmoduleConfigParser (GitConfigParser ):
10
+ """Catches calls to _write, and updates the .gitmodules blob in the index
11
+ with the new data, if we have written into a stream. Otherwise it will
12
+ add the local file to the index to make it correspond with the working tree."""
13
+ _mutating_methods_ = tuple ()
14
+
15
+
9
16
class Submodule (base .IndexObject ):
10
17
"""Implements access to a git submodule. They are special in that their sha
11
18
represents a commit in the submodule's repository which is to be checked out
@@ -20,14 +27,14 @@ class Submodule(base.IndexObject):
20
27
# this is a bogus type for base class compatability
21
28
type = 'submodule'
22
29
23
- __slots__ = ('_root_tree ' , '_url' , '_ref' )
30
+ __slots__ = ('_parent_commit ' , '_url' , '_ref' )
24
31
25
32
def _set_cache_ (self , attr ):
26
33
if attr == 'size' :
27
34
raise ValueError ("Submodules do not have a size as they do not refer to anything in this repository" )
28
- elif attr == '_root_tree ' :
35
+ elif attr == '_parent_commit ' :
29
36
# set a default value, which is the root tree of the current head
30
- self ._root_tree = self .repo .tree ()
37
+ self ._parent_commit = self .repo .commit ()
31
38
elif attr in ('path' , '_url' , '_ref' ):
32
39
reader = self .config_reader ()
33
40
# default submodule values
@@ -39,13 +46,26 @@ def _set_cache_(self, attr):
39
46
super (Submodule , self )._set_cache_ (attr )
40
47
# END handle attribute name
41
48
42
- def _fp_config (self ):
49
+ def _sio_modules (self ):
43
50
""":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 ())
51
+ sio = StringIO (self ._parent_commit .tree [self .kModulesFile ].datastream .read ())
52
+ sio .name = self .kModulesFile
53
+ return sio
45
54
46
55
def _config_parser (self , read_only ):
47
56
""":return: Config Parser constrained to our submodule in read or write mode"""
48
- parser = GitConfigParser (self ._fp_config (), read_only = read_only )
57
+ parent_matches_head = self .repo .head .commit == self ._parent_commit
58
+ if not self .repo .bare and parent_matches_head :
59
+ fp_module = self .kModulesFile
60
+ else :
61
+ fp_module = self ._sio_modules ()
62
+ # END handle non-bare working tree
63
+
64
+ if not read_only and not parent_matches_head :
65
+ raise ValueError ("Cannot write blobs of 'historical' submodule configurations" )
66
+ # END handle writes of historical submodules
67
+
68
+ parser = GitConfigParser (fp_module , read_only = read_only )
49
69
return SectionConstraint (parser , 'submodule "%s"' % self .path )
50
70
51
71
#{ Edit Interface
@@ -61,21 +81,24 @@ def add(cls, repo, path, url, skip_init=False):
61
81
:param skip_init: if True, the new repository will not be cloned to its location.
62
82
:return: The newly created submodule instance"""
63
83
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 ))
84
+ def set_parent_commit (self , commit ):
85
+ """Set this instance to use the given commit whose tree is supposed to
86
+ contain the .gitmodules blob.
87
+ :param commit: Commit 'ish reference pointing at the root_tree
88
+ :raise ValueError: if the commit's tree didn't contain the .gitmodules blob."""
89
+ pcommit = self .repo .commit ( commit )
90
+ if self .kModulesFile not in pcommit . tree :
91
+ raise ValueError ("Tree of commit %s did not contain the %s file" % (commit , self .kModulesFile ))
72
92
# END handle exceptions
73
- self ._root_tree = tree
93
+ self ._parent_commit = pcommit
74
94
75
- # clear the possibly changing values
76
- del (self .path )
77
- del (self ._ref )
78
- del (self ._url )
95
+ # clear the possibly changed values
96
+ for name in ('path' , '_ref' , '_url' ):
97
+ try :
98
+ delattr (self , name )
99
+ except AttributeError :
100
+ pass
101
+ # END for each name to delete
79
102
80
103
def config_writer (self ):
81
104
""":return: a config writer instance allowing you to read and write the data
@@ -108,11 +131,10 @@ def url(self):
108
131
""":return: The url to the repository which our module-repository refers to"""
109
132
return self ._url
110
133
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
134
+ def parent_commit (self ):
135
+ """:return: Commit instance with the tree containing the .gitmodules file
136
+ :note: will always point to the current head's commit if it was not set explicitly"""
137
+ return self ._parent_commit
116
138
117
139
def config_reader (self ):
118
140
""":return: ConfigReader instance which allows you to qurey the configuration values
0 commit comments