Repository: spack/spack

Issue:
External package setup via modules not working?
Please let me know if I am using this feature incorrectly and how to go about debugging the error below.

I would like to use an externally provided installation of cmake when building metis. I edited `packages.yaml` to register cmake by using the `modules` syntax:

```
packages:
  cmake:
    version: [3.9.0]
    modules:
      cmake@3.9.0: cmake/3.9.0
    buildable: False
```

Spack sees the external package for cmake and parses the yaml file without error:

```
% spack spec metis
...
Concretized
--------------------------------
metis@5.1.0%intel@17.0.1~debug~gdb~int64~real64+shared arch=linux-rhel7-x86_64 
    ^cmake@3.9.0%intel@17.0.1~doc+ncurses+openssl+ownlibs~qt arch=linux-rhel7-x86_64 
```

But when I try to install `metis`, spack crashes with this cryptic error:

```
% spack install metis
==> cmake@3.9.0 : has external module in cmake/3.9.0
==> cmake@3.9.0 : is actually installed in None
==> cmake@3.9.0 : generating module file
==> Error: 'NoneType' object has no attribute 'startswith'
```

Am I using the `modules:` section incorrectly? How do I go about debugging this error?

FWIW - the `cmake/3.9.0` module is available and cmake exists at the path listed.

```
% module show cmake/3.9.0
-------------------------------------------------------------------------------------------------------------------------------------------------
   /usr/projects/hpcsoft/toss3/modulefiles/snow/friendly-testing/cmake/3.9.0:
-------------------------------------------------------------------------------------------------------------------------------------------------
conflict("cmake")
whatis("CMAKE 3.9.0 ")
setenv("_MODULES_CMAKE","cmake/3.9.0")
setenv("CMAKE_DIR","/usr/projects/hpcsoft/toss3/common/cmake/3.9.0")
prepend_path("PATH","/usr/projects/hpcsoft/toss3/common/cmake/3.9.0/bin")
help([[ CMAKE 3.9.0
]])
```




Discussion:
@KineticTheory, when you specify an external package with a module, spack parses the modulefile and tries to find out where the package is actually installed. The function that implements the logic is called get_path_from_module. You can find it in ./lib/spack/spack/util/module_cmd.py. As you can see it checks for the value of LD_LIBRARY_PATH but, to my surprise, it does not check the value of PATH. Thus, it can't find where your external cmake is actually installed and fails.

Yeah, we definitely should improve interaction with external packages.
@skosukhin I tested your suggestion.  It works.  I will submit a PR to fix this.

Resolving patch:
diff --git a/lib/spack/spack/util/module_cmd.py b/lib/spack/spack/util/module_cmd.py
--- a/lib/spack/spack/util/module_cmd.py
+++ b/lib/spack/spack/util/module_cmd.py
@@ -187,6 +187,12 @@ def get_path_from_module(mod):
         if L >= 0:
             return line[L + 2:line.find('/lib')]
 
+    # If it sets the PATH, use it
+    for line in text:
+        if line.find('PATH') >= 0:
+            path = get_argument_from_module_line(line)
+            return path[:path.find('/bin')]
+
     # Unable to find module path
     return None
 


Test patch:
diff --git a/lib/spack/spack/test/module_parsing.py b/lib/spack/spack/test/module_parsing.py
--- a/lib/spack/spack/test/module_parsing.py
+++ b/lib/spack/spack/test/module_parsing.py
@@ -53,7 +53,8 @@ def test_get_path_from_module(save_env):
     lines = ['prepend-path LD_LIBRARY_PATH /path/to/lib',
              'setenv MOD_DIR /path/to',
              'setenv LDFLAGS -Wl,-rpath/path/to/lib',
-             'setenv LDFLAGS -L/path/to/lib']
+             'setenv LDFLAGS -L/path/to/lib',
+             'prepend-path PATH /path/to/bin']
 
     for line in lines:
         module_func = '() { eval `echo ' + line + ' bash filler`\n}'