Repository: spack/spack

Issue:
fetch error with BundlePackage
`xsdk` is  recently changed to a `BundlePackage` at c9e214f6d3

```
bash-5.0$ spack fetch --dependencies xsdk
==> Error: Can only fetch a package with a URL.
```
I've used this functionality before to download all the package sources on front-end - so that the builds can be done on a back-end node [which have limited network connectivity]. But now its broke.

Perhaps the code should just warn about BundlePackage - and continue - and not error out?






Discussion:
For now - I've disabled this check.
```
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index b49c8c1a2..41f42ae1f 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -1045,8 +1045,8 @@ class PackageBase(with_metaclass(PackageMeta, PackageViewMixin, object)):
         if not self.spec.concrete:
             raise ValueError("Can only fetch concrete packages.")
 
-        if not self.has_code:
-            raise InvalidPackageOpError("Can only fetch a package with a URL.")
+        #if not self.has_code:
+        #    raise InvalidPackageOpError("Can only fetch a package with a URL.")
 
         start_time = time.time()
         checksum = spack.config.get('config:checksum')
```
I do see messages of type:
```
######################################################################## 100.0%
==> Cloning git repository: https://github.com/pghysels/STRUMPACK.git on branch master
==> No checksum needed when fetching with git
==> Fetching https://github.com/ORNL/TASMANIAN/archive/v7.0.tar.gz
######################################################################## 100.0%
==> No code to cache.
==> No code to fetch.
==> No code to check.
==> No code to cache.
```
It would be good to print the package name that these messages correspond to. [same with the original error message on this issue]

Resolving patch:
diff --git a/lib/spack/spack/fetch_strategy.py b/lib/spack/spack/fetch_strategy.py
--- a/lib/spack/spack/fetch_strategy.py
+++ b/lib/spack/spack/fetch_strategy.py
@@ -201,28 +201,16 @@ class BundleFetchStrategy(FetchStrategy):
     url_attr = ''
 
     def fetch(self):
-        tty.msg("No code to fetch.")
+        """Simply report success -- there is no code to fetch."""
         return True
 
-    def check(self):
-        tty.msg("No code to check.")
-
-    def expand(self):
-        tty.msg("No archive to expand.")
-
-    def reset(self):
-        tty.msg("No code to reset.")
-
-    def archive(self, destination):
-        tty.msg("No code to archive.")
-
     @property
     def cachable(self):
-        tty.msg("No code to cache.")
+        """Report False as there is no code to cache."""
         return False
 
     def source_id(self):
-        tty.msg("No code to be uniquely identified.")
+        """BundlePackages don't have a source id."""
         return ''
 
 
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
@@ -1046,7 +1046,9 @@ def do_fetch(self, mirror_only=False):
             raise ValueError("Can only fetch concrete packages.")
 
         if not self.has_code:
-            raise InvalidPackageOpError("Can only fetch a package with a URL.")
+            tty.msg(
+                "No fetch required for %s: package has no code." % self.name
+            )
 
         start_time = time.time()
         checksum = spack.config.get('config:checksum')


Test patch:
diff --git a/lib/spack/spack/test/install.py b/lib/spack/spack/test/install.py
--- a/lib/spack/spack/test/install.py
+++ b/lib/spack/spack/test/install.py
@@ -9,8 +9,7 @@
 
 from llnl.util.filesystem import mkdirp, touch, working_dir
 
-from spack.package import \
-    InstallError, InvalidPackageOpError, PackageBase, PackageStillNeededError
+from spack.package import InstallError, PackageBase, PackageStillNeededError
 import spack.patch
 import spack.repo
 import spack.store
@@ -327,7 +326,9 @@ def test_uninstall_by_spec_errors(mutable_database):
         PackageBase.uninstall_by_spec(rec.spec)
 
 
-def test_nosource_pkg_install(install_mockery, mock_fetch, mock_packages):
+@pytest.mark.disable_clean_stage_check
+def test_nosource_pkg_install(
+        install_mockery, mock_fetch, mock_packages, capfd):
     """Test install phases with the nosource package."""
     spec = Spec('nosource').concretized()
     pkg = spec.package
@@ -336,9 +337,8 @@ def test_nosource_pkg_install(install_mockery, mock_fetch, mock_packages):
     pkg.do_install()
 
     # Also make sure an error is raised if `do_fetch` is called.
-    with pytest.raises(InvalidPackageOpError,
-                       match="fetch a package with a URL"):
-        pkg.do_fetch()
+    pkg.do_fetch()
+    assert "No fetch required for nosource" in capfd.readouterr()[0]
 
 
 def test_nosource_pkg_install_post_install(