Upgrade Git to latest master
[navymail.git] / import.c
blob61f2b5514af8343e307ce0d22a68fc21555d9832
1 /* import mbox into navymail store
2 * Copyright (C) 2011-2012 Kirill Smelkov <kirr@navytux.spb.ru>
4 * This program is free software: you can Use, Study, Modify and Redistribute it
5 * under the terms of the GNU General Public License version 2. This program is
6 * distributed WITHOUT ANY WARRANTY. See COPYING file for full License terms.
7 */
9 #include "git-compat-util.h"
10 #include "parse-options.h"
11 #include "cache.h"
12 #include "object.h"
13 #include "blob.h"
14 #include "tree.h"
15 #include "commit.h"
16 #include "refs.h"
17 #include "sha1-array.h"
18 #include "run-command.h"
19 #include "navymail/navymail.h"
20 #include "navymail/mbox-walk.h"
22 /* XXX better naming for gbox */
23 static const char * const import_usage[] = {
24 "navymail import <gbox> <mbox>",
25 NULL
28 static const struct option import_options[] = {
29 OPT_END()
33 static const char *argv_git_gc_auto[] = { "git", "gc", "--auto", NULL };
36 static int import_mbox(const char *gbox, FILE *fmbox)
38 struct mbox_walk m;
40 unsigned char blob_sha1[20];
41 struct sha1_array blobs = SHA1_ARRAY_INIT;
43 struct strbuf tree_buf = STRBUF_INIT;
44 unsigned char tree_sha1[20];
46 unsigned char parent_sha1[20], commit_sha1[20];
47 struct commit *parent = NULL;
48 struct commit_list *parents = NULL;
49 struct strbuf commit_msg = STRBUF_INIT;
50 struct strbuf reflog_msg = STRBUF_INIT;
52 int i, nmsg_width, nmsg, err;
55 /* (1) msgs -> blobs */
56 prepare_mbox_walk(&m, fmbox);
58 while (next_mbox_entry(&m)) {
59 err = write_sha1_file(m.msg.buf, m.msg.len, blob_type, blob_sha1);
60 if (err)
61 die("import: Unable to put msg -> blob");
63 sha1_array_append(&blobs, blob_sha1);
66 /* (2) blobs -> tree ; in reverse order, so that more recent msg comes first
68 * NOTE we have to be careful, and prepare tree entry names in the same
69 * order as done git-mktree. Git expects tree entries to be sorted by
70 * name, so we prepend enough leading 0 to make that sort numerical.
72 nmsg_width = 0;
73 for (i=blobs.nr; i>0; i /= 10)
74 nmsg_width++;
76 for (i=0; i<blobs.nr; ++i) {
77 strbuf_addf(&tree_buf, "100644 %0*i%c", nmsg_width, i, '\0');
78 strbuf_add (&tree_buf, blobs.sha1[blobs.nr-i-1], 20);
81 err = write_sha1_file(tree_buf.buf, tree_buf.len, tree_type, tree_sha1);
82 if (err)
83 die("import: Unable to put blobs -> tree");
85 /* free tree and blobs[] early - they could be large for bulk imports */
86 strbuf_release(&tree_buf);
87 nmsg = blobs.nr;
88 sha1_array_clear(&blobs);
90 /* (3) tree -> commit */
91 if (!get_sha1(gbox, parent_sha1)) {
92 parent = lookup_commit_or_die(parent_sha1, gbox);
93 err = parse_commit(parent);
94 if (err)
95 die("import: could not parse %s commit", gbox);
98 strbuf_addf(&commit_msg, "Import %i msg into %s", nmsg, gbox);
99 strbuf_addf(&reflog_msg, "commit (mail%s)", parent ? "" : ", initial");
101 if (parent)
102 commit_list_insert(parent, &parents);
104 err = commit_tree(&commit_msg, tree_sha1, parents, commit_sha1, /*author=*/NULL, /*sign=*/NULL);
105 if (err)
106 die("import: Unable to put tree -> commit");
108 update_ref(reflog_msg.buf, gbox, commit_sha1,
109 parent ? parent->object.sha1 : NULL, 0, DIE_ON_ERR);
111 /* (4) houskeeping */
112 run_command_v_opt(argv_git_gc_auto, 0);
115 strbuf_release(&commit_msg);
116 strbuf_release(&reflog_msg);
117 return 0;
120 int cmd_import(int argc, const char **argv, const char *prefix)
122 const char *gbox, *mbox;
123 struct strbuf gbox_ref = STRBUF_INIT;
124 FILE *fmbox;
125 int ret;
127 argc = parse_options(argc, argv, NULL /*prefix?*/, import_options, import_usage, 0);
129 /* git_config(git_default_config, NULL); ? */
131 if (argc != 2)
132 usage_with_options(import_usage, import_options);
134 gbox = argv[0];
135 strbuf_addf(&gbox_ref, "refs/mail/%s", gbox); /* XXX don't hardcode mail/ here */
137 mbox = argv[1];
138 if (!strcmp(mbox, "-"))
139 fmbox = stdin;
140 else {
141 fmbox = fopen(mbox, "r");
142 if (!fmbox)
143 die_errno("Can't open %s", mbox);
146 ret = import_mbox(gbox_ref.buf, fmbox);
148 if (fmbox != stdin)
149 fclose(fmbox);
151 strbuf_release(&gbox_ref);
152 return ret;