81ee0eccac4f4c8fa6bdd452fa58bea62f2ec1ef

Author
Ayman Bagabas <ayman.bagabas@gmail.com>
Committer
Ayman Bagabas <ayman.bagabas@gmail.com>
Date

Message

fix(git): hang on git i/o error

Diff

 1diff --git a/pkg/git/service.go b/pkg/git/service.go
 2index 9608af999aefb07183369b6d37ef24f063a666af..24576421d4b9a0850501a34143ae6482d4358391 100644
 3--- a/pkg/git/service.go
 4+++ b/pkg/git/service.go
 5@@ -8,8 +8,9 @@ import (
 6 	"os"
 7 	"os/exec"
 8 	"strings"
 9+	"sync"
10 
11-	"golang.org/x/sync/errgroup"
12+	"github.com/charmbracelet/log"
13 )
14 
15 // Service is a Git daemon service.
16@@ -118,34 +119,46 @@ func gitServiceHandler(ctx context.Context, svc Service, scmd ServiceCommand) er
17 		return err
18 	}
19 
20-	errg, _ := errgroup.WithContext(ctx)
21+	wg := &sync.WaitGroup{}
22 
23 	// stdin
24 	if scmd.Stdin != nil {
25-		errg.Go(func() error {
26+		go func() {
27 			defer stdin.Close() // nolint: errcheck
28-			_, err := io.Copy(stdin, scmd.Stdin)
29-			return err
30-		})
31+			if _, err := io.Copy(stdin, scmd.Stdin); err != nil {
32+				log.Errorf("gitServiceHandler: failed to copy stdin: %v", err)
33+			}
34+		}()
35 	}
36 
37 	// stdout
38 	if scmd.Stdout != nil {
39-		errg.Go(func() error {
40-			_, err := io.Copy(scmd.Stdout, stdout)
41-			return err
42-		})
43+		wg.Add(1)
44+		go func() {
45+			defer wg.Done()
46+			if _, err := io.Copy(scmd.Stdout, stdout); err != nil {
47+				log.Errorf("gitServiceHandler: failed to copy stdout: %v", err)
48+			}
49+		}()
50 	}
51 
52 	// stderr
53 	if scmd.Stderr != nil {
54-		errg.Go(func() error {
55-			_, erro := io.Copy(scmd.Stderr, stderr)
56-			return erro
57-		})
58+		wg.Add(1)
59+		go func() {
60+			defer wg.Done()
61+			if _, erro := io.Copy(scmd.Stderr, stderr); err != nil {
62+				log.Errorf("gitServiceHandler: failed to copy stderr: %v", erro)
63+			}
64+		}()
65 	}
66 
67-	err = errors.Join(errg.Wait(), cmd.Wait())
68+	// Ensure all the output is written before waiting for the command to
69+	// finish.
70+	// Stdin is handled by the client side.
71+	wg.Wait()
72+
73+	err = cmd.Wait()
74 	if err != nil && errors.Is(err, os.ErrNotExist) {
75 		return ErrInvalidRepo
76 	} else if err != nil {