@@ -2,18 +2,46 @@ package integration
22
33import (
44 "fmt"
5+ "io"
56 "log"
67 "os"
78 "os/exec"
89 "path/filepath"
910 "strings"
11+ "sync"
1012)
1113
1214type gitRepository struct {
1315 Path string
1416}
1517
18+ var testGitRepositoryTemplate = sync .OnceValues (func () (string , error ) {
19+ repo , err := createSeedTestGitRepository ()
20+ if err != nil {
21+ return "" , err
22+ }
23+ return repo .Path , nil
24+ })
25+
1626func createTestGitRespository () (* gitRepository , error ) {
27+ templatePath , err := testGitRepositoryTemplate ()
28+ if err != nil {
29+ return nil , err
30+ }
31+
32+ repoPath , err := newGitRepositoryPath ()
33+ if err != nil {
34+ return nil , err
35+ }
36+ if err := copyDirectory (templatePath , repoPath ); err != nil {
37+ _ = os .RemoveAll (repoPath )
38+ return nil , fmt .Errorf ("copying git repo template: %w" , err )
39+ }
40+
41+ return & gitRepository {Path : repoPath }, nil
42+ }
43+
44+ func createSeedTestGitRepository () (* gitRepository , error ) {
1745 repo , err := newGitRepository ()
1846 if err != nil {
1947 return nil , err
@@ -95,9 +123,25 @@ func createTestGitRespository() (*gitRepository, error) {
95123}
96124
97125func newGitRepository () (* gitRepository , error ) {
126+ tempDir , err := newGitRepositoryPath ()
127+ if err != nil {
128+ return nil , err
129+ }
130+
131+ gr := & gitRepository {Path : tempDir }
132+ gitErr := gr .ExecuteAll ([][]string {
133+ {"init" },
134+ {"config" , "user.email" , "you@example.com" },
135+ {"config" , "user.name" , "Your Name" },
136+ })
137+
138+ return gr , gitErr
139+ }
140+
141+ func newGitRepositoryPath () (string , error ) {
98142 tempDirRaw , err := os .MkdirTemp ("" , "git-repo" )
99143 if err != nil {
100- return nil , fmt .Errorf ("Error creating temp dir: %w" , err )
144+ return "" , fmt .Errorf ("Error creating temp dir: %w" , err )
101145 }
102146
103147 // io.TempDir on Windows tilde-shortens (8.3 style?) long filenames in the path.
@@ -118,17 +162,68 @@ func newGitRepository() (*gitRepository, error) {
118162 // EvalSymlinks seems best? Maybe there's a better way?
119163 tempDir , err := filepath .EvalSymlinks (tempDirRaw )
120164 if err != nil {
121- return nil , fmt .Errorf ("EvalSymlinks for temp dir: %w" , err )
165+ return "" , fmt .Errorf ("EvalSymlinks for temp dir: %w" , err )
122166 }
167+ return tempDir , nil
168+ }
123169
124- gr := & gitRepository {Path : tempDir }
125- gitErr := gr .ExecuteAll ([][]string {
126- {"init" },
127- {"config" , "user.email" , "you@example.com" },
128- {"config" , "user.name" , "Your Name" },
170+ func copyDirectory (src , dst string ) error {
171+ return filepath .WalkDir (src , func (path string , d os.DirEntry , walkErr error ) error {
172+ if walkErr != nil {
173+ return walkErr
174+ }
175+
176+ relPath , err := filepath .Rel (src , path )
177+ if err != nil {
178+ return err
179+ }
180+ if relPath == "." {
181+ return nil
182+ }
183+
184+ targetPath := filepath .Join (dst , relPath )
185+ info , err := os .Lstat (path )
186+ if err != nil {
187+ return err
188+ }
189+
190+ switch mode := info .Mode (); {
191+ case mode .IsDir ():
192+ return os .MkdirAll (targetPath , mode .Perm ())
193+ case mode .IsRegular ():
194+ return copyFile (path , targetPath , mode )
195+ case mode & os .ModeSymlink != 0 :
196+ linkTarget , err := os .Readlink (path )
197+ if err != nil {
198+ return err
199+ }
200+ return os .Symlink (linkTarget , targetPath )
201+ default :
202+ return fmt .Errorf ("unsupported file mode %s for %s" , mode , path )
203+ }
129204 })
205+ }
130206
131- return gr , gitErr
207+ func copyFile (src , dst string , mode os.FileMode ) error {
208+ reader , err := os .Open (src )
209+ if err != nil {
210+ return err
211+ }
212+ defer reader .Close ()
213+
214+ writer , err := os .OpenFile (dst , os .O_CREATE | os .O_TRUNC | os .O_WRONLY , mode .Perm ())
215+ if err != nil {
216+ return err
217+ }
218+
219+ if _ , err := io .Copy (writer , reader ); err != nil {
220+ writer .Close ()
221+ return err
222+ }
223+ if err := writer .Close (); err != nil {
224+ return err
225+ }
226+ return os .Chmod (dst , mode .Perm ())
132227}
133228
134229func (gr * gitRepository ) Add (path string ) error {
0 commit comments