From 05b2b062afa2ab4cbd504735fd16cf53d969a2a5 Mon Sep 17 00:00:00 2001 From: Sam Thursfield Date: Tue, 5 May 2015 15:16:54 +0000 Subject: Move 'git config' wrapper into its own class We use 'git config' format config files outside Git repos, so it's useful to have a helper class independent of the GitDirectory class. This allows us to use it in the sysbranchdir.open() function to remove a hack. Change-Id: Ifa5e87f404d10666c98b9469079b7925d16becf6 --- morphlib/gitdir.py | 66 +++++++++++++++++++++++++++++++++++++++++------- morphlib/gitdir_tests.py | 7 +++++ morphlib/sysbranchdir.py | 20 ++++++++------- 3 files changed, 75 insertions(+), 18 deletions(-) diff --git a/morphlib/gitdir.py b/morphlib/gitdir.py index 688e4b34..9cb62e3b 100644 --- a/morphlib/gitdir.py +++ b/morphlib/gitdir.py @@ -134,6 +134,60 @@ class PushFailureError(PushError): 'stderr: %(stderr)s' % locals()) +class Config(object): + '''Class representing Git repo configuration. + + The 'git config' format is reusable outside of Git repos, and this class + can be used for these files too. + + This class doesn't take any notice of updates by other processes to the + config file, at present. Updates are cached in memory, so changes made from + outside the process may be ignored. + + ''' + def __init__(self, config_file, runcmd=None): + '''Creates a Config instance. + + The 'filepath' parameter can be None if 'runcmd' is passed. Calls to + 'git config' will be passed through 'runcmd', which can set the 'cwd' + parameter to a git repo. + + ''' + assert runcmd or config_file + + if runcmd: + self.runcmd = runcmd + self.extra_args = [] + else: + self.runcmd = cliapp.runcmd + self.extra_args = ['-f', config_file] + + self.cache = dict() + + def __setitem__(self, key, value): + '''Set a git repository configuration variable. + + The key must have at least one period in it: foo.bar for example, + not just foo. The part before the first period is interpreted + by git as a section name. + + ''' + self.cache[key] = value + self.runcmd(['git', 'config'] + self.extra_args + [key, value]) + + def __getitem__(self, key): + '''Return value for a git repository configuration variable. + + If the variable is unset, this will raise cliapp.AppException. + + ''' + if key not in self.cache: + value = self.runcmd( + ['git', 'config'] + self.extra_args + ['-z', key]) + self.cache[key] = value.rstrip('\0') + return self.cache[key] + + class RefSpec(object): '''Class representing how to push or pull a ref. @@ -384,7 +438,7 @@ class GitDirectory(object): dirname = morphlib.util.find_root(dirname, '.git') self.dirname = dirname - self._config = {} + self.config = Config(config_file=None, runcmd=self._runcmd) self._ensure_is_git_repo() @@ -486,9 +540,7 @@ class GitDirectory(object): by git as a section name. ''' - - morphlib.git.gitcmd(self._runcmd, 'config', key, value) - self._config[key] = value + self.config[key] = value def get_config(self, key): '''Return value for a git repository configuration variable. @@ -496,11 +548,7 @@ class GitDirectory(object): If the variable is unset, this will raise cliapp.AppException. ''' - - if key not in self._config: - value = morphlib.git.gitcmd(self._runcmd, 'config', '-z', key) - self._config[key] = value.rstrip('\0') - return self._config[key] + return self.config[key] def get_remote(self, *args, **kwargs): '''Get a remote for this Repository. diff --git a/morphlib/gitdir_tests.py b/morphlib/gitdir_tests.py index f606dfe7..0eafc0e8 100644 --- a/morphlib/gitdir_tests.py +++ b/morphlib/gitdir_tests.py @@ -90,6 +90,13 @@ class GitDirectoryTests(unittest.TestCase): gitdir.set_config('foo.bar', 'yoyo') self.assertEqual(gitdir.get_config('foo.bar'), 'yoyo') + def test_sets_and_gets_configuration_from_file(self): + gitdir = self.empty_git_directory() + config = morphlib.gitdir.Config( + config_file=os.path.join(gitdir.dirname, '.git', 'config')) + config['foo.bar'] = 'yoyo' + self.assertEqual(config['foo.bar'], 'yoyo') + def test_gets_index(self): gitdir = self.empty_git_directory() self.assertIsInstance(gitdir.get_index(), morphlib.gitindex.GitIndex) diff --git a/morphlib/sysbranchdir.py b/morphlib/sysbranchdir.py index 69119f5b..3ca5a8cb 100644 --- a/morphlib/sysbranchdir.py +++ b/morphlib/sysbranchdir.py @@ -50,6 +50,8 @@ class SystemBranchDirectory(object): self.root_repository_url = root_repository_url self.system_branch_name = system_branch_name + self.config = morphlib.gitdir.Config(config_file=self._config_path) + @property def _magic_path(self): return os.path.join(self.root_directory, '.morph-system-branch') @@ -60,14 +62,11 @@ class SystemBranchDirectory(object): def set_config(self, key, value): '''Set a configuration key/value pair.''' - morphlib.git.gitcmd(cliapp.runcmd, 'config', '-f', - self._config_path, key, value) + self.config[key] = value def get_config(self, key): '''Get a configuration value for a given key.''' - value = morphlib.git.gitcmd(cliapp.runcmd, 'config', '-f', - self._config_path, key) - return value.strip() + return self.config[key] def _find_git_directory(self, repo_url): for gd in self.list_git_directories(): @@ -210,6 +209,7 @@ class SystemBranchDirectory(object): yield m + def create(root_directory, root_repository_url, system_branch_name): '''Create a new system branch directory on disk. @@ -242,10 +242,12 @@ def create(root_directory, root_repository_url, system_branch_name): def open(root_directory): '''Open an existing system branch directory.''' - # Ugly hack follows. - sb = SystemBranchDirectory(root_directory, None, None) - root_repository_url = sb.get_config('branch.root') - system_branch_name = sb.get_config('branch.name') + config_file_path = os.path.join( + root_directory, '.morph-system-branch', 'config') + config = morphlib.gitdir.Config(config_file=config_file_path) + + root_repository_url = config['branch.root'] + system_branch_name = config['branch.name'] return SystemBranchDirectory( root_directory, root_repository_url, system_branch_name) -- cgit v1.2.1