Skip to content

Commit 066ea49

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 8582a90 commit 066ea49

File tree

1 file changed

+80
-45
lines changed

1 file changed

+80
-45
lines changed

src/lib.rs

Lines changed: 80 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,18 +1580,15 @@ impl Bindings {
15801580

15811581
/// Write these bindings as source text to a file.
15821582
pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
1583-
{
1584-
let file = try!(
1585-
OpenOptions::new()
1586-
.write(true)
1587-
.truncate(true)
1588-
.create(true)
1589-
.open(path.as_ref())
1590-
);
1591-
self.write(Box::new(file))?;
1592-
}
1593-
1594-
self.rustfmt_generated_file(path.as_ref())
1583+
let file = try!(
1584+
OpenOptions::new()
1585+
.write(true)
1586+
.truncate(true)
1587+
.create(true)
1588+
.open(path.as_ref())
1589+
);
1590+
self.write(Box::new(file))?;
1591+
Ok(())
15951592
}
15961593

15971594
/// Write these bindings as source text to the given `Write`able.
@@ -1604,31 +1601,50 @@ impl Bindings {
16041601
writer.write(line.as_bytes())?;
16051602
writer.write("\n".as_bytes())?;
16061603
}
1604+
16071605
if !self.options.raw_lines.is_empty() {
16081606
writer.write("\n".as_bytes())?;
16091607
}
16101608

1611-
writer.write(self.module.as_str().as_bytes())?;
1609+
let bindings = self.module.as_str().to_string();
1610+
1611+
match self.rustfmt_generated_string(bindings) {
1612+
Ok(rustfmt_bindings) => {
1613+
writer.write(rustfmt_bindings.as_str().as_bytes())?;
1614+
},
1615+
Err(err) => eprintln!("{:?}", err),
1616+
}
16121617
Ok(())
16131618
}
16141619

1615-
/// Checks if rustfmt_bindings is set and runs rustfmt on the file
1616-
fn rustfmt_generated_file(&self, file: &Path) -> io::Result<()> {
1617-
let _t = time::Timer::new("rustfmt_generated_file")
1620+
/// Checks if rustfmt_bindings is set and runs rustfmt on the string
1621+
fn rustfmt_generated_string(&self, source: String) -> io::Result<String> {
1622+
let _t = time::Timer::new("rustfmt_generated_string")
16181623
.with_output(self.options.time_phases);
16191624

16201625
if !self.options.rustfmt_bindings {
1621-
return Ok(());
1626+
return Ok(source);
16221627
}
16231628

16241629
let rustfmt = if let Ok(rustfmt) = which::which("rustfmt") {
16251630
rustfmt
16261631
} else {
1627-
warn!("Not running rustfmt because it does not exist in PATH");
1628-
return Ok(());
1632+
eprintln!("warning: could not find usable rustfmt to pretty print bindings");
1633+
return Ok(source);
1634+
};
1635+
1636+
let mut cmd = if let Ok(rustup) = which::which("rustup") {
1637+
let mut cmd = Command::new(rustup);
1638+
cmd.args(&["run", "nightly", "rustfmt", "--"]);
1639+
cmd
1640+
} else {
1641+
Command::new(rustfmt)
16291642
};
16301643

1631-
let mut cmd = Command::new(rustfmt);
1644+
cmd
1645+
.args(&["--write-mode=display"])
1646+
.stdin(Stdio::piped())
1647+
.stdout(Stdio::piped());
16321648

16331649
if let Some(path) = self.options
16341650
.rustfmt_configuration_file
@@ -1638,34 +1654,53 @@ impl Bindings {
16381654
cmd.args(&["--config-path", path]);
16391655
}
16401656

1641-
if let Ok(output) = cmd.arg(file).output() {
1642-
if !output.status.success() {
1643-
let stderr = String::from_utf8_lossy(&output.stderr);
1644-
match output.status.code() {
1645-
Some(2) => Err(io::Error::new(
1646-
io::ErrorKind::Other,
1647-
format!("Rustfmt parsing errors:\n{}", stderr),
1648-
)),
1649-
Some(3) => {
1650-
warn!(
1651-
"Rustfmt could not format some lines:\n{}",
1652-
stderr
1653-
);
1654-
Ok(())
1657+
if let Ok(mut child) = cmd.spawn() {
1658+
1659+
let mut child_stdin = child.stdin.take().unwrap();
1660+
let mut child_stdout = child.stdout.take().unwrap();
1661+
1662+
// Write to stdin in a new thread, so that we can read from stdout on this
1663+
// thread. This keeps the child from blocking on writing to its stdout which
1664+
// might block us from writing to its stdin.
1665+
let stdin_handle = ::std::thread::spawn(move || {
1666+
let _ = child_stdin.write_all(source.as_bytes());
1667+
1668+
source
1669+
});
1670+
1671+
let mut output = vec![];
1672+
io::copy(&mut child_stdout, &mut output)?;
1673+
1674+
let status = child.wait()?;
1675+
1676+
let source = stdin_handle.join().unwrap();
1677+
1678+
match String::from_utf8(output) {
1679+
Ok(bindings) => {
1680+
if !status.success() {
1681+
match status.code() {
1682+
Some(2) => Err(io::Error::new(
1683+
io::ErrorKind::Other,
1684+
format!("Rustfmt parsing errors."),
1685+
)),
1686+
Some(3) => {
1687+
warn!("Rustfmt could not format some lines.");
1688+
Ok(bindings)
1689+
}
1690+
_ => Err(io::Error::new(
1691+
io::ErrorKind::Other,
1692+
format!("Internal rustfmt error"),
1693+
)),
1694+
}
1695+
} else {
1696+
Ok(bindings)
16551697
}
1656-
_ => Err(io::Error::new(
1657-
io::ErrorKind::Other,
1658-
format!("Internal rustfmt error:\n{}", stderr),
1659-
)),
1660-
}
1661-
} else {
1662-
Ok(())
1698+
},
1699+
_ => Ok(source)
16631700
}
16641701
} else {
1665-
Err(io::Error::new(
1666-
io::ErrorKind::Other,
1667-
"Error executing rustfmt!",
1668-
))
1702+
eprintln!("Error executing rustfmt!");
1703+
Ok(source)
16691704
}
16701705
}
16711706
}

0 commit comments

Comments
 (0)