summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGreg Becker <becker33@llnl.gov>2019-07-19 20:08:05 -0500
committerTamara Dahlgren <35777542+tldahlgren@users.noreply.github.com>2019-07-19 18:08:05 -0700
commit4f9131fdc2ff2d9e6c62da15f82ce7384e70895b (patch)
tree124431c02894216297beb796aa4ff03d32684d41 /lib
parent4b6de7806218d4ee19ab5a40ed781a44032b80c7 (diff)
downloadspack-4f9131fdc2ff2d9e6c62da15f82ce7384e70895b.tar.gz
spack-4f9131fdc2ff2d9e6c62da15f82ce7384e70895b.tar.bz2
spack-4f9131fdc2ff2d9e6c62da15f82ce7384e70895b.tar.xz
spack-4f9131fdc2ff2d9e6c62da15f82ce7384e70895b.zip
Package inheritance: Find patch files defined in parent classes using MRO (#12051)
Fixes #8908, 11844 Use Python MRO to find patch files from parent classes.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/patch.py26
-rw-r--r--lib/spack/spack/test/packages.py6
-rw-r--r--lib/spack/spack/test/patch.py9
3 files changed, 40 insertions, 1 deletions
diff --git a/lib/spack/spack/patch.py b/lib/spack/spack/patch.py
index ef03c54f45..09aa48d9da 100644
--- a/lib/spack/spack/patch.py
+++ b/lib/spack/spack/patch.py
@@ -6,6 +6,7 @@
import hashlib
import os
import os.path
+import inspect
import llnl.util.filesystem
import llnl.util.lang
@@ -110,7 +111,30 @@ class FilePatch(Patch):
def __init__(self, pkg, relative_path, level, working_dir,
ordering_key=None):
self.relative_path = relative_path
- abs_path = os.path.join(pkg.package_dir, self.relative_path)
+
+ # patches may be defined by relative paths to parent classes
+ # search mro to look for the file
+ abs_path = None
+ # At different times we call FilePatch on instances and classes
+ pkg_cls = pkg if inspect.isclass(pkg) else pkg.__class__
+ for cls in inspect.getmro(pkg_cls):
+ if not hasattr(cls, 'module'):
+ # We've gone too far up the MRO
+ break
+
+ # Cannot use pkg.package_dir because it's a property and we have
+ # classes, not instances.
+ pkg_dir = os.path.abspath(os.path.dirname(cls.module.__file__))
+ path = os.path.join(pkg_dir, self.relative_path)
+ if os.path.exists(path):
+ abs_path = path
+ break
+
+ if abs_path is None:
+ msg = 'FilePatch: Patch file %s for ' % relative_path
+ msg += 'package %s.%s does not exist.' % (pkg.namespace, pkg.name)
+ raise ValueError(msg)
+
super(FilePatch, self).__init__(pkg, abs_path, level, working_dir)
self.path = abs_path
self._sha256 = None
diff --git a/lib/spack/spack/test/packages.py b/lib/spack/spack/test/packages.py
index 43f1719ca3..145c8fb2aa 100644
--- a/lib/spack/spack/test/packages.py
+++ b/lib/spack/spack/test/packages.py
@@ -123,6 +123,12 @@ class TestPackage(object):
assert '~openblas' in s
assert 'mpi' in s
+ @pytest.mark.regression('11844')
+ def test_inheritance_of_patches(self):
+ s = Spec('patch-inheritance')
+ # Will error if inheritor package cannot find inherited patch files
+ s.concretize()
+
def test_dependency_extensions(self):
s = Spec('extension2')
s.concretize()
diff --git a/lib/spack/spack/test/patch.py b/lib/spack/spack/test/patch.py
index 13a0233fb1..5ea3ba65bc 100644
--- a/lib/spack/spack/test/patch.py
+++ b/lib/spack/spack/test/patch.py
@@ -6,6 +6,7 @@
import os
import filecmp
import pytest
+import collections
from llnl.util.filesystem import working_dir, mkdirp
@@ -314,3 +315,11 @@ def test_write_and_read_sub_dags_with_patched_deps(mock_packages, config):
libelf, libdwarf, fake,
'builtin.mock.patch-several-dependencies',
spec.package.package_dir)
+
+
+def test_file_patch_no_file():
+ # Give it the attributes we need to construct the error message
+ FakePackage = collections.namedtuple('FakePackage', ['name', 'namespace'])
+ fp = FakePackage('fake-package', 'test')
+ with pytest.raises(ValueError, match=r'FilePatch:.*'):
+ spack.patch.FilePatch(fp, 'nonexistent_file', 0, '')