-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Retry command invocation with argfile #10546
Conversation
- Add `ProcessBuilder::output` and ProcessBuilder::status`, which are unopinionated version of `exec_*` (won't error out when exitcode > 0) - Add `ProcessBuilder::retry_with_argfile` to enable trying with argfile when hitting the "command line too big" error.
r? @ehuss (rust-highfive has picked a reviewer for you, use r? to override) |
a42104e
to
8278192
Compare
let (mut cmd, _argfile) = self.build_command_with_argfile()?; | ||
apply(&mut cmd); | ||
cmd.spawn() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't we closing / removing the tempfile before the process has completed, racing with the application that is accessing it?
And should we explicitly close the tempfile, identifying any errors from the clean up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let mut cmd = ProcessBuilder::new(self.path.as_path()).wrapped(self.wrapper.as_ref()); | ||
cmd.retry_with_argfile(true); | ||
cmd | ||
} | ||
|
||
/// Gets a process builder set up to use the found rustc version, with a wrapper if `Some`. | ||
pub fn workspace_process(&self) -> ProcessBuilder { | ||
ProcessBuilder::new(self.path.as_path()) | ||
let mut cmd = ProcessBuilder::new(self.path.as_path()) | ||
.wrapped(self.workspace_wrapper.as_ref()) | ||
.wrapped(self.wrapper.as_ref()) | ||
.wrapped(self.wrapper.as_ref()); | ||
cmd.retry_with_argfile(true); | ||
cmd | ||
} | ||
|
||
pub fn process_no_wrapper(&self) -> ProcessBuilder { | ||
ProcessBuilder::new(&self.path) | ||
let mut cmd = ProcessBuilder::new(&self.path); | ||
cmd.retry_with_argfile(true); | ||
cmd | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How comes retry_with_argfile
isn't chained
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I followed the existing pattern from both ProcessBuilder
and std::process::Command
. It is worth making it more chainable, but a dedicated PR should better IMO.
if let Some(argfile_path) = rustc.to_str().unwrap_or_default().strip_prefix("@") { | ||
// Because cargo in fix-proxy-mode might hit the command line size limit, | ||
// cargo fix need handle `@path` argfile for this special case. | ||
if argv.next().is_some() { | ||
bail!("argfile `@path` cannot be combined with other arguments"); | ||
} | ||
let contents = fs::read_to_string(argfile_path) | ||
.with_context(|| format!("failed to read argfile at `{argfile_path}`"))?; | ||
let mut iter = contents.lines().map(OsString::from); | ||
rustc = iter | ||
.next() | ||
.map(PathBuf::from) | ||
.ok_or_else(|| anyhow::anyhow!("expected rustc as first argument"))?; | ||
for arg in iter { | ||
handle_arg(arg)?; | ||
} | ||
} else { | ||
for arg in argv { | ||
handle_arg(arg)?; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Side note: While I'm assuming this is doing things like in other places, there is now the argfile crate
"argument contains invalid UTF-8 characters", | ||
) | ||
})?; | ||
writeln!(buf, "{}", ArgEscape::from(arg))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the other question to escaping is what do rustc and similar tools support?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is how rustc generates argfiles for ld. As I read it so far, they just follow the specification. rustc uses only newlines to determine so I guess escaping \r
\n
and \\
might be sufficient.
However, I found that rustc_driver just naively reads line by line from argfile, they won't do any unescaping. As long as rustc does nothing special and our primary use case is serving rustc, I decide to remove the escape part and error out if someone passes line feeds in, as you recommended earlier.
BTW there is a test case validating that behaviour, which unfortunately accept whitespaces in RUSTDOCFLAGS
.
cargo in fix-proxy-mode might read `@path` argfile as what rustc does. Therefore, we should collect info from `ProcessBuilder::get_args()`.
8278192
to
275b0c6
Compare
Addressed issues in review comments. Ready to re-review :)
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
@bors r+ |
📌 Commit 275b0c6 has been approved by |
☀️ Test successful - checks-actions |
Update cargo 11 commits in e2e2dddebe66dfc1403a312653557e332445308b..dba5baf4345858c591517b24801902a062c399f8 2022-04-05 17:04:53 +0000 to 2022-04-13 21:58:27 +0000 - Part 6 of RFC2906 - Switch the inheritance source from `workspace` to… (rust-lang/cargo#10564) - Part 5 of RFC2906 - Add support for inheriting `rust-version` (rust-lang/cargo#10563) - Add support for rustc --check-cfg well known names and values (rust-lang/cargo#10486) - Reserve filename `Cargo.toml.orig` in `cargo package` (rust-lang/cargo#10551) - Retry command invocation with argfile (rust-lang/cargo#10546) - Add a progress indicator for `cargo clean` (rust-lang/cargo#10236) - Ensure host units don't depend on Docscrape units, fixes rust-lang/cargo#10545 (rust-lang/cargo#10549) - Fix docs: Bindeps env vars are passed to build script at runtime (rust-lang/cargo#10550) - Part 4 of RFC2906 - Add support for inheriting `readme` (rust-lang/cargo#10548) - Part 3 of RFC2906 - Add support for inheriting `license-path`, and `depednency.path` (rust-lang/cargo#10538) - Bump to 0.63.0, update changelog (rust-lang/cargo#10544)
Update cargo 11 commits in e2e2dddebe66dfc1403a312653557e332445308b..dba5baf4345858c591517b24801902a062c399f8 2022-04-05 17:04:53 +0000 to 2022-04-13 21:58:27 +0000 - Part 6 of RFC2906 - Switch the inheritance source from `workspace` to… (rust-lang/cargo#10564) - Part 5 of RFC2906 - Add support for inheriting `rust-version` (rust-lang/cargo#10563) - Add support for rustc --check-cfg well known names and values (rust-lang/cargo#10486) - Reserve filename `Cargo.toml.orig` in `cargo package` (rust-lang/cargo#10551) - Retry command invocation with argfile (rust-lang/cargo#10546) - Add a progress indicator for `cargo clean` (rust-lang/cargo#10236) - Ensure host units don't depend on Docscrape units, fixes rust-lang/cargo#10545 (rust-lang/cargo#10549) - Fix docs: Bindeps env vars are passed to build script at runtime (rust-lang/cargo#10550) - Part 4 of RFC2906 - Add support for inheriting `readme` (rust-lang/cargo#10548) - Part 3 of RFC2906 - Add support for inheriting `license-path`, and `depednency.path` (rust-lang/cargo#10538) - Bump to 0.63.0, update changelog (rust-lang/cargo#10544)
Bump cargo-util version. #10546 made a semver-incompatible change to the API of `ProcessBuilder::get_args`. Unfortunately we did not catch that until it was published. This bumps the version of cargo-util to 0.2.1 to accommodate that change. Stable will get version 0.2.0 so that the changes on beta can be released as 0.2.1 in their own time. cc #10803
What does this PR try to resolve?
Fixes #10381
The goal is to invoke
rustc
andrustdoc
with@path
arg file as a fallback.Since the
-Zcheck-cfg-features
1 has already been implemented, in the foreseeable future cargo will probably hit the “command line too big” more often on Windows.rustdoc
andrustc
both support@path
argfile 23, so we can leverage the feature for the fallback logic.The idea behind this PR is that we put the retry logic in
ProcessBuilder::exec*
functions and reuse them as much as possible.How should we test and review this PR?
Review it commit by commit is recommended.
Argfile fallback is hard to tested with integration tests, so I added some unit tests for
cargo_util::ProcessBuilder
andcargo::ops::fix::FixArgs
.If you do want to test the support of argfile manually, a new environment variable
__CARGO_TEST_FORCE_ARGFILE
is added for the sake of forcing cargo to use argfile for rustc invocations. For example,__CARGO_TEST_FORCE_ARGFILE cargo test --test testsuite -- fix::
is usually a good start to test this feature.Additional information
Should we escape line feed when writing into argfile and unescape while reading? 82781929b8fffd65f363aab1549e1b8f6773920f implements that but I am not sure whether it is necessary.
Footnotes
https://doc.rust-lang.org/beta/cargo/reference/unstable.html?highlight=check#check-cfg-features ↩
https://doc.rust-lang.org/rustc/command-line-arguments.html#path-load-command-line-flags-from-a-path ↩
https://doc.rust-lang.org/rustdoc/command-line-arguments.html#path-load-command-line-flags-from-a-path ↩