Repository: spack/spack

Issue:
pkg-config is broken on a fresh Ubuntu
subj
```
==> Error: NoSuchMethodError: Package PkgConfig does not support setup_dependent_environment called with pkg-config arch=cray-None-None.  Options are: pkg-config arch=cray-None-None
/home/denis/spack/lib/spack/spack/build_environment.py:567, in child_execution:
     547      def child_execution(child_connection, input_stream):
     548          try:
     549              setup_package(pkg, dirty=dirty)
     550              function(input_stream)
     551              child_connection.send(None)
     552          except StopIteration as e:
     553              # StopIteration is used to stop installations
     554              # before the final stage, mainly for debug purposes
     555              tty.msg(e.message)
     556              child_connection.send(None)
     557          except:
     558              # catch ANYTHING that goes wrong in the child process
     559              exc_type, exc, tb = sys.exc_info()
     560  
     561              # Need to unwind the traceback in the child because traceback
     562              # objects can't be sent to the parent.
     563              tb_string = traceback.format_exc()
     564  
     565              # build up some context from the offending package so we can
     566              # show that, too.
  >> 567              package_context = get_package_context(tb)
     568  
     569              build_log = None
     570              if hasattr(pkg, 'log_path'):
     571                  build_log = pkg.log_path
     572  
     573              # make a pickleable exception to send to parent.
     574              msg = "%s: %s" % (str(exc_type.__name__), str(exc))
     575  
     576              ce = ChildError(msg, tb_string, build_log, package_context)
     577              child_connection.send(ce)
     578  
     579          finally:
     580              child_connection.close()

```


Discussion:

Resolving patch:
diff --git a/lib/spack/spack/multimethod.py b/lib/spack/spack/multimethod.py
--- a/lib/spack/spack/multimethod.py
+++ b/lib/spack/spack/multimethod.py
@@ -128,10 +128,16 @@ def __call__(self, package_self, *args, **kwargs):
 
         if self.default:
             return self.default(package_self, *args, **kwargs)
+
         else:
-            raise NoSuchMethodError(
-                type(package_self), self.__name__, spec,
-                [m[0] for m in self.method_list])
+            superclass = super(package_self.__class__, package_self)
+            superclass_fn = getattr(superclass, self.__name__, None)
+            if callable(superclass_fn):
+                return superclass_fn(*args, **kwargs)
+            else:
+                raise NoSuchMethodError(
+                    type(package_self), self.__name__, spec,
+                    [m[0] for m in self.method_list])
 
     def __str__(self):
         return "SpecMultiMethod {\n\tdefault: %s,\n\tspecs: %s\n}" % (
diff --git a/var/spack/repos/builtin.mock/packages/multimethod-base/package.py b/var/spack/repos/builtin.mock/packages/multimethod-base/package.py
new file mode 100644
--- /dev/null
+++ b/var/spack/repos/builtin.mock/packages/multimethod-base/package.py
@@ -0,0 +1,40 @@
+##############################################################################
+# Copyright (c) 2013-2017, 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 MultimethodBase(Package):
+    """This is a base class for the Multimethod test case.
+
+    It tests whether mutlimethod properly invokes methods in a base
+    class when subclass multi-methods do not match.
+
+    """
+
+    homepage = 'http://www.example.com/'
+    url      = 'http://www.example.com/example-1.0.tar.gz'
+
+    def base_method(self):
+        return "base_method"
diff --git a/var/spack/repos/builtin.mock/packages/multimethod/package.py b/var/spack/repos/builtin.mock/packages/multimethod/package.py
--- a/var/spack/repos/builtin.mock/packages/multimethod/package.py
+++ b/var/spack/repos/builtin.mock/packages/multimethod/package.py
@@ -25,8 +25,10 @@
 from spack import *
 import spack.architecture
 
+from spack.pkg.builtin.mock.multimethod_base import MultimethodBase
 
-class Multimethod(Package):
+
+class Multimethod(MultimethodBase):
     """This package is designed for use with Spack's multimethod test.
        It has a bunch of test cases for the @when decorator that the
        test uses.
@@ -132,3 +134,11 @@ def different_by_virtual_dep(self):
     @when('^mpi@2:')
     def different_by_virtual_dep(self):
         return 2
+
+    #
+    # Make sure methods with a default implementation in a superclass
+    # will invoke that method when none in the subclass match.
+    #
+    @when("@2:")
+    def base_method(self):
+        return "subclass_method"


Test patch:
diff --git a/lib/spack/spack/test/multimethod.py b/lib/spack/spack/test/multimethod.py
--- a/lib/spack/spack/test/multimethod.py
+++ b/lib/spack/spack/test/multimethod.py
@@ -118,3 +118,11 @@ def test_virtual_dep_match(builtin_mock):
 
     pkg = spack.repo.get('multimethod^mpich@1.0')
     assert pkg.different_by_virtual_dep() == 1
+
+
+def test_multimethod_with_base_class(builtin_mock):
+    pkg = spack.repo.get('multimethod@3')
+    assert pkg.base_method() == "subclass_method"
+
+    pkg = spack.repo.get('multimethod@1')
+    assert pkg.base_method() == "base_method"