commit 8d725ae11ecc53e7d7f7bc3b576f7e949d08b980 from: Stefan Sperling date: Sun Aug 18 11:35:04 2019 UTC make blame go through first parent history; add more blame test cases commit - 14ed98fdf951d01d640d17b7ef18d4a9a3b761a7 commit + 8d725ae11ecc53e7d7f7bc3b576f7e949d08b980 blob - d7a5a560a572e11ce47c89a95d7c14bc30483ee8 blob + a1b4bd57e86473bd5bd845a4ee2c6601b8df3430 --- lib/blame.c +++ lib/blame.c @@ -40,7 +40,6 @@ struct got_blame_line { int annotated; struct got_object_id id; - off_t offset; }; struct got_blame_diff_offsets { @@ -188,16 +187,22 @@ blame_changes(struct got_blame *blame, struct got_diff static const struct got_error * blame_commit(struct got_blame *blame, struct got_object_id *id, - struct got_object_id *pid, const char *path, struct got_repository *repo, + const char *path, struct got_repository *repo, const struct got_error *(*cb)(void *, int, int, struct got_object_id *), void *arg) { const struct got_error *err = NULL; struct got_object *obj = NULL, *pobj = NULL; struct got_object_id *obj_id = NULL, *pobj_id = NULL; + struct got_commit_object *commit = NULL; struct got_blob_object *blob = NULL, *pblob = NULL; struct got_diff_changes *changes = NULL; + struct got_object_qid *pid = NULL; + err = got_object_open_as_commit(&commit, repo, id); + if (err) + return err; + err = got_object_id_by_path(&obj_id, repo, id, path); if (err) goto done; @@ -211,8 +216,9 @@ blame_commit(struct got_blame *blame, struct got_objec goto done; } + pid = SIMPLEQ_FIRST(got_object_commit_get_parent_ids(commit)); if (pid) { - err = got_object_id_by_path(&pobj_id, repo, pid, path); + err = got_object_id_by_path(&pobj_id, repo, pid->id, path); if (err) { if (err->code == GOT_ERR_NO_TREE_ENTRY) { /* Blob's history began in previous commit. */ @@ -260,6 +266,8 @@ blame_commit(struct got_blame *blame, struct got_objec } else if (cb) err = cb(arg, blame->nlines, -1, id); done: + if (commit) + got_object_commit_close(commit); free(obj_id); free(pobj_id); if (obj) @@ -302,7 +310,7 @@ blame_open(struct got_blame **blamep, const char *path struct got_object_id *obj_id = NULL; struct got_blob_object *blob = NULL; struct got_blame *blame = NULL; - struct got_object_id *id = NULL, *parent_id = NULL; + struct got_object_id *id = NULL, *next_id = NULL; int lineno; struct got_commit_graph *graph = NULL; @@ -345,7 +353,7 @@ blame_open(struct got_blame **blamep, const char *path goto done; } - err = got_commit_graph_open(&graph, start_commit_id, path, 0, repo); + err = got_commit_graph_open(&graph, start_commit_id, path, 1, repo); if (err) return err; err = got_commit_graph_iter_start(graph, start_commit_id, repo); @@ -354,12 +362,12 @@ blame_open(struct got_blame **blamep, const char *path id = NULL; for (;;) { - err = got_commit_graph_iter_next(&parent_id, graph); + err = got_commit_graph_iter_next(&next_id, graph); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) { if (id) err = blame_commit(blame, id, - parent_id, path, repo, cb, arg); + path, repo, cb, arg); else err = NULL; break; @@ -372,7 +380,7 @@ blame_open(struct got_blame **blamep, const char *path continue; } if (id) { - err = blame_commit(blame, id, parent_id, path, repo, + err = blame_commit(blame, id, path, repo, cb, arg); if (err) { if (err->code == GOT_ERR_ITER_COMPLETED) @@ -382,7 +390,7 @@ blame_open(struct got_blame **blamep, const char *path if (blame->nannotated == blame->nlines) break; } - id = parent_id; + id = next_id; } if (id && blame->nannotated < blame->nlines) { blob - 60ecdd0c932486f6f73a0a6a29d9048339d48eae blob + 66015530063440d784e2152767420965b157b0de --- regress/cmdline/blame.sh +++ regress/cmdline/blame.sh @@ -161,7 +161,342 @@ function test_blame_file_single_line_no_newline { test_done "$testroot" "$ret" } +function test_blame_all_lines_replaced { + local testroot=`test_init blame_all_lines_replaced` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + jot 8 > $testroot/wt/alpha + (cd $testroot/wt && got commit -m "change 1" > /dev/null) + local commit1=`git_show_head $testroot/repo` + local short_commit1=`trim_obj_id 32 $commit1` + local author_time=`git_show_author_time $testroot/repo` + + (cd $testroot/wt && got blame alpha > $testroot/stdout) + + d=`date -r $author_time +"%g/%m/%d"` + echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected + echo "2) $short_commit1 $d $GOT_AUTHOR_8 2" >> $testroot/stdout.expected + echo "3) $short_commit1 $d $GOT_AUTHOR_8 3" >> $testroot/stdout.expected + echo "4) $short_commit1 $d $GOT_AUTHOR_8 4" >> $testroot/stdout.expected + echo "5) $short_commit1 $d $GOT_AUTHOR_8 5" >> $testroot/stdout.expected + echo "6) $short_commit1 $d $GOT_AUTHOR_8 6" >> $testroot/stdout.expected + echo "7) $short_commit1 $d $GOT_AUTHOR_8 7" >> $testroot/stdout.expected + echo "8) $short_commit1 $d $GOT_AUTHOR_8 8" >> $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" + +} + +function test_blame_lines_shifted_up { + local testroot=`test_init blame_lines_shifted_up` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + jot 8 > $testroot/wt/alpha + (cd $testroot/wt && got commit -m "change 1" > /dev/null) + local commit1=`git_show_head $testroot/repo` + local short_commit1=`trim_obj_id 32 $commit1` + local author_time=`git_show_author_time $testroot/repo` + + sed -i -e '/^[345]$/d' $testroot/wt/alpha + (cd $testroot/wt && got commit -m "change 2" > /dev/null) + local commit2=`git_show_head $testroot/repo` + local short_commit2=`trim_obj_id 32 $commit2` + + jot 2 > $testroot/wt/alpha + echo foo >> $testroot/wt/alpha + echo bar >> $testroot/wt/alpha + echo baz >> $testroot/wt/alpha + jot 8 6 8 1 >> $testroot/wt/alpha + (cd $testroot/wt && got commit -m "change 3" > /dev/null) + local commit3=`git_show_head $testroot/repo` + local short_commit3=`trim_obj_id 32 $commit3` + local author_time=`git_show_author_time $testroot/repo` + + (cd $testroot/wt && got blame alpha > $testroot/stdout) + + d=`date -r $author_time +"%g/%m/%d"` + echo "1) $short_commit1 $d $GOT_AUTHOR_8 1" > $testroot/stdout.expected + echo "2) $short_commit1 $d $GOT_AUTHOR_8 2" >> $testroot/stdout.expected + echo "3) $short_commit3 $d $GOT_AUTHOR_8 foo" >> $testroot/stdout.expected + echo "4) $short_commit3 $d $GOT_AUTHOR_8 bar" >> $testroot/stdout.expected + echo "5) $short_commit3 $d $GOT_AUTHOR_8 baz" >> $testroot/stdout.expected + echo "6) $short_commit1 $d $GOT_AUTHOR_8 6" >> $testroot/stdout.expected + echo "7) $short_commit1 $d $GOT_AUTHOR_8 7" >> $testroot/stdout.expected + echo "8) $short_commit1 $d $GOT_AUTHOR_8 8" >> $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + + test_done "$testroot" "$ret" +} + +function test_blame_lines_shifted_down { + local testroot=`test_init blame_lines_shifted_down` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + jot 8 > $testroot/wt/alpha + (cd $testroot/wt && got commit -m "change 1" > /dev/null) + local commit1=`git_show_head $testroot/repo` + local short_commit1=`trim_obj_id 32 $commit1` + local author_time=`git_show_author_time $testroot/repo` + + sed -i -e '/^8$/d' $testroot/wt/alpha + (cd $testroot/wt && got commit -m "change 2" > /dev/null) + local commit2=`git_show_head $testroot/repo` + local short_commit2=`trim_obj_id 32 $commit2` + + jot 2 > $testroot/wt/alpha + echo foo >> $testroot/wt/alpha + echo bar >> $testroot/wt/alpha + echo baz >> $testroot/wt/alpha + jot 8 3 8 1 >> $testroot/wt/alpha + (cd $testroot/wt && got commit -m "change 3" > /dev/null) + local commit3=`git_show_head $testroot/repo` + local short_commit3=`trim_obj_id 32 $commit3` + local author_time=`git_show_author_time $testroot/repo` + + (cd $testroot/wt && got blame alpha > $testroot/stdout) + + d=`date -r $author_time +"%g/%m/%d"` + echo "01) $short_commit1 $d $GOT_AUTHOR_8 1" \ + > $testroot/stdout.expected + echo "02) $short_commit1 $d $GOT_AUTHOR_8 2" \ + >> $testroot/stdout.expected + echo "03) $short_commit3 $d $GOT_AUTHOR_8 foo" \ + >> $testroot/stdout.expected + echo "04) $short_commit3 $d $GOT_AUTHOR_8 bar" \ + >> $testroot/stdout.expected + echo "05) $short_commit3 $d $GOT_AUTHOR_8 baz" \ + >> $testroot/stdout.expected + echo "06) $short_commit1 $d $GOT_AUTHOR_8 3" \ + >> $testroot/stdout.expected + echo "07) $short_commit1 $d $GOT_AUTHOR_8 4" \ + >> $testroot/stdout.expected + echo "08) $short_commit1 $d $GOT_AUTHOR_8 5" \ + >> $testroot/stdout.expected + echo "09) $short_commit1 $d $GOT_AUTHOR_8 6" \ + >> $testroot/stdout.expected + echo "10) $short_commit1 $d $GOT_AUTHOR_8 7" \ + >> $testroot/stdout.expected + echo "11) $short_commit3 $d $GOT_AUTHOR_8 8" \ + >> $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + + test_done "$testroot" "$ret" +} + +function test_blame_commit_subsumed { + local testroot=`test_init blame_commit_subsumed` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + cat > $testroot/wt/alpha < /dev/null) + local commit1=`git_show_head $testroot/repo` + local short_commit1=`trim_obj_id 32 $commit1` + local author_time1=`git_show_author_time $testroot/repo` + local d1=`date -r $author_time1 +"%g/%m/%d"` + + cat > $testroot/wt/alpha < /dev/null) + local commit2=`git_show_head $testroot/repo` + local short_commit2=`trim_obj_id 32 $commit2` + local author_time2=`git_show_author_time $testroot/repo` + local d2=`date -r $author_time2 +"%g/%m/%d"` + + cat > $testroot/wt/alpha < /dev/null) + local commit3=`git_show_head $testroot/repo` + local short_commit3=`trim_obj_id 32 $commit3` + local author_time3=`git_show_author_time $testroot/repo` + local d3=`date -r $author_time3 +"%g/%m/%d"` + + cat > $testroot/wt/alpha < /dev/null) + local commit4=`git_show_head $testroot/repo` + local short_commit4=`trim_obj_id 32 $commit4` + local author_time4=`git_show_author_time $testroot/repo` + local d4=`date -r $author_time4 +"%g/%m/%d"` + + (cd $testroot/wt && got blame alpha > $testroot/stdout) + + echo -n "01) $short_commit3 $d3 $GOT_AUTHOR_8 " \ + > $testroot/stdout.expected + echo "SUBDIRS = ext modules pdns codedocs docs" \ + >> $testroot/stdout.expected + echo "02) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + echo -n "03) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + echo 'EXTRA_DIST =' >> $testroot/stdout.expected + echo -n "04) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + printf "\tINSTALL\n" >> $testroot/stdout.expected + echo -n "05) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + printf "\tNOTICE\n" >> $testroot/stdout.expected + echo -n "06) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + printf "\tREADME\n" >> $testroot/stdout.expected + echo -n "07) $short_commit4 $d4 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + printf "\tCOPYING\n" >> $testroot/stdout.expected + echo -n "08) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + printf "\tcodedocs/doxygen.conf\n" >> $testroot/stdout.expected + echo -n "09) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + printf "\tcontrib/powerdns.solaris.init.d\n" \ + >> $testroot/stdout.expected + echo -n "10) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + printf "\tpdns/named.conf.parsertest\n" >> $testroot/stdout.expected + echo -n "11) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + printf "\tregression-tests/zones/unit.test\n" \ + >> $testroot/stdout.expected + echo -n "12) $short_commit4 $d4 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + printf "\tbuilder-support/gen-version\n" >> $testroot/stdout.expected + echo "13) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + echo -n "14) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + echo "ACLOCAL_AMFLAGS = -I m4" \ + >> $testroot/stdout.expected + echo "15) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + echo -n "16) $short_commit1 $d1 $GOT_AUTHOR_8 " \ + >> $testroot/stdout.expected + echo "dvi: # do nothing to build dvi" \ + >> $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" "xfail: line 3 has wrong annotation" + return 1 + fi + test_done "$testroot" "$ret" +} + run_test test_blame_basic run_test test_blame_tag run_test test_blame_file_single_line run_test test_blame_file_single_line_no_newline +run_test test_blame_all_lines_replaced +run_test test_blame_lines_shifted_up +run_test test_blame_lines_shifted_down +run_test test_blame_commit_subsumed