To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / extra / fast-export / svn-fast-export.c @ 1561:6074fffd8a1d
History | View | Annotate | Download (5.1 KB)
| 1 |
/*
|
|---|---|
| 2 |
* svn-fast-export.c
|
| 3 |
* ----------
|
| 4 |
* Walk through each revision of a local Subversion repository and export it
|
| 5 |
* in a stream that git-fast-import can consume.
|
| 6 |
*
|
| 7 |
* Author: Chris Lee <clee@kde.org>
|
| 8 |
* License: MIT <http://www.opensource.org/licenses/mit-license.php>
|
| 9 |
*/
|
| 10 |
|
| 11 |
#define _XOPEN_SOURCE
|
| 12 |
#include <unistd.h> |
| 13 |
#include <string.h> |
| 14 |
#include <stdio.h> |
| 15 |
#include <time.h> |
| 16 |
|
| 17 |
#ifndef PATH_MAX
|
| 18 |
#define PATH_MAX 4096 |
| 19 |
#endif
|
| 20 |
|
| 21 |
#include <apr_lib.h> |
| 22 |
#include <apr_getopt.h> |
| 23 |
#include <apr_general.h> |
| 24 |
|
| 25 |
#include <svn_fs.h> |
| 26 |
#include <svn_repos.h> |
| 27 |
#include <svn_pools.h> |
| 28 |
#include <svn_types.h> |
| 29 |
|
| 30 |
#undef SVN_ERR
|
| 31 |
#define SVN_ERR(expr) SVN_INT_ERR(expr)
|
| 32 |
#define apr_sane_push(arr, contents) *(char **)apr_array_push(arr) = contents |
| 33 |
|
| 34 |
#define TRUNK "/trunk/" |
| 35 |
|
| 36 |
time_t get_epoch(char *svn_date)
|
| 37 |
{
|
| 38 |
struct tm tm = {0}; |
| 39 |
char *date = malloc(strlen(svn_date) * sizeof(char *)); |
| 40 |
strncpy(date, svn_date, strlen(svn_date) - 8);
|
| 41 |
strptime(date, "%Y-%m-%dT%H:%M:%S", &tm);
|
| 42 |
free(date); |
| 43 |
return mktime(&tm);
|
| 44 |
} |
| 45 |
|
| 46 |
int dump_blob(svn_fs_root_t *root, char *full_path, apr_pool_t *pool) |
| 47 |
{
|
| 48 |
apr_size_t len; |
| 49 |
svn_stream_t *stream, *outstream; |
| 50 |
svn_filesize_t stream_length; |
| 51 |
|
| 52 |
SVN_ERR(svn_fs_file_length(&stream_length, root, full_path, pool)); |
| 53 |
SVN_ERR(svn_fs_file_contents(&stream, root, full_path, pool)); |
| 54 |
|
| 55 |
fprintf(stdout, "data %lu\n", stream_length);
|
| 56 |
fflush(stdout); |
| 57 |
|
| 58 |
SVN_ERR(svn_stream_for_stdout(&outstream, pool)); |
| 59 |
SVN_ERR(svn_stream_copy(stream, outstream, pool)); |
| 60 |
|
| 61 |
fprintf(stdout, "\n");
|
| 62 |
fflush(stdout); |
| 63 |
|
| 64 |
return 0; |
| 65 |
} |
| 66 |
|
| 67 |
int export_revision(svn_revnum_t rev, svn_fs_t *fs, apr_pool_t *pool)
|
| 68 |
{
|
| 69 |
unsigned int mark; |
| 70 |
const void *key; |
| 71 |
void *val;
|
| 72 |
char *path, *file_change;
|
| 73 |
apr_pool_t *revpool; |
| 74 |
apr_hash_t *changes, *props; |
| 75 |
apr_hash_index_t *i; |
| 76 |
apr_array_header_t *file_changes; |
| 77 |
svn_string_t *author, *committer, *svndate, *svnlog; |
| 78 |
svn_boolean_t is_dir; |
| 79 |
svn_fs_root_t *fs_root; |
| 80 |
svn_fs_path_change_t *change; |
| 81 |
|
| 82 |
fprintf(stderr, "Exporting revision %ld... ", rev);
|
| 83 |
|
| 84 |
SVN_ERR(svn_fs_revision_root(&fs_root, fs, rev, pool)); |
| 85 |
SVN_ERR(svn_fs_paths_changed(&changes, fs_root, pool)); |
| 86 |
SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, pool)); |
| 87 |
|
| 88 |
revpool = svn_pool_create(pool); |
| 89 |
|
| 90 |
file_changes = apr_array_make(pool, apr_hash_count(changes), sizeof(char *)); |
| 91 |
mark = 1;
|
| 92 |
for (i = apr_hash_first(pool, changes); i; i = apr_hash_next(i)) {
|
| 93 |
svn_pool_clear(revpool); |
| 94 |
apr_hash_this(i, &key, NULL, &val);
|
| 95 |
path = (char *)key;
|
| 96 |
change = (svn_fs_path_change_t *)val; |
| 97 |
|
| 98 |
SVN_ERR(svn_fs_is_dir(&is_dir, fs_root, path, revpool)); |
| 99 |
|
| 100 |
if (is_dir || strncmp(TRUNK, path, strlen(TRUNK))) {
|
| 101 |
continue;
|
| 102 |
} |
| 103 |
|
| 104 |
if (change->change_kind == svn_fs_path_change_delete) {
|
| 105 |
apr_sane_push(file_changes, (char *)svn_string_createf(pool, "D %s", path + strlen(TRUNK))->data); |
| 106 |
} else {
|
| 107 |
apr_sane_push(file_changes, (char *)svn_string_createf(pool, "M 644 :%u %s", mark, path + strlen(TRUNK))->data); |
| 108 |
fprintf(stdout, "blob\nmark :%u\n", mark++);
|
| 109 |
dump_blob(fs_root, (char *)path, revpool);
|
| 110 |
} |
| 111 |
} |
| 112 |
|
| 113 |
if (file_changes->nelts == 0) { |
| 114 |
fprintf(stderr, "skipping.\n");
|
| 115 |
svn_pool_destroy(revpool); |
| 116 |
return 0; |
| 117 |
} |
| 118 |
|
| 119 |
author = apr_hash_get(props, "svn:author", APR_HASH_KEY_STRING);
|
| 120 |
if (svn_string_isempty(author))
|
| 121 |
author = svn_string_create("nobody", pool);
|
| 122 |
svndate = apr_hash_get(props, "svn:date", APR_HASH_KEY_STRING);
|
| 123 |
svnlog = apr_hash_get(props, "svn:log", APR_HASH_KEY_STRING);
|
| 124 |
|
| 125 |
fprintf(stdout, "commit refs/heads/master\n");
|
| 126 |
fprintf(stdout, "committer %s <%s@localhost> %ld -0000\n", author->data, author->data, get_epoch((char *)svndate->data)); |
| 127 |
fprintf(stdout, "data %d\n", svnlog->len);
|
| 128 |
fputs(svnlog->data, stdout); |
| 129 |
fprintf(stdout, "\n");
|
| 130 |
fputs(apr_array_pstrcat(pool, file_changes, '\n'), stdout);
|
| 131 |
fprintf(stdout, "\n\n");
|
| 132 |
fflush(stdout); |
| 133 |
|
| 134 |
svn_pool_destroy(revpool); |
| 135 |
|
| 136 |
fprintf(stderr, "done!\n");
|
| 137 |
|
| 138 |
return 0; |
| 139 |
} |
| 140 |
|
| 141 |
int crawl_revisions(char *repos_path) |
| 142 |
{
|
| 143 |
apr_pool_t *pool, *subpool; |
| 144 |
svn_fs_t *fs; |
| 145 |
svn_repos_t *repos; |
| 146 |
svn_revnum_t youngest_rev, min_rev, max_rev, rev; |
| 147 |
|
| 148 |
pool = svn_pool_create(NULL);
|
| 149 |
|
| 150 |
SVN_ERR(svn_fs_initialize(pool)); |
| 151 |
SVN_ERR(svn_repos_open(&repos, repos_path, pool)); |
| 152 |
if ((fs = svn_repos_fs(repos)) == NULL) |
| 153 |
return -1; |
| 154 |
SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool)); |
| 155 |
|
| 156 |
min_rev = 1;
|
| 157 |
max_rev = youngest_rev; |
| 158 |
|
| 159 |
subpool = svn_pool_create(pool); |
| 160 |
for (rev = min_rev; rev <= max_rev; rev++) {
|
| 161 |
svn_pool_clear(subpool); |
| 162 |
export_revision(rev, fs, subpool); |
| 163 |
} |
| 164 |
|
| 165 |
svn_pool_destroy(pool); |
| 166 |
|
| 167 |
return 0; |
| 168 |
} |
| 169 |
|
| 170 |
int main(int argc, char *argv[]) |
| 171 |
{
|
| 172 |
if (argc != 2) { |
| 173 |
fprintf(stderr, "usage: %s REPOS_PATH\n", argv[0]); |
| 174 |
return -1; |
| 175 |
} |
| 176 |
|
| 177 |
if (apr_initialize() != APR_SUCCESS) {
|
| 178 |
fprintf(stderr, "You lose at apr_initialize().\n");
|
| 179 |
return -1; |
| 180 |
} |
| 181 |
|
| 182 |
crawl_revisions(argv[1]);
|
| 183 |
|
| 184 |
apr_terminate(); |
| 185 |
|
| 186 |
return 0; |
| 187 |
} |