diff options
author | Jannis Pohlmann <jannis.pohlmann@codethink.co.uk> | 2013-01-03 13:34:36 +0000 |
---|---|---|
committer | Jannis Pohlmann <jannis.pohlmann@codethink.co.uk> | 2013-01-07 18:15:07 +0000 |
commit | 24577c3e4a2b8e08ef0fcf23a4664bc38530ef2b (patch) | |
tree | 29ab330d69888711e4715a05bebce869903ee986 | |
parent | 7172dca14d7306d79e93b97dcef3a006309f2e03 (diff) | |
download | morph-24577c3e4a2b8e08ef0fcf23a4664bc38530ef2b.tar.gz |
Add RemoteRepoCache.resolve_refs() method with tests
This method is for batch-resolving of refs into SHA1s using the remote
repo cache. It takes a list of (repo, ref) tuples and returns
dictionary that maps these tuples to dictionaries that look as follow
in successful cases
{
'repo': <original repo>,
'ref': <original ref>,
'repo-url': <expanded full repo URL>,
'sha1': <resolved SHA1>,
'tree': <tree SHA1 of the commit>,
}
and like this in negative cases:
{
'repo': <original repo>,
'ref': <original ref>,
'repo-url': <expanded full repo URL>,
'error': <error string>,
}
The mapping may seem redundant but it might be useful when looking up
the results. If tuples are passed in they will be available at the
caller's end already.
-rw-r--r-- | morphlib/localrepocache.py | 1 | ||||
-rw-r--r-- | morphlib/remoterepocache.py | 41 | ||||
-rw-r--r-- | morphlib/remoterepocache_tests.py | 83 |
3 files changed, 124 insertions, 1 deletions
diff --git a/morphlib/localrepocache.py b/morphlib/localrepocache.py index 465e9f03..47680da1 100644 --- a/morphlib/localrepocache.py +++ b/morphlib/localrepocache.py @@ -195,6 +195,7 @@ class LocalRepoCache(object): def _cache_name(self, url): scheme, netloc, path, query, fragment = urlparse.urlsplit(url) if scheme == 'file': + return path else: basename = self._escape(url) diff --git a/morphlib/remoterepocache.py b/morphlib/remoterepocache.py index 5c2017de..4a735187 100644 --- a/morphlib/remoterepocache.py +++ b/morphlib/remoterepocache.py @@ -28,6 +28,13 @@ class ResolveRefError(cliapp.AppException): (ref, repo_name)) +class ResolveRefsError(cliapp.AppException): + + def __init__(self, tuples): + cliapp.AppException.__init__( + self, 'Failed to resolve refs: %s' % tuples) + + class CatFileError(cliapp.AppException): def __init__(self, repo_name, ref, filename): @@ -56,6 +63,13 @@ class RemoteRepoCache(object): except: raise ResolveRefError(repo_name, ref) + def resolve_refs(self, tuples): + pull_urls = [self._resolver.pull_url(repo) for repo, ref in tuples] + try: + return self._resolve_refs_for_repo_urls(tuples, pull_urls) + except: + raise ResolveRefsError(tuples) + def cat_file(self, repo_name, ref, filename): repo_url = self._resolver.pull_url(repo_name) try: @@ -76,6 +90,25 @@ class RemoteRepoCache(object): info = json.loads(data) return info['sha1'], info['tree'] + def _resolve_refs_for_repo_urls(self, tuples, urls): # pragma: no cover + request_data = [] + for n in xrange(0, len(tuples)): + request_data.append({'repo': urls[n], 'ref': tuples[n][1]}) + response_data = self._make_post_request('sha1s', request_data) + data = {} + for n in xrange(0, len(tuples)): + data[tuples[n]] = { + 'repo': tuples[n][0], + 'repo-url': response_data[n]['repo'], + 'ref': response_data[n]['ref'], + } + if 'error' in resonse_data[n]: + data[tuples[n]]['error'] = response_data[n]['error'] + else: + data[tuples[n]]['sha1'] = response_data[n]['sha1'] + data[tuples[n]]['tree'] = response_data[n]['tree'] + return data + def _cat_file_for_repo_url(self, repo_url, ref, filename): # pragma: no cover return self._make_request( @@ -91,3 +124,11 @@ class RemoteRepoCache(object): url = urlparse.urljoin(server_url, '/1.0/%s' % path) handle = urllib2.urlopen(url) return handle.read() + + def _make_post_request(self, path, data): # pragma: no cover + server_url = self.server_url + if not server_url.endswith('/'): + server_url += '/' + url = urlparse.urljoin(server_url, '/1.0/%s' % path) + handle = urllib2.urlopen(url, data) + return handle.read() diff --git a/morphlib/remoterepocache_tests.py b/morphlib/remoterepocache_tests.py index 5ef61f48..e448b91c 100644 --- a/morphlib/remoterepocache_tests.py +++ b/morphlib/remoterepocache_tests.py @@ -1,4 +1,4 @@ -# Copyright (C) 2012 Codethink Limited +# Copyright (C) 2012-2013 Codethink Limited # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,6 +25,23 @@ class RemoteRepoCacheTests(unittest.TestCase): def _resolve_ref_for_repo_url(self, repo_url, ref): return self.sha1s[repo_url][ref] + def _resolve_refs_for_repo_urls(self, tuples, urls): + if self.fail_resolving: + raise Exception('Failed') + data = {} + for n in xrange(0, len(tuples)): + data[tuples[n]] = { + 'repo': tuples[n][0], + 'repo-url': urls[n], + 'ref': tuples[n][1], + } + if tuples[n][0] == 'upstream:foo': + data[tuples[n]]['error'] = 'Failed' + else: + data[tuples[n]]['sha1'] = self.sha1s[urls[n]][tuples[n][1]] + data[tuples[n]]['tree'] = self.trees[urls[n]][tuples[n][1]] + return data + def _cat_file_for_repo_url(self, repo_url, sha1, filename): return self.files[repo_url][sha1][filename] @@ -39,6 +56,17 @@ class RemoteRepoCacheTests(unittest.TestCase): self.sha1s = { 'git://gitorious.org/baserock/morph': { 'master': 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9' + }, + 'git://gitorious.org/baserock-morphs/linux': { + 'foo/bar': 'aa363025d0b699b4251ee80aeec2b863e57dd7ec' + } + } + self.trees = { + 'git://gitorious.org/baserock/morph': { + 'master': 'f99e30eb68c28ea8bc2ca7710e2894c49bbaedbe' + }, + 'git://gitorious.org/baserock-morphs/linux': { + 'foo/bar': '4c7b6184fe12775ceb83cefb405921e961495e9c' } } self.files = { @@ -57,8 +85,11 @@ class RemoteRepoCacheTests(unittest.TestCase): self.cache = morphlib.remoterepocache.RemoteRepoCache( self.server_url, resolver) self.cache._resolve_ref_for_repo_url = self._resolve_ref_for_repo_url + self.cache._resolve_refs_for_repo_urls = \ + self._resolve_refs_for_repo_urls self.cache._cat_file_for_repo_url = self._cat_file_for_repo_url self.cache._ls_tree_for_repo_url = self._ls_tree_for_repo_url + self.fail_resolving = False def test_sets_server_url(self): self.assertEqual(self.cache.server_url, self.server_url) @@ -84,6 +115,56 @@ class RemoteRepoCacheTests(unittest.TestCase): self.cache.resolve_ref, 'non-existent-repo', 'non-existent-ref') + def test_resolves_multiple_existing_refs(self): + sha1s = self.cache.resolve_refs( + [('baserock:morph', 'master'), ('upstream:linux', 'foo/bar')]) + self.assertEqual( + sha1s[('baserock:morph', 'master')], + { + 'repo': 'baserock:morph', + 'repo-url': 'git://gitorious.org/baserock/morph', + 'ref': 'master', + 'sha1': 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9', + 'tree': 'f99e30eb68c28ea8bc2ca7710e2894c49bbaedbe' + }) + self.assertEqual( + sha1s[('upstream:linux', 'foo/bar')], + { + 'repo': 'upstream:linux', + 'repo-url': 'git://gitorious.org/baserock-morphs/linux', + 'ref': 'foo/bar', + 'sha1': 'aa363025d0b699b4251ee80aeec2b863e57dd7ec', + 'tree': '4c7b6184fe12775ceb83cefb405921e961495e9c' + }) + + def test_throws_exception_when_failing_to_resolve_refs_entirely(self): + self.fail_resolving = True + self.assertRaises( + morphlib.remoterepocache.ResolveRefsError, + self.cache.resolve_refs, + [('baserock:morph', 'master'), ('upstream:linux', 'foo/bar')]) + + def test_fills_error_fields_when_failing_to_resolve_some_refs(self): + sha1s = self.cache.resolve_refs( + [('baserock:morph', 'master'), ('upstream:foo', 'bar')]) + self.assertEqual( + sha1s[('baserock:morph', 'master')], + { + 'repo': 'baserock:morph', + 'repo-url': 'git://gitorious.org/baserock/morph', + 'ref': 'master', + 'sha1': 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9', + 'tree': 'f99e30eb68c28ea8bc2ca7710e2894c49bbaedbe' + }) + self.assertEqual( + sha1s[('upstream:foo', 'bar')], + { + 'repo': 'upstream:foo', + 'repo-url': 'git://gitorious.org/baserock-morphs/foo', + 'ref': 'bar', + 'error': 'Failed', + }) + def test_cat_existing_file_in_existing_repo_and_ref(self): content = self.cache.cat_file( 'upstream:linux', 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9', |