Skip to content

Commit 2bd960c

Browse files
committed
Put the local repo in a subdir of --root
1 parent b8792bf commit 2bd960c

2 files changed

Lines changed: 48 additions & 51 deletions

File tree

main.go

Lines changed: 39 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ type repoSync struct {
118118
cmd string // the git command to run
119119
root absPath // absolute path to the root directory
120120
remoteRepo string // remote repo to sync
121+
localRepo absPath // absolute path to the local repo
121122
ref string // the ref to sync
122123
depth int // for shallow sync
123124
filter string // for partial clone
@@ -727,6 +728,7 @@ func main() {
727728
cmd: *flGitCmd,
728729
root: absRoot,
729730
remoteRepo: *flRepo,
731+
localRepo: absRoot.Join(".repo"),
730732
ref: *flRef,
731733
depth: *flDepth,
732734
filter: *flFilter,
@@ -1252,40 +1254,37 @@ func (git *repoSync) initRepo(ctx context.Context) error {
12521254
needGitInit := false
12531255

12541256
// Check out the git root, and see if it is already usable.
1255-
_, err := os.Stat(git.root.String())
1257+
_, err := os.Stat(git.localRepo.String())
12561258
switch {
12571259
case os.IsNotExist(err):
12581260
// Probably the first sync. defaultDirMode ensures that this is usable
12591261
// as a volume when the consumer isn't running as the same UID.
1260-
git.log.V(1).Info("repo directory does not exist, creating it", "path", git.root)
1261-
if err := os.MkdirAll(git.root.String(), defaultDirMode); err != nil {
1262+
git.log.V(1).Info("repo directory does not exist, creating it", "path", git.localRepo)
1263+
if err := os.MkdirAll(git.localRepo.String(), defaultDirMode); err != nil {
12621264
return err
12631265
}
12641266
needGitInit = true
12651267
case err != nil:
12661268
return err
12671269
default:
12681270
// Make sure the directory we found is actually usable.
1269-
git.log.V(3).Info("repo directory exists", "path", git.root)
1271+
git.log.V(3).Info("repo directory exists", "path", git.localRepo)
12701272
if git.sanityCheckRepo(ctx) {
1271-
git.log.V(4).Info("repo directory is valid", "path", git.root)
1273+
git.log.V(4).Info("repo directory is valid", "path", git.localRepo)
12721274
} else {
1273-
// Maybe a previous run crashed? Git won't use this dir. We remove
1274-
// the contents rather than the dir itself, because a common use-case
1275-
// is to have a volume mounted at git.root, which makes removing it
1276-
// impossible.
1277-
git.log.V(0).Info("repo directory was empty or failed checks", "path", git.root)
1278-
if err := removeDirContents(git.root, git.log); err != nil {
1279-
return fmt.Errorf("can't wipe unusable root directory: %w", err)
1275+
// Maybe a previous run crashed? Git won't use this dir.
1276+
git.log.V(0).Info("repo directory was empty or failed checks", "path", git.localRepo)
1277+
if err := os.RemoveAll(git.localRepo.String()); err != nil {
1278+
return fmt.Errorf("can't remove unusable repo directory: %w", err)
12801279
}
12811280
needGitInit = true
12821281
}
12831282
}
12841283

12851284
if needGitInit {
12861285
// Running `git init` in an existing repo is safe (according to git docs).
1287-
git.log.V(0).Info("initializing repo directory", "path", git.root)
1288-
if _, _, err := git.Run(ctx, git.root, "init", "-b", "git-sync"); err != nil {
1286+
git.log.V(0).Info("initializing repo directory", "path", git.localRepo)
1287+
if _, _, err := git.Run(ctx, git.localRepo, "init", "-b", "git-sync"); err != nil {
12891288
return err
12901289
}
12911290
if !git.sanityCheckRepo(ctx) {
@@ -1295,17 +1294,17 @@ func (git *repoSync) initRepo(ctx context.Context) error {
12951294

12961295
// The "origin" remote has special meaning, like in relative-path
12971296
// submodules.
1298-
if stdout, stderr, err := git.Run(ctx, git.root, "remote", "get-url", "origin"); err != nil {
1297+
if stdout, stderr, err := git.Run(ctx, git.localRepo, "remote", "get-url", "origin"); err != nil {
12991298
if !strings.Contains(stderr, "No such remote") {
13001299
return err
13011300
}
13021301
// It doesn't exist - make it.
1303-
if _, _, err := git.Run(ctx, git.root, "remote", "add", "origin", git.remoteRepo); err != nil {
1302+
if _, _, err := git.Run(ctx, git.localRepo, "remote", "add", "origin", git.remoteRepo); err != nil {
13041303
return err
13051304
}
13061305
} else if strings.TrimSpace(stdout) != git.remoteRepo {
13071306
// It exists, but is wrong.
1308-
if _, _, err := git.Run(ctx, git.root, "remote", "set-url", "origin", git.remoteRepo); err != nil {
1307+
if _, _, err := git.Run(ctx, git.localRepo, "remote", "set-url", "origin", git.remoteRepo); err != nil {
13091308
return err
13101309
}
13111310
}
@@ -1352,32 +1351,32 @@ func hasGitLockFile(gitRoot absPath) (string, error) {
13521351

13531352
// sanityCheckRepo tries to make sure that the repo dir is a valid git repository.
13541353
func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
1355-
git.log.V(3).Info("sanity-checking git repo", "repo", git.root)
1354+
git.log.V(3).Info("sanity-checking git repo", "repo", git.localRepo)
13561355
// If it is empty, we are done.
1357-
if empty, err := dirIsEmpty(git.root); err != nil {
1358-
git.log.Error(err, "can't list repo directory", "path", git.root)
1356+
if empty, err := dirIsEmpty(git.localRepo); err != nil {
1357+
git.log.Error(err, "can't list repo directory", "path", git.localRepo)
13591358
return false
13601359
} else if empty {
1361-
git.log.V(3).Info("repo directory is empty", "path", git.root)
1360+
git.log.V(3).Info("repo directory is empty", "path", git.localRepo)
13621361
return false
13631362
}
13641363

13651364
// Check that this is actually the root of the repo.
1366-
if root, _, err := git.Run(ctx, git.root, "rev-parse", "--show-toplevel"); err != nil {
1367-
git.log.Error(err, "can't get repo toplevel", "path", git.root)
1365+
if root, _, err := git.Run(ctx, git.localRepo, "rev-parse", "--show-toplevel"); err != nil {
1366+
git.log.Error(err, "can't get repo toplevel", "path", git.localRepo)
13681367
return false
13691368
} else {
13701369
root = strings.TrimSpace(root)
1371-
if root != git.root.String() {
1372-
git.log.Error(nil, "repo directory is under another repo", "path", git.root, "parent", root)
1370+
if root != git.localRepo.String() {
1371+
git.log.Error(nil, "repo directory is under another repo", "path", git.localRepo, "parent", root)
13731372
return false
13741373
}
13751374
}
13761375

13771376
// Consistency-check the repo. Don't use --verbose because it can be
13781377
// REALLY verbose.
1379-
if _, _, err := git.Run(ctx, git.root, "fsck", "--no-progress", "--connectivity-only"); err != nil {
1380-
git.log.Error(err, "repo fsck failed", "path", git.root)
1378+
if _, _, err := git.Run(ctx, git.localRepo, "fsck", "--no-progress", "--connectivity-only"); err != nil {
1379+
git.log.Error(err, "repo fsck failed", "path", git.localRepo)
13811380
return false
13821381
}
13831382

@@ -1399,7 +1398,7 @@ func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
13991398
// files checked out - git could have died halfway through and the repo will
14001399
// still pass this check.
14011400
func (git *repoSync) sanityCheckWorktree(ctx context.Context, worktree worktree) bool {
1402-
git.log.V(3).Info("sanity-checking worktree", "repo", git.root, "worktree", worktree)
1401+
git.log.V(3).Info("sanity-checking worktree", "repo", git.localRepo, "worktree", worktree)
14031402

14041403
// If it is empty, we are done.
14051404
if empty, err := dirIsEmpty(worktree.Path()); err != nil {
@@ -1439,13 +1438,6 @@ func dirIsEmpty(dir absPath) (bool, error) {
14391438
return len(dirents) == 0, nil
14401439
}
14411440

1442-
// removeDirContents iterated the specified dir and removes all contents.
1443-
func removeDirContents(dir absPath, log *logging.Logger) error {
1444-
return removeDirContentsIf(dir, log, func(fi os.FileInfo) (bool, error) {
1445-
return true, nil
1446-
})
1447-
}
1448-
14491441
func removeDirContentsIf(dir absPath, log *logging.Logger, fn func(fi os.FileInfo) (bool, error)) error {
14501442
dirents, err := os.ReadDir(dir.String())
14511443
if err != nil {
@@ -1529,7 +1521,7 @@ func (git *repoSync) removeWorktree(ctx context.Context, worktree worktree) erro
15291521
if err := os.RemoveAll(worktree.Path().String()); err != nil {
15301522
return fmt.Errorf("error removing directory: %w", err)
15311523
}
1532-
if _, _, err := git.Run(ctx, git.root, "worktree", "prune", "--verbose"); err != nil {
1524+
if _, _, err := git.Run(ctx, git.localRepo, "worktree", "prune", "--verbose"); err != nil {
15331525
return err
15341526
}
15351527
return nil
@@ -1550,7 +1542,7 @@ func (git *repoSync) createWorktree(ctx context.Context, hash string) (worktree,
15501542
}
15511543

15521544
git.log.V(1).Info("adding worktree", "path", worktree.Path(), "hash", hash)
1553-
_, _, err := git.Run(ctx, git.root, "worktree", "add", "--force", "--detach", worktree.Path().String(), hash, "--no-checkout")
1545+
_, _, err := git.Run(ctx, git.localRepo, "worktree", "add", "--force", "--detach", worktree.Path().String(), hash, "--no-checkout")
15541546
if err != nil {
15551547
return "", err
15561548
}
@@ -1568,7 +1560,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
15681560
// using relative paths, so that other containers can use a different volume
15691561
// mount name.
15701562
var rootDotGit string
1571-
if rel, err := filepath.Rel(worktree.Path().String(), git.root.String()); err != nil {
1563+
if rel, err := filepath.Rel(worktree.Path().String(), git.localRepo.String()); err != nil {
15721564
return err
15731565
} else {
15741566
rootDotGit = filepath.Join(rel, ".git")
@@ -1580,7 +1572,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
15801572

15811573
// If sparse checkout is requested, configure git for it, otherwise
15821574
// unconfigure it.
1583-
gitInfoPath := filepath.Join(git.root.String(), ".git/worktrees", hash, "info")
1575+
gitInfoPath := filepath.Join(git.localRepo.String(), ".git/worktrees", hash, "info")
15841576
gitSparseConfigPath := filepath.Join(gitInfoPath, "sparse-checkout")
15851577
if git.sparseFile == "" {
15861578
os.RemoveAll(gitSparseConfigPath)
@@ -1661,13 +1653,13 @@ func (git *repoSync) cleanup(ctx context.Context) error {
16611653

16621654
// Let git know we don't need those old commits any more.
16631655
git.log.V(3).Info("pruning worktrees")
1664-
if _, _, err := git.Run(ctx, git.root, "worktree", "prune", "--verbose"); err != nil {
1656+
if _, _, err := git.Run(ctx, git.localRepo, "worktree", "prune", "--verbose"); err != nil {
16651657
cleanupErrs = append(cleanupErrs, err)
16661658
}
16671659

16681660
// Expire old refs.
16691661
git.log.V(3).Info("expiring unreachable refs")
1670-
if _, _, err := git.Run(ctx, git.root, "reflog", "expire", "--expire-unreachable=all", "--all"); err != nil {
1662+
if _, _, err := git.Run(ctx, git.localRepo, "reflog", "expire", "--expire-unreachable=all", "--all"); err != nil {
16711663
cleanupErrs = append(cleanupErrs, err)
16721664
}
16731665

@@ -1683,7 +1675,7 @@ func (git *repoSync) cleanup(ctx context.Context) error {
16831675
args = append(args, "--aggressive")
16841676
}
16851677
git.log.V(3).Info("running git garbage collection")
1686-
if _, _, err := git.Run(ctx, git.root, args...); err != nil {
1678+
if _, _, err := git.Run(ctx, git.localRepo, args...); err != nil {
16871679
cleanupErrs = append(cleanupErrs, err)
16881680
}
16891681
}
@@ -1786,7 +1778,7 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
17861778
// their underlying commit hashes, but has no effect if we fetched a
17871779
// branch, plain tag, or hash.
17881780
var remoteHash string
1789-
if output, _, err := git.Run(ctx, git.root, "rev-parse", "FETCH_HEAD^{}"); err != nil {
1781+
if output, _, err := git.Run(ctx, git.localRepo, "rev-parse", "FETCH_HEAD^{}"); err != nil {
17901782
return false, "", err
17911783
} else {
17921784
remoteHash = strings.Trim(output, "\n")
@@ -1818,14 +1810,14 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
18181810
// Reset the repo (note: not the worktree - that happens later) to the new
18191811
// ref. This makes subsequent fetches much less expensive. It uses --soft
18201812
// so no files are checked out.
1821-
if _, _, err := git.Run(ctx, git.root, "reset", "--soft", remoteHash, "--"); err != nil {
1813+
if _, _, err := git.Run(ctx, git.localRepo, "reset", "--soft", remoteHash); err != nil {
18221814
return false, "", err
18231815
}
18241816

18251817
// If we have a new hash, make a new worktree
18261818
newWorktree := currentWorktree
18271819
if changed {
1828-
// Create a worktree for this hash in git.root.
1820+
// Create a worktree for this hash.
18291821
if wt, err := git.createWorktree(ctx, remoteHash); err != nil {
18301822
return false, "", err
18311823
} else {
@@ -1901,15 +1893,15 @@ func (git *repoSync) fetch(ctx context.Context, ref string) error {
19011893
if git.filter != "" {
19021894
args = append(args, "--filter", git.filter)
19031895
}
1904-
if _, _, err := git.Run(ctx, git.root, args...); err != nil {
1896+
if _, _, err := git.Run(ctx, git.localRepo, args...); err != nil {
19051897
return err
19061898
}
19071899

19081900
return nil
19091901
}
19101902

19111903
func (git *repoSync) isShallow(ctx context.Context) (bool, error) {
1912-
boolStr, _, err := git.Run(ctx, git.root, "rev-parse", "--is-shallow-repository")
1904+
boolStr, _, err := git.Run(ctx, git.localRepo, "rev-parse", "--is-shallow-repository")
19131905
if err != nil {
19141906
return false, fmt.Errorf("can't determine repo shallowness: %w", err)
19151907
}

main_test.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package main
1818

1919
import (
20+
"io/fs"
2021
"os"
2122
"path/filepath"
2223
"reflect"
@@ -315,7 +316,7 @@ func TestDirIsEmpty(t *testing.T) {
315316
}
316317
}
317318

318-
func TestRemoveDirContents(t *testing.T) {
319+
func TestRemoveDirContentsIf(t *testing.T) {
319320
root := absPath(t.TempDir())
320321

321322
// Brand new should be empty.
@@ -325,8 +326,12 @@ func TestRemoveDirContents(t *testing.T) {
325326
t.Errorf("expected %q to be deemed empty", root)
326327
}
327328

329+
fn := func(fi fs.FileInfo) (bool, error) {
330+
return true, nil
331+
}
332+
328333
// Test removal.
329-
if err := removeDirContents(root, nil); err != nil {
334+
if err := removeDirContentsIf(root, nil, fn); err != nil {
330335
t.Errorf("unexpected error: %v", err)
331336
}
332337

@@ -352,12 +357,12 @@ func TestRemoveDirContents(t *testing.T) {
352357
}
353358

354359
// Test removal.
355-
if err := removeDirContents(root, nil); err != nil {
360+
if err := removeDirContentsIf(root, nil, fn); err != nil {
356361
t.Errorf("unexpected error: %v", err)
357362
}
358363

359364
// Test error path.
360-
if err := removeDirContents(root.Join("does-not-exist"), nil); err == nil {
365+
if err := removeDirContentsIf(root.Join("does-not-exist"), nil, fn); err == nil {
361366
t.Errorf("unexpected success for non-existent dir")
362367
}
363368
}

0 commit comments

Comments
 (0)