| 1 | #include "test-tool.h" |
| 2 | #include "connect.h" |
| 3 | #include "hex.h" |
| 4 | #include "parse-options.h" |
| 5 | #include "pkt-line.h" |
| 6 | #include "sigchain.h" |
| 7 | #include "string-list.h" |
| 8 | |
| 9 | static const char *const proc_receive_usage[] = { |
| 10 | "test-tool proc-receive [<options>]", |
| 11 | NULL |
| 12 | }; |
| 13 | |
| 14 | static int die_read_version; |
| 15 | static int die_write_version; |
| 16 | static int die_read_commands; |
| 17 | static int die_read_push_options; |
| 18 | static int die_write_report; |
| 19 | static int no_push_options; |
| 20 | static int use_atomic; |
| 21 | static int use_push_options; |
| 22 | static int verbose; |
| 23 | static int version = 1; |
| 24 | static struct string_list returns = STRING_LIST_INIT_NODUP; |
| 25 | |
| 26 | struct command { |
| 27 | struct command *next; |
| 28 | const char *error_string; |
| 29 | unsigned int skip_update:1, |
| 30 | did_not_exist:1; |
| 31 | int index; |
| 32 | struct object_id old_oid; |
| 33 | struct object_id new_oid; |
| 34 | char ref_name[FLEX_ARRAY]; /* more */ |
| 35 | }; |
| 36 | |
| 37 | static void proc_receive_verison(struct packet_reader *reader) { |
| 38 | int server_version = 0; |
| 39 | |
| 40 | if (die_read_version) |
| 41 | die("die with the --die-read-version option"); |
| 42 | |
| 43 | for (;;) { |
| 44 | int linelen; |
| 45 | |
| 46 | if (packet_reader_read(reader) != PACKET_READ_NORMAL) |
| 47 | break; |
| 48 | |
| 49 | /* Ignore version negotiation for version 0 */ |
| 50 | if (version == 0) |
| 51 | continue; |
| 52 | |
| 53 | if (reader->pktlen > 8 && starts_with(reader->line, "version=")) { |
| 54 | server_version = atoi(reader->line+8); |
| 55 | if (server_version != 1) |
| 56 | die("bad protocol version: %d", server_version); |
| 57 | linelen = strlen(reader->line); |
| 58 | if (linelen < reader->pktlen) { |
| 59 | const char *feature_list = reader->line + linelen + 1; |
| 60 | if (parse_feature_request(feature_list, "atomic")) |
| 61 | use_atomic= 1; |
| 62 | if (parse_feature_request(feature_list, "push-options")) |
| 63 | use_push_options = 1; |
| 64 | } |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | if (die_write_version) |
| 69 | die("die with the --die-write-version option"); |
| 70 | |
| 71 | if (version != 0) |
| 72 | packet_write_fmt(1, "version=%d%c%s\n", |
| 73 | version, '\0', |
| 74 | use_push_options && !no_push_options ? "push-options": ""); |
| 75 | packet_flush(1); |
| 76 | } |
| 77 | |
| 78 | static void proc_receive_read_commands(struct packet_reader *reader, |
| 79 | struct command **commands) |
| 80 | { |
| 81 | struct command **tail = commands; |
| 82 | |
| 83 | for (;;) { |
| 84 | struct object_id old_oid, new_oid; |
| 85 | struct command *cmd; |
| 86 | const char *refname; |
| 87 | const char *p; |
| 88 | |
| 89 | if (packet_reader_read(reader) != PACKET_READ_NORMAL) |
| 90 | break; |
| 91 | |
| 92 | if (die_read_commands) |
| 93 | die("die with the --die-read-commands option"); |
| 94 | |
| 95 | if (parse_oid_hex_any(reader->line, &old_oid, &p) == GIT_HASH_UNKNOWN || |
| 96 | *p++ != ' ' || |
| 97 | parse_oid_hex_any(p, &new_oid, &p) == GIT_HASH_UNKNOWN || |
| 98 | *p++ != ' ') |
| 99 | die("protocol error: expected 'old new ref', got '%s'", |
| 100 | reader->line); |
| 101 | refname = p; |
| 102 | FLEX_ALLOC_STR(cmd, ref_name, refname); |
| 103 | oidcpy(&cmd->old_oid, &old_oid); |
| 104 | oidcpy(&cmd->new_oid, &new_oid); |
| 105 | |
| 106 | *tail = cmd; |
| 107 | tail = &cmd->next; |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | static void proc_receive_read_push_options(struct packet_reader *reader, |
| 112 | struct string_list *options) |
| 113 | { |
| 114 | |
| 115 | if (no_push_options || !use_push_options) |
| 116 | return; |
| 117 | |
| 118 | if (die_read_push_options) |
| 119 | die("die with the --die-read-push-options option"); |
| 120 | |
| 121 | while (1) { |
| 122 | if (packet_reader_read(reader) != PACKET_READ_NORMAL) |
| 123 | break; |
| 124 | |
| 125 | string_list_append(options, reader->line); |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | int cmd__proc_receive(int argc, const char **argv) |
| 130 | { |
| 131 | struct packet_reader reader; |
| 132 | struct command *commands = NULL; |
| 133 | struct string_list push_options = STRING_LIST_INIT_DUP; |
| 134 | struct string_list_item *item; |
| 135 | struct option options[] = { |
| 136 | OPT_BOOL(0, "no-push-options", &no_push_options, |
| 137 | "disable push options"), |
| 138 | OPT_BOOL(0, "die-read-version", &die_read_version, |
| 139 | "die when reading version"), |
| 140 | OPT_BOOL(0, "die-write-version", &die_write_version, |
| 141 | "die when writing version"), |
| 142 | OPT_BOOL(0, "die-read-commands", &die_read_commands, |
| 143 | "die when reading commands"), |
| 144 | OPT_BOOL(0, "die-read-push-options", &die_read_push_options, |
| 145 | "die when reading push-options"), |
| 146 | OPT_BOOL(0, "die-write-report", &die_write_report, |
| 147 | "die when writing report"), |
| 148 | OPT_STRING_LIST('r', "return", &returns, "old/new/ref/status/msg", |
| 149 | "return of results"), |
| 150 | OPT__VERBOSE(&verbose, "be verbose"), |
| 151 | OPT_INTEGER('V', "version", &version, |
| 152 | "use this protocol version number"), |
| 153 | OPT_END() |
| 154 | }; |
| 155 | |
| 156 | argc = parse_options(argc, argv, "test-tools", options, proc_receive_usage, 0); |
| 157 | if (argc > 0) |
| 158 | usage_msg_opt("Too many arguments.", proc_receive_usage, options); |
| 159 | packet_reader_init(&reader, 0, NULL, 0, |
| 160 | PACKET_READ_CHOMP_NEWLINE | |
| 161 | PACKET_READ_GENTLE_ON_EOF); |
| 162 | |
| 163 | sigchain_push(SIGPIPE, SIG_IGN); |
| 164 | proc_receive_verison(&reader); |
| 165 | proc_receive_read_commands(&reader, &commands); |
| 166 | proc_receive_read_push_options(&reader, &push_options); |
| 167 | |
| 168 | if (verbose) { |
| 169 | struct command *cmd; |
| 170 | |
| 171 | if (use_push_options || use_atomic) |
| 172 | fprintf(stderr, "proc-receive:%s%s\n", |
| 173 | use_atomic? " atomic": "", |
| 174 | use_push_options ? " push_options": ""); |
| 175 | |
| 176 | for (cmd = commands; cmd; cmd = cmd->next) |
| 177 | fprintf(stderr, "proc-receive< %s %s %s\n", |
| 178 | oid_to_hex(&cmd->old_oid), |
| 179 | oid_to_hex(&cmd->new_oid), |
| 180 | cmd->ref_name); |
| 181 | |
| 182 | if (push_options.nr > 0) |
| 183 | for_each_string_list_item(item, &push_options) |
| 184 | fprintf(stderr, "proc-receive< %s\n", item->string); |
| 185 | |
| 186 | if (returns.nr) |
| 187 | for_each_string_list_item(item, &returns) |
| 188 | fprintf(stderr, "proc-receive> %s\n", item->string); |
| 189 | } |
| 190 | |
| 191 | if (die_write_report) |
| 192 | die("die with the --die-write-report option"); |
| 193 | if (returns.nr) |
| 194 | for_each_string_list_item(item, &returns) |
| 195 | packet_write_fmt(1, "%s\n", item->string); |
| 196 | packet_flush(1); |
| 197 | sigchain_pop(SIGPIPE); |
| 198 | |
| 199 | while (commands) { |
| 200 | struct command *next = commands->next; |
| 201 | free(commands); |
| 202 | commands = next; |
| 203 | } |
| 204 | string_list_clear(&push_options, 0); |
| 205 | |
| 206 | return 0; |
| 207 | } |