Skip to content

Commit 855a69b

Browse files
committed
Put the local repo in a subdir of --root
1 parent 04ea5e4 commit 855a69b

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
@@ -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
submodules submodulesMode // how to handle submodules
@@ -707,6 +708,7 @@ func main() {
707708
cmd: *flGitCmd,
708709
root: absRoot,
709710
remoteRepo: *flRepo,
711+
localRepo: absRoot.Join(".repo"),
710712
ref: *flRef,
711713
depth: *flDepth,
712714
submodules: submodulesMode(*flSubmodules),
@@ -1212,40 +1214,37 @@ func (git *repoSync) initRepo(ctx context.Context) error {
12121214
needGitInit := false
12131215

12141216
// 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())
12161218
switch {
12171219
case os.IsNotExist(err):
12181220
// Probably the first sync. defaultDirMode ensures that this is usable
12191221
// 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 {
12221224
return err
12231225
}
12241226
needGitInit = true
12251227
case err != nil:
12261228
return err
12271229
default:
12281230
// 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)
12301232
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)
12321234
} 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)
12401239
}
12411240
needGitInit = true
12421241
}
12431242
}
12441243

12451244
if needGitInit {
12461245
// 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 {
12491248
return err
12501249
}
12511250
if !git.sanityCheckRepo(ctx) {
@@ -1255,17 +1254,17 @@ func (git *repoSync) initRepo(ctx context.Context) error {
12551254

12561255
// The "origin" remote has special meaning, like in relative-path
12571256
// 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 {
12591258
if !strings.Contains(stderr, "No such remote") {
12601259
return err
12611260
}
12621261
// 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 {
12641263
return err
12651264
}
12661265
} else if strings.TrimSpace(stdout) != git.remoteRepo {
12671266
// 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 {
12691268
return err
12701269
}
12711270
}
@@ -1312,32 +1311,32 @@ func hasGitLockFile(gitRoot absPath) (string, error) {
13121311

13131312
// sanityCheckRepo tries to make sure that the repo dir is a valid git repository.
13141313
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)
13161315
// 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)
13191318
return false
13201319
} 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)
13221321
return false
13231322
}
13241323

13251324
// 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)
13281327
return false
13291328
} else {
13301329
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)
13331332
return false
13341333
}
13351334
}
13361335

13371336
// Consistency-check the repo. Don't use --verbose because it can be
13381337
// 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)
13411340
return false
13421341
}
13431342

@@ -1359,7 +1358,7 @@ func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
13591358
// files checked out - git could have died halfway through and the repo will
13601359
// still pass this check.
13611360
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)
13631362

13641363
// If it is empty, we are done.
13651364
if empty, err := dirIsEmpty(worktree.Path()); err != nil {
@@ -1399,13 +1398,6 @@ func dirIsEmpty(dir absPath) (bool, error) {
13991398
return len(dirents) == 0, nil
14001399
}
14011400

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-
14091401
func removeDirContentsIf(dir absPath, log *logging.Logger, fn func(fi os.FileInfo) (bool, error)) error {
14101402
dirents, err := os.ReadDir(dir.String())
14111403
if err != nil {
@@ -1489,7 +1481,7 @@ func (git *repoSync) removeWorktree(ctx context.Context, worktree worktree) erro
14891481
if err := os.RemoveAll(worktree.Path().String()); err != nil {
14901482
return fmt.Errorf("error removing directory: %w", err)
14911483
}
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 {
14931485
return err
14941486
}
14951487
return nil
@@ -1510,7 +1502,7 @@ func (git *repoSync) createWorktree(ctx context.Context, hash string) (worktree,
15101502
}
15111503

15121504
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")
15141506
if err != nil {
15151507
return "", err
15161508
}
@@ -1528,7 +1520,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
15281520
// using relative paths, so that other containers can use a different volume
15291521
// mount name.
15301522
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 {
15321524
return err
15331525
} else {
15341526
rootDotGit = filepath.Join(rel, ".git")
@@ -1540,7 +1532,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
15401532

15411533
// If sparse checkout is requested, configure git for it, otherwise
15421534
// unconfigure it.
1543-
gitInfoPath := filepath.Join(git.root.String(), ".git/worktrees", hash, "info")
1535+
gitInfoPath := filepath.Join(git.localRepo.String(), ".git/worktrees", hash, "info")
15441536
gitSparseConfigPath := filepath.Join(gitInfoPath, "sparse-checkout")
15451537
if git.sparseFile == "" {
15461538
os.RemoveAll(gitSparseConfigPath)
@@ -1621,13 +1613,13 @@ func (git *repoSync) cleanup(ctx context.Context) error {
16211613

16221614
// Let git know we don't need those old commits any more.
16231615
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 {
16251617
cleanupErrs = append(cleanupErrs, err)
16261618
}
16271619

16281620
// Expire old refs.
16291621
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 {
16311623
cleanupErrs = append(cleanupErrs, err)
16321624
}
16331625

@@ -1643,7 +1635,7 @@ func (git *repoSync) cleanup(ctx context.Context) error {
16431635
args = append(args, "--aggressive")
16441636
}
16451637
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 {
16471639
cleanupErrs = append(cleanupErrs, err)
16481640
}
16491641
}
@@ -1746,7 +1738,7 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
17461738
// their underlying commit hashes, but has no effect if we fetched a
17471739
// branch, plain tag, or hash.
17481740
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 {
17501742
return false, "", err
17511743
} else {
17521744
remoteHash = strings.Trim(output, "\n")
@@ -1778,14 +1770,14 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
17781770
// Reset the repo (note: not the worktree - that happens later) to the new
17791771
// ref. This makes subsequent fetches much less expensive. It uses --soft
17801772
// 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 {
17821774
return false, "", err
17831775
}
17841776

17851777
// If we have a new hash, make a new worktree
17861778
newWorktree := currentWorktree
17871779
if changed {
1788-
// Create a worktree for this hash in git.root.
1780+
// Create a worktree for this hash.
17891781
if wt, err := git.createWorktree(ctx, remoteHash); err != nil {
17901782
return false, "", err
17911783
} else {
@@ -1858,15 +1850,15 @@ func (git *repoSync) fetch(ctx context.Context, ref string) error {
18581850
args = append(args, "--unshallow")
18591851
}
18601852
}
1861-
if _, _, err := git.Run(ctx, git.root, args...); err != nil {
1853+
if _, _, err := git.Run(ctx, git.localRepo, args...); err != nil {
18621854
return err
18631855
}
18641856

18651857
return nil
18661858
}
18671859

18681860
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")
18701862
if err != nil {
18711863
return false, fmt.Errorf("can't determine repo shallowness: %w", err)
18721864
}

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)