Source code for spack.solver.splicing

# Copyright Spack Project Developers. See COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
from functools import cmp_to_key
from typing import Dict, List, NamedTuple

import spack.deptypes as dt
from spack.spec import Spec
from spack.traverse import by_dag_hash, traverse_nodes


[docs] class Splice(NamedTuple): #: The spec being spliced into a parent splice_spec: Spec #: The name of the child that splice spec is replacing child_name: str #: The hash of the child that `splice_spec` is replacing child_hash: str
def _resolve_collected_splices( specs: List[Spec], splices: Dict[Spec, List[Splice]] ) -> Dict[Spec, Spec]: """After all of the specs have been concretized, apply all immediate splices. Returns a dict mapping original specs to their resolved counterparts """ def splice_cmp(s1: Spec, s2: Spec): """This function can be used to sort a list of specs such that that any spec which will be spliced into a parent comes after the parent it will be spliced into. This order ensures that transitive splices will be executed in the correct order. """ s1_splices = splices.get(s1, []) s2_splices = splices.get(s2, []) if any([s2.dag_hash() == splice.splice_spec.dag_hash() for splice in s1_splices]): return -1 elif any([s1.dag_hash() == splice.splice_spec.dag_hash() for splice in s2_splices]): return 1 else: return 0 splice_order = sorted(specs, key=cmp_to_key(splice_cmp)) reverse_topo_order = reversed( [x for x in traverse_nodes(splice_order, order="topo", key=by_dag_hash) if x in specs] ) already_resolved: Dict[Spec, Spec] = {} for spec in reverse_topo_order: immediate = splices.get(spec, []) if not immediate and not any( edge.spec in already_resolved for edge in spec.edges_to_dependencies() ): continue new_spec = spec.copy(deps=False) new_spec.clear_caches(ignore=("package_hash",)) new_spec.build_spec = spec for edge in spec.edges_to_dependencies(): depflag = edge.depflag & ~dt.BUILD if any(edge.spec.dag_hash() == splice.child_hash for splice in immediate): splice = [s for s in immediate if s.child_hash == edge.spec.dag_hash()][0] # If the spec being splice in is also spliced splice_spec = already_resolved.get(splice.splice_spec, splice.splice_spec) new_spec.add_dependency_edge(splice_spec, depflag=depflag, virtuals=edge.virtuals) elif edge.spec in already_resolved: new_spec.add_dependency_edge( already_resolved[edge.spec], depflag=depflag, virtuals=edge.virtuals ) else: new_spec.add_dependency_edge(edge.spec, depflag=depflag, virtuals=edge.virtuals) already_resolved[spec] = new_spec return already_resolved