mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00
State that arg in argfile must not contain newlines
This commit is contained in:
parent
beaaefd90a
commit
877c0add35
@ -37,6 +37,7 @@ pub struct ProcessBuilder {
|
|||||||
/// `true` to include environment variable in display.
|
/// `true` to include environment variable in display.
|
||||||
display_env_vars: bool,
|
display_env_vars: bool,
|
||||||
/// `true` to retry with an argfile if hitting "command line too big" error.
|
/// `true` to retry with an argfile if hitting "command line too big" error.
|
||||||
|
/// See [`ProcessBuilder::retry_with_argfile`] for more information.
|
||||||
retry_with_argfile: bool,
|
retry_with_argfile: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,6 +186,22 @@ impl ProcessBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Enables retrying with an argfile if hitting "command line too big" error
|
/// Enables retrying with an argfile if hitting "command line too big" error
|
||||||
|
///
|
||||||
|
/// This is primarily for the `@path` arg of rustc and rustdoc, which treat
|
||||||
|
/// each line as an command-line argument, so `LF` and `CRLF` bytes are not
|
||||||
|
/// valid as an argument for argfile at this moment.
|
||||||
|
/// For example, `RUSTDOCFLAGS="--crate-version foo\nbar" cargo doc` is
|
||||||
|
/// valid when invoking from command-line but not from argfile.
|
||||||
|
///
|
||||||
|
/// To sum up, the limitations of the argfile are:
|
||||||
|
///
|
||||||
|
/// - Must be valid UTF-8 encoded.
|
||||||
|
/// - Must not contain any newlines in each argument.
|
||||||
|
///
|
||||||
|
/// Ref:
|
||||||
|
///
|
||||||
|
/// - https://doc.rust-lang.org/rustdoc/command-line-arguments.html#path-load-command-line-flags-from-a-path
|
||||||
|
/// - https://doc.rust-lang.org/rustc/command-line-arguments.html#path-load-command-line-flags-from-a-path>
|
||||||
pub fn retry_with_argfile(&mut self, enabled: bool) -> &mut Self {
|
pub fn retry_with_argfile(&mut self, enabled: bool) -> &mut Self {
|
||||||
self.retry_with_argfile = enabled;
|
self.retry_with_argfile = enabled;
|
||||||
self
|
self
|
||||||
@ -393,11 +410,6 @@ impl ProcessBuilder {
|
|||||||
|
|
||||||
/// Builds the command with an `@<path>` argfile that contains all the
|
/// Builds the command with an `@<path>` argfile that contains all the
|
||||||
/// arguments. This is primarily served for rustc/rustdoc command family.
|
/// arguments. This is primarily served for rustc/rustdoc command family.
|
||||||
///
|
|
||||||
/// Ref:
|
|
||||||
///
|
|
||||||
/// - https://doc.rust-lang.org/rustdoc/command-line-arguments.html#path-load-command-line-flags-from-a-path
|
|
||||||
/// - https://doc.rust-lang.org/rustc/command-line-arguments.html#path-load-command-line-flags-from-a-path>
|
|
||||||
fn build_command_with_argfile(&self) -> io::Result<(Command, NamedTempFile)> {
|
fn build_command_with_argfile(&self) -> io::Result<(Command, NamedTempFile)> {
|
||||||
use std::io::Write as _;
|
use std::io::Write as _;
|
||||||
|
|
||||||
@ -411,21 +423,26 @@ impl ProcessBuilder {
|
|||||||
log::debug!("created argfile at {path} for `{self}`");
|
log::debug!("created argfile at {path} for `{self}`");
|
||||||
|
|
||||||
let cap = self.get_args().map(|arg| arg.len() + 1).sum::<usize>();
|
let cap = self.get_args().map(|arg| arg.len() + 1).sum::<usize>();
|
||||||
let mut buf = String::with_capacity(cap);
|
let mut buf = Vec::with_capacity(cap);
|
||||||
for arg in &self.args {
|
for arg in &self.args {
|
||||||
let arg = arg
|
let arg = arg.to_str().ok_or_else(|| {
|
||||||
.to_str()
|
io::Error::new(
|
||||||
.ok_or_else(|| {
|
io::ErrorKind::Other,
|
||||||
io::Error::new(
|
format!(
|
||||||
io::ErrorKind::Other,
|
"argument for argfile contains invalid UTF-8 characters: `{}`",
|
||||||
"argument contains invalid UTF-8 characters",
|
arg.to_string_lossy()
|
||||||
)
|
),
|
||||||
})?;
|
)
|
||||||
// TODO: Shall we escape line feed?
|
})?;
|
||||||
buf.push_str(arg);
|
if arg.contains('\n') {
|
||||||
buf.push('\n');
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("argument for argfile contains newlines: `{arg}`"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
writeln!(buf, "{arg}")?;
|
||||||
}
|
}
|
||||||
tmp.write_all(buf.as_bytes())?;
|
tmp.write_all(&mut buf)?;
|
||||||
Ok((cmd, tmp))
|
Ok((cmd, tmp))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,10 +569,11 @@ mod imp {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::ProcessBuilder;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_argfile() {
|
fn argfile_build_succeeds() {
|
||||||
let mut cmd = ProcessBuilder::new("echo");
|
let mut cmd = ProcessBuilder::new("echo");
|
||||||
cmd.args(["foo", "bar"].as_slice());
|
cmd.args(["foo", "bar"].as_slice());
|
||||||
let (cmd, argfile) = cmd.build_command_with_argfile().unwrap();
|
let (cmd, argfile) = cmd.build_command_with_argfile().unwrap();
|
||||||
@ -569,4 +587,39 @@ mod tests {
|
|||||||
let buf = fs::read_to_string(argfile.path()).unwrap();
|
let buf = fs::read_to_string(argfile.path()).unwrap();
|
||||||
assert_eq!(buf, "foo\nbar\n");
|
assert_eq!(buf, "foo\nbar\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn argfile_build_fails_if_arg_contains_newline() {
|
||||||
|
let mut cmd = ProcessBuilder::new("echo");
|
||||||
|
cmd.arg("foo\n");
|
||||||
|
let err = cmd.build_command_with_argfile().unwrap_err();
|
||||||
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
"argument for argfile contains newlines: `foo\n`"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn argfile_build_fails_if_arg_contains_invalid_utf8() {
|
||||||
|
let mut cmd = ProcessBuilder::new("echo");
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let invalid_arg = {
|
||||||
|
use std::os::windows::prelude::*;
|
||||||
|
std::ffi::OsString::from_wide(&[0x0066, 0x006f, 0xD800, 0x006f])
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
let invalid_arg = {
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
std::ffi::OsStr::from_bytes(&[0x66, 0x6f, 0x80, 0x6f]).to_os_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
cmd.arg(invalid_arg);
|
||||||
|
let err = cmd.build_command_with_argfile().unwrap_err();
|
||||||
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
"argument for argfile contains invalid UTF-8 characters: `fo<66>o`"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user