@@ -2,6 +2,8 @@ use std::borrow::Cow;
22use std:: error:: Error ;
33use std:: fmt;
44use std:: io;
5+ use std:: process:: ExitCode ;
6+ use std:: process:: Termination ;
57
68mod commitmsgfmt;
79mod parser;
@@ -107,6 +109,26 @@ impl<'a> Error for CliError<'a> {
107109 }
108110}
109111
112+ impl Termination for CliError < ' _ > {
113+ fn report ( self ) -> ExitCode {
114+ match self {
115+ CliError :: EarlyExit ( s) => {
116+ println ! ( "{}" , s) ;
117+ ExitCode :: SUCCESS
118+ }
119+ CliError :: Io ( ref e) if e. kind ( ) == io:: ErrorKind :: BrokenPipe => {
120+ let ret = 128 + 13 ;
121+ debug_assert ! ( ret == 141 ) ;
122+ ExitCode :: from ( ret)
123+ }
124+ _ => {
125+ eprintln ! ( "fatal: {}" , self ) ;
126+ ExitCode :: FAILURE
127+ }
128+ }
129+ }
130+ }
131+
110132enum CliArgument < ' a > {
111133 HelpShort ,
112134 HelpLong ,
@@ -172,11 +194,11 @@ fn parse_git_config_commentchar(git_output: Result<Vec<u8>, io::Error>) -> char
172194 }
173195}
174196
175- fn main ( ) {
197+ fn main ( ) -> ExitCode {
176198 let command_line = std:: env:: args ( ) . collect :: < Vec < String > > ( ) ;
177199 let cfg = try_config_from_command_line ( & command_line) ;
178- if let Err ( ref e) = cfg {
179- exit_abnormally ( e ) ;
200+ if let Err ( e) = cfg {
201+ return e . report ( ) ;
180202 }
181203 let cfg = cfg. unwrap ( ) ;
182204
@@ -187,8 +209,9 @@ fn main() {
187209 . map ( |text| commitmsgfmt. filter ( & text) )
188210 . and_then ( to_stdout) ;
189211
190- if let Err ( ref e) = result {
191- exit_abnormally ( e) ;
212+ match result {
213+ Ok ( ( ) ) => ExitCode :: SUCCESS ,
214+ Err ( e) => e. report ( ) ,
192215 }
193216}
194217
@@ -293,25 +316,6 @@ fn to_stdout<'a>(msg: String) -> CliResult<'a, ()> {
293316 Ok ( ( ) )
294317}
295318
296- fn exit_abnormally ( e : & CliError ) {
297- let ret = match e {
298- CliError :: EarlyExit ( s) => {
299- println ! ( "{}" , s) ;
300- 0
301- }
302- CliError :: Io ( ref e) if e. kind ( ) == io:: ErrorKind :: BrokenPipe => {
303- let ret = 128 + 13 ;
304- debug_assert ! ( ret == 141 ) ;
305- ret
306- }
307- _ => {
308- eprintln ! ( "fatal: {}" , e) ;
309- 1
310- }
311- } ;
312- :: std:: process:: exit ( ret) ;
313- }
314-
315319#[ cfg( test) ]
316320mod tests {
317321 use super :: * ;
@@ -475,6 +479,26 @@ mod tests {
475479 assert_eq ! ( expected, actual) ;
476480 }
477481
482+ #[ test]
483+ fn impl_clierror_termination ( ) {
484+ let errs = vec ! [
485+ ( CliError :: ArgUnrecognized ( "foo" . into( ) ) , ExitCode :: FAILURE ) ,
486+ ( CliError :: ArgWidthNaN ( "nan" . into( ) ) , ExitCode :: FAILURE ) ,
487+ ( CliError :: ArgWidthOutOfBounds ( 0 ) , ExitCode :: FAILURE ) ,
488+ ( CliError :: EarlyExit ( "help" . into( ) ) , ExitCode :: SUCCESS ) ,
489+ (
490+ CliError :: from( io:: Error :: from( io:: ErrorKind :: BrokenPipe ) ) ,
491+ ExitCode :: from( 141 ) ,
492+ ) ,
493+ ( CliError :: Other ( "other" . into( ) ) , ExitCode :: FAILURE ) ,
494+ ] ;
495+ let ( actual, expected) : ( Vec < _ > , Vec < _ > ) = errs
496+ . into_iter ( )
497+ . map ( |( input, ex) | ( format ! ( "{:?}" , input. report( ) ) , format ! ( "{:?}" , ex) ) )
498+ . unzip ( ) ;
499+ assert_eq ! ( expected, actual) ;
500+ }
501+
478502 #[ test]
479503 fn smoke_decide_behavior_from_command_line ( ) {
480504 use crate :: CliError :: * ;
0 commit comments