Repository: pdm-project/pdm

Issue:
metadata.files sorting in pdm.lock changes between computers
## Steps to reproduce

* Add several package sources which contain the same wheels with different hashes (for example https://piwheels.org for deploying to raspberry pi)
* run `pdm lock` on different computers (linux vs windows)

## Actual behavior

The following diff is observed between the two computers
```diff
 "uritemplate 3.0.1" = [
-    {url = "https://files.pythonhosted.org/packages/bf/0c/60d82c077998feb631608dca3cc1fe19ac074e772bf0c24cf409b977b815/uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f"},
     {url = "https://www.piwheels.org/simple/uritemplate/uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f"},
+    {url = "https://files.pythonhosted.org/packages/bf/0c/60d82c077998feb631608dca3cc1fe19ac074e772bf0c24cf409b977b815/uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f"},
     {url = "https://files.pythonhosted.org/packages/42/da/fa9aca2d866f932f17703b3b5edb7b17114bb261122b6e535ef0d9f618f8/uritemplate-3.0.1.tar.gz", hash = "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"},
 ]
```

## Expected behavior

pdm.lock should be the same no matter which computer last locked it.

## Environment Information

Debian docker image with PDM 2.0.2 and WIndows 10 workstation with PDM 2.0.2


Discussion:
codecov-commenter: # [Codecov](https://codecov.io/gh/pdm-project/pdm/pull/1257?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) Report
> Merging [#1257](https://codecov.io/gh/pdm-project/pdm/pull/1257?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) (e065b9a) into [main](https://codecov.io/gh/pdm-project/pdm/commit/bfc827927cb78843dd7fa1bfa4a396351bc6c85a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) (bfc8279) will **decrease** coverage by `0.02%`.
> The diff coverage is `n/a`.

```diff
@@            Coverage Diff             @@
##             main    #1257      +/-   ##
==========================================
- Coverage   81.27%   81.25%   -0.03%     
==========================================
  Files          93       93              
  Lines        7643     7643              
  Branches     1785     1785              
==========================================
- Hits         6212     6210       -2     
- Misses       1069     1070       +1     
- Partials      362      363       +1     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `81.14% <ø> (-0.03%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/pdm-project/pdm/pull/1257?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project) | Coverage Δ | |
|---|---|---|
| [pdm/cli/utils.py](https://codecov.io/gh/pdm-project/pdm/pull/1257/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project#diff-cGRtL2NsaS91dGlscy5weQ==) | `80.06% <ø> (ø)` | |
| [pdm/resolver/core.py](https://codecov.io/gh/pdm-project/pdm/pull/1257/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project#diff-cGRtL3Jlc29sdmVyL2NvcmUucHk=) | `89.47% <ø> (ø)` | |
| [pdm/models/repositories.py](https://codecov.io/gh/pdm-project/pdm/pull/1257/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project#diff-cGRtL21vZGVscy9yZXBvc2l0b3JpZXMucHk=) | `77.50% <0.00%> (-0.84%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pdm-project/pdm/pull/1257?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pdm-project/pdm/pull/1257?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project). Last update [bfc8279...e065b9a](https://codecov.io/gh/pdm-project/pdm/pull/1257?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pdm-project).


Patch:
diff --git a/news/1256.bugfix.md b/news/1256.bugfix.md
new file mode 100644
index 00000000..c111cf60
--- /dev/null
+++ b/news/1256.bugfix.md
@@ -0,0 +1,1 @@
+Stabilize sorting of URLs in `metadata.files` in `pdm.lock`.
diff --git a/pdm/cli/utils.py b/pdm/cli/utils.py
index e822f7fc..725d0c94 100644
--- a/pdm/cli/utils.py
+++ b/pdm/cli/utils.py
@@ -465,7 +465,7 @@ def format_lockfile(
                 continue
             array = tomlkit.array().multiline(True)
             for link, hash_value in sorted(
-                v.hashes.items(), key=lambda l: l[0].filename
+                v.hashes.items(), key=lambda l_h: (l_h[0].url_without_fragment, l_h[1])
             ):
                 inline = make_inline_table(
                     {"url": link.url_without_fragment, "hash": hash_value}
diff --git a/pdm/resolver/core.py b/pdm/resolver/core.py
index 4a6993c2..195af3bc 100644
--- a/pdm/resolver/core.py
+++ b/pdm/resolver/core.py
@@ -20,11 +20,10 @@ def resolve(
     max_rounds: int = 10000,
 ) -> tuple[dict[str, Candidate], dict[str, list[Requirement]]]:
     """Core function to perform the actual resolve process.
-    Return a tuple containing 3 items:
+    Return a tuple containing 2 items:
 
         1. A map of pinned candidates
         2. A map of resolved dependencies for each dependency group
-        3. A map of package descriptions fetched from PyPI source
     """
     requirements.append(PythonRequirement.from_pyspec_set(requires_python))
     provider = cast(BaseProvider, resolver.provider)


Test patch:
diff --git a/tests/cli/test_lock.py b/tests/cli/test_lock.py
index 071ab9ff..80a10cf9 100644
--- a/tests/cli/test_lock.py
+++ b/tests/cli/test_lock.py
@@ -30,24 +30,23 @@ def test_lock_refresh(invoke, project, repository):
     assert project.is_lockfile_hash_match()
     assert not project.lockfile["metadata"]["files"].get("requests 2.19.1")
     project.add_dependencies({"requests": parse_requirement("requests>=2.0")})
-    repository.get_hashes = (
-        lambda c: {
-            Link(
-                "http://example.com/requests-2.19.1-py3-none-any.whl"
-            ): "sha256:abcdef123456"
-        }
+    url_hashes = {
+        "http://example.com/requests-2.19.1-py3-none-any.whl": "sha256:abcdef123456",
+        "http://example2.com/requests-2.19.1-py3-none-AMD64.whl": "sha256:abcdef123456",
+        "http://example1.com/requests-2.19.1-py3-none-any.whl": "sha256:abcdef123456",
+    }
+    repository.get_hashes = lambda c: (
+        {Link(url): hash for url, hash in url_hashes.items()}
         if c.identify() == "requests"
         else {}
     )
-    print(project.lockfile)
     assert not project.is_lockfile_hash_match()
     result = invoke(["lock", "--refresh", "-v"], obj=project)
     assert result.exit_code == 0
     assert project.is_lockfile_hash_match()
-    assert project.lockfile["metadata"]["files"]["requests 2.19.1"][0] == {
-        "url": "http://example.com/requests-2.19.1-py3-none-any.whl",
-        "hash": "sha256:abcdef123456",
-    }
+    assert project.lockfile["metadata"]["files"]["requests 2.19.1"] == [
+        {"url": url, "hash": hash} for url, hash in sorted(url_hashes.items())
+    ]
 
 
 def test_lock_refresh_keep_consistent(invoke, project, repository):