summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2015-02-19 17:14:15 +0000
committerSam Thursfield <sam.thursfield@codethink.co.uk>2015-02-20 13:48:33 +0000
commit9cdeacaea8528c1bc090046715374882e9be0e15 (patch)
treee5138900758950e066f2a5f28c6814b6c3151664
parent88e8767791d85aa0d01715f04b7e0f311f54759e (diff)
downloadmorph-9cdeacaea8528c1bc090046715374882e9be0e15.tar.gz
sourceresolver: Fix LsTreeError raised when constructing build graph
If you had a repo that was not in your local or remote cache in your definitions, Morph might raise LsTreeError and abort. The code was assuming the repo would already be cached in the local cache by the time it got to detecting build systems, but that's not always true -- if the (reponame, ref) pair was already in the 'resolved_trees' cache but the repo had been deleted from the local Git cache, to name one possibility. Also, the remoterepocache.ls_tree operation can fail if the repo is not hosted in the Trove, so we shouldn't abort the program in that case. Finally, this patch removes an unused variable.
-rw-r--r--morphlib/sourceresolver.py26
-rw-r--r--morphlib/sourceresolver_tests.py23
2 files changed, 40 insertions, 9 deletions
diff --git a/morphlib/sourceresolver.py b/morphlib/sourceresolver.py
index 29069d7d..0c2d1a0a 100644
--- a/morphlib/sourceresolver.py
+++ b/morphlib/sourceresolver.py
@@ -233,6 +233,7 @@ class SourceResolver(object):
loader = morphlib.morphloader.MorphologyLoader()
+ morph = None
if defs_filename and os.path.exists(defs_filename): # pragma: no cover
morph = loader.load_from_file(defs_filename)
elif self.lrc.has_repo(reponame):
@@ -245,7 +246,6 @@ class SourceResolver(object):
morph = loader.load_from_string(text)
except IOError:
morph = None
- file_list = repo.list_files(ref=sha1, recurse=False)
elif self.rrc is not None:
self.status(msg="Looking for %(reponame)s:%(filename)s in the "
"remote repo cache.",
@@ -280,16 +280,28 @@ class SourceResolver(object):
"chunk morph from repo's build system" %
expected_filename, chatty=True)
+ file_list = None
+
if self.lrc.has_repo(reponame):
repo = self.lrc.get_repo(reponame)
file_list = repo.list_files(ref=sha1, recurse=False)
elif self.rrc is not None:
- file_list = self.rrc.ls_tree(reponame, sha1)
- else:
- # We assume that _resolve_ref() must have already been called and
- # so the repo in question would have been made available already
- # if it had been possible.
- raise NotcachedError(reponame)
+ try:
+ # This may or may not succeed; if the is repo not
+ # hosted on the same Git server as the cache server then
+ # it'll definitely fail.
+ file_list = self.rrc.ls_tree(reponame, sha1)
+ except morphlib.remoterepocache.LsTreeError:
+ pass
+ if not file_list:
+ if self.update:
+ self.status(msg='Caching git repository %(reponame)s',
+ reponame=reponame)
+ repo = self.lrc.cache_repo(reponame)
+ repo.update()
+ file_list = repo.list_files(ref=sha1, recurse=False)
+ else: # pragma: no cover
+ raise NotcachedError(reponame)
buildsystem = morphlib.buildsystem.detect_build_system(file_list)
diff --git a/morphlib/sourceresolver_tests.py b/morphlib/sourceresolver_tests.py
index 2410218a..6d6a83fa 100644
--- a/morphlib/sourceresolver_tests.py
+++ b/morphlib/sourceresolver_tests.py
@@ -24,7 +24,7 @@ from morphlib.sourceresolver import (SourceResolver,
PickleCacheManager,
MorphologyNotFoundError,
NotcachedError)
-from morphlib.remoterepocache import CatFileError
+from morphlib.remoterepocache import CatFileError, LsTreeError
class FakeRemoteRepoCache(object):
@@ -135,6 +135,9 @@ class FakeLocalRepo(object):
def list_files(self, ref, recurse):
return self.morphologies.keys()
+ def update(self):
+ pass
+
class FakeLocalRepoCache(object):
@@ -147,6 +150,9 @@ class FakeLocalRepoCache(object):
def get_repo(self, reponame):
return self.lr
+ def cache_repo(self, reponame):
+ return self.lr
+
class SourceResolverTests(unittest.TestCase):
@@ -188,6 +194,9 @@ class SourceResolverTests(unittest.TestCase):
def noremotefile(self, *args):
raise CatFileError('reponame', 'ref', 'filename')
+ def noremoterepo(self, *args):
+ raise LsTreeError('reponame', 'ref')
+
def localmorph(self, *args):
return ['chunk.morph']
@@ -241,6 +250,15 @@ class SourceResolverTests(unittest.TestCase):
'assumed-local.morph')
self.assertEqual('autotools', name)
+ def test_cache_repo_if_not_in_either_cache(self):
+ self.lrc.has_repo = self.doesnothaverepo
+ self.lr.read_file = self.nolocalmorph
+ self.lr.list_files = self.autotoolsbuildsystem
+ self.rrc.ls_tree = self.noremoterepo
+ name = self.sr._detect_build_system('reponame', 'sha1',
+ 'assumed-local.morph')
+ self.assertEqual('autotools', name)
+
def test_autodetects_remote_morphology(self):
self.lrc.has_repo = self.doesnothaverepo
self.rrc.cat_file = self.noremotemorph
@@ -262,7 +280,8 @@ class SourceResolverTests(unittest.TestCase):
def test_raises_error_when_repo_does_not_exist(self):
self.lrc.has_repo = self.doesnothaverepo
- self.assertRaises(NotcachedError, self.lsr._detect_build_system,
+ self.assertRaises(MorphologyNotFoundError,
+ self.lsr._detect_build_system,
'reponame', 'sha1', 'non-existent.morph')
def test_raises_error_when_failed_to_detect_build_system(self):