diff options
Diffstat (limited to 'refs.c')
-rw-r--r-- | refs.c | 194 |
1 files changed, 141 insertions, 53 deletions
@@ -882,51 +882,71 @@ struct read_ref_at_cb { int *cutoff_cnt; }; +static void set_read_ref_cutoffs(struct read_ref_at_cb *cb, + timestamp_t timestamp, int tz, const char *message) +{ + if (cb->msg) + *cb->msg = xstrdup(message); + if (cb->cutoff_time) + *cb->cutoff_time = timestamp; + if (cb->cutoff_tz) + *cb->cutoff_tz = tz; + if (cb->cutoff_cnt) + *cb->cutoff_cnt = cb->reccnt; +} + static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid, const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct read_ref_at_cb *cb = cb_data; + int reached_count; - cb->reccnt++; cb->tz = tz; cb->date = timestamp; - if (timestamp <= cb->at_time || cb->cnt == 0) { - if (cb->msg) - *cb->msg = xstrdup(message); - if (cb->cutoff_time) - *cb->cutoff_time = timestamp; - if (cb->cutoff_tz) - *cb->cutoff_tz = tz; - if (cb->cutoff_cnt) - *cb->cutoff_cnt = cb->reccnt - 1; + /* + * It is not possible for cb->cnt == 0 on the first iteration because + * that special case is handled in read_ref_at(). + */ + if (cb->cnt > 0) + cb->cnt--; + reached_count = cb->cnt == 0 && !is_null_oid(ooid); + if (timestamp <= cb->at_time || reached_count) { + set_read_ref_cutoffs(cb, timestamp, tz, message); /* * we have not yet updated cb->[n|o]oid so they still * hold the values for the previous record. */ - if (!is_null_oid(&cb->ooid)) { - oidcpy(cb->oid, noid); - if (!oideq(&cb->ooid, noid)) - warning(_("log for ref %s has gap after %s"), + if (!is_null_oid(&cb->ooid) && !oideq(&cb->ooid, noid)) + warning(_("log for ref %s has gap after %s"), cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822))); - } - else if (cb->date == cb->at_time) + if (reached_count) + oidcpy(cb->oid, ooid); + else if (!is_null_oid(&cb->ooid) || cb->date == cb->at_time) oidcpy(cb->oid, noid); else if (!oideq(noid, cb->oid)) warning(_("log for ref %s unexpectedly ended on %s"), cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822))); - oidcpy(&cb->ooid, ooid); - oidcpy(&cb->noid, noid); cb->found_it = 1; - return 1; } + cb->reccnt++; oidcpy(&cb->ooid, ooid); oidcpy(&cb->noid, noid); - if (cb->cnt > 0) - cb->cnt--; - return 0; + return cb->found_it; +} + +static int read_ref_at_ent_newest(struct object_id *ooid, struct object_id *noid, + const char *email, timestamp_t timestamp, + int tz, const char *message, void *cb_data) +{ + struct read_ref_at_cb *cb = cb_data; + + set_read_ref_cutoffs(cb, timestamp, tz, message); + oidcpy(cb->oid, noid); + /* We just want the first entry */ + return 1; } static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid, @@ -935,14 +955,7 @@ static int read_ref_at_ent_oldest(struct object_id *ooid, struct object_id *noid { struct read_ref_at_cb *cb = cb_data; - if (cb->msg) - *cb->msg = xstrdup(message); - if (cb->cutoff_time) - *cb->cutoff_time = timestamp; - if (cb->cutoff_tz) - *cb->cutoff_tz = tz; - if (cb->cutoff_cnt) - *cb->cutoff_cnt = cb->reccnt; + set_read_ref_cutoffs(cb, timestamp, tz, message); oidcpy(cb->oid, ooid); if (is_null_oid(cb->oid)) oidcpy(cb->oid, noid); @@ -967,6 +980,11 @@ int read_ref_at(struct ref_store *refs, const char *refname, cb.cutoff_cnt = cutoff_cnt; cb.oid = oid; + if (cb.cnt == 0) { + refs_for_each_reflog_ent_reverse(refs, refname, read_ref_at_ent_newest, &cb); + return 0; + } + refs_for_each_reflog_ent_reverse(refs, refname, read_ref_at_ent, &cb); if (!cb.reccnt) { @@ -1546,6 +1564,93 @@ int for_each_rawref(each_ref_fn fn, void *cb_data) return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data); } +static int qsort_strcmp(const void *va, const void *vb) +{ + const char *a = *(const char **)va; + const char *b = *(const char **)vb; + + return strcmp(a, b); +} + +static void find_longest_prefixes_1(struct string_list *out, + struct strbuf *prefix, + const char **patterns, size_t nr) +{ + size_t i; + + for (i = 0; i < nr; i++) { + char c = patterns[i][prefix->len]; + if (!c || is_glob_special(c)) { + string_list_append(out, prefix->buf); + return; + } + } + + i = 0; + while (i < nr) { + size_t end; + + /* + * Set "end" to the index of the element _after_ the last one + * in our group. + */ + for (end = i + 1; end < nr; end++) { + if (patterns[i][prefix->len] != patterns[end][prefix->len]) + break; + } + + strbuf_addch(prefix, patterns[i][prefix->len]); + find_longest_prefixes_1(out, prefix, patterns + i, end - i); + strbuf_setlen(prefix, prefix->len - 1); + + i = end; + } +} + +static void find_longest_prefixes(struct string_list *out, + const char **patterns) +{ + struct strvec sorted = STRVEC_INIT; + struct strbuf prefix = STRBUF_INIT; + + strvec_pushv(&sorted, patterns); + QSORT(sorted.v, sorted.nr, qsort_strcmp); + + find_longest_prefixes_1(out, &prefix, sorted.v, sorted.nr); + + strvec_clear(&sorted); + strbuf_release(&prefix); +} + +int for_each_fullref_in_prefixes(const char *namespace, + const char **patterns, + each_ref_fn fn, void *cb_data, + unsigned int broken) +{ + struct string_list prefixes = STRING_LIST_INIT_DUP; + struct string_list_item *prefix; + struct strbuf buf = STRBUF_INIT; + int ret = 0, namespace_len; + + find_longest_prefixes(&prefixes, patterns); + + if (namespace) + strbuf_addstr(&buf, namespace); + namespace_len = buf.len; + + for_each_string_list_item(prefix, &prefixes) { + strbuf_addstr(&buf, prefix->string); + ret = for_each_fullref_in(buf.buf, fn, cb_data, broken); + if (ret) + break; + strbuf_setlen(&buf, namespace_len); + } + + string_list_clear(&prefixes, 0); + strbuf_release(&buf); + return ret; +} + static int refs_read_special_head(struct ref_store *ref_store, const char *refname, struct object_id *oid, struct strbuf *referent, unsigned int *type) @@ -1898,31 +2003,14 @@ int refs_pack_refs(struct ref_store *refs, unsigned int flags) return refs->be->pack_refs(refs, flags); } -int refs_peel_ref(struct ref_store *refs, const char *refname, - struct object_id *oid) +int peel_iterated_oid(const struct object_id *base, struct object_id *peeled) { - int flag; - struct object_id base; - - if (current_ref_iter && current_ref_iter->refname == refname) { - struct object_id peeled; - - if (ref_iterator_peel(current_ref_iter, &peeled)) - return -1; - oidcpy(oid, &peeled); - return 0; - } + if (current_ref_iter && + (current_ref_iter->oid == base || + oideq(current_ref_iter->oid, base))) + return ref_iterator_peel(current_ref_iter, peeled); - if (refs_read_ref_full(refs, refname, - RESOLVE_REF_READING, &base, &flag)) - return -1; - - return peel_object(&base, oid); -} - -int peel_ref(const char *refname, struct object_id *oid) -{ - return refs_peel_ref(get_main_ref_store(the_repository), refname, oid); + return peel_object(base, peeled); } int refs_create_symref(struct ref_store *refs, |