Skip to content

Commit 920e7ef

Browse files
committed
adjust code to latest cachi2
1 parent 246a2d8 commit 920e7ef

File tree

1 file changed

+83
-19
lines changed

1 file changed

+83
-19
lines changed

cachi2/core/package_managers/cargo.py

Lines changed: 83 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
# SPDX-License-Identifier: GPL-3.0-or-later
2+
from pathlib import Path
3+
from textwrap import dedent
4+
from typing import Any
25
import hashlib
36
import json
47
import logging
58
import tarfile
6-
from pathlib import Path
7-
from textwrap import dedent
9+
import urllib
810

11+
from packageurl import PackageURL
912
import tomli
1013

1114
from cachi2.core.checksum import ChecksumInfo, must_match_any_checksum
12-
from cachi2.core.models.input import Request
15+
from cachi2.core.models.input import CargoPackageInput, Request
1316
from cachi2.core.models.output import Component, ProjectFile, RequestOutput
1417
from cachi2.core.package_managers.general import download_binary_file
1518
from cachi2.core.rooted_path import RootedPath
19+
from cachi2.core.scm import get_repo_id
1620

1721
log = logging.getLogger(__name__)
1822

@@ -24,20 +28,20 @@ def fetch_cargo_source(request: Request) -> RequestOutput:
2428
"""Resolve and fetch cargo dependencies for the given request."""
2529
components: list[Component] = []
2630
for package in request.cargo_packages:
27-
info = _resolve_cargo(
28-
request.source_dir / package.path,
29-
request.output_dir,
30-
package.lock_file,
31-
package.pkg_name,
32-
package.pkg_version,
33-
)
31+
info = _resolve_cargo(request.source_dir, request.output_dir, package)
3432
components.append(Component.from_package_dict(info["package"]))
35-
3633
for dependency in info["dependencies"]:
37-
components.append(Component.from_package_dict(dependency))
34+
dep_purl = _generate_purl_dependency(dependency)
35+
components.append(
36+
Component(
37+
name=dependency["name"],
38+
version=dependency["version"],
39+
purl=dep_purl,
40+
)
41+
)
3842

3943
cargo_config = ProjectFile(
40-
abspath=request.source_dir.join_within_root(".cargo/config.toml"),
44+
abspath=Path(request.source_dir.join_within_root(".cargo/config.toml")),
4145
template=dedent(
4246
"""
4347
[source.crates-io]
@@ -56,18 +60,21 @@ def fetch_cargo_source(request: Request) -> RequestOutput:
5660
)
5761

5862

59-
def _resolve_cargo(
60-
app_path: Path, output_dir: Path, lock_file=None, pkg_name=None, pkg_version=None
61-
):
63+
def _resolve_cargo(source_dir: Path, output_dir: Path, package: CargoPackageInput):
6264
"""
6365
Resolve and fetch cargo dependencies for the given cargo application.
6466
"""
67+
app_path = source_dir / package.path
68+
pkg_name = package.pkg_name
69+
pkg_version = package.pkg_version
6570
if pkg_name is None and pkg_version is None:
6671
pkg_name, pkg_version = _get_cargo_metadata(app_path)
6772
assert pkg_name and pkg_version, "INVALID PACKAGE"
6873

74+
purl = _generate_purl_main_package(pkg_name, pkg_version, source_dir)
75+
6976
dependencies = []
70-
lock_file = app_path / (lock_file or DEFAULT_LOCK_FILE)
77+
lock_file = app_path / (package.lock_file or DEFAULT_LOCK_FILE)
7178

7279
cargo_lock_dict = tomli.load(lock_file.open("rb"))
7380
for dependency in cargo_lock_dict["package"]:
@@ -78,7 +85,7 @@ def _resolve_cargo(
7885

7986
dependencies = _download_cargo_dependencies(output_dir, dependencies)
8087
return {
81-
"package": {"name": pkg_name, "version": pkg_version, "type": "cargo"},
88+
"package": {"name": pkg_name, "version": pkg_version, "type": "cargo", "purl": purl},
8289
"dependencies": dependencies,
8390
"lock_file": lock_file,
8491
}
@@ -90,7 +97,9 @@ def _get_cargo_metadata(package_dir: Path):
9097
return metadata["package"]["name"], metadata["package"]["version"]
9198

9299

93-
def _download_cargo_dependencies(output_path: RootedPath, cargo_dependencies: list[dict]):
100+
def _download_cargo_dependencies(
101+
output_path: RootedPath, cargo_dependencies: list[dict]
102+
) -> list[dict[str, Any]]:
94103
downloads = []
95104
for dep in cargo_dependencies:
96105
checksum_info = ChecksumInfo(algorithm="sha256", hexdigest=dep["checksum"])
@@ -112,13 +121,16 @@ def _download_cargo_dependencies(output_path: RootedPath, cargo_dependencies: li
112121
"path": vendored_dep,
113122
"type": "cargo",
114123
"dev": False,
124+
"kind": "cratesio",
115125
}
116126
)
117127
return downloads
118128

129+
119130
def _calc_sha256(content: bytes):
120131
return hashlib.sha256(content).hexdigest()
121132

133+
122134
def generate_cargo_checksum(crate_path: Path):
123135
"""Generate Cargo checksums
124136
@@ -156,3 +168,55 @@ def prepare_crate_as_vendored_dep(crate_path: Path) -> Path:
156168
cargo_checksum = crate_path.parent / folder_name / ".cargo-checksum.json"
157169
json.dump(checksums, cargo_checksum.open("w"))
158170
return crate_path.parent / folder_name
171+
172+
173+
def _generate_purl_main_package(name: str, version: str, package_path: RootedPath) -> str:
174+
"""Get the purl for this package."""
175+
type = "cargo"
176+
url = get_repo_id(package_path.root).as_vcs_url_qualifier()
177+
qualifiers = {"vcs_url": url}
178+
if package_path.subpath_from_root != Path("."):
179+
subpath = package_path.subpath_from_root.as_posix()
180+
else:
181+
subpath = None
182+
183+
purl = PackageURL(
184+
type=type,
185+
name=name,
186+
version=version,
187+
qualifiers=qualifiers,
188+
subpath=subpath,
189+
)
190+
191+
return purl.to_string()
192+
193+
194+
def _generate_purl_dependency(package: dict[str, Any]) -> str:
195+
"""Get the purl for this dependency."""
196+
type = "cargo"
197+
name = package["name"]
198+
dependency_kind = package.get("kind", None)
199+
version = None
200+
qualifiers = None
201+
202+
if dependency_kind == "cratesio":
203+
version = package["version"]
204+
elif dependency_kind == "vcs":
205+
qualifiers = {"vcs_url": package["version"]}
206+
elif dependency_kind == "url":
207+
parsed_url = urllib.parse.urldefrag(package["version"])
208+
fragments = urllib.parse.parse_qs(parsed_url.fragment)
209+
checksum = fragments["cachito_hash"][0]
210+
qualifiers = {"download_url": parsed_url.url, "checksum": checksum}
211+
else:
212+
# Should not happen
213+
raise RuntimeError(f"Unexpected requirement kind: {dependency_kind}")
214+
215+
purl = PackageURL(
216+
type=type,
217+
name=name,
218+
version=version,
219+
qualifiers=qualifiers,
220+
)
221+
222+
return purl.to_string()

0 commit comments

Comments
 (0)