Skip to content

Commit ce8c4d3

Browse files
committed
Allow --dest to be an absolute path
This means it might live outside of --root.
1 parent d88ae88 commit ce8c4d3

File tree

2 files changed

+62
-14
lines changed

2 files changed

+62
-14
lines changed

cmd/git-sync/main.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ var flSubmodules = flag.String("submodules", envString("GIT_SYNC_SUBMODULES", "r
6262
var flRoot = flag.String("root", envString("GIT_SYNC_ROOT", envString("HOME", "")+"/git"),
6363
"the root directory for git-sync operations, under which --dest will be created")
6464
var flDest = flag.String("dest", envString("GIT_SYNC_DEST", ""),
65-
"the name of (a symlink to) a directory in which to check-out files under --root (defaults to the leaf dir of --repo)")
65+
"the path (absolute or relative to --root) at which to create a symlink to the directory holding the checked-out files (defaults to the leaf dir of --repo)")
6666
var flErrorFile = flag.String("error-file", envString("GIT_SYNC_ERROR_FILE", ""),
6767
"the name of a file into which errors will be written under --root (defaults to \"\", disabling error reporting)")
6868
var flWait = flag.Float64("wait", envFloat("GIT_SYNC_WAIT", 1),
@@ -286,9 +286,8 @@ func main() {
286286
parts := strings.Split(strings.Trim(*flRepo, "/"), "/")
287287
*flDest = parts[len(parts)-1]
288288
}
289-
290-
if strings.Contains(*flDest, "/") {
291-
handleError(true, "ERROR: --dest must be a leaf name, not a path")
289+
if !filepath.IsAbs(*flDest) {
290+
*flDest = filepath.Join(*flRoot, *flDest)
292291
}
293292

294293
if *flWait < 0 {
@@ -627,28 +626,36 @@ func addUser() error {
627626
// directory and cleans up the previous worktree. If there was a previous
628627
// worktree, this returns the path to it.
629628
func updateSymlink(ctx context.Context, gitRoot, link, newDir string) (string, error) {
629+
linkDir, linkFile := filepath.Split(link)
630+
631+
// Make sure the link directory exists. We do this here, rather than at
632+
// startup because it might be under --root and that gets wiped in some
633+
// circumstances.
634+
if err := os.MkdirAll(filepath.Dir(linkDir), os.FileMode(int(0755))); err != nil {
635+
return "", fmt.Errorf("error making symlink dir: %v", err)
636+
}
637+
630638
// Get currently-linked repo directory (to be removed), unless it doesn't exist
631-
linkPath := filepath.Join(gitRoot, link)
632-
oldWorktreePath, err := filepath.EvalSymlinks(linkPath)
639+
oldWorktreePath, err := filepath.EvalSymlinks(link)
633640
if err != nil && !os.IsNotExist(err) {
634641
return "", fmt.Errorf("error accessing current worktree: %v", err)
635642
}
636643

637644
// newDir is absolute, so we need to change it to a relative path. This is
638645
// so it can be volume-mounted at another path and the symlink still works.
639-
newDirRelative, err := filepath.Rel(gitRoot, newDir)
646+
newDirRelative, err := filepath.Rel(linkDir, newDir)
640647
if err != nil {
641648
return "", fmt.Errorf("error converting to relative path: %v", err)
642649
}
643650

644651
const tmplink = "tmp-link"
645-
log.V(1).Info("creating tmp symlink", "root", gitRoot, "dst", newDirRelative, "src", tmplink)
646-
if _, err := cmdRunner.Run(ctx, gitRoot, "ln", "-snf", newDirRelative, tmplink); err != nil {
652+
log.V(1).Info("creating tmp symlink", "root", linkDir, "dst", newDirRelative, "src", tmplink)
653+
if _, err := cmdRunner.Run(ctx, linkDir, "ln", "-snf", newDirRelative, tmplink); err != nil {
647654
return "", fmt.Errorf("error creating symlink: %v", err)
648655
}
649656

650-
log.V(1).Info("renaming symlink", "root", gitRoot, "old_name", tmplink, "new_name", link)
651-
if _, err := cmdRunner.Run(ctx, gitRoot, "mv", "-T", tmplink, link); err != nil {
657+
log.V(1).Info("renaming symlink", "root", linkDir, "old_name", tmplink, "new_name", linkFile)
658+
if _, err := cmdRunner.Run(ctx, linkDir, "mv", "-T", tmplink, linkFile); err != nil {
652659
return "", fmt.Errorf("error replacing symlink: %v", err)
653660
}
654661

@@ -958,8 +965,7 @@ func syncRepo(ctx context.Context, repo, branch, rev string, depth int, gitRoot,
958965
askpassCount.WithLabelValues(metricKeySuccess).Inc()
959966
}
960967

961-
target := filepath.Join(gitRoot, dest)
962-
gitRepoPath := filepath.Join(target, ".git")
968+
gitRepoPath := filepath.Join(gitRoot, ".git")
963969
var hash string
964970
_, err := os.Stat(gitRepoPath)
965971
switch {
@@ -977,7 +983,7 @@ func syncRepo(ctx context.Context, repo, branch, rev string, depth int, gitRoot,
977983
return false, "", fmt.Errorf("error checking if repo exists %q: %v", gitRepoPath, err)
978984
default:
979985
// Not the first time. Figure out if the ref has changed.
980-
local, remote, err := getRevs(ctx, target, branch, rev)
986+
local, remote, err := getRevs(ctx, dest, branch, rev)
981987
if err != nil {
982988
return false, "", err
983989
}

test_e2e.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,48 @@ function e2e::non_zero_exit() {
220220
)
221221
}
222222

223+
##############################################
224+
# Test HEAD one-time with an absolute-path link
225+
##############################################
226+
function e2e::absolute_dest() {
227+
echo "$FUNCNAME" > "$REPO"/file
228+
git -C "$REPO" commit -qam "$FUNCNAME"
229+
230+
GIT_SYNC \
231+
--one-time \
232+
--repo="file://$REPO" \
233+
--branch="$MAIN_BRANCH" \
234+
--rev=HEAD \
235+
--root="$ROOT/root" \
236+
--dest="$ROOT/other/dir/link" \
237+
>> "$1" 2>&1
238+
assert_file_absent "$ROOT"/root/link
239+
assert_link_exists "$ROOT"/other/dir/link
240+
assert_file_exists "$ROOT"/other/dir/link/file
241+
assert_file_eq "$ROOT"/other/dir/link/file "$FUNCNAME"
242+
}
243+
244+
##############################################
245+
# Test HEAD one-time with a subdir-path link
246+
##############################################
247+
function e2e::subdir_dest() {
248+
echo "$FUNCNAME" > "$REPO"/file
249+
git -C "$REPO" commit -qam "$FUNCNAME"
250+
251+
GIT_SYNC \
252+
--one-time \
253+
--repo="file://$REPO" \
254+
--branch="$MAIN_BRANCH" \
255+
--rev=HEAD \
256+
--root="$ROOT" \
257+
--dest="other/dir/link" \
258+
>> "$1" 2>&1
259+
assert_file_absent "$ROOT"/link
260+
assert_link_exists "$ROOT"/other/dir/link
261+
assert_file_exists "$ROOT"/other/dir/link/file
262+
assert_file_eq "$ROOT"/other/dir/link/file "$FUNCNAME"
263+
}
264+
223265
##############################################
224266
# Test default syncing (master)
225267
##############################################

0 commit comments

Comments
 (0)