summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--errors.go126
-rw-r--r--exit.go17
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.