Skip to content

Commit bc1bfc5

Browse files
committed
Put the local repo in a subdir of --root
1 parent c8c1e89 commit bc1bfc5

File tree

2 files changed

+48
-51
lines changed

2 files changed

+48
-51
lines changed

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
@@ -598,6 +599,7 @@ func main() {
598599
cmd: *flGitCmd,
599600
root: absRoot,
600601
remoteRepo: *flRepo,
602+
localRepo: absRoot.Join(".repo"),
601603
ref: *flRef,
602604
depth: *flDepth,
603605
submodules: submodulesMode(*flSubmodules),
@@ -1056,40 +1058,37 @@ func (git *repoSync) initRepo(ctx context.Context) error {
10561058
needGitInit := false
10571059

10581060
// Check out the git root, and see if it is already usable.
1059-
_, err := os.Stat(git.root.String())
1061+
_, err := os.Stat(git.localRepo.String())
10601062
switch {
10611063
case os.IsNotExist(err):
10621064
// Probably the first sync. defaultDirMode ensures that this is usable
10631065
// as a volume when the consumer isn't running as the same UID.
1064-
git.log.V(1).Info("repo directory does not exist, creating it", "path", git.root)
1065-
if err := os.MkdirAll(git.root.String(), defaultDirMode); err != nil {
1066+
git.log.V(1).Info("repo directory does not exist, creating it", "path", git.localRepo)
1067+
if err := os.MkdirAll(git.localRepo.String(), defaultDirMode); err != nil {
10661068
return err
10671069
}
10681070
needGitInit = true
10691071
case err != nil:
10701072
return err
10711073
default:
10721074
// Make sure the directory we found is actually usable.
1073-
git.log.V(3).Info("repo directory exists", "path", git.root)
1075+
git.log.V(3).Info("repo directory exists", "path", git.localRepo)
10741076
if git.sanityCheckRepo(ctx) {
1075-
git.log.V(4).Info("repo directory is valid", "path", git.root)
1077+
git.log.V(4).Info("repo directory is valid", "path", git.localRepo)
10761078
} else {
1077-
// Maybe a previous run crashed? Git won't use this dir. We remove
1078-
// the contents rather than the dir itself, because a common use-case
1079-
// is to have a volume mounted at git.root, which makes removing it
1080-
// impossible.
1081-
git.log.V(0).Info("repo directory was empty or failed checks", "path", git.root)
1082-
if err := removeDirContents(git.root, git.log); err != nil {
1083-
return fmt.Errorf("can't wipe unusable root directory: %w", err)
1079+
// Maybe a previous run crashed? Git won't use this dir.
1080+
git.log.V(0).Info("repo directory was empty or failed checks", "path", git.localRepo)
1081+
if err := os.RemoveAll(git.localRepo.String()); err != nil {
1082+
return fmt.Errorf("can't remove unusable repo directory: %w", err)
10841083
}
10851084
needGitInit = true
10861085
}
10871086
}
10881087

10891088
if needGitInit {
10901089
// Running `git init` in an existing repo is safe (according to git docs).
1091-
git.log.V(0).Info("initializing repo directory", "path", git.root)
1092-
if _, _, err := git.Run(ctx, git.root, "init", "-b", "git-sync"); err != nil {
1090+
git.log.V(0).Info("initializing repo directory", "path", git.localRepo)
1091+
if _, _, err := git.Run(ctx, git.localRepo, "init", "-b", "git-sync"); err != nil {
10931092
return err
10941093
}
10951094
if !git.sanityCheckRepo(ctx) {
@@ -1099,17 +1098,17 @@ func (git *repoSync) initRepo(ctx context.Context) error {
10991098

11001099
// The "origin" remote has special meaning, like in relative-path
11011100
// submodules.
1102-
if stdout, stderr, err := git.Run(ctx, git.root, "remote", "get-url", "origin"); err != nil {
1101+
if stdout, stderr, err := git.Run(ctx, git.localRepo, "remote", "get-url", "origin"); err != nil {
11031102
if !strings.Contains(stderr, "No such remote") {
11041103
return err
11051104
}
11061105
// It doesn't exist - make it.
1107-
if _, _, err := git.Run(ctx, git.root, "remote", "add", "origin", git.remoteRepo); err != nil {
1106+
if _, _, err := git.Run(ctx, git.localRepo, "remote", "add", "origin", git.remoteRepo); err != nil {
11081107
return err
11091108
}
11101109
} else if strings.TrimSpace(stdout) != git.remoteRepo {
11111110
// It exists, but is wrong.
1112-
if _, _, err := git.Run(ctx, git.root, "remote", "set-url", "origin", git.remoteRepo); err != nil {
1111+
if _, _, err := git.Run(ctx, git.localRepo, "remote", "set-url", "origin", git.remoteRepo); err != nil {
11131112
return err
11141113
}
11151114
}
@@ -1142,32 +1141,32 @@ func (git *repoSync) removeStaleWorktrees() (int, error) {
11421141

11431142
// sanityCheckRepo tries to make sure that the repo dir is a valid git repository.
11441143
func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
1145-
git.log.V(3).Info("sanity-checking git repo", "repo", git.root)
1144+
git.log.V(3).Info("sanity-checking git repo", "repo", git.localRepo)
11461145
// If it is empty, we are done.
1147-
if empty, err := dirIsEmpty(git.root); err != nil {
1148-
git.log.Error(err, "can't list repo directory", "path", git.root)
1146+
if empty, err := dirIsEmpty(git.localRepo); err != nil {
1147+
git.log.Error(err, "can't list repo directory", "path", git.localRepo)
11491148
return false
11501149
} else if empty {
1151-
git.log.V(3).Info("repo directory is empty", "path", git.root)
1150+
git.log.V(3).Info("repo directory is empty", "path", git.localRepo)
11521151
return false
11531152
}
11541153

11551154
// Check that this is actually the root of the repo.
1156-
if root, _, err := git.Run(ctx, git.root, "rev-parse", "--show-toplevel"); err != nil {
1157-
git.log.Error(err, "can't get repo toplevel", "path", git.root)
1155+
if root, _, err := git.Run(ctx, git.localRepo, "rev-parse", "--show-toplevel"); err != nil {
1156+
git.log.Error(err, "can't get repo toplevel", "path", git.localRepo)
11581157
return false
11591158
} else {
11601159
root = strings.TrimSpace(root)
1161-
if root != git.root.String() {
1162-
git.log.Error(nil, "repo directory is under another repo", "path", git.root, "parent", root)
1160+
if root != git.localRepo.String() {
1161+
git.log.Error(nil, "repo directory is under another repo", "path", git.localRepo, "parent", root)
11631162
return false
11641163
}
11651164
}
11661165

11671166
// Consistency-check the repo. Don't use --verbose because it can be
11681167
// REALLY verbose.
1169-
if _, _, err := git.Run(ctx, git.root, "fsck", "--no-progress", "--connectivity-only"); err != nil {
1170-
git.log.Error(err, "repo fsck failed", "path", git.root)
1168+
if _, _, err := git.Run(ctx, git.localRepo, "fsck", "--no-progress", "--connectivity-only"); err != nil {
1169+
git.log.Error(err, "repo fsck failed", "path", git.localRepo)
11711170
return false
11721171
}
11731172

@@ -1179,7 +1178,7 @@ func (git *repoSync) sanityCheckRepo(ctx context.Context) bool {
11791178
// files checked out - git could have died halfway through and the repo will
11801179
// still pass this check.
11811180
func (git *repoSync) sanityCheckWorktree(ctx context.Context, worktree worktree) bool {
1182-
git.log.V(3).Info("sanity-checking worktree", "repo", git.root, "worktree", worktree)
1181+
git.log.V(3).Info("sanity-checking worktree", "repo", git.localRepo, "worktree", worktree)
11831182

11841183
// If it is empty, we are done.
11851184
if empty, err := dirIsEmpty(worktree.Path()); err != nil {
@@ -1219,13 +1218,6 @@ func dirIsEmpty(dir absPath) (bool, error) {
12191218
return len(dirents) == 0, nil
12201219
}
12211220

1222-
// removeDirContents iterated the specified dir and removes all contents
1223-
func removeDirContents(dir absPath, log *logging.Logger) error {
1224-
return removeDirContentsIf(dir, log, func(fi os.FileInfo) (bool, error) {
1225-
return true, nil
1226-
})
1227-
}
1228-
12291221
func removeDirContentsIf(dir absPath, log *logging.Logger, fn func(fi os.FileInfo) (bool, error)) error {
12301222
dirents, err := os.ReadDir(dir.String())
12311223
if err != nil {
@@ -1309,7 +1301,7 @@ func (git *repoSync) removeWorktree(ctx context.Context, worktree worktree) erro
13091301
if err := os.RemoveAll(worktree.Path().String()); err != nil {
13101302
return fmt.Errorf("error removing directory: %w", err)
13111303
}
1312-
if _, _, err := git.Run(ctx, git.root, "worktree", "prune", "--verbose"); err != nil {
1304+
if _, _, err := git.Run(ctx, git.localRepo, "worktree", "prune", "--verbose"); err != nil {
13131305
return err
13141306
}
13151307
return nil
@@ -1330,7 +1322,7 @@ func (git *repoSync) createWorktree(ctx context.Context, hash string) (worktree,
13301322
}
13311323

13321324
git.log.V(1).Info("adding worktree", "path", worktree.Path(), "hash", hash)
1333-
_, _, err := git.Run(ctx, git.root, "worktree", "add", "--force", "--detach", worktree.Path().String(), hash, "--no-checkout")
1325+
_, _, err := git.Run(ctx, git.localRepo, "worktree", "add", "--force", "--detach", worktree.Path().String(), hash, "--no-checkout")
13341326
if err != nil {
13351327
return "", err
13361328
}
@@ -1348,7 +1340,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
13481340
// using relative paths, so that other containers can use a different volume
13491341
// mount name.
13501342
rootDotGit := ""
1351-
if rel, err := filepath.Rel(worktree.Path().String(), git.root.String()); err != nil {
1343+
if rel, err := filepath.Rel(worktree.Path().String(), git.localRepo.String()); err != nil {
13521344
return err
13531345
} else {
13541346
rootDotGit = filepath.Join(rel, ".git")
@@ -1360,7 +1352,7 @@ func (git *repoSync) configureWorktree(ctx context.Context, worktree worktree) e
13601352

13611353
// If sparse checkout is requested, configure git for it, otherwise
13621354
// unconfigure it.
1363-
gitInfoPath := filepath.Join(git.root.String(), ".git/worktrees", hash, "info")
1355+
gitInfoPath := filepath.Join(git.localRepo.String(), ".git/worktrees", hash, "info")
13641356
gitSparseConfigPath := filepath.Join(gitInfoPath, "sparse-checkout")
13651357
if git.sparseFile == "" {
13661358
os.RemoveAll(gitSparseConfigPath)
@@ -1441,13 +1433,13 @@ func (git *repoSync) cleanup(ctx context.Context) error {
14411433

14421434
// Let git know we don't need those old commits any more.
14431435
git.log.V(3).Info("pruning worktrees")
1444-
if _, _, err := git.Run(ctx, git.root, "worktree", "prune", "--verbose"); err != nil {
1436+
if _, _, err := git.Run(ctx, git.localRepo, "worktree", "prune", "--verbose"); err != nil {
14451437
cleanupErrs = append(cleanupErrs, err)
14461438
}
14471439

14481440
// Expire old refs.
14491441
git.log.V(3).Info("expiring unreachable refs")
1450-
if _, _, err := git.Run(ctx, git.root, "reflog", "expire", "--expire-unreachable=all", "--all"); err != nil {
1442+
if _, _, err := git.Run(ctx, git.localRepo, "reflog", "expire", "--expire-unreachable=all", "--all"); err != nil {
14511443
cleanupErrs = append(cleanupErrs, err)
14521444
}
14531445

@@ -1463,7 +1455,7 @@ func (git *repoSync) cleanup(ctx context.Context) error {
14631455
args = append(args, "--aggressive")
14641456
}
14651457
git.log.V(3).Info("running git garbage collection")
1466-
if _, _, err := git.Run(ctx, git.root, args...); err != nil {
1458+
if _, _, err := git.Run(ctx, git.localRepo, args...); err != nil {
14671459
cleanupErrs = append(cleanupErrs, err)
14681460
}
14691461
}
@@ -1566,7 +1558,7 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
15661558
// their underlying commit hashes, but has no effect if we fetched a
15671559
// branch, plain tag, or hash.
15681560
remoteHash := ""
1569-
if output, _, err := git.Run(ctx, git.root, "rev-parse", "FETCH_HEAD^{}"); err != nil {
1561+
if output, _, err := git.Run(ctx, git.localRepo, "rev-parse", "FETCH_HEAD^{}"); err != nil {
15701562
return false, "", err
15711563
} else {
15721564
remoteHash = strings.Trim(output, "\n")
@@ -1598,14 +1590,14 @@ func (git *repoSync) SyncRepo(ctx context.Context, refreshCreds func(context.Con
15981590
// Reset the repo (note: not the worktree - that happens later) to the new
15991591
// ref. This makes subsequent fetches much less expensive. It uses --soft
16001592
// so no files are checked out.
1601-
if _, _, err := git.Run(ctx, git.root, "reset", "--soft", remoteHash); err != nil {
1593+
if _, _, err := git.Run(ctx, git.localRepo, "reset", "--soft", remoteHash); err != nil {
16021594
return false, "", err
16031595
}
16041596

16051597
// If we have a new hash, make a new worktree
16061598
newWorktree := currentWorktree
16071599
if changed {
1608-
// Create a worktree for this hash in git.root.
1600+
// Create a worktree for this hash.
16091601
if wt, err := git.createWorktree(ctx, remoteHash); err != nil {
16101602
return false, "", err
16111603
} else {
@@ -1678,15 +1670,15 @@ func (git *repoSync) fetch(ctx context.Context, ref string) error {
16781670
args = append(args, "--unshallow")
16791671
}
16801672
}
1681-
if _, _, err := git.Run(ctx, git.root, args...); err != nil {
1673+
if _, _, err := git.Run(ctx, git.localRepo, args...); err != nil {
16821674
return err
16831675
}
16841676

16851677
return nil
16861678
}
16871679

16881680
func (git *repoSync) isShallow(ctx context.Context) (bool, error) {
1689-
boolStr, _, err := git.Run(ctx, git.root, "rev-parse", "--is-shallow-repository")
1681+
boolStr, _, err := git.Run(ctx, git.localRepo, "rev-parse", "--is-shallow-repository")
16901682
if err != nil {
16911683
return false, fmt.Errorf("can't determine repo shallowness: %w", err)
16921684
}

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)