We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
spack checksum prefers version-specific url over global url
<!-- Explain, in a clear and concise way, the command you ran and the result you were trying to achieve.
Example: "I ran `spack find` to list all the installed packages and ..." -->

I wanted to update `py-setuptools-rust` to the newest version and ran into something that might be a bug regarding the chosen download path.

I updated the package to use pypi as default but wanted to keep the existing checksum for the old package (to avoid breaking anything), so my `package.py` looks like this:

```python
from spack import *


class PySetuptoolsRust(PythonPackage):
    """Setuptools rust extension plugin."""

    homepage = "https://github.com/PyO3/setuptools-rust"
    pypi = "setuptools-rust/setuptools-rust-0.12.1.tar.gz"

    version('0.12.1', sha256='647009e924f0ae439c7f3e0141a184a69ad247ecb9044c511dabde232d3d570e')
    version('0.10.6', sha256='1446d3985e4aaf4cc679fda8a48a73ac1390b627c8ae1bebe7d9e08bb3b33769',
            url="https://github.com/PyO3/setuptools-rust/archive/v0.10.6.tar.gz")

    depends_on('python@3.6:', when='@0.12:', type=('build', 'run'))
    depends_on('py-setuptools@46.1:', when='@0.12:', type='build')
    depends_on('py-setuptools', when='@:0.11', type='build')
    depends_on('py-semantic-version@2.6.0:', type=('build', 'run'))
    depends_on('py-toml@0.9.0:', type=('build', 'run'))
    depends_on('rust', type='run')
```

When running `spack checksum py-setuptools-rust` for the latest package, spack still uses the github url
```
==> How many would you like to checksum? (default is 1, q to abort)  
==> Fetching https://github.com/PyO3/setuptools-rust/archive/refs/tags/v0.12.1.tar.gz
```

Wheras if I remove `url=....` from version 0.10.6, version 0.12.1 is correctly fetched from pypi. But this means that 0.10.6 is broken since it does not exist there (and if so the checksum would be wrong).
```
==> How many would you like to checksum? (default is 1, q to abort)
==> Fetching https://files.pythonhosted.org/packages/12/22/6ba3031e7cbd6eb002e13ffc7397e136df95813b6a2bd71ece52a8f89613/setuptools-rust-0.12.1.tar.gz#sha256=647009e924f0ae439c7f3e0141a184a69ad247ecb9044c511dabde232d3d570e
```

I thought the download mechanism works like this:
1. try the default url (here pypi)
2. if a version specific url is defined use this one instead only for that version

Do I understand something wrong here or is this a bug?


A workaround is to define `url_for_version` in this case but I still wanted to report the behaviour

### Information on your system

<!-- Please include the output of `spack debug report` -->
* **Spack:** 0.13.4-8544-c8868f1922
* **Python:** 3.5.3
* **Platform:** linux-debian9-piledriver
* **Concretizer:** clingo


<!-- If you have any relevant configuration detail (custom `packages.yaml` or `modules.yaml`, etc.) you can add that here as well. -->

### Additional information

<!-- These boxes can be checked by replacing [ ] with [x] or by clicking them after submitting the issue. -->
- [x] I have run `spack debug report` and reported the version of Spack/Python/Platform
- [x] I have searched the issues of this repo and believe this is not a duplicate

<!-- We encourage you to try, as much as possible, to reduce your problem to the minimal example that still reproduces the issue. That would help us a lot in fixing it quickly and effectively!

If you want to ask a question about the tool (how to use it, what it can currently do, etc.), try the `#general` channel on our Slack first. We have a welcoming community and chances are you'll get your reply faster and without opening an issue.

Other than that, thanks for taking the time to contribute to Spack! -->


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lib/spack/spack/cmd/checksum.py`
Content:
```
1 # Copyright 2013-2021 Lawrence Livermore National Security, LLC and other
2 # Spack Project Developers. See the top-level COPYRIGHT file for details.
3 #
4 # SPDX-License-Identifier: (Apache-2.0 OR MIT)
5 
6 from __future__ import print_function
7 
8 import argparse
9 
10 import llnl.util.tty as tty
11 
12 import spack.cmd
13 import spack.cmd.common.arguments as arguments
14 import spack.repo
15 import spack.stage
16 import spack.util.crypto
17 from spack.util.naming import valid_fully_qualified_module_name
18 from spack.version import Version, ver
19 
20 description = "checksum available versions of a package"
21 section = "packaging"
22 level = "long"
23 
24 
25 def setup_parser(subparser):
26     subparser.add_argument(
27         '--keep-stage', action='store_true',
28         help="don't clean up staging area when command completes")
29     subparser.add_argument(
30         '-b', '--batch', action='store_true',
31         help="don't ask which versions to checksum")
32     arguments.add_common_arguments(subparser, ['package'])
33     subparser.add_argument(
34         'versions', nargs=argparse.REMAINDER,
35         help='versions to generate checksums for')
36 
37 
38 def checksum(parser, args):
39     # Did the user pass 'package@version' string?
40     if len(args.versions) == 0 and '@' in args.package:
41         args.versions = [args.package.split('@')[1]]
42         args.package = args.package.split('@')[0]
43 
44     # Make sure the user provided a package and not a URL
45     if not valid_fully_qualified_module_name(args.package):
46         tty.die("`spack checksum` accepts package names, not URLs.")
47 
48     # Get the package we're going to generate checksums for
49     pkg = spack.repo.get(args.package)
50 
51     if args.versions:
52         # If the user asked for specific versions, use those
53         url_dict = {}
54         for version in args.versions:
55             version = ver(version)
56             if not isinstance(version, Version):
57                 tty.die("Cannot generate checksums for version lists or "
58                         "version ranges. Use unambiguous versions.")
59             url_dict[version] = pkg.url_for_version(version)
60     else:
61         # Otherwise, see what versions we can find online
62         url_dict = pkg.fetch_remote_versions()
63         if not url_dict:
64             tty.die("Could not find any versions for {0}".format(pkg.name))
65 
66     version_lines = spack.stage.get_checksums_for_versions(
67         url_dict, pkg.name, keep_stage=args.keep_stage,
68         batch=(args.batch or len(args.versions) > 0 or len(url_dict) == 1),
69         fetch_options=pkg.fetch_options)
70 
71     print()
72     print(version_lines)
73     print()
74
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lib/spack/spack/cmd/checksum.py b/lib/spack/spack/cmd/checksum.py
--- a/lib/spack/spack/cmd/checksum.py
+++ b/lib/spack/spack/cmd/checksum.py
@@ -63,6 +63,16 @@
         if not url_dict:
             tty.die("Could not find any versions for {0}".format(pkg.name))
 
+        # And ensure the specified version URLs take precedence, if available
+        try:
+            explicit_dict = {}
+            for v in pkg.versions:
+                if not v.isdevelop():
+                    explicit_dict[v] = pkg.url_for_version(v)
+            url_dict.update(explicit_dict)
+        except spack.package.NoURLError:
+            pass
+
     version_lines = spack.stage.get_checksums_for_versions(
         url_dict, pkg.name, keep_stage=args.keep_stage,
         batch=(args.batch or len(args.versions) > 0 or len(url_dict) == 1),

{"golden_diff": "diff --git a/lib/spack/spack/cmd/checksum.py b/lib/spack/spack/cmd/checksum.py\n--- a/lib/spack/spack/cmd/checksum.py\n+++ b/lib/spack/spack/cmd/checksum.py\n@@ -63,6 +63,16 @@\n         if not url_dict:\n             tty.die(\"Could not find any versions for {0}\".format(pkg.name))\n \n+        # And ensure the specified version URLs take precedence, if available\n+        try:\n+            explicit_dict = {}\n+            for v in pkg.versions:\n+                if not v.isdevelop():\n+                    explicit_dict[v] = pkg.url_for_version(v)\n+            url_dict.update(explicit_dict)\n+        except spack.package.NoURLError:\n+            pass\n+\n     version_lines = spack.stage.get_checksums_for_versions(\n         url_dict, pkg.name, keep_stage=args.keep_stage,\n         batch=(args.batch or len(args.versions) > 0 or len(url_dict) == 1),\n", "issue": "spack checksum prefers version-specific url over global url\n<!-- Explain, in a clear and concise way, the command you ran and the result you were trying to achieve.\r\nExample: \"I ran `spack find` to list all the installed packages and ...\" -->\r\n\r\nI wanted to update `py-setuptools-rust` to the newest version and ran into something that might be a bug regarding the chosen download path.\r\n\r\nI updated the package to use pypi as default but wanted to keep the existing checksum for the old package (to avoid breaking anything), so my `package.py` looks like this:\r\n\r\n```python\r\nfrom spack import *\r\n\r\n\r\nclass PySetuptoolsRust(PythonPackage):\r\n    \"\"\"Setuptools rust extension plugin.\"\"\"\r\n\r\n    homepage = \"https://github.com/PyO3/setuptools-rust\"\r\n    pypi = \"setuptools-rust/setuptools-rust-0.12.1.tar.gz\"\r\n\r\n    version('0.12.1', sha256='647009e924f0ae439c7f3e0141a184a69ad247ecb9044c511dabde232d3d570e')\r\n    version('0.10.6', sha256='1446d3985e4aaf4cc679fda8a48a73ac1390b627c8ae1bebe7d9e08bb3b33769',\r\n            url=\"https://github.com/PyO3/setuptools-rust/archive/v0.10.6.tar.gz\")\r\n\r\n    depends_on('python@3.6:', when='@0.12:', type=('build', 'run'))\r\n    depends_on('py-setuptools@46.1:', when='@0.12:', type='build')\r\n    depends_on('py-setuptools', when='@:0.11', type='build')\r\n    depends_on('py-semantic-version@2.6.0:', type=('build', 'run'))\r\n    depends_on('py-toml@0.9.0:', type=('build', 'run'))\r\n    depends_on('rust', type='run')\r\n```\r\n\r\nWhen running `spack checksum py-setuptools-rust` for the latest package, spack still uses the github url\r\n```\r\n==> How many would you like to checksum? (default is 1, q to abort)  \r\n==> Fetching https://github.com/PyO3/setuptools-rust/archive/refs/tags/v0.12.1.tar.gz\r\n```\r\n\r\nWheras if I remove `url=....` from version 0.10.6, version 0.12.1 is correctly fetched from pypi. But this means that 0.10.6 is broken since it does not exist there (and if so the checksum would be wrong).\r\n```\r\n==> How many would you like to checksum? (default is 1, q to abort)\r\n==> Fetching https://files.pythonhosted.org/packages/12/22/6ba3031e7cbd6eb002e13ffc7397e136df95813b6a2bd71ece52a8f89613/setuptools-rust-0.12.1.tar.gz#sha256=647009e924f0ae439c7f3e0141a184a69ad247ecb9044c511dabde232d3d570e\r\n```\r\n\r\nI thought the download mechanism works like this:\r\n1. try the default url (here pypi)\r\n2. if a version specific url is defined use this one instead only for that version\r\n\r\nDo I understand something wrong here or is this a bug?\r\n\r\n\r\nA workaround is to define `url_for_version` in this case but I still wanted to report the behaviour\r\n\r\n### Information on your system\r\n\r\n<!-- Please include the output of `spack debug report` -->\r\n* **Spack:** 0.13.4-8544-c8868f1922\r\n* **Python:** 3.5.3\r\n* **Platform:** linux-debian9-piledriver\r\n* **Concretizer:** clingo\r\n\r\n\r\n<!-- If you have any relevant configuration detail (custom `packages.yaml` or `modules.yaml`, etc.) you can add that here as well. -->\r\n\r\n### Additional information\r\n\r\n<!-- These boxes can be checked by replacing [ ] with [x] or by clicking them after submitting the issue. -->\r\n- [x] I have run `spack debug report` and reported the version of Spack/Python/Platform\r\n- [x] I have searched the issues of this repo and believe this is not a duplicate\r\n\r\n<!-- We encourage you to try, as much as possible, to reduce your problem to the minimal example that still reproduces the issue. That would help us a lot in fixing it quickly and effectively!\r\n\r\nIf you want to ask a question about the tool (how to use it, what it can currently do, etc.), try the `#general` channel on our Slack first. We have a welcoming community and chances are you'll get your reply faster and without opening an issue.\r\n\r\nOther than that, thanks for taking the time to contribute to Spack! -->\r\n\n", "before_files": [{"content": "# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other\n# Spack Project Developers. See the top-level COPYRIGHT file for details.\n#\n# SPDX-License-Identifier: (Apache-2.0 OR MIT)\n\nfrom __future__ import print_function\n\nimport argparse\n\nimport llnl.util.tty as tty\n\nimport spack.cmd\nimport spack.cmd.common.arguments as arguments\nimport spack.repo\nimport spack.stage\nimport spack.util.crypto\nfrom spack.util.naming import valid_fully_qualified_module_name\nfrom spack.version import Version, ver\n\ndescription = \"checksum available versions of a package\"\nsection = \"packaging\"\nlevel = \"long\"\n\n\ndef setup_parser(subparser):\n    subparser.add_argument(\n        '--keep-stage', action='store_true',\n        help=\"don't clean up staging area when command completes\")\n    subparser.add_argument(\n        '-b', '--batch', action='store_true',\n        help=\"don't ask which versions to checksum\")\n    arguments.add_common_arguments(subparser, ['package'])\n    subparser.add_argument(\n        'versions', nargs=argparse.REMAINDER,\n        help='versions to generate checksums for')\n\n\ndef checksum(parser, args):\n    # Did the user pass 'package@version' string?\n    if len(args.versions) == 0 and '@' in args.package:\n        args.versions = [args.package.split('@')[1]]\n        args.package = args.package.split('@')[0]\n\n    # Make sure the user provided a package and not a URL\n    if not valid_fully_qualified_module_name(args.package):\n        tty.die(\"`spack checksum` accepts package names, not URLs.\")\n\n    # Get the package we're going to generate checksums for\n    pkg = spack.repo.get(args.package)\n\n    if args.versions:\n        # If the user asked for specific versions, use those\n        url_dict = {}\n        for version in args.versions:\n            version = ver(version)\n            if not isinstance(version, Version):\n                tty.die(\"Cannot generate checksums for version lists or \"\n                        \"version ranges. Use unambiguous versions.\")\n            url_dict[version] = pkg.url_for_version(version)\n    else:\n        # Otherwise, see what versions we can find online\n        url_dict = pkg.fetch_remote_versions()\n        if not url_dict:\n            tty.die(\"Could not find any versions for {0}\".format(pkg.name))\n\n    version_lines = spack.stage.get_checksums_for_versions(\n        url_dict, pkg.name, keep_stage=args.keep_stage,\n        batch=(args.batch or len(args.versions) > 0 or len(url_dict) == 1),\n        fetch_options=pkg.fetch_options)\n\n    print()\n    print(version_lines)\n    print()\n", "path": "lib/spack/spack/cmd/checksum.py"}], "after_files": [{"content": "# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other\n# Spack Project Developers. See the top-level COPYRIGHT file for details.\n#\n# SPDX-License-Identifier: (Apache-2.0 OR MIT)\n\nfrom __future__ import print_function\n\nimport argparse\n\nimport llnl.util.tty as tty\n\nimport spack.cmd\nimport spack.cmd.common.arguments as arguments\nimport spack.repo\nimport spack.stage\nimport spack.util.crypto\nfrom spack.util.naming import valid_fully_qualified_module_name\nfrom spack.version import Version, ver\n\ndescription = \"checksum available versions of a package\"\nsection = \"packaging\"\nlevel = \"long\"\n\n\ndef setup_parser(subparser):\n    subparser.add_argument(\n        '--keep-stage', action='store_true',\n        help=\"don't clean up staging area when command completes\")\n    subparser.add_argument(\n        '-b', '--batch', action='store_true',\n        help=\"don't ask which versions to checksum\")\n    arguments.add_common_arguments(subparser, ['package'])\n    subparser.add_argument(\n        'versions', nargs=argparse.REMAINDER,\n        help='versions to generate checksums for')\n\n\ndef checksum(parser, args):\n    # Did the user pass 'package@version' string?\n    if len(args.versions) == 0 and '@' in args.package:\n        args.versions = [args.package.split('@')[1]]\n        args.package = args.package.split('@')[0]\n\n    # Make sure the user provided a package and not a URL\n    if not valid_fully_qualified_module_name(args.package):\n        tty.die(\"`spack checksum` accepts package names, not URLs.\")\n\n    # Get the package we're going to generate checksums for\n    pkg = spack.repo.get(args.package)\n\n    if args.versions:\n        # If the user asked for specific versions, use those\n        url_dict = {}\n        for version in args.versions:\n            version = ver(version)\n            if not isinstance(version, Version):\n                tty.die(\"Cannot generate checksums for version lists or \"\n                        \"version ranges. Use unambiguous versions.\")\n            url_dict[version] = pkg.url_for_version(version)\n    else:\n        # Otherwise, see what versions we can find online\n        url_dict = pkg.fetch_remote_versions()\n        if not url_dict:\n            tty.die(\"Could not find any versions for {0}\".format(pkg.name))\n\n        # And ensure the specified version URLs take precedence, if available\n        try:\n            explicit_dict = {}\n            for v in pkg.versions:\n                if not v.isdevelop():\n                    explicit_dict[v] = pkg.url_for_version(v)\n            url_dict.update(explicit_dict)\n        except spack.package.NoURLError:\n            pass\n\n    version_lines = spack.stage.get_checksums_for_versions(\n        url_dict, pkg.name, keep_stage=args.keep_stage,\n        batch=(args.batch or len(args.versions) > 0 or len(url_dict) == 1),\n        fetch_options=pkg.fetch_options)\n\n    print()\n    print(version_lines)\n    print()\n", "path": "lib/spack/spack/cmd/checksum.py"}]}