Repository: spack/spack

Issue:
spack find -L in non-empty environment fails
Trying to run `spack find -L` inside a non-empty environment (e.g.: with at least one root spec) triggers an error.

### Steps to reproduce the issue

```console
$ spack env create test
==> Created environment 'test' in /Users/fmontag/Documents/Hacking/spack/var/spack/environments/test
$ spack env activate test
$ spack find -L
==> In environment test
==> No root specs

==> 0 installed packages
$ spack add zlib
==> Adding zlib to environment test
$ spack find
==> In environment test
==> Root specs
zlib

==> 0 installed packages
$ spack find -L
==> In environment test
==> Root specs
==> Error: can't multiply sequence by non-int of type 'NoneType'
```

### Error Message

```console
$ spack --debug find -L
==> Reading config file /Users/fmontag/Documents/Hacking/spack/etc/spack/defaults/modules.yaml
==> Reading config file /Users/fmontag/Documents/Hacking/spack/etc/spack/defaults/darwin/modules.yaml
==> Reading config file /Users/fmontag/Documents/Hacking/spack/var/spack/environments/test/spack.yaml
==> Reading config file /Users/fmontag/Documents/Hacking/spack/etc/spack/defaults/config.yaml
==> Reading config file /Users/fmontag/.spack/config.yaml
==> DATABASE LOCK TIMEOUT: 120s
==> PACKAGE LOCK TIMEOUT: No timeout
==> READ LOCK: /Users/fmontag/Documents/Hacking/spack/opt/spack/.spack-db/lock[0:0] [Acquiring]
==> READ LOCK: /Users/fmontag/Documents/Hacking/spack/opt/spack/.spack-db/lock[0:0] [Acquired]
==> READ LOCK: /Users/fmontag/Documents/Hacking/spack/opt/spack/.spack-db/lock[0:0] [Released]
==> In environment test
==> Root specs
Traceback (most recent call last):
  File "/Users/fmontag/Documents/Hacking/spack/bin/spack", line 48, in <module>
    sys.exit(spack.main.main())
  File "/Users/fmontag/Documents/Hacking/spack/lib/spack/spack/main.py", line 669, in main
    return _invoke_command(command, parser, args, unknown)
  File "/Users/fmontag/Documents/Hacking/spack/lib/spack/spack/main.py", line 440, in _invoke_command
    return_val = command(parser, args)
  File "/Users/fmontag/Documents/Hacking/spack/lib/spack/spack/cmd/find.py", line 180, in find
    decorator=lambda s, f: color.colorize('@*{%s}' % f))
  File "/Users/fmontag/Documents/Hacking/spack/lib/spack/spack/cmd/__init__.py", line 317, in display_specs
    colify((fmt(s) for s in specs), indent=indent)
  File "/Users/fmontag/Documents/Hacking/spack/lib/spack/llnl/util/tty/colify.py", line 140, in colify
    elts = [text_type(elt) for elt in elts]
  File "/Users/fmontag/Documents/Hacking/spack/lib/spack/spack/cmd/__init__.py", line 317, in <genexpr>
    colify((fmt(s) for s in specs), indent=indent)
  File "/Users/fmontag/Documents/Hacking/spack/lib/spack/spack/cmd/__init__.py", line 310, in fmt
    string += gray_hash(s, hlen) + ' '
  File "/Users/fmontag/Documents/Hacking/spack/lib/spack/spack/cmd/__init__.py", line 178, in gray_hash
    h = spec.dag_hash(length) if spec.concrete else '-' * length
TypeError: can't multiply sequence by non-int of type 'NoneType'
```

### Information on your system

 1. macOSX 10.13
 2. using a fresh clone of spack @ `26e51ff17`



Discussion:
Do you know if it produces a different result if you find within an environment without activating?  I believe that would be something like `spack -e test find -L`


Resolving patch:
diff --git a/lib/spack/spack/cmd/__init__.py b/lib/spack/spack/cmd/__init__.py
--- a/lib/spack/spack/cmd/__init__.py
+++ b/lib/spack/spack/cmd/__init__.py
@@ -212,6 +212,9 @@ def disambiguate_spec(spec, env, local=False, installed=True):
 
 
 def gray_hash(spec, length):
+    if not length:
+        # default to maximum hash length
+        length = 32
     h = spec.dag_hash(length) if spec.concrete else '-' * length
     return colorize('@K{%s}' % h)
 
diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py
--- a/lib/spack/spack/cmd/find.py
+++ b/lib/spack/spack/cmd/find.py
@@ -4,6 +4,7 @@
 # SPDX-License-Identifier: (Apache-2.0 OR MIT)
 
 from __future__ import print_function
+import copy
 
 import llnl.util.tty as tty
 import llnl.util.tty.color as color
@@ -166,11 +167,16 @@ def display_env(env, args, decorator):
     else:
         tty.msg('Root specs')
 
+        # Root specs cannot be displayed with prefixes, since those are not
+        # set for abstract specs. Same for hashes
+        root_args = copy.copy(args)
+        root_args.paths = False
+
         # Roots are displayed with variants, etc. so that we can see
         # specifically what the user asked for.
         cmd.display_specs(
             env.user_specs,
-            args,
+            root_args,
             decorator=lambda s, f: color.colorize('@*{%s}' % f),
             namespace=True,
             show_flags=True,


Test patch:
diff --git a/lib/spack/spack/test/cmd/find.py b/lib/spack/spack/test/cmd/find.py
--- a/lib/spack/spack/test/cmd/find.py
+++ b/lib/spack/spack/test/cmd/find.py
@@ -12,9 +12,12 @@
 from spack.main import SpackCommand
 from spack.spec import Spec
 from spack.util.pattern import Bunch
+import spack.environment as ev
 
 
 find = SpackCommand('find')
+env = SpackCommand('env')
+install = SpackCommand('install')
 
 base32_alphabet = 'abcdefghijklmnopqrstuvwxyz234567'
 
@@ -302,3 +305,16 @@ def test_find_no_sections(database, config):
 def test_find_command_basic_usage(database):
     output = find()
     assert 'mpileaks' in output
+
+
+@pytest.mark.regression('9875')
+def test_find_prefix_in_env(mutable_mock_env_path, install_mockery, mock_fetch,
+                            mock_packages, mock_archive, config):
+    """Test `find` formats requiring concrete specs work in environments."""
+    env('create', 'test')
+    with ev.read('test'):
+        install('mpileaks')
+        find('-p')
+        find('-l')
+        find('-L')
+        # Would throw error on regression