312
die("option unknown: %s", next);
313
}
314
315
+static void parse_cmd_start(struct ref_transaction *transaction,
316
+ const char *next, const char *end)
317
+{
318
+ if (*next != line_termination)
319
+ die("start: extra input: %s", next);
320
+ puts("start: ok");
321
+}
322
+
323
+static void parse_cmd_prepare(struct ref_transaction *transaction,
324
+ const char *next, const char *end)
325
+{
326
+ struct strbuf error = STRBUF_INIT;
327
+ if (*next != line_termination)
328
+ die("prepare: extra input: %s", next);
329
+ if (ref_transaction_prepare(transaction, &error))
330
+ die("prepare: %s", error.buf);
331
+ puts("prepare: ok");
332
+}
333
+
334
+static void parse_cmd_abort(struct ref_transaction *transaction,
335
+ const char *next, const char *end)
336
+{
337
+ struct strbuf error = STRBUF_INIT;
338
+ if (*next != line_termination)
339
+ die("abort: extra input: %s", next);
340
+ if (ref_transaction_abort(transaction, &error))
341
+ die("abort: %s", error.buf);
342
+ puts("abort: ok");
343
+}
344
+
345
+static void parse_cmd_commit(struct ref_transaction *transaction,
346
+ const char *next, const char *end)
347
+{
348
+ struct strbuf error = STRBUF_INIT;
349
+ if (*next != line_termination)
350
+ die("commit: extra input: %s", next);
351
+ if (ref_transaction_commit(transaction, &error))
352
+ die("commit: %s", error.buf);
353
+ puts("commit: ok");
354
+ ref_transaction_free(transaction);
355
+}
356
+
357
+enum update_refs_state {
358
+ /* Non-transactional state open for updates. */
359
+ UPDATE_REFS_OPEN,
360
+ /* A transaction has been started. */
361
+ UPDATE_REFS_STARTED,
362
+ /* References are locked and ready for commit */
363
+ UPDATE_REFS_PREPARED,
364
+ /* Transaction has been committed or closed. */
365
+ UPDATE_REFS_CLOSED,
366
+};
367
+
368
static const struct parse_cmd {
369
const char *prefix;
370
void (*fn)(struct ref_transaction *, const char *, const char *);
371
unsigned args;
372
+ enum update_refs_state state;
373
} command[] = {
320
- { "update", parse_cmd_update, 3 },
321
- { "create", parse_cmd_create, 2 },
322
- { "delete", parse_cmd_delete, 2 },
323
- { "verify", parse_cmd_verify, 2 },
324
- { "option", parse_cmd_option, 1 },
374
+ { "update", parse_cmd_update, 3, UPDATE_REFS_OPEN },
375
+ { "create", parse_cmd_create, 2, UPDATE_REFS_OPEN },
376
+ { "delete", parse_cmd_delete, 2, UPDATE_REFS_OPEN },
377
+ { "verify", parse_cmd_verify, 2, UPDATE_REFS_OPEN },
378
+ { "option", parse_cmd_option, 1, UPDATE_REFS_OPEN },
379
+ { "start", parse_cmd_start, 0, UPDATE_REFS_STARTED },
380
+ { "prepare", parse_cmd_prepare, 0, UPDATE_REFS_PREPARED },
381
+ { "abort", parse_cmd_abort, 0, UPDATE_REFS_CLOSED },
382
+ { "commit", parse_cmd_commit, 0, UPDATE_REFS_CLOSED },
383
};
384
385
static void update_refs_stdin(void)
386
{
387
struct strbuf input = STRBUF_INIT, err = STRBUF_INIT;
388
+ enum update_refs_state state = UPDATE_REFS_OPEN;
389
struct ref_transaction *transaction;
390
int i, j;
391
433
if (strbuf_appendwholeline(&input, stdin, line_termination))
434
break;
435
436
+ switch (state) {
437
+ case UPDATE_REFS_OPEN:
438
+ case UPDATE_REFS_STARTED:
439
+ /* Do not downgrade a transaction to a non-transaction. */
440
+ if (cmd->state >= state)
441
+ state = cmd->state;
442
+ break;
443
+ case UPDATE_REFS_PREPARED:
444
+ if (cmd->state != UPDATE_REFS_CLOSED)
445
+ die("prepared transactions can only be closed");
446
+ state = cmd->state;
447
+ break;
448
+ case UPDATE_REFS_CLOSED:
449
+ die("transaction is closed");
450
+ break;
451
+ }
452
+
453
cmd->fn(transaction, input.buf + strlen(cmd->prefix) + !!cmd->args,
454
input.buf + input.len);
455
}
456
381
- if (ref_transaction_commit(transaction, &err))
382
- die("%s", err.buf);
457
+ switch (state) {
458
+ case UPDATE_REFS_OPEN:
459
+ /* Commit by default if no transaction was requested. */
460
+ if (ref_transaction_commit(transaction, &err))
461
+ die("%s", err.buf);
462
+ ref_transaction_free(transaction);
463
+ break;
464
+ case UPDATE_REFS_STARTED:
465
+ case UPDATE_REFS_PREPARED:
466
+ /* If using a transaction, we want to abort it. */
467
+ if (ref_transaction_abort(transaction, &err))
468
+ die("%s", err.buf);
469
+ break;
470
+ case UPDATE_REFS_CLOSED:
471
+ /* Otherwise no need to do anything, the transaction was closed already. */
472
+ break;
473
+ }
474
384
- ref_transaction_free(transaction);
475
strbuf_release(&err);
476
strbuf_release(&input);
477
}