Repository: spack/spack

Issue:
Add ability to toggle default state of Buildable
Add ability to change the default state of Buildable to False instead of True.

### Rationale

Unless you are careful and lock down your dependencies, Spack builds far too many packages (perl, tar, etc).  Users who are unfamiliar with the problem often waste hours thinking that a 2 hour library build is normal when it should be < 10 minutes. It would be nice to be able to provide a list of packages I want Spack to build instead of the opposite which is turning off the ones I don't want it to build.

### Description

```
packages:
   all:
    buildable: False
  axom:
    buildable: True
  conduit:
    buildable: True

```






Discussion:

Resolving patch:
diff --git a/lib/spack/spack/package_prefs.py b/lib/spack/spack/package_prefs.py
--- a/lib/spack/spack/package_prefs.py
+++ b/lib/spack/spack/package_prefs.py
@@ -190,11 +190,17 @@ def spec_externals(spec):
 
 def is_spec_buildable(spec):
     """Return true if the spec pkgspec is configured as buildable"""
+
     allpkgs = spack.config.get('packages')
-    do_not_build = [name for name, entry in allpkgs.items()
-                    if not entry.get('buildable', True)]
-    return not (spec.name in do_not_build or
-                any(spec.package.provides(name) for name in do_not_build))
+    all_buildable = allpkgs.get('all', {}).get('buildable', True)
+
+    # Get the list of names for which all_buildable is overridden
+    reverse = [name for name, entry in allpkgs.items()
+               if entry.get('buildable', all_buildable) != all_buildable]
+    # Does this spec override all_buildable
+    spec_reversed = (spec.name in reverse or
+                     any(spec.package.provides(name) for name in reverse))
+    return not all_buildable if spec_reversed else all_buildable
 
 
 def get_package_dir_permissions(spec):


Test patch:
diff --git a/lib/spack/spack/test/concretize_preferences.py b/lib/spack/spack/test/concretize_preferences.py
--- a/lib/spack/spack/test/concretize_preferences.py
+++ b/lib/spack/spack/test/concretize_preferences.py
@@ -239,6 +239,70 @@ def mock_module(cmd, module):
         spec.concretize()
         assert spec['mpich'].external_path == '/dummy/path'
 
+    def test_buildable_false(self):
+        conf = syaml.load_config("""\
+libelf:
+  buildable: false
+""")
+        spack.config.set('packages', conf, scope='concretize')
+        spec = Spec('libelf')
+        assert not spack.package_prefs.is_spec_buildable(spec)
+
+        spec = Spec('mpich')
+        assert spack.package_prefs.is_spec_buildable(spec)
+
+    def test_buildable_false_virtual(self):
+        conf = syaml.load_config("""\
+mpi:
+  buildable: false
+""")
+        spack.config.set('packages', conf, scope='concretize')
+        spec = Spec('libelf')
+        assert spack.package_prefs.is_spec_buildable(spec)
+
+        spec = Spec('mpich')
+        assert not spack.package_prefs.is_spec_buildable(spec)
+
+    def test_buildable_false_all(self):
+        conf = syaml.load_config("""\
+all:
+  buildable: false
+""")
+        spack.config.set('packages', conf, scope='concretize')
+        spec = Spec('libelf')
+        assert not spack.package_prefs.is_spec_buildable(spec)
+
+        spec = Spec('mpich')
+        assert not spack.package_prefs.is_spec_buildable(spec)
+
+    def test_buildable_false_all_true_package(self):
+        conf = syaml.load_config("""\
+all:
+  buildable: false
+libelf:
+  buildable: true
+""")
+        spack.config.set('packages', conf, scope='concretize')
+        spec = Spec('libelf')
+        assert spack.package_prefs.is_spec_buildable(spec)
+
+        spec = Spec('mpich')
+        assert not spack.package_prefs.is_spec_buildable(spec)
+
+    def test_buildable_false_all_true_virtual(self):
+        conf = syaml.load_config("""\
+all:
+  buildable: false
+mpi:
+  buildable: true
+""")
+        spack.config.set('packages', conf, scope='concretize')
+        spec = Spec('libelf')
+        assert not spack.package_prefs.is_spec_buildable(spec)
+
+        spec = Spec('mpich')
+        assert spack.package_prefs.is_spec_buildable(spec)
+
     def test_config_permissions_from_all(self, configure_permissions):
         # Although these aren't strictly about concretization, they are
         # configured in the same file and therefore convenient to test here.