Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions cmd/meeseeks/exit.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package main
import (
"flag"
"fmt"
"log/slog"
"os"
"strconv"
"syscall"

"github.com/GustavoCaso/meeseeks/internal/logger"
)

func exitCommand(args []string) error {
func exitCommand(args []string, _ *logger.Logger) error {
fs := flag.NewFlagSet("exit", flag.ExitOnError)
fs.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: meeseeks exit\n\n")
Expand Down Expand Up @@ -41,8 +42,8 @@ func exitCommand(args []string) error {
if err != nil {
return err
}
//nolint:sloglint //currently working on adding support for custom logger
slog.Info("Exiting meeseeks")

fmt.Fprintln(os.Stdout, "Exiting meeseeks")

return nil
}
3 changes: 2 additions & 1 deletion cmd/meeseeks/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import (
"fmt"
"os"

"github.com/GustavoCaso/meeseeks/internal/logger"
"github.com/GustavoCaso/meeseeks/internal/server"
)

func logsCommand(args []string) error {
func logsCommand(args []string, _ *logger.Logger) error {
fs := flag.NewFlagSet("logs", flag.ExitOnError)
fs.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: meeseeks logs <program_name>\n\n")
Expand Down
14 changes: 9 additions & 5 deletions cmd/meeseeks/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package main
import (
"fmt"
"os"

"github.com/GustavoCaso/meeseeks/internal/logger"
)

func main() {
Expand All @@ -14,29 +16,31 @@ func main() {
command := os.Args[1]
args := os.Args[2:]

logger := logger.New()

switch command {
case "run":
if err := runCommand(args); err != nil {
if err := runCommand(args, logger); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
case "status":
if err := statusCommand(args); err != nil {
if err := statusCommand(args, logger); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
case "logs":
if err := logsCommand(args); err != nil {
if err := logsCommand(args, logger); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
case "stop":
if err := stopCommand(args); err != nil {
if err := stopCommand(args, logger); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
case "exit":
if err := exitCommand(args); err != nil {
if err := exitCommand(args, logger); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
Expand Down
131 changes: 77 additions & 54 deletions cmd/meeseeks/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,36 @@ import (
"context"
"flag"
"fmt"
"log/slog"
"os"
"os/exec"
"os/signal"
"syscall"

"github.com/GustavoCaso/meeseeks/internal/config"
"github.com/GustavoCaso/meeseeks/internal/logger"
"github.com/GustavoCaso/meeseeks/internal/server"
)

func runCommand(args []string) error {
fs := flag.NewFlagSet("run", flag.ExitOnError)
configFile := fs.String(
"config",
"",
"Path to configuration file (defaults to $MEESEEKS_CONFIG_DIR/config.yaml or ~/.meeseeks/config.yaml)",
)
detach := fs.Bool("d", false, "Run in detached mode")

fs.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: meeseeks run [options]\n\n")
fmt.Fprintf(os.Stderr, "Start programs from configuration file\n\n")
fmt.Fprintf(os.Stderr, "Options:\n")
fs.PrintDefaults()
}

if err := fs.Parse(args); err != nil {
return err
}

if *configFile == "" {
*configFile = getDefaultConfigPath()
}

cfg, err := config.LoadConfig(*configFile)
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}

sockPath := getSocketPath()
pidFile := getPidFile()
type cmd struct {
configPath string
cfg *config.Config
pidFile string
socketPath string
logger *logger.Logger
detach bool
}

if *detach {
return runDetached(pidFile, *configFile, cfg)
func (c *cmd) run() error {
if c.detach {
return c.runDetached()
}

return runForeground(cfg, sockPath, pidFile)
return c.runForeground()
}

func runDetached(pidFile, configFile string, cfg *config.Config) error {
func (c *cmd) runDetached() error {
//nolint:gosec // the arguments are provided by the user
cmd := exec.Command(os.Args[0], "run", "-config", configFile)
cmd := exec.Command(os.Args[0], "run", "-config", c.configPath)
cmd.Env = os.Environ()
cmd.SysProcAttr = &syscall.SysProcAttr{
Setsid: true,
Expand All @@ -64,8 +42,7 @@ func runDetached(pidFile, configFile string, cfg *config.Config) error {
cmd.Stdin = nil
stdoutFile, stdoutErr := getInternalStdoutFile()
if stdoutErr != nil {
//nolint:sloglint //currently working on adding support for custom logger
slog.Warn("Failed to create log file for meeseeks, using /dev/null", "error", stdoutErr.Error())
c.logger.Warn("Failed to create log file for meeseeks, using /dev/null", "error", stdoutErr.Error())
cmd.Stdout = nil
cmd.Stderr = nil
}
Expand All @@ -76,56 +53,102 @@ func runDetached(pidFile, configFile string, cfg *config.Config) error {
return fmt.Errorf("failed to start meeseeks process: %w", err)
}

if err := writePidFile(pidFile, cmd.Process.Pid); err != nil {
if err := writePidFile(c.pidFile, cmd.Process.Pid); err != nil {
return fmt.Errorf("failed to write PID file: %w", err)
}

//nolint:sloglint //currently working on adding support for custom logger
slog.Info("Started meeseeks (detached)", "pid", cmd.Process.Pid, "program_count", len(cfg.Programs))
c.logger.Info("Started meeseeks (detached)", "pid", cmd.Process.Pid, "program_count", len(c.cfg.Programs))

_ = cmd.Process.Release()

return nil
}

func runForeground(cfg *config.Config, sockPath, pidFile string) error {
func (c *cmd) runForeground() error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

s, err := startServer(ctx, cfg, sockPath)
s, err := startServer(ctx, c.cfg, c.logger, c.socketPath)
if err != nil {
return err
}

go func() {
slog.Info("Started meeseeks", "program_count", len(cfg.Programs))
c.logger.Info("Started meeseeks", "program_count", len(c.cfg.Programs))

if waitErr := s.Wait(ctx); waitErr != nil {
slog.Warn("Wait completed with error", "error", waitErr)
c.logger.Warn("Wait completed with error", "error", waitErr)
}
}()

sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

<-sigChan
//nolint:sloglint //currently working on adding support for custom logger
slog.Info("Received signal, shutting down...")
c.logger.Info("Received signal, shutting down...")
err = s.Stop()
if err != nil {
//nolint:sloglint //currently working on adding support for custom logger
slog.Warn("Error stopping the server.", "error", err.Error())
c.logger.Warn("Error stopping the server.", "error", err.Error())
}
_ = os.Remove(pidFile)
_ = os.Remove(c.pidFile)

return nil
}

func startServer(ctx context.Context, cfg *config.Config, sockPath string) (*server.Server, error) {
s := server.New(sockPath)
func runCommand(args []string, logger *logger.Logger) error {
fs := flag.NewFlagSet("run", flag.ExitOnError)
configPath := fs.String(
"config",
"",
"Path to configuration file (defaults to $MEESEEKS_CONFIG_DIR/config.yaml or ~/.meeseeks/config.yaml)",
)
detach := fs.Bool("d", false, "Run in detached mode")

fs.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: meeseeks run [options]\n\n")
fmt.Fprintf(os.Stderr, "Start programs from configuration file\n\n")
fmt.Fprintf(os.Stderr, "Options:\n")
fs.PrintDefaults()
}

if err := fs.Parse(args); err != nil {
return err
}

if *configPath == "" {
*configPath = getDefaultConfigPath()
}

cfg, err := config.LoadConfig(*configPath)
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}

sockPath := getSocketPath()
pidFile := getPidFile()

cmd := &cmd{
configPath: *configPath,
cfg: cfg,
pidFile: pidFile,
socketPath: sockPath,
logger: logger,
detach: *detach,
}

return cmd.run()
}

func startServer(
ctx context.Context,
cfg *config.Config,
logger *logger.Logger,
sockPath string,
) (*server.Server, error) {
s := server.New(sockPath, logger)

for _, programConfig := range cfg.Programs {
prog, err := createProgramFromConfig(programConfig)
prog, err := createProgramFromConfig(programConfig, logger)
if err != nil {
return nil, fmt.Errorf("failed to create program %s: %w", programConfig.Name, err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/meeseeks/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func TestRunCommand_Foreground(t *testing.T) {
}

output := stdout.String() + stderr.String()
expected := "Started meeseeks program_count=1"
expected := "\"Started meeseeks\""
if !strings.Contains(output, expected) {
t.Fatalf("Expected output to contain %q, got %q", expected, output)
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/meeseeks/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import (
"fmt"
"os"

"github.com/GustavoCaso/meeseeks/internal/logger"
"github.com/GustavoCaso/meeseeks/internal/server"
)

func statusCommand(args []string) error {
func statusCommand(args []string, _ *logger.Logger) error {
fs := flag.NewFlagSet("status", flag.ExitOnError)
format := fs.String("format", "table", "Output format: table, json")
fs.StringVar(format, "f", "table", "Output format: table, json (shorthand)")
Expand Down
3 changes: 2 additions & 1 deletion cmd/meeseeks/stop.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import (
"fmt"
"os"

"github.com/GustavoCaso/meeseeks/internal/logger"
"github.com/GustavoCaso/meeseeks/internal/server"
)

func stopCommand(args []string) error {
func stopCommand(args []string, _ *logger.Logger) error {
fs := flag.NewFlagSet("stop", flag.ExitOnError)
timeout := fs.String(
"timeout",
Expand Down
5 changes: 4 additions & 1 deletion cmd/meeseeks/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"text/tabwriter"

"github.com/GustavoCaso/meeseeks/internal/config"
"github.com/GustavoCaso/meeseeks/internal/logger"
"github.com/GustavoCaso/meeseeks/pkg/meeseeks"
"github.com/GustavoCaso/meeseeks/pkg/program"
)
Expand Down Expand Up @@ -56,7 +57,7 @@ func writePidFile(pidFile string, pid int) error {
return os.WriteFile(pidFile, []byte(strconv.Itoa(pid)), 0600)
}

func createProgramFromConfig(pc config.ProgramConfig) (program.Program, error) {
func createProgramFromConfig(pc config.ProgramConfig, logger *logger.Logger) (program.Program, error) {
var opts []program.Option

if len(pc.Args) > 0 {
Expand Down Expand Up @@ -87,6 +88,8 @@ func createProgramFromConfig(pc config.ProgramConfig) (program.Program, error) {
opts = append(opts, program.Stderr(file))
}

opts = append(opts, program.Logger(logger))

return program.New(pc.Name, pc.Command, opts...), nil
}

Expand Down
5 changes: 4 additions & 1 deletion cmd/meeseeks/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

"github.com/GustavoCaso/meeseeks/internal/config"
"github.com/GustavoCaso/meeseeks/internal/logger"
)

func TestCreateProgramFromConfig(t *testing.T) {
Expand Down Expand Up @@ -47,9 +48,11 @@ func TestCreateProgramFromConfig(t *testing.T) {
},
}

logger := logger.New()

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
prog, err := createProgramFromConfig(tt.config)
prog, err := createProgramFromConfig(tt.config, logger)

if tt.expectError {
if err == nil {
Expand Down
Loading