diff --git a/src/fromager/vendor_rust.py b/src/fromager/vendor_rust.py index 14e409bf..2798b9be 100644 --- a/src/fromager/vendor_rust.py +++ b/src/fromager/vendor_rust.py @@ -86,28 +86,27 @@ def _cargo_config(project_dir: pathlib.Path) -> None: tomlkit.dump(cfg, f) -def _should_vendor_rust(req: Requirement, project_dir: pathlib.Path) -> bool: +def _detect_rust_build_backend( + req: Requirement, pyproject_toml: dict[str, typing.Any] +) -> str | None: """Detect if project has build requirement on Rust Detects setuptools-rust and maturin. """ - pyproject_toml = dependencies.get_pyproject_contents(project_dir) - if not pyproject_toml: - logger.debug(f"{req.name}: has no pyproject.toml") - return False - build_backend = dependencies.get_build_backend(pyproject_toml) + if build_backend["build-backend"] == "maturin": + return "maturin" for reqstring in build_backend["requires"]: req = Requirement(reqstring) if req.name in RUST_BUILD_REQUIRES: logger.debug( - f"{req.name}: build-system requires {req.name}, vendoring crates" + f"{req.name}: build-system requires '{req.name}', vendoring crates" ) - return True + return req.name logger.debug(f"{req.name}: no Rust build plugin detected") - return False + return None def vendor_rust( @@ -119,11 +118,42 @@ def vendor_rust( ``setuptools-rust`` or ``maturin``, and has a ``Cargo.toml``, otherwise ``False``. """ - if not _should_vendor_rust(req, project_dir): + pyproject_toml = dependencies.get_pyproject_contents(project_dir) + if not pyproject_toml: + logger.debug(f"{req.name}: has no pyproject.toml") return False - # check for Cargo.toml - manifests = list(project_dir.glob("**/Cargo.toml")) + backend = _detect_rust_build_backend(req, pyproject_toml) + if backend is None: + return False + + manifests: list[pathlib.Path] = [] + # check for Cargo.toml in project root + root_cargo_toml = project_dir / "Cargo.toml" + if root_cargo_toml.is_file(): + manifests.append(root_cargo_toml) + + # maturin and setuptools-rust can have Cargo.toml in other directories. + # tool.setuptools-rust and tool.maturin are optional. + if backend == "maturin": + try: + tool_maturin: dict[str, typing.Any] = pyproject_toml["tool"]["maturin"] + except KeyError as e: + logger.debug(f"{req.name}: No additional maturin settings: {e}") + else: + if "manifest-path" in tool_maturin: + manifests.append(project_dir / tool_maturin["manifest-path"]) + elif backend == "setuptools-rust": + ext_modules: list[dict[str, typing.Any]] + try: + ext_modules = pyproject_toml["tool"]["setuptools-rust"]["ext-modules"] + except KeyError as e: + logger.debug(f"{req.name}: No additional setuptools-rust settings: {e}") + else: + for ext_module in ext_modules: + if "path" in ext_module: + manifests.append(project_dir / ext_module["path"]) + if not manifests: logger.debug(f"{req.name}: has no Cargo.toml files") return False