update: enhance command execution with real-time logging and add shorthand flag for deployment file

This commit is contained in:
jon brookes 2025-08-16 11:45:47 +01:00
parent 4b8a27a2d7
commit 5f448d7fc7
3 changed files with 90 additions and 8 deletions

View file

@ -1,6 +1,7 @@
package app
import (
"bufio"
"bytes"
"fmt"
"log/slog"
@ -67,19 +68,52 @@ func k8sCreateNamespace(project string) error {
func RunCommand(command string) error {
slog.Debug(fmt.Sprintf("🐞 Running command: %s", command))
cmd := exec.Command("sh", "-c", command)
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
// Get pipes for real-time reading
stdoutPipe, err := cmd.StdoutPipe()
if err != nil {
return fmt.Errorf("failed to create stdout pipe: %w", err)
}
stderrPipe, err := cmd.StderrPipe()
if err != nil {
return fmt.Errorf("failed to create stderr pipe: %w", err)
}
// Start the command
if err := cmd.Start(); err != nil {
return fmt.Errorf("failed to start command: %w", err)
}
// Read stdout line by line and log through slog
go func() {
scanner := bufio.NewScanner(stdoutPipe)
for scanner.Scan() {
line := scanner.Text()
stdout.WriteString(line + "\n")
slog.Info(line)
}
}()
// Read stderr line by line and log through slog
go func() {
scanner := bufio.NewScanner(stderrPipe)
for scanner.Scan() {
line := scanner.Text()
stderr.WriteString(line + "\n")
slog.Error(line)
}
}()
// Wait for command to complete
err = cmd.Wait()
if err != nil {
slog.Error(fmt.Sprintf("❌ Command failed with error: %v\n", err))
slog.Debug(fmt.Sprintf("🐞 Stdout: %s\n", stdout.String()))
slog.Debug(fmt.Sprintf("🐞 Stderr: %s\n", stderr.String()))
return fmt.Errorf("failed to run script command: %w", err)
}
output := stdout.String()
slog.Debug(fmt.Sprintf("RunCommand executed successfully: %s", command))
slog.Debug(fmt.Sprintf("RunCommand output: %s", output))
return nil
}

View file

@ -35,6 +35,8 @@ func ReadBaseConfig(path string) (BaseConfig, error) {
deploymentType := os.Getenv("DEPLOYMENT_TYPE")
deploymentFile := flag.String("deployment-file", "", "path to config file")
deploymentFileShorthand := flag.String("f", "", "shorthand for -deployment-file")
helpFlag := flag.Bool("help", false, "show help")
flag.Parse()
@ -45,7 +47,9 @@ func ReadBaseConfig(path string) (BaseConfig, error) {
}
var config BaseConfig
if *deploymentFile != "" {
if *deploymentFileShorthand != "" {
config.DeploymentFile = *deploymentFileShorthand
} else if *deploymentFile != "" {
config.DeploymentFile = *deploymentFile
}

46
main.go
View file

@ -14,6 +14,7 @@
package main
import (
"context"
"fmt"
"log"
"log/slog"
@ -23,11 +24,54 @@ import (
"headshed/infctl-cli/config"
)
type customMessageOnlyHandler struct {
output *os.File
}
func (h *customMessageOnlyHandler) Enabled(_ context.Context, _ slog.Level) bool {
return true
}
func (h *customMessageOnlyHandler) Handle(_ context.Context, r slog.Record) error {
// Directly retrieve the message from the record
msg := r.Message
if msg != "" {
_, err := fmt.Fprintln(h.output, msg)
return err
}
return nil
}
func (h *customMessageOnlyHandler) WithAttrs(_ []slog.Attr) slog.Handler {
return h
}
func (h *customMessageOnlyHandler) WithGroup(_ string) slog.Handler {
return h
}
func main() {
var levelVar slog.LevelVar
levelVar.Set(slog.LevelDebug)
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: &levelVar}))
var logger *slog.Logger
if os.Getenv("LOG_FORMAT") == "basic" {
logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey {
return slog.Attr{}
}
return a
},
}))
} else if os.Getenv("LOG_FORMAT") == "none" {
logger = slog.New(&customMessageOnlyHandler{output: os.Stdout})
} else {
logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: &levelVar}))
}
slog.SetDefault(logger)