@@ -110,6 +110,7 @@ use crate::ffi::OsStr;
110
110
use crate :: fmt;
111
111
use crate :: fs;
112
112
use crate :: io:: { self , Initializer , IoSlice , IoSliceMut } ;
113
+ use crate :: num:: NonZeroI32 ;
113
114
use crate :: path:: Path ;
114
115
use crate :: str;
115
116
use crate :: sys:: pipe:: { read2, AnonPipe } ;
@@ -1387,8 +1388,8 @@ impl From<fs::File> for Stdio {
1387
1388
/// An `ExitStatus` represents every possible disposition of a process. On Unix this
1388
1389
/// is the **wait status**. It is *not* simply an *exit status* (a value passed to `exit`).
1389
1390
///
1390
- /// For proper error reporting of failed processes, print the value of `ExitStatus` using its
1391
- /// implementation of [`Display`](crate::fmt::Display).
1391
+ /// For proper error reporting of failed processes, print the value of `ExitStatus` or
1392
+ /// `ExitStatusError` using their implementations of [`Display`](crate::fmt::Display).
1392
1393
///
1393
1394
/// [`status`]: Command::status
1394
1395
/// [`wait`]: Child::wait
@@ -1401,6 +1402,29 @@ pub struct ExitStatus(imp::ExitStatus);
1401
1402
impl crate :: sealed:: Sealed for ExitStatus { }
1402
1403
1403
1404
impl ExitStatus {
1405
+ /// Was termination successful? Returns a `Result`.
1406
+ ///
1407
+ /// # Examples
1408
+ ///
1409
+ /// ```
1410
+ /// #![feature(exit_status_error)]
1411
+ /// # if cfg!(unix) {
1412
+ /// use std::process::Command;
1413
+ ///
1414
+ /// let status = Command::new("ls")
1415
+ /// .arg("/dev/nonexistent")
1416
+ /// .status()
1417
+ /// .expect("ls could not be executed");
1418
+ ///
1419
+ /// println!("ls: {}", status);
1420
+ /// status.exit_ok().expect_err("/dev/nonexistent could be listed!");
1421
+ /// # } // cfg!(unix)
1422
+ /// ```
1423
+ #[ unstable( feature = "exit_status_error" , issue = "84908" ) ]
1424
+ pub fn exit_ok ( & self ) -> Result < ( ) , ExitStatusError > {
1425
+ self . 0 . exit_ok ( ) . map_err ( ExitStatusError )
1426
+ }
1427
+
1404
1428
/// Was termination successful? Signal termination is not considered a
1405
1429
/// success, and success is defined as a zero exit status.
1406
1430
///
@@ -1422,7 +1446,7 @@ impl ExitStatus {
1422
1446
/// ```
1423
1447
#[ stable( feature = "process" , since = "1.0.0" ) ]
1424
1448
pub fn success ( & self ) -> bool {
1425
- self . 0 . success ( )
1449
+ self . 0 . exit_ok ( ) . is_ok ( )
1426
1450
}
1427
1451
1428
1452
/// Returns the exit code of the process, if any.
@@ -1476,6 +1500,114 @@ impl fmt::Display for ExitStatus {
1476
1500
}
1477
1501
}
1478
1502
1503
+ /// Describes the result of a process after it has failed
1504
+ ///
1505
+ /// Produced by the [`.exit_ok`](ExitStatus::exit_ok) method on [`ExitStatus`].
1506
+ ///
1507
+ /// # Examples
1508
+ ///
1509
+ /// ```
1510
+ /// #![feature(exit_status_error)]
1511
+ /// # if cfg!(unix) {
1512
+ /// use std::process::{Command, ExitStatusError};
1513
+ ///
1514
+ /// fn run(cmd: &str) -> Result<(),ExitStatusError> {
1515
+ /// Command::new(cmd).status().unwrap().exit_ok()?;
1516
+ /// Ok(())
1517
+ /// }
1518
+ ///
1519
+ /// run("true").unwrap();
1520
+ /// run("false").unwrap_err();
1521
+ /// # } // cfg!(unix)
1522
+ /// ```
1523
+ #[ derive( PartialEq , Eq , Clone , Copy , Debug ) ]
1524
+ #[ unstable( feature = "exit_status_error" , issue = "84908" ) ]
1525
+ // The definition of imp::ExitStatusError should ideally be such that
1526
+ // Result<(), imp::ExitStatusError> has an identical representation to imp::ExitStatus.
1527
+ pub struct ExitStatusError ( imp:: ExitStatusError ) ;
1528
+
1529
+ #[ unstable( feature = "exit_status_error" , issue = "84908" ) ]
1530
+ impl ExitStatusError {
1531
+ /// Reports the exit code, if applicable, from an `ExitStatusError`.
1532
+ ///
1533
+ /// In Unix terms the return value is the **exit status**: the value passed to `exit`, if the
1534
+ /// process finished by calling `exit`. Note that on Unix the exit status is truncated to 8
1535
+ /// bits, and that values that didn't come from a program's call to `exit` may be invented the
1536
+ /// runtime system (often, for example, 255, 254, 127 or 126).
1537
+ ///
1538
+ /// On Unix, this will return `None` if the process was terminated by a signal. If you want to
1539
+ /// handle such situations specially, consider using
1540
+ /// [`ExitStatusExt`](crate::os::unix::process::ExitStatusExt) (possibly after getting the
1541
+ /// general `ExitStatus` by using [`status()`](ExitStatusError::status).
1542
+ ///
1543
+ /// If the process finished by calling `exit` with a nonzero value, this will return
1544
+ /// that exit status.
1545
+ ///
1546
+ /// If the error was something else, it will return `None`.
1547
+ ///
1548
+ /// If the process exited successfully (ie, by calling `exit(0)`), there is no
1549
+ /// `ExitStatusError`. So the return value from `ExitStatusError::code()` is always nonzero.
1550
+ ///
1551
+ /// # Examples
1552
+ ///
1553
+ /// ```
1554
+ /// #![feature(exit_status_error)]
1555
+ /// # #[cfg(unix)] {
1556
+ /// use std::process::Command;
1557
+ ///
1558
+ /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err();
1559
+ /// assert_eq!(bad.code(), Some(1));
1560
+ /// # } // #[cfg(unix)]
1561
+ /// ```
1562
+ pub fn code ( & self ) -> Option < i32 > {
1563
+ self . code_nonzero ( ) . map ( Into :: into)
1564
+ }
1565
+
1566
+ /// Reports the exit code, if applicable, from an `ExitStatusError`, as a `NonZero`
1567
+ ///
1568
+ /// This is exaclty like [`code()`](Self::code), except that it returns a `NonZeroI32`.
1569
+ ///
1570
+ /// Plain `code`, returning a plain integer, is provided because is is often more convenient.
1571
+ /// The returned value from `code()` is indeed also nonzero; use `code_nonzero()` when you want
1572
+ /// a type-level guarantee of nonzeroness.
1573
+ ///
1574
+ /// # Examples
1575
+ ///
1576
+ /// ```
1577
+ /// #![feature(exit_status_error)]
1578
+ /// # if cfg!(unix) {
1579
+ /// use std::convert::TryFrom;
1580
+ /// use std::num::NonZeroI32;
1581
+ /// use std::process::Command;
1582
+ ///
1583
+ /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err();
1584
+ /// assert_eq!(bad.code_nonzero().unwrap(), NonZeroI32::try_from(1).unwrap());
1585
+ /// # } // cfg!(unix)
1586
+ /// ```
1587
+ pub fn code_nonzero ( & self ) -> Option < NonZeroI32 > {
1588
+ self . 0 . code ( )
1589
+ }
1590
+
1591
+ /// Converts an `ExitStatusError` (back) to an `ExitStatus`.
1592
+ pub fn into_status ( & self ) -> ExitStatus {
1593
+ ExitStatus ( self . 0 . into ( ) )
1594
+ }
1595
+ }
1596
+
1597
+ #[ unstable( feature = "exit_status_error" , issue = "84908" ) ]
1598
+ impl Into < ExitStatus > for ExitStatusError {
1599
+ fn into ( self ) -> ExitStatus {
1600
+ ExitStatus ( self . 0 . into ( ) )
1601
+ }
1602
+ }
1603
+
1604
+ #[ unstable( feature = "exit_status_error" , issue = "84908" ) ]
1605
+ impl fmt:: Display for ExitStatusError {
1606
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1607
+ self . into_status ( ) . fmt ( f)
1608
+ }
1609
+ }
1610
+
1479
1611
/// This type represents the status code a process can return to its
1480
1612
/// parent under normal termination.
1481
1613
///
0 commit comments