From 975b3f30605c36a714bf5b9619817a897cb6a4a3 Mon Sep 17 00:00:00 2001 From: Sam Thursfield Date: Fri, 24 Aug 2012 17:57:49 +0100 Subject: Support 'git ls-tree' in local and remote repos --- morphlib/cachedrepo.py | 22 ++++++++++++++++++++++ morphlib/cachedrepo_tests.py | 23 +++++++++++++++++++++++ morphlib/remoterepocache.py | 18 ++++++++++++++++++ morphlib/remoterepocache_tests.py | 28 ++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+) (limited to 'morphlib') diff --git a/morphlib/cachedrepo.py b/morphlib/cachedrepo.py index d7f22400..f647102f 100644 --- a/morphlib/cachedrepo.py +++ b/morphlib/cachedrepo.py @@ -158,6 +158,24 @@ class CachedRepo(object): except cliapp.AppException: raise CheckoutError(self, ref, target_dir) + def ls_tree(self, ref): + '''Return file names found in root tree. Does not recurse to subtrees. + + Raises an UnresolvedNamedReferenceError if the ref is not a SHA1 + ref. Raises an InvalidReferenceError if the SHA1 ref is not found + in the repository. + + ''' + + if not self.is_valid_sha1(ref): + raise UnresolvedNamedReferenceError(self, ref) + try: + sha1 = self._rev_list(ref).strip() + except cliapp.AppException: + raise InvalidReferenceError(self, ref) + + return self._ls_tree(sha1) + def update(self): '''Updates the cached repository using its origin remote. @@ -182,6 +200,10 @@ class CachedRepo(object): def _rev_list(self, ref): # pragma: no cover return self._runcmd(['git', 'rev-list', '--no-walk', ref]) + def _ls_tree(self, ref): # pragma: no cover + result = self._runcmd(['git', 'ls-tree', '--name-only', ref]) + return result.split('\n') + def _cat_file(self, ref, filename): # pragma: no cover return self._runcmd(['git', 'cat-file', 'blob', '%s:%s' % (ref, filename)]) diff --git a/morphlib/cachedrepo_tests.py b/morphlib/cachedrepo_tests.py index 2a0c2c4b..fa660010 100644 --- a/morphlib/cachedrepo_tests.py +++ b/morphlib/cachedrepo_tests.py @@ -79,6 +79,16 @@ class CachedRepoTests(unittest.TestCase): with open(os.path.join(target_dir, 'foo.morph'), 'w') as f: f.write('contents of foo.morph') + def ls_tree(self, ref): + output = { + 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9': + ['foo.morph'] + } + try: + return output[ref] + except: + raise cliapp.AppException('git ls-tree --name-only %s' % (ref)) + def update_successfully(self): pass @@ -96,6 +106,7 @@ class CachedRepoTests(unittest.TestCase): self.repo._cat_file = self.cat_file self.repo._copy_repository = self.copy_repository self.repo._checkout_ref = self.checkout_ref + self.repo._ls_tree = self.ls_tree self.tempdir = morphlib.tempdir.Tempdir() def tearDown(self): @@ -177,6 +188,18 @@ class CachedRepoTests(unittest.TestCase): 'a4da32f5a81c8bc6d660404724cedc3bc0914a75', self.tempdir.join('failed-checkout')) + def test_ls_tree_in_existing_ref(self): + data = self.repo.ls_tree('e28a23812eadf2fce6583b8819b9c5dbd36b9fb9') + self.assertEqual(data, ['foo.morph']) + + def test_fail_ls_tree_in_invalid_ref(self): + self.assertRaises(cachedrepo.InvalidReferenceError, self.repo.ls_tree, + '079bbfd447c8534e464ce5d40b80114c2022ebf4') + + def test_fail_because_ls_tree_in_named_ref_is_not_allowed(self): + self.assertRaises(cachedrepo.UnresolvedNamedReferenceError, + self.repo.ls_tree, 'master') + def test_successful_update(self): self.repo._update = self.update_successfully self.repo.update() diff --git a/morphlib/remoterepocache.py b/morphlib/remoterepocache.py index d8526562..c40057b1 100644 --- a/morphlib/remoterepocache.py +++ b/morphlib/remoterepocache.py @@ -35,6 +35,13 @@ class CatFileError(cliapp.AppException): self, 'Failed to cat file %s in ref %s of repo %s' % (filename, ref, repo_name)) +class LsTreeError(cliapp.AppException): + + def __init__(self, repo_name, ref): + cliapp.AppException.__init__( + self, 'Failed to list tree in ref %s of repo %s' % + (ref, repo_name)) + class RemoteRepoCache(object): @@ -56,6 +63,14 @@ class RemoteRepoCache(object): except: raise CatFileError(repo_name, ref, filename) + def ls_tree(self, repo_name, ref): + repo_url = self._resolver.pull_url(repo_name) + try: + info = json.loads(self._ls_tree_for_repo_url(repo_url, ref)) + return info['tree'].keys() + except: + raise LsTreeError(repo_name, ref) + def _resolve_ref_for_repo_url(self, repo_url, ref): # pragma: no cover data = self._make_request('sha1s?repo=%s&ref=%s' % (repo_url, ref)) info = json.loads(data) @@ -66,6 +81,9 @@ class RemoteRepoCache(object): return self._make_request( 'files?repo=%s&ref=%s&filename=%s' % (repo_url, ref, filename)) + def _ls_tree_for_repo_url(self, repo_url, ref): # pragma: no cover + return self._make_request('trees?repo=%s&ref=%s' % (repo_url, ref)) + def _make_request(self, path): # pragma: no cover server_url = self.server_url if not server_url.endswith('/'): diff --git a/morphlib/remoterepocache_tests.py b/morphlib/remoterepocache_tests.py index 6f162f7d..5ef61f48 100644 --- a/morphlib/remoterepocache_tests.py +++ b/morphlib/remoterepocache_tests.py @@ -14,6 +14,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +import json import unittest import morphlib @@ -27,6 +28,13 @@ class RemoteRepoCacheTests(unittest.TestCase): def _cat_file_for_repo_url(self, repo_url, sha1, filename): return self.files[repo_url][sha1][filename] + def _ls_tree_for_repo_url(self, repo_url, sha1): + return json.dumps({ + 'repo': repo_url, + 'ref': sha1, + 'tree': self.files[repo_url][sha1] + }) + def setUp(self): self.sha1s = { 'git://gitorious.org/baserock/morph': { @@ -50,6 +58,7 @@ class RemoteRepoCacheTests(unittest.TestCase): self.server_url, resolver) self.cache._resolve_ref_for_repo_url = self._resolve_ref_for_repo_url 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 def test_sets_server_url(self): self.assertEqual(self.cache.server_url, self.server_url) @@ -103,3 +112,22 @@ class RemoteRepoCacheTests(unittest.TestCase): self.cache.cat_file, 'non-existent-repo', 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9', 'some-file') + + def test_ls_tree_in_existing_repo_and_ref(self): + content = self.cache.ls_tree( + 'upstream:linux', 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9') + self.assertEqual(content, ['linux.morph']) + + def test_fail_ls_tree_using_invalid_sha1(self): + self.assertRaises(morphlib.remoterepocache.LsTreeError, + self.cache.ls_tree, 'upstream:linux', 'blablabla') + + def test_fail_ls_file_in_non_existent_ref_in_existing_repo(self): + self.assertRaises(morphlib.remoterepocache.LsTreeError, + self.cache.ls_tree, 'upstream:linux', + 'ecd7a325095a0d19b8c3d76f578d85b979461d41') + + def test_fail_ls_tree_in_non_existent_repo(self): + self.assertRaises(morphlib.remoterepocache.LsTreeError, + self.cache.ls_tree, 'non-existent-repo', + 'e28a23812eadf2fce6583b8819b9c5dbd36b9fb9') -- cgit v1.2.1