Repository: spack/spack

Issue:
Catch errors and fail fast during buildcache creation.
> Just to be clear: I don't think my point above about catching the permission denied errors needs to be incorporated for this PR, necessarily.  Someone (probably me, since I wrote the code) can handle that in another PR.

_Originally posted by @opadron in https://github.com/spack/spack/pull/15090/review_comment/create_


Discussion:
Some more context: from @gartung:

```
(flake8) [gartung@gartung spack]$ spack buildcache create -r -a -d  /3n2qkuj /skjzxw6 
==> creating binary cache file for package git@2.25.0%gcc@4.8.5~tcltk arch=linux-scientific7-x86_64 
==> Warning: Missing a source id for curl@7.29.0
==> Warning: Missing a source id for expat@2.1.0
==> Warning: Missing a source id for libxml2@2.9.1
==> Warning: Missing a source id for tar@1.26
==> Warning: Missing a source id for zlib@1.2.7
==> Warning: [Errno 13] Permission denied: '/3n2qkuj'
==> creating binary cache file for package gettext@0.20.1%gcc@4.8.5+bzip2+curses+git~libunistring+libxml2+tar+xz arch=linux-scientific7-x86_64 
==> Warning: [Errno 13] Permission denied: '/3n2qkuj'
==> creating binary cache file for package libiconv@1.16%gcc@4.8.5 arch=linux-scientific7-x86_64 
==> Warning: [Errno 13] Permission denied: '/3n2qkuj'
==> creating binary cache file for package pcre2@10.31%gcc@4.8.5+multibyte arch=linux-scientific7-x86_64 
==> Warning: [Errno 13] Permission denied: '/3n2qkuj'
==> creating binary cache file for package libunistring@0.9.10%gcc@4.8.5 arch=linux-scientific7-x86_64 
==> Warning: [Errno 13] Permission denied: '/3n2qkuj'
==> creating binary cache file for package libidn2@2.1.1a%gcc@4.8.5 arch=linux-scientific7-x86_64 
==> Warning: [Errno 13] Permission denied: '/3n2qkuj'
```

The buildcache creation process should properly catch these "Permission denied" errors and fail quickly.

Resolving patch:
diff --git a/lib/spack/spack/cmd/buildcache.py b/lib/spack/spack/cmd/buildcache.py
--- a/lib/spack/spack/cmd/buildcache.py
+++ b/lib/spack/spack/cmd/buildcache.py
@@ -361,13 +361,9 @@ def _createtarball(env, spec_yaml, packages, directory, key, no_deps, force,
 
     for spec in specs:
         tty.msg('creating binary cache file for package %s ' % spec.format())
-        try:
-            bindist.build_tarball(spec, outdir, force, rel,
-                                  unsigned, allow_root, signkey,
-                                  not no_rebuild_index)
-        except Exception as e:
-            tty.warn('%s' % e)
-            pass
+        bindist.build_tarball(spec, outdir, force, rel,
+                              unsigned, allow_root, signkey,
+                              not no_rebuild_index)
 
 
 def createtarball(args):
diff --git a/lib/spack/spack/util/web.py b/lib/spack/spack/util/web.py
--- a/lib/spack/spack/util/web.py
+++ b/lib/spack/spack/util/web.py
@@ -205,6 +205,8 @@ def push_to_url(
                     # needs to be done in separate steps.
                     shutil.copy2(local_file_path, remote_file_path)
                     os.remove(local_file_path)
+                else:
+                    raise
 
     elif remote_url.scheme == 's3':
         if extra_args is None:


Test patch:
diff --git a/lib/spack/spack/test/cmd/buildcache.py b/lib/spack/spack/test/cmd/buildcache.py
--- a/lib/spack/spack/test/cmd/buildcache.py
+++ b/lib/spack/spack/test/cmd/buildcache.py
@@ -3,6 +3,7 @@
 #
 # SPDX-License-Identifier: (Apache-2.0 OR MIT)
 
+import errno
 import platform
 
 import pytest
@@ -11,6 +12,7 @@
 import spack.binary_distribution
 
 buildcache = spack.main.SpackCommand('buildcache')
+install = spack.main.SpackCommand('install')
 
 
 @pytest.fixture()
@@ -41,3 +43,16 @@ def test_buildcache_list_duplicates(mock_get_specs, capsys):
         output = buildcache('list', 'mpileaks', '@2.3')
 
     assert output.count('mpileaks') == 3
+
+
+def test_buildcache_create_fail_on_perm_denied(
+        install_mockery, mock_fetch, monkeypatch, tmpdir):
+    """Ensure that buildcache create fails on permission denied error."""
+    install('trivial-install-test-package')
+
+    tmpdir.chmod(0)
+    with pytest.raises(OSError) as error:
+        buildcache('create', '-d', str(tmpdir),
+                   '--unsigned', 'trivial-install-test-package')
+    assert error.value.errno == errno.EACCES
+    tmpdir.chmod(0o700)