Skip to content

Commit 5660db7

Browse files
committed
lib: rustfmt output to stdout
Simplify the rustfmt and write mechanism. Use rustfmt generated string to allow writing to stdout or to rustfmt a file.
1 parent 208b98a commit 5660db7

File tree

1 file changed

+80
-45
lines changed

1 file changed

+80
-45
lines changed

src/lib.rs

+80-45
Original file line numberDiff line numberDiff line change
@@ -1626,18 +1626,15 @@ impl Bindings {
16261626

16271627
/// Write these bindings as source text to a file.
16281628
pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
1629-
{
1630-
let file = try!(
1631-
OpenOptions::new()
1632-
.write(true)
1633-
.truncate(true)
1634-
.create(true)
1635-
.open(path.as_ref())
1636-
);
1637-
self.write(Box::new(file))?;
1638-
}
1639-
1640-
self.rustfmt_generated_file(path.as_ref())
1629+
let file = try!(
1630+
OpenOptions::new()
1631+
.write(true)
1632+
.truncate(true)
1633+
.create(true)
1634+
.open(path.as_ref())
1635+
);
1636+
self.write(Box::new(file))?;
1637+
Ok(())
16411638
}
16421639

16431640
/// Write these bindings as source text to the given `Write`able.
@@ -1650,31 +1647,50 @@ impl Bindings {
16501647
writer.write(line.as_bytes())?;
16511648
writer.write("\n".as_bytes())?;
16521649
}
1650+
16531651
if !self.options.raw_lines.is_empty() {
16541652
writer.write("\n".as_bytes())?;
16551653
}
16561654

1657-
writer.write(self.module.as_str().as_bytes())?;
1655+
let bindings = self.module.as_str().to_string();
1656+
1657+
match self.rustfmt_generated_string(bindings) {
1658+
Ok(rustfmt_bindings) => {
1659+
writer.write(rustfmt_bindings.as_str().as_bytes())?;
1660+
},
1661+
Err(err) => eprintln!("{:?}", err),
1662+
}
16581663
Ok(())
16591664
}
16601665

1661-
/// Checks if rustfmt_bindings is set and runs rustfmt on the file
1662-
fn rustfmt_generated_file(&self, file: &Path) -> io::Result<()> {
1663-
let _t = time::Timer::new("rustfmt_generated_file")
1666+
/// Checks if rustfmt_bindings is set and runs rustfmt on the string
1667+
fn rustfmt_generated_string(&self, source: String) -> io::Result<String> {
1668+
let _t = time::Timer::new("rustfmt_generated_string")
16641669
.with_output(self.options.time_phases);
16651670

16661671
if !self.options.rustfmt_bindings {
1667-
return Ok(());
1672+
return Ok(source);
16681673
}
16691674

16701675
let rustfmt = if let Ok(rustfmt) = which::which("rustfmt") {
16711676
rustfmt
16721677
} else {
1673-
warn!("Not running rustfmt because it does not exist in PATH");
1674-
return Ok(());
1678+
eprintln!("warning: could not find usable rustfmt to pretty print bindings");
1679+
return Ok(source);
1680+
};
1681+
1682+
let mut cmd = if let Ok(rustup) = which::which("rustup") {
1683+
let mut cmd = Command::new(rustup);
1684+
cmd.args(&["run", "nightly", "rustfmt", "--"]);
1685+
cmd
1686+
} else {
1687+
Command::new(rustfmt)
16751688
};
16761689

1677-
let mut cmd = Command::new(rustfmt);
1690+
cmd
1691+
.args(&["--write-mode=display"])
1692+
.stdin(Stdio::piped())
1693+
.stdout(Stdio::piped());
16781694

16791695
if let Some(path) = self.options
16801696
.rustfmt_configuration_file
@@ -1684,34 +1700,53 @@ impl Bindings {
16841700
cmd.args(&["--config-path", path]);
16851701
}
16861702

1687-
if let Ok(output) = cmd.arg(file).output() {
1688-
if !output.status.success() {
1689-
let stderr = String::from_utf8_lossy(&output.stderr);
1690-
match output.status.code() {
1691-
Some(2) => Err(io::Error::new(
1692-
io::ErrorKind::Other,
1693-
format!("Rustfmt parsing errors:\n{}", stderr),
1694-
)),
1695-
Some(3) => {
1696-
warn!(
1697-
"Rustfmt could not format some lines:\n{}",
1698-
stderr
1699-
);
1700-
Ok(())
1703+
if let Ok(mut child) = cmd.spawn() {
1704+
1705+
let mut child_stdin = child.stdin.take().unwrap();
1706+
let mut child_stdout = child.stdout.take().unwrap();
1707+
1708+
// Write to stdin in a new thread, so that we can read from stdout on this
1709+
// thread. This keeps the child from blocking on writing to its stdout which
1710+
// might block us from writing to its stdin.
1711+
let stdin_handle = ::std::thread::spawn(move || {
1712+
let _ = child_stdin.write_all(source.as_bytes());
1713+
1714+
source
1715+
});
1716+
1717+
let mut output = vec![];
1718+
io::copy(&mut child_stdout, &mut output)?;
1719+
1720+
let status = child.wait()?;
1721+
1722+
let source = stdin_handle.join().unwrap();
1723+
1724+
match String::from_utf8(output) {
1725+
Ok(bindings) => {
1726+
if !status.success() {
1727+
match status.code() {
1728+
Some(2) => Err(io::Error::new(
1729+
io::ErrorKind::Other,
1730+
format!("Rustfmt parsing errors."),
1731+
)),
1732+
Some(3) => {
1733+
warn!("Rustfmt could not format some lines.");
1734+
Ok(bindings)
1735+
}
1736+
_ => Err(io::Error::new(
1737+
io::ErrorKind::Other,
1738+
format!("Internal rustfmt error"),
1739+
)),
1740+
}
1741+
} else {
1742+
Ok(bindings)
17011743
}
1702-
_ => Err(io::Error::new(
1703-
io::ErrorKind::Other,
1704-
format!("Internal rustfmt error:\n{}", stderr),
1705-
)),
1706-
}
1707-
} else {
1708-
Ok(())
1744+
},
1745+
_ => Ok(source)
17091746
}
17101747
} else {
1711-
Err(io::Error::new(
1712-
io::ErrorKind::Other,
1713-
"Error executing rustfmt!",
1714-
))
1748+
eprintln!("Error executing rustfmt!");
1749+
Ok(source)
17151750
}
17161751
}
17171752
}

0 commit comments

Comments
 (0)