commit 0587e10c4c4e054f8aeda2bd499b76c0ec60dc40 from: Stefan Sperling date: Thu Jul 23 14:21:28 2020 UTC add symlink support to 'got blame' and 'tog blame' commit - e40622f412c8f937c81a8f76aa780647ea7392bf commit + 0587e10c4c4e054f8aeda2bd499b76c0ec60dc40 blob - f14e875454e17d7c6012447918fec9a697f40c10 blob + ab4db7cd394dd2226cb63800aa4dc8c0d517c846 --- got/got.c +++ got/got.c @@ -4100,6 +4100,7 @@ cmd_blame(int argc, char *argv[]) struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; + char *link_target = NULL; struct got_object_id *obj_id = NULL; struct got_object_id *commit_id = NULL; struct got_blob_object *blob = NULL; @@ -4214,7 +4215,13 @@ cmd_blame(int argc, char *argv[]) goto done; } - error = got_object_id_by_path(&obj_id, repo, commit_id, in_repo_path); + error = got_object_resolve_symlinks(&link_target, in_repo_path, + commit_id, repo); + if (error) + goto done; + + error = got_object_id_by_path(&obj_id, repo, commit_id, + link_target ? link_target : in_repo_path); if (error) goto done; @@ -4258,10 +4265,11 @@ cmd_blame(int argc, char *argv[]) } bca.repo = repo; - error = got_blame(in_repo_path, commit_id, repo, blame_cb, &bca, - check_cancelled, NULL); + error = got_blame(link_target ? link_target : in_repo_path, commit_id, + repo, blame_cb, &bca, check_cancelled, NULL); done: free(in_repo_path); + free(link_target); free(repo_path); free(cwd); free(commit_id); blob - 9e0475af05cac63a02818ca77164c2355cf2428e blob + d3a3bf3015086c89a0e41790e267184927b15cee --- regress/cmdline/blame.sh +++ regress/cmdline/blame.sh @@ -761,7 +761,127 @@ function test_blame_submodule { fi test_done "$testroot" "$ret" } + +function test_blame_symlink { + local testroot=`test_init blame_symlink` + local commit_id0=`git_show_head $testroot/repo` + local short_commit0=`trim_obj_id 32 $commit_id0` + + (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 commit_id1=`git_show_head $testroot/repo` + local short_commit1=`trim_obj_id 32 $commit_id1` + local author_time=`git_show_author_time $testroot/repo` + + # got blame dereferences symlink to a regular file + got blame -r $testroot/repo alpha.link > $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + echo "blame command failed unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + + d=`date -r $author_time +"%G-%m-%d"` + echo "1) $short_commit0 $d $GOT_AUTHOR_8 alpha" \ + > $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" -a "$xfail" == "" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "1" + return 1 + fi + # got blame dereferences symlink with relative path + got blame -r $testroot/repo epsilon/beta.link > $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + echo "blame command failed unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + + d=`date -r $author_time +"%G-%m-%d"` + echo "1) $short_commit0 $d $GOT_AUTHOR_8 beta" \ + > $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" -a "$xfail" == "" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "1" + return 1 + fi + + got blame -r $testroot/repo epsilon.link > $testroot/stdout \ + 2> $testroot/stderr + ret="$?" + if [ "$ret" == "0" ]; then + echo "blame command succeeded unexpectedly" >&2 + test_done "$testroot" "1" + return 1 + fi + + # blame dereferences symlink to a directory + echo "got: wrong type of object" > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "1" + return 1 + fi + + # got blame fails if symlink target does not exist in repo + got blame -r $testroot/repo passwd.link > $testroot/stdout \ + 2> $testroot/stderr + ret="$?" + if [ "$ret" == "0" ]; then + echo "blame command succeeded unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + + echo "got: /etc/passwd: no such entry found in tree" \ + > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "1" + return 1 + fi + + got blame -r $testroot/repo nonexistent.link > $testroot/stdout \ + 2> $testroot/stderr + ret="$?" + if [ "$ret" == "0" ]; then + echo "blame command succeeded unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + + echo "got: /nonexistent: no such entry found in tree" \ + > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "1" + return 1 + fi + + test_done "$testroot" "$ret" +} + run_test test_blame_basic run_test test_blame_tag run_test test_blame_file_single_line @@ -773,3 +893,4 @@ run_test test_blame_commit_subsumed run_test test_blame_blame_h run_test test_blame_added_on_branch run_test test_blame_submodule +run_test test_blame_symlink blob - 37110e98ad018c151bf660c62fd637570da2df3a blob + 47ddd48ca251a920a6562265a2746e94e9df8ad5 --- tog/tog.c +++ tog/tog.c @@ -4499,6 +4499,7 @@ cmd_blame(int argc, char *argv[]) struct got_reflist_head refs; struct got_worktree *worktree = NULL; char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL; + char *link_target = NULL; struct got_object_id *commit_id = NULL; char *commit_id_str = NULL; int ch; @@ -4594,9 +4595,16 @@ cmd_blame(int argc, char *argv[]) error = got_error_from_errno("view_open"); goto done; } - error = open_blame_view(view, in_repo_path, commit_id, &refs, repo); + + error = got_object_resolve_symlinks(&link_target, in_repo_path, + commit_id, repo); if (error) goto done; + + error = open_blame_view(view, link_target ? link_target : in_repo_path, + commit_id, &refs, repo); + if (error) + goto done; if (worktree) { /* Release work tree lock. */ got_worktree_close(worktree); @@ -4606,6 +4614,7 @@ cmd_blame(int argc, char *argv[]) done: free(repo_path); free(in_repo_path); + free(link_target); free(cwd); free(commit_id); if (worktree)