refs_verify_refname_available(): implement once for all backends
It turns out that we can now implement `refs_verify_refname_available()` based on the other virtual functions, so there is no need for it to be defined at the backend level. Instead, define it once in `refs.c` and remove the `files_backend` definition. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
parent
e121b9cb5f
commit
b05855b5bc
85
refs.c
85
refs.c
|
@ -5,6 +5,7 @@
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "lockfile.h"
|
#include "lockfile.h"
|
||||||
|
#include "iterator.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
#include "refs/refs-internal.h"
|
#include "refs/refs-internal.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
@ -1658,11 +1659,91 @@ int ref_transaction_commit(struct ref_transaction *transaction,
|
||||||
|
|
||||||
int refs_verify_refname_available(struct ref_store *refs,
|
int refs_verify_refname_available(struct ref_store *refs,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
const struct string_list *extra,
|
const struct string_list *extras,
|
||||||
const struct string_list *skip,
|
const struct string_list *skip,
|
||||||
struct strbuf *err)
|
struct strbuf *err)
|
||||||
{
|
{
|
||||||
return refs->be->verify_refname_available(refs, refname, extra, skip, err);
|
const char *slash;
|
||||||
|
const char *extra_refname;
|
||||||
|
struct strbuf dirname = STRBUF_INIT;
|
||||||
|
struct strbuf referent = STRBUF_INIT;
|
||||||
|
struct object_id oid;
|
||||||
|
unsigned int type;
|
||||||
|
struct ref_iterator *iter;
|
||||||
|
int ok;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For the sake of comments in this function, suppose that
|
||||||
|
* refname is "refs/foo/bar".
|
||||||
|
*/
|
||||||
|
|
||||||
|
assert(err);
|
||||||
|
|
||||||
|
strbuf_grow(&dirname, strlen(refname) + 1);
|
||||||
|
for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
|
||||||
|
/* Expand dirname to the new prefix, not including the trailing slash: */
|
||||||
|
strbuf_add(&dirname, refname + dirname.len, slash - refname - dirname.len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are still at a leading dir of the refname (e.g.,
|
||||||
|
* "refs/foo"; if there is a reference with that name,
|
||||||
|
* it is a conflict, *unless* it is in skip.
|
||||||
|
*/
|
||||||
|
if (skip && string_list_has_string(skip, dirname.buf))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!refs_read_raw_ref(refs, dirname.buf, oid.hash, &referent, &type)) {
|
||||||
|
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",
|
||||||
|
refname, dirname.buf);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are at the leaf of our refname (e.g., "refs/foo/bar").
|
||||||
|
* There is no point in searching for a reference with that
|
||||||
|
* name, because a refname isn't considered to conflict with
|
||||||
|
* itself. But we still need to check for references whose
|
||||||
|
* names are in the "refs/foo/bar/" namespace, because they
|
||||||
|
* *do* conflict.
|
||||||
|
*/
|
||||||
|
strbuf_addstr(&dirname, refname + dirname.len);
|
||||||
|
strbuf_addch(&dirname, '/');
|
||||||
|
|
||||||
|
iter = refs_ref_iterator_begin(refs, dirname.buf, 0,
|
||||||
|
DO_FOR_EACH_INCLUDE_BROKEN);
|
||||||
|
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
|
||||||
|
if (skip &&
|
||||||
|
string_list_has_string(skip, iter->refname))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
extra_refname = find_descendant_ref(dirname.buf, extras, skip);
|
||||||
|
if (extra_refname)
|
||||||
|
strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
|
||||||
|
refname, extra_refname);
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
strbuf_release(&referent);
|
||||||
|
strbuf_release(&dirname);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data)
|
||||||
|
|
2
refs.h
2
refs.h
|
@ -97,7 +97,7 @@ int read_ref(const char *refname, unsigned char *sha1);
|
||||||
|
|
||||||
int refs_verify_refname_available(struct ref_store *refs,
|
int refs_verify_refname_available(struct ref_store *refs,
|
||||||
const char *refname,
|
const char *refname,
|
||||||
const struct string_list *extra,
|
const struct string_list *extras,
|
||||||
const struct string_list *skip,
|
const struct string_list *skip,
|
||||||
struct strbuf *err);
|
struct strbuf *err);
|
||||||
|
|
||||||
|
|
|
@ -1724,10 +1724,9 @@ retry:
|
||||||
goto error_return;
|
goto error_return;
|
||||||
} else if (remove_dir_recursively(&ref_file,
|
} else if (remove_dir_recursively(&ref_file,
|
||||||
REMOVE_DIR_EMPTY_ONLY)) {
|
REMOVE_DIR_EMPTY_ONLY)) {
|
||||||
if (verify_refname_available_dir(
|
if (refs_verify_refname_available(
|
||||||
refname, extras, skip,
|
&refs->base, refname,
|
||||||
get_loose_refs(refs),
|
extras, skip, err)) {
|
||||||
err)) {
|
|
||||||
/*
|
/*
|
||||||
* The error message set by
|
* The error message set by
|
||||||
* verify_refname_available() is OK.
|
* verify_refname_available() is OK.
|
||||||
|
@ -2094,9 +2093,9 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,
|
||||||
*/
|
*/
|
||||||
if (remove_empty_directories(&ref_file)) {
|
if (remove_empty_directories(&ref_file)) {
|
||||||
last_errno = errno;
|
last_errno = errno;
|
||||||
if (!verify_refname_available_dir(
|
if (!refs_verify_refname_available(
|
||||||
refname, extras, skip,
|
&refs->base,
|
||||||
get_loose_refs(refs), err))
|
refname, extras, skip, err))
|
||||||
strbuf_addf(err, "there are still refs under '%s'",
|
strbuf_addf(err, "there are still refs under '%s'",
|
||||||
refname);
|
refname);
|
||||||
goto error_return;
|
goto error_return;
|
||||||
|
@ -2108,9 +2107,8 @@ static struct ref_lock *lock_ref_sha1_basic(struct files_ref_store *refs,
|
||||||
if (!resolved) {
|
if (!resolved) {
|
||||||
last_errno = errno;
|
last_errno = errno;
|
||||||
if (last_errno != ENOTDIR ||
|
if (last_errno != ENOTDIR ||
|
||||||
!verify_refname_available_dir(
|
!refs_verify_refname_available(&refs->base, refname,
|
||||||
refname, extras, skip,
|
extras, skip, err))
|
||||||
get_loose_refs(refs), err))
|
|
||||||
strbuf_addf(err, "unable to resolve reference '%s': %s",
|
strbuf_addf(err, "unable to resolve reference '%s': %s",
|
||||||
refname, strerror(last_errno));
|
refname, strerror(last_errno));
|
||||||
|
|
||||||
|
@ -2606,26 +2604,6 @@ static int rename_tmp_log(struct files_ref_store *refs, const char *newrefname)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int files_verify_refname_available(struct ref_store *ref_store,
|
|
||||||
const char *newname,
|
|
||||||
const struct string_list *extras,
|
|
||||||
const struct string_list *skip,
|
|
||||||
struct strbuf *err)
|
|
||||||
{
|
|
||||||
struct files_ref_store *refs =
|
|
||||||
files_downcast(ref_store, REF_STORE_READ, "verify_refname_available");
|
|
||||||
struct ref_dir *packed_refs = get_packed_refs(refs);
|
|
||||||
struct ref_dir *loose_refs = get_loose_refs(refs);
|
|
||||||
|
|
||||||
if (verify_refname_available_dir(newname, extras, skip,
|
|
||||||
packed_refs, err) ||
|
|
||||||
verify_refname_available_dir(newname, extras, skip,
|
|
||||||
loose_refs, err))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_ref_to_lockfile(struct ref_lock *lock,
|
static int write_ref_to_lockfile(struct ref_lock *lock,
|
||||||
const unsigned char *sha1, struct strbuf *err);
|
const unsigned char *sha1, struct strbuf *err);
|
||||||
static int commit_ref_update(struct files_ref_store *refs,
|
static int commit_ref_update(struct files_ref_store *refs,
|
||||||
|
@ -4288,7 +4266,6 @@ struct ref_storage_be refs_be_files = {
|
||||||
|
|
||||||
files_ref_iterator_begin,
|
files_ref_iterator_begin,
|
||||||
files_read_raw_ref,
|
files_read_raw_ref,
|
||||||
files_verify_refname_available,
|
|
||||||
|
|
||||||
files_reflog_iterator_begin,
|
files_reflog_iterator_begin,
|
||||||
files_for_each_reflog_ent,
|
files_for_each_reflog_ent,
|
||||||
|
|
|
@ -590,12 +590,6 @@ typedef int read_raw_ref_fn(struct ref_store *ref_store,
|
||||||
const char *refname, unsigned char *sha1,
|
const char *refname, unsigned char *sha1,
|
||||||
struct strbuf *referent, unsigned int *type);
|
struct strbuf *referent, unsigned int *type);
|
||||||
|
|
||||||
typedef int verify_refname_available_fn(struct ref_store *ref_store,
|
|
||||||
const char *newname,
|
|
||||||
const struct string_list *extras,
|
|
||||||
const struct string_list *skip,
|
|
||||||
struct strbuf *err);
|
|
||||||
|
|
||||||
struct ref_storage_be {
|
struct ref_storage_be {
|
||||||
struct ref_storage_be *next;
|
struct ref_storage_be *next;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -612,7 +606,6 @@ struct ref_storage_be {
|
||||||
|
|
||||||
ref_iterator_begin_fn *iterator_begin;
|
ref_iterator_begin_fn *iterator_begin;
|
||||||
read_raw_ref_fn *read_raw_ref;
|
read_raw_ref_fn *read_raw_ref;
|
||||||
verify_refname_available_fn *verify_refname_available;
|
|
||||||
|
|
||||||
reflog_iterator_begin_fn *reflog_iterator_begin;
|
reflog_iterator_begin_fn *reflog_iterator_begin;
|
||||||
for_each_reflog_ent_fn *for_each_reflog_ent;
|
for_each_reflog_ent_fn *for_each_reflog_ent;
|
||||||
|
|
Loading…
Reference in New Issue