Skip to content

Commit

Permalink
for-each-ref: add 'is-base' token
Browse files Browse the repository at this point in the history
Signed-off-by: Derrick Stolee <stolee@gmail.com>
  • Loading branch information
derrickstolee committed Jul 3, 2024
1 parent 74c34d6 commit cb26f4f
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
70 changes: 70 additions & 0 deletions ref-filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ enum atom_type {
ATOM_ELSE,
ATOM_REST,
ATOM_AHEADBEHIND,
ATOM_ISBASE,
};

/*
Expand Down Expand Up @@ -891,6 +892,23 @@ static int ahead_behind_atom_parser(struct ref_format *format,
return 0;
}

static int is_base_atom_parser(struct ref_format *format,
struct used_atom *atom UNUSED,
const char *arg, struct strbuf *err)
{
struct string_list_item *item;

if (!arg)
return strbuf_addf_ret(err, -1, _("expected format: %%(is-base:<committish>)"));

item = string_list_append(&format->is_base_tips, 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)
Expand Down Expand Up @@ -956,6 +974,7 @@ static struct {
[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 },
[ATOM_ISBASE] = { "is-base", SOURCE_OTHER, FIELD_STR, is_base_atom_parser },
/*
* Please update $__git_ref_fieldlist in git-completion.bash
* when you add new atoms
Expand Down Expand Up @@ -2340,6 +2359,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
int i;
struct object_info empty = OBJECT_INFO_INIT;
int ahead_behind_atoms = 0;
int is_base_atoms = 0;

CALLOC_ARRAY(ref->value, used_atom_cnt);

Expand Down Expand Up @@ -2483,6 +2503,12 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
v->s = xstrdup("");
}
continue;
} else if (atom_type == ATOM_ISBASE) {
if (ref->is_base && ref->is_base[is_base_atoms++])
v->s = xstrdup("(base)");
else
v->s = xstrdup(""); /* not a commit. */
continue;
} else
continue;

Expand Down Expand Up @@ -2888,6 +2914,7 @@ static void free_array_item(struct ref_array_item *item)
free(item->value);
}
free(item->counts);
free(item->is_base);
free(item);
}

Expand Down Expand Up @@ -3052,6 +3079,48 @@ void filter_ahead_behind(struct repository *r,
free(commits);
}

void filter_is_base(struct repository *r,
struct ref_format *format,
struct ref_array *array)
{
struct commit **bases;
size_t bases_nr = 0;
struct ref_array_item **back_index;

if (!array->nr)
return;

CALLOC_ARRAY(back_index, array->nr);
CALLOC_ARRAY(bases, array->nr);

for (size_t i = 0; i < array->nr; i++) {
const char *name = array->items[i]->refname;
struct commit *c = lookup_commit_reference_by_name(name);

CALLOC_ARRAY(array->items[i]->is_base, format->is_base_tips.nr);

if (!c)
continue;

back_index[bases_nr] = array->items[i];
bases[bases_nr] = c;
bases_nr++;
}

for (size_t i = 0; i < format->is_base_tips.nr; i++) {
struct commit *tip = format->is_base_tips.items[i].util;
int base_index = get_branch_base_for_tip(r, tip, bases, bases_nr);

if (base_index < 0)
continue;

back_index[base_index]->is_base[i] = 1;
}

free(back_index);
free(bases);
}

static int do_filter_refs(struct ref_filter *filter, unsigned int type, each_ref_fn fn, void *cb_data)
{
int ret = 0;
Expand Down Expand Up @@ -3169,6 +3238,7 @@ void filter_and_format_refs(struct ref_filter *filter, unsigned int type,
struct ref_array array = { 0 };
filter_refs(&array, filter, type);
filter_ahead_behind(the_repository, format, &array);
filter_is_base(the_repository, format, &array);
ref_array_sort(sorting, &array);
print_formatted_ref_array(&array, format);
ref_array_clear(&array);
Expand Down
14 changes: 14 additions & 0 deletions ref-filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct ref_array_item {
struct commit *commit;
struct atom_value *value;
struct ahead_behind_count **counts;
int *is_base;

char refname[FLEX_ARRAY];
};
Expand Down Expand Up @@ -101,6 +102,9 @@ struct ref_format {
/* List of bases for ahead-behind counts. */
struct string_list bases;

/* List of bases for is-base indicators. */
struct string_list is_base_tips;

struct {
int max_count;
int omit_empty;
Expand Down Expand Up @@ -203,6 +207,16 @@ void filter_ahead_behind(struct repository *r,
struct ref_format *format,
struct ref_array *array);

/*
* If the provided format includes is-base atoms, then compute the base checks
* for those tips against all refs.
*
* If this is not called, then any is-base atoms will be blank.
*/
void filter_is_base(struct repository *r,
struct ref_format *format,
struct ref_array *array);

void ref_filter_init(struct ref_filter *filter);
void ref_filter_clear(struct ref_filter *filter);

Expand Down
47 changes: 47 additions & 0 deletions t/t6600-test-reach.sh
Original file line number Diff line number Diff line change
Expand Up @@ -659,4 +659,51 @@ test_expect_success 'get_branch_base_for_tip: all reach tip' '
test_all_modes get_branch_base_for_tip
'

test_expect_success 'for-each-ref is-base: none reach' '
cat >input <<-\EOF &&
refs/heads/commit-1-1
refs/heads/commit-4-2
refs/heads/commit-4-4
refs/heads/commit-8-4
EOF
cat >expect <<-\EOF &&
refs/heads/commit-1-1
refs/heads/commit-4-2 (base)
refs/heads/commit-4-4
refs/heads/commit-8-4
EOF
run_all_modes git for-each-ref \
--format="%(refname) %(is-base:commit-2-3)" --stdin
'

test_expect_success 'for-each-ref is-base: all reach' '
cat >input <<-\EOF &&
refs/heads/commit-4-2
refs/heads/commit-5-1
EOF
cat >expect <<-\EOF &&
refs/heads/commit-4-2 (base)
refs/heads/commit-5-1
EOF
run_all_modes git for-each-ref \
--format="%(refname) %(is-base:commit-4-1)" --stdin
'

test_expect_success 'for-each-ref is-base:multiple' '
cat >input <<-\EOF &&
refs/heads/commit-1-1
refs/heads/commit-4-2
refs/heads/commit-4-4
refs/heads/commit-8-4
EOF
cat >expect <<-\EOF &&
refs/heads/commit-1-1 [-]
refs/heads/commit-4-2 [(base)-]
refs/heads/commit-4-4 [-]
refs/heads/commit-8-4 [-(base)]
EOF
run_all_modes git for-each-ref \
--format="%(refname) [%(is-base:commit-2-3)-%(is-base:commit-6-5)]" --stdin
'

test_done

0 comments on commit cb26f4f

Please sign in to comment.