Refactor handling of error_string in receive-pack

I discovered we did not send an ng line in the report-status feedback
if the ref was not updated because the repository has the config
option receive.denyNonFastForwards enabled.  I think the reason this
happened is that it is simply too easy to forget to set error_string
when returning back a failure from update()

We now return an ng line for a non-fastforward update, which in
turn will cause send-pack to exit with a non-zero exit status.
Hence the modified test.

This refactoring changes update to return a const char* describing
the error, which execute_commands always loads into error_string.
The result is what I think is cleaner code, and allows us to
initialize the error_string member to NULL when we read_head_info.

I want error_string to be NULL in all commands before we call
execute_commands, so that we can reuse the run_hook function to
execute a new pre-receive hook.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Shawn O. Pearce 2007-03-07 16:51:59 -05:00 committed by Junio C Hamano
parent c8dd277109
commit 8aaf7d6410
2 changed files with 36 additions and 32 deletions

View File

@ -127,24 +127,22 @@ static int run_hook(const char *hook_name,
} }
} }
static int update(struct command *cmd) static const char *update(struct command *cmd)
{ {
const char *name = cmd->ref_name; const char *name = cmd->ref_name;
unsigned char *old_sha1 = cmd->old_sha1; unsigned char *old_sha1 = cmd->old_sha1;
unsigned char *new_sha1 = cmd->new_sha1; unsigned char *new_sha1 = cmd->new_sha1;
struct ref_lock *lock; struct ref_lock *lock;
cmd->error_string = NULL;
if (!prefixcmp(name, "refs/") && check_ref_format(name + 5)) { if (!prefixcmp(name, "refs/") && check_ref_format(name + 5)) {
cmd->error_string = "funny refname"; error("refusing to create funny ref '%s' locally", name);
return error("refusing to create funny ref '%s' locally", return "funny refname";
name);
} }
if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) { if (!is_null_sha1(new_sha1) && !has_sha1_file(new_sha1)) {
cmd->error_string = "bad pack"; error("unpack should have generated %s, "
return error("unpack should have generated %s, " "but I can't find it!", sha1_to_hex(new_sha1));
"but I can't find it!", sha1_to_hex(new_sha1)); return "bad pack";
} }
if (deny_non_fast_forwards && !is_null_sha1(new_sha1) && if (deny_non_fast_forwards && !is_null_sha1(new_sha1) &&
!is_null_sha1(old_sha1) && !is_null_sha1(old_sha1) &&
@ -159,37 +157,39 @@ static int update(struct command *cmd)
if (!hashcmp(old_sha1, ent->item->object.sha1)) if (!hashcmp(old_sha1, ent->item->object.sha1))
break; break;
free_commit_list(bases); free_commit_list(bases);
if (!ent) if (!ent) {
return error("denying non-fast forward;" error("denying non-fast forward %s"
" you should pull first"); " (you should pull first)", name);
return "non-fast forward";
}
} }
if (run_hook(update_hook, cmd, 1)) { if (run_hook(update_hook, cmd, 1)) {
cmd->error_string = "hook declined"; error("hook declined to update %s", name);
return error("hook declined to update %s", name); return "hook declined";
} }
if (is_null_sha1(new_sha1)) { if (is_null_sha1(new_sha1)) {
if (delete_ref(name, old_sha1)) { if (delete_ref(name, old_sha1)) {
cmd->error_string = "failed to delete"; error("failed to delete %s", name);
return error("failed to delete %s", name); return "failed to delete";
} }
fprintf(stderr, "%s: %s -> deleted\n", name, fprintf(stderr, "%s: %s -> deleted\n", name,
sha1_to_hex(old_sha1)); sha1_to_hex(old_sha1));
return NULL; /* good */
} }
else { else {
lock = lock_any_ref_for_update(name, old_sha1); lock = lock_any_ref_for_update(name, old_sha1);
if (!lock) { if (!lock) {
cmd->error_string = "failed to lock"; error("failed to lock %s", name);
return error("failed to lock %s", name); return "failed to lock";
} }
if (write_ref_sha1(lock, new_sha1, "push")) { if (write_ref_sha1(lock, new_sha1, "push")) {
cmd->error_string = "failed to write"; return "failed to write"; /* error() already called */
return -1; /* error() already called */
} }
fprintf(stderr, "%s: %s -> %s\n", name, fprintf(stderr, "%s: %s -> %s\n", name,
sha1_to_hex(old_sha1), sha1_to_hex(new_sha1)); sha1_to_hex(old_sha1), sha1_to_hex(new_sha1));
return NULL; /* good */
} }
return 0;
} }
static char update_post_hook[] = "hooks/post-update"; static char update_post_hook[] = "hooks/post-update";
@ -224,15 +224,20 @@ static void run_update_post_hook(struct command *cmd)
| RUN_COMMAND_STDOUT_TO_STDERR); | RUN_COMMAND_STDOUT_TO_STDERR);
} }
/* static void execute_commands(const char *unpacker_error)
* This gets called after(if) we've successfully
* unpacked the data payload.
*/
static void execute_commands(void)
{ {
struct command *cmd = commands; struct command *cmd = commands;
if (unpacker_error) {
while (cmd) {
cmd->error_string = "n/a (unpacker error)";
cmd = cmd->next;
}
return;
}
while (cmd) { while (cmd) {
update(cmd); cmd->error_string = update(cmd);
cmd = cmd->next; cmd = cmd->next;
} }
} }
@ -270,7 +275,7 @@ static void read_head_info(void)
hashcpy(cmd->old_sha1, old_sha1); hashcpy(cmd->old_sha1, old_sha1);
hashcpy(cmd->new_sha1, new_sha1); hashcpy(cmd->new_sha1, new_sha1);
memcpy(cmd->ref_name, line + 82, len - 81); memcpy(cmd->ref_name, line + 82, len - 81);
cmd->error_string = "n/a (unpacker error)"; cmd->error_string = NULL;
cmd->next = NULL; cmd->next = NULL;
*p = cmd; *p = cmd;
p = &cmd->next; p = &cmd->next;
@ -473,8 +478,7 @@ int main(int argc, char **argv)
if (!delete_only(commands)) if (!delete_only(commands))
unpack_status = unpack(); unpack_status = unpack();
if (!unpack_status) execute_commands(unpack_status);
execute_commands();
if (pack_lockfile) if (pack_lockfile)
unlink(pack_lockfile); unlink(pack_lockfile);
if (report_status) if (report_status)

View File

@ -108,9 +108,9 @@ test_expect_success \
cd victim && cd victim &&
git-config receive.denyNonFastforwards true && git-config receive.denyNonFastforwards true &&
cd .. && cd .. &&
git-update-ref refs/heads/master master^ && git-update-ref refs/heads/master master^ || return 1
git-send-pack --force ./victim/.git/ master && git-send-pack --force ./victim/.git/ master && return 1
! diff -u .git/refs/heads/master victim/.git/refs/heads/master ! diff .git/refs/heads/master victim/.git/refs/heads/master
' '
test_done test_done