sequencer: make the todo_list structure public
[gitweb.git] / refs.c
diff --git a/refs.c b/refs.c
index 7820a52c4f4362829a95f73e5899451c486b2c35..f9936355cda6a1515f3192151f7fc14d0c2d7522 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -9,6 +9,7 @@
 #include "iterator.h"
 #include "refs.h"
 #include "refs/refs-internal.h"
+#include "object-store.h"
 #include "object.h"
 #include "tag.h"
 #include "submodule.h"
@@ -188,7 +189,7 @@ int ref_resolves_to_object(const char *refname,
        if (flags & REF_ISBROKEN)
                return 0;
        if (!has_sha1_file(oid->hash)) {
-               error("%s does not point to a valid object!", refname);
+               error(_("%s does not point to a valid object!"), refname);
                return 0;
        }
        return 1;
@@ -216,6 +217,7 @@ char *resolve_refdup(const char *refname, int resolve_flags,
 /* The argument to filter_refs */
 struct ref_filter {
        const char *pattern;
+       const char *prefix;
        each_ref_fn *fn;
        void *cb_data;
 };
@@ -295,6 +297,8 @@ static int filter_refs(const char *refname, const struct object_id *oid,
 
        if (wildmatch(filter->pattern, refname, 0))
                return 0;
+       if (filter->prefix)
+               skip_prefix(refname, filter->prefix, &refname);
        return filter->fn(refname, oid, flags, filter->cb_data);
 }
 
@@ -303,8 +307,8 @@ enum peel_status peel_object(const struct object_id *name, struct object_id *oid
        struct object *o = lookup_unknown_object(name->hash);
 
        if (o->type == OBJ_NONE) {
-               int type = oid_object_info(name, NULL);
-               if (type < 0 || !object_as_type(o, type, 0))
+               int type = oid_object_info(the_repository, name, NULL);
+               if (type < 0 || !object_as_type(the_repository, o, type, 0))
                        return PEEL_INVALID;
        }
 
@@ -457,6 +461,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
        }
 
        filter.pattern = real_pattern.buf;
+       filter.prefix = prefix;
        filter.fn = fn;
        filter.cb_data = cb_data;
        ret = for_each_ref(filter_refs, &filter);
@@ -489,16 +494,24 @@ static const char *ref_rev_parse_rules[] = {
        NULL
 };
 
+#define NUM_REV_PARSE_RULES (ARRAY_SIZE(ref_rev_parse_rules) - 1)
+
+/*
+ * Is it possible that the caller meant full_name with abbrev_name?
+ * If so return a non-zero value to signal "yes"; the magnitude of
+ * the returned value gives the precedence used for disambiguation.
+ *
+ * If abbrev_name cannot mean full_name, return 0.
+ */
 int refname_match(const char *abbrev_name, const char *full_name)
 {
        const char **p;
        const int abbrev_name_len = strlen(abbrev_name);
+       const int num_rules = NUM_REV_PARSE_RULES;
 
-       for (p = ref_rev_parse_rules; *p; p++) {
-               if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {
-                       return 1;
-               }
-       }
+       for (p = ref_rev_parse_rules; *p; p++)
+               if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name)))
+                       return &ref_rev_parse_rules[num_rules] - p;
 
        return 0;
 }
@@ -567,9 +580,9 @@ int expand_ref(const char *str, int len, struct object_id *oid, char **ref)
                        if (!warn_ambiguous_refs)
                                break;
                } else if ((flag & REF_ISSYMREF) && strcmp(fullref.buf, "HEAD")) {
-                       warning("ignoring dangling symref %s.", fullref.buf);
+                       warning(_("ignoring dangling symref %s"), fullref.buf);
                } else if ((flag & REF_ISBROKEN) && strchr(fullref.buf, '/')) {
-                       warning("ignoring broken ref %s.", fullref.buf);
+                       warning(_("ignoring broken ref %s"), fullref.buf);
                }
        }
        strbuf_release(&fullref);
@@ -615,7 +628,9 @@ int dwim_log(const char *str, int len, struct object_id *oid, char **log)
 static int is_per_worktree_ref(const char *refname)
 {
        return !strcmp(refname, "HEAD") ||
-               starts_with(refname, "refs/bisect/");
+               starts_with(refname, "refs/worktree/") ||
+               starts_with(refname, "refs/bisect/") ||
+               starts_with(refname, "refs/rewritten/");
 }
 
 static int is_pseudoref_syntax(const char *refname)
@@ -630,13 +645,34 @@ static int is_pseudoref_syntax(const char *refname)
        return 1;
 }
 
+static int is_main_pseudoref_syntax(const char *refname)
+{
+       return skip_prefix(refname, "main-worktree/", &refname) &&
+               *refname &&
+               is_pseudoref_syntax(refname);
+}
+
+static int is_other_pseudoref_syntax(const char *refname)
+{
+       if (!skip_prefix(refname, "worktrees/", &refname))
+               return 0;
+       refname = strchr(refname, '/');
+       if (!refname || !refname[1])
+               return 0;
+       return is_pseudoref_syntax(refname + 1);
+}
+
 enum ref_type ref_type(const char *refname)
 {
        if (is_per_worktree_ref(refname))
                return REF_TYPE_PER_WORKTREE;
        if (is_pseudoref_syntax(refname))
                return REF_TYPE_PSEUDOREF;
-       return REF_TYPE_NORMAL;
+       if (is_main_pseudoref_syntax(refname))
+               return REF_TYPE_MAIN_PSEUDOREF;
+       if (is_other_pseudoref_syntax(refname))
+               return REF_TYPE_OTHER_PSEUDOREF;
+       return REF_TYPE_NORMAL;
 }
 
 long get_files_ref_lock_timeout_ms(void)
@@ -659,7 +695,7 @@ static int write_pseudoref(const char *pseudoref, const struct object_id *oid,
 {
        const char *filename;
        int fd;
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
        struct strbuf buf = STRBUF_INIT;
        int ret = -1;
 
@@ -669,11 +705,10 @@ static int write_pseudoref(const char *pseudoref, const struct object_id *oid,
        strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
 
        filename = git_path("%s", pseudoref);
-       fd = hold_lock_file_for_update_timeout(&lock, filename,
-                                              LOCK_DIE_ON_ERROR,
+       fd = hold_lock_file_for_update_timeout(&lock, filename, 0,
                                               get_files_ref_lock_timeout_ms());
        if (fd < 0) {
-               strbuf_addf(err, "could not open '%s' for writing: %s",
+               strbuf_addf(err, _("could not open '%s' for writing: %s"),
                            filename, strerror(errno));
                goto done;
        }
@@ -681,10 +716,20 @@ static int write_pseudoref(const char *pseudoref, const struct object_id *oid,
        if (old_oid) {
                struct object_id actual_old_oid;
 
-               if (read_ref(pseudoref, &actual_old_oid))
-                       die("could not read ref '%s'", pseudoref);
-               if (oidcmp(&actual_old_oid, old_oid)) {
-                       strbuf_addf(err, "unexpected object ID when writing '%s'",
+               if (read_ref(pseudoref, &actual_old_oid)) {
+                       if (!is_null_oid(old_oid)) {
+                               strbuf_addf(err, _("could not read ref '%s'"),
+                                           pseudoref);
+                               rollback_lock_file(&lock);
+                               goto done;
+                       }
+               } else if (is_null_oid(old_oid)) {
+                       strbuf_addf(err, _("ref '%s' already exists"),
+                                   pseudoref);
+                       rollback_lock_file(&lock);
+                       goto done;
+               } else if (!oideq(&actual_old_oid, old_oid)) {
+                       strbuf_addf(err, _("unexpected object ID when writing '%s'"),
                                    pseudoref);
                        rollback_lock_file(&lock);
                        goto done;
@@ -692,7 +737,7 @@ static int write_pseudoref(const char *pseudoref, const struct object_id *oid,
        }
 
        if (write_in_full(fd, buf.buf, buf.len) < 0) {
-               strbuf_addf(err, "could not write to '%s'", filename);
+               strbuf_addf(err, _("could not write to '%s'"), filename);
                rollback_lock_file(&lock);
                goto done;
        }
@@ -706,24 +751,27 @@ static int write_pseudoref(const char *pseudoref, const struct object_id *oid,
 
 static int delete_pseudoref(const char *pseudoref, const struct object_id *old_oid)
 {
-       static struct lock_file lock;
        const char *filename;
 
        filename = git_path("%s", pseudoref);
 
        if (old_oid && !is_null_oid(old_oid)) {
+               struct lock_file lock = LOCK_INIT;
                int fd;
                struct object_id actual_old_oid;
 
                fd = hold_lock_file_for_update_timeout(
-                               &lock, filename, LOCK_DIE_ON_ERROR,
+                               &lock, filename, 0,
                                get_files_ref_lock_timeout_ms());
-               if (fd < 0)
-                       die_errno(_("Could not open '%s' for writing"), filename);
+               if (fd < 0) {
+                       error_errno(_("could not open '%s' for writing"),
+                                   filename);
+                       return -1;
+               }
                if (read_ref(pseudoref, &actual_old_oid))
-                       die("could not read ref '%s'", pseudoref);
-               if (oidcmp(&actual_old_oid, old_oid)) {
-                       error("unexpected object ID when deleting '%s'",
+                       die(_("could not read ref '%s'"), pseudoref);
+               if (!oideq(&actual_old_oid, old_oid)) {
+                       error(_("unexpected object ID when deleting '%s'"),
                              pseudoref);
                        rollback_lock_file(&lock);
                        return -1;
@@ -773,25 +821,21 @@ int delete_ref(const char *msg, const char *refname,
                               old_oid, flags);
 }
 
-int copy_reflog_msg(char *buf, const char *msg)
+void copy_reflog_msg(struct strbuf *sb, const char *msg)
 {
-       char *cp = buf;
        char c;
        int wasspace = 1;
 
-       *cp++ = '\t';
+       strbuf_addch(sb, '\t');
        while ((c = *msg++)) {
                if (wasspace && isspace(c))
                        continue;
                wasspace = isspace(c);
                if (wasspace)
                        c = ' ';
-               *cp++ = c;
+               strbuf_addch(sb, c);
        }
-       while (buf < cp && isspace(cp[-1]))
-               cp--;
-       *cp++ = '\n';
-       return cp - buf;
+       strbuf_rtrim(sb);
 }
 
 int should_autocreate_reflog(const char *refname)
@@ -857,14 +901,14 @@ static int read_ref_at_ent(struct object_id *ooid, struct object_id *noid,
                 */
                if (!is_null_oid(&cb->ooid)) {
                        oidcpy(cb->oid, noid);
-                       if (oidcmp(&cb->ooid, noid))
-                               warning("Log for ref %s has gap after %s.",
+                       if (!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)
                        oidcpy(cb->oid, noid);
-               else if (oidcmp(noid, cb->oid))
-                       warning("Log for ref %s unexpectedly ended on %s.",
+               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);
@@ -922,7 +966,7 @@ int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, in
                if (flags & GET_OID_QUIETLY)
                        exit(128);
                else
-                       die("Log for %s is empty.", refname);
+                       die(_("log for %s is empty"), refname);
        }
        if (cb.found_it)
                return 0;
@@ -961,10 +1005,10 @@ void ref_transaction_free(struct ref_transaction *transaction)
                /* OK */
                break;
        case REF_TRANSACTION_PREPARED:
-               die("BUG: free called on a prepared reference transaction");
+               BUG("free called on a prepared reference transaction");
                break;
        default:
-               die("BUG: unexpected reference transaction state");
+               BUG("unexpected reference transaction state");
                break;
        }
 
@@ -986,7 +1030,7 @@ struct ref_update *ref_transaction_add_update(
        struct ref_update *update;
 
        if (transaction->state != REF_TRANSACTION_OPEN)
-               die("BUG: update called for transaction that is not open");
+               BUG("update called for transaction that is not open");
 
        FLEX_ALLOC_STR(update, refname, refname);
        ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);
@@ -1014,7 +1058,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
        if ((new_oid && !is_null_oid(new_oid)) ?
            check_refname_format(refname, REFNAME_ALLOW_ONELEVEL) :
            !refname_is_safe(refname)) {
-               strbuf_addf(err, "refusing to update ref with bad name '%s'",
+               strbuf_addf(err, _("refusing to update ref with bad name '%s'"),
                            refname);
                return -1;
        }
@@ -1036,7 +1080,7 @@ int ref_transaction_create(struct ref_transaction *transaction,
                           struct strbuf *err)
 {
        if (!new_oid || is_null_oid(new_oid))
-               die("BUG: create called without valid new_oid");
+               BUG("create called without valid new_oid");
        return ref_transaction_update(transaction, refname, new_oid,
                                      &null_oid, flags, msg, err);
 }
@@ -1048,7 +1092,7 @@ int ref_transaction_delete(struct ref_transaction *transaction,
                           struct strbuf *err)
 {
        if (old_oid && is_null_oid(old_oid))
-               die("BUG: delete called with old_oid set to zeros");
+               BUG("delete called with old_oid set to zeros");
        return ref_transaction_update(transaction, refname,
                                      &null_oid, old_oid,
                                      flags, msg, err);
@@ -1061,7 +1105,7 @@ int ref_transaction_verify(struct ref_transaction *transaction,
                           struct strbuf *err)
 {
        if (!old_oid)
-               die("BUG: verify called with old_oid set to NULL");
+               BUG("verify called with old_oid set to NULL");
        return ref_transaction_update(transaction, refname,
                                      NULL, old_oid,
                                      flags, NULL, err);
@@ -1090,7 +1134,7 @@ int refs_update_ref(struct ref_store *refs, const char *msg,
                }
        }
        if (ret) {
-               const char *str = "update_ref failed for ref '%s': %s";
+               const char *str = _("update_ref failed for ref '%s': %s");
 
                switch (onerr) {
                case UPDATE_REFS_MSG_ON_ERR:
@@ -1149,8 +1193,8 @@ char *shorten_unambiguous_ref(const char *refname, int strict)
                for (i = 0; i < nr_rules; i++) {
                        assert(offset < total_len);
                        scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;
-                       offset += snprintf(scanf_fmts[i], total_len - offset,
-                                          ref_rev_parse_rules[i], 2, "%s") + 1;
+                       offset += xsnprintf(scanf_fmts[i], total_len - offset,
+                                           ref_rev_parse_rules[i], 2, "%s") + 1;
                }
        }
 
@@ -1376,17 +1420,50 @@ struct ref_iterator *refs_ref_iterator_begin(
  * non-zero value, stop the iteration and return that value;
  * otherwise, return 0.
  */
+static int do_for_each_repo_ref(struct repository *r, const char *prefix,
+                               each_repo_ref_fn fn, int trim, int flags,
+                               void *cb_data)
+{
+       struct ref_iterator *iter;
+       struct ref_store *refs = get_main_ref_store(r);
+
+       if (!refs)
+               return 0;
+
+       iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
+
+       return do_for_each_repo_ref_iterator(r, iter, fn, cb_data);
+}
+
+struct do_for_each_ref_help {
+       each_ref_fn *fn;
+       void *cb_data;
+};
+
+static int do_for_each_ref_helper(struct repository *r,
+                                 const char *refname,
+                                 const struct object_id *oid,
+                                 int flags,
+                                 void *cb_data)
+{
+       struct do_for_each_ref_help *hp = cb_data;
+
+       return hp->fn(refname, oid, flags, hp->cb_data);
+}
+
 static int do_for_each_ref(struct ref_store *refs, const char *prefix,
                           each_ref_fn fn, int trim, int flags, void *cb_data)
 {
        struct ref_iterator *iter;
+       struct do_for_each_ref_help hp = { fn, cb_data };
 
        if (!refs)
                return 0;
 
        iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
 
-       return do_for_each_ref_iterator(iter, fn, cb_data);
+       return do_for_each_repo_ref_iterator(the_repository, iter,
+                                       do_for_each_ref_helper, &hp);
 }
 
 int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
@@ -1431,12 +1508,11 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
        return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data);
 }
 
-int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data)
+int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref(get_main_ref_store(r),
-                              git_replace_ref_base, fn,
-                              strlen(git_replace_ref_base),
-                              DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
+       return do_for_each_repo_ref(r, git_replace_ref_base, fn,
+                                   strlen(git_replace_ref_base),
+                                   DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
 }
 
 int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
@@ -1659,7 +1735,7 @@ static struct ref_store *ref_store_init(const char *gitdir,
        struct ref_store *refs;
 
        if (!be)
-               die("BUG: reference backend %s is unknown", be_name);
+               BUG("reference backend %s is unknown", be_name);
 
        refs = be->init(gitdir, flags);
        return refs;
@@ -1670,6 +1746,9 @@ struct ref_store *get_main_ref_store(struct repository *r)
        if (r->refs)
                return r->refs;
 
+       if (!r->gitdir)
+               BUG("attempting to get main_ref_store outside of repository");
+
        r->refs = ref_store_init(r->gitdir, REF_STORE_ALL_CAPS);
        return r->refs;
 }
@@ -1687,7 +1766,7 @@ static void register_ref_store_map(struct hashmap *map,
                hashmap_init(map, ref_store_hash_cmp, NULL, 0);
 
        if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs)))
-               die("BUG: %s ref_store '%s' initialized twice", type, name);
+               BUG("%s ref_store '%s' initialized twice", type, name);
 }
 
 struct ref_store *get_submodule_ref_store(const char *submodule)
@@ -1829,11 +1908,11 @@ int ref_update_reject_duplicates(struct string_list *refnames,
 
                if (!cmp) {
                        strbuf_addf(err,
-                                   "multiple updates for ref '%s' not allowed.",
+                                   _("multiple updates for ref '%s' not allowed"),
                                    refnames->items[i].string);
                        return 1;
                } else if (cmp > 0) {
-                       die("BUG: ref_update_reject_duplicates() received unsorted list");
+                       BUG("ref_update_reject_duplicates() received unsorted list");
                }
        }
        return 0;
@@ -1849,13 +1928,13 @@ int ref_transaction_prepare(struct ref_transaction *transaction,
                /* Good. */
                break;
        case REF_TRANSACTION_PREPARED:
-               die("BUG: prepare called twice on reference transaction");
+               BUG("prepare called twice on reference transaction");
                break;
        case REF_TRANSACTION_CLOSED:
-               die("BUG: prepare called on a closed reference transaction");
+               BUG("prepare called on a closed reference transaction");
                break;
        default:
-               die("BUG: unexpected reference transaction state");
+               BUG("unexpected reference transaction state");
                break;
        }
 
@@ -1882,10 +1961,10 @@ int ref_transaction_abort(struct ref_transaction *transaction,
                ret = refs->be->transaction_abort(refs, transaction, err);
                break;
        case REF_TRANSACTION_CLOSED:
-               die("BUG: abort called on a closed reference transaction");
+               BUG("abort called on a closed reference transaction");
                break;
        default:
-               die("BUG: unexpected reference transaction state");
+               BUG("unexpected reference transaction state");
                break;
        }
 
@@ -1910,10 +1989,10 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                /* Fall through to finish. */
                break;
        case REF_TRANSACTION_CLOSED:
-               die("BUG: commit called on a closed reference transaction");
+               BUG("commit called on a closed reference transaction");
                break;
        default:
-               die("BUG: unexpected reference transaction state");
+               BUG("unexpected reference transaction state");
                break;
        }
 
@@ -1957,13 +2036,13 @@ int refs_verify_refname_available(struct ref_store *refs,
                        continue;
 
                if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent, &type)) {
-                       strbuf_addf(err, "'%s' exists; cannot create '%s'",
+                       strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
                                    dirname.buf, refname);
                        goto cleanup;
                }
 
                if (extras && string_list_has_string(extras, dirname.buf)) {
-                       strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
+                       strbuf_addf(err, _("cannot process '%s' and '%s' at the same time"),
                                    refname, dirname.buf);
                        goto cleanup;
                }
@@ -1987,18 +2066,18 @@ int refs_verify_refname_available(struct ref_store *refs,
                    string_list_has_string(skip, iter->refname))
                        continue;
 
-               strbuf_addf(err, "'%s' exists; cannot create '%s'",
+               strbuf_addf(err, _("'%s' exists; cannot create '%s'"),
                            iter->refname, refname);
                ref_iterator_abort(iter);
                goto cleanup;
        }
 
        if (ok != ITER_DONE)
-               die("BUG: error while iterating over references");
+               BUG("error while iterating over references");
 
        extra_refname = find_descendant_ref(dirname.buf, extras, skip);
        if (extra_refname)
-               strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
+               strbuf_addf(err, _("cannot process '%s' and '%s' at the same time"),
                            refname, extra_refname);
        else
                ret = 0;
@@ -2012,10 +2091,12 @@ int refs_verify_refname_available(struct ref_store *refs,
 int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data)
 {
        struct ref_iterator *iter;
+       struct do_for_each_ref_help hp = { fn, cb_data };
 
        iter = refs->be->reflog_iterator_begin(refs);
 
-       return do_for_each_ref_iterator(iter, fn, cb_data);
+       return do_for_each_repo_ref_iterator(the_repository, iter,
+                                            do_for_each_ref_helper, &hp);
 }
 
 int for_each_reflog(each_ref_fn fn, void *cb_data)