Spec.satisfies accesses Spec.concrete as property (#2928)

* Spec.satisfies accesses Spec.concrete as property

Fixes #2760

When copying a spec, _concrete is always set to False for each
dependency. "Spec.satisfies" was accessing the member "_concrete"
directly instead of using the property "concrete". This means that
if you copy a spec, the dependencies will be considered equal, but
did not necessarily satisfy one another. Spec.satisfies is a
prerequisite for a package to be considered an extension; as a
consequence, an extension with run-time dependencies that were also
extensions did not activate those extensions. This updates
Spec.satisfies to avoid checking the cached member "_concrete"
directly.

* Added test to check for activation of dependency extension

* Added test to check for transitive satisfiability between a spec and its copy
This commit is contained in:
scheibelp 2017-01-25 20:43:12 -08:00 committed by Todd Gamblin
parent 596190c83c
commit e4d2d747ce
7 changed files with 143 additions and 6 deletions

View file

@ -1560,10 +1560,9 @@ def do_activate(self, force=False):
# Activate any package dependencies that are also extensions.
if not force:
for spec in self.spec.traverse(root=False, deptype='run'):
if spec.package.extends(self.extendee_spec):
if not spec.package.activated:
spec.package.do_activate(force=force)
for spec in self.dependency_activations():
if not spec.package.activated:
spec.package.do_activate(force=force)
self.extendee_spec.package.activate(self, **self.extendee_args)
@ -1571,6 +1570,10 @@ def do_activate(self, force=False):
tty.msg("Activated extension %s for %s" %
(self.spec.short_spec, self.extendee_spec.format("$_$@$+$%@")))
def dependency_activations(self):
return (spec for spec in self.spec.traverse(root=False, deptype='run')
if spec.package.extends(self.extendee_spec))
def activate(self, extension, **kwargs):
"""Symlinks all files from the extension into extendee's install dir.

View file

@ -2011,8 +2011,8 @@ def satisfies(self, other, deps=True, strict=False, strict_deps=False):
other = self._autospec(other)
# The only way to satisfy a concrete spec is to match its hash exactly.
if other._concrete:
return self._concrete and self.dag_hash() == other.dag_hash()
if other.concrete:
return self.concrete and self.dag_hash() == other.dag_hash()
# A concrete provider can satisfy a virtual dependency.
if not self.virtual and other.virtual:

View file

@ -108,6 +108,13 @@ def test_inheritance_of_diretives():
assert 'mpi' in s
def test_dependency_extensions():
s = Spec('extension2')
s.concretize()
deps = set(x.name for x in s.package.dependency_activations())
assert deps == set(['extension1'])
def test_import_class_from_package(builtin_mock):
from spack.pkg.builtin.mock.mpich import Mpich # noqa

View file

@ -287,6 +287,14 @@ def test_unsatisfiable_compiler_flag(self):
# 'mpich' is concrete:
check_unsatisfiable('mpich', 'mpich cppflags="-O3"', True)
def test_copy_satisfies_transitive(self):
spec = Spec('dttop')
spec.concretize()
copy = spec.copy()
for s in spec.traverse():
assert s.satisfies(copy[s.name])
assert copy[s.name].satisfies(s)
def test_unsatisfiable_compiler_flag_mismatch(self):
# No matchi in specs
check_unsatisfiable(

View file

@ -0,0 +1,39 @@
##############################################################################
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://github.com/llnl/spack
# Please also see the LICENSE file for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License (as
# published by the Free Software Foundation) version 2.1, February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *
class Extendee(Package):
"""A package with extensions"""
homepage = "http://www.example.com"
url = "http://www.example.com/extendee-1.0.tar.gz"
extendable = True
version('1.0', 'hash-extendee-1.0')
def install(self, spec, prefix):
pass

View file

@ -0,0 +1,39 @@
##############################################################################
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://github.com/llnl/spack
# Please also see the LICENSE file for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License (as
# published by the Free Software Foundation) version 2.1, February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *
class Extension1(Package):
"""A package which extends another package"""
homepage = "http://www.example.com"
url = "http://www.example.com/extension1-1.0.tar.gz"
extends('extendee')
version('1.0', 'hash-extension1-1.0')
def install(self, spec, prefix):
pass

View file

@ -0,0 +1,41 @@
##############################################################################
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://github.com/llnl/spack
# Please also see the LICENSE file for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License (as
# published by the Free Software Foundation) version 2.1, February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
from spack import *
class Extension2(Package):
"""A package which extends another package. It also depends on another
package which extends the same package."""
homepage = "http://www.example.com"
url = "http://www.example.com/extension2-1.0.tar.gz"
extends('extendee')
depends_on('extension1', type=('build', 'run'))
version('1.0', 'hash-extension2-1.0')
def install(self, spec, prefix):
pass