@@ -1626,18 +1626,15 @@ impl Bindings {
1626
1626
1627
1627
/// Write these bindings as source text to a file.
1628
1628
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 ( ( ) )
1641
1638
}
1642
1639
1643
1640
/// Write these bindings as source text to the given `Write`able.
@@ -1650,31 +1647,50 @@ impl Bindings {
1650
1647
writer. write ( line. as_bytes ( ) ) ?;
1651
1648
writer. write ( "\n " . as_bytes ( ) ) ?;
1652
1649
}
1650
+
1653
1651
if !self . options . raw_lines . is_empty ( ) {
1654
1652
writer. write ( "\n " . as_bytes ( ) ) ?;
1655
1653
}
1656
1654
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
+ }
1658
1663
Ok ( ( ) )
1659
1664
}
1660
1665
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 " )
1664
1669
. with_output ( self . options . time_phases ) ;
1665
1670
1666
1671
if !self . options . rustfmt_bindings {
1667
- return Ok ( ( ) ) ;
1672
+ return Ok ( source ) ;
1668
1673
}
1669
1674
1670
1675
let rustfmt = if let Ok ( rustfmt) = which:: which ( "rustfmt" ) {
1671
1676
rustfmt
1672
1677
} 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)
1675
1688
} ;
1676
1689
1677
- let mut cmd = Command :: new ( rustfmt) ;
1690
+ cmd
1691
+ . args ( & [ "--write-mode=display" ] )
1692
+ . stdin ( Stdio :: piped ( ) )
1693
+ . stdout ( Stdio :: piped ( ) ) ;
1678
1694
1679
1695
if let Some ( path) = self . options
1680
1696
. rustfmt_configuration_file
@@ -1684,34 +1700,53 @@ impl Bindings {
1684
1700
cmd. args ( & [ "--config-path" , path] ) ;
1685
1701
}
1686
1702
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)
1701
1743
}
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)
1709
1746
}
1710
1747
} else {
1711
- Err ( io:: Error :: new (
1712
- io:: ErrorKind :: Other ,
1713
- "Error executing rustfmt!" ,
1714
- ) )
1748
+ eprintln ! ( "Error executing rustfmt!" ) ;
1749
+ Ok ( source)
1715
1750
}
1716
1751
}
1717
1752
}
0 commit comments