commit - 8d0fe45ad75f58cd5f797f72f4b621bab1282fdb
commit + 78695fb724a1e3e628efb42140d48dbd88d562b3
blob - e00d1afadd8e8acb4b5fc54c640fe23ccfe9d3bd
blob + 93f2913aab432dfc47a0e6bc7af1016b5e89ed80
--- lib/blame.c
+++ lib/blame.c
goto done;
}
- err = got_object_id_by_path(&pobj_id, repo, pid, path);
- if (err) {
- if (err->code == GOT_ERR_NO_TREE_ENTRY) {
- /* Blob's history began in previous commit. */
- err = got_error(GOT_ERR_ITER_COMPLETED);
+ if (pid) {
+ err = got_object_id_by_path(&pobj_id, repo, pid, path);
+ if (err) {
+ if (err->code == GOT_ERR_NO_TREE_ENTRY) {
+ /* Blob's history began in previous commit. */
+ err = got_error(GOT_ERR_ITER_COMPLETED);
+ }
+ goto done;
}
- goto done;
- }
- /* If IDs match then don't bother with diffing. */
- if (got_object_id_cmp(obj_id, pobj_id) == 0) {
- if (cb)
- err = cb(arg, blame->nlines, -1, id);
- goto done;
- }
+ /* If IDs match then don't bother with diffing. */
+ if (got_object_id_cmp(obj_id, pobj_id) == 0) {
+ if (cb)
+ err = cb(arg, blame->nlines, -1, id);
+ goto done;
+ }
- err = got_object_open(&pobj, repo, pobj_id);
- if (err)
- goto done;
+ err = got_object_open(&pobj, repo, pobj_id);
+ if (err)
+ goto done;
- if (pobj->type != GOT_OBJ_TYPE_BLOB) {
- /*
- * Encountered a non-blob at the path (probably a tree).
- * Blob's history began in previous commit.
- */
- err = got_error(GOT_ERR_ITER_COMPLETED);
- goto done;
+ if (pobj->type != GOT_OBJ_TYPE_BLOB) {
+ /*
+ * Encountered a non-blob at the path (probably a tree).
+ * Blob's history began in previous commit.
+ */
+ err = got_error(GOT_ERR_ITER_COMPLETED);
+ goto done;
+ }
+
+ err = got_object_blob_open(&pblob, repo, pobj, 8192);
+ if (err)
+ goto done;
}
err = got_object_blob_open(&blob, repo, obj, 8192);
if (err)
goto done;
- err = got_object_blob_open(&pblob, repo, pobj, 8192);
- if (err)
- goto done;
-
err = got_diff_blob_lines_changed(&changes, pblob, blob);
if (err)
goto done;
struct got_object_id *obj_id = NULL;
struct got_blob_object *blob = NULL;
struct got_blame *blame = NULL;
- struct got_object_id *id = NULL;
+ struct got_object_id *id = NULL, *parent_id = NULL;
int lineno;
struct got_commit_graph *graph = NULL;
id = NULL;
for (;;) {
- struct got_object_id *next_id;
-
- err = got_commit_graph_iter_next(&next_id, graph);
+ err = got_commit_graph_iter_next(&parent_id, graph);
if (err) {
if (err->code == GOT_ERR_ITER_COMPLETED) {
- err = NULL;
+ if (id)
+ err = blame_commit(blame, id,
+ parent_id, path, repo, cb, arg);
+ else
+ err = NULL;
break;
}
if (err->code != GOT_ERR_ITER_NEED_MORE)
err = got_commit_graph_fetch_commits(graph, 1, repo);
if (err)
break;
- else
- continue;
+ continue;
}
- if (next_id == NULL)
- break;
if (id) {
- err = blame_commit(blame, id, next_id, path, repo,
+ err = blame_commit(blame, id, parent_id, path, repo,
cb, arg);
if (err) {
if (err->code == GOT_ERR_ITER_COMPLETED)
if (blame->nannotated == blame->nlines)
break;
}
- id = next_id;
+ id = parent_id;
}
if (id && blame->nannotated < blame->nlines) {
blob - 42e0035977023ee76bd78dbd06474f29da5c19c5
blob + 90e8331aa0d5ab5db7909bb85d3c2623d80126eb
--- lib/object.c
+++ lib/object.c
if (len == 0)
break;
buf = got_object_blob_get_read_buf(blob);
- for (i = hdrlen; i < len; i++) {
- if (buf[i] != '\n')
- continue;
- if (nlines)
- (*nlines)++;
- if (line_offsets && nlines && noffsets < *nlines) {
- off_t *o = recallocarray(*line_offsets,
- noffsets, *nlines, sizeof(**line_offsets));
- if (o == NULL) {
- free(*line_offsets);
- *line_offsets = NULL;
- return got_error_from_errno(
- "recallocarray");
- }
- *line_offsets = o;
- noffsets = *nlines;
+ if (line_offsets && nlines) {
+ if (*line_offsets == NULL) {
+ /* Have some data but perhaps no '\n'. */
+ noffsets = 1;
+ *nlines = 1;
+ *line_offsets = malloc(sizeof(**line_offsets));
+ if (*line_offsets == NULL)
+ return got_error_from_errno("malloc");
+ (*line_offsets)[0] = 0;
}
- if (line_offsets && nlines && total_len) {
- (*line_offsets)[*nlines - 1] = off;
- off = *total_len + i + 1 - got_object_blob_get_hdrlen(blob);
+ /* Scan '\n' offsets in this chunk of data. */
+ for (i = hdrlen; i < len; i++) {
+ if (i > hdrlen && buf[i] == '\n')
+ (*nlines)++;
+ if (noffsets < *nlines) {
+ off_t *o = recallocarray(*line_offsets,
+ noffsets, *nlines,
+ sizeof(**line_offsets));
+ if (o == NULL) {
+ free(*line_offsets);
+ *line_offsets = NULL;
+ return got_error_from_errno(
+ "recallocarray");
+ }
+ *line_offsets = o;
+ noffsets = *nlines;
+ }
+ if (total_len) {
+ (*line_offsets)[*nlines - 1] = off;
+ off = *total_len + i -
+ got_object_blob_get_hdrlen(blob);
+ }
}
}
- if (total_len)
- *total_len += len;
/* Skip blob object header first time around. */
n = fwrite(buf + hdrlen, 1, len - hdrlen, outfile);
if (n != len - hdrlen)
return got_ferror(outfile, GOT_ERR_IO);
+ if (total_len)
+ *total_len += len - hdrlen;
hdrlen = 0;
} while (len != 0);
blob - ccd7980f4fa22dcd0dfb01b2e5a895ca27b01246
blob + bd295cf08b277cac199f4c1fc887139d66aecd2f
--- regress/cmdline/blame.sh
+++ regress/cmdline/blame.sh
test_done "$testroot" "$ret"
}
+function test_blame_file_single_line {
+ local testroot=`test_init blame_file_single_line`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo 1 > $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "change 1" > /dev/null)
+ local commit1=`git_show_head $testroot/repo`
+
+ (cd $testroot/wt && got blame alpha > $testroot/stdout)
+
+ local short_commit1=`trim_obj_id 32 $commit1`
+
+ echo "$short_commit1 1" > $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_file_single_line_no_newline {
+ local testroot=`test_init blame_file_single_line_no_newline`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo -n 1 > $testroot/wt/alpha
+ (cd $testroot/wt && got commit -m "change 1" > /dev/null)
+ local commit1=`git_show_head $testroot/repo`
+
+ (cd $testroot/wt && got blame alpha > $testroot/stdout)
+
+ local short_commit1=`trim_obj_id 32 $commit1`
+
+ echo "$short_commit1 1" > $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"
+}
+
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