Skip to content

Commit f661f58

Browse files
author
bors-servo
authored
Auto merge of #1109 - fitzgen:rustfmt-stdout, r=fitzgen
lib: rustfmt output to stdout *(Recreated + slightly touched up version of #1042 + a version bump)* Simplify the rustfmt and write mechanism. Use rustfmt generated string to allow writing to stdout or to rustfmt a file.
2 parents a08d8fd + 849c41d commit f661f58

File tree

5 files changed

+86
-48
lines changed

5 files changed

+86
-48
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ name = "bindgen"
1313
readme = "README.md"
1414
repository = "https://github.com/rust-lang-nursery/rust-bindgen"
1515
documentation = "https://docs.rs/bindgen"
16-
version = "0.30.1"
16+
version = "0.31.0"
1717
build = "build.rs"
1818

1919
include = [

src/lib.rs

+80-46
Original file line numberDiff line numberDiff line change
@@ -1652,18 +1652,13 @@ impl Bindings {
16521652

16531653
/// Write these bindings as source text to a file.
16541654
pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
1655-
{
1656-
let file = try!(
1657-
OpenOptions::new()
1658-
.write(true)
1659-
.truncate(true)
1660-
.create(true)
1661-
.open(path.as_ref())
1662-
);
1663-
self.write(Box::new(file))?;
1664-
}
1665-
1666-
self.rustfmt_generated_file(path.as_ref())
1655+
let file = OpenOptions::new()
1656+
.write(true)
1657+
.truncate(true)
1658+
.create(true)
1659+
.open(path.as_ref())?;
1660+
self.write(Box::new(file))?;
1661+
Ok(())
16671662
}
16681663

16691664
/// Write these bindings as source text to the given `Write`able.
@@ -1676,31 +1671,52 @@ impl Bindings {
16761671
writer.write(line.as_bytes())?;
16771672
writer.write("\n".as_bytes())?;
16781673
}
1674+
16791675
if !self.options.raw_lines.is_empty() {
16801676
writer.write("\n".as_bytes())?;
16811677
}
16821678

1683-
writer.write(self.module.as_str().as_bytes())?;
1679+
let bindings = self.module.as_str().to_string();
1680+
1681+
match self.rustfmt_generated_string(bindings) {
1682+
Ok(rustfmt_bindings) => {
1683+
writer.write(rustfmt_bindings.as_str().as_bytes())?;
1684+
},
1685+
Err(err) => eprintln!("{:?}", err),
1686+
}
16841687
Ok(())
16851688
}
16861689

1687-
/// Checks if rustfmt_bindings is set and runs rustfmt on the file
1688-
fn rustfmt_generated_file(&self, file: &Path) -> io::Result<()> {
1689-
let _t = time::Timer::new("rustfmt_generated_file")
1690+
/// Checks if rustfmt_bindings is set and runs rustfmt on the string
1691+
fn rustfmt_generated_string(&self, source: String) -> io::Result<String> {
1692+
let _t = time::Timer::new("rustfmt_generated_string")
16901693
.with_output(self.options.time_phases);
16911694

16921695
if !self.options.rustfmt_bindings {
1693-
return Ok(());
1696+
return Ok(source);
16941697
}
16951698

16961699
let rustfmt = if let Ok(rustfmt) = which::which("rustfmt") {
16971700
rustfmt
16981701
} else {
1699-
warn!("Not running rustfmt because it does not exist in PATH");
1700-
return Ok(());
1702+
eprintln!("warning: could not find usable rustfmt to pretty print bindings");
1703+
return Ok(source);
1704+
};
1705+
1706+
// Prefer using the `rustfmt-nightly` version of `rustmft`, if
1707+
// possible. It requires being run via `rustup run nightly ...`.
1708+
let mut cmd = if let Ok(rustup) = which::which("rustup") {
1709+
let mut cmd = Command::new(rustup);
1710+
cmd.args(&["run", "nightly", "rustfmt", "--"]);
1711+
cmd
1712+
} else {
1713+
Command::new(rustfmt)
17011714
};
17021715

1703-
let mut cmd = Command::new(rustfmt);
1716+
cmd
1717+
.args(&["--write-mode=display"])
1718+
.stdin(Stdio::piped())
1719+
.stdout(Stdio::piped());
17041720

17051721
if let Some(path) = self.options
17061722
.rustfmt_configuration_file
@@ -1710,34 +1726,52 @@ impl Bindings {
17101726
cmd.args(&["--config-path", path]);
17111727
}
17121728

1713-
if let Ok(output) = cmd.arg(file).output() {
1714-
if !output.status.success() {
1715-
let stderr = String::from_utf8_lossy(&output.stderr);
1716-
match output.status.code() {
1717-
Some(2) => Err(io::Error::new(
1718-
io::ErrorKind::Other,
1719-
format!("Rustfmt parsing errors:\n{}", stderr),
1720-
)),
1721-
Some(3) => {
1722-
warn!(
1723-
"Rustfmt could not format some lines:\n{}",
1724-
stderr
1725-
);
1726-
Ok(())
1727-
}
1728-
_ => Err(io::Error::new(
1729-
io::ErrorKind::Other,
1730-
format!("Internal rustfmt error:\n{}", stderr),
1731-
)),
1729+
match cmd.spawn() {
1730+
Ok(mut child) => {
1731+
let mut child_stdin = child.stdin.take().unwrap();
1732+
let mut child_stdout = child.stdout.take().unwrap();
1733+
1734+
// Write to stdin in a new thread, so that we can read from stdout on this
1735+
// thread. This keeps the child from blocking on writing to its stdout which
1736+
// might block us from writing to its stdin.
1737+
let stdin_handle = ::std::thread::spawn(move || {
1738+
let _ = child_stdin.write_all(source.as_bytes());
1739+
source
1740+
});
1741+
1742+
let mut output = vec![];
1743+
io::copy(&mut child_stdout, &mut output)?;
1744+
1745+
let status = child.wait()?;
1746+
let source = stdin_handle.join()
1747+
.expect("The thread writing to rustfmt's stdin doesn't do \
1748+
anything that could panic");
1749+
1750+
match String::from_utf8(output) {
1751+
Ok(bindings) => {
1752+
match status.code() {
1753+
Some(0) => Ok(bindings),
1754+
Some(2) => Err(io::Error::new(
1755+
io::ErrorKind::Other,
1756+
"Rustfmt parsing errors.".to_string(),
1757+
)),
1758+
Some(3) => {
1759+
warn!("Rustfmt could not format some lines.");
1760+
Ok(bindings)
1761+
}
1762+
_ => Err(io::Error::new(
1763+
io::ErrorKind::Other,
1764+
"Internal rustfmt error".to_string(),
1765+
)),
1766+
}
1767+
},
1768+
_ => Ok(source)
17321769
}
1733-
} else {
1734-
Ok(())
17351770
}
1736-
} else {
1737-
Err(io::Error::new(
1738-
io::ErrorKind::Other,
1739-
"Error executing rustfmt!",
1740-
))
1771+
Err(e) => {
1772+
eprintln!("Error spawning rustfmt: {}", e);
1773+
Ok(source)
1774+
}
17411775
}
17421776
}
17431777
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

tests/tests.rs

+3
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ fn create_bindgen_builder(header: &PathBuf) -> Result<Option<Builder>, Error> {
256256

257257
let prepend = [
258258
"bindgen",
259+
// We format in `compare_generated_header` ourselves to have a little
260+
// more control.
261+
"--no-rustfmt-bindings",
259262
"--with-derive-default",
260263
header_str,
261264
"--raw-line",

0 commit comments

Comments
 (0)