github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/cmd/state-exec/main.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "os/exec" 8 "runtime" 9 "time" 10 11 "github.com/ActiveState/cli/cmd/state-exec/internal/logr" 12 ) 13 14 const ( 15 executorName = "state-exec" 16 envVarKeyVerbose = "ACTIVESTATE_VERBOSE" 17 userErrMsg = "Not user serviceable; Please contact support for assistance." 18 ) 19 20 var ( 21 logErr = func(format string, args ...interface{}) { 22 fmt.Fprintf(os.Stderr, "%s: ", executorName) 23 fmt.Fprintf(os.Stderr, format+"\n", args...) 24 } 25 ) 26 27 func logDbgFunc(start time.Time) logr.LogFunc { 28 return func(format string, args ...interface{}) { 29 fmt.Fprintf(os.Stderr, "[DEBUG %9d] ", time.Since(start).Nanoseconds()) 30 fmt.Fprintf(os.Stderr, format+"\n", args...) 31 } 32 } 33 34 func init() { 35 // This application is not doing enough to warrant parallelism, so let's 36 // skip it and avoid the cost of scheduling. 37 runtime.GOMAXPROCS(1) 38 } 39 40 func main() { 41 if os.Getenv(envVarKeyVerbose) == "true" { 42 logr.SetDebug(logDbgFunc(time.Now())) 43 } 44 45 if err := run(); err != nil { 46 if exitErr := (&exec.ExitError{}); errors.As(err, &exitErr) { 47 os.Exit(exitErr.ExitCode()) 48 } 49 50 logErr("run failed: %s", err) 51 logErr(userErrMsg) 52 os.Exit(1) 53 } 54 55 os.Exit(0) 56 } 57 58 func run() error { 59 logr.Debug("hello") 60 defer logr.Debug("run goodbye") 61 62 hb, err := newHeartbeat() 63 if err != nil { 64 return fmt.Errorf("cannot create new heartbeat: %w", err) 65 } 66 logr.Debug("message data - pid: %s, exec: %s", hb.ProcessID, hb.ExecPath) 67 68 meta, err := newExecutorMeta(hb.ExecPath) 69 if err != nil { 70 return fmt.Errorf("cannot create new executor meta: %w", err) 71 } 72 logr.CallIfDebugIsSet(func() { 73 logr.Debug("meta data - bins...") 74 for _, bin := range meta.Bins { 75 logr.Debug(" bins : %s", bin) 76 } 77 }) 78 logr.Debug("meta data - matching bin: %s", meta.MatchingBin) 79 logr.CallIfDebugIsSet(func() { 80 logr.Debug("meta data - env...") 81 for _, entry := range meta.TransformedEnv { 82 logr.Debug(" env - kv: %s", entry) 83 } 84 }) 85 86 logr.Debug("communications - sock: %s", meta.SockPath) 87 if err := sendMsgToService(meta.SockPath, hb); err != nil { 88 logr.Debug(" sock - error: %v", err) 89 90 if inActiveStateCI() { // halt control flow on CI only 91 return fmt.Errorf("cannot send message to service (this error is handled in CI only): %w", err) 92 } 93 } 94 95 logr.Debug("cmd - running: %s", meta.MatchingBin) 96 exitCode, err := runCmd(meta) 97 if err != nil { 98 logr.Debug(" running - failed: bins (%v)", meta.ExecMeta.Bins) 99 return fmt.Errorf("cannot run command: %w", err) 100 } 101 102 msg, err := newExitCodeMessage(exitCode) 103 if err != nil { 104 return fmt.Errorf("cannot create new exit code message: %w", err) 105 } 106 logr.Debug("message data - exec: %s, exit code: %s", msg.ExecPath, msg.ExitCode) 107 108 if err := sendMsgToService(meta.SockPath, msg); err != nil { 109 logr.Debug(" sock - error: %v", err) 110 111 if inActiveStateCI() { // halt control flow on CI only 112 return fmt.Errorf("cannot send message to service (this error is handled in CI only): %w", err) 113 } 114 } 115 116 return nil 117 }