Skip to content

Commit

Permalink
Pass errors down from ProjectRunner
Browse files Browse the repository at this point in the history
In preparation for being able to gracefully shutdown the HTTP server.

The existing exit code is wrapped in a new type that satisfies `error`
and lets us pull the code out for `os.Exit`.
  • Loading branch information
dcarley authored and F1bonacc1 committed Jul 12, 2024
1 parent 3cd252d commit 598c41e
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 24 deletions.
17 changes: 14 additions & 3 deletions src/app/project_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ import (
"github.com/rs/zerolog/log"
)

type ExitError struct {
Code int
}

func (e *ExitError) Error() string {
return fmt.Sprintf("project non-zero exit code: %d", e.Code)
}

type ProjectRunner struct {
procConfMutex sync.Mutex
project *types.Project
Expand Down Expand Up @@ -47,15 +55,15 @@ func (p *ProjectRunner) init() {
p.initProcessLogs()
}

func (p *ProjectRunner) Run() int {
func (p *ProjectRunner) Run() error {
p.runningProcesses = make(map[string]*Process)
runOrder := []types.ProcessConfig{}
err := p.project.WithProcesses([]string{}, func(process types.ProcessConfig) error {
runOrder = append(runOrder, process)
return nil
})
if err != nil {
log.Error().Msgf("Failed to build project run order: %s", err.Error())
return fmt.Errorf("failed to build project run order: %e", err)
}
var nameOrder []string
for _, v := range runOrder {
Expand All @@ -75,7 +83,10 @@ func (p *ProjectRunner) Run() int {
}
p.waitGroup.Wait()
log.Info().Msg("Project completed")
return p.exitCode
if p.exitCode != 0 {
err = &ExitError{p.exitCode}
}
return err
}

func (p *ProjectRunner) runProcess(config *types.ProcessConfig) {
Expand Down
8 changes: 4 additions & 4 deletions src/app/system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ func TestSystem_TestComposeChainExit(t *testing.T) {
t.Errorf(err.Error())
return
}
exitCode := runner.Run()
want := 42
if want != exitCode {
t.Errorf("Project.Run() = %v, want %v", exitCode, want)
err = runner.Run()
want := "project non-zero exit code: 42"
if want != err.Error() {
t.Errorf("Project.Run() = %v, want %v", err, want)
}
})
}
Expand Down
21 changes: 10 additions & 11 deletions src/cmd/project_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ func getProjectRunner(process []string, noDeps bool, mainProcess string, mainPro
return runner
}

func runProject(runner *app.ProjectRunner) {
exitCode := 0
func runProject(runner *app.ProjectRunner) error {
var err error
if *pcFlags.IsTuiEnabled {
exitCode = runTui(runner)
err = runTui(runner)
} else {
exitCode = runHeadless(runner)
err = runHeadless(runner)
}
os.Remove(*pcFlags.UnixSocketPath)
log.Info().Msg("Thank you for using process-compose")
os.Exit(exitCode)
return err
}

func setSignal(signalHandler func()) {
Expand All @@ -60,23 +60,22 @@ func setSignal(signalHandler func()) {
}()
}

func runHeadless(project *app.ProjectRunner) int {
func runHeadless(project *app.ProjectRunner) error {
setSignal(func() {
_ = project.ShutDownProject()
})
exitCode := project.Run()
return exitCode
return project.Run()
}

func runTui(project *app.ProjectRunner) int {
func runTui(project *app.ProjectRunner) error {
go startTui(project)
exitCode := project.Run()
err := project.Run()
if !*pcFlags.KeepTuiOn {
tui.Stop()
} else {
tui.Wait()
}
return exitCode
return err
}

func startTui(runner app.IProject) {
Expand Down
19 changes: 15 additions & 4 deletions src/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,18 @@ var (
pcFlags.PcThemeChanged = cmd.Flags().Changed(flagTheme)
pcFlags.SortColumnChanged = cmd.Flags().Changed(flagSort)
},
RunE: run,
Run: run,
}
)

func run(cmd *cobra.Command, args []string) error {
func run(cmd *cobra.Command, args []string) {
defer func() {
_ = logFile.Close()
}()
runner := getProjectRunner([]string{}, false, "", []string{})
startHttpServerIfEnabled(!*pcFlags.IsTuiEnabled, runner)
runProject(runner)
return nil
err := runProject(runner)
handleErrorAndExit(err)
}

// Execute adds all child commands to the root command and sets flags appropriately.
Expand Down Expand Up @@ -137,6 +137,17 @@ func setupLogger() *os.File {
return file
}

// Logs and exits with a non-zero code if there are any errors.
func handleErrorAndExit(err error) {
if err != nil {
log.Error().Err(err)
if exitErr, ok := err.(*app.ExitError); ok {
os.Exit(exitErr.Code)
}
os.Exit(1)
}
}

func startHttpServerIfEnabled(useLogger bool, runner *app.ProjectRunner) {
if !*pcFlags.NoServer {
if *pcFlags.IsUnixSocket {
Expand Down
3 changes: 2 additions & 1 deletion src/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ Command line arguments, provided after --, are passed to the PROCESS.`,
)

startHttpServerIfEnabled(false, runner)
runProject(runner)
err := runProject(runner)
handleErrorAndExit(err)
},
}

Expand Down
3 changes: 2 additions & 1 deletion src/cmd/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ will start them and their dependencies only`,
Run: func(cmd *cobra.Command, args []string) {
runner := getProjectRunner(args, *pcFlags.NoDependencies, "", []string{})
startHttpServerIfEnabled(!*pcFlags.IsTuiEnabled, runner)
runProject(runner)
err := runProject(runner)
handleErrorAndExit(err)
},
}

Expand Down

0 comments on commit 598c41e

Please sign in to comment.