Repository: spack/spack

Issue:
Version-specific URL overrides package-specific URL of newer version
#2725 was closed, so I'm moving the bug report to here. See #2725 for details and instructions on how to reproduce the bug.


Discussion:
Also see #4365 and #4366 for another example of this bug.
This bug also affects the `converge` package.
Also see #4385 for another package affected by this bug.
#4982 is another example of this.
#7206, #7118, and #7002 are all examples of this.
#7849 is another lovely example of this bug.
See #7951 for another example of this...

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
@@ -766,22 +766,6 @@ def version_urls(self):
                 version_urls[v] = args['url']
         return version_urls
 
-    def nearest_url(self, version):
-        """Finds the URL for the next lowest version with a URL.
-           If there is no lower version with a URL, uses the
-           package url property. If that isn't there, uses a
-           *higher* URL, and if that isn't there raises an error.
-        """
-        version_urls = self.version_urls()
-        url = getattr(self.__class__, 'url', None)
-
-        for v in version_urls:
-            if v > version and url:
-                break
-            if version_urls[v]:
-                url = version_urls[v]
-        return url
-
     # TODO: move this out of here and into some URL extrapolation module?
     def url_for_version(self, version):
         """Returns a URL from which the specified version of this package
@@ -804,9 +788,10 @@ def url_for_version(self, version):
         if version in version_urls:
             return version_urls[version]
 
-        # If we have no idea, try to substitute the version.
+        # If we have no idea, substitute the version into the default URL.
+        default_url = getattr(self.__class__, 'url', None)
         return spack.url.substitute_version(
-            self.nearest_url(version), self.url_version(version))
+            default_url, self.url_version(version))
 
     def _make_resource_stage(self, root_stage, fetcher, resource):
         resource_stage_folder = self._resource_stage(resource)
diff --git a/var/spack/repos/builtin.mock/packages/url_override/package.py b/var/spack/repos/builtin.mock/packages/url_override/package.py
new file mode 100644
--- /dev/null
+++ b/var/spack/repos/builtin.mock/packages/url_override/package.py
@@ -0,0 +1,34 @@
+##############################################################################
+# Copyright (c) 2013-2018, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://github.com/spack/spack
+# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License (as
+# published by the Free Software Foundation) version 2.1, February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+from spack import *
+
+
+class UrlOverride(Package):
+    homepage = 'http://www.doesnotexist.org'
+    url      = 'http://www.doesnotexist.org/url_override-1.0.0.tar.gz'
+
+    version('1.0.0', 'cxyzab')
+    version('0.9.0', 'bcxyza', url='http://www.anothersite.org/uo-0.9.0.tgz')
+    version('0.8.1', 'cxyzab')


Test patch:
diff --git a/lib/spack/spack/test/packages.py b/lib/spack/spack/test/packages.py
--- a/lib/spack/spack/test/packages.py
+++ b/lib/spack/spack/test/packages.py
@@ -165,3 +165,18 @@ def test_import_namespace_container_modules(self):
         import spack.pkg.builtin.mock                   # noqa
         import spack.pkg.builtin.mock as m              # noqa
         from spack.pkg.builtin import mock              # noqa
+
+    @pytest.mark.regression('2737')
+    def test_urls_for_versions(self):
+        # Checks that a version directive without a 'url' argument
+        # specified uses the default url
+        for spec_str in ('url_override@0.9.0', 'url_override@1.0.0'):
+            s = Spec(spec_str).concretized()
+            url = s.package.url_for_version('0.9.0')
+            assert url == 'http://www.anothersite.org/uo-0.9.0.tgz'
+
+            url = s.package.url_for_version('1.0.0')
+            assert url == 'http://www.doesnotexist.org/url_override-1.0.0.tar.gz'
+
+            url = s.package.url_for_version('0.8.1')
+            assert url == 'http://www.doesnotexist.org/url_override-0.8.1.tar.gz'