Diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce 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.
| -rw-r--r-- | source/shared.c | 18 | |
| -rw-r--r-- | source/shared.h | 6 | |
| -rw-r--r-- | source/ui-blame.c | 17 | |
| -rw-r--r-- | source/ui-blob.c | 17 | |
| -rw-r--r-- | source/ui-plain.c | 24 | |
| -rw-r--r-- | source/ui-tree.c | 15 |
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 |
