diff options
context:
space:
mode:
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Limit rawdiff to the requested path
The diff and patch pages honour the path in the url, which the parameter table documents for every page, but rawdiff never handed it to git and answered with the whole diff.
-rw-r--r--source/shared.c27
-rw-r--r--source/shared.h5
-rw-r--r--source/ui-diff.c7
-rwxr-xr-xtests/t0108-rawdiff.sh9
4 files changed, 35 insertions, 13 deletions
diff --git a/source/shared.c b/source/shared.c
index 1b610a0..78dc3f4 100644
--- a/source/shared.c
+++ b/source/shared.c
@@ -451,11 +451,24 @@ int cgit_diff_files(const struct object_id *old_oid, const struct object_id *new
return 0;
}
+void cgit_diff_limit_path(struct diff_options *opt, const char *prefix)
+{
+ struct pathspec_item *item;
+
+ item = xcalloc(1, sizeof(*item));
+ item->match = xstrdup(prefix);
+ item->len = strlen(prefix);
+ // nowildcard_len matching len makes git treat the path as literal
+ // rather than as a glob.
+ item->nowildcard_len = item->len;
+ opt->pathspec.nr = 1;
+ opt->pathspec.items = item;
+}
+
void cgit_diff_tree(const struct object_id *old_oid, const struct object_id *new_oid,
filepair_fn fn, const char *prefix, int ignorews)
{
struct diff_options opt;
- struct pathspec_item *item;
repo_diff_setup(the_repository, &opt);
opt.output_format = DIFF_FORMAT_CALLBACK;
@@ -466,16 +479,8 @@ void cgit_diff_tree(const struct object_id *old_oid, const struct object_id *new
DIFF_XDL_SET(&opt, IGNORE_WHITESPACE);
opt.format_callback = cgit_diff_tree_cb;
opt.format_callback_data = fn;
- if (prefix) {
- item = xcalloc(1, sizeof(*item));
- item->match = xstrdup(prefix);
- item->len = strlen(prefix);
- // nowildcard_len matching len makes git treat the path as
- // literal rather than as a glob.
- item->nowildcard_len = item->len;
- opt.pathspec.nr = 1;
- opt.pathspec.items = item;
- }
+ if (prefix)
+ cgit_diff_limit_path(&opt, prefix);
diff_setup_done(&opt);
if (old_oid && !is_null_oid(old_oid))
diff --git a/source/shared.h b/source/shared.h
index 9e39389..d61c1f1 100644
--- a/source/shared.h
+++ b/source/shared.h
@@ -60,6 +60,11 @@ extern int cgit_diff_files(const struct object_id *old_oid, const struct object_
unsigned long *old_size, unsigned long *new_size, int *binary, int context, int ignorews,
linediff_fn fn);
+/*
+ * Limit a diff to the paths below prefix, which is taken literally.
+ */
+extern void cgit_diff_limit_path(struct diff_options *opt, const char *prefix);
+
extern void cgit_diff_tree(const struct object_id *old_oid, const struct object_id *new_oid,
filepair_fn fn, const char *prefix, int ignorews);
extern void cgit_diff_commit(struct commit *commit, filepair_fn fn, const char *prefix);
diff --git a/source/ui-diff.c b/source/ui-diff.c
index 5c9cd1c..a5202b5 100644
--- a/source/ui-diff.c
+++ b/source/ui-diff.c
@@ -535,13 +535,16 @@ static void filepair_cb(struct diff_filepair *pair)
end_file();
}
-static void print_raw_patch(const struct object_id *old_tree_oid, const struct object_id *new_tree_oid)
+static void print_raw_patch(const struct object_id *old_tree_oid, const struct object_id *new_tree_oid,
+ const char *prefix)
{
struct diff_options diffopt;
repo_diff_setup(the_repository, &diffopt);
diffopt.output_format = DIFF_FORMAT_PATCH;
diffopt.flags.recursive = 1;
+ if (prefix)
+ cgit_diff_limit_path(&diffopt, prefix);
diff_setup_done(&diffopt);
ctx.page.mimetype = "text/plain";
@@ -683,7 +686,7 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefi
cap_diffs = !path || prefix_is_dir(old_tree_oid, new_tree_oid, path);
if (raw) {
- print_raw_patch(old_tree_oid, new_tree_oid);
+ print_raw_patch(old_tree_oid, new_tree_oid, path);
return;
}
diff --git a/tests/t0108-rawdiff.sh b/tests/t0108-rawdiff.sh
index 7753bdb..f68628a 100755
--- a/tests/t0108-rawdiff.sh
+++ b/tests/t0108-rawdiff.sh
@@ -46,4 +46,13 @@ test_expect_success 'compare with output of git-diff(1)' '
cmp tmp_ tmp2
'
+test_expect_success 'a path limits the diff to that file' '
+ cgit_query "url=foo/rawdiff/file-4&id=$id&id2=$id2" >tmp &&
+ git --git-dir="$PWD/repos/foo/.git" diff HEAD~3..HEAD -- file-4 >tmp2 &&
+ strip_headers <tmp >tmp_ &&
+ cmp tmp_ tmp2 &&
+ grep "file-4" tmp_ &&
+ ! grep "file-5" tmp_
+'
+
test_done