@@ -2,78 +2,73 @@ package git
2
2
3
3
import (
4
4
"bytes"
5
+ "context"
5
6
"fmt"
6
7
"os"
7
- "os/exec"
8
8
"strings"
9
- )
10
9
11
- func GetExecCommand (args []string ) (* exec.Cmd , error ) {
12
- git , err := exec .LookPath ("git" )
13
- if err != nil {
14
- return nil , fmt .Errorf ("failed to find 'git' on the path: %w" , err )
15
- }
10
+ "github.com/github/git-bundle-server/internal/cmd"
11
+ "github.com/github/git-bundle-server/internal/log"
12
+ )
16
13
17
- cmd := exec .Command (git , args ... )
18
- cmd .Env = append (cmd .Env , "LC_CTYPE=C" )
14
+ type GitHelper interface {
15
+ CreateBundle (ctx context.Context , repoDir string , filename string ) (bool , error )
16
+ CreateBundleFromRefs (ctx context.Context , repoDir string , filename string , refs map [string ]string ) error
17
+ CreateIncrementalBundle (ctx context.Context , repoDir string , filename string , prereqs []string ) (bool , error )
18
+ CloneBareRepo (ctx context.Context , url string , destination string ) error
19
+ }
19
20
20
- return cmd , nil
21
+ type gitHelper struct {
22
+ logger log.TraceLogger
23
+ cmdExec cmd.CommandExecutor
21
24
}
22
25
23
- func GitCommand ( args ... string ) error {
24
- cmd , err := GetExecCommand ( args )
25
- if err != nil {
26
- return err
26
+ func NewGitHelper ( l log. TraceLogger , c cmd. CommandExecutor ) GitHelper {
27
+ return & gitHelper {
28
+ logger : l ,
29
+ cmdExec : c ,
27
30
}
31
+ }
28
32
29
- cmd .Stderr = os .Stderr
30
- cmd .Stdout = os .Stdout
31
-
32
- err = cmd .Start ()
33
- if err != nil {
34
- return fmt .Errorf ("git command failed to start: %w" , err )
35
- }
33
+ func (g * gitHelper ) gitCommand (ctx context.Context , args ... string ) error {
34
+ exitCode , err := g .cmdExec .Run (ctx , "git" , args ,
35
+ cmd .Stdout (os .Stdout ),
36
+ cmd .Stderr (os .Stderr ),
37
+ cmd .Env ([]string {"LC_CTYPE=C" }),
38
+ )
36
39
37
- err = cmd .Wait ()
38
40
if err != nil {
39
- return fmt .Errorf ("git command returned a failure: %w" , err )
41
+ return g .logger .Error (ctx , err )
42
+ } else if exitCode != 0 {
43
+ return g .logger .Errorf (ctx , "'git' exited with status %d" , exitCode )
40
44
}
41
45
42
- return err
46
+ return nil
43
47
}
44
48
45
- func GitCommandWithStdin (stdinLines []string , args ... string ) error {
46
- cmd , err := GetExecCommand (args )
47
- if err != nil {
48
- return err
49
- }
50
-
49
+ func (g * gitHelper ) gitCommandWithStdin (ctx context.Context , stdinLines []string , args ... string ) error {
51
50
buffer := bytes.Buffer {}
52
51
for line := range stdinLines {
53
52
buffer .Write ([]byte (stdinLines [line ] + "\n " ))
54
53
}
54
+ exitCode , err := g .cmdExec .Run (ctx , "git" , args ,
55
+ cmd .Stdin (& buffer ),
56
+ cmd .Stdout (os .Stdout ),
57
+ cmd .Stderr (os .Stderr ),
58
+ cmd .Env ([]string {"LC_CTYPE=C" }),
59
+ )
55
60
56
- cmd .Stdin = & buffer
57
-
58
- errorBuffer := bytes.Buffer {}
59
- cmd .Stderr = & errorBuffer
60
- cmd .Stdout = os .Stdout
61
-
62
- err = cmd .Start ()
63
- if err != nil {
64
- return fmt .Errorf ("git command failed to start: %w" , err )
65
- }
66
-
67
- err = cmd .Wait ()
68
61
if err != nil {
69
- return fmt .Errorf ("git command returned a failure: %w\n stderr: %s" , err , errorBuffer .String ())
62
+ return g .logger .Error (ctx , err )
63
+ } else if exitCode != 0 {
64
+ return g .logger .Errorf (ctx , "'git' exited with status %d" , exitCode )
70
65
}
71
66
72
- return err
67
+ return nil
73
68
}
74
69
75
- func CreateBundle (repoDir string , filename string ) (bool , error ) {
76
- err := GitCommand (
70
+ func ( g * gitHelper ) CreateBundle (ctx context. Context , repoDir string , filename string ) (bool , error ) {
71
+ err := g . gitCommand ( ctx ,
77
72
"-C" , repoDir , "bundle" , "create" ,
78
73
filename , "--branches" )
79
74
if err != nil {
@@ -86,19 +81,19 @@ func CreateBundle(repoDir string, filename string) (bool, error) {
86
81
return true , nil
87
82
}
88
83
89
- func CreateBundleFromRefs (repoDir string , filename string , refs map [string ]string ) error {
84
+ func ( g * gitHelper ) CreateBundleFromRefs (ctx context. Context , repoDir string , filename string , refs map [string ]string ) error {
90
85
refNames := []string {}
91
86
92
87
for ref , oid := range refs {
93
- err := GitCommand ( "-C" , repoDir , "branch" , "-f" , ref , oid )
88
+ err := g . gitCommand ( ctx , "-C" , repoDir , "branch" , "-f" , ref , oid )
94
89
if err != nil {
95
90
return fmt .Errorf ("failed to create ref %s: %w" , ref , err )
96
91
}
97
92
98
93
refNames = append (refNames , ref )
99
94
}
100
95
101
- err := GitCommandWithStdin (
96
+ err := g . gitCommandWithStdin ( ctx ,
102
97
refNames ,
103
98
"-C" , repoDir , "bundle" , "create" ,
104
99
filename , "--stdin" )
@@ -109,8 +104,8 @@ func CreateBundleFromRefs(repoDir string, filename string, refs map[string]strin
109
104
return nil
110
105
}
111
106
112
- func CreateIncrementalBundle (repoDir string , filename string , prereqs []string ) (bool , error ) {
113
- err := GitCommandWithStdin (
107
+ func ( g * gitHelper ) CreateIncrementalBundle (ctx context. Context , repoDir string , filename string , prereqs []string ) (bool , error ) {
108
+ err := g . gitCommandWithStdin ( ctx ,
114
109
prereqs , "-C" , repoDir , "bundle" , "create" ,
115
110
filename , "--stdin" , "--branches" )
116
111
if err != nil {
@@ -122,3 +117,23 @@ func CreateIncrementalBundle(repoDir string, filename string, prereqs []string)
122
117
123
118
return true , nil
124
119
}
120
+
121
+ func (g * gitHelper ) CloneBareRepo (ctx context.Context , url string , destination string ) error {
122
+ gitErr := g .gitCommand (ctx , "clone" , "--bare" , url , destination )
123
+
124
+ if gitErr != nil {
125
+ return g .logger .Errorf (ctx , "failed to clone repository: %w" , gitErr )
126
+ }
127
+
128
+ gitErr = g .gitCommand (ctx , "-C" , destination , "config" , "remote.origin.fetch" , "+refs/heads/*:refs/heads/*" )
129
+ if gitErr != nil {
130
+ return g .logger .Errorf (ctx , "failed to configure refspec: %w" , gitErr )
131
+ }
132
+
133
+ gitErr = g .gitCommand (ctx , "-C" , destination , "fetch" , "origin" )
134
+ if gitErr != nil {
135
+ return g .logger .Errorf (ctx , "failed to fetch latest refs: %w" , gitErr )
136
+ }
137
+
138
+ return nil
139
+ }
0 commit comments