commit c631b1152565e4c18cb2123e1d3d7c08d513c02f from: Stefan Sperling date: Thu Jul 23 14:22:36 2020 UTC make staging of symlinks work commit - cf34e6e70511929983a7a035e946966e8a833b8f commit + c631b1152565e4c18cb2123e1d3d7c08d513c02f blob - 315fadb7928641092f567960ffa58125ab66b04a blob + bde4162e571552b42ca8aea844c0fb7d81ee59e3 --- lib/worktree.c +++ lib/worktree.c @@ -1736,11 +1736,6 @@ get_file_status(unsigned char *status, struct stat *sb goto done; if (S_ISLNK(sb->st_mode)) { - /* Staging changes to symlinks is not yet(?) supported. */ - if (staged_status != GOT_STATUS_NO_CHANGE) { - err = got_error_path(abspath, GOT_ERR_FILE_STATUS); - goto done; - } err = get_symlink_status(status, sb, ie, abspath, dirfd, de_name, blob); goto done; @@ -5041,9 +5036,18 @@ reinstall_symlink_after_commit(int *is_bad_symlink, st struct got_tree_entry *te; char *entry_name; - err = got_object_open_as_blob(&blob, repo, ct->blob_id, PATH_MAX); - if (err) - return err; + if (ct->staged_status == GOT_STATUS_ADD || + ct->staged_status == GOT_STATUS_MODIFY) { + err = got_object_open_as_blob(&blob, repo, ct->staged_blob_id, + PATH_MAX); + if (err) + return err; + } else { + err = got_object_open_as_blob(&blob, repo, ct->blob_id, + PATH_MAX); + if (err) + return err; + } err = got_path_dirname(&tree_path, ct->in_repo_path); if (err) { @@ -5108,7 +5112,9 @@ reinstall_symlinks_after_commit(struct got_pathlist_he struct got_fileindex_entry *ie; int is_bad_symlink = 0; - if (!S_ISLNK(get_ct_file_mode(ct))) + if (!S_ISLNK(get_ct_file_mode(ct)) || + ct->staged_status == GOT_STATUS_DELETE || + ct->status == GOT_STATUS_DELETE) continue; err = reinstall_symlink_after_commit(&is_bad_symlink, blob - a537bcbfccf7f2f23f1ffd8cf0407deef0991edd blob + 199eaf6bbf1859c535e340a5c5f30777378ba090 --- regress/cmdline/stage.sh +++ regress/cmdline/stage.sh @@ -2350,7 +2350,292 @@ EOF diff -u $testroot/stdout.expected $testroot/stdout fi test_done "$testroot" "$ret" + +} + +function test_stage_symlink { + local testroot=`test_init stage_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 && git add .) + git_commit $testroot/repo -m "add symlinks" + local head_commit=`git_show_head $testroot/repo` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/wt && ln -sf beta alpha.link) + (cd $testroot/wt && ln -sfh gamma epsilon.link) + (cd $testroot/wt && ln -sf ../gamma/delta epsilon/beta.link) + echo 'this is regular file foo' > $testroot/wt/dotgotfoo.link + (cd $testroot/wt && got add dotgotfoo.link > /dev/null) + (cd $testroot/wt && ln -sf .got/bar dotgotbar.link) + (cd $testroot/wt && got add dotgotbar.link > /dev/null) + (cd $testroot/wt && got rm nonexistent.link > /dev/null) + (cd $testroot/wt && ln -sf gamma/delta zeta.link) + (cd $testroot/wt && got add zeta.link > /dev/null) + + (cd $testroot/wt && got stage > $testroot/stdout) + + cat > $testroot/stdout.expected < $testroot/stdout) + + echo "diff $head_commit $testroot/wt (staged changes)" \ + > $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -i | grep 'alpha.link@ -> alpha$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + (cd $testroot/wt && got stage -l alpha.link) | cut -d' ' -f 1 \ + >> $testroot/stdout.expected + echo '--- alpha.link' >> $testroot/stdout.expected + echo '+++ alpha.link' >> $testroot/stdout.expected + echo '@@ -1 +1 @@' >> $testroot/stdout.expected + echo '-alpha' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo '+beta' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo 'blob - /dev/null' >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + (cd $testroot/wt && got stage -l dotgotbar.link) | cut -d' ' -f 1 \ + >> $testroot/stdout.expected + echo '--- /dev/null' >> $testroot/stdout.expected + echo '+++ dotgotbar.link' >> $testroot/stdout.expected + echo '@@ -0,0 +1 @@' >> $testroot/stdout.expected + echo '+.got/bar' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo 'blob - /dev/null' >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + (cd $testroot/wt && got stage -l dotgotfoo.link) | cut -d' ' -f 1 \ + >> $testroot/stdout.expected + echo '--- /dev/null' >> $testroot/stdout.expected + echo '+++ dotgotfoo.link' >> $testroot/stdout.expected + echo '@@ -0,0 +1 @@' >> $testroot/stdout.expected + echo '+this is regular file foo' >> $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -i epsilon | grep 'beta.link@ -> ../beta$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + (cd $testroot/wt && got stage -l epsilon/beta.link) | cut -d' ' -f 1 \ + >> $testroot/stdout.expected + echo '--- epsilon/beta.link' >> $testroot/stdout.expected + echo '+++ epsilon/beta.link' >> $testroot/stdout.expected + echo '@@ -1 +1 @@' >> $testroot/stdout.expected + echo '-../beta' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo '+../gamma/delta' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -i | grep 'epsilon.link@ -> epsilon$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + (cd $testroot/wt && got stage -l epsilon.link) | cut -d' ' -f 1 \ + >> $testroot/stdout.expected + echo '--- epsilon.link' >> $testroot/stdout.expected + echo '+++ epsilon.link' >> $testroot/stdout.expected + echo '@@ -1 +1 @@' >> $testroot/stdout.expected + echo '-epsilon' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo '+gamma' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -i | grep 'nonexistent.link@ -> nonexistent$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo 'blob + /dev/null' >> $testroot/stdout.expected + echo '--- nonexistent.link' >> $testroot/stdout.expected + echo '+++ /dev/null' >> $testroot/stdout.expected + echo '@@ -1 +0,0 @@' >> $testroot/stdout.expected + echo '-nonexistent' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $testroot/stdout.expected + echo 'blob - /dev/null' >> $testroot/stdout.expected + echo -n 'blob + ' >> $testroot/stdout.expected + (cd $testroot/wt && got stage -l zeta.link) | cut -d' ' -f 1 \ + >> $testroot/stdout.expected + echo '--- /dev/null' >> $testroot/stdout.expected + echo '+++ zeta.link' >> $testroot/stdout.expected + echo '@@ -0,0 +1 @@' >> $testroot/stdout.expected + echo '+gamma/delta' >> $testroot/stdout.expected + echo '\ No newline at end of file' >> $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 + + (cd $testroot/wt && got commit -m "staged symlink" \ + > $testroot/stdout) + ret="$?" + if [ "$ret" != "0" ]; then + echo "got commit command failed unexpectedly" >&2 + test_done "$testroot" "1" + return 1 + fi + local commit_id=`git_show_head $testroot/repo` + echo "A dotgotbar.link" > $testroot/stdout.expected + echo "A dotgotfoo.link" >> $testroot/stdout.expected + echo "A zeta.link" >> $testroot/stdout.expected + echo "M alpha.link" >> $testroot/stdout.expected + echo "M epsilon/beta.link" >> $testroot/stdout.expected + echo "M epsilon.link" >> $testroot/stdout.expected + echo "D nonexistent.link" >> $testroot/stdout.expected + echo "Created commit $commit_id" >> $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 + + got tree -r $testroot/repo -c $commit_id > $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + echo "got tree command failed unexpectedly" >&2 + test_done "$testroot" "1" + return 1 + fi + + cat > $testroot/stdout.expected < beta +beta +dotgotbar.link@ -> .got/bar +dotgotfoo.link +epsilon/ +epsilon.link@ -> gamma +gamma/ +passwd.link@ -> /etc/passwd +zeta.link@ -> gamma/delta +EOF + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + return 1 + fi + + if ! [ -h $testroot/wt/alpha.link ]; then + echo "alpha.link is not a symlink" + test_done "$testroot" "1" + return 1 + fi + + readlink $testroot/wt/alpha.link > $testroot/stdout + echo "beta" > $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/dotgotbar.link ]; then + echo "dotgotbar.link is a symlink" + test_done "$testroot" "1" + return 1 + fi + echo -n ".got/bar" >> $testroot/content.expected + cp $testroot/wt/dotgotbar.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 + + if [ -h $testroot/wt/dotgotfoo.link ]; then + echo "dotgotfoo.link is a symlink" + test_done "$testroot" "1" + return 1 + fi + echo "this is regular file foo" > $testroot/content.expected + cp $testroot/wt/dotgotfoo.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 + + 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 "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 + + if [ -h $testroot/wt/passwd.link ]; then + echo "passwd.link is a symlink" + 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 + + if ! [ -h $testroot/wt/zeta.link ]; then + echo "zeta.link is not a symlink" + test_done "$testroot" "1" + return 1 + fi + + readlink $testroot/wt/zeta.link > $testroot/stdout + echo "gamma/delta" > $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 + + test_done "$testroot" "0" } run_test test_stage_basic @@ -2380,3 +2665,4 @@ run_test test_stage_patch_removed run_test test_stage_patch_removed_twice run_test test_stage_patch_quit run_test test_stage_patch_incomplete_script +run_test test_stage_symlink