summaryrefslogtreecommitdiff
path: root/ref-filter.c
diff options
context:
space:
mode:
Diffstat (limited to 'ref-filter.c')
-rw-r--r--ref-filter.c240
1 files changed, 173 insertions, 67 deletions
diff --git a/ref-filter.c b/ref-filter.c
index 914908fac5..4991cd4f7a 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -1,9 +1,15 @@
-#include "builtin.h"
-#include "cache.h"
+#include "git-compat-util.h"
+#include "alloc.h"
+#include "environment.h"
+#include "gettext.h"
+#include "gpg-interface.h"
+#include "hex.h"
#include "parse-options.h"
#include "refs.h"
#include "wildmatch.h"
+#include "object-name.h"
#include "object-store.h"
+#include "oid-array.h"
#include "repository.h"
#include "commit.h"
#include "remote.h"
@@ -13,8 +19,8 @@
#include "ref-filter.h"
#include "revision.h"
#include "utf8.h"
-#include "git-compat-util.h"
#include "version.h"
+#include "versioncmp.h"
#include "trailer.h"
#include "wt-status.h"
#include "commit-slab.h"
@@ -158,6 +164,7 @@ enum atom_type {
ATOM_THEN,
ATOM_ELSE,
ATOM_REST,
+ ATOM_AHEADBEHIND,
};
/*
@@ -228,6 +235,22 @@ static int strbuf_addf_ret(struct strbuf *sb, int ret, const char *fmt, ...)
return ret;
}
+static int err_no_arg(struct strbuf *sb, const char *name)
+{
+ size_t namelen = strchrnul(name, ':') - name;
+ strbuf_addf(sb, _("%%(%.*s) does not take arguments"),
+ (int)namelen, name);
+ return -1;
+}
+
+static int err_bad_arg(struct strbuf *sb, const char *name, const char *arg)
+{
+ size_t namelen = strchrnul(name, ':') - name;
+ strbuf_addf(sb, _("unrecognized %%(%.*s) argument: %s"),
+ (int)namelen, name, arg);
+ return -1;
+}
+
static int color_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *color_value, struct strbuf *err)
{
@@ -262,11 +285,12 @@ static int refname_atom_parser_internal(struct refname_atom *atom, const char *a
if (strtol_i(arg, 10, &atom->rstrip))
return strbuf_addf_ret(err, -1, _("Integer value expected refname:rstrip=%s"), arg);
} else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), name, arg);
+ return err_bad_arg(err, name, arg);
return 0;
}
-static int remote_ref_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int remote_ref_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
struct string_list params = STRING_LIST_INIT_DUP;
@@ -313,11 +337,12 @@ static int remote_ref_atom_parser(struct ref_format *format, struct used_atom *a
return 0;
}
-static int objecttype_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int objecttype_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
- return strbuf_addf_ret(err, -1, _("%%(objecttype) does not take arguments"));
+ return err_no_arg(err, "objecttype");
if (*atom->name == '*')
oi_deref.info.typep = &oi_deref.type;
else
@@ -325,7 +350,8 @@ static int objecttype_atom_parser(struct ref_format *format, struct used_atom *a
return 0;
}
-static int objectsize_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int objectsize_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg) {
@@ -341,15 +367,16 @@ static int objectsize_atom_parser(struct ref_format *format, struct used_atom *a
else
oi.info.disk_sizep = &oi.disk_size;
} else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "objectsize", arg);
+ return err_bad_arg(err, "objectsize", arg);
return 0;
}
-static int deltabase_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int deltabase_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
- return strbuf_addf_ret(err, -1, _("%%(deltabase) does not take arguments"));
+ return err_no_arg(err, "deltabase");
if (*atom->name == '*')
oi_deref.info.delta_base_oid = &oi_deref.delta_base_oid;
else
@@ -357,16 +384,18 @@ static int deltabase_atom_parser(struct ref_format *format, struct used_atom *at
return 0;
}
-static int body_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int body_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
- return strbuf_addf_ret(err, -1, _("%%(body) does not take arguments"));
+ return err_no_arg(err, "body");
atom->u.contents.option = C_BODY_DEP;
return 0;
}
-static int subject_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int subject_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg)
@@ -374,11 +403,12 @@ static int subject_atom_parser(struct ref_format *format, struct used_atom *atom
else if (!strcmp(arg, "sanitize"))
atom->u.contents.option = C_SUB_SANITIZE;
else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "subject", arg);
+ return err_bad_arg(err, "subject", arg);
return 0;
}
-static int trailers_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int trailers_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
atom->u.contents.trailer_opts.no_divider = 1;
@@ -428,23 +458,25 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
if (strtoul_ui(arg, 10, &atom->u.contents.nlines))
return strbuf_addf_ret(err, -1, _("positive value expected contents:lines=%s"), arg);
} else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "contents", arg);
+ return err_bad_arg(err, "contents", arg);
return 0;
}
-static int raw_atom_parser(struct ref_format *format, struct used_atom *atom,
- const char *arg, struct strbuf *err)
+static int raw_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
+ const char *arg, struct strbuf *err)
{
if (!arg)
atom->u.raw_data.option = RAW_BARE;
else if (!strcmp(arg, "size"))
atom->u.raw_data.option = RAW_LENGTH;
else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "raw", arg);
+ return err_bad_arg(err, "raw", arg);
return 0;
}
-static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int oid_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg)
@@ -459,11 +491,12 @@ static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
if (atom->u.oid.length < MINIMUM_ABBREV)
atom->u.oid.length = MINIMUM_ABBREV;
} else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), atom->name, arg);
+ return err_bad_arg(err, atom->name, arg);
return 0;
}
-static int person_email_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int person_email_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg)
@@ -473,11 +506,12 @@ static int person_email_atom_parser(struct ref_format *format, struct used_atom
else if (!strcmp(arg, "localpart"))
atom->u.email_option.option = EO_LOCALPART;
else
- return strbuf_addf_ret(err, -1, _("unrecognized email option: %s"), arg);
+ return err_bad_arg(err, atom->name, arg);
return 0;
}
-static int refname_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int refname_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
return refname_atom_parser_internal(&atom->u.refname, arg, atom->name, err);
@@ -494,7 +528,8 @@ static align_type parse_align_position(const char *s)
return -1;
}
-static int align_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int align_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
struct align *align = &atom->u.align;
@@ -546,7 +581,8 @@ static int align_atom_parser(struct ref_format *format, struct used_atom *atom,
return 0;
}
-static int if_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int if_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (!arg) {
@@ -557,22 +593,41 @@ static int if_atom_parser(struct ref_format *format, struct used_atom *atom,
} else if (skip_prefix(arg, "notequals=", &atom->u.if_then_else.str)) {
atom->u.if_then_else.cmp_status = COMPARE_UNEQUAL;
} else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "if", arg);
+ return err_bad_arg(err, "if", arg);
return 0;
}
-static int rest_atom_parser(struct ref_format *format, struct used_atom *atom,
+static int rest_atom_parser(struct ref_format *format,
+ struct used_atom *atom UNUSED,
const char *arg, struct strbuf *err)
{
if (arg)
- return strbuf_addf_ret(err, -1, _("%%(rest) does not take arguments"));
- format->use_rest = 1;
+ return err_no_arg(err, "rest");
return 0;
}
-static int head_atom_parser(struct ref_format *format, struct used_atom *atom,
- const char *arg, struct strbuf *unused_err)
+static int ahead_behind_atom_parser(struct ref_format *format, struct used_atom *atom,
+ const char *arg, struct strbuf *err)
+{
+ struct string_list_item *item;
+
+ if (!arg)
+ return strbuf_addf_ret(err, -1, _("expected format: %%(ahead-behind:<committish>)"));
+
+ item = string_list_append(&format->bases, arg);
+ item->util = lookup_commit_reference_by_name(arg);
+ if (!item->util)
+ die("failed to find '%s'", arg);
+
+ return 0;
+}
+
+static int head_atom_parser(struct ref_format *format UNUSED,
+ struct used_atom *atom,
+ const char *arg, struct strbuf *err)
{
+ if (arg)
+ return err_no_arg(err, "HEAD");
atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
return 0;
}
@@ -627,6 +682,7 @@ static struct {
[ATOM_THEN] = { "then", SOURCE_NONE },
[ATOM_ELSE] = { "else", SOURCE_NONE },
[ATOM_REST] = { "rest", SOURCE_NONE, FIELD_STR, rest_atom_parser },
+ [ATOM_AHEADBEHIND] = { "ahead-behind", SOURCE_OTHER, FIELD_STR, ahead_behind_atom_parser },
/*
* Please update $__git_ref_fieldlist in git-completion.bash
* when you add new atoms
@@ -773,7 +829,7 @@ static void quote_formatting(struct strbuf *s, const char *str, ssize_t len, int
}
static int append_atom(struct atom_value *v, struct ref_formatting_state *state,
- struct strbuf *unused_err)
+ struct strbuf *err UNUSED)
{
/*
* Quote formatting is only done when the stack has a single
@@ -823,7 +879,7 @@ static void end_align_handler(struct ref_formatting_stack **stack)
}
static int align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
- struct strbuf *unused_err)
+ struct strbuf *err UNUSED)
{
struct ref_formatting_stack *new_stack;
@@ -870,7 +926,7 @@ static void if_then_else_handler(struct ref_formatting_stack **stack)
}
static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
- struct strbuf *unused_err)
+ struct strbuf *err UNUSED)
{
struct ref_formatting_stack *new_stack;
struct if_then_else *if_then_else = xcalloc(1,
@@ -897,7 +953,8 @@ static int is_empty(struct strbuf *buf)
return cur == end;
}
-static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
+static int then_atom_handler(struct atom_value *atomv UNUSED,
+ struct ref_formatting_state *state,
struct strbuf *err)
{
struct ref_formatting_stack *cur = state->stack;
@@ -934,7 +991,8 @@ static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
return 0;
}
-static int else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
+static int else_atom_handler(struct atom_value *atomv UNUSED,
+ struct ref_formatting_state *state,
struct strbuf *err)
{
struct ref_formatting_stack *prev = state->stack;
@@ -955,7 +1013,8 @@ static int else_atom_handler(struct atom_value *atomv, struct ref_formatting_sta
return 0;
}
-static int end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
+static int end_atom_handler(struct atom_value *atomv UNUSED,
+ struct ref_formatting_state *state,
struct strbuf *err)
{
struct ref_formatting_stack *current = state->stack;
@@ -1057,9 +1116,11 @@ static const char *do_grab_oid(const char *field, const struct object_id *oid,
case O_FULL:
return oid_to_hex(oid);
case O_LENGTH:
- return find_unique_abbrev(oid, atom->u.oid.length);
+ return repo_find_unique_abbrev(the_repository, oid,
+ atom->u.oid.length);
case O_SHORT:
- return find_unique_abbrev(oid, DEFAULT_ABBREV);
+ return repo_find_unique_abbrev(the_repository, oid,
+ DEFAULT_ABBREV);
default:
BUG("unknown %%(%s) option", field);
}
@@ -1191,7 +1252,7 @@ static const char *copy_name(const char *buf)
{
const char *cp;
for (cp = buf; *cp && *cp != '\n'; cp++) {
- if (!strncmp(cp, " <", 2))
+ if (starts_with(cp, " <"))
return xmemdupz(buf, cp - buf);
}
return xstrdup("");
@@ -1358,6 +1419,7 @@ static void find_subpos(const char *buf,
/* parse signature first; we might not even have a subject line */
parse_signature(buf, end - buf, &payload, &signature);
+ strbuf_release(&payload);
/* skip past header until we hit empty line */
while (*buf && *buf != '\n') {
@@ -1375,12 +1437,12 @@ static void find_subpos(const char *buf,
/* subject is first non-empty line */
*sub = buf;
/* subject goes to first empty line before signature begins */
- if ((eol = strstr(*sub, "\n\n"))) {
+ if ((eol = strstr(*sub, "\n\n")) ||
+ (eol = strstr(*sub, "\r\n\r\n"))) {
eol = eol < sigstart ? eol : sigstart;
- /* check if message uses CRLF */
- } else if (! (eol = strstr(*sub, "\r\n\r\n"))) {
+ } else {
/* treat whole message as subject */
- eol = strrchr(*sub, '\0');
+ eol = sigstart;
}
buf = eol;
*sublen = buf - *sub;
@@ -1803,7 +1865,7 @@ static void lazy_init_worktree_map(void)
populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
}
-static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+static char *get_worktree_path(const struct ref_array_item *ref)
{
struct hashmap_entry entry, *e;
struct ref_to_worktree_entry *lookup_result;
@@ -1829,6 +1891,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
struct object *obj;
int i;
struct object_info empty = OBJECT_INFO_INIT;
+ int ahead_behind_atoms = 0;
CALLOC_ARRAY(ref->value, used_atom_cnt);
@@ -1862,7 +1925,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
refname = get_refname(atom, ref);
else if (atom_type == ATOM_WORKTREEPATH) {
if (ref->kind == FILTER_REFS_BRANCHES)
- v->s = get_worktree_path(atom, ref);
+ v->s = get_worktree_path(ref);
else
v->s = xstrdup("");
continue;
@@ -1959,6 +2022,16 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
else
v->s = xstrdup("");
continue;
+ } else if (atom_type == ATOM_AHEADBEHIND) {
+ if (ref->counts) {
+ const struct ahead_behind_count *count;
+ count = ref->counts[ahead_behind_atoms++];
+ v->s = xstrfmt("%d %d", count->ahead, count->behind);
+ } else {
+ /* Not a commit. */
+ v->s = xstrdup("");
+ }
+ continue;
} else
continue;
@@ -2128,8 +2201,9 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
return for_each_fullref_in("", cb, cb_data);
}
- return for_each_fullref_in_prefixes(NULL, filter->name_patterns,
- cb, cb_data);
+ return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository),
+ NULL, filter->name_patterns,
+ cb, cb_data);
}
/*
@@ -2308,6 +2382,7 @@ static void free_array_item(struct ref_array_item *item)
free((char *)item->value[i].s);
free(item->value);
}
+ free(item->counts);
free(item);
}
@@ -2336,6 +2411,8 @@ void ref_array_clear(struct ref_array *array)
free_worktrees(ref_to_worktree_map.worktrees);
ref_to_worktree_map.worktrees = NULL;
}
+
+ FREE_AND_NULL(array->counts);
}
#define EXCLUDE_REACHED 0
@@ -2344,33 +2421,22 @@ static void reach_filter(struct ref_array *array,
struct commit_list *check_reachable,
int include_reached)
{
- struct rev_info revs;
int i, old_nr;
struct commit **to_clear;
- struct commit_list *cr;
if (!check_reachable)
return;
CALLOC_ARRAY(to_clear, array->nr);
-
- repo_init_revisions(the_repository, &revs, NULL);
-
for (i = 0; i < array->nr; i++) {
struct ref_array_item *item = array->items[i];
- add_pending_object(&revs, &item->commit->object, item->refname);
to_clear[i] = item->commit;
}
- for (cr = check_reachable; cr; cr = cr->next) {
- struct commit *merge_commit = cr->item;
- merge_commit->object.flags |= UNINTERESTING;
- add_pending_object(&revs, &merge_commit->object, "");
- }
-
- revs.limited = 1;
- if (prepare_revision_walk(&revs))
- die(_("revision walk setup failed"));
+ tips_reachable_from_bases(the_repository,
+ check_reachable,
+ to_clear, array->nr,
+ UNINTERESTING);
old_nr = array->nr;
array->nr = 0;
@@ -2394,10 +2460,50 @@ static void reach_filter(struct ref_array *array,
clear_commit_marks(merge_commit, ALL_REV_FLAGS);
}
- release_revisions(&revs);
free(to_clear);
}
+void filter_ahead_behind(struct repository *r,
+ struct ref_format *format,
+ struct ref_array *array)
+{
+ struct commit **commits;
+ size_t commits_nr = format->bases.nr + array->nr;
+
+ if (!format->bases.nr || !array->nr)
+ return;
+
+ ALLOC_ARRAY(commits, commits_nr);
+ for (size_t i = 0; i < format->bases.nr; i++)
+ commits[i] = format->bases.items[i].util;
+
+ ALLOC_ARRAY(array->counts, st_mult(format->bases.nr, array->nr));
+
+ commits_nr = format->bases.nr;
+ array->counts_nr = 0;
+ for (size_t i = 0; i < array->nr; i++) {
+ const char *name = array->items[i]->refname;
+ commits[commits_nr] = lookup_commit_reference_by_name(name);
+
+ if (!commits[commits_nr])
+ continue;
+
+ CALLOC_ARRAY(array->items[i]->counts, format->bases.nr);
+ for (size_t j = 0; j < format->bases.nr; j++) {
+ struct ahead_behind_count *count;
+ count = &array->counts[array->counts_nr++];
+ count->tip_index = commits_nr;
+ count->base_index = j;
+
+ array->items[i]->counts[j] = count;
+ }
+ commits_nr++;
+ }
+
+ ahead_behind(r, commits, commits_nr, array->counts, array->counts_nr);
+ free(commits);
+}
+
/*
* API for filtering a set of refs. Based on the type of refs the user
* has requested, we iterate through those refs and apply filters
@@ -2745,7 +2851,7 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset)
BUG_ON_OPT_NEG(unset);
- if (get_oid(arg, &oid))
+ if (repo_get_oid(the_repository, arg, &oid))
die(_("malformed object name %s"), arg);
merge_commit = lookup_commit_reference_gently(the_repository, &oid, 0);