@@ -1652,18 +1652,13 @@ impl Bindings {
1652
1652
1653
1653
/// Write these bindings as source text to a file.
1654
1654
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 ( ( ) )
1667
1662
}
1668
1663
1669
1664
/// Write these bindings as source text to the given `Write`able.
@@ -1676,31 +1671,52 @@ impl Bindings {
1676
1671
writer. write ( line. as_bytes ( ) ) ?;
1677
1672
writer. write ( "\n " . as_bytes ( ) ) ?;
1678
1673
}
1674
+
1679
1675
if !self . options . raw_lines . is_empty ( ) {
1680
1676
writer. write ( "\n " . as_bytes ( ) ) ?;
1681
1677
}
1682
1678
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
+ }
1684
1687
Ok ( ( ) )
1685
1688
}
1686
1689
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 " )
1690
1693
. with_output ( self . options . time_phases ) ;
1691
1694
1692
1695
if !self . options . rustfmt_bindings {
1693
- return Ok ( ( ) ) ;
1696
+ return Ok ( source ) ;
1694
1697
}
1695
1698
1696
1699
let rustfmt = if let Ok ( rustfmt) = which:: which ( "rustfmt" ) {
1697
1700
rustfmt
1698
1701
} 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)
1701
1714
} ;
1702
1715
1703
- let mut cmd = Command :: new ( rustfmt) ;
1716
+ cmd
1717
+ . args ( & [ "--write-mode=display" ] )
1718
+ . stdin ( Stdio :: piped ( ) )
1719
+ . stdout ( Stdio :: piped ( ) ) ;
1704
1720
1705
1721
if let Some ( path) = self . options
1706
1722
. rustfmt_configuration_file
@@ -1710,34 +1726,52 @@ impl Bindings {
1710
1726
cmd. args ( & [ "--config-path" , path] ) ;
1711
1727
}
1712
1728
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)
1732
1769
}
1733
- } else {
1734
- Ok ( ( ) )
1735
1770
}
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
+ }
1741
1775
}
1742
1776
}
1743
1777
}
0 commit comments