Repository: spack/spack

Issue:
Problems raising errors during install with Python 3
When installing a package with a broken URL, Spack crashes when trying to raise a `FetchError` if using Python 3.

### Expected Result

Things work correctly when using Python 2:
```
$ python2 $(which spack) install example
==> Installing example
==> Fetching http://www.example.com/example-1.2.3.tar.gz

curl: (22) The requested URL returned error: 404 Not Found
==> Fetching from http://www.example.com/example-1.2.3.tar.gz failed.
==> Error: FetchError: All fetchers failed for example-1.2.3-p2xvcgjgyyiarllbm3spwju6nvxt5f36
FetchError: FetchError: All fetchers failed for example-1.2.3-p2xvcgjgyyiarllbm3spwju6nvxt5f36

/Users/Adam/spack/lib/spack/spack/package.py:993, in do_fetch:
     25                                     self.spec.format('$_$@'), ck_msg)
     26    
     27            self.stage.create()
  >> 28            self.stage.fetch(mirror_only)
     29            self._fetch_time = time.time() - start_time
     30    
     31            if spack.do_checksum and self.version in self.versions:
```

### Actual Result

When using Python 3, Spack crashes when trying to raise this error:
```
$ python3 $(which spack) install example
==> Installing example
==> Fetching http://www.example.com/example-1.2.3.tar.gz

curl: (22) The requested URL returned error: 404 Not Found
==> Fetching from http://www.example.com/example-1.2.3.tar.gz failed.
Process Process-1:
Traceback (most recent call last):
  File "/Users/Adam/spack/lib/spack/spack/build_environment.py", line 665, in child_process
    return_value = function()
  File "/Users/Adam/spack/lib/spack/spack/package.py", line 1405, in build_process
    self.do_patch()
  File "/Users/Adam/spack/lib/spack/spack/package.py", line 1052, in do_patch
    self.do_stage()
  File "/Users/Adam/spack/lib/spack/spack/package.py", line 1006, in do_stage
    self.do_fetch(mirror_only)     # this will create the stage
  File "/Users/Adam/spack/lib/spack/spack/package.py", line 993, in do_fetch
    self.stage.fetch(mirror_only)
  File "/Users/Adam/spack/lib/spack/spack/util/pattern.py", line 87, in getter
    getattr(item, self.name)(*args, **kwargs)
  File "/Users/Adam/spack/lib/spack/spack/stage.py", line 441, in fetch
    raise fs.FetchError(errMessage, None)
spack.fetch_strategy.FetchError: All fetchers failed for example-1.2.3-p2xvcgjgyyiarllbm3spwju6nvxt5f36

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/Adam/anaconda3/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/Users/Adam/anaconda3/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/Adam/spack/lib/spack/spack/build_environment.py", line 686, in child_process
    if hasattr(pkg, 'log_path'):
  File "/Users/Adam/spack/lib/spack/spack/package.py", line 801, in log_path
    return os.path.join(self.stage.source_path, 'spack-build.out')
  File "/Users/Adam/anaconda3/lib/python3.6/posixpath.py", line 78, in join
    a = os.fspath(a)
TypeError: expected str, bytes or os.PathLike object, not NoneType
```

### Steps to reproduce the issue

```console
$ spack create
# uncomment the version()
$ spack install example
```

Note: the problem occurs only when running `spack install`, not when running `spack fetch`, so the problem may not be in the fetcher itself.

@alalazo 


Discussion:
Similar, possibly related error. When trying to debug #6875, I noticed the following problem.

### Expected Result

Things work as expected in Python 2:
```
$ python2 $(which spack) install tbl2asn
==> Installing tbl2asn
==> Using cached archive: /Users/Adam/spack/var/spack/cache/tbl2asn/tbl2asn-25.6.gz
==> Staging archive: /Users/Adam/spack/var/spack/stage/tbl2asn-25.6-lvueshk3uptk6q53f7y33obkguwcrgwc/linux64.tbl2asn.gz
gunzip: /Users/Adam/spack/var/spack/stage/tbl2asn-25.6-lvueshk3uptk6q53f7y33obkguwcrgwc/linux64.tbl2asn.gz is not a regular file
==> Error: ProcessError: Command exited with status 1:
    '/usr/bin/gunzip' '/Users/Adam/spack/var/spack/stage/tbl2asn-25.6-lvueshk3uptk6q53f7y33obkguwcrgwc/linux64.tbl2asn.gz'
==> Error: [Errno 2] No such file or directory: '/Users/Adam/spack/var/spack/stage/tbl2asn-25.6-lvueshk3uptk6q53f7y33obkguwcrgwc/spack-expanded-archive/spack-build.out'
```

### Actual Result

Things crash for Python 3:
```
$ python3 $(which spack) install tbl2asn
==> Installing tbl2asn
==> Fetching ftp://ftp.ncbi.nih.gov/toolbox/ncbi_tools/converters/by_program/tbl2asn/linux64.tbl2asn.gz
######################################################################## 100.0%
==> Staging archive: /Users/Adam/spack/var/spack/stage/tbl2asn-25.6-lvueshk3uptk6q53f7y33obkguwcrgwc/linux64.tbl2asn.gz
==> Created stage in /Users/Adam/spack/var/spack/stage/tbl2asn-25.6-lvueshk3uptk6q53f7y33obkguwcrgwc
==> No patches needed for tbl2asn
==> Building tbl2asn [Package]
Process Process-1:
Traceback (most recent call last):
  File "/Users/Adam/spack/lib/spack/spack/build_environment.py", line 665, in child_process
    return_value = function()
  File "/Users/Adam/spack/lib/spack/spack/package.py", line 1434, in build_process
    with working_dir(self.stage.source_path):
  File "/Users/Adam/anaconda3/lib/python3.6/contextlib.py", line 81, in __enter__
    return next(self.gen)
  File "/Users/Adam/spack/lib/spack/llnl/util/filesystem.py", line 291, in working_dir
    os.chdir(dirname)
TypeError: chdir: path should be string, bytes, os.PathLike or integer, not NoneType

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/Adam/anaconda3/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/Users/Adam/anaconda3/lib/python3.6/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/Adam/spack/lib/spack/spack/build_environment.py", line 686, in child_process
    if hasattr(pkg, 'log_path'):
  File "/Users/Adam/spack/lib/spack/spack/package.py", line 801, in log_path
    return os.path.join(self.stage.source_path, 'spack-build.out')
  File "/Users/Adam/anaconda3/lib/python3.6/posixpath.py", line 78, in join
    a = os.fspath(a)
TypeError: expected str, bytes or os.PathLike object, not NoneType
```

### Steps to reproduce the issue

This problem can be reproduced by using the following package.py:
```python
from spack import *                                                             
import os                                                                       
                                                                                
                                                                                
class Tbl2asn(Package):                                                         
    """Tbl2asn is a command-line program that automates the creation of         
    sequence records for submission to GenBank."""                              
                                                                                
    homepage = "https://www.ncbi.nlm.nih.gov/genbank/tbl2asn2"                  
                                                                                
    version('25.6', 'acf3575909b4d28aa74dcd46f17c281f',                         
            url="ftp://ftp.ncbi.nih.gov/toolbox/ncbi_tools/converters/by_program/tbl2asn/linux64.tbl2asn.gz")
                                                                                
    def install(self, spec, prefix):                                            
        # Documentation instructs to remove the platform designation            
        install('linux64.tbl2asn', os.path.join(prefix, 'tbl2asn'))             
        set_executable(os.path.join(prefix, 'tbl2asn'))                         
                                                                                
    def setup_environment(self, spack_env, run_env):                            
        run_env.prepend_path('PATH', prefix)  
```

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
@@ -794,11 +794,17 @@ def stage(self, stage):
 
     @property
     def env_path(self):
-        return os.path.join(self.stage.source_path, 'spack-build.env')
+        if self.stage.source_path is None:
+            return None
+        else:
+            return os.path.join(self.stage.source_path, 'spack-build.env')
 
     @property
     def log_path(self):
-        return os.path.join(self.stage.source_path, 'spack-build.out')
+        if self.stage.source_path is None:
+            return None
+        else:
+            return os.path.join(self.stage.source_path, 'spack-build.out')
 
     def _make_fetcher(self):
         # Construct a composite fetcher that always contains at least


Test patch: