Skip to content

Commit d9584b5

Browse files
committed
print agent output when it exits with a non-zero status code
1 parent 7487c25 commit d9584b5

File tree

2 files changed

+52
-35
lines changed

2 files changed

+52
-35
lines changed

cmd/server/server.go

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import (
66
"log/slog"
77
"net/http"
88
"os"
9+
"strings"
910

1011
"github.com/spf13/cobra"
12+
"golang.org/x/xerrors"
1113

1214
"github.com/coder/agentapi/lib/httpapi"
1315
"github.com/coder/agentapi/lib/logctx"
@@ -68,6 +70,48 @@ func parseAgentType(firstArg string, agentTypeVar string) (AgentType, error) {
6870
return agentType, nil
6971
}
7072

73+
func runServer(ctx context.Context, logger *slog.Logger, argsToPass []string) error {
74+
agent := argsToPass[0]
75+
agentType, err := parseAgentType(agent, agentTypeVar)
76+
if err != nil {
77+
return xerrors.Errorf("failed to parse agent type: %w", err)
78+
}
79+
var process *termexec.Process
80+
if printOpenAPI {
81+
process = nil
82+
} else {
83+
process, err = httpapi.SetupProcess(ctx, agent, argsToPass[1:]...)
84+
if err != nil {
85+
return xerrors.Errorf("failed to setup process: %w", err)
86+
}
87+
}
88+
srv := httpapi.NewServer(ctx, agentType, process, port)
89+
if printOpenAPI {
90+
fmt.Println(srv.GetOpenAPI())
91+
return nil
92+
}
93+
logger.Info("Starting server on port", "port", port)
94+
processExitCh := make(chan error, 1)
95+
go func() {
96+
defer close(processExitCh)
97+
if err := process.Wait(); err != nil {
98+
processExitCh <- xerrors.Errorf("agent exited with error:\n========\n%s\n========\n: %w", strings.TrimSpace(process.ReadScreen()), err)
99+
}
100+
if err := srv.Stop(ctx); err != nil {
101+
logger.Error("Failed to stop server", "error", err)
102+
}
103+
}()
104+
if err := srv.Start(); err != nil && err != context.Canceled && err != http.ErrServerClosed {
105+
return xerrors.Errorf("failed to start server: %w", err)
106+
}
107+
select {
108+
case err := <-processExitCh:
109+
return xerrors.Errorf("process exited with error: %w", err)
110+
default:
111+
}
112+
return nil
113+
}
114+
71115
var ServerCmd = &cobra.Command{
72116
Use: "server [agent]",
73117
Short: "Run the server",
@@ -76,39 +120,8 @@ var ServerCmd = &cobra.Command{
76120
Run: func(cmd *cobra.Command, args []string) {
77121
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
78122
ctx := logctx.WithLogger(context.Background(), logger)
79-
argsToPass := cmd.Flags().Args()
80-
agent := argsToPass[0]
81-
agentType, err := parseAgentType(agent, agentTypeVar)
82-
if err != nil {
83-
logger.Error("Failed to parse agent type", "error", err)
84-
os.Exit(1)
85-
}
86-
var process *termexec.Process
87-
if printOpenAPI {
88-
process = nil
89-
} else {
90-
process, err = httpapi.SetupProcess(ctx, agent, argsToPass[1:]...)
91-
if err != nil {
92-
logger.Error("Failed to setup process", "error", err)
93-
os.Exit(1)
94-
}
95-
}
96-
srv := httpapi.NewServer(ctx, agentType, process, port)
97-
if printOpenAPI {
98-
fmt.Println(srv.GetOpenAPI())
99-
os.Exit(0)
100-
}
101-
logger.Info("Starting server on port", "port", port)
102-
go func() {
103-
if err := process.Wait(); err != nil {
104-
logger.Error("Process exited with error", "error", err)
105-
}
106-
if err := srv.Stop(ctx); err != nil {
107-
logger.Error("Failed to stop server", "error", err)
108-
}
109-
}()
110-
if err := srv.Start(); err != nil && err != context.Canceled && err != http.ErrServerClosed {
111-
logger.Error("Failed to start server", "error", err)
123+
if err := runServer(ctx, logger, cmd.Flags().Args()); err != nil {
124+
fmt.Fprintf(os.Stderr, "%+v\n", err)
112125
os.Exit(1)
113126
}
114127
},

lib/termexec/termexec.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func (p *Process) Write(data []byte) (int, error) {
7575
return p.xp.TerminalInPipe().Write(data)
7676
}
7777

78-
// Closecloses the process using a SIGINT signal or forcefully killing it if the process
78+
// Close closes the process using a SIGINT signal or forcefully killing it if the process
7979
// does not exit after the timeout. It then closes the pseudo terminal.
8080
func (p *Process) Close(logger *slog.Logger, timeout time.Duration) error {
8181
logger.Info("Closing process")
@@ -113,8 +113,12 @@ func (p *Process) Close(logger *slog.Logger, timeout time.Duration) error {
113113

114114
// Wait waits for the process to exit.
115115
func (p *Process) Wait() error {
116-
if _, err := p.execCmd.Process.Wait(); err != nil {
116+
state, err := p.execCmd.Process.Wait()
117+
if err != nil {
117118
return xerrors.Errorf("process exited with error: %w", err)
118119
}
120+
if state.ExitCode() != 0 {
121+
return xerrors.Errorf("non-zero exit code: %d", state.ExitCode())
122+
}
119123
return nil
120124
}

0 commit comments

Comments
 (0)