Repository: spack/spack

Issue:
"spack reindex" fails
Installing `git` failed (some `libintl` problem). Trying to install it again failed with the usual `no such spec in database` error:

```
$ spack install -v julia
==> Installing julia
==> Installing git
==> pcre is already installed in /xfs1/eschnetter/src/spack/opt/spack/linux-Ubuntu14-x86_64/gcc-6.1.1/pcre-8.39-2rfd5ubv7lwztbdm4khcqkclvcontzie
Traceback (most recent call last):
  File "/xfs1/eschnetter/src/spack/bin/spack", line 192, in <module>
    main()
  File "/xfs1/eschnetter/src/spack/bin/spack", line 169, in main
    return_val = command(parser, args)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/cmd/install.py", line 92, in install
    explicit=True)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/package.py", line 916, in do_install
    run_tests=run_tests)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/package.py", line 1066, in do_install_dependencies
    dep.package.do_install(**kwargs)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/package.py", line 916, in do_install
    run_tests=run_tests)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/package.py", line 1066, in do_install_dependencies
    dep.package.do_install(**kwargs)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/package.py", line 898, in do_install
    rec = spack.installed_db.get_record(self.spec)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/database.py", line 75, in converter
    return function(self, spec_like, *args, **kwargs)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/database.py", line 521, in get_record
    key = self._get_matching_spec_key(spec, **kwargs)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/database.py", line 516, in _get_matching_spec_key
    raise KeyError("No such spec in database! %s" % spec)
KeyError: 'No such spec in database! pcre@8.39%gcc@6.1.1+utf arch=linux-Ubuntu14-x86_64'
```

That error usually goes away after a `spack reindex`. However:

```
$ spack reindex
Traceback (most recent call last):
  File "/xfs1/eschnetter/src/spack/bin/spack", line 192, in <module>
    main()
  File "/xfs1/eschnetter/src/spack/bin/spack", line 169, in main
    return_val = command(parser, args)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/cmd/reindex.py", line 31, in reindex
    spack.installed_db.reindex(spack.install_layout)
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/database.py", line 375, in reindex
    self._check_ref_counts()
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/database.py", line 396, in _check_ref_counts
    dep_key = dep.dag_hash()
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/spec.py", line 911, in dag_hash
    if self.concrete:
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/spec.py", line 756, in concrete
    self.variants.concrete and
  File "/xfs1/eschnetter/src/spack/lib/spack/spack/spec.py", line 381, in concrete
    v in self for v in self.spec.package_class.variants)
AttributeError: type object 'Zlib' has no attribute 'variants'
```

That's a new error; I see this for the first time today.



Discussion:
This problem is reproducible; it just happened on another machine as well:

```
$ spack install -v julia
==> Installing julia
==> git is already installed in /home/eschnett/src/spack/opt/spack/linux-centos7-x86_64/gcc-6.1.0-spack/git-2.9.3-kgah4b5gurqx2rswlt44xoinshfw7doi
Traceback (most recent call last):
  File "/home/eschnett/src/spack/bin/spack", line 192, in <module>
    main()
  File "/home/eschnett/src/spack/bin/spack", line 169, in main
    return_val = command(parser, args)
  File "/home/eschnett/src/spack/lib/spack/spack/cmd/install.py", line 92, in install
    explicit=True)
  File "/home/eschnett/src/spack/lib/spack/spack/package.py", line 916, in do_install
    run_tests=run_tests)
  File "/home/eschnett/src/spack/lib/spack/spack/package.py", line 1066, in do_install_dependencies
    dep.package.do_install(**kwargs)
  File "/home/eschnett/src/spack/lib/spack/spack/package.py", line 898, in do_install
    rec = spack.installed_db.get_record(self.spec)
  File "/home/eschnett/src/spack/lib/spack/spack/database.py", line 75, in converter
    return function(self, spec_like, *args, **kwargs)
  File "/home/eschnett/src/spack/lib/spack/spack/database.py", line 521, in get_record
    key = self._get_matching_spec_key(spec, **kwargs)
  File "/home/eschnett/src/spack/lib/spack/spack/database.py", line 516, in _get_matching_spec_key
    raise KeyError("No such spec in database! %s" % spec)
KeyError: 'No such spec in database! git@2.9.3%gcc@6.1.0-spack arch=linux-centos7-x86_64^autoconf@2.69%gcc@6.1.0-spack arch=linux-centos7-x86_64^bzip2@1.0.6%gcc@6.1.0-spack arch=linux-centos7-x86_64^curl@7.50.1%gcc@6.1.0-spack arch=linux-centos7-x86_64^expat@2.2.0%gcc@6.1.0-spack arch=linux-centos7-x86_64^gettext@0.19.8.1%gcc@6.1.0-spack+bzip2+curses+git~libunistring+libxml2+tar+xz arch=linux-centos7-x86_64^libsigsegv@2.10%gcc@6.1.0-spack arch=linux-centos7-x86_64^libxml2@2.9.4%gcc@6.1.0-spack~python arch=linux-centos7-x86_64^m4@1.4.17%gcc@6.1.0-spack+sigsegv arch=linux-centos7-x86_64^ncurses@6.0%gcc@6.1.0-spack arch=linux-centos7-x86_64^openssl@1.0.2h%gcc@6.1.0-spack arch=linux-centos7-x86_64^pcre@8.39%gcc@6.1.0-spack+utf arch=linux-centos7-x86_64^perl@5.24.0%gcc@6.1.0-spack+cpanm arch=linux-centos7-x86_64^tar@1.29%gcc@6.1.0-spack arch=linux-centos7-x86_64^xz@5.2.2%gcc@6.1.0-spack arch=linux-centos7-x86_64^zlib@1.2.8%gcc@6.1.0-spack arch=linux-centos7-x86_64'
eschnett@bethe:~/src/spack (08:07:37)
$ spack reindex
Traceback (most recent call last):
  File "/home/eschnett/src/spack/bin/spack", line 192, in <module>
    main()
  File "/home/eschnett/src/spack/bin/spack", line 169, in main
    return_val = command(parser, args)
  File "/home/eschnett/src/spack/lib/spack/spack/cmd/reindex.py", line 31, in reindex
    spack.installed_db.reindex(spack.install_layout)
  File "/home/eschnett/src/spack/lib/spack/spack/database.py", line 375, in reindex
    self._check_ref_counts()
  File "/home/eschnett/src/spack/lib/spack/spack/database.py", line 396, in _check_ref_counts
    dep_key = dep.dag_hash()
  File "/home/eschnett/src/spack/lib/spack/spack/spec.py", line 911, in dag_hash
    if self.concrete:
  File "/home/eschnett/src/spack/lib/spack/spack/spec.py", line 756, in concrete
    self.variants.concrete and
  File "/home/eschnett/src/spack/lib/spack/spack/spec.py", line 381, in concrete
    v in self for v in self.spec.package_class.variants)
AttributeError: type object 'Zlib' has no attribute 'variants'
```

Ditto. I've just started from scratch with lightly modified (packages only) branch based on `417fe0e`. I hit that same error

``` bash
spack/bin$ ./spack reindex
Traceback (most recent call last):
  File "./spack", line 192, in <module>
    main()
  File "./spack", line 169, in main
    return_val = command(parser, args)
  File "/Users/jp/Programs/GitHub/Spack/spack/lib/spack/spack/cmd/reindex.py", line 31, in reindex
    spack.installed_db.reindex(spack.install_layout)
  File "/Users/jp/Programs/GitHub/Spack/spack/lib/spack/spack/database.py", line 375, in reindex
    self._check_ref_counts()
  File "/Users/jp/Programs/GitHub/Spack/spack/lib/spack/spack/database.py", line 396, in _check_ref_counts
    dep_key = dep.dag_hash()
  File "/Users/jp/Programs/GitHub/Spack/spack/lib/spack/spack/spec.py", line 911, in dag_hash
    if self.concrete:
  File "/Users/jp/Programs/GitHub/Spack/spack/lib/spack/spack/spec.py", line 756, in concrete
    self.variants.concrete and
  File "/Users/jp/Programs/GitHub/Spack/spack/lib/spack/spack/spec.py", line 381, in concrete
    v in self for v in self.spec.package_class.variants)
AttributeError: type object 'Zlib' has no attribute 'variants
```

with only a few packages installed

``` bash
spack/bin$ spack find
==> 10 installed packages.
-- darwin-elcapitan-x86_64 / clang@7.3.0-apple ------------------
environment-modules@3.2.10  gcc@6.2.0  gmp@6.1.1  isl@0.14  libsigsegv@2.10  m4@1.4.17  mpc@1.0.3  mpfr@3.1.4  tcl@8.6.5  zlib@1.2.8
```

There is also strange results from some of the other basic functionality. I'm presuming the two points are related?

``` bash
spack/bin$ ./spack location -i environment-modules
==> Error: environment-modules matches multiple packages.
  Matching packages:
    environment-modules@3.2.10%clang@7.3.0-apple arch=darwin-elcapitan-x86_64^tcl@8.6.5%clang@7.3.0-apple arch=darwin-elcapitan-x86_64^zlib@1.2.8%clang@7.3.0-apple arch=darwin-elcapitan-x86_64
    environment-modules@3.2.10%clang@7.3.0-apple arch=darwin-elcapitan-x86_64^tcl@8.6.5%clang@7.3.0-apple arch=darwin-elcapitan-x86_64^zlib@1.2.8%clang@7.3.0-apple arch=darwin-elcapitan-x86_64
  Use a more specific spec.
```

Just a "me too".  I have no idea what the offending line is supposed to do, and maybe this makes things worse but this quells the error:

``` diff
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 8b0486c..fd40bf8 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -378,7 +378,7 @@ class VariantMap(HashableMap):
     @property
     def concrete(self):
         return self.spec._concrete or all(
-            v in self for v in self.spec.package_class.variants)
+            v in self for v in getattr(self.spec.package_class,'variants',[]))

     def copy(self):
         clone = VariantMap(None)
```


Resolving patch:
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -329,6 +329,12 @@ class SomePackage(Package):
     """
     sanity_check_is_dir = []
 
+    class __metaclass__(type):
+        """Ensure  attributes required by Spack directives are present."""
+        def __init__(cls, name, bases, dict):
+            type.__init__(cls, name, bases, dict)
+            spack.directives.ensure_dicts(cls)
+
     def __init__(self, spec):
         # this determines how the package should be built.
         self.spec = spec
@@ -342,9 +348,6 @@ def __init__(self, spec):
         # Allow custom staging paths for packages
         self.path = None
 
-        # Sanity check attributes required by Spack directives.
-        spack.directives.ensure_dicts(type(self))
-
         # Check versions in the versions dict.
         for v in self.versions:
             assert (isinstance(v, Version))


Test patch: