Repository: spack/spack

Issue:
Pipelines failing if two specs have same dag hash, but different full hashes
### Steps to reproduce

The issue can be reproduce locally with this simple environment:
```yaml
spack:
  specs:
  - libpciaccess ^libtool@2.4.6
  - libpciaccess ^libtool@develop
```
which installs the same spec using two different build dependencies. This results in the two specs having:
- The same value for `dag_hash`
- Different values for `build_hash` and `full_hash`

The environment can be concretized correctly and produces a valid `spack.lock`:

<details>

<summary>$ spack concretize</summary>

```console
==> Concretized libpciaccess ^libtool@2.4.6
 -   hihk3pi  libpciaccess@0.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
 -   swnsnhf      ^libtool@2.4.6%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
 -   grd2nfx          ^m4@1.4.19%gcc@11.1.0+sigsegv arch=linux-ubuntu18.04-broadwell
[+]  oo46dbm              ^libsigsegv@2.13%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
[+]  o55dukk      ^pkgconf@1.8.0%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
[+]  gzatf2b      ^util-macros@1.19.3%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell

==> Concretized libpciaccess ^libtool@develop
 -   hihk3pi  libpciaccess@0.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
 -   7fvqcq5      ^libtool@develop%gcc@11.1.0 patches=055fdac32f7768c44f64dfc18c183233a7909ff8b7556f67038350eed2056571 arch=linux-ubuntu18.04-broadwell
 -   nw7erwd          ^autoconf@2.69%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
 -   grd2nfx              ^m4@1.4.19%gcc@11.1.0+sigsegv arch=linux-ubuntu18.04-broadwell
[+]  oo46dbm                  ^libsigsegv@2.13%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
 -   276j6k5              ^perl@5.34.0%gcc@11.1.0+cpanm+shared+threads arch=linux-ubuntu18.04-broadwell
[+]  zygezsz                  ^berkeley-db@18.1.40%gcc@11.1.0+cxx~docs+stl patches=b231fcc4d5cff05e5c3a4814f6a5af0e9a966428dc2176540d2c05aff41de522 arch=linux-ubuntu18.04-broadwell
 -   maxtuqi                  ^bzip2@1.0.8%gcc@11.1.0~debug~pic+shared arch=linux-ubuntu18.04-broadwell
 -   cxdoxv2                      ^diffutils@3.7%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
[+]  kju5v7i                          ^libiconv@1.16%gcc@11.1.0 libs=shared,static arch=linux-ubuntu18.04-broadwell
 -   fpjhmtn                  ^gdbm@1.19%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
 -   uycefnd                      ^readline@8.1%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
 -   6peormu                          ^ncurses@6.2%gcc@11.1.0~symlinks+termlib abi=none arch=linux-ubuntu18.04-broadwell
[+]  o55dukk                              ^pkgconf@1.8.0%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
[+]  5rs6nuu                  ^zlib@1.2.11%gcc@11.1.0+optimize+pic+shared arch=linux-ubuntu18.04-broadwell
 -   gvowywk          ^automake@1.16.3%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
 -   7fpysee          ^help2man@1.47.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
 -   s5tjkhg          ^texinfo@6.5%gcc@11.1.0 patches=12f6edb0c6b270b8c8dba2ce17998c580db01182d871ee32b7b6e4129bd1d23a,1732115f651cff98989cb0215d8f64da5e0f7911ebf0c13b064920f088f2ffe1 arch=linux-ubuntu18.04-broadwell
[+]  o7bfci5          ^xz@5.2.5%gcc@11.1.0~pic libs=shared,static arch=linux-ubuntu18.04-broadwell
[+]  gzatf2b      ^util-macros@1.19.3%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
```

</details>

It can also be installed correctly as a whole by:
```console
$ spack install
```
However, trying to install only part of it fails:
```console
$ spack install --no-add libpciaccess
==> Error: libpciaccess matches multiple specs in the environment /home/culpo/tmp/fullhash: 
Root spec libpciaccess ^libtool@2.4.6
  hihk3pi  libpciaccess@0.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
Root spec libpciaccess ^libtool@develop
  hihk3pi  libpciaccess@0.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
```
Not that **this also happens if we use a spec.yaml from a concrete spec** which is what we do in pipelines:
```console
$ spack install --no-add -f libpciaccess.yaml
==> Error: libpciaccess@0.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell ^libsigsegv@2.13%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell ^libtool@2.4.6%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell ^m4@1.4.19%gcc@11.1.0+sigsegv arch=linux-ubuntu18.04-broadwell ^pkgconf@1.8.0%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell ^util-macros@1.19.3%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell matches multiple specs in the environment /home/culpo/tmp/fullhash: 
Root spec libpciaccess ^libtool@2.4.6
  hihk3pi  libpciaccess@0.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
Root spec libpciaccess ^libtool@develop
  hihk3pi  libpciaccess@0.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
```

### Error message

```console
$ spack install --no-add -f libpciaccess.yaml
==> Error: libpciaccess@0.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell ^libsigsegv@2.13%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell ^libtool@2.4.6%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell ^m4@1.4.19%gcc@11.1.0+sigsegv arch=linux-ubuntu18.04-broadwell ^pkgconf@1.8.0%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell ^util-macros@1.19.3%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell matches multiple specs in the environment /home/culpo/tmp/fullhash: 
Root spec libpciaccess ^libtool@2.4.6
  hihk3pi  libpciaccess@0.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
Root spec libpciaccess ^libtool@develop
  hihk3pi  libpciaccess@0.16%gcc@11.1.0 arch=linux-ubuntu18.04-broadwell
```

### Information on your system

This should not be extremely relevant. The error was first spotted in pipelines, e.g. [here](https://gitlab.spack.io/spack/spack/-/jobs/659647) I reproduced it on:

* **Spack:** 0.16.2-4008-2971a630b8
* **Python:** 3.6.9
* **Platform:** linux-ubuntu18.04-broadwell
* **Concretizer:** original

Another thing to note is that _the issue happens also with the original concretizer_, but for some reason `clingo` is more likely to change build dependencies than the original concretizer.

### General information

- [X] I have run `spack debug report` and reported the version of Spack/Python/Platform
- [X] I have searched the issues of this repo and believe this is not a duplicate
- [X] I have run the failing commands in debug mode and reported the output


Discussion:
@scottwittenburg @tldahlgren @tgamblin @becker33 
These seem to be the relevant lines:

https://github.com/spack/spack/blob/2971a630b815fa88b71152787eca4ce2deb2dc7c/lib/spack/spack/environment.py#L1605-L1607

The condition `concretized_user_spec.satisfies(spec)` checks just the DAG hash if `spec` is concrete. We should probably special case the matching on concreteness of the argument.

Resolving patch:
diff --git a/lib/spack/spack/environment.py b/lib/spack/spack/environment.py
--- a/lib/spack/spack/environment.py
+++ b/lib/spack/spack/environment.py
@@ -1602,7 +1602,22 @@ def matching_spec(self, spec):
         # Dependency-only specs will have value None
         matches = {}
 
+        if not isinstance(spec, spack.spec.Spec):
+            spec = spack.spec.Spec(spec)
+
         for user_spec, concretized_user_spec in self.concretized_specs():
+            # Deal with concrete specs differently
+            if spec.concrete:
+                # Matching a concrete spec is more restrictive
+                # than just matching the dag hash
+                is_match = (
+                    spec in concretized_user_spec and
+                    concretized_user_spec[spec.name].build_hash() == spec.build_hash()
+                )
+                if is_match:
+                    matches[spec] = spec
+                continue
+
             if concretized_user_spec.satisfies(spec):
                 matches[concretized_user_spec] = user_spec
             for dep_spec in concretized_user_spec.traverse(root=False):


Test patch: