@@ -20,6 +20,7 @@ import (
2020 "bytes"
2121 "context"
2222 "fmt"
23+ "io/ioutil"
2324 "math/rand"
2425 "net/url"
2526 "os"
@@ -28,6 +29,7 @@ import (
2829 "strings"
2930 "time"
3031
32+ securejoin "github.com/cyphar/filepath-securejoin"
3133 "github.com/fluxcd/pkg/apis/acl"
3234 git2go "github.com/libgit2/git2go/v33"
3335 "golang.org/x/crypto/openpgp"
@@ -1329,57 +1331,170 @@ func commitInRepo(repoURL, branch, msg string, changeFiles func(path string)) {
13291331
13301332// Initialise a git server with a repo including the files in dir.
13311333func initGitRepo (gitServer * gittestserver.GitServer , fixture , branch , repositoryPath string ) error {
1332- fs := memfs .New ()
1333- repo , err := git .Init (memory .NewStorage (), fs )
1334+ workDir , err := securejoin .SecureJoin (gitServer .Root (), repositoryPath )
13341335 if err != nil {
13351336 return err
13361337 }
13371338
1338- err = populateRepoFromFixture ( repo , fixture )
1339+ repo , err := initGitRepoPlain ( fixture , workDir )
13391340 if err != nil {
13401341 return err
13411342 }
13421343
1343- working , err := repo . Worktree ( )
1344+ commitID , err := headCommit ( repo )
13441345 if err != nil {
13451346 return err
13461347 }
1347- if err = working .Checkout (& git.CheckoutOptions {
1348- Branch : plumbing .NewBranchReferenceName (branch ),
1349- Create : true ,
1350- }); err != nil {
1348+
1349+ _ , err = repo .CreateBranch (branch , commitID , false )
1350+ if err != nil {
13511351 return err
13521352 }
13531353
1354- remote , err := repo .CreateRemote (& config.RemoteConfig {
1355- Name : "origin" ,
1356- URLs : []string {gitServer .HTTPAddressWithCredentials () + repositoryPath },
1357- })
1354+ return repo .Remotes .AddPush ("origin" , branchRefName (branch ))
1355+ }
1356+
1357+ func initGitRepoPlain (fixture , repositoryPath string ) (* git2go.Repository , error ) {
1358+ repo , err := git2go .InitRepository (repositoryPath , false )
13581359 if err != nil {
1359- return err
1360+ return nil , err
13601361 }
13611362
1362- err = remote .Push (& git.PushOptions {
1363- RefSpecs : []config.RefSpec {
1364- config .RefSpec (fmt .Sprintf ("refs/heads/%s:refs/heads/%s" , branch , branch )),
1365- },
1366- })
1363+ err = copyDir (fixture , repositoryPath )
13671364 if err != nil {
1365+ return nil , err
1366+ }
1367+
1368+ _ , err = commitWorkDir (repo , "main" )
1369+ if err != nil {
1370+ return nil , err
1371+ }
1372+
1373+ return repo , nil
1374+ }
1375+
1376+ func headFromBranch (repo * git2go.Repository , branchName string ) (* git2go.Commit , error ) {
1377+ branch , err := repo .LookupBranch (branchName , git2go .BranchAll )
1378+ if err != nil {
1379+ return nil , err
1380+ }
1381+ defer branch .Free ()
1382+
1383+ return repo .LookupCommit (branch .Reference .Target ())
1384+ }
1385+
1386+ func commitWorkDir (repo * git2go.Repository , branchName string ) (* git2go.Oid , error ) {
1387+ var parentC []* git2go.Commit
1388+ head , err := headFromBranch (repo , branchName )
1389+ if err == nil {
1390+ defer head .Free ()
1391+ parentC = append (parentC , head )
1392+ }
1393+
1394+ index , err := repo .Index ()
1395+ if err != nil {
1396+ return nil , err
1397+ }
1398+ defer index .Free ()
1399+
1400+ // add to index any files that are not within .git/
1401+ if err = filepath .Walk (repo .Workdir (),
1402+ func (path string , info os.FileInfo , err error ) error {
1403+ if err != nil {
1404+ return err
1405+ }
1406+ rel , err := filepath .Rel (repo .Workdir (), path )
1407+ if err != nil {
1408+ return err
1409+ }
1410+ f , err := os .Stat (path )
1411+ if err != nil {
1412+ return err
1413+ }
1414+ if f .IsDir () || strings .HasPrefix (rel , ".git" ) || rel == "." {
1415+ return nil
1416+ }
1417+ if err := index .AddByPath (rel ); err != nil {
1418+ return err
1419+ }
1420+ return nil
1421+ }); err != nil {
1422+ return nil , err
1423+ }
1424+
1425+ if err := index .Write (); err != nil {
1426+ return nil , err
1427+ }
1428+
1429+ treeID , err := index .WriteTree ()
1430+ if err != nil {
1431+ return nil , err
1432+ }
1433+
1434+ tree , err := repo .LookupTree (treeID )
1435+ if err != nil {
1436+ return nil , err
1437+ }
1438+ defer tree .Free ()
1439+
1440+ sig := mockSignature (time .Now ())
1441+ c , err := repo .CreateCommit ("HEAD" , sig , sig , "Committing " + repo .Workdir (), tree , parentC ... )
1442+ if err != nil {
1443+ return nil , err
1444+ }
1445+ return c , nil
1446+ }
1447+
1448+ func copyDir (src string , dest string ) error {
1449+ file , err := os .Stat (src )
1450+ if err != nil {
1451+ return err
1452+ }
1453+ if ! file .IsDir () {
1454+ return fmt .Errorf ("source %q must be a directory" , file .Name ())
1455+ }
1456+
1457+ if err = os .MkdirAll (dest , 0o755 ); err != nil {
13681458 return err
13691459 }
13701460
1371- // Adhoc fix to a bug in which most clone operations during test fail.
1372- // This started with the upgrade from libgit2 1.1.1 to 1.3.0, and
1373- // requires further investigation as to why repositories created and
1374- // amended by go-git stopped working for libgit2 clone operations.
1375- repo2 , err := git2go .OpenRepository (gitServer .Root () + repositoryPath )
1461+ files , err := ioutil .ReadDir (src )
13761462 if err != nil {
13771463 return err
13781464 }
1379- defer repo2 .Free ()
1380- _ , err = commitFile (repo2 , "branch" , "init" , time .Now ())
13811465
1382- return err
1466+ for _ , f := range files {
1467+ srcFile := filepath .Join (src , f .Name ())
1468+ destFile := filepath .Join (dest , f .Name ())
1469+
1470+ if f .IsDir () {
1471+ if err = copyDir (srcFile , destFile ); err != nil {
1472+ return err
1473+ }
1474+ }
1475+
1476+ if ! f .IsDir () {
1477+ // ignore symlinks
1478+ if f .Mode ()& os .ModeSymlink == os .ModeSymlink {
1479+ continue
1480+ }
1481+
1482+ content , err := ioutil .ReadFile (srcFile )
1483+ if err != nil {
1484+ return err
1485+ }
1486+
1487+ if err = ioutil .WriteFile (destFile , content , 0o755 ); err != nil {
1488+ return err
1489+ }
1490+ }
1491+ }
1492+
1493+ return nil
1494+ }
1495+
1496+ func branchRefName (branch string ) string {
1497+ return fmt .Sprintf ("refs/heads/%s:refs/heads/%s" , branch , branch )
13831498}
13841499
13851500func checkoutBranch (repo * git.Repository , branch string ) error {
@@ -1509,3 +1624,26 @@ func headCommit(repo *git2go.Repository) (*git2go.Commit, error) {
15091624 }
15101625 return c , nil
15111626}
1627+
1628+ func clone (repoURL , remoteName , branchName string ) (* git2go.Repository , error ) {
1629+ dir , err := os .MkdirTemp ("" , "iac-clone-*" )
1630+ if err != nil {
1631+ return nil , err
1632+ }
1633+ opts := & git2go.CloneOptions {
1634+ Bare : false ,
1635+ CheckoutBranch : branchName ,
1636+ CheckoutOptions : git2go.CheckoutOptions {
1637+ Strategy : git2go .CheckoutForce ,
1638+ },
1639+ FetchOptions : git2go.FetchOptions {
1640+ RemoteCallbacks : git2go.RemoteCallbacks {
1641+ CertificateCheckCallback : func (cert * git2go.Certificate , valid bool , hostname string ) error {
1642+ return nil
1643+ },
1644+ },
1645+ },
1646+ }
1647+
1648+ return git2go .Clone (repoURL , dir , opts )
1649+ }
0 commit comments