summaryrefslogtreecommitdiff
path: root/morphlib/artifactresolver.py
diff options
context:
space:
mode:
Diffstat (limited to 'morphlib/artifactresolver.py')
-rw-r--r--morphlib/artifactresolver.py204
1 files changed, 102 insertions, 102 deletions
diff --git a/morphlib/artifactresolver.py b/morphlib/artifactresolver.py
index 17f038a2..ae0cfcf5 100644
--- a/morphlib/artifactresolver.py
+++ b/morphlib/artifactresolver.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2012-2013 Codethink Limited
+# Copyright (C) 2012-2014 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
@@ -16,6 +16,7 @@
import cliapp
import collections
+import logging
import morphlib
@@ -29,35 +30,21 @@ class MutualDependencyError(cliapp.AppException):
class DependencyOrderError(cliapp.AppException):
- def __init__(self, stratum, chunk, dependency_name):
+ def __init__(self, stratum_source, chunk, dependency_name):
cliapp.AppException.__init__(
self, 'In stratum %s, chunk %s references its dependency %s '
'before it is defined' %
- (stratum.source, chunk, dependency_name))
+ (stratum_source, chunk, dependency_name))
class DependencyFormatError(cliapp.AppException):
- def __init__(self, stratum, chunk):
+ def __init__(self, stratum_source, chunk):
cliapp.AppException.__init__(
self, 'In stratum %s, chunk %s uses an invalid '
- 'build-depends format' % (stratum.source, chunk))
+ 'build-depends format' % (stratum_source, chunk))
-class UndefinedChunkArtifactError(cliapp.AppException):
-
- '''Exception raised when non-existent artifacts are referenced.
-
- Usually, this will only occur when a stratum refers to a chunk
- artifact that is not defined in a chunk.
-
- '''
-
- def __init__(self, parent, reference):
- cliapp.AppException.__init__(
- self, 'Undefined chunk artifact "%s" referenced in '
- 'stratum %s' % (reference, parent))
-
class ArtifactResolver(object):
@@ -71,13 +58,11 @@ class ArtifactResolver(object):
'''
def __init__(self):
- self._cached_artifacts = None
self._added_artifacts = None
self._source_pool = None
def resolve_artifacts(self, source_pool):
self._source_pool = source_pool
- self._cached_artifacts = {}
self._added_artifacts = set()
artifacts = self._resolve_artifacts_recursively()
@@ -93,12 +78,13 @@ class ArtifactResolver(object):
source = queue.popleft()
if source.morphology['kind'] == 'system':
- systems = [self._get_artifact(source, a)
- for a in source.morphology.builds_artifacts]
+ systems = [source.artifacts[name]
+ for name in source.split_rules.artifacts]
- if any(a not in self._added_artifacts for a in systems):
- artifacts.extend(systems)
- self._added_artifacts.update(systems)
+ for system in (s for s in systems
+ if s not in self._added_artifacts):
+ artifacts.append(system)
+ self._added_artifacts.add(system)
resolved_artifacts = self._resolve_system_dependencies(
systems, source, queue)
@@ -108,28 +94,36 @@ class ArtifactResolver(object):
artifacts.append(artifact)
self._added_artifacts.add(artifact)
elif source.morphology['kind'] == 'stratum':
- assert len(source.morphology.builds_artifacts) == 1
- artifact = self._get_artifact(
- source, source.morphology.builds_artifacts[0])
-
- if not artifact in self._added_artifacts:
- artifacts.append(artifact)
- self._added_artifacts.add(artifact)
+ strata = [source.artifacts[name]
+ for name in source.split_rules.artifacts]
+
+ # If we were not given systems, return the strata here,
+ # rather than have the systems return them.
+ if not any(s.morphology['kind'] == 'system'
+ for s in self._source_pool):
+ for stratum in (s for s in strata
+ if s not in self._added_artifacts):
+ artifacts.append(stratum)
+ self._added_artifacts.add(stratum)
resolved_artifacts = self._resolve_stratum_dependencies(
- artifact, queue)
+ strata, source, queue)
for artifact in resolved_artifacts:
if not artifact in self._added_artifacts:
artifacts.append(artifact)
self._added_artifacts.add(artifact)
elif source.morphology['kind'] == 'chunk':
- names = source.morphology.builds_artifacts
- for name in names:
- artifact = self._get_artifact(source, name)
- if not artifact in self._added_artifacts:
- artifacts.append(artifact)
- self._added_artifacts.add(artifact)
+ chunks = [source.artifacts[name]
+ for name in source.split_rules.artifacts]
+ # If we were only given chunks, return them here, rather than
+ # have the strata return them.
+ if not any(s.morphology['kind'] == 'stratum'
+ for s in self._source_pool):
+ for chunk in (c for c in chunks
+ if c not in self._added_artifacts):
+ artifacts.append(chunk)
+ self._added_artifacts.add(chunk)
return artifacts
@@ -141,15 +135,6 @@ class ArtifactResolver(object):
if x.morphology['kind'] != 'chunk']
return collections.deque(sources)
- def _get_artifact(self, source, name):
- info = (source, name)
- if info in self._cached_artifacts:
- return self._cached_artifacts[info]
- else:
- artifact = morphlib.artifact.Artifact(info[0], info[1])
- self._cached_artifacts[info] = artifact
- return artifact
-
def _resolve_system_dependencies(self, systems, source, queue):
artifacts = []
@@ -158,67 +143,60 @@ class ArtifactResolver(object):
info['repo'] or source.repo_name,
info['ref'] or source.original_ref,
'%s.morph' % info['morph'])
+ stratum_name = stratum_source.morphology['name']
- stratum_name = stratum_source.morphology.builds_artifacts[0]
- stratum = self._get_artifact(stratum_source, stratum_name)
-
+ matches, overlaps, unmatched = source.split_rules.partition(
+ ((stratum_name, sta_name) for sta_name
+ in stratum_source.split_rules.artifacts))
for system in systems:
- system.add_dependency(stratum)
- queue.append(stratum_source)
+ for (stratum_name, sta_name) in matches[system.name]:
+ stratum = stratum_source.artifacts[sta_name]
+ system.add_dependency(stratum)
+ artifacts.append(stratum)
- artifacts.append(stratum)
+ queue.append(stratum_source)
return artifacts
- def _resolve_stratum_dependencies(self, stratum, queue):
+ def _resolve_stratum_dependencies(self, strata, source, queue):
artifacts = []
- strata = []
+ stratum_build_depends = []
- if stratum.source.morphology['build-depends']:
- for stratum_info in stratum.source.morphology['build-depends']:
- other_source = self._source_pool.lookup(
- stratum_info['repo'] or stratum.source.repo_name,
- stratum_info['ref'] or stratum.source.original_ref,
- '%s.morph' % stratum_info['morph'])
+ for stratum_info in source.morphology.get('build-depends') or []:
+ other_source = self._source_pool.lookup(
+ stratum_info['repo'] or source.repo_name,
+ stratum_info['ref'] or source.original_ref,
+ '%s.morph' % stratum_info['morph'])
- other_stratum = self._get_artifact(
- other_source, other_source.morphology.builds_artifacts[0])
+ # Make every stratum artifact this stratum source produces
+ # depend on every stratum artifact the other stratum source
+ # produces.
+ for sta_name in other_source.split_rules.artifacts:
+ other_stratum = other_source.artifacts[sta_name]
- strata.append(other_stratum)
+ stratum_build_depends.append(other_stratum)
artifacts.append(other_stratum)
- if other_stratum.depends_on(stratum):
- raise MutualDependencyError(stratum, other_stratum)
+ for stratum in strata:
+ if other_stratum.depends_on(stratum):
+ raise MutualDependencyError(stratum, other_stratum)
+
+ stratum.add_dependency(other_stratum)
- stratum.add_dependency(other_stratum)
- queue.append(other_source)
+ queue.append(other_source)
# 'name' here is the chunk artifact name
- chunk_artifacts = []
- processed_artifacts = []
- name_to_processed_artifact = {}
+ name_to_processed_artifacts = {}
- for info in stratum.source.morphology['chunks']:
+ for info in source.morphology['chunks']:
chunk_source = self._source_pool.lookup(
info['repo'],
info['ref'],
'%s.morph' % info['morph'])
- possible_names = chunk_source.morphology.builds_artifacts
- if not info['name'] in possible_names:
- raise UndefinedChunkArtifactError(stratum.source, info['name'])
-
- chunk_artifact = self._get_artifact(chunk_source, info['name'])
- chunk_artifacts.append(chunk_artifact)
-
- artifacts.append(chunk_artifact)
-
- stratum.add_dependency(chunk_artifact)
-
- for other_stratum in strata:
- chunk_artifact.add_dependency(other_stratum)
+ chunk_name = chunk_source.morphology['name']
# Resolve now to avoid a search for the parent morphology later
chunk_source.build_mode = info['build-mode']
@@ -226,23 +204,45 @@ class ArtifactResolver(object):
build_depends = info.get('build-depends', None)
- if build_depends is None:
- for earlier_artifact in processed_artifacts:
- if earlier_artifact.depends_on(chunk_artifact):
- raise MutualDependencyError(
- chunk_artifact, earlier_artifact)
- chunk_artifact.add_dependency(earlier_artifact)
- elif isinstance(build_depends, list):
+ for ca_name in chunk_source.split_rules.artifacts:
+ chunk_artifact = chunk_source.artifacts[ca_name]
+
+ # Add our stratum's build depends as dependencies of this chunk
+ for other_stratum in stratum_build_depends:
+ chunk_artifact.add_dependency(other_stratum)
+
+ # Add dependencies between chunks mentioned in this stratum
+ if isinstance(build_depends, list):
for name in build_depends:
- other_artifact = name_to_processed_artifact.get(name, None)
- if other_artifact:
- chunk_artifact.add_dependency(other_artifact)
- else:
+ if name not in name_to_processed_artifacts:
raise DependencyOrderError(
- stratum, info['name'], name)
+ source, info['name'], name)
+ other_artifacts = name_to_processed_artifacts[name]
+ for other_artifact in other_artifacts:
+ for ca_name in chunk_source.split_rules.artifacts:
+ chunk_artifact = chunk_source.artifacts[ca_name]
+ chunk_artifact.add_dependency(other_artifact)
else:
- raise DependencyFormatError(stratum, info['name'])
- processed_artifacts.append(chunk_artifact)
- name_to_processed_artifact[info['name']] = chunk_artifact
+ raise DependencyFormatError(source, info['name'])
+
+ # Add build dependencies between our stratum's artifacts
+ # and the chunk artifacts produced by this stratum.
+ matches, overlaps, unmatched = source.split_rules.partition(
+ ((chunk_name, ca_name) for ca_name
+ in chunk_source.split_rules.artifacts))
+ for stratum in strata:
+ for (chunk_name, ca_name) in matches[stratum.name]:
+ chunk_artifact = chunk_source.artifacts[ca_name]
+ stratum.add_dependency(chunk_artifact)
+ # Only return chunks required to build strata we need
+ if chunk_artifact not in artifacts:
+ artifacts.append(chunk_artifact)
+
+
+ # Add these chunks to the processed artifacts, so other
+ # chunks may refer to them.
+ name_to_processed_artifacts[info['name']] = \
+ [chunk_source.artifacts[n] for n
+ in chunk_source.split_rules.artifacts]
return artifacts