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.
9 #include "git-compat-util.h"
10 #include "parse-options.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>",
28 static const struct option import_options
[] = {
33 static const char *argv_git_gc_auto
[] = { "git", "gc", "--auto", NULL
};
36 static int import_mbox(const char *gbox
, FILE *fmbox
)
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
);
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.
73 for (i
=blobs
.nr
; i
>0; i
/= 10)
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
);
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
);
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
);
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");
102 commit_list_insert(parent
, &parents
);
104 err
= commit_tree(&commit_msg
, tree_sha1
, parents
, commit_sha1
, /*author=*/NULL
, /*sign=*/NULL
);
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
);
120 int cmd_import(int argc
, const char **argv
, const char *prefix
)
122 const char *gbox
, *mbox
;
123 struct strbuf gbox_ref
= STRBUF_INIT
;
127 argc
= parse_options(argc
, argv
, NULL
/*prefix?*/, import_options
, import_usage
, 0);
129 /* git_config(git_default_config, NULL); ? */
132 usage_with_options(import_usage
, import_options
);
135 strbuf_addf(&gbox_ref
, "refs/mail/%s", gbox
); /* XXX don't hardcode mail/ here */
138 if (!strcmp(mbox
, "-"))
141 fmbox
= fopen(mbox
, "r");
143 die_errno("Can't open %s", mbox
);
146 ret
= import_mbox(gbox_ref
.buf
, fmbox
);
151 strbuf_release(&gbox_ref
);