summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJannis Pohlmann <jannis.pohlmann@codethink.co.uk>2013-01-03 13:34:36 +0000
committerJannis Pohlmann <jannis.pohlmann@codethink.co.uk>2013-01-07 18:15:07 +0000
commit24577c3e4a2b8e08ef0fcf23a4664bc38530ef2b (patch)
tree29ab330d69888711e4715a05bebce869903ee986
parent7172dca14d7306d79e93b97dcef3a006309f2e03 (diff)
downloadmorph-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.py1
-rw-r--r--morphlib/remoterepocache.py41
-rw-r--r--morphlib/remoterepocache_tests.py83
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',