Add vendors directive
For the time being this directive prevents the vendored package to be in the same DAG as the one vendoring it.
This commit is contained in:
		
				
					committed by
					
						
						Todd Gamblin
					
				
			
			
				
	
			
			
			
						parent
						
							2da34de519
						
					
				
				
					commit
					1db73eb1f2
				
			@@ -69,6 +69,7 @@ class OpenMpi(Package):
 | 
			
		||||
    "resource",
 | 
			
		||||
    "build_system",
 | 
			
		||||
    "requires",
 | 
			
		||||
    "vendors",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
#: These are variant names used by Spack internally; packages can't use them
 | 
			
		||||
@@ -916,6 +917,29 @@ def _execute_requires(pkg):
 | 
			
		||||
    return _execute_requires
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@directive("vendors")
 | 
			
		||||
def vendors(spec, when=None):
 | 
			
		||||
    """Declares that a package has an internal copy of another package.
 | 
			
		||||
 | 
			
		||||
    Currently, the effect is to forbid having the two packages in the same
 | 
			
		||||
    "unification set".
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        spec: spec being vendored
 | 
			
		||||
        when: optional constraint that triggers vendoring
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def _execute_vendors(pkg):
 | 
			
		||||
        when_spec = make_when_spec(when)
 | 
			
		||||
        if not when_spec:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        when_spec_list = pkg.vendors.setdefault(spec, [])
 | 
			
		||||
        when_spec_list.append(when_spec)
 | 
			
		||||
 | 
			
		||||
    return _execute_vendors
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DirectiveError(spack.error.SpackError):
 | 
			
		||||
    """This is raised when something is wrong with a package directive."""
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1040,6 +1040,15 @@ def conflict_rules(self, pkg):
 | 
			
		||||
                )
 | 
			
		||||
                self.gen.newline()
 | 
			
		||||
 | 
			
		||||
    def vendor_rules(self, pkg):
 | 
			
		||||
        """Facts about vendored packages."""
 | 
			
		||||
        for vendored_spec_str, constraints in pkg.vendors.items():
 | 
			
		||||
            vendored_spec = spack.spec.Spec(vendored_spec_str)
 | 
			
		||||
            for constraint in constraints:
 | 
			
		||||
                constraint_id = self.condition(constraint, name=pkg.name)
 | 
			
		||||
                self.gen.fact(fn.pkg_fact(pkg.name, fn.vendors(constraint_id, vendored_spec.name)))
 | 
			
		||||
                self.gen.newline()
 | 
			
		||||
 | 
			
		||||
    def compiler_facts(self):
 | 
			
		||||
        """Facts about available compilers."""
 | 
			
		||||
 | 
			
		||||
@@ -1189,6 +1198,9 @@ def pkg_rules(self, pkg, tests):
 | 
			
		||||
        # conflicts
 | 
			
		||||
        self.conflict_rules(pkg)
 | 
			
		||||
 | 
			
		||||
        # vendoring
 | 
			
		||||
        self.vendor_rules(pkg)
 | 
			
		||||
 | 
			
		||||
        # default compilers for this package
 | 
			
		||||
        self.package_compiler_defaults(pkg)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -449,6 +449,16 @@ error(1, Msg)
 | 
			
		||||
     not external(node(ID, Package)),  % ignore conflicts for externals
 | 
			
		||||
     not attr("hash", node(ID, Package), _).  % ignore conflicts for installed packages
 | 
			
		||||
 | 
			
		||||
%-----------------------------------------------------------------------------
 | 
			
		||||
% Vendoring
 | 
			
		||||
%-----------------------------------------------------------------------------
 | 
			
		||||
error(1, "{0} vendors an internal copy of {1}, so it cannot be in the same unification set as {1}", Package, VendoredPackage)
 | 
			
		||||
  :- pkg_fact(Package, vendors(ConditionID, VendoredPackage)),
 | 
			
		||||
     attr("node", node(ID, Package)),
 | 
			
		||||
     condition_holds(ConditionID, node(ID, Package)),
 | 
			
		||||
     unification_set(X, node(ID, Package)),
 | 
			
		||||
     unification_set(X, node(_, VendoredPackage)).
 | 
			
		||||
 | 
			
		||||
%-----------------------------------------------------------------------------
 | 
			
		||||
% Virtual dependencies
 | 
			
		||||
%-----------------------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -551,3 +551,38 @@ def test_environment_config_scheme_used(tmp_path, unify_in_config):
 | 
			
		||||
    with spack.config.override("concretizer:unify", unify_in_config):
 | 
			
		||||
        with ev.Environment(manifest.parent) as e:
 | 
			
		||||
            assert e.unify == unify_in_config
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.parametrize(
 | 
			
		||||
    "spec_str,expected_raise,expected_spec",
 | 
			
		||||
    [
 | 
			
		||||
        # vendorsb vendors "b" only when @=1.1
 | 
			
		||||
        ("vendorsb", False, "vendorsb@=1.0"),
 | 
			
		||||
        ("vendorsb@=1.1", True, None),
 | 
			
		||||
    ],
 | 
			
		||||
)
 | 
			
		||||
def test_vendors_directive(
 | 
			
		||||
    spec_str, expected_raise, expected_spec, tmp_path, mock_packages, config
 | 
			
		||||
):
 | 
			
		||||
    """Tests that we cannot concretize two specs together, if one vendors the other."""
 | 
			
		||||
    if spack.config.get("config:concretizer") == "original":
 | 
			
		||||
        pytest.xfail("Known failure of the original concretizer")
 | 
			
		||||
 | 
			
		||||
    manifest = tmp_path / "spack.yaml"
 | 
			
		||||
    manifest.write_text(
 | 
			
		||||
        f"""\
 | 
			
		||||
spack:
 | 
			
		||||
  specs:
 | 
			
		||||
  - {spec_str}
 | 
			
		||||
  - b
 | 
			
		||||
  concretizer:
 | 
			
		||||
    unify: true
 | 
			
		||||
"""
 | 
			
		||||
    )
 | 
			
		||||
    with ev.Environment(manifest.parent) as e:
 | 
			
		||||
        if expected_raise:
 | 
			
		||||
            with pytest.raises(spack.solver.asp.UnsatisfiableSpecError):
 | 
			
		||||
                e.concretize()
 | 
			
		||||
        else:
 | 
			
		||||
            e.concretize()
 | 
			
		||||
            assert any(s.satisfies(expected_spec) for s in e.concrete_roots())
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								var/spack/repos/builtin.mock/packages/vendorsb/package.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								var/spack/repos/builtin.mock/packages/vendorsb/package.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
 | 
			
		||||
# Spack Project Developers. See the top-level COPYRIGHT file for details.
 | 
			
		||||
#
 | 
			
		||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
 | 
			
		||||
 | 
			
		||||
from spack.package import *
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Vendorsb(Package):
 | 
			
		||||
    """A package that vendors another"""
 | 
			
		||||
 | 
			
		||||
    homepage = "http://www.example.com"
 | 
			
		||||
    url = "http://www.example.com/b-1.0.tar.gz"
 | 
			
		||||
 | 
			
		||||
    version("1.1", md5="0123456789abcdef0123456789abcdef")
 | 
			
		||||
    version("1.0", md5="0123456789abcdef0123456789abcdef")
 | 
			
		||||
 | 
			
		||||
    vendors("b", when="@=1.1")
 | 
			
		||||
@@ -40,7 +40,7 @@ class Memkind(AutotoolsPackage):
 | 
			
		||||
 | 
			
		||||
    # memkind includes a copy of jemalloc; see
 | 
			
		||||
    # <https://github.com/memkind/memkind#jemalloc>.
 | 
			
		||||
    conflicts("jemalloc")
 | 
			
		||||
    vendors("jemalloc")
 | 
			
		||||
 | 
			
		||||
    # https://github.com/spack/spack/issues/37292
 | 
			
		||||
    parallel = False
 | 
			
		||||
 
 | 
			
		||||
@@ -94,9 +94,9 @@ class Palace(CMakePackage):
 | 
			
		||||
        depends_on("arpack-ng+shared", when="+shared")
 | 
			
		||||
        depends_on("arpack-ng~shared", when="~shared")
 | 
			
		||||
 | 
			
		||||
    # Conflicts: Palace always builds its own internal MFEM, GSLIB
 | 
			
		||||
    conflicts("^mfem", msg="Palace builds its own internal MFEM")
 | 
			
		||||
    conflicts("^gslib", msg="Palace builds its own internal GSLIB")
 | 
			
		||||
    # Palace always builds its own internal MFEM, GSLIB
 | 
			
		||||
    vendors("mfem")
 | 
			
		||||
    vendors("gslib")
 | 
			
		||||
 | 
			
		||||
    # More dependency variant conflicts
 | 
			
		||||
    conflicts("^hypre+int64", msg="Palace uses HYPRE's mixedint option for 64 bit integers")
 | 
			
		||||
 
 | 
			
		||||
@@ -70,8 +70,8 @@ class Scotch(CMakePackage, MakefilePackage):
 | 
			
		||||
 | 
			
		||||
    # Vendored dependency of METIS/ParMETIS conflicts with standard
 | 
			
		||||
    # installations
 | 
			
		||||
    conflicts("^metis", when="+metis")
 | 
			
		||||
    conflicts("^parmetis", when="+metis")
 | 
			
		||||
    vendors("metis", when="+metis")
 | 
			
		||||
    vendors("parmetis", when="+metis")
 | 
			
		||||
 | 
			
		||||
    parallel = False
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,9 +28,10 @@ class Votca(CMakePackage):
 | 
			
		||||
        "new-gmx", default=False, description="Build against gromacs>2019 - no tabulated kernels"
 | 
			
		||||
    )
 | 
			
		||||
    variant("xtp", default=True, description="Build xtp parts of votca")
 | 
			
		||||
    conflicts("votca-tools")
 | 
			
		||||
    conflicts("votca-csg")
 | 
			
		||||
    conflicts("votca-xtp")
 | 
			
		||||
 | 
			
		||||
    vendors("votca-tools")
 | 
			
		||||
    vendors("votca-csg")
 | 
			
		||||
    vendors("votca-xtp")
 | 
			
		||||
 | 
			
		||||
    depends_on("cmake@3.13:", type="build")
 | 
			
		||||
    depends_on("expat")
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user