commit 369fd7e5fa99b95f7d7aa812b5260584b86a3778 from: Stefan Sperling date: Thu Jul 23 14:22:38 2020 UTC add support for symlinks to 'got revert -p' commit - fa3cef63799016195e8a917f39c82815522692aa commit + 369fd7e5fa99b95f7d7aa812b5260584b86a3778 blob - df57239f50ac1caa3457f59d6df054cab52a05bc blob + 2a2d317c015385526ce0f22c09ed3240dafad6a5 --- lib/worktree.c +++ lib/worktree.c @@ -4375,15 +4375,28 @@ revert_file(void *arg, unsigned char status, unsigned if (a->patch_cb && (status == GOT_STATUS_MODIFY || status == GOT_STATUS_CONFLICT)) { + int is_bad_symlink = 0; err = create_patched_content(&path_content, 1, &id, ondisk_path, dirfd, de_name, ie->path, a->repo, a->patch_cb, a->patch_arg); if (err || path_content == NULL) break; - if (rename(path_content, ondisk_path) == -1) { - err = got_error_from_errno3("rename", - path_content, ondisk_path); - goto done; + if (te && S_ISLNK(te->mode)) { + if (unlink(path_content) == -1) { + err = got_error_from_errno2("unlink", + path_content); + break; + } + err = install_symlink(&is_bad_symlink, + a->worktree, ondisk_path, ie->path, + blob, 0, 1, 0, a->repo, + a->progress_cb, a->progress_arg); + } else { + if (rename(path_content, ondisk_path) == -1) { + err = got_error_from_errno3("rename", + path_content, ondisk_path); + goto done; + } } } else { int is_bad_symlink = 0; blob - 72a6ec979f66c13f3dd2fe3b41d969024ebf7283 blob + 84419db8223bceeb8d7e6ec0d1d43f75ebff9b5a --- regress/cmdline/revert.sh +++ regress/cmdline/revert.sh @@ -1223,6 +1223,260 @@ EOF test_done "$testroot" "$ret" } +function test_revert_patch_symlink { + local testroot=`test_init revert_patch_symlink` + + (cd $testroot/repo && ln -s alpha alpha.link) + (cd $testroot/repo && ln -s epsilon epsilon.link) + (cd $testroot/repo && ln -s /etc/passwd passwd.link) + (cd $testroot/repo && ln -s ../beta epsilon/beta.link) + (cd $testroot/repo && ln -s nonexistent nonexistent.link) + (cd $testroot/repo && ln -sf epsilon/zeta zeta.link) + (cd $testroot/repo && ln -sf epsilon/zeta zeta2.link) + (cd $testroot/repo && git add .) + git_commit $testroot/repo -m "add symlinks" + local commit_id1=`git_show_head $testroot/repo` + + got checkout $testroot/repo $testroot/wt > /dev/null + + # symlink to file A now points to file B + (cd $testroot/wt && ln -sf gamma/delta alpha.link) + # symlink to a directory A now points to file B + (cd $testroot/wt && ln -sfh beta epsilon.link) + # "bad" symlink now contains a different target path + echo "foo" > $testroot/wt/passwd.link + # relative symlink to directory A now points to relative directory B + (cd $testroot/wt && ln -sfh ../gamma epsilon/beta.link) + # an unversioned symlink + (cd $testroot/wt && ln -sf .got/foo dotgotfoo.link) + # symlink to file A now points to non-existent file B + (cd $testroot/wt && ln -sf nonexistent2 nonexistent.link) + # removed symlink + (cd $testroot/wt && got rm zeta.link > /dev/null) + (cd $testroot/wt && got rm zeta2.link > /dev/null) + # added symlink + (cd $testroot/wt && ln -sf beta new.link) + (cd $testroot/wt && got add new.link > /dev/null) + (cd $testroot/wt && ln -sf beta zeta3.link) + (cd $testroot/wt && got add zeta3.link > /dev/null) + + printf "y\nn\ny\nn\ny\ny\nn\ny\ny\n" > $testroot/patchscript + (cd $testroot/wt && got revert -F $testroot/patchscript -p -R . \ + > $testroot/stdout) + ret="$?" + if [ "$ret" != "0" ]; then + echo "got revert command failed unexpectedly" >&2 + test_done "$testroot" "1" + return 1 + fi + cat > $testroot/stdout.expected < $testroot/stdout + echo "alpha" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + if ! [ -h $testroot/wt/epsilon.link ]; then + echo "epsilon.link is not a symlink" + test_done "$testroot" "1" + return 1 + fi + + readlink $testroot/wt/epsilon.link > $testroot/stdout + echo "epsilon" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + if [ -h $testroot/wt/passwd.link ]; then + echo "passwd.link should not be a symlink" >&2 + test_done "$testroot" "1" + return 1 + fi + + echo -n "/etc/passwd" > $testroot/content.expected + cp $testroot/wt/passwd.link $testroot/content + + cmp -s $testroot/content.expected $testroot/content + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/content.expected $testroot/content + test_done "$testroot" "$ret" + return 1 + fi + + readlink $testroot/wt/epsilon/beta.link > $testroot/stdout + echo "../gamma" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + readlink $testroot/wt/nonexistent.link > $testroot/stdout + echo "nonexistent" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + fi + + if [ ! -h $testroot/wt/dotgotfoo.link ]; then + echo "dotgotfoo.link is not a symlink " >&2 + test_done "$testroot" "1" + return 1 + fi + readlink $testroot/wt/dotgotfoo.link > $testroot/stdout + echo ".got/foo" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + fi + + + if [ -e $testroot/wt/zeta.link ]; then + echo -n "zeta.link should not exist on disk" >&2 + test_done "$testroot" "1" + return 1 + fi + + if [ ! -h $testroot/wt/zeta2.link ]; then + echo -n "zeta2.link is not a symlink" >&2 + test_done "$testroot" "1" + return 1 + fi + + readlink $testroot/wt/zeta2.link > $testroot/stdout + echo "epsilon/zeta" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + fi + + if [ ! -h $testroot/wt/zeta3.link ]; then + echo -n "zeta3.link is not a symlink" >&2 + test_done "$testroot" "1" + return 1 + fi + + readlink $testroot/wt/zeta2.link > $testroot/stdout + echo "epsilon/zeta" > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + fi + + if [ ! -h $testroot/wt/new.link ]; then + echo -n "new.link is not a symlink" >&2 + test_done "$testroot" "1" + return 1 + fi + + (cd $testroot/wt && got status > $testroot/stdout) + echo "? dotgotfoo.link" > $testroot/stdout.expected + echo "M epsilon/beta.link" >> $testroot/stdout.expected + echo "A new.link" >> $testroot/stdout.expected + echo "D zeta.link" >> $testroot/stdout.expected + echo "? zeta3.link" >> $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + return 1 + fi + test_done "$testroot" "$ret" +} + run_test test_revert_basic run_test test_revert_rm run_test test_revert_add @@ -1238,3 +1492,4 @@ run_test test_revert_patch_one_change run_test test_revert_added_subtree run_test test_revert_deleted_subtree run_test test_revert_symlink +run_test test_revert_patch_symlink