Grammar fixes for gitattributes documentation
[gitweb.git] / fast-import.c
index 429ab491bd3dc6d084c7301ec4fc2bb5afa3ed04..5e83296bf49f9b41b019185539cbd4ec1bf94513 100644 (file)
@@ -154,13 +154,16 @@ Format of STDIN stream:
 
 #define PACK_ID_BITS 16
 #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
+#define DEPTH_BITS 13
+#define MAX_DEPTH ((1<<DEPTH_BITS)-1)
 
 struct object_entry
 {
        struct object_entry *next;
        uint32_t offset;
-       unsigned type : TYPE_BITS;
-       unsigned pack_id : PACK_ID_BITS;
+       uint32_t type : TYPE_BITS,
+               pack_id : PACK_ID_BITS,
+               depth : DEPTH_BITS;
        unsigned char sha1[20];
 };
 
@@ -269,6 +272,13 @@ typedef enum {
        WHENSPEC_NOW,
 } whenspec_type;
 
+struct recent_command
+{
+       struct recent_command *prev;
+       struct recent_command *next;
+       char *buf;
+};
+
 /* Configured limits on output */
 static unsigned long max_depth = 10;
 static off_t max_packsize = (1LL << 32) - 1;
@@ -335,9 +345,119 @@ static struct tag *last_tag;
 static whenspec_type whenspec = WHENSPEC_RAW;
 static struct strbuf command_buf;
 static int unread_command_buf;
+static struct recent_command cmd_hist = {&cmd_hist, &cmd_hist, NULL};
+static struct recent_command *cmd_tail = &cmd_hist;
+static struct recent_command *rc_free;
+static unsigned int cmd_save = 100;
 static uintmax_t next_mark;
 static struct dbuf new_data;
 
+static void write_branch_report(FILE *rpt, struct branch *b)
+{
+       fprintf(rpt, "%s:\n", b->name);
+
+       fprintf(rpt, "  status      :");
+       if (b->active)
+               fputs(" active", rpt);
+       if (b->branch_tree.tree)
+               fputs(" loaded", rpt);
+       if (is_null_sha1(b->branch_tree.versions[1].sha1))
+               fputs(" dirty", rpt);
+       fputc('\n', rpt);
+
+       fprintf(rpt, "  tip commit  : %s\n", sha1_to_hex(b->sha1));
+       fprintf(rpt, "  old tree    : %s\n", sha1_to_hex(b->branch_tree.versions[0].sha1));
+       fprintf(rpt, "  cur tree    : %s\n", sha1_to_hex(b->branch_tree.versions[1].sha1));
+       fprintf(rpt, "  commit clock: %" PRIuMAX "\n", b->last_commit);
+
+       fputs("  last pack   : ", rpt);
+       if (b->pack_id < MAX_PACK_ID)
+               fprintf(rpt, "%u", b->pack_id);
+       fputc('\n', rpt);
+
+       fputc('\n', rpt);
+}
+
+static void write_crash_report(const char *err)
+{
+       char *loc = git_path("fast_import_crash_%d", getpid());
+       FILE *rpt = fopen(loc, "w");
+       struct branch *b;
+       unsigned long lu;
+       struct recent_command *rc;
+
+       if (!rpt) {
+               error("can't write crash report %s: %s", loc, strerror(errno));
+               return;
+       }
+
+       fprintf(stderr, "fast-import: dumping crash report to %s\n", loc);
+
+       fprintf(rpt, "fast-import crash report:\n");
+       fprintf(rpt, "    fast-import process: %d\n", getpid());
+       fprintf(rpt, "    parent process     : %d\n", getppid());
+       fprintf(rpt, "    at %s\n", show_date(time(NULL), 0, DATE_LOCAL));
+       fputc('\n', rpt);
+
+       fputs("fatal: ", rpt);
+       fputs(err, rpt);
+       fputc('\n', rpt);
+
+       fputc('\n', rpt);
+       fputs("Most Recent Commands Before Crash\n", rpt);
+       fputs("---------------------------------\n", rpt);
+       for (rc = cmd_hist.next; rc != &cmd_hist; rc = rc->next) {
+               if (rc->next == &cmd_hist)
+                       fputs("* ", rpt);
+               else
+                       fputs("  ", rpt);
+               fputs(rc->buf, rpt);
+               fputc('\n', rpt);
+       }
+
+       fputc('\n', rpt);
+       fputs("Active Branch LRU\n", rpt);
+       fputs("-----------------\n", rpt);
+       fprintf(rpt, "    active_branches = %lu cur, %lu max\n",
+               cur_active_branches,
+               max_active_branches);
+       fputc('\n', rpt);
+       fputs("  pos  clock name\n", rpt);
+       fputs("  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", rpt);
+       for (b = active_branches, lu = 0; b; b = b->active_next_branch)
+               fprintf(rpt, "  %2lu) %6" PRIuMAX" %s\n",
+                       ++lu, b->last_commit, b->name);
+
+       fputc('\n', rpt);
+       fputs("Inactive Branches\n", rpt);
+       fputs("-----------------\n", rpt);
+       for (lu = 0; lu < branch_table_sz; lu++) {
+               for (b = branch_table[lu]; b; b = b->table_next_branch)
+                       write_branch_report(rpt, b);
+       }
+
+       fputc('\n', rpt);
+       fputs("-------------------\n", rpt);
+       fputs("END OF CRASH REPORT\n", rpt);
+       fclose(rpt);
+}
+
+static NORETURN void die_nicely(const char *err, va_list params)
+{
+       static int zombie;
+       char message[2 * PATH_MAX];
+
+       vsnprintf(message, sizeof(message), err, params);
+       fputs("fatal: ", stderr);
+       fputs(message, stderr);
+       fputc('\n', stderr);
+
+       if (!zombie) {
+               zombie = 1;
+               write_crash_report(message);
+       }
+       exit(128);
+}
 
 static void alloc_objects(unsigned int cnt)
 {
@@ -988,7 +1108,7 @@ static int store_object(
                unsigned pos = sizeof(hdr) - 1;
 
                delta_count_by_type[type]++;
-               last->depth++;
+               e->depth = last->depth + 1;
 
                hdrlen = encode_header(OBJ_OFS_DELTA, deltalen, hdr);
                write_or_die(pack_data->pack_fd, hdr, hdrlen);
@@ -1000,8 +1120,7 @@ static int store_object(
                write_or_die(pack_data->pack_fd, hdr + pos, sizeof(hdr) - pos);
                pack_size += sizeof(hdr) - pos;
        } else {
-               if (last)
-                       last->depth = 0;
+               e->depth = 0;
                hdrlen = encode_header(type, datlen, hdr);
                write_or_die(pack_data->pack_fd, hdr, hdrlen);
                pack_size += hdrlen;
@@ -1017,6 +1136,7 @@ static int store_object(
                        free(last->data);
                last->data = dat;
                last->offset = e->offset;
+               last->depth = e->depth;
                last->len = datlen;
        }
        return 0;
@@ -1064,7 +1184,7 @@ static void load_tree(struct tree_entry *root)
        if (myoe && myoe->pack_id != MAX_PACK_ID) {
                if (myoe->type != OBJ_TREE)
                        die("Not a tree: %s", sha1_to_hex(sha1));
-               t->delta_depth = 0;
+               t->delta_depth = myoe->depth;
                buf = gfi_unpack_entry(myoe, &size);
        } else {
                enum object_type type;
@@ -1471,14 +1591,38 @@ static void dump_marks(void)
 static void read_next_command(void)
 {
        do {
-               if (unread_command_buf)
+               if (unread_command_buf) {
                        unread_command_buf = 0;
-               else
+                       if (command_buf.eof)
+                               return;
+               } else {
+                       struct recent_command *rc;
+
+                       command_buf.buf = NULL;
                        read_line(&command_buf, stdin, '\n');
-       } while (!command_buf.eof && command_buf.buf[0] == '#');
+                       if (command_buf.eof)
+                               return;
+
+                       rc = rc_free;
+                       if (rc)
+                               rc_free = rc->next;
+                       else {
+                               rc = cmd_hist.next;
+                               cmd_hist.next = rc->next;
+                               cmd_hist.next->prev = &cmd_hist;
+                               free(rc->buf);
+                       }
+
+                       rc->buf = command_buf.buf;
+                       rc->prev = cmd_tail;
+                       rc->next = cmd_hist.prev;
+                       rc->prev->next = rc;
+                       cmd_tail = rc;
+               }
+       } while (command_buf.buf[0] == '#');
 }
 
-static void skip_optional_lf()
+static void skip_optional_lf(void)
 {
        int term_char = fgetc(stdin);
        if (term_char != '\n' && term_char != EOF)
@@ -1508,6 +1652,7 @@ static void *cmd_data (size_t *size)
                size_t sz = 8192, term_len = command_buf.len - 5 - 2;
                length = 0;
                buffer = xmalloc(sz);
+               command_buf.buf = NULL;
                for (;;) {
                        read_line(&command_buf, stdin, '\n');
                        if (command_buf.eof)
@@ -1717,7 +1862,7 @@ static void file_change_m(struct branch *b)
        } else if (oe) {
                if (oe->type != OBJ_BLOB)
                        die("Not a blob (actually a %s): %s",
-                               command_buf.buf, typename(oe->type));
+                               typename(oe->type), command_buf.buf);
        } else {
                enum object_type type = sha1_object_info(sha1, NULL);
                if (type < 0)
@@ -2177,7 +2322,7 @@ static const char fast_import_usage[] =
 
 int main(int argc, const char **argv)
 {
-       int i, show_stats = 1;
+       unsigned int i, show_stats = 1;
 
        git_config(git_default_config);
        alloc_objects(object_entry_alloc);
@@ -2205,8 +2350,11 @@ int main(int argc, const char **argv)
                }
                else if (!prefixcmp(a, "--max-pack-size="))
                        max_packsize = strtoumax(a + 16, NULL, 0) * 1024 * 1024;
-               else if (!prefixcmp(a, "--depth="))
+               else if (!prefixcmp(a, "--depth=")) {
                        max_depth = strtoul(a + 8, NULL, 0);
+                       if (max_depth > MAX_DEPTH)
+                               die("--depth cannot exceed %u", MAX_DEPTH);
+               }
                else if (!prefixcmp(a, "--active-branches="))
                        max_active_branches = strtoul(a + 18, NULL, 0);
                else if (!prefixcmp(a, "--import-marks="))
@@ -2231,8 +2379,14 @@ int main(int argc, const char **argv)
        if (i != argc)
                usage(fast_import_usage);
 
+       rc_free = pool_alloc(cmd_save * sizeof(*rc_free));
+       for (i = 0; i < (cmd_save - 1); i++)
+               rc_free[i].next = &rc_free[i + 1];
+       rc_free[cmd_save - 1].next = NULL;
+
        prepare_packed_git();
        start_packfile();
+       set_die_routine(die_nicely);
        for (;;) {
                read_next_command();
                if (command_buf.eof)