Merge branch 'kn/update-ref-symref'
"git update-ref --stdin" learned to handle transactional updates of symbolic-refs. * kn/update-ref-symref: update-ref: add support for 'symref-update' command reftable: pick either 'oid' or 'target' for new updates update-ref: add support for 'symref-create' command update-ref: add support for 'symref-delete' command update-ref: add support for 'symref-verify' command refs: specify error for regular refs with `old_target` refs: create and use `ref_update_expects_existing_old_ref()`
This commit is contained in:
@ -76,6 +76,65 @@ static char *parse_refname(const char **next)
|
||||
return strbuf_detach(&ref, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper around parse_refname which skips the next delimiter.
|
||||
*/
|
||||
static char *parse_next_refname(const char **next)
|
||||
{
|
||||
if (line_termination) {
|
||||
/* Without -z, consume SP and use next argument */
|
||||
if (!**next || **next == line_termination)
|
||||
return NULL;
|
||||
if (**next != ' ')
|
||||
die("expected SP but got: %s", *next);
|
||||
} else {
|
||||
/* With -z, read the next NUL-terminated line */
|
||||
if (**next)
|
||||
return NULL;
|
||||
}
|
||||
/* Skip the delimiter */
|
||||
(*next)++;
|
||||
|
||||
return parse_refname(next);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper around parse_arg which skips the next delimiter.
|
||||
*/
|
||||
static char *parse_next_arg(const char **next)
|
||||
{
|
||||
struct strbuf arg = STRBUF_INIT;
|
||||
|
||||
if (line_termination) {
|
||||
/* Without -z, consume SP and use next argument */
|
||||
if (!**next || **next == line_termination)
|
||||
return NULL;
|
||||
if (**next != ' ')
|
||||
die("expected SP but got: %s", *next);
|
||||
} else {
|
||||
/* With -z, read the next NUL-terminated line */
|
||||
if (**next)
|
||||
return NULL;
|
||||
}
|
||||
/* Skip the delimiter */
|
||||
(*next)++;
|
||||
|
||||
if (line_termination) {
|
||||
/* Without -z, use the next argument */
|
||||
*next = parse_arg(*next, &arg);
|
||||
} else {
|
||||
/* With -z, use everything up to the next NUL */
|
||||
strbuf_addstr(&arg, *next);
|
||||
*next += arg.len;
|
||||
}
|
||||
|
||||
if (arg.len)
|
||||
return strbuf_detach(&arg, NULL);
|
||||
|
||||
strbuf_release(&arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The value being parsed is <old-oid> (as opposed to <new-oid>; the
|
||||
* difference affects which error messages are generated):
|
||||
@ -214,6 +273,61 @@ static void parse_cmd_update(struct ref_transaction *transaction,
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
static void parse_cmd_symref_update(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
{
|
||||
char *refname, *new_target, *old_arg;
|
||||
char *old_target = NULL;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
struct object_id old_oid;
|
||||
int have_old_oid = 0;
|
||||
|
||||
refname = parse_refname(&next);
|
||||
if (!refname)
|
||||
die("symref-update: missing <ref>");
|
||||
|
||||
new_target = parse_next_refname(&next);
|
||||
if (!new_target)
|
||||
die("symref-update %s: missing <new-target>", refname);
|
||||
|
||||
old_arg = parse_next_arg(&next);
|
||||
if (old_arg) {
|
||||
old_target = parse_next_arg(&next);
|
||||
if (!old_target)
|
||||
die("symref-update %s: expected old value", refname);
|
||||
|
||||
if (!strcmp(old_arg, "oid")) {
|
||||
if (repo_get_oid(the_repository, old_target, &old_oid))
|
||||
die("symref-update %s: invalid oid: %s", refname, old_target);
|
||||
|
||||
have_old_oid = 1;
|
||||
} else if (!strcmp(old_arg, "ref")) {
|
||||
if (check_refname_format(old_target, REFNAME_ALLOW_ONELEVEL))
|
||||
die("symref-update %s: invalid ref: %s", refname, old_target);
|
||||
} else {
|
||||
die("symref-update %s: invalid arg '%s' for old value", refname, old_arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (*next != line_termination)
|
||||
die("symref-update %s: extra input: %s", refname, next);
|
||||
|
||||
if (ref_transaction_update(transaction, refname, NULL,
|
||||
have_old_oid ? &old_oid : NULL,
|
||||
new_target,
|
||||
have_old_oid ? NULL : old_target,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err))
|
||||
die("%s", err.buf);
|
||||
|
||||
update_flags = default_flags;
|
||||
free(refname);
|
||||
free(old_arg);
|
||||
free(old_target);
|
||||
free(new_target);
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
static void parse_cmd_create(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
{
|
||||
@ -234,7 +348,7 @@ static void parse_cmd_create(struct ref_transaction *transaction,
|
||||
if (*next != line_termination)
|
||||
die("create %s: extra input: %s", refname, next);
|
||||
|
||||
if (ref_transaction_create(transaction, refname, &new_oid,
|
||||
if (ref_transaction_create(transaction, refname, &new_oid, NULL,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err))
|
||||
die("%s", err.buf);
|
||||
@ -244,6 +358,35 @@ static void parse_cmd_create(struct ref_transaction *transaction,
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
|
||||
static void parse_cmd_symref_create(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
char *refname, *new_target;
|
||||
|
||||
refname = parse_refname(&next);
|
||||
if (!refname)
|
||||
die("symref-create: missing <ref>");
|
||||
|
||||
new_target = parse_next_refname(&next);
|
||||
if (!new_target)
|
||||
die("symref-create %s: missing <new-target>", refname);
|
||||
|
||||
if (*next != line_termination)
|
||||
die("symref-create %s: extra input: %s", refname, next);
|
||||
|
||||
if (ref_transaction_create(transaction, refname, NULL, new_target,
|
||||
update_flags | create_reflog_flag,
|
||||
msg, &err))
|
||||
die("%s", err.buf);
|
||||
|
||||
update_flags = default_flags;
|
||||
free(refname);
|
||||
free(new_target);
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
static void parse_cmd_delete(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
{
|
||||
@ -270,7 +413,7 @@ static void parse_cmd_delete(struct ref_transaction *transaction,
|
||||
|
||||
if (ref_transaction_delete(transaction, refname,
|
||||
have_old ? &old_oid : NULL,
|
||||
update_flags, msg, &err))
|
||||
NULL, update_flags, msg, &err))
|
||||
die("%s", err.buf);
|
||||
|
||||
update_flags = default_flags;
|
||||
@ -278,6 +421,36 @@ static void parse_cmd_delete(struct ref_transaction *transaction,
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
|
||||
static void parse_cmd_symref_delete(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
char *refname, *old_target;
|
||||
|
||||
if (!(update_flags & REF_NO_DEREF))
|
||||
die("symref-delete: cannot operate with deref mode");
|
||||
|
||||
refname = parse_refname(&next);
|
||||
if (!refname)
|
||||
die("symref-delete: missing <ref>");
|
||||
|
||||
old_target = parse_next_refname(&next);
|
||||
|
||||
if (*next != line_termination)
|
||||
die("symref-delete %s: extra input: %s", refname, next);
|
||||
|
||||
if (ref_transaction_delete(transaction, refname, NULL,
|
||||
old_target, update_flags, msg, &err))
|
||||
die("%s", err.buf);
|
||||
|
||||
update_flags = default_flags;
|
||||
free(refname);
|
||||
free(old_target);
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
|
||||
static void parse_cmd_verify(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
{
|
||||
@ -297,7 +470,7 @@ static void parse_cmd_verify(struct ref_transaction *transaction,
|
||||
die("verify %s: extra input: %s", refname, next);
|
||||
|
||||
if (ref_transaction_verify(transaction, refname, &old_oid,
|
||||
update_flags, &err))
|
||||
NULL, update_flags, &err))
|
||||
die("%s", err.buf);
|
||||
|
||||
update_flags = default_flags;
|
||||
@ -305,6 +478,42 @@ static void parse_cmd_verify(struct ref_transaction *transaction,
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
static void parse_cmd_symref_verify(struct ref_transaction *transaction,
|
||||
const char *next, const char *end)
|
||||
{
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
struct object_id old_oid;
|
||||
char *refname, *old_target;
|
||||
|
||||
if (!(update_flags & REF_NO_DEREF))
|
||||
die("symref-verify: cannot operate with deref mode");
|
||||
|
||||
refname = parse_refname(&next);
|
||||
if (!refname)
|
||||
die("symref-verify: missing <ref>");
|
||||
|
||||
/*
|
||||
* old_ref is optional, if not provided, we need to ensure that the
|
||||
* ref doesn't exist.
|
||||
*/
|
||||
old_target = parse_next_refname(&next);
|
||||
if (!old_target)
|
||||
oidcpy(&old_oid, null_oid());
|
||||
|
||||
if (*next != line_termination)
|
||||
die("symref-verify %s: extra input: %s", refname, next);
|
||||
|
||||
if (ref_transaction_verify(transaction, refname,
|
||||
old_target ? NULL : &old_oid,
|
||||
old_target, update_flags, &err))
|
||||
die("%s", err.buf);
|
||||
|
||||
update_flags = default_flags;
|
||||
free(refname);
|
||||
free(old_target);
|
||||
strbuf_release(&err);
|
||||
}
|
||||
|
||||
static void report_ok(const char *command)
|
||||
{
|
||||
fprintf(stdout, "%s: ok\n", command);
|
||||
@ -380,15 +589,19 @@ static const struct parse_cmd {
|
||||
unsigned args;
|
||||
enum update_refs_state state;
|
||||
} command[] = {
|
||||
{ "update", parse_cmd_update, 3, UPDATE_REFS_OPEN },
|
||||
{ "create", parse_cmd_create, 2, UPDATE_REFS_OPEN },
|
||||
{ "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN },
|
||||
{ "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN },
|
||||
{ "option", parse_cmd_option, 1, UPDATE_REFS_OPEN },
|
||||
{ "start", parse_cmd_start, 0, UPDATE_REFS_STARTED },
|
||||
{ "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED },
|
||||
{ "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED },
|
||||
{ "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
|
||||
{ "update", parse_cmd_update, 3, UPDATE_REFS_OPEN },
|
||||
{ "create", parse_cmd_create, 2, UPDATE_REFS_OPEN },
|
||||
{ "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN },
|
||||
{ "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN },
|
||||
{ "symref-update", parse_cmd_symref_update, 4, UPDATE_REFS_OPEN },
|
||||
{ "symref-create", parse_cmd_symref_create, 2, UPDATE_REFS_OPEN },
|
||||
{ "symref-delete", parse_cmd_symref_delete, 2, UPDATE_REFS_OPEN },
|
||||
{ "symref-verify", parse_cmd_symref_verify, 2, UPDATE_REFS_OPEN },
|
||||
{ "option", parse_cmd_option, 1, UPDATE_REFS_OPEN },
|
||||
{ "start", parse_cmd_start, 0, UPDATE_REFS_STARTED },
|
||||
{ "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED },
|
||||
{ "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED },
|
||||
{ "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
|
||||
};
|
||||
|
||||
static void update_refs_stdin(void)
|
||||
|
Reference in New Issue
Block a user