Repository: spack/spack

Issue:
Unable to uninstall external package
On the latest develop, I tried uninstalling all of my packages, and Spack hung on an external `jdk` installation. It appears that Spack is unable to uninstall extendable packages (or any package that extends them) when that external package is installed in a directory the user does not have permission to access.

### Steps to reproduce the issue

Add the following to `packages.yaml`:
```yaml
packages:
    jdk:
        paths:
            jdk@10.0.1_10: /Library/Java/JavaVirtualMachines/jdk-10.0.1.jdk/Contents/Home
        buildable: False
```
Then try to install and uninstall the package:
```console
$ spack install commons-lang  # extends jdk
$ spack uninstall commons-lang
```

### Error Message

```console
$ spack -d uninstall commons-lang
...
Traceback (most recent call last):
  File "/Users/Adam/spack/bin/spack", line 48, in <module>
    sys.exit(spack.main.main())
  File "/Users/Adam/spack/lib/spack/spack/main.py", line 697, in main
    return _invoke_command(command, parser, args, unknown)
  File "/Users/Adam/spack/lib/spack/spack/main.py", line 447, in _invoke_command
    return_val = command(parser, args)
  File "/Users/Adam/spack/lib/spack/spack/cmd/uninstall.py", line 336, in uninstall
    args, spack.cmd.parse_specs(args.packages) if args.packages else [any])
  File "/Users/Adam/spack/lib/spack/spack/cmd/uninstall.py", line 326, in uninstall_specs
    do_uninstall(env, uninstall_list, args.force)
  File "/Users/Adam/spack/lib/spack/spack/cmd/uninstall.py", line 224, in do_uninstall
    item.do_uninstall(force=force)
  File "/Users/Adam/spack/lib/spack/spack/package.py", line 2017, in do_uninstall
    Package.uninstall_by_spec(self.spec, force)
  File "/Users/Adam/spack/lib/spack/spack/package.py", line 1997, in uninstall_by_spec
    spack.hooks.pre_uninstall(spec)
  File "/Users/Adam/spack/lib/spack/spack/hooks/__init__.py", line 54, in __call__
    hook(*args, **kwargs)
  File "/Users/Adam/spack/lib/spack/spack/hooks/extensions.py", line 16, in pre_uninstall
    view = YamlFilesystemView(target, spack.store.layout)
  File "/Users/Adam/spack/lib/spack/spack/filesystem_view.py", line 204, in __init__
    mkdirp(os.path.dirname(projections_path))
  File "/Users/Adam/spack/lib/spack/llnl/util/filesystem.py", line 436, in mkdirp
    raise e
  File "/Users/Adam/spack/lib/spack/llnl/util/filesystem.py", line 431, in mkdirp
    os.makedirs(path)
  File "/Users/Adam/miniconda3/lib/python3.7/os.py", line 221, in makedirs
    mkdir(name, mode)
PermissionError: [Errno 13] Permission denied: '/Library/Java/JavaVirtualMachines/jdk-10.0.1.jdk/Contents/Home/.spack'
```

### Information on your system

This occurred on macOS Mojave 10.14.5.

It appears that this bug only occurs with extensions, and only when an extension is actually installed. This bug is not exclusive to `jdk`, it can be reproduced with other packages as well. For example, add `libsigsegv` to `packages.yaml` in a directory lacking permissions. Then edit `libsigsegv` to add `extendable = True`, and edit `m4` to add `extends('libsigsegv')`. Then run:
```console
$ spack install m4  # extends libsigsegv
$ spack uninstall m4
```


Discussion:
Were there any recent PRs that modified how external packages are treated? Wasn't there a recent attempt to fix module-file creation for installations where the package no longer exists/was renamed? I wonder if that's what is trying to access the `.spack` directory in the installation prefix.
I am unable to reproduce it:
```console
$ spack install jdk
==> jdk@10.0.1_10 : externally installed in /home/mculpo/tmp/jdk
==> jdk@10.0.1_10 : generating module file
==> jdk@10.0.1_10 : registering into DB

$ chmod a-xrw jdk/
$ ls -larth jdk
ls: cannot open directory 'jdk': Permission denied

$ spack uninstall -y jdk
==> Successfully uninstalled jdk@10.0.1_10%gcc@9.0.1 arch=linux-ubuntu18.04-x86_64/w63ovqh
```
@alalazo I updated the initial bug report to add more details on how to reproduce the issue. It looks like an extension must also be installed for the bug to occur. Maybe Spack is trying to check if the extension has been activated and is crashing when it can't check?
I've also found a workaround for uninstalling the packages affected by this bug. Simply remove `extends('jdk')` from any extension and you can uninstall everything successfully.

Resolving patch:
diff --git a/lib/spack/spack/filesystem_view.py b/lib/spack/spack/filesystem_view.py
--- a/lib/spack/spack/filesystem_view.py
+++ b/lib/spack/spack/filesystem_view.py
@@ -201,9 +201,13 @@ def __init__(self, root, layout, **kwargs):
                 # Write projections file to new view
                 # Not strictly necessary as the empty file is the empty
                 # projection but it makes sense for consistency
-                mkdirp(os.path.dirname(projections_path))
-                with open(projections_path, 'w') as f:
-                    f.write(s_yaml.dump({'projections': self.projections}))
+                try:
+                    mkdirp(os.path.dirname(projections_path))
+                    with open(projections_path, 'w') as f:
+                        f.write(s_yaml.dump({'projections': self.projections}))
+                except OSError as e:
+                    if self.projections:
+                        raise e
         elif not os.path.exists(projections_path):
             # Write projections file to new view
             mkdirp(os.path.dirname(projections_path))


Test patch: