Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4d36f8f

Browse filesBrowse files
committed
Improved GitConfigurationParser to better deal with streams and the corresponding locks. Submodule class now operates on parent_commits, the configuration is either streamed from the repository or written directly into a blob ( or file ) dependending on whether we have a working tree checkout or not which matches our parent_commit
1 parent a1e2f63 commit 4d36f8f
Copy full SHA for 4d36f8f

File tree

4 files changed

+60
-32
lines changed
Filter options

4 files changed

+60
-32
lines changed

‎lib/git/config.py

Copy file name to clipboardExpand all lines: lib/git/config.py
+8-4Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,9 +271,9 @@ def read(self):
271271
if not hasattr(file_object, "seek"):
272272
try:
273273
fp = open(file_object)
274+
close_fp = True
274275
except IOError,e:
275276
continue
276-
close_fp = True
277277
# END fp handling
278278

279279
try:
@@ -308,17 +308,21 @@ def write(self):
308308
:raise IOError: if this is a read-only writer instance or if we could not obtain
309309
a file lock"""
310310
self._assure_writable("write")
311-
self._lock._obtain_lock()
312-
313311

314312
fp = self._file_or_files
315313
close_fp = False
316314

315+
# we have a physical file on disk, so get a lock
316+
if isinstance(fp, (basestring, file)):
317+
self._lock._obtain_lock()
318+
# END get lock for physical files
319+
317320
if not hasattr(fp, "seek"):
318321
fp = open(self._file_or_files, "w")
319322
close_fp = True
320323
else:
321324
fp.seek(0)
325+
# END handle stream or file
322326

323327
# WRITE DATA
324328
try:
@@ -390,7 +394,7 @@ def get_value(self, section, option, default = None):
390394
return valuestr
391395

392396
@needs_values
393-
@set_dirty_and_flush_changes
397+
@set_dirty_and_flush_changes
394398
def set_value(self, section, option, value):
395399
"""Sets the given option in section to the given value.
396400
It will create the section if required, and will not throw as opposed to the default

‎lib/git/objects/submodule.py

Copy file name to clipboardExpand all lines: lib/git/objects/submodule.py
+46-24Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66

77
__all__ = ("Submodule", )
88

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+
916
class Submodule(base.IndexObject):
1017
"""Implements access to a git submodule. They are special in that their sha
1118
represents a commit in the submodule's repository which is to be checked out
@@ -20,14 +27,14 @@ class Submodule(base.IndexObject):
2027
# this is a bogus type for base class compatability
2128
type = 'submodule'
2229

23-
__slots__ = ('_root_tree', '_url', '_ref')
30+
__slots__ = ('_parent_commit', '_url', '_ref')
2431

2532
def _set_cache_(self, attr):
2633
if attr == 'size':
2734
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':
2936
# 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()
3138
elif attr in ('path', '_url', '_ref'):
3239
reader = self.config_reader()
3340
# default submodule values
@@ -39,13 +46,26 @@ def _set_cache_(self, attr):
3946
super(Submodule, self)._set_cache_(attr)
4047
# END handle attribute name
4148

42-
def _fp_config(self):
49+
def _sio_modules(self):
4350
""":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
4554

4655
def _config_parser(self, read_only):
4756
""":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)
4969
return SectionConstraint(parser, 'submodule "%s"' % self.path)
5070

5171
#{ Edit Interface
@@ -61,21 +81,24 @@ def add(cls, repo, path, url, skip_init=False):
6181
:param skip_init: if True, the new repository will not be cloned to its location.
6282
:return: The newly created submodule instance"""
6383

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))
7292
# END handle exceptions
73-
self._root_tree = tree
93+
self._parent_commit = pcommit
7494

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
79102

80103
def config_writer(self):
81104
""":return: a config writer instance allowing you to read and write the data
@@ -108,11 +131,10 @@ def url(self):
108131
""":return: The url to the repository which our module-repository refers to"""
109132
return self._url
110133

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
116138

117139
def config_reader(self):
118140
""":return: ConfigReader instance which allows you to qurey the configuration values

‎test/git/test_config.py

Copy file name to clipboardExpand all lines: test/git/test_config.py
+1-3Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ class TestBase(TestCase):
1414

1515
def _to_memcache(self, file_path):
1616
fp = open(file_path, "r")
17-
sio = StringIO.StringIO()
18-
sio.write(fp.read())
19-
sio.seek(0)
17+
sio = StringIO.StringIO(fp.read())
2018
sio.name = file_path
2119
return sio
2220

‎test/git/test_submodule.py

Copy file name to clipboardExpand all lines: test/git/test_submodule.py
+5-1Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ def _do_base_tests(self, rwrepo):
1919
# size is invalid
2020
self.failUnlessRaises(ValueError, getattr, sm, 'size')
2121

22-
# fails if tree has no gitmodule file
22+
# set_parent_commit fails if tree has no gitmodule file
23+
24+
2325

2426
if rwrepo.bare:
2527
# module fails
@@ -28,6 +30,8 @@ def _do_base_tests(self, rwrepo):
2830
# get the module repository
2931
pass
3032
# END bare handling
33+
34+
# Writing of historical submodule configurations must not work
3135

3236
@with_rw_repo(kCOTag)
3337
def test_base_rw(self, rwrepo):

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.