@@ -3,9 +3,12 @@ package app
33
44import (
55 "bufio"
6+ "context"
67 "fmt"
8+ "io"
79 "log/slog"
810 "os/exec"
11+ "sync"
912
1013 "github.com/sgaunet/gitlab-backup2s3/pkg/logger"
1114)
@@ -55,37 +58,79 @@ func (a *App) Run() error {
5558// execCommand executes a command.
5659// It wraps all errors from external packages.
5760func (a * App ) execCommand (cmdToExec []string ) error {
58- cmd := exec .Command (cmdToExec [0 ], cmdToExec [1 :]... ) // #nosec G204
61+ cmd := exec .CommandContext (context .Background (), cmdToExec [0 ], cmdToExec [1 :]... ) // #nosec G204
62+
5963 stderr , err := cmd .StderrPipe ()
6064 if err != nil {
6165 return fmt .Errorf ("error creating stderr pipe: %w" , err )
6266 }
67+
6368 stdout , err := cmd .StdoutPipe ()
6469 if err != nil {
6570 return fmt .Errorf ("error creating stdout pipe: %w" , err )
6671 }
72+
6773 err = cmd .Start ()
6874 if err != nil {
6975 return fmt .Errorf ("error starting command: %w" , err )
7076 }
7177
72- go func () {
73- scanner := bufio .NewScanner (stderr )
74- for scanner .Scan () {
75- m := scanner .Text ()
76- a .logger .Error (m )
77- }
78- }()
79- go func () {
80- scanner := bufio .NewScanner (stdout )
81- for scanner .Scan () {
82- m := scanner .Text ()
83- a .logger .Info (m )
84- }
85- }()
86- err = cmd .Wait ()
78+ return a .handleCommandOutput (cmd , stderr , stdout )
79+ }
80+
81+ // handleCommandOutput handles the output streams from the command.
82+ func (a * App ) handleCommandOutput (cmd * exec.Cmd , stderr , stdout io.ReadCloser ) error {
83+ var stderrErr , stdoutErr error
84+ var wg sync.WaitGroup
85+
86+ // Add wait group counter for both stdout and stderr goroutines
87+ const numGoroutines = 2
88+ wg .Add (numGoroutines )
89+
90+ go a .processStderr (stderr , & wg , & stderrErr )
91+ go a .processStdout (stdout , & wg , & stdoutErr )
92+
93+ err := cmd .Wait ()
8794 if err != nil {
8895 return fmt .Errorf ("error waiting for command: %w" , err )
8996 }
97+
98+ wg .Wait ()
99+
100+ if stderrErr != nil {
101+ return stderrErr
102+ }
103+ if stdoutErr != nil {
104+ return stdoutErr
105+ }
106+
90107 return nil
91108}
109+
110+ // processStderr processes the stderr stream.
111+ func (a * App ) processStderr (stderr io.ReadCloser , wg * sync.WaitGroup , stderrErr * error ) {
112+ defer wg .Done ()
113+ scanner := bufio .NewScanner (stderr )
114+ for scanner .Scan () {
115+ m := scanner .Text ()
116+ a .logger .Error (m )
117+ }
118+ scannerErr := scanner .Err ()
119+ if scannerErr != nil {
120+ * stderrErr = fmt .Errorf ("stderr scanner error: %w" , scannerErr )
121+ }
122+ }
123+
124+ // processStdout processes the stdout stream.
125+ func (a * App ) processStdout (stdout io.ReadCloser , wg * sync.WaitGroup , stdoutErr * error ) {
126+ defer wg .Done ()
127+ scanner := bufio .NewScanner (stdout )
128+ for scanner .Scan () {
129+ m := scanner .Text ()
130+ a .logger .Info (m )
131+ }
132+ scannerErr := scanner .Err ()
133+ if scannerErr != nil {
134+ * stdoutErr = fmt .Errorf ("stdout scanner error: %w" , scannerErr )
135+ }
136+ }
0 commit comments