commit - 28466fcabc0e493ee2ad79cf288842307653cd28
commit + be97ab03efd83aac37b83f2df2dea936213b456c
blob - a694c0e1f36f3891e4f55c84802c58833a6445a1
blob + 06f7a35a329a5563b7c304c6b2be8b38e249e518
--- got/got.1
+++ got/got.1
If this option is not specified, default to the work tree's current branch
if invoked in a work tree, or to the repository's HEAD reference.
.It Fl d
-Display diffstat of changes introduced in the commit.
+Display diffstat of changes introduced in each commit.
Cannot be used with the
.Fl s
option.
blob - f70f4faf97c36aa65cabcb8d08afdc2c40d8516b
blob + be354c6eccc813b8775349e6f2615d21cc0a6884
--- got/got.c
+++ got/got.c
static const struct got_error *
diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2,
const char *path, int diff_context, int ignore_whitespace,
- int force_text_diff, int show_diffstat, struct got_repository *repo,
- FILE *outfile)
+ int force_text_diff, struct got_diffstat_cb_arg *dsa,
+ struct got_repository *repo, FILE *outfile)
{
const struct got_error *err = NULL;
struct got_blob_object *blob1 = NULL, *blob2 = NULL;
path++;
err = got_diff_blob(NULL, NULL, blob1, blob2, f1, f2, path, path,
GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace,
- force_text_diff, show_diffstat, NULL, outfile);
+ force_text_diff, dsa, outfile);
done:
if (fd1 != -1 && close(fd1) == -1 && err == NULL)
err = got_error_from_errno("close");
static const struct got_error *
diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2,
const char *path, int diff_context, int ignore_whitespace,
- int force_text_diff, struct got_repository *repo, FILE *outfile)
+ int force_text_diff, struct got_diffstat_cb_arg *dsa,
+ struct got_repository *repo, FILE *outfile)
{
const struct got_error *err = NULL;
struct got_tree_object *tree1 = NULL, *tree2 = NULL;
arg.diff_context = diff_context;
arg.ignore_whitespace = ignore_whitespace;
arg.force_text_diff = force_text_diff;
- arg.show_diffstat = 0;
- arg.diffstat = NULL;
+ arg.diffstat = dsa;
arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE;
arg.outfile = outfile;
arg.lines = NULL;
static const struct got_error *
print_patch(struct got_commit_object *commit, struct got_object_id *id,
- const char *path, int diff_context, struct got_repository *repo,
- FILE *outfile)
+ const char *path, int diff_context, struct got_diffstat_cb_arg *dsa,
+ struct got_repository *repo, FILE *outfile)
{
const struct got_error *err = NULL;
struct got_commit_object *pcommit = NULL;
switch (obj_type) {
case GOT_OBJ_TYPE_BLOB:
err = diff_blobs(obj_id1, obj_id2, path, diff_context,
- 0, 0, 0, repo, outfile);
+ 0, 0, dsa, repo, outfile);
break;
case GOT_OBJ_TYPE_TREE:
err = diff_trees(obj_id1, obj_id2, path, diff_context,
- 0, 0, repo, outfile);
+ 0, 0, dsa, repo, outfile);
break;
default:
err = got_error(GOT_ERR_OBJ_TYPE);
id_str1 ? id_str1 : "/dev/null");
fprintf(outfile, "commit + %s\n", id_str2);
err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, 0,
- repo, outfile);
+ dsa, repo, outfile);
}
done:
free(id_str1);
if (err)
return err;
- err = print_patch(commit, id, path, diff_context, repo, f);
+ err = print_patch(commit, id, path, diff_context, NULL, repo, f);
if (err)
goto done;
}
static const struct got_error *
-print_diffstat(struct got_diffstat_cb_arg *dsa, struct got_pathlist_head *paths,
- const char *header)
+print_diffstat(struct got_diffstat_cb_arg *dsa, const char *header)
{
struct got_pathlist_entry *pe;
if (header != NULL)
printf("%s\n", header);
- TAILQ_FOREACH(pe, paths, entry) {
+ TAILQ_FOREACH(pe, dsa->paths, entry) {
struct got_diff_changed_path *cp = pe->data;
int pad = dsa->max_path_len - pe->path_len + 1;
}
static const struct got_error *
+printfile(FILE *f)
+{
+ char buf[8192];
+ size_t r;
+
+ if (fseeko(f, 0L, SEEK_SET) == -1)
+ return got_error_from_errno("fseek");
+
+ for (;;) {
+ r = fread(buf, 1, sizeof(buf), f);
+ if (r == 0) {
+ if (ferror(f))
+ return got_error_from_errno("fread");
+ if (feof(f))
+ break;
+ }
+ if (fwrite(buf, 1, r, stdout) != r)
+ return got_ferror(stdout, GOT_ERR_IO);
+ }
+
+ return NULL;
+}
+
+static const struct got_error *
print_commit(struct got_commit_object *commit, struct got_object_id *id,
struct got_repository *repo, const char *path,
- struct got_pathlist_head *changed_paths, struct got_diffstat_cb_arg *dsa,
- int show_patch, int diff_context,
+ struct got_pathlist_head *changed_paths,
+ struct got_diffstat_cb_arg *diffstat, int show_patch, int diff_context,
struct got_reflist_object_id_map *refs_idmap, const char *custom_refs_str)
{
const struct got_error *err = NULL;
+ FILE *f = NULL;
char *id_str, *datestr, *logmsg0, *logmsg, *line;
char datebuf[26];
time_t committer_time;
} while (line);
free(logmsg0);
- if (dsa && changed_paths) {
- err = print_diffstat(dsa, changed_paths, NULL);
- if (err)
- goto done;
- } else if (changed_paths) {
+ if (changed_paths && diffstat == NULL) {
struct got_pathlist_entry *pe;
TAILQ_FOREACH(pe, changed_paths, entry) {
printf("\n");
}
if (show_patch) {
- err = print_patch(commit, id, path, diff_context, repo, stdout);
- if (err == 0)
- printf("\n");
+ if (diffstat) {
+ f = got_opentemp();
+ if (f == NULL) {
+ err = got_error_from_errno("got_opentemp");
+ goto done;
+ }
+ }
+
+ err = print_patch(commit, id, path, diff_context, diffstat,
+ repo, diffstat == NULL ? stdout : f);
+ if (err)
+ goto done;
}
+ if (diffstat) {
+ err = print_diffstat(diffstat, NULL);
+ if (err)
+ goto done;
+ if (show_patch) {
+ err = printfile(f);
+ if (err)
+ goto done;
+ }
+ }
+ if (show_patch)
+ printf("\n");
if (fflush(stdout) != 0 && err == NULL)
err = got_error_from_errno("fflush");
done:
+ if (f && fclose(f) == EOF && err == NULL)
+ err = got_error_from_errno("fclose");
free(id_str);
free(refs_str);
return err;
if (err)
break;
- if ((show_changed_paths || show_diffstat) &&
- !reverse_display_order) {
+ if ((show_changed_paths || (show_diffstat && !show_patch))
+ && !reverse_display_order) {
err = get_changed_paths(&changed_paths, commit, repo,
show_diffstat ? &dsa : NULL);
if (err)
&changed_paths, ®ex);
if (have_match == 0 && show_patch) {
err = match_patch(&have_match, commit, &id,
- path, diff_context, repo, ®ex,
- tmpfile);
+ path, diff_context, repo, ®ex, tmpfile);
if (err)
break;
}
&qid->id);
if (err)
break;
- if (show_changed_paths || show_diffstat) {
- err = get_changed_paths(&changed_paths,
- commit, repo, show_diffstat ? &dsa : NULL);
+ if (show_changed_paths ||
+ (show_diffstat && !show_patch)) {
+ err = get_changed_paths(&changed_paths, commit,
+ repo, show_diffstat ? &dsa : NULL);
if (err)
break;
}
enum got_diff_algorithm diff_algo;
int ignore_whitespace;
int force_text_diff;
- int show_diffstat;
FILE *f1;
FILE *f2;
FILE *outfile;
err = got_diff_objects_as_blobs(NULL, NULL, a->f1, a->f2,
fd1, fd2, blob_id, staged_blob_id, label1, label2,
a->diff_algo, a->diff_context, a->ignore_whitespace,
- a->force_text_diff, a->show_diffstat, a->diffstat, a->repo,
- a->outfile);
+ a->force_text_diff, a->diffstat, a->repo, a->outfile);
goto done;
}
err = got_diff_blob_file(blob1, a->f1, size1, label1, f2 ? f2 : a->f2,
f2_exists, &sb, path, GOT_DIFF_ALGORITHM_PATIENCE, a->diff_context,
- a->ignore_whitespace, a->force_text_diff, a->show_diffstat,
- a->diffstat, a->outfile);
+ a->ignore_whitespace, a->force_text_diff, a->diffstat, a->outfile);
done:
if (fd1 != -1 && close(fd1) == -1 && err == NULL)
err = got_error_from_errno("close");
}
static const struct got_error *
-printfile(FILE *f)
-{
- char buf[8192];
- size_t r;
-
- if (fseeko(f, 0L, SEEK_SET) == -1)
- return got_error_from_errno("fseek");
-
- for (;;) {
- r = fread(buf, 1, sizeof(buf), f);
- if (r == 0) {
- if (ferror(f))
- return got_error_from_errno("fread");
- if (feof(f))
- break;
- }
- if (fwrite(buf, 1, r, stdout) != r)
- return got_ferror(stdout, GOT_ERR_IO);
- }
-
- return NULL;
-}
-
-static const struct got_error *
cmd_diff(int argc, char *argv[])
{
const struct got_error *error;
arg.diff_staged = diff_staged;
arg.ignore_whitespace = ignore_whitespace;
arg.force_text_diff = force_text_diff;
- arg.show_diffstat = show_diffstat;
- arg.diffstat = &dsa;
+ arg.diffstat = show_diffstat ? &dsa : NULL;
arg.f1 = f1;
arg.f2 = f2;
arg.outfile = outfile;
goto done;
}
- error = print_diffstat(&dsa, &diffstat_paths, header);
+ error = print_diffstat(&dsa, header);
free(header);
if (error)
goto done;
error = got_diff_objects_as_blobs(NULL, NULL, f1, f2,
fd1, fd2, ids[0], ids[1], NULL, NULL,
GOT_DIFF_ALGORITHM_PATIENCE, diff_context,
- ignore_whitespace, force_text_diff, show_diffstat,
+ ignore_whitespace, force_text_diff,
show_diffstat ? &dsa : NULL, repo, outfile);
break;
case GOT_OBJ_TYPE_TREE:
error = got_diff_objects_as_trees(NULL, NULL, f1, f2, fd1, fd2,
ids[0], ids[1], &paths, "", "",
GOT_DIFF_ALGORITHM_PATIENCE, diff_context,
- ignore_whitespace, force_text_diff, show_diffstat,
+ ignore_whitespace, force_text_diff,
show_diffstat ? &dsa : NULL, repo, outfile);
break;
case GOT_OBJ_TYPE_COMMIT:
error = got_diff_objects_as_commits(NULL, NULL, f1, f2,
fd1, fd2, ids[0], ids[1], &paths,
GOT_DIFF_ALGORITHM_PATIENCE, diff_context,
- ignore_whitespace, force_text_diff, show_diffstat,
+ ignore_whitespace, force_text_diff,
show_diffstat ? &dsa : NULL, repo, outfile);
break;
default:
goto done;
}
- error = print_diffstat(&dsa, &diffstat_paths, header);
+ error = print_diffstat(&dsa, header);
free(header);
if (error)
goto done;
blob - 9abf39da83bf1be247e7a193dbd862538fbc98e1
blob + e4c0296bd2054f17e6580ab90ac106d0cf9fe9bd
--- gotwebd/got_operations.c
+++ gotwebd/got_operations.c
case GOT_OBJ_TYPE_BLOB:
error = got_diff_objects_as_blobs(NULL, NULL, f1, f2, fd4, fd5,
id1, id2, NULL, NULL, GOT_DIFF_ALGORITHM_MYERS, 3, 0, 0,
- 0, NULL, repo, f3);
+ NULL, repo, f3);
break;
case GOT_OBJ_TYPE_TREE:
error = got_diff_objects_as_trees(NULL, NULL, f1, f2, fd4, fd5,
id1, id2, NULL, "", "", GOT_DIFF_ALGORITHM_MYERS, 3, 0, 0,
- 0, NULL, repo, f3);
+ NULL, repo, f3);
break;
case GOT_OBJ_TYPE_COMMIT:
error = got_diff_objects_as_commits(NULL, NULL, f1, f2, fd4,
fd5, id1, id2, NULL, GOT_DIFF_ALGORITHM_MYERS, 3, 0, 0,
- 0, NULL, repo, f3);
+ NULL, repo, f3);
break;
default:
error = got_error(GOT_ERR_OBJ_TYPE);
blob - ba881aed5067fd49ac9a5f284d1df97cc01b1def
blob + 4ace88b7e3ac64b1a5b78bf1f0652f1c0116658c
--- include/got_diff.h
+++ include/got_diff.h
*/
const struct got_error *got_diff_blob(struct got_diff_line **, size_t *,
struct got_blob_object *, struct got_blob_object *, FILE *, FILE *,
- const char *, const char *, enum got_diff_algorithm, int, int, int, int,
+ const char *, const char *, enum got_diff_algorithm, int, int, int,
struct got_diffstat_cb_arg *, FILE *);
/*
*/
const struct got_error *got_diff_blob_file(struct got_blob_object *, FILE *,
off_t, const char *, FILE *, int, struct stat *, const char *,
- enum got_diff_algorithm, int, int, int, int, struct got_diffstat_cb_arg *,
+ enum got_diff_algorithm, int, int, int, struct got_diffstat_cb_arg *,
FILE *);
/*
int diff_context; /* Sets the number of context lines. */
int ignore_whitespace; /* Ignore whitespace differences. */
int force_text_diff; /* Assume text even if binary data detected. */
- int show_diffstat; /* Compute diffstat of changes */
- struct got_diffstat_cb_arg *diffstat;
+ struct got_diffstat_cb_arg *diffstat; /* Compute diffstat of changes */
enum got_diff_algorithm diff_algo; /* Diffing algorithm to use. */
/*
const struct got_error *got_diff_objects_as_blobs(struct got_diff_line **,
size_t *, FILE *, FILE *, int, int, struct got_object_id *,
struct got_object_id *, const char *, const char *, enum got_diff_algorithm,
- int, int, int, int, struct got_diffstat_cb_arg *, struct got_repository *,
+ int, int, int, struct got_diffstat_cb_arg *, struct got_repository *,
FILE *);
struct got_pathlist_head;
const struct got_error *got_diff_objects_as_trees(struct got_diff_line **,
size_t *, FILE *, FILE *, int, int, struct got_object_id *,
struct got_object_id *, struct got_pathlist_head *, const char *,
- const char *, enum got_diff_algorithm, int, int, int, int,
+ const char *, enum got_diff_algorithm, int, int, int,
struct got_diffstat_cb_arg *, struct got_repository *, FILE *);
/*
const struct got_error *got_diff_objects_as_commits(struct got_diff_line **,
size_t *, FILE *, FILE *, int, int, struct got_object_id *,
struct got_object_id *, struct got_pathlist_head *, enum got_diff_algorithm,
- int, int, int, int, struct got_diffstat_cb_arg *, struct got_repository *,
+ int, int, int, struct got_diffstat_cb_arg *, struct got_repository *,
FILE *);
#define GOT_DIFF_MAX_CONTEXT 64
blob - a30a4a283cc796552f16019ba25c277b5e921812
blob + 60f065829263cd6efb7509bf77e6120c3ff8aa62
--- lib/diff.c
+++ lib/diff.c
struct got_blob_object *blob2, FILE *f1, FILE *f2,
const char *label1, const char *label2, mode_t mode1, mode_t mode2,
int diff_context, int ignore_whitespace, int force_text_diff,
- int show_diffstat, struct got_diffstat_cb_arg *ds, FILE *outfile,
+ struct got_diffstat_cb_arg *diffstat, FILE *outfile,
enum got_diff_algorithm diff_algo)
{
const struct got_error *err = NULL, *free_err;
if (err)
goto done;
- if (show_diffstat) {
+ if (diffstat) {
char *path = NULL;
int status = GOT_STATUS_NO_CHANGE;
- /*
- * Ignore 'm'ode status change: if there's no accompanying
- * content change, there'll be no diffstat, and if there
- * are actual changes, 'M'odified takes precedence.
- */
if (blob1 == NULL)
status = GOT_STATUS_ADD;
else if (blob2 == NULL)
status = GOT_STATUS_DELETE;
- else
- status = GOT_STATUS_MODIFY;
+ else {
+ if (strcmp(idstr1, idstr2) != 0)
+ status = GOT_STATUS_MODIFY;
+ else if (mode1 != mode2)
+ status = GOT_STATUS_MODE_CHANGE;
+ }
if (label1 == NULL && label2 == NULL) {
/* diffstat of blobs, show hash instead of path */
}
}
- err = get_diffstat(ds, path, result->result, force_text_diff,
- status);
+ err = get_diffstat(diffstat, path, result->result,
+ force_text_diff, status);
if (err) {
free(path);
goto done;
return diff_blobs(&a->lines, &a->nlines, NULL,
blob1, blob2, f1, f2, label1, label2, mode1, mode2, a->diff_context,
- a->ignore_whitespace, a->force_text_diff, a->show_diffstat,
- a->diffstat, a->outfile, a->diff_algo);
+ a->ignore_whitespace, a->force_text_diff, a->diffstat, a->outfile,
+ a->diff_algo);
}
const struct got_error *
struct got_blob_object *blob1, struct got_blob_object *blob2,
FILE *f1, FILE *f2, const char *label1, const char *label2,
enum got_diff_algorithm diff_algo, int diff_context,
- int ignore_whitespace, int force_text_diff, int show_diffstat,
+ int ignore_whitespace, int force_text_diff,
struct got_diffstat_cb_arg *ds, FILE *outfile)
{
return diff_blobs(lines, nlines, NULL, blob1, blob2, f1, f2,
label1, label2, 0, 0, diff_context, ignore_whitespace,
- force_text_diff, show_diffstat, ds, outfile, diff_algo);
+ force_text_diff, ds, outfile, diff_algo);
}
static const struct got_error *
struct got_blob_object *blob1, FILE *f1, off_t size1, const char *label1,
FILE *f2, int f2_exists, struct stat *sb2, const char *label2,
enum got_diff_algorithm diff_algo, int diff_context, int ignore_whitespace,
- int force_text_diff, int show_diffstat, struct got_diffstat_cb_arg *ds,
- FILE *outfile)
+ int force_text_diff, struct got_diffstat_cb_arg *diffstat, FILE *outfile)
{
const struct got_error *err = NULL, *free_err;
char hex1[SHA1_DIGEST_STRING_LENGTH];
goto done;
}
- if (show_diffstat) {
+ if (diffstat) {
char *path = NULL;
int status = GOT_STATUS_NO_CHANGE;
goto done;
}
- err = get_diffstat(ds, path, result->result, force_text_diff,
- status);
+ err = get_diffstat(diffstat, path, result->result,
+ force_text_diff, status);
if (err) {
free(path);
goto done;
got_diff_blob_file(struct got_blob_object *blob1, FILE *f1, off_t size1,
const char *label1, FILE *f2, int f2_exists, struct stat *sb2,
const char *label2, enum got_diff_algorithm diff_algo, int diff_context,
- int ignore_whitespace, int force_text_diff, int show_diffstat,
+ int ignore_whitespace, int force_text_diff,
struct got_diffstat_cb_arg *ds, FILE *outfile)
{
return diff_blob_file(NULL, blob1, f1, size1, label1, f2, f2_exists,
sb2, label2, diff_algo, diff_context, ignore_whitespace,
- force_text_diff, show_diffstat, ds, outfile);
+ force_text_diff, ds, outfile);
}
static const struct got_error *
struct got_object_id *id1, struct got_object_id *id2,
const char *label1, const char *label2,
enum got_diff_algorithm diff_algo, int diff_context,
- int ignore_whitespace, int force_text_diff, int show_diffstat,
- struct got_diffstat_cb_arg *ds, struct got_repository *repo, FILE *outfile)
+ int ignore_whitespace, int force_text_diff, struct got_diffstat_cb_arg *ds,
+ struct got_repository *repo, FILE *outfile)
{
const struct got_error *err;
struct got_blob_object *blob1 = NULL, *blob2 = NULL;
}
err = got_diff_blob(lines, nlines, blob1, blob2, f1, f2, label1, label2,
diff_algo, diff_context, ignore_whitespace, force_text_diff,
- show_diffstat, ds, outfile);
+ ds, outfile);
done:
if (blob1)
got_object_blob_close(blob1);
struct got_object_id *id1, struct got_object_id *id2,
struct got_pathlist_head *paths, const char *label1, const char *label2,
int diff_context, int ignore_whitespace, int force_text_diff,
- int show_diffstat, struct got_diffstat_cb_arg *dsa,
- struct got_repository *repo, FILE *outfile,
- enum got_diff_algorithm diff_algo)
+ struct got_diffstat_cb_arg *dsa, struct got_repository *repo,
+ FILE *outfile, enum got_diff_algorithm diff_algo)
{
const struct got_error *err;
struct got_tree_object *tree1 = NULL, *tree2 = NULL;
arg.diff_context = diff_context;
arg.ignore_whitespace = ignore_whitespace;
arg.force_text_diff = force_text_diff;
- arg.show_diffstat = show_diffstat;
arg.diffstat = dsa;
arg.outfile = outfile;
if (want_linemeta) {
struct got_object_id *id1, struct got_object_id *id2,
struct got_pathlist_head *paths, const char *label1, const char *label2,
enum got_diff_algorithm diff_algo, int diff_context, int ignore_whitespace,
- int force_text_diff, int show_diffstat, struct got_diffstat_cb_arg *dsa,
+ int force_text_diff, struct got_diffstat_cb_arg *dsa,
struct got_repository *repo, FILE *outfile)
{
const struct got_error *err;
err = diff_objects_as_trees(lines, nlines, f1, f2, fd1, fd2, id1, id2,
paths, label1, label2, diff_context, ignore_whitespace,
- force_text_diff, show_diffstat, dsa, repo, outfile, diff_algo);
+ force_text_diff, dsa, repo, outfile, diff_algo);
done:
free(idstr);
return err;
struct got_object_id *id1, struct got_object_id *id2,
struct got_pathlist_head *paths, enum got_diff_algorithm diff_algo,
int diff_context, int ignore_whitespace, int force_text_diff,
- int show_diffstat, struct got_diffstat_cb_arg *dsa,
- struct got_repository *repo, FILE *outfile)
+ struct got_diffstat_cb_arg *dsa, struct got_repository *repo, FILE *outfile)
{
const struct got_error *err;
struct got_commit_object *commit1 = NULL, *commit2 = NULL;
err = diff_objects_as_trees(lines, nlines, f1, f2, fd1, fd2,
commit1 ? got_object_commit_get_tree_id(commit1) : NULL,
got_object_commit_get_tree_id(commit2), paths, "", "",
- diff_context, ignore_whitespace, force_text_diff, show_diffstat,
- dsa, repo, outfile, diff_algo);
+ diff_context, ignore_whitespace, force_text_diff, dsa, repo,
+ outfile, diff_algo);
done:
if (commit1)
got_object_commit_close(commit1);
blob - f9d87a6c3b42dbde68bf5e0cea306d6c56ea8538
blob + e7d384ced28a2afa345ba4462240f5a910c9ee0a
--- lib/worktree.c
+++ lib/worktree.c
}
err = got_diff_objects_as_blobs(NULL, NULL, f1, f2,
fd1, fd2, ct->base_blob_id, ct->staged_blob_id,
- label1, label2, GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, 0,
+ label1, label2, GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0,
NULL, repo, diff_outfile);
goto done;
}
err = got_diff_blob_file(blob1, f1, size1, label1,
ondisk_file ? ondisk_file : f2, f2_exists, &sb, ct->path,
- GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, 0, NULL, diff_outfile);
+ GOT_DIFF_ALGORITHM_PATIENCE, 3, 0, 0, NULL, diff_outfile);
done:
if (fd1 != -1 && close(fd1) == -1 && err == NULL)
err = got_error_from_errno("close");
blob - 181370be4b4b57a6312dd3f026ccfc0f8c2f2e65
blob + 18bedc311aae2c5285002daa766c494a456e1ac5
--- tog/tog.c
+++ tog/tog.c
}
static const struct got_error *
-get_changed_paths(struct got_pathlist_head *paths,
- struct got_commit_object *commit, struct got_repository *repo,
- struct got_diffstat_cb_arg *dsa)
-{
- const struct got_error *err = NULL;
- struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL;
- struct got_tree_object *tree1 = NULL, *tree2 = NULL;
- struct got_object_qid *qid;
- FILE *f1 = NULL, *f2 = NULL;
- int fd1 = -1, fd2 = -1;
-
- f1 = got_opentemp();
- if (f1 == NULL) {
- err = got_error_from_errno("got_opentemp");
- goto done;
- }
- f2 = got_opentemp();
- if (f2 == NULL) {
- err = got_error_from_errno("got_opentemp");
- goto done;
- }
-
- fd1 = got_opentempfd();
- if (fd1 == -1) {
- err = got_error_from_errno("got_opentempfd");
- goto done;
- }
- fd2 = got_opentempfd();
- if (fd2 == -1) {
- err = got_error_from_errno("got_opentempfd");
- goto done;
- }
-
- qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
- if (qid != NULL) {
- struct got_commit_object *pcommit;
- err = got_object_open_as_commit(&pcommit, repo,
- &qid->id);
- if (err)
- return err;
-
- tree_id1 = got_object_id_dup(
- got_object_commit_get_tree_id(pcommit));
- if (tree_id1 == NULL) {
- got_object_commit_close(pcommit);
- return got_error_from_errno("got_object_id_dup");
- }
- got_object_commit_close(pcommit);
-
- }
-
- if (tree_id1) {
- err = got_object_open_as_tree(&tree1, repo, tree_id1);
- if (err)
- goto done;
- }
-
- tree_id2 = got_object_commit_get_tree_id(commit);
- err = got_object_open_as_tree(&tree2, repo, tree_id2);
- if (err)
- goto done;
-
- err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo,
- got_diff_tree_compute_diffstat, dsa, 1);
-done:
- if (tree1)
- got_object_tree_close(tree1);
- if (tree2)
- got_object_tree_close(tree2);
- if (fd1 != -1 && close(fd1) == -1 && err == NULL)
- err = got_error_from_errno("close");
- if (fd2 != -1 && close(fd2) == -1 && err == NULL)
- err = got_error_from_errno("close");
- if (f1 && fclose(f1) == EOF && err == NULL)
- err = got_error_from_errno("fclose");
- if (f2 && fclose(f2) == EOF && err == NULL)
- err = got_error_from_errno("fclose");
- free(tree_id1);
- return err;
-}
-
-static const struct got_error *
add_line_metadata(struct got_diff_line **lines, size_t *nlines,
off_t off, uint8_t type)
{
}
static const struct got_error *
+cat_diff(FILE *dst, FILE *src, struct got_diff_line **d_lines, size_t *d_nlines,
+ struct got_diff_line *s_lines, size_t s_nlines)
+{
+ struct got_diff_line *p;
+ char buf[BUFSIZ];
+ size_t i, r;
+
+ if (fseeko(src, 0L, SEEK_SET) == -1)
+ return got_error_from_errno("fseeko");
+
+ for (;;) {
+ r = fread(buf, 1, sizeof(buf), src);
+ if (r == 0) {
+ if (ferror(src))
+ return got_error_from_errno("fread");
+ if (feof(src))
+ break;
+ }
+ if (fwrite(buf, 1, r, dst) != r)
+ return got_ferror(dst, GOT_ERR_IO);
+ }
+
+ /*
+ * The diff driver initialises the first line at offset zero when the
+ * array isn't prepopulated, skip it; we already have it in *d_lines.
+ */
+ for (i = 1; i < s_nlines; ++i)
+ s_lines[i].offset += (*d_lines)[*d_nlines - 1].offset;
+
+ --s_nlines;
+
+ p = reallocarray(*d_lines, *d_nlines + s_nlines, sizeof(*p));
+ if (p == NULL) {
+ /* d_lines is freed in close_diff_view() */
+ return got_error_from_errno("reallocarray");
+ }
+
+ *d_lines = p;
+
+ memcpy(*d_lines + *d_nlines, s_lines + 1, s_nlines * sizeof(*s_lines));
+ *d_nlines += s_nlines;
+
+ return NULL;
+}
+
+static const struct got_error *
write_commit_info(struct got_diff_line **lines, size_t *nlines,
struct got_object_id *commit_id, struct got_reflist_head *refs,
struct got_repository *repo, int ignore_ws, int force_text_diff,
- FILE *outfile)
+ struct got_diffstat_cb_arg *dsa, FILE *outfile)
{
const struct got_error *err = NULL;
char datebuf[26], *datestr;
time_t committer_time;
const char *author, *committer;
char *refs_str = NULL;
- struct got_pathlist_head changed_paths;
struct got_pathlist_entry *pe;
- struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0, &changed_paths,
- ignore_ws, force_text_diff, tog_diff_algo };
off_t outoff = 0;
int n;
- TAILQ_INIT(&changed_paths);
-
if (refs) {
err = build_refs_str(&refs_str, refs, commit_id, repo);
if (err)
goto done;
}
- err = get_changed_paths(&changed_paths, commit, repo, &dsa);
- if (err)
- goto done;
-
- TAILQ_FOREACH(pe, &changed_paths, entry) {
+ TAILQ_FOREACH(pe, dsa->paths, entry) {
struct got_diff_changed_path *cp = pe->data;
- int pad = dsa.max_path_len - pe->path_len + 1;
+ int pad = dsa->max_path_len - pe->path_len + 1;
n = fprintf(outfile, "%c %s%*c | %*d+ %*d-\n", cp->status,
- pe->path, pad, ' ', dsa.add_cols + 1, cp->add,
- dsa.rm_cols + 1, cp->rm);
+ pe->path, pad, ' ', dsa->add_cols + 1, cp->add,
+ dsa->rm_cols + 1, cp->rm);
if (n < 0) {
err = got_error_from_errno("fprintf");
goto done;
n = fprintf(outfile,
"%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n",
- dsa.nfiles, dsa.nfiles > 1 ? "s" : "", dsa.ins,
- dsa.ins != 1 ? "s" : "", dsa.del, dsa.del != 1 ? "s" : "");
+ dsa->nfiles, dsa->nfiles > 1 ? "s" : "", dsa->ins,
+ dsa->ins != 1 ? "s" : "", dsa->del, dsa->del != 1 ? "s" : "");
if (n < 0) {
err = got_error_from_errno("fprintf");
goto done;
outoff++;
err = add_line_metadata(lines, nlines, outoff, GOT_DIFF_LINE_NONE);
done:
- got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL);
free(id_str);
free(logmsg);
free(refs_str);
create_diff(struct tog_diff_view_state *s)
{
const struct got_error *err = NULL;
- FILE *f = NULL;
+ FILE *f = NULL, *tmp_diff_file = NULL;
int obj_type;
+ struct got_diff_line *lines = NULL;
+ struct got_pathlist_head changed_paths;
+ TAILQ_INIT(&changed_paths);
+
free(s->lines);
s->lines = malloc(sizeof(*s->lines));
if (s->lines == NULL)
err = got_error_from_errno("got_opentemp");
goto done;
}
+ tmp_diff_file = got_opentemp();
+ if (tmp_diff_file == NULL) {
+ err = got_error_from_errno("got_opentemp");
+ goto done;
+ }
if (s->f && fclose(s->f) == EOF) {
err = got_error_from_errno("fclose");
goto done;
err = got_diff_objects_as_blobs(&s->lines, &s->nlines,
s->f1, s->f2, s->fd1, s->fd2, s->id1, s->id2,
s->label1, s->label2, tog_diff_algo, s->diff_context,
- s->ignore_whitespace, s->force_text_diff, 0, NULL, s->repo,
+ s->ignore_whitespace, s->force_text_diff, NULL, s->repo,
s->f);
break;
case GOT_OBJ_TYPE_TREE:
err = got_diff_objects_as_trees(&s->lines, &s->nlines,
s->f1, s->f2, s->fd1, s->fd2, s->id1, s->id2, NULL, "", "",
tog_diff_algo, s->diff_context, s->ignore_whitespace,
- s->force_text_diff, 0, NULL, s->repo, s->f);
+ s->force_text_diff, NULL, s->repo, s->f);
break;
case GOT_OBJ_TYPE_COMMIT: {
const struct got_object_id_queue *parent_ids;
struct got_object_qid *pid;
struct got_commit_object *commit2;
struct got_reflist_head *refs;
+ size_t nlines = 0;
+ struct got_diffstat_cb_arg dsa = {
+ 0, 0, 0, 0, 0, 0,
+ &changed_paths,
+ s->ignore_whitespace,
+ s->force_text_diff,
+ tog_diff_algo
+ };
+ lines = malloc(sizeof(*lines));
+ if (lines == NULL) {
+ err = got_error_from_errno("malloc");
+ goto done;
+ }
+
+ /* build diff first in tmp file then append to commit info */
+ err = got_diff_objects_as_commits(&lines, &nlines,
+ s->f1, s->f2, s->fd1, s->fd2, s->id1, s->id2, NULL,
+ tog_diff_algo, s->diff_context, s->ignore_whitespace,
+ s->force_text_diff, &dsa, s->repo, tmp_diff_file);
+ if (err)
+ break;
+
err = got_object_open_as_commit(&commit2, s->repo, s->id2);
if (err)
goto done;
if (s->id1 == NULL) {
err = write_commit_info(&s->lines, &s->nlines, s->id2,
refs, s->repo, s->ignore_whitespace,
- s->force_text_diff, s->f);
+ s->force_text_diff, &dsa, s->f);
if (err)
goto done;
} else {
err = write_commit_info(&s->lines,
&s->nlines, s->id2, refs, s->repo,
s->ignore_whitespace,
- s->force_text_diff, s->f);
+ s->force_text_diff, &dsa, s->f);
if (err)
goto done;
break;
}
got_object_commit_close(commit2);
- err = got_diff_objects_as_commits(&s->lines, &s->nlines,
- s->f1, s->f2, s->fd1, s->fd2, s->id1, s->id2, NULL,
- tog_diff_algo, s->diff_context, s->ignore_whitespace,
- s->force_text_diff, 0, NULL, s->repo, s->f);
+ err = cat_diff(s->f, tmp_diff_file, &s->lines, &s->nlines,
+ lines, nlines);
break;
}
default:
break;
}
done:
+ free(lines);
+ got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL);
if (s->f && fflush(s->f) != 0 && err == NULL)
err = got_error_from_errno("fflush");
+ if (tmp_diff_file && fclose(tmp_diff_file) == EOF && err == NULL)
+ err = got_error_from_errno("fclose");
return err;
}