23
24
('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
24
25
('merge' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)*
27
28
commit_msg ::= data;
29
file_change ::= file_clr | file_del | file_obm | file_inm;
30
file_change ::= file_clr
30
36
file_clr ::= 'deleteall' lf;
31
37
file_del ::= 'D' sp path_str lf;
38
file_rnm ::= 'R' sp path_str sp path_str lf;
39
file_cpy ::= 'C' sp path_str sp path_str lf;
32
40
file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
33
41
file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
36
44
new_tag ::= 'tag' sp tag_str lf
37
45
'from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf
38
'tagger' sp name '<' email '>' when lf
46
'tagger' sp name '<' email '>' when lf
42
50
reset_branch ::= 'reset' sp ref_str lf
43
51
('from' sp (ref_str | hexsha1 | sha1exp_str | idnum) lf)?
46
54
checkpoint ::= 'checkpoint' lf
57
progress ::= 'progress' sp not_lf* lf
49
60
# note: the first idnum in a stream should be 1 and subsequent
50
61
# idnums should not have gaps between values as this will cause
51
62
# the stream parser to reserve space for the gapped values. An
52
# idnum can be updated in the future to a new object by issuing
63
# idnum can be updated in the future to a new object by issuing
53
64
# a new mark directive with the old idnum.
55
66
mark ::= 'mark' sp idnum lf;
56
67
data ::= (delimited_data | exact_data)
59
70
# note: delim may be any string but must not contain lf.
60
71
# data_line may contain any data but must not be exactly
62
73
delimited_data ::= 'data' sp '<<' delim lf
66
77
# note: declen indicates the length of binary_data in bytes.
67
78
# declen does not include the lf preceeding the binary data.
108
119
hexsha1 ::= # SHA1 in hexadecimal format;
110
121
# note: name and email are UTF8 strings, however name must not
111
# contain '<' or lf and email must not contain any of the
122
# contain '<' or lf and email must not contain any of the
112
123
# following: '<', '>', lf.
114
125
name ::= # valid GIT author/committer name;
115
126
email ::= # valid GIT author/committer email;
116
127
ts ::= # time since the epoch in seconds, ascii base10 notation;
117
128
tz ::= # GIT style timezone;
130
# note: comments may appear anywhere in the input, except
131
# within a data command. Any form of the data command
132
# always escapes the related input from comment processing.
134
# In case it is not clear, the '#' that starts the comment
135
# must be the first character on that the line (an lf have
138
comment ::= '#' not_lf* lf;
139
not_lf ::= # Any byte that is not ASCII newline (LF);
120
142
#include "builtin.h"
312
341
/* Input stream parsing */
313
342
static whenspec_type whenspec = WHENSPEC_RAW;
314
343
static struct strbuf command_buf;
344
static int unread_command_buf;
345
static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};
346
static struct recent_command *cmd_tail = &cmd_hist;
347
static struct recent_command *rc_free;
348
static unsigned int cmd_save = 100;
315
349
static uintmax_t next_mark;
316
350
static struct dbuf new_data;
352
static void write_branch_report(FILE *rpt, struct branch *b)
354
fprintf(rpt, "%s:\n", b->name);
356
fprintf(rpt, " status :");
358
fputs(" active", rpt);
359
if (b->branch_tree.tree)
360
fputs(" loaded", rpt);
361
if (is_null_sha1(b->branch_tree.versions[1].sha1))
362
fputs(" dirty", rpt);
365
fprintf(rpt, " tip commit : %s\n", sha1_to_hex(b->sha1));
366
fprintf(rpt, " old tree : %s\n", sha1_to_hex(b->branch_tree.versions[0].sha1));
367
fprintf(rpt, " cur tree : %s\n", sha1_to_hex(b->branch_tree.versions[1].sha1));
368
fprintf(rpt, " commit clock: %" PRIuMAX "\n", b->last_commit);
370
fputs(" last pack : ", rpt);
371
if (b->pack_id < MAX_PACK_ID)
372
fprintf(rpt, "%u", b->pack_id);
378
static void write_crash_report(const char *err)
380
char *loc = git_path("fast_import_crash_%d", getpid());
381
FILE *rpt = fopen(loc, "w");
384
struct recent_command *rc;
387
error("can't write crash report %s: %s", loc, strerror(errno));
391
fprintf(stderr, "fast-import: dumping crash report to %s\n", loc);
393
fprintf(rpt, "fast-import crash report:\n");
394
fprintf(rpt, " fast-import process: %d\n", getpid());
395
fprintf(rpt, " parent process : %d\n", getppid());
396
fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL));
399
fputs("fatal: ", rpt);
404
fputs("Most Recent Commands Before Crash\n", rpt);
405
fputs("---------------------------------\n", rpt);
406
for (rc = cmd_hist.next; rc != &cmd_hist; rc = rc->next) {
407
if (rc->next == &cmd_hist)
416
fputs("Active Branch LRU\n", rpt);
417
fputs("-----------------\n", rpt);
418
fprintf(rpt, " active_branches = %lu cur, %lu max\n",
420
max_active_branches);
422
fputs(" pos clock name\n", rpt);
423
fputs(" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", rpt);
424
for (b = active_branches, lu = 0; b; b = b->active_next_branch)
425
fprintf(rpt, " %2lu) %6" PRIuMAX" %s\n",
426
++lu, b->last_commit, b->name);
429
fputs("Inactive Branches\n", rpt);
430
fputs("-----------------\n", rpt);
431
for (lu = 0; lu < branch_table_sz; lu++) {
432
for (b = branch_table[lu]; b; b = b->table_next_branch)
433
write_branch_report(rpt, b);
437
fputs("-------------------\n", rpt);
438
fputs("END OF CRASH REPORT\n", rpt);
442
static NORETURN void die_nicely(const char *err, va_list params)
445
char message[2 * PATH_MAX];
447
vsnprintf(message, sizeof(message), err, params);
448
fputs("fatal: ", stderr);
449
fputs(message, stderr);
454
write_crash_report(message);
319
459
static void alloc_objects(unsigned int cnt)
1170
1336
die("Empty path component found in input");
1337
if (!slash1 && !S_ISDIR(mode) && subtree)
1338
die("Non-directories cannot have subtrees");
1172
1340
for (i = 0; i < t->entry_count; i++) {
1173
1341
e = t->entries[i];
1174
1342
if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
1176
if (e->versions[1].mode == mode
1345
&& e->versions[1].mode == mode
1177
1346
&& !hashcmp(e->versions[1].sha1, sha1))
1179
1348
e->versions[1].mode = mode;
1180
1349
hashcpy(e->versions[1].sha1, sha1);
1182
1351
release_tree_content_recursive(e->tree);
1185
1353
hashclr(root->versions[1].sha1);
1430
memcpy(backup_leaf, e, sizeof(*backup_leaf));
1258
1432
release_tree_content_recursive(e->tree);
1261
1434
e->versions[1].mode = 0;
1262
1435
hashclr(e->versions[1].sha1);
1263
1436
hashclr(root->versions[1].sha1);
1440
static int tree_content_get(
1441
struct tree_entry *root,
1443
struct tree_entry *leaf)
1445
struct tree_content *t = root->tree;
1448
struct tree_entry *e;
1450
slash1 = strchr(p, '/');
1456
for (i = 0; i < t->entry_count; i++) {
1458
if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
1460
memcpy(leaf, e, sizeof(*leaf));
1461
if (e->tree && is_null_sha1(e->versions[1].sha1))
1462
leaf->tree = dup_tree_content(e->tree);
1467
if (!S_ISDIR(e->versions[1].mode))
1471
return tree_content_get(e, slash1 + 1, leaf);
1267
1477
static int update_branch(struct branch *b)
1269
1479
static const char *msg = "fast-import";
1378
1588
static void read_next_command(void)
1380
read_line(&command_buf, stdin, '\n');
1591
if (unread_command_buf) {
1592
unread_command_buf = 0;
1593
if (command_buf.eof)
1596
struct recent_command *rc;
1598
command_buf.buf = NULL;
1599
read_line(&command_buf, stdin, '\n');
1600
if (command_buf.eof)
1608
cmd_hist.next = rc->next;
1609
cmd_hist.next->prev = &cmd_hist;
1613
rc->buf = command_buf.buf;
1614
rc->prev = cmd_tail;
1615
rc->next = cmd_hist.prev;
1616
rc->prev->next = rc;
1619
} while (command_buf.buf[0] == '#');
1622
static void skip_optional_lf(void)
1624
int term_char = fgetc(stdin);
1625
if (term_char != '\n' && term_char != EOF)
1626
ungetc(term_char, stdin);
1383
1629
static void cmd_mark(void)
1403
1649
size_t sz = 8192, term_len = command_buf.len - 5 - 2;
1405
1651
buffer = xmalloc(sz);
1652
command_buf.buf = NULL;
1407
read_next_command();
1654
read_line(&command_buf, stdin, '\n');
1408
1655
if (command_buf.eof)
1409
1656
die("EOF in data (terminator '%s' not found)", term);
1410
1657
if (term_len == command_buf.len
1411
1658
&& !strcmp(term, command_buf.buf))
1413
if (sz < (length + command_buf.len)) {
1414
sz = sz * 3 / 2 + 16;
1415
if (sz < (length + command_buf.len))
1416
sz = length + command_buf.len;
1417
buffer = xrealloc(buffer, sz);
1660
ALLOC_GROW(buffer, length + command_buf.len, sz);
1419
1661
memcpy(buffer + length,
1420
1662
command_buf.buf,
1421
1663
command_buf.len - 1);
1645
1885
die("Garbage after path in: %s", command_buf.buf);
1648
tree_content_remove(&b->branch_tree, p);
1888
tree_content_remove(&b->branch_tree, p, NULL);
1892
static void file_change_cr(struct branch *b, int rename)
1897
struct tree_entry leaf;
1899
s = command_buf.buf + 2;
1900
s_uq = unquote_c_style(s, &endp);
1903
die("Missing space after source: %s", command_buf.buf);
1906
endp = strchr(s, ' ');
1908
die("Missing space after source: %s", command_buf.buf);
1909
s_uq = xmalloc(endp - s + 1);
1910
memcpy(s_uq, s, endp - s);
1917
die("Missing dest: %s", command_buf.buf);
1920
d_uq = unquote_c_style(d, &endp);
1923
die("Garbage after dest in: %s", command_buf.buf);
1927
memset(&leaf, 0, sizeof(leaf));
1929
tree_content_remove(&b->branch_tree, s, &leaf);
1931
tree_content_get(&b->branch_tree, s, &leaf);
1932
if (!leaf.versions[1].mode)
1933
die("Path %s not in branch", s);
1934
tree_content_set(&b->branch_tree, d,
1935
leaf.versions[1].sha1,
1936
leaf.versions[1].mode,
1652
1943
static void file_change_deleteall(struct branch *b)
1654
1945
release_tree_content_recursive(b->branch_tree.tree);
1811
2103
/* file_change* */
1813
if (1 == command_buf.len)
1815
else if (!prefixcmp(command_buf.buf, "M "))
2104
while (!command_buf.eof && command_buf.len > 1) {
2105
if (!prefixcmp(command_buf.buf, "M "))
1816
2106
file_change_m(b);
1817
2107
else if (!prefixcmp(command_buf.buf, "D "))
1818
2108
file_change_d(b);
2109
else if (!prefixcmp(command_buf.buf, "R "))
2110
file_change_cr(b, 1);
2111
else if (!prefixcmp(command_buf.buf, "C "))
2112
file_change_cr(b, 0);
1819
2113
else if (!strcmp("deleteall", command_buf.buf))
1820
2114
file_change_deleteall(b);
1822
die("Unsupported file_change: %s", command_buf.buf);
2116
unread_command_buf = 1;
1823
2119
read_next_command();