diff options
| -rw-r--r-- | errors.go | 126 | ||||
| -rw-r--r-- | exit.go | 17 | 
2 files changed, 59 insertions, 84 deletions
@@ -1,92 +1,52 @@  package argvpb -// Gemini's excellent at this sorta research. Not much else though +import "fmt" -// This file defines a set of conventional exit codes for command-line applications, -// based on the BSD `sysexits.h` standard and common GNU/Linux practices. -// Using these constants makes the program's exit behavior clear and consistent. +// This file defines the set of conventional exit codes for command-line applications, +// These are the standard and common GNU/Linux and BSD `sysexits.h` best practices -// ExitCode represents a program's exit status code.  type ExitCode int  const ( -	// --- Standard Success/Failure --- - -	// ExitSuccess indicates that the program completed its task without errors. -	ExitSuccess ExitCode = 0 - -	// ExitFailure is a generic, catch-all code for "something went wrong." -	// It should be used if no other more specific code applies. -	ExitFailure ExitCode = 1 - -	// --- Errors based on BSD sysexits.h --- - -	// ExitUsage indicates that the user provided invalid command-line arguments or flags. -	// (Standard: EX_USAGE) -	ExitUsage ExitCode = 64 - -	// ExitDataErr indicates that the input data was incorrect or malformed. -	// (e.g., a corrupt configuration file). -	// (Standard: EX_DATAERR) -	ExitDataErr ExitCode = 65 - -	// ExitNoInput indicates that an input file was not found or could not be read. -	// (Standard: EX_NOINPUT) -	ExitNoInput ExitCode = 66 - -	// ExitNoUser indicates that a specified user did not exist. -	// (Standard: EX_NOUSER) -	ExitNoUser ExitCode = 67 - -	// ExitNoHost indicates that a specified host did not exist. -	// (Standard: EX_NOHOST) -	ExitNoHost ExitCode = 68 - -	// ExitUnavailable indicates that a required service is unavailable. -	// (Standard: EX_UNAVAILABLE) -	ExitUnavailable ExitCode = 69 - -	// ExitSoftware indicates an internal software error. This is for unexpected -	// conditions and bugs ("this should never happen"). -	// (Standard: EX_SOFTWARE) -	ExitSoftware ExitCode = 70 - -	// ExitOSErr indicates an operating system error, such as a failed system call. -	// (e.g., fork failed, couldn't create a directory). -	// (Standard: EX_OSERR) -	ExitOSErr ExitCode = 71 - -	// ExitOSFile indicates a critical OS file is missing or corrupt. -	// (e.g., /etc/passwd). -	// (Standard: EX_OSFILE) -	ExitOSFile ExitCode = 72 - -	// ExitCantCreat indicates that a user-specified output file could not be created. -	// (Standard: EX_CANTCREAT) -	ExitCantCreat ExitCode = 73 - -	// ExitIOErr indicates an error occurred during an I/O operation. -	// (Standard: EX_IOERR) -	ExitIOErr ExitCode = 74 - -	// ExitTempFail indicates a temporary failure. The user is invited to retry. -	// (Standard: EX_TEMPFAIL) -	ExitTempFail ExitCode = 75 - -	// ExitProtocol indicates a protocol error during network communication. -	// (Standard: EX_PROTOCOL) -	ExitProtocol ExitCode = 76 - -	// ExitNoPerm indicates that the user does not have sufficient permissions. -	// This is for filesystem permissions, not for authentication issues. -	// (Standard: EX_NOPERM) -	ExitNoPerm ExitCode = 77 - -	// ExitConfig indicates that something is wrong in a configuration file. -	// (Standard: EX_CONFIG) -	ExitConfig ExitCode = 78 +	ExitSuccess     ExitCode = 0      // the program completed its task without errors. +	ExitFailure     ExitCode = 1      // generic, catch-all code for "something went wrong." +	ExitUsage       ExitCode = 64     // EX_USAGE:       user provided invalid command-line arguments or flags. +	ExitDataErr     ExitCode = 65     // EX_DATAERR:     input data was incorrect or malformed. +	ExitNoInput     ExitCode = 66     // EX_NOINPUT:     an input file was not found or could not be read. +	ExitNoUser      ExitCode = 67     // EX_NOUSER:      a specified user did not exist. +	ExitNoHost      ExitCode = 68     // EX_NOHOST:      a specified host did not exist. +	ExitUnavailable ExitCode = 69     // EX_UNAVAILABLE: a required service is unavailable. +	ExitSoftware    ExitCode = 70     // EX_SOFTWARE:    internal software error. bugs ("this should never happen") +	ExitOSErr       ExitCode = 71     // EX_OSERR:       an operating system error, such as a failed system call. +	ExitOSFile      ExitCode = 72     // EX_OSFILE:      a critical OS file is missing or corrupt. (e.g., /etc/passwd) +	ExitCantCreate  ExitCode = 73     // EX_CANTCREATE:  a user-specified output file could not be created. +	ExitIOErr       ExitCode = 74     // EX_IOERR:       an error occurred during an I/O operation. +	ExitTempFail    ExitCode = 75     // EX_TEMPFAIL:    temporary failure. The user is invited to retry. +	ExitProtocol    ExitCode = 76     // EX_PROTOCOL:    protocol error during network communication. +	ExitNoPerm      ExitCode = 77     // EX_NOPERM:      the user does not have sufficient filesystem permissions. +	ExitConfig      ExitCode = 78     // EX_CONFIG:      something is wrong in a configuration file. +	Exit126         ExitCode = 126    // Reserved for shell (command not executable) +	Exit127         ExitCode = 127    // Reserved for shell (command not found) +	Exit128         ExitCode = 128    // Reserved for shell (termination by a signal) +	ExitPB          ExitCode = 252525 // NEW FOR ARGV:   return a protobuf on exit. todo: need someone to make an RFC for this +	Exit109         ExitCode = 109    // for testing argv. 109 = 252525 % 256  ) -// Note: Exit codes 126, 127, and >128 are reserved for the shell to indicate -// specific execution failures (command not executable, command not found, or -// termination by a signal) and should not be used by applications. +// todo: finish this struct +func (x ExitCode) String() string { +	switch x { +	case ExitSuccess: +		return "ExitSuccess" +	case ExitFailure: +		return "ExitFailure" +	case ExitUsage: +		return "invalid command-line arguments or flags." +	case ExitDataErr: +		return "the input data was incorrect or malformed." +	case ExitNoInput: +		return "the input file not found, could not be read" +	case ExitPB: +		return "In the year 252525, the backwards time-machine still won't have arrived" +	} +	return fmt.Sprintf("%d", x) +} @@ -6,6 +6,7 @@ import (  	"time"  	"go.wit.com/lib/cobol" +	"golang.org/x/term"  )  // since we know when the command starts (duh, this parses os.Args) @@ -22,6 +23,18 @@ func BadExit(msg string, err error) {  	PB.badExit(msg, err)  } +func isInteractive() { +	// For os.Stdin, this is typically 0. +	stdinFd := int(os.Stdin.Fd()) + +	// IsTerminal() returns true if the given file descriptor is connected to a terminal. +	if term.IsTerminal(stdinFd) { +		fmt.Println("Running in an INTERACTIVE terminal.") +	} else { +		fmt.Println("Running in a NON-INTERACTIVE environment (pipe, script, etc.).") +	} +} +  func (pb *Argv) goodExit(msg string) {  	go ExitWatchdog()  	if me.appExit != nil { @@ -34,6 +47,7 @@ func (pb *Argv) goodExit(msg string) {  	} else {  		appname = pb.AppInfo.APPNAME  	} +	isInteractive()  	fmt.Printf("%s: %s (%s)\n", appname, msg, cobol.FormatDuration(dur))  	os.Exit(0)  } @@ -43,6 +57,7 @@ func (pb *Argv) badExit(msg string, err error) {  	if me.appExit != nil {  		me.appExit()  	} +	isInteractive()  	// print out errors. this handles wrapped errors which is a useful  	if err != nil {  		if u, ok := err.(interface{ Unwrap() []error }); ok { @@ -65,7 +80,7 @@ func (pb *Argv) badExit(msg string, err error) {  		appname = pb.AppInfo.APPNAME  	}  	fmt.Printf("%s error: %s (%s)\n", appname, msg, cobol.FormatDuration(dur)) -	os.Exit(1) +	os.Exit(int(ExitPB))  }  // this code doesn't need to be this complicated. I put it here as reference code for myself so I could remember where it is.  | 
