extensions: allow multiple "extends" directives (#28853)
* extensions: allow multiple "extends" directives This will allow multiple extends directives in a package as long as only one of them is selected as a dependency in the concrete spec. * document the option to have multiple extends
This commit is contained in:
		@@ -2470,6 +2470,24 @@ Now, the ``py-numpy`` package can be used as an argument to ``spack
 | 
			
		||||
activate``.  When it is activated, all the files in its prefix will be
 | 
			
		||||
symbolically linked into the prefix of the python package.
 | 
			
		||||
 | 
			
		||||
A package can only extend one other package at a time.  To support packages
 | 
			
		||||
that may extend one of a list of other packages, Spack supports multiple
 | 
			
		||||
``extends`` directives as long as at most one of them is selected as
 | 
			
		||||
a dependency during concretization.  For example, a lua package could extend
 | 
			
		||||
either lua or luajit, but not both:
 | 
			
		||||
 | 
			
		||||
.. code-block:: python
 | 
			
		||||
 | 
			
		||||
   class LuaLpeg(Package):
 | 
			
		||||
       ...
 | 
			
		||||
       variant('use_lua', default=True)
 | 
			
		||||
       extends('lua', when='+use_lua')
 | 
			
		||||
       extends('lua-luajit', when='~use_lua')
 | 
			
		||||
       ...
 | 
			
		||||
 | 
			
		||||
Now, a user can install, and activate, the ``lua-lpeg`` package for either
 | 
			
		||||
lua or luajit.
 | 
			
		||||
 | 
			
		||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
Adding additional constraints
 | 
			
		||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
 
 | 
			
		||||
@@ -1186,22 +1186,27 @@ def extendee_spec(self):
 | 
			
		||||
        if not self.extendees:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        # TODO: allow more than one extendee.
 | 
			
		||||
        name = next(iter(self.extendees))
 | 
			
		||||
        deps = []
 | 
			
		||||
 | 
			
		||||
        # If the extendee is in the spec's deps already, return that.
 | 
			
		||||
        for dep in self.spec.traverse(deptypes=('link', 'run')):
 | 
			
		||||
            if name == dep.name:
 | 
			
		||||
                return dep
 | 
			
		||||
            if dep.name in self.extendees:
 | 
			
		||||
                deps.append(dep)
 | 
			
		||||
 | 
			
		||||
        # TODO: allow more than one active extendee.
 | 
			
		||||
        if deps:
 | 
			
		||||
            assert len(deps) == 1
 | 
			
		||||
            return deps[0]
 | 
			
		||||
 | 
			
		||||
        # if the spec is concrete already, then it extends something
 | 
			
		||||
        # that is an *optional* dependency, and the dep isn't there.
 | 
			
		||||
        if self.spec._concrete:
 | 
			
		||||
            return None
 | 
			
		||||
        else:
 | 
			
		||||
            # TODO: do something sane here with more than one extendee
 | 
			
		||||
            # If it's not concrete, then return the spec from the
 | 
			
		||||
            # extends() directive since that is all we know so far.
 | 
			
		||||
            spec, kwargs = self.extendees[name]
 | 
			
		||||
            spec, kwargs = next(iter(self.extendees.items()))
 | 
			
		||||
            return spec
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user