1// Copyright (c) 2014-2018 Bitmark Inc. 2// Use of this source code is governed by an ISC 3// license that can be found in the LICENSE file. 4 5// replacement for os.Exit(N) that runs defers 6// 7// Original article: http://soniacodes.wordpress.com/2011/04/28/deferred-functions-and-an-exit-code/ 8// 9// This is modified version to pass an integer status to os.Exit 10// 11// usage: as the first line of main add: 12// defer exitwithstatus.HandleFatal() 13// 14// to exit with a particular integer value: 15// exitwithstatus.Exit(42) 16package exitwithstatus 17 18import ( 19 "fmt" 20 "os" 21 "path/filepath" 22) 23 24type fatal struct { 25 err interface{} 26} 27 28// Exit with the integer status value 29// 30// e.g to exit calling all defers with the value three: exitwithstatus.Exit(3) 31func Exit(status int) { 32 panic(fatal{status}) 33} 34 35// This must be the first defer in the program 36// 37// i.e. the first line of main must be: defer exitwithstatus.Handle() 38func Handler() { 39 if err := recover(); err != nil { 40 if status, ok := err.(fatal); ok { 41 s := status.err.(int) 42 os.Exit(s) 43 } 44 panic(err) // this is some other kind of panic so pass it up the chain 45 } 46} 47 48// print a message to stderr and exit wit error status 49func Message(message string, args ...interface{}) { 50 51 m := "failed" 52 53 // if a blank message print a simple usage message 54 if message == "" { 55 56 // tidy up the program name 57 programName := filepath.Base(os.Args[0]) 58 59 m = fmt.Sprintf("Use %s -h to show usage", programName) 60 } else { 61 62 // user supplied message 63 m = fmt.Sprintf(message, args...) 64 } 65 66 // print to stderr with final '\n' 67 fmt.Fprintln(os.Stderr, m) 68 69 Exit(1) 70} 71