Merge branch 'ab/ambiguous-object-name'

Error output given in response to an ambiguous object name has been
improved.

* ab/ambiguous-object-name:
  object-name: re-use "struct strbuf" in show_ambiguous_object()
  object-name: iterate ambiguous objects before showing header
  object-name: show date for ambiguous tag objects
  object-name: make ambiguous object output translatable
  object-name: explicitly handle bad tags in show_ambiguous_object()
  object-name: explicitly handle OBJ_BAD in show_ambiguous_object()
  object-name tests: add tests for ambiguous object blind spots
This commit is contained in:
Junio C Hamano
2022-02-25 15:47:33 -08:00
2 changed files with 190 additions and 12 deletions

View File

@ -351,35 +351,118 @@ static int init_object_disambiguation(struct repository *r,
return 0;
}
struct ambiguous_output {
const struct disambiguate_state *ds;
struct strbuf advice;
struct strbuf sb;
};
static int show_ambiguous_object(const struct object_id *oid, void *data)
{
const struct disambiguate_state *ds = data;
struct strbuf desc = STRBUF_INIT;
struct ambiguous_output *state = data;
const struct disambiguate_state *ds = state->ds;
struct strbuf *advice = &state->advice;
struct strbuf *sb = &state->sb;
int type;
const char *hash;
if (ds->fn && !ds->fn(ds->repo, oid, ds->cb_data))
return 0;
hash = repo_find_unique_abbrev(ds->repo, oid, DEFAULT_ABBREV);
type = oid_object_info(ds->repo, oid, NULL);
if (type < 0) {
/*
* TRANSLATORS: This is a line of ambiguous object
* output shown when we cannot look up or parse the
* object in question. E.g. "deadbeef [bad object]".
*/
strbuf_addf(sb, _("%s [bad object]"), hash);
goto out;
}
assert(type == OBJ_TREE || type == OBJ_COMMIT ||
type == OBJ_BLOB || type == OBJ_TAG);
if (type == OBJ_COMMIT) {
struct strbuf date = STRBUF_INIT;
struct strbuf msg = STRBUF_INIT;
struct commit *commit = lookup_commit(ds->repo, oid);
if (commit) {
struct pretty_print_context pp = {0};
pp.date_mode.type = DATE_SHORT;
format_commit_message(commit, " %ad - %s", &desc, &pp);
format_commit_message(commit, "%ad", &date, &pp);
format_commit_message(commit, "%s", &msg, &pp);
}
/*
* TRANSLATORS: This is a line of ambiguous commit
* object output. E.g.:
*
* "deadbeef commit 2021-01-01 - Some Commit Message"
*/
strbuf_addf(sb, _("%s commit %s - %s"), hash, date.buf,
msg.buf);
strbuf_release(&date);
strbuf_release(&msg);
} else if (type == OBJ_TAG) {
struct tag *tag = lookup_tag(ds->repo, oid);
if (!parse_tag(tag) && tag->tag)
strbuf_addf(&desc, " %s", tag->tag);
if (!parse_tag(tag) && tag->tag) {
/*
* TRANSLATORS: This is a line of ambiguous
* tag object output. E.g.:
*
* "deadbeef tag 2022-01-01 - Some Tag Message"
*
* The second argument is the YYYY-MM-DD found
* in the tag.
*
* The third argument is the "tag" string
* from object.c.
*/
strbuf_addf(sb, _("%s tag %s - %s"), hash,
show_date(tag->date, 0, DATE_MODE(SHORT)),
tag->tag);
} else {
/*
* TRANSLATORS: This is a line of ambiguous
* tag object output where we couldn't parse
* the tag itself. E.g.:
*
* "deadbeef [bad tag, could not parse it]"
*/
strbuf_addf(sb, _("%s [bad tag, could not parse it]"),
hash);
}
} else if (type == OBJ_TREE) {
/*
* TRANSLATORS: This is a line of ambiguous <type>
* object output. E.g. "deadbeef tree".
*/
strbuf_addf(sb, _("%s tree"), hash);
} else if (type == OBJ_BLOB) {
/*
* TRANSLATORS: This is a line of ambiguous <type>
* object output. E.g. "deadbeef blob".
*/
strbuf_addf(sb, _("%s blob"), hash);
}
advise(" %s %s%s",
repo_find_unique_abbrev(ds->repo, oid, DEFAULT_ABBREV),
type_name(type) ? type_name(type) : "unknown type",
desc.buf);
strbuf_release(&desc);
out:
/*
* TRANSLATORS: This is line item of ambiguous object output
* from describe_ambiguous_object() above. For RTL languages
* you'll probably want to swap the "%s" and leading " " space
* around.
*/
strbuf_addf(advice, _(" %s\n"), sb->buf);
strbuf_reset(sb);
return 0;
}
@ -476,6 +559,11 @@ static enum get_oid_result get_short_oid(struct repository *r,
if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {
struct oid_array collect = OID_ARRAY_INIT;
struct ambiguous_output out = {
.ds = &ds,
.sb = STRBUF_INIT,
.advice = STRBUF_INIT,
};
error(_("short object ID %s is ambiguous"), ds.hex_pfx);
@ -488,13 +576,22 @@ static enum get_oid_result get_short_oid(struct repository *r,
if (!ds.ambiguous)
ds.fn = NULL;
advise(_("The candidates are:"));
repo_for_each_abbrev(r, ds.hex_pfx, collect_ambiguous, &collect);
sort_ambiguous_oid_array(r, &collect);
if (oid_array_for_each(&collect, show_ambiguous_object, &ds))
if (oid_array_for_each(&collect, show_ambiguous_object, &out))
BUG("show_ambiguous_object shouldn't return non-zero");
/*
* TRANSLATORS: The argument is the list of ambiguous
* objects composed in show_ambiguous_object(). See
* its "TRANSLATORS" comments for details.
*/
advise(_("The candidates are:\n%s"), out.advice.buf);
oid_array_clear(&collect);
strbuf_release(&out.advice);
strbuf_release(&out.sb);
}
return status;