import json import subprocess from typing import Any from pathlib import Path import tomli # YYC MARK: # We use `tomli` with at least 2.4.0 version by design. # Considering that Cargo has approve the change allowing TOML 1.1 syntax in `Cargo.toml`, # Python embedded `toml` package, which only support TOML 1.0 syntax until Python 3.15, # is not suit for parsing `Cargo.toml` in future. # So we use the upstream of official `toml` package, i.e. `tomli` as our solution. # And according to the document if `tomli`, the version starting support TOML 1.1 syntax is 2.4.0. _TOKEN_PACKAGES: str = "packages" _TOKEN_PACKAGE_MANIFEST_PATH: str = "manifest_path" _TOKEN_TARGET_DIRECTORY: str = "target_directory" class Metadata: __cargo_toml_path: Path __cargo_metadata: dict[str, Any] __cargo_toml: dict[str, Any] def __init__(self, cargo_toml: Path) -> None: self.__cargo_toml_path = cargo_toml self.__cargo_toml = Metadata.__extract_cargo_toml(cargo_toml) self.__cargo_metadata = Metadata.__extract_cargo_metadata(cargo_toml) @staticmethod def __extract_cargo_toml(cargo_toml: Path) -> dict[str, Any]: with open(cargo_toml, "rb") as f: return tomli.load(f) @staticmethod def __extract_cargo_metadata(cargo_toml: Path) -> dict[str, Any]: cmd = [ "cargo", "metadata", "--no-deps", "--format-version", "1", "--manifest-path", str(cargo_toml), ] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: stdout, stderr = proc.communicate(timeout=10) except subprocess.TimeoutExpired: proc.kill() proc.communicate() raise RuntimeError("fail to fetch cargo metadata: timed out") if proc.returncode != 0: raise RuntimeError( "fail to fetch cargo metadata: " + stderr.decode("utf-8", errors="ignore") ) else: return json.loads(stdout)