@@ -1580,18 +1580,15 @@ impl Bindings {
1580
1580
1581
1581
/// Write these bindings as source text to a file.
1582
1582
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 ( ( ) )
1595
1592
}
1596
1593
1597
1594
/// Write these bindings as source text to the given `Write`able.
@@ -1604,31 +1601,50 @@ impl Bindings {
1604
1601
writer. write ( line. as_bytes ( ) ) ?;
1605
1602
writer. write ( "\n " . as_bytes ( ) ) ?;
1606
1603
}
1604
+
1607
1605
if !self . options . raw_lines . is_empty ( ) {
1608
1606
writer. write ( "\n " . as_bytes ( ) ) ?;
1609
1607
}
1610
1608
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
+ }
1612
1617
Ok ( ( ) )
1613
1618
}
1614
1619
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 " )
1618
1623
. with_output ( self . options . time_phases ) ;
1619
1624
1620
1625
if !self . options . rustfmt_bindings {
1621
- return Ok ( ( ) ) ;
1626
+ return Ok ( source ) ;
1622
1627
}
1623
1628
1624
1629
let rustfmt = if let Ok ( rustfmt) = which:: which ( "rustfmt" ) {
1625
1630
rustfmt
1626
1631
} 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)
1629
1642
} ;
1630
1643
1631
- let mut cmd = Command :: new ( rustfmt) ;
1644
+ cmd
1645
+ . args ( & [ "--write-mode=display" ] )
1646
+ . stdin ( Stdio :: piped ( ) )
1647
+ . stdout ( Stdio :: piped ( ) ) ;
1632
1648
1633
1649
if let Some ( path) = self . options
1634
1650
. rustfmt_configuration_file
@@ -1638,34 +1654,53 @@ impl Bindings {
1638
1654
cmd. args ( & [ "--config-path" , path] ) ;
1639
1655
}
1640
1656
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)
1655
1697
}
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)
1663
1700
}
1664
1701
} else {
1665
- Err ( io:: Error :: new (
1666
- io:: ErrorKind :: Other ,
1667
- "Error executing rustfmt!" ,
1668
- ) )
1702
+ eprintln ! ( "Error executing rustfmt!" ) ;
1703
+ Ok ( source)
1669
1704
}
1670
1705
}
1671
1706
}
0 commit comments