Skip to content

Commit 55211d9

Browse files
authored
Merge pull request #256 from davidhewitt/error-quiet
respect `quiet` flag in `cargo metadata`
2 parents fdd3d52 + 7d50d9b commit 55211d9

File tree

4 files changed

+55
-34
lines changed

4 files changed

+55
-34
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
### Changed
1313
- `Exec` binding `RustExtension` with `script=True` is deprecated in favor of `RustBin`. [#248](https://github.com/PyO3/setuptools-rust/pull/248)
14+
- Errors while calling `cargo metadata` are now reported back to the user [#254](https://github.com/PyO3/setuptools-rust/pull/254)
15+
- `quiet` option will now suppress output of `cargo metadata`. [#256](https://github.com/PyO3/setuptools-rust/pull/256)
1416

1517
### Fixed
1618
- If the sysconfig for `BLDSHARED` has no flags, `setuptools-rust` won't crash anymore. [#241](https://github.com/PyO3/setuptools-rust/pull/241)

setuptools_rust/build.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from .command import RustCommand
2424
from .extension import RustBin, RustExtension, Strip
25+
from .private import format_called_process_error
2526
from .utils import (
2627
PyLimitedApi,
2728
binding_features,
@@ -139,13 +140,14 @@ def build_extension(
139140
f"can't find Rust extension project file: {ext.path}"
140141
)
141142

143+
quiet = self.qbuild or ext.quiet
144+
debug = self._is_debug_build(ext)
145+
142146
# Find where to put the temporary build files created by `cargo`
143-
target_dir = _base_cargo_target_dir(ext)
147+
target_dir = _base_cargo_target_dir(ext, quiet=quiet)
144148
if target_triple is not None:
145149
target_dir = os.path.join(target_dir, target_triple)
146150

147-
quiet = self.qbuild or ext.quiet
148-
debug = self._is_debug_build(ext)
149151
cargo_args = self._cargo_args(
150152
ext=ext, target_triple=target_triple, release=not debug, quiet=quiet
151153
)
@@ -210,21 +212,12 @@ def build_extension(
210212

211213
# Execute cargo
212214
try:
215+
stderr = subprocess.PIPE if quiet else None
213216
output = subprocess.check_output(
214-
command, env=env, encoding="latin-1", stderr=subprocess.PIPE
217+
command, env=env, encoding="latin-1", stderr=stderr
215218
)
216219
except subprocess.CalledProcessError as e:
217-
raise CompileError(
218-
f"""
219-
cargo failed with code: {e.returncode}
220-
221-
Output captured from stderr:
222-
{e.stderr}
223-
224-
Output captured from stdout:
225-
{e.stdout}
226-
"""
227-
)
220+
raise CompileError(format_called_process_error(e))
228221

229222
except OSError:
230223
raise DistutilsExecError(
@@ -280,7 +273,7 @@ def build_extension(
280273
else:
281274
dylib_ext = "so"
282275

283-
wildcard_so = "*{}.{}".format(ext.get_lib_name(), dylib_ext)
276+
wildcard_so = "*{}.{}".format(ext.get_lib_name(quiet=quiet), dylib_ext)
284277

285278
try:
286279
dylib_paths.append(
@@ -711,13 +704,13 @@ def _prepare_build_environment(cross_lib: Optional[str]) -> Dict[str, str]:
711704
return env
712705

713706

714-
def _base_cargo_target_dir(ext: RustExtension) -> str:
707+
def _base_cargo_target_dir(ext: RustExtension, *, quiet: bool) -> str:
715708
"""Returns the root target directory cargo will use.
716709
717710
If --target is passed to cargo in the command line, the target directory
718711
will have the target appended as a child.
719712
"""
720-
target_directory = ext._metadata()["target_directory"]
713+
target_directory = ext._metadata(quiet=quiet)["target_directory"]
721714
assert isinstance(
722715
target_directory, str
723716
), "expected cargo metadata to contain a string target directory"

setuptools_rust/extension.py

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import json
22
import os
33
import re
4-
import warnings
54
import subprocess
5+
import warnings
66
from distutils.errors import DistutilsSetupError
77
from enum import IntEnum, auto
88
from typing import Any, Dict, List, NewType, Optional, Union
99

1010
from semantic_version import SimpleSpec
1111
from typing_extensions import Literal
1212

13+
from .private import format_called_process_error
14+
1315

1416
class Binding(IntEnum):
1517
"""
@@ -167,9 +169,9 @@ def __init__(
167169
DeprecationWarning,
168170
)
169171

170-
def get_lib_name(self) -> str:
172+
def get_lib_name(self, *, quiet: bool) -> str:
171173
"""Parse Cargo.toml to get the name of the shared library."""
172-
metadata = self._metadata()
174+
metadata = self._metadata(quiet=quiet)
173175
root_key = metadata["resolve"]["root"]
174176
[pkg] = [p for p in metadata["packages"] if p["id"] == root_key]
175177
name = pkg["targets"][0]["name"]
@@ -224,7 +226,7 @@ def install_script(self, module_name: str, exe_path: str) -> None:
224226
with open(file, "w") as f:
225227
f.write(_SCRIPT_TEMPLATE.format(executable=repr(executable)))
226228

227-
def _metadata(self) -> "_CargoMetadata":
229+
def _metadata(self, *, quiet: bool) -> "_CargoMetadata":
228230
"""Returns cargo metedata for this extension package.
229231
230232
Cached - will only execute cargo on first invocation.
@@ -242,21 +244,12 @@ def _metadata(self) -> "_CargoMetadata":
242244
metadata_command.extend(self.cargo_manifest_args)
243245

244246
try:
247+
stderr = subprocess.PIPE if quiet else None
245248
payload = subprocess.check_output(
246-
metadata_command, encoding="latin-1", stderr=subprocess.PIPE
249+
metadata_command, encoding="latin-1", stderr=stderr
247250
)
248251
except subprocess.CalledProcessError as e:
249-
raise DistutilsSetupError(
250-
f"""
251-
cargo metadata failed with code: {e.returncode}
252-
253-
Output captured from stderr:
254-
{e.stderr}
255-
256-
Output captured from stdout:
257-
{e.stdout}
258-
"""
259-
)
252+
raise DistutilsSetupError(format_called_process_error(e))
260253
try:
261254
self._cargo_metadata = json.loads(payload)
262255
except json.decoder.JSONDecodeError as e:

setuptools_rust/private.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import subprocess
2+
3+
4+
def format_called_process_error(e: subprocess.CalledProcessError) -> str:
5+
"""Helper to convert a CalledProcessError to an error message.
6+
7+
>>> format_called_process_error(subprocess.CalledProcessError(
8+
... 1, ['cargo', 'foo bar'], 'message', None
9+
... ))
10+
"`cargo 'foo bar'` failed with code 1\\n-- Output captured from stdout:\\nmessage"
11+
>>> format_called_process_error(subprocess.CalledProcessError(
12+
... -1, ['cargo'], 'stdout', 'stderr'
13+
... ))
14+
'`cargo` failed with code -1\\n-- Output captured from stdout:\\nstdout\\n-- Output captured from stderr:\\nstderr'
15+
"""
16+
command = " ".join(_quote_whitespace(arg) for arg in e.cmd)
17+
message = f"""`{command}` failed with code {e.returncode}
18+
-- Output captured from stdout:
19+
{e.stdout}"""
20+
21+
if e.stderr is not None:
22+
message += f"""
23+
-- Output captured from stderr:
24+
{e.stderr}"""
25+
26+
return message
27+
28+
29+
def _quote_whitespace(string: str) -> str:
30+
if " " in string:
31+
return f"'{string}'"
32+
else:
33+
return string

0 commit comments

Comments
 (0)