diff options
-rw-r--r-- | git/config.py | 36 | ||||
-rw-r--r-- | git/test/test_config.py | 17 |
2 files changed, 38 insertions, 15 deletions
diff --git a/git/config.py b/git/config.py index 21af6159..5bd10975 100644 --- a/git/config.py +++ b/git/config.py @@ -133,10 +133,11 @@ class SectionConstraint(object): return self._config.release() def __enter__(self): + self._config.__enter__() return self def __exit__(self, exception_type, exception_value, traceback): - self.release() + self._config.__exit__(exception_type, exception_value, traceback) class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, object)): @@ -155,8 +156,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje :note: The config is case-sensitive even when queried, hence section and option names must match perfectly. - If used as a context manager, will release the locked file. This parser cannot - be used afterwards.""" + If used as a context manager, will release the locked file.""" #{ Configuration # The lock type determines the type of lock to use in new configuration readers. @@ -206,18 +206,23 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje self._is_initialized = False self._merge_includes = merge_includes self._lock = None - - if not read_only: - if isinstance(file_or_files, (tuple, list)): - raise ValueError( - "Write-ConfigParsers can operate on a single file only, multiple files have been passed") - # END single file check - - if not isinstance(file_or_files, string_types): - file_or_files = file_or_files.name - # END get filename from handle/stream - # initialize lock base - we want to write - self._lock = self.t_lock(file_or_files) + self._aquire_lock() + + def _aquire_lock(self): + if not self._read_only: + if not self._lock: + if isinstance(self._file_or_files, (tuple, list)): + raise ValueError( + "Write-ConfigParsers can operate on a single file only, multiple files have been passed") + # END single file check + + file_or_files = self._file_or_files + if not isinstance(self._file_or_files, string_types): + file_or_files = self._file_or_files.name + # END get filename from handle/stream + # initialize lock base - we want to write + self._lock = self.t_lock(file_or_files) + # END lock check self._lock._obtain_lock() # END read-only check @@ -228,6 +233,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje self.release() def __enter__(self): + self._aquire_lock() return self def __exit__(self, exception_type, exception_value, traceback): diff --git a/git/test/test_config.py b/git/test/test_config.py index 81eacd20..c0889c1a 100644 --- a/git/test/test_config.py +++ b/git/test/test_config.py @@ -72,6 +72,23 @@ class TestBase(TestCase): w_config.release() # END for each filename + @with_rw_directory + def test_lock_reentry(self, rw_dir): + fpl = os.path.join(rw_dir, 'l') + gcp = GitConfigParser(fpl, read_only=False) + with gcp as cw: + cw.set_value('include', 'some_value', 'a') + # entering again locks the file again... + with gcp as cw: + cw.set_value('include', 'some_other_value', 'b') + # ...so creating an additional config writer must fail due to exclusive access + self.failUnlessRaises(IOError, GitConfigParser, fpl, read_only=False) + # but work when the lock is removed + with GitConfigParser(fpl, read_only=False): + assert os.path.exists(fpl) + # reentering with an existing lock must fail due to exclusive access + self.failUnlessRaises(IOError, gcp.__enter__) + def test_multi_line_config(self): file_obj = self._to_memcache(fixture_path("git_config_with_comments")) config = GitConfigParser(file_obj, read_only=False) |