Skip to content

Commit eec7e9c

Browse files
committed
Fix vendor Rust: limit to manifests from backend
Fromager was vendoring crates from all `Cargo.toml` files in a project. This approach is causing issues for projects that have cargo files in tests and example directories. The `vendor_rust()` function now only vendors crates from `Cargo.toml` in the project's root directory and additional cargo files listed in `tools.maturin` or `tools.setuptools-rust` entries. Fixes: #529 Signed-off-by: Christian Heimes <[email protected]>
1 parent c84ee7a commit eec7e9c

File tree

1 file changed

+42
-12
lines changed

1 file changed

+42
-12
lines changed

src/fromager/vendor_rust.py

+42-12
Original file line numberDiff line numberDiff line change
@@ -86,28 +86,27 @@ def _cargo_config(project_dir: pathlib.Path) -> None:
8686
tomlkit.dump(cfg, f)
8787

8888

89-
def _should_vendor_rust(req: Requirement, project_dir: pathlib.Path) -> bool:
89+
def _detect_rust_build_backend(
90+
req: Requirement, pyproject_toml: dict[str, typing.Any]
91+
) -> str | None:
9092
"""Detect if project has build requirement on Rust
9193
9294
Detects setuptools-rust and maturin.
9395
"""
94-
pyproject_toml = dependencies.get_pyproject_contents(project_dir)
95-
if not pyproject_toml:
96-
logger.debug(f"{req.name}: has no pyproject.toml")
97-
return False
98-
9996
build_backend = dependencies.get_build_backend(pyproject_toml)
97+
if build_backend["build-backend"] == "maturin":
98+
return "maturin"
10099

101100
for reqstring in build_backend["requires"]:
102101
req = Requirement(reqstring)
103102
if req.name in RUST_BUILD_REQUIRES:
104103
logger.debug(
105-
f"{req.name}: build-system requires {req.name}, vendoring crates"
104+
f"{req.name}: build-system requires '{req.name}', vendoring crates"
106105
)
107-
return True
106+
return req.name
108107

109108
logger.debug(f"{req.name}: no Rust build plugin detected")
110-
return False
109+
return None
111110

112111

113112
def vendor_rust(
@@ -119,11 +118,42 @@ def vendor_rust(
119118
``setuptools-rust`` or ``maturin``, and has a ``Cargo.toml``, otherwise
120119
``False``.
121120
"""
122-
if not _should_vendor_rust(req, project_dir):
121+
pyproject_toml = dependencies.get_pyproject_contents(project_dir)
122+
if not pyproject_toml:
123+
logger.debug(f"{req.name}: has no pyproject.toml")
123124
return False
124125

125-
# check for Cargo.toml
126-
manifests = list(project_dir.glob("**/Cargo.toml"))
126+
backend = _detect_rust_build_backend(req, pyproject_toml)
127+
if backend is None:
128+
return False
129+
130+
manifests: list[pathlib.Path] = []
131+
# check for Cargo.toml in project root
132+
root_cargo_toml = project_dir / "Cargo.toml"
133+
if root_cargo_toml.is_file():
134+
manifests.append(root_cargo_toml)
135+
136+
# maturin and setuptools-rust can have Cargo.toml in other directories.
137+
# tool.setuptools-rust and tool.maturin are optional.
138+
if backend == "maturin":
139+
try:
140+
tool_maturin: dict[str, typing.Any] = pyproject_toml["tool"]["maturin"]
141+
except KeyError as e:
142+
logger.debug(f"{req.name}: No additional maturin settings: {e}")
143+
else:
144+
if "manifest-path" in tool_maturin:
145+
manifests.append(project_dir / tool_maturin["manifest-path"])
146+
elif backend == "setuptools-rust":
147+
ext_modules: list[dict[str, typing.Any]]
148+
try:
149+
ext_modules = pyproject_toml["tool"]["setuptools-rust"]["ext-modules"]
150+
except KeyError as e:
151+
logger.debug(f"{req.name}: No additional setuptools-rust settings: {e}")
152+
else:
153+
for ext_module in ext_modules:
154+
if "path" in ext_module:
155+
manifests.append(project_dir / ext_module["path"])
156+
127157
if not manifests:
128158
logger.debug(f"{req.name}: has no Cargo.toml files")
129159
return False

0 commit comments

Comments
 (0)