From 0f757009e17ed38f6aa8012691747f465872a994 Mon Sep 17 00:00:00 2001 From: Richard Maw Date: Tue, 12 Nov 2013 16:50:27 +0000 Subject: GitDir: Split out Remote object Operations on remotes are now accessed through this proxy object. --- morphlib/gitdir.py | 55 ++++++++++++++++++++++++++++++++++++------------ morphlib/gitdir_tests.py | 41 +++++++++++++++++++++++++++--------- morphlib/sysbranchdir.py | 3 ++- 3 files changed, 74 insertions(+), 25 deletions(-) diff --git a/morphlib/gitdir.py b/morphlib/gitdir.py index df2fde61..2b7bba2a 100644 --- a/morphlib/gitdir.py +++ b/morphlib/gitdir.py @@ -90,6 +90,39 @@ class RefDeleteError(RefChangeError): 'located at %(dirname)s: %(original_exception)r' % locals()) +class Remote(object): + '''Represent a remote git repository. + + This can either be nascent or concrete, depending on whether the + name is given. + + Changes to a concrete remote's config are written-through to git's + config files, while a nascent remote keeps changes in-memory. + + ''' + + def __init__(self, gd, name=None): + self.gd = gd + self.name = name + self.fetch_url = None + + def set_fetch_url(self, url): + self.fetch_url = url + if self.name is not None: + self.gd._runcmd(['git', 'remote', 'set-url', self.name, url]) + + def get_fetch_url(self): + if self.name is None: + return self.fetch_url + try: + # git-ls-remote is used, rather than git-config, since + # url.*.{push,}insteadof is processed after config is loaded + return self.gd._runcmd( + ['git', 'ls-remote', '--get-url', self.name]).rstrip('\n') + except cliapp.AppException: + return None + + class GitDirectory(object): '''Represent a git working tree + .git directory. @@ -196,20 +229,14 @@ class GitDirectory(object): value = self._runcmd(['git', 'config', '-z', key]) return value.rstrip('\0') - def set_remote_fetch_url(self, remote_name, url): - '''Set the fetch URL for a remote.''' - self._runcmd(['git', 'remote', 'set-url', remote_name, url]) - - def get_remote_fetch_url(self, remote_name): - '''Return the fetch URL for a given remote.''' - output = self._runcmd(['git', 'remote', '-v']) - for line in output.splitlines(): - words = line.split() - if (len(words) == 3 and - words[0] == remote_name and - words[2] == '(fetch)'): - return words[1] - return None + def get_remote(self, *args, **kwargs): + '''Get a remote for this Repository. + + Gets a previously configured remote if a remote name is given. + Otherwise a nascent one is created. + + ''' + return Remote(self, *args, **kwargs) def update_remotes(self): # pragma: no cover '''Run "git remote update --prune".''' diff --git a/morphlib/gitdir_tests.py b/morphlib/gitdir_tests.py index 7a251d23..2adbec62 100644 --- a/morphlib/gitdir_tests.py +++ b/morphlib/gitdir_tests.py @@ -55,16 +55,6 @@ class GitDirectoryTests(unittest.TestCase): gitdir.set_config('foo.bar', 'yoyo') self.assertEqual(gitdir.get_config('foo.bar'), 'yoyo') - def test_sets_remote(self): - os.mkdir(self.dirname) - gitdir = morphlib.gitdir.init(self.dirname) - self.assertEqual(gitdir.get_remote_fetch_url('origin'), None) - - gitdir._runcmd(['git', 'remote', 'add', 'origin', 'foobar']) - url = 'git://git.example.com/foo' - gitdir.set_remote_fetch_url('origin', url) - self.assertEqual(gitdir.get_remote_fetch_url('origin'), url) - def test_gets_index(self): os.mkdir(self.dirname) gitdir = morphlib.gitdir.init(self.dirname) @@ -289,3 +279,34 @@ class GitDirectoryRefTwiddlingTests(unittest.TestCase): prev_commit = gd._rev_parse('refs/heads/master^') with self.assertRaises(morphlib.gitdir.RefDeleteError): gd.delete_ref('refs/heads/master', prev_commit) + + +class GitDirectoryRemoteConfigTests(unittest.TestCase): + + def setUp(self): + self.tempdir = tempfile.mkdtemp() + self.dirname = os.path.join(self.tempdir, 'foo') + + def tearDown(self): + shutil.rmtree(self.tempdir) + + def test_sets_fetch_url(self): + os.mkdir(self.dirname) + gitdir = morphlib.gitdir.init(self.dirname) + self.assertEqual(gitdir.get_remote('origin').get_fetch_url(), None) + + gitdir._runcmd(['git', 'remote', 'add', 'origin', 'foobar']) + url = 'git://git.example.com/foo' + remote = gitdir.get_remote('origin') + remote.set_fetch_url(url) + self.assertEqual(remote.get_fetch_url(), url) + + def test_nascent_remote(self): + os.mkdir(self.dirname) + gitdir = morphlib.gitdir.init(self.dirname) + remote = gitdir.get_remote(None) + self.assertEqual(remote.get_fetch_url(), None) + + url = 'git://git.example.com/foo' + remote.set_fetch_url(url) + self.assertEqual(remote.get_fetch_url(), url) diff --git a/morphlib/sysbranchdir.py b/morphlib/sysbranchdir.py index a05ca52e..73a07d5e 100644 --- a/morphlib/sysbranchdir.py +++ b/morphlib/sysbranchdir.py @@ -141,7 +141,8 @@ class SystemBranchDirectory(object): # and not the locally cached copy. resolver = morphlib.repoaliasresolver.RepoAliasResolver( cached_repo.app.settings['repo-alias']) - gd.set_remote_fetch_url('origin', resolver.pull_url(cached_repo.url)) + remote = gd.get_remote('origin') + remote.set_fetch_url(resolver.pull_url(cached_repo.url)) gd.set_config( 'url.%s.pushInsteadOf' % resolver.push_url(cached_repo.original_name), -- cgit v1.2.1