@@ -118,6 +118,7 @@ type repoSync struct {
118
118
cmd string // the git command to run
119
119
root absPath // absolute path to the root directory
120
120
remoteRepo string // remote repo to sync
121
+ localRepo absPath // absolute path to the local repo
121
122
ref string // the ref to sync
122
123
depth int // for shallow sync
123
124
submodules submodulesMode // how to handle submodules
@@ -707,6 +708,7 @@ func main() {
707
708
cmd : * flGitCmd ,
708
709
root : absRoot ,
709
710
remoteRepo : * flRepo ,
711
+ localRepo : absRoot .Join (".repo" ),
710
712
ref : * flRef ,
711
713
depth : * flDepth ,
712
714
submodules : submodulesMode (* flSubmodules ),
@@ -1212,40 +1214,37 @@ func (git *repoSync) initRepo(ctx context.Context) error {
1212
1214
needGitInit := false
1213
1215
1214
1216
// Check out the git root, and see if it is already usable.
1215
- _ , err := os .Stat (git .root .String ())
1217
+ _ , err := os .Stat (git .localRepo .String ())
1216
1218
switch {
1217
1219
case os .IsNotExist (err ):
1218
1220
// Probably the first sync. defaultDirMode ensures that this is usable
1219
1221
// as a volume when the consumer isn't running as the same UID.
1220
- git .log .V (1 ).Info ("repo directory does not exist, creating it" , "path" , git .root )
1221
- if err := os .MkdirAll (git .root .String (), defaultDirMode ); err != nil {
1222
+ git .log .V (1 ).Info ("repo directory does not exist, creating it" , "path" , git .localRepo )
1223
+ if err := os .MkdirAll (git .localRepo .String (), defaultDirMode ); err != nil {
1222
1224
return err
1223
1225
}
1224
1226
needGitInit = true
1225
1227
case err != nil :
1226
1228
return err
1227
1229
default :
1228
1230
// Make sure the directory we found is actually usable.
1229
- git .log .V (3 ).Info ("repo directory exists" , "path" , git .root )
1231
+ git .log .V (3 ).Info ("repo directory exists" , "path" , git .localRepo )
1230
1232
if git .sanityCheckRepo (ctx ) {
1231
- git .log .V (4 ).Info ("repo directory is valid" , "path" , git .root )
1233
+ git .log .V (4 ).Info ("repo directory is valid" , "path" , git .localRepo )
1232
1234
} else {
1233
- // Maybe a previous run crashed? Git won't use this dir. We remove
1234
- // the contents rather than the dir itself, because a common use-case
1235
- // is to have a volume mounted at git.root, which makes removing it
1236
- // impossible.
1237
- git .log .V (0 ).Info ("repo directory was empty or failed checks" , "path" , git .root )
1238
- if err := removeDirContents (git .root , git .log ); err != nil {
1239
- return fmt .Errorf ("can't wipe unusable root directory: %w" , err )
1235
+ // Maybe a previous run crashed? Git won't use this dir.
1236
+ git .log .V (0 ).Info ("repo directory was empty or failed checks" , "path" , git .localRepo )
1237
+ if err := os .RemoveAll (git .localRepo .String ()); err != nil {
1238
+ return fmt .Errorf ("can't remove unusable repo directory: %w" , err )
1240
1239
}
1241
1240
needGitInit = true
1242
1241
}
1243
1242
}
1244
1243
1245
1244
if needGitInit {
1246
1245
// Running `git init` in an existing repo is safe (according to git docs).
1247
- git .log .V (0 ).Info ("initializing repo directory" , "path" , git .root )
1248
- if _ , _ , err := git .Run (ctx , git .root , "init" , "-b" , "git-sync" ); err != nil {
1246
+ git .log .V (0 ).Info ("initializing repo directory" , "path" , git .localRepo )
1247
+ if _ , _ , err := git .Run (ctx , git .localRepo , "init" , "-b" , "git-sync" ); err != nil {
1249
1248
return err
1250
1249
}
1251
1250
if ! git .sanityCheckRepo (ctx ) {
@@ -1255,17 +1254,17 @@ func (git *repoSync) initRepo(ctx context.Context) error {
1255
1254
1256
1255
// The "origin" remote has special meaning, like in relative-path
1257
1256
// submodules.
1258
- if stdout , stderr , err := git .Run (ctx , git .root , "remote" , "get-url" , "origin" ); err != nil {
1257
+ if stdout , stderr , err := git .Run (ctx , git .localRepo , "remote" , "get-url" , "origin" ); err != nil {
1259
1258
if ! strings .Contains (stderr , "No such remote" ) {
1260
1259
return err
1261
1260
}
1262
1261
// It doesn't exist - make it.
1263
- if _ , _ , err := git .Run (ctx , git .root , "remote" , "add" , "origin" , git .remoteRepo ); err != nil {
1262
+ if _ , _ , err := git .Run (ctx , git .localRepo , "remote" , "add" , "origin" , git .remoteRepo ); err != nil {
1264
1263
return err
1265
1264
}
1266
1265
} else if strings .TrimSpace (stdout ) != git .remoteRepo {
1267
1266
// It exists, but is wrong.
1268
- if _ , _ , err := git .Run (ctx , git .root , "remote" , "set-url" , "origin" , git .remoteRepo ); err != nil {
1267
+ if _ , _ , err := git .Run (ctx , git .localRepo , "remote" , "set-url" , "origin" , git .remoteRepo ); err != nil {
1269
1268
return err
1270
1269
}
1271
1270
}
@@ -1312,32 +1311,32 @@ func hasGitLockFile(gitRoot absPath) (string, error) {
1312
1311
1313
1312
// sanityCheckRepo tries to make sure that the repo dir is a valid git repository.
1314
1313
func (git * repoSync ) sanityCheckRepo (ctx context.Context ) bool {
1315
- git .log .V (3 ).Info ("sanity-checking git repo" , "repo" , git .root )
1314
+ git .log .V (3 ).Info ("sanity-checking git repo" , "repo" , git .localRepo )
1316
1315
// If it is empty, we are done.
1317
- if empty , err := dirIsEmpty (git .root ); err != nil {
1318
- git .log .Error (err , "can't list repo directory" , "path" , git .root )
1316
+ if empty , err := dirIsEmpty (git .localRepo ); err != nil {
1317
+ git .log .Error (err , "can't list repo directory" , "path" , git .localRepo )
1319
1318
return false
1320
1319
} else if empty {
1321
- git .log .V (3 ).Info ("repo directory is empty" , "path" , git .root )
1320
+ git .log .V (3 ).Info ("repo directory is empty" , "path" , git .localRepo )
1322
1321
return false
1323
1322
}
1324
1323
1325
1324
// Check that this is actually the root of the repo.
1326
- if root , _ , err := git .Run (ctx , git .root , "rev-parse" , "--show-toplevel" ); err != nil {
1327
- git .log .Error (err , "can't get repo toplevel" , "path" , git .root )
1325
+ if root , _ , err := git .Run (ctx , git .localRepo , "rev-parse" , "--show-toplevel" ); err != nil {
1326
+ git .log .Error (err , "can't get repo toplevel" , "path" , git .localRepo )
1328
1327
return false
1329
1328
} else {
1330
1329
root = strings .TrimSpace (root )
1331
- if root != git .root .String () {
1332
- git .log .Error (nil , "repo directory is under another repo" , "path" , git .root , "parent" , root )
1330
+ if root != git .localRepo .String () {
1331
+ git .log .Error (nil , "repo directory is under another repo" , "path" , git .localRepo , "parent" , root )
1333
1332
return false
1334
1333
}
1335
1334
}
1336
1335
1337
1336
// Consistency-check the repo. Don't use --verbose because it can be
1338
1337
// REALLY verbose.
1339
- if _ , _ , err := git .Run (ctx , git .root , "fsck" , "--no-progress" , "--connectivity-only" ); err != nil {
1340
- git .log .Error (err , "repo fsck failed" , "path" , git .root )
1338
+ if _ , _ , err := git .Run (ctx , git .localRepo , "fsck" , "--no-progress" , "--connectivity-only" ); err != nil {
1339
+ git .log .Error (err , "repo fsck failed" , "path" , git .localRepo )
1341
1340
return false
1342
1341
}
1343
1342
@@ -1359,7 +1358,7 @@ func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
1359
1358
// files checked out - git could have died halfway through and the repo will
1360
1359
// still pass this check.
1361
1360
func (git * repoSync ) sanityCheckWorktree (ctx context.Context , worktree worktree ) bool {
1362
- git .log .V (3 ).Info ("sanity-checking worktree" , "repo" , git .root , "worktree" , worktree )
1361
+ git .log .V (3 ).Info ("sanity-checking worktree" , "repo" , git .localRepo , "worktree" , worktree )
1363
1362
1364
1363
// If it is empty, we are done.
1365
1364
if empty , err := dirIsEmpty (worktree .Path ()); err != nil {
@@ -1399,13 +1398,6 @@ func dirIsEmpty(dir absPath) (bool, error) {
1399
1398
return len (dirents ) == 0 , nil
1400
1399
}
1401
1400
1402
- // removeDirContents iterated the specified dir and removes all contents
1403
- func removeDirContents (dir absPath , log * logging.Logger ) error {
1404
- return removeDirContentsIf (dir , log , func (fi os.FileInfo ) (bool , error ) {
1405
- return true , nil
1406
- })
1407
- }
1408
-
1409
1401
func removeDirContentsIf (dir absPath , log * logging.Logger , fn func (fi os.FileInfo ) (bool , error )) error {
1410
1402
dirents , err := os .ReadDir (dir .String ())
1411
1403
if err != nil {
@@ -1489,7 +1481,7 @@ func (git *repoSync) removeWorktree(ctx context.Context, worktree worktree) erro
1489
1481
if err := os .RemoveAll (worktree .Path ().String ()); err != nil {
1490
1482
return fmt .Errorf ("error removing directory: %w" , err )
1491
1483
}
1492
- if _ , _ , err := git .Run (ctx , git .root , "worktree" , "prune" , "--verbose" ); err != nil {
1484
+ if _ , _ , err := git .Run (ctx , git .localRepo , "worktree" , "prune" , "--verbose" ); err != nil {
1493
1485
return err
1494
1486
}
1495
1487
return nil
@@ -1510,7 +1502,7 @@ func (git *repoSync) createWorktree(ctx context.Context, hash string) (worktree,
1510
1502
}
1511
1503
1512
1504
git .log .V (1 ).Info ("adding worktree" , "path" , worktree .Path (), "hash" , hash )
1513
- _ , _ , err := git .Run (ctx , git .root , "worktree" , "add" , "--force" , "--detach" , worktree .Path ().String (), hash , "--no-checkout" )
1505
+ _ , _ , err := git .Run (ctx , git .localRepo , "worktree" , "add" , "--force" , "--detach" , worktree .Path ().String (), hash , "--no-checkout" )
1514
1506
if err != nil {
1515
1507
return "" , err
1516
1508
}
@@ -1528,7 +1520,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
1528
1520
// using relative paths, so that other containers can use a different volume
1529
1521
// mount name.
1530
1522
rootDotGit := ""
1531
- if rel , err := filepath .Rel (worktree .Path ().String (), git .root .String ()); err != nil {
1523
+ if rel , err := filepath .Rel (worktree .Path ().String (), git .localRepo .String ()); err != nil {
1532
1524
return err
1533
1525
} else {
1534
1526
rootDotGit = filepath .Join (rel , ".git" )
@@ -1540,7 +1532,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
1540
1532
1541
1533
// If sparse checkout is requested, configure git for it, otherwise
1542
1534
// unconfigure it.
1543
- gitInfoPath := filepath .Join (git .root .String (), ".git/worktrees" , hash , "info" )
1535
+ gitInfoPath := filepath .Join (git .localRepo .String (), ".git/worktrees" , hash , "info" )
1544
1536
gitSparseConfigPath := filepath .Join (gitInfoPath , "sparse-checkout" )
1545
1537
if git .sparseFile == "" {
1546
1538
os .RemoveAll (gitSparseConfigPath )
@@ -1621,13 +1613,13 @@ func (git *repoSync) cleanup(ctx context.Context) error {
1621
1613
1622
1614
// Let git know we don't need those old commits any more.
1623
1615
git .log .V (3 ).Info ("pruning worktrees" )
1624
- if _ , _ , err := git .Run (ctx , git .root , "worktree" , "prune" , "--verbose" ); err != nil {
1616
+ if _ , _ , err := git .Run (ctx , git .localRepo , "worktree" , "prune" , "--verbose" ); err != nil {
1625
1617
cleanupErrs = append (cleanupErrs , err )
1626
1618
}
1627
1619
1628
1620
// Expire old refs.
1629
1621
git .log .V (3 ).Info ("expiring unreachable refs" )
1630
- if _ , _ , err := git .Run (ctx , git .root , "reflog" , "expire" , "--expire-unreachable=all" , "--all" ); err != nil {
1622
+ if _ , _ , err := git .Run (ctx , git .localRepo , "reflog" , "expire" , "--expire-unreachable=all" , "--all" ); err != nil {
1631
1623
cleanupErrs = append (cleanupErrs , err )
1632
1624
}
1633
1625
@@ -1643,7 +1635,7 @@ func (git *repoSync) cleanup(ctx context.Context) error {
1643
1635
args = append (args , "--aggressive" )
1644
1636
}
1645
1637
git .log .V (3 ).Info ("running git garbage collection" )
1646
- if _ , _ , err := git .Run (ctx , git .root , args ... ); err != nil {
1638
+ if _ , _ , err := git .Run (ctx , git .localRepo , args ... ); err != nil {
1647
1639
cleanupErrs = append (cleanupErrs , err )
1648
1640
}
1649
1641
}
@@ -1746,7 +1738,7 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
1746
1738
// their underlying commit hashes, but has no effect if we fetched a
1747
1739
// branch, plain tag, or hash.
1748
1740
remoteHash := ""
1749
- if output , _ , err := git .Run (ctx , git .root , "rev-parse" , "FETCH_HEAD^{}" ); err != nil {
1741
+ if output , _ , err := git .Run (ctx , git .localRepo , "rev-parse" , "FETCH_HEAD^{}" ); err != nil {
1750
1742
return false , "" , err
1751
1743
} else {
1752
1744
remoteHash = strings .Trim (output , "\n " )
@@ -1778,14 +1770,14 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
1778
1770
// Reset the repo (note: not the worktree - that happens later) to the new
1779
1771
// ref. This makes subsequent fetches much less expensive. It uses --soft
1780
1772
// so no files are checked out.
1781
- if _ , _ , err := git .Run (ctx , git .root , "reset" , "--soft" , remoteHash ); err != nil {
1773
+ if _ , _ , err := git .Run (ctx , git .localRepo , "reset" , "--soft" , remoteHash ); err != nil {
1782
1774
return false , "" , err
1783
1775
}
1784
1776
1785
1777
// If we have a new hash, make a new worktree
1786
1778
newWorktree := currentWorktree
1787
1779
if changed {
1788
- // Create a worktree for this hash in git.root .
1780
+ // Create a worktree for this hash.
1789
1781
if wt , err := git .createWorktree (ctx , remoteHash ); err != nil {
1790
1782
return false , "" , err
1791
1783
} else {
@@ -1858,15 +1850,15 @@ func (git *repoSync) fetch(ctx context.Context, ref string) error {
1858
1850
args = append (args , "--unshallow" )
1859
1851
}
1860
1852
}
1861
- if _ , _ , err := git .Run (ctx , git .root , args ... ); err != nil {
1853
+ if _ , _ , err := git .Run (ctx , git .localRepo , args ... ); err != nil {
1862
1854
return err
1863
1855
}
1864
1856
1865
1857
return nil
1866
1858
}
1867
1859
1868
1860
func (git * repoSync ) isShallow (ctx context.Context ) (bool , error ) {
1869
- boolStr , _ , err := git .Run (ctx , git .root , "rev-parse" , "--is-shallow-repository" )
1861
+ boolStr , _ , err := git .Run (ctx , git .localRepo , "rev-parse" , "--is-shallow-repository" )
1870
1862
if err != nil {
1871
1863
return false , fmt .Errorf ("can't determine repo shallowness: %w" , err )
1872
1864
}
0 commit comments