Diff options
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Build a literal pathspec in one place
Git's pathspec item holds a const string now, so a path needs no writable copy to be matched.
Diffstat (limited to '')
-rw-r--r--source/shared.c18
-rw-r--r--source/shared.h6
-rw-r--r--source/ui-blame.c17
-rw-r--r--source/ui-blob.c17
-rw-r--r--source/ui-plain.c24
-rw-r--r--source/ui-tree.c15
6 files changed, 35 insertions, 62 deletions
diff --git a/source/shared.c b/source/shared.c
index e075b8a..183d085 100644
--- a/source/shared.c
+++ b/source/shared.c
@@ -394,18 +394,20 @@ int cgit_blob_too_large(size_t size)
return ctx.cfg.max_blob_size && size / 1024 > (size_t)ctx.cfg.max_blob_size;
}
-void cgit_diff_limit_path(struct diff_options *opt, const char *prefix)
+void cgit_literal_pathspec(struct pathspec *ps, struct pathspec_item *item, const char *path)
{
- struct pathspec_item *item;
+ int len = path ? strlen(path) : 0;
- 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;
+ *item = (struct pathspec_item){ .match = path, .len = len, .nowildcard_len = len };
+ ps->nr = path ? 1 : 0;
+ ps->items = item;
+}
+
+void cgit_diff_limit_path(struct diff_options *opt, const char *prefix)
+{
+ cgit_literal_pathspec(&opt->pathspec, xmalloc(sizeof(struct pathspec_item)), xstrdup(prefix));
}
void cgit_diff_tree(const struct object_id *old_oid, const struct object_id *new_oid,
diff --git a/source/shared.h b/source/shared.h
index 09e9296..2633a24 100644
--- a/source/shared.h
+++ b/source/shared.h
@@ -73,6 +73,12 @@ extern int cgit_diff_files(const struct object_id *old_oid, const struct object_
extern int cgit_blob_too_large(size_t size);
/*
+ * Point ps at item alone, set to match path literally rather than as a glob,
+ * or at no item when path is NULL, which leaves every path matching.
+ */
+extern void cgit_literal_pathspec(struct pathspec *ps, struct pathspec_item *item, const char *path);
+
+/*
* 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);
diff --git a/source/ui-blame.c b/source/ui-blame.c
index 28fd16f..7254118 100644
--- a/source/ui-blame.c
+++ b/source/ui-blame.c
@@ -369,18 +369,8 @@ void cgit_print_blame(void)
const char *rev = ctx.qry.oid;
struct object_id oid;
struct commit *commit;
- int path_len = ctx.qry.path ? strlen(ctx.qry.path) : 0;
- // nowildcard_len matches len so git treats the path as literal rather
- // than as a glob, which is what a request naming one file means.
- struct pathspec_item path_items = {
- .match = ctx.qry.path,
- .len = path_len,
- .nowildcard_len = path_len
- };
- struct pathspec paths = {
- .nr = 1,
- .items = &path_items
- };
+ struct pathspec_item path_item;
+ struct pathspec paths = { 0 };
struct walk_tree_context walk = {
.found = TARGET_MISSING
};
@@ -393,7 +383,8 @@ void cgit_print_blame(void)
return;
walk.rev = rev;
- walk.match_baselen = path_items.match ? basedir_len(path_items.match) : -1;
+ walk.match_baselen = ctx.qry.path ? basedir_len(ctx.qry.path) : -1;
+ cgit_literal_pathspec(&paths, &path_item, ctx.qry.path);
read_tree(the_repository, repo_get_commit_tree(the_repository, commit), &paths, walk_tree, &walk);
if (walk.found == TARGET_MISSING)
diff --git a/source/ui-blob.c b/source/ui-blob.c
index bc66509..5118ac2 100644
--- a/source/ui-blob.c
+++ b/source/ui-blob.c
@@ -55,24 +55,14 @@ static int walk_tree(const struct object_id *oid, struct strbuf *base,
/*
* oid comes in naming a commit and goes out naming the blob found at path,
- * which every caller relies on. The path has to be writable because a pathspec
- * item does not hold a const string.
+ * which every caller relies on.
*/
static int find_path_oid(struct object_id *oid, char *path, int file_only)
{
struct commit *commit = lookup_commit_reference(the_repository, oid);
struct tree *tree;
- // nowildcard_len matching len makes git treat the path as literal
- // rather than as a glob.
- struct pathspec_item item = {
- .match = path,
- .len = strlen(path),
- .nowildcard_len = strlen(path)
- };
- struct pathspec paths = {
- .nr = 1,
- .items = &item
- };
+ struct pathspec_item item;
+ struct pathspec paths = { 0 };
struct walk_tree_context walk = {
.match_path = path,
.matched_oid = oid,
@@ -87,6 +77,7 @@ static int find_path_oid(struct object_id *oid, char *path, int file_only)
tree = repo_get_commit_tree(the_repository, commit);
if (!tree)
return 0;
+ cgit_literal_pathspec(&paths, &item, path);
read_tree(the_repository, tree, &paths, walk_tree, &walk);
return walk.found_path;
}
diff --git a/source/ui-plain.c b/source/ui-plain.c
index f97b80c..0d12896 100644
--- a/source/ui-plain.c
+++ b/source/ui-plain.c
@@ -202,19 +202,8 @@ void cgit_print_plain(void)
const char *rev = ctx.qry.oid;
struct object_id oid;
struct commit *commit;
- int path_len = ctx.qry.path ? strlen(ctx.qry.path) : 0;
- // nowildcard_len matches len so git treats the path as literal. As a
- // glob, every entry a pattern like * matches would be answered with
- // its own HTTP headers inside the body of the first.
- struct pathspec_item path_items = {
- .match = ctx.qry.path,
- .len = path_len,
- .nowildcard_len = path_len
- };
- struct pathspec paths = {
- .nr = 1,
- .items = &path_items
- };
+ struct pathspec_item path_item;
+ struct pathspec paths = { 0 };
struct walk_tree_context walk = {
.response = RESPONSE_NONE
};
@@ -231,15 +220,18 @@ void cgit_print_plain(void)
cgit_print_error_page(404, "Not Found", "Not found");
return;
}
- if (!path_items.match) {
+ // The path is taken literally, since as a glob every entry a pattern
+ // like * matches would be answered with its own HTTP headers inside
+ // the body of the first.
+ cgit_literal_pathspec(&paths, &path_item, ctx.qry.path);
+ if (!ctx.qry.path) {
// The walk is never handed an entry for the top of the tree
// itself, so the listing it would have opened is opened here.
- paths.nr = 0;
walk.dir_len = -1;
print_dir("", 0, "");
walk.response = RESPONSE_LISTING;
} else {
- walk.dir_len = dir_prefix_len(path_items.match);
+ walk.dir_len = dir_prefix_len(ctx.qry.path);
}
read_tree(the_repository, repo_get_commit_tree(the_repository, commit), &paths, walk_tree, &walk);
if (walk.response == RESPONSE_NONE)
diff --git a/source/ui-tree.c b/source/ui-tree.c
index 300207f..157aba3 100644
--- a/source/ui-tree.c
+++ b/source/ui-tree.c
@@ -466,18 +466,8 @@ void cgit_print_tree(const char *rev, char *path)
{
struct object_id oid;
struct commit *commit;
- int path_len = path ? strlen(path) : 0;
- // nowildcard_len matches len so git treats the path as literal rather
- // than as a glob.
- struct pathspec_item path_items = {
- .match = path,
- .len = path_len,
- .nowildcard_len = path_len
- };
- struct pathspec paths = {
- .nr = path ? 1 : 0,
- .items = &path_items
- };
+ struct pathspec_item path_item;
+ struct pathspec paths = { 0 };
struct walk_tree_context walk = {
.match_path = path,
.state = WALK_LOOKING
@@ -491,6 +481,7 @@ void cgit_print_tree(const char *rev, char *path)
return;
walk.rev = rev;
+ cgit_literal_pathspec(&paths, &path_item, path);
if (!path) {
// The walk is never handed an entry for the top of the tree