From 530ac2899bac7ba0548942ea251329eb92ca8790 Mon Sep 17 00:00:00 2001 From: Tim Hockin Date: Tue, 22 Jun 2021 15:04:58 -0700 Subject: [PATCH] Clean up worktree dirs during sync loop Avoid "already exists" error. This is a port of #412 but I changed the e2e to use `docker pause`. --- cmd/git-sync/main.go | 28 ++++++++++++++++++++------ test_e2e.sh | 48 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/cmd/git-sync/main.go b/cmd/git-sync/main.go index 30af498..e2ab25e 100644 --- a/cmd/git-sync/main.go +++ b/cmd/git-sync/main.go @@ -881,6 +881,18 @@ func setRepoReady() { repoReady = true } +// cleanupWorkTree() is used to remove a worktree and its folder +func cleanupWorkTree(ctx context.Context, gitRoot, worktree string) error { + // Clean up worktree(s) + log.V(1).Info("removing worktree", "path", worktree) + if err := os.RemoveAll(worktree); err != nil { + return fmt.Errorf("error removing directory: %v", err) + } else if _, err := runCommand(ctx, gitRoot, *flGitCmd, "worktree", "prune"); err != nil { + return err + } + return nil +} + // AddWorktreeAndSwap creates a new worktree and calls UpdateSymlink to swap the symlink to point to the new worktree func (git *repoSync) AddWorktreeAndSwap(ctx context.Context, hash string) error { log.V(0).Info("syncing git", "rev", git.rev, "hash", hash) @@ -903,6 +915,15 @@ func (git *repoSync) AddWorktreeAndSwap(ctx context.Context, hash string) error // Make a worktree for this exact git hash. worktreePath := filepath.Join(git.root, hash) + + // Avoid wedge cases where the worktree was created but this function + // error'd without cleaning up. The next time thru the sync loop fails to + // create the worktree and bails out. This manifests as: + // "fatal: '/repo/root/rev-nnnn' already exists" + if err := cleanupWorkTree(ctx, git.root, worktreePath); err != nil { + return err + } + _, err := runCommand(ctx, git.root, git.cmd, "worktree", "add", worktreePath, "origin/"+git.branch, "--no-checkout") log.V(0).Info("adding worktree", "path", worktreePath, "branch", fmt.Sprintf("origin/%s", git.branch)) if err != nil { @@ -1028,12 +1049,7 @@ func (git *repoSync) AddWorktreeAndSwap(ctx context.Context, hash string) error // Clean up previous worktrees. var cleanupErr error if oldWorktree != "" { - log.V(1).Info("removing old worktree", "path", oldWorktree) - if err := os.RemoveAll(oldWorktree); err != nil { - cleanupErr = fmt.Errorf("error removing directory: %v", err) - } else if _, err := runCommand(ctx, git.root, git.cmd, "worktree", "prune"); err != nil { - cleanupErr = err - } + cleanupErr = cleanupWorkTree(ctx, git.root, oldWorktree) } if cleanupErr != nil { diff --git a/test_e2e.sh b/test_e2e.sh index b14d192..3c9d1dc 100755 --- a/test_e2e.sh +++ b/test_e2e.sh @@ -424,6 +424,54 @@ assert_file_eq "$ROOT"/link/file "$TESTCASE 1" # Wrap up pass +############################################## +# Test worktree-cleanup +############################################## +testcase "worktree-cleanup" + +echo "$TESTCASE" > "$REPO"/file +git -C "$REPO" commit -qam "$TESTCASE" +GIT_SYNC \ + --period=100ms \ + --repo="file://$REPO" \ + --branch=e2e-branch \ + --rev=HEAD \ + --root="$ROOT" \ + --dest="link" \ + > "$DIR"/log."$TESTCASE" 2>&1 & + +# wait for first sync +sleep 3 +assert_link_exists "$ROOT"/link +assert_file_exists "$ROOT"/link/file +assert_file_eq "$ROOT"/link/file "$TESTCASE" + +# suspend time so we can fake corruption +docker ps --filter label="git-sync-e2e=$RUNID" --format="{{.ID}}" \ + | while read CTR; do + docker pause "$CTR" >/dev/null + done + +# make a second commit +echo "$TESTCASE-ok" > "$REPO"/file2 +git -C "$REPO" add file2 +git -C "$REPO" commit -qam "$TESTCASE new file" +# make a worktree to collide with git-sync +REV=$(git -C "$REPO" rev-list -n1 HEAD) +git -C "$REPO" worktree add -q "$ROOT"/"$REV" -b e2e --no-checkout + +# resume time +docker ps --filter label="git-sync-e2e=$RUNID" --format="{{.ID}}" \ + | while read CTR; do + docker unpause "$CTR" >/dev/null + done + +sleep 3 +assert_file_exists "$ROOT"/link/file2 +assert_file_eq "$ROOT"/link/file2 "$TESTCASE-ok" +# Wrap up +pass + ############################################## # Test readlink ##############################################