Skip to content

Commit f82f26d

Browse files
committed
Put the local repo in a subdir of --root
1 parent 369f8e0 commit f82f26d

File tree

2 files changed

+48
-51
lines changed

2 files changed

+48
-51
lines changed

Diff for: main.go

+39-47
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ const defaultDirMode = os.FileMode(0775) // subject to umask
109109
type repoSync struct {
110110
cmd string // the git command to run
111111
root absPath // absolute path to the root directory
112+
localRepo absPath // absolute path to the local repo
112113
remoteRepo string // remote repo to sync
113114
ref string // the ref to sync
114115
depth int // for shallow sync
@@ -618,6 +619,7 @@ func main() {
618619
cmd: *flGitCmd,
619620
root: absRoot,
620621
remoteRepo: *flRepo,
622+
localRepo: absRoot.Join(".repo"),
621623
ref: *flRef,
622624
depth: *flDepth,
623625
submodules: submodulesMode(*flSubmodules),
@@ -1076,40 +1078,37 @@ func (git *repoSync) initRepo(ctx context.Context) error {
10761078
needGitInit := false
10771079

10781080
// Check out the git root, and see if it is already usable.
1079-
_, err := os.Stat(git.root.String())
1081+
_, err := os.Stat(git.localRepo.String())
10801082
switch {
10811083
case os.IsNotExist(err):
10821084
// Probably the first sync. defaultDirMode ensures that this is usable
10831085
// as a volume when the consumer isn't running as the same UID.
1084-
git.log.V(1).Info("repo directory does not exist, creating it", "path", git.root)
1085-
if err := os.MkdirAll(git.root.String(), defaultDirMode); err != nil {
1086+
git.log.V(1).Info("repo directory does not exist, creating it", "path", git.localRepo)
1087+
if err := os.MkdirAll(git.localRepo.String(), defaultDirMode); err != nil {
10861088
return err
10871089
}
10881090
needGitInit = true
10891091
case err != nil:
10901092
return err
10911093
default:
10921094
// Make sure the directory we found is actually usable.
1093-
git.log.V(3).Info("repo directory exists", "path", git.root)
1095+
git.log.V(3).Info("repo directory exists", "path", git.localRepo)
10941096
if git.sanityCheckRepo(ctx) {
1095-
git.log.V(4).Info("repo directory is valid", "path", git.root)
1097+
git.log.V(4).Info("repo directory is valid", "path", git.localRepo)
10961098
} else {
1097-
// Maybe a previous run crashed? Git won't use this dir. We remove
1098-
// the contents rather than the dir itself, because a common use-case
1099-
// is to have a volume mounted at git.root, which makes removing it
1100-
// impossible.
1101-
git.log.V(0).Info("repo directory was empty or failed checks", "path", git.root)
1102-
if err := removeDirContents(git.root, git.log); err != nil {
1103-
return fmt.Errorf("can't wipe unusable root directory: %w", err)
1099+
// Maybe a previous run crashed? Git won't use this dir.
1100+
git.log.V(0).Info("repo directory was empty or failed checks", "path", git.localRepo)
1101+
if err := os.RemoveAll(git.localRepo.String()); err != nil {
1102+
return fmt.Errorf("can't remove unusable repo directory: %w", err)
11041103
}
11051104
needGitInit = true
11061105
}
11071106
}
11081107

11091108
if needGitInit {
11101109
// Running `git init` in an existing repo is safe (according to git docs).
1111-
git.log.V(0).Info("initializing repo directory", "path", git.root)
1112-
if _, _, err := git.Run(ctx, git.root, "init", "-b", "git-sync"); err != nil {
1110+
git.log.V(0).Info("initializing repo directory", "path", git.localRepo)
1111+
if _, _, err := git.Run(ctx, git.localRepo, "init", "-b", "git-sync"); err != nil {
11131112
return err
11141113
}
11151114
if !git.sanityCheckRepo(ctx) {
@@ -1119,17 +1118,17 @@ func (git *repoSync) initRepo(ctx context.Context) error {
11191118

11201119
// The "origin" remote has special meaning, like in relative-path
11211120
// submodules.
1122-
if stdout, stderr, err := git.Run(ctx, git.root, "remote", "get-url", "origin"); err != nil {
1121+
if stdout, stderr, err := git.Run(ctx, git.localRepo, "remote", "get-url", "origin"); err != nil {
11231122
if !strings.Contains(stderr, "No such remote") {
11241123
return err
11251124
}
11261125
// It doesn't exist - make it.
1127-
if _, _, err := git.Run(ctx, git.root, "remote", "add", "origin", git.remoteRepo); err != nil {
1126+
if _, _, err := git.Run(ctx, git.localRepo, "remote", "add", "origin", git.remoteRepo); err != nil {
11281127
return err
11291128
}
11301129
} else if strings.TrimSpace(stdout) != git.remoteRepo {
11311130
// It exists, but is wrong.
1132-
if _, _, err := git.Run(ctx, git.root, "remote", "set-url", "origin", git.remoteRepo); err != nil {
1131+
if _, _, err := git.Run(ctx, git.localRepo, "remote", "set-url", "origin", git.remoteRepo); err != nil {
11331132
return err
11341133
}
11351134
}
@@ -1162,32 +1161,32 @@ func (git *repoSync) removeStaleWorktrees() (int, error) {
11621161

11631162
// sanityCheckRepo tries to make sure that the repo dir is a valid git repository.
11641163
func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
1165-
git.log.V(3).Info("sanity-checking git repo", "repo", git.root)
1164+
git.log.V(3).Info("sanity-checking git repo", "repo", git.localRepo)
11661165
// If it is empty, we are done.
1167-
if empty, err := dirIsEmpty(git.root); err != nil {
1168-
git.log.Error(err, "can't list repo directory", "path", git.root)
1166+
if empty, err := dirIsEmpty(git.localRepo); err != nil {
1167+
git.log.Error(err, "can't list repo directory", "path", git.localRepo)
11691168
return false
11701169
} else if empty {
1171-
git.log.V(3).Info("repo directory is empty", "path", git.root)
1170+
git.log.V(3).Info("repo directory is empty", "path", git.localRepo)
11721171
return false
11731172
}
11741173

11751174
// Check that this is actually the root of the repo.
1176-
if root, _, err := git.Run(ctx, git.root, "rev-parse", "--show-toplevel"); err != nil {
1177-
git.log.Error(err, "can't get repo toplevel", "path", git.root)
1175+
if root, _, err := git.Run(ctx, git.localRepo, "rev-parse", "--show-toplevel"); err != nil {
1176+
git.log.Error(err, "can't get repo toplevel", "path", git.localRepo)
11781177
return false
11791178
} else {
11801179
root = strings.TrimSpace(root)
1181-
if root != git.root.String() {
1182-
git.log.Error(nil, "repo directory is under another repo", "path", git.root, "parent", root)
1180+
if root != git.localRepo.String() {
1181+
git.log.Error(nil, "repo directory is under another repo", "path", git.localRepo, "parent", root)
11831182
return false
11841183
}
11851184
}
11861185

11871186
// Consistency-check the repo. Don't use --verbose because it can be
11881187
// REALLY verbose.
1189-
if _, _, err := git.Run(ctx, git.root, "fsck", "--no-progress", "--connectivity-only"); err != nil {
1190-
git.log.Error(err, "repo fsck failed", "path", git.root)
1188+
if _, _, err := git.Run(ctx, git.localRepo, "fsck", "--no-progress", "--connectivity-only"); err != nil {
1189+
git.log.Error(err, "repo fsck failed", "path", git.localRepo)
11911190
return false
11921191
}
11931192

@@ -1199,7 +1198,7 @@ func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
11991198
// files checked out - git could have died halfway through and the repo will
12001199
// still pass this check.
12011200
func (git *repoSync) sanityCheckWorktree(ctx context.Context, worktree worktree) bool {
1202-
git.log.V(3).Info("sanity-checking worktree", "repo", git.root, "worktree", worktree)
1201+
git.log.V(3).Info("sanity-checking worktree", "repo", git.localRepo, "worktree", worktree)
12031202

12041203
// If it is empty, we are done.
12051204
if empty, err := dirIsEmpty(worktree.Path()); err != nil {
@@ -1239,13 +1238,6 @@ func dirIsEmpty(dir absPath) (bool, error) {
12391238
return len(dirents) == 0, nil
12401239
}
12411240

1242-
// removeDirContents iterated the specified dir and removes all contents
1243-
func removeDirContents(dir absPath, log *logging.Logger) error {
1244-
return removeDirContentsIf(dir, log, func(fi os.FileInfo) (bool, error) {
1245-
return true, nil
1246-
})
1247-
}
1248-
12491241
func removeDirContentsIf(dir absPath, log *logging.Logger, fn func(fi os.FileInfo) (bool, error)) error {
12501242
dirents, err := os.ReadDir(dir.String())
12511243
if err != nil {
@@ -1329,7 +1321,7 @@ func (git *repoSync) removeWorktree(ctx context.Context, worktree worktree) erro
13291321
if err := os.RemoveAll(worktree.Path().String()); err != nil {
13301322
return fmt.Errorf("error removing directory: %w", err)
13311323
}
1332-
if _, _, err := git.Run(ctx, git.root, "worktree", "prune", "--verbose"); err != nil {
1324+
if _, _, err := git.Run(ctx, git.localRepo, "worktree", "prune", "--verbose"); err != nil {
13331325
return err
13341326
}
13351327
return nil
@@ -1350,7 +1342,7 @@ func (git *repoSync) createWorktree(ctx context.Context, hash string) (worktree,
13501342
}
13511343

13521344
git.log.V(1).Info("adding worktree", "path", worktree.Path(), "hash", hash)
1353-
_, _, err := git.Run(ctx, git.root, "worktree", "add", "--force", "--detach", worktree.Path().String(), hash, "--no-checkout")
1345+
_, _, err := git.Run(ctx, git.localRepo, "worktree", "add", "--force", "--detach", worktree.Path().String(), hash, "--no-checkout")
13541346
if err != nil {
13551347
return "", err
13561348
}
@@ -1368,7 +1360,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
13681360
// using relative paths, so that other containers can use a different volume
13691361
// mount name.
13701362
rootDotGit := ""
1371-
if rel, err := filepath.Rel(worktree.Path().String(), git.root.String()); err != nil {
1363+
if rel, err := filepath.Rel(worktree.Path().String(), git.localRepo.String()); err != nil {
13721364
return err
13731365
} else {
13741366
rootDotGit = filepath.Join(rel, ".git")
@@ -1380,7 +1372,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
13801372

13811373
// If sparse checkout is requested, configure git for it, otherwise
13821374
// unconfigure it.
1383-
gitInfoPath := filepath.Join(git.root.String(), ".git/worktrees", hash, "info")
1375+
gitInfoPath := filepath.Join(git.localRepo.String(), ".git/worktrees", hash, "info")
13841376
gitSparseConfigPath := filepath.Join(gitInfoPath, "sparse-checkout")
13851377
if git.sparseFile == "" {
13861378
os.RemoveAll(gitSparseConfigPath)
@@ -1461,13 +1453,13 @@ func (git *repoSync) cleanup(ctx context.Context) error {
14611453

14621454
// Let git know we don't need those old commits any more.
14631455
git.log.V(3).Info("pruning worktrees")
1464-
if _, _, err := git.Run(ctx, git.root, "worktree", "prune", "--verbose"); err != nil {
1456+
if _, _, err := git.Run(ctx, git.localRepo, "worktree", "prune", "--verbose"); err != nil {
14651457
cleanupErrs = append(cleanupErrs, err)
14661458
}
14671459

14681460
// Expire old refs.
14691461
git.log.V(3).Info("expiring unreachable refs")
1470-
if _, _, err := git.Run(ctx, git.root, "reflog", "expire", "--expire-unreachable=all", "--all"); err != nil {
1462+
if _, _, err := git.Run(ctx, git.localRepo, "reflog", "expire", "--expire-unreachable=all", "--all"); err != nil {
14711463
cleanupErrs = append(cleanupErrs, err)
14721464
}
14731465

@@ -1483,7 +1475,7 @@ func (git *repoSync) cleanup(ctx context.Context) error {
14831475
args = append(args, "--aggressive")
14841476
}
14851477
git.log.V(3).Info("running git garbage collection")
1486-
if _, _, err := git.Run(ctx, git.root, args...); err != nil {
1478+
if _, _, err := git.Run(ctx, git.localRepo, args...); err != nil {
14871479
cleanupErrs = append(cleanupErrs, err)
14881480
}
14891481
}
@@ -1586,7 +1578,7 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
15861578
// their underlying commit hashes, but has no effect if we fetched a
15871579
// branch, plain tag, or hash.
15881580
remoteHash := ""
1589-
if output, _, err := git.Run(ctx, git.root, "rev-parse", "FETCH_HEAD^{}"); err != nil {
1581+
if output, _, err := git.Run(ctx, git.localRepo, "rev-parse", "FETCH_HEAD^{}"); err != nil {
15901582
return false, "", err
15911583
} else {
15921584
remoteHash = strings.Trim(output, "\n")
@@ -1618,14 +1610,14 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
16181610
// Reset the repo (note: not the worktree - that happens later) to the new
16191611
// ref. This makes subsequent fetches much less expensive. It uses --soft
16201612
// so no files are checked out.
1621-
if _, _, err := git.Run(ctx, git.root, "reset", "--soft", remoteHash); err != nil {
1613+
if _, _, err := git.Run(ctx, git.localRepo, "reset", "--soft", remoteHash); err != nil {
16221614
return false, "", err
16231615
}
16241616

16251617
// If we have a new hash, make a new worktree
16261618
newWorktree := currentWorktree
16271619
if changed {
1628-
// Create a worktree for this hash in git.root.
1620+
// Create a worktree for this hash.
16291621
if wt, err := git.createWorktree(ctx, remoteHash); err != nil {
16301622
return false, "", err
16311623
} else {
@@ -1698,15 +1690,15 @@ func (git *repoSync) fetch(ctx context.Context, ref string) error {
16981690
args = append(args, "--unshallow")
16991691
}
17001692
}
1701-
if _, _, err := git.Run(ctx, git.root, args...); err != nil {
1693+
if _, _, err := git.Run(ctx, git.localRepo, args...); err != nil {
17021694
return err
17031695
}
17041696

17051697
return nil
17061698
}
17071699

17081700
func (git *repoSync) isShallow(ctx context.Context) (bool, error) {
1709-
boolStr, _, err := git.Run(ctx, git.root, "rev-parse", "--is-shallow-repository")
1701+
boolStr, _, err := git.Run(ctx, git.localRepo, "rev-parse", "--is-shallow-repository")
17101702
if err != nil {
17111703
return false, fmt.Errorf("can't determine repo shallowness: %w", err)
17121704
}

Diff for: main_test.go

+9-4
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)