From 6b8742f6898e4cf8a8d1306c262afeb321c0e0a1 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Thu, 30 Oct 2025 14:03:46 -0500 Subject: aim for new achievments (or crash and burn trying) --- errors.go | 126 +++++++++++++++++++++----------------------------------------- exit.go | 17 ++++++++- 2 files changed, 59 insertions(+), 84 deletions(-) diff --git a/errors.go b/errors.go index 68db4ea..01f8310 100644 --- a/errors.go +++ b/errors.go @@ -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) +} diff --git a/exit.go b/exit.go index 83f2ddd..9752214 100644 --- a/exit.go +++ b/exit.go @@ -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. -- cgit v1.2.3