4 * Walk through each revision of a local Subversion repository and export it
5 * in a stream that git-fast-import can consume.
7 * Author: Chris Lee <clee@kde.org>
8 * License: MIT <http://www.opensource.org/licenses/mit-license.php>
22 #include <apr_getopt.h>
23 #include <apr_general.h>
26 #include <svn_pools.h>
27 #include <svn_types.h>
30 #define SVN_ERR(expr) SVN_INT_ERR(expr)
31 #define apr_sane_push(arr, contents) *(char **)apr_array_push(arr) = contents
33 #define TRUNK "/trunk/"
35 time_t get_epoch(char *svn_date
)
38 char *date
= malloc(strlen(svn_date
) * sizeof(char *));
39 strncpy(date
, svn_date
, strlen(svn_date
) - 8);
40 strptime(date
, "%Y-%m-%dT%H:%M:%S", &tm
);
45 int dump_blob(svn_fs_root_t
*root
, char *full_path
, apr_pool_t
*pool
)
48 svn_stream_t
*stream
, *outstream
;
49 svn_filesize_t stream_length
;
51 SVN_ERR(svn_fs_file_length(&stream_length
, root
, full_path
, pool
));
52 SVN_ERR(svn_fs_file_contents(&stream
, root
, full_path
, pool
));
54 fprintf(stdout
, "data %lu\n", stream_length
);
57 SVN_ERR(svn_stream_for_stdout(&outstream
, pool
));
58 SVN_ERR(svn_stream_copy(stream
, outstream
, pool
));
60 fprintf(stdout
, "\n");
66 int export_revision(svn_revnum_t rev
, svn_fs_t
*fs
, apr_pool_t
*pool
)
71 char *path
, *file_change
;
73 apr_hash_t
*changes
, *props
;
75 apr_array_header_t
*file_changes
;
76 svn_string_t
*author
, *committer
, *svndate
, *svnlog
;
78 svn_fs_root_t
*fs_root
;
79 svn_fs_path_change_t
*change
;
81 fprintf(stderr
, "Exporting revision %ld... ", rev
);
83 SVN_ERR(svn_fs_revision_root(&fs_root
, fs
, rev
, pool
));
84 SVN_ERR(svn_fs_paths_changed(&changes
, fs_root
, pool
));
85 SVN_ERR(svn_fs_revision_proplist(&props
, fs
, rev
, pool
));
87 revpool
= svn_pool_create(pool
);
89 file_changes
= apr_array_make(pool
, apr_hash_count(changes
), sizeof(char *));
91 for (i
= apr_hash_first(pool
, changes
); i
; i
= apr_hash_next(i
)) {
92 svn_pool_clear(revpool
);
93 apr_hash_this(i
, &key
, NULL
, &val
);
95 change
= (svn_fs_path_change_t
*)val
;
97 SVN_ERR(svn_fs_is_dir(&is_dir
, fs_root
, path
, revpool
));
99 if (is_dir
|| strncmp(TRUNK
, path
, strlen(TRUNK
))) {
103 if (change
->change_kind
== svn_fs_path_change_delete
) {
104 apr_sane_push(file_changes
, (char *)svn_string_createf(pool
, "D %s", path
+ strlen(TRUNK
))->data
);
106 apr_sane_push(file_changes
, (char *)svn_string_createf(pool
, "M 644 :%u %s", mark
, path
+ strlen(TRUNK
))->data
);
107 fprintf(stdout
, "blob\nmark :%u\n", mark
++);
108 dump_blob(fs_root
, (char *)path
, revpool
);
112 if (file_changes
->nelts
== 0) {
113 fprintf(stderr
, "skipping.\n");
114 svn_pool_destroy(revpool
);
118 author
= apr_hash_get(props
, "svn:author", APR_HASH_KEY_STRING
);
119 if (svn_string_isempty(author
))
120 author
= svn_string_create("nobody", pool
);
121 svndate
= apr_hash_get(props
, "svn:date", APR_HASH_KEY_STRING
);
122 svnlog
= apr_hash_get(props
, "svn:log", APR_HASH_KEY_STRING
);
124 fprintf(stdout
, "commit refs/heads/master\n");
125 fprintf(stdout
, "committer %s <%s@localhost> %ld -0000\n", author
->data
, author
->data
, get_epoch((char *)svndate
->data
));
126 fprintf(stdout
, "data %d\n", svnlog
->len
);
127 fputs(svnlog
->data
, stdout
);
128 fprintf(stdout
, "\n");
129 fputs(apr_array_pstrcat(pool
, file_changes
, '\n'), stdout
);
130 fprintf(stdout
, "\n\n");
133 svn_pool_destroy(revpool
);
135 fprintf(stderr
, "done!\n");
140 int crawl_revisions(char *repos_path
)
142 apr_pool_t
*pool
, *subpool
;
144 svn_revnum_t youngest_rev
, min_rev
, max_rev
, rev
;
146 pool
= svn_pool_create(NULL
);
148 SVN_ERR(svn_fs_initialize(pool
));
149 SVN_ERR(svn_fs_open(&fs
, repos_path
, NULL
, pool
));
150 SVN_ERR(svn_fs_youngest_rev(&youngest_rev
, fs
, pool
));
153 max_rev
= youngest_rev
;
155 subpool
= svn_pool_create(pool
);
156 for (rev
= min_rev
; rev
<= max_rev
; rev
++) {
157 svn_pool_clear(subpool
);
158 export_revision(rev
, fs
, subpool
);
161 svn_pool_destroy(pool
);
166 int main(int argc
, char *argv
[])
169 fprintf(stderr
, "usage: %s REPOS_PATH\n", argv
[0]);
173 if (apr_initialize() != APR_SUCCESS
) {
174 fprintf(stderr
, "You lose at apr_initialize().\n");
178 crawl_revisions(argv
[1]);