changeset 1567:3ad53f43483d live

Update hg-fast-export to current version (with fix-broken-bare upstream branch) for compatibility with current git
author Chris Cannam
date Mon, 10 Oct 2016 12:56:28 +0100
parents ac2e4a54a6a6
children bc47b68a9487 26a4f99ec679
files extra/fast-export/Makefile extra/fast-export/hg-fast-export.py extra/fast-export/hg-fast-export.sh extra/fast-export/hg-reset.sh extra/fast-export/hg2git.py extra/fast-export/svn-archive.c extra/fast-export/svn-fast-export.c extra/fast-export/svn-fast-export.py
diffstat 8 files changed, 71 insertions(+), 628 deletions(-) [+]
line wrap: on
line diff
--- a/extra/fast-export/Makefile	Tue Jul 19 13:49:56 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-SVN ?= /usr/local/svn
-APR_INCLUDES ?= /usr/include/apr-1.0
-CFLAGS += -I${APR_INCLUDES} -I${SVN}/include/subversion-1 -pipe -O2 -std=c99
-LDFLAGS += -L${SVN}/lib -lsvn_fs-1 -lsvn_repos-1
-
-all: svn-fast-export svn-archive
-
-svn-fast-export: svn-fast-export.c
-svn-archive: svn-archive.c
-
-.PHONY: clean
-
-clean:
-	rm -rf svn-fast-export svn-archive
--- a/extra/fast-export/hg-fast-export.py	Tue Jul 19 13:49:56 2016 +0100
+++ b/extra/fast-export/hg-fast-export.py	Mon Oct 10 12:56:28 2016 +0100
@@ -145,14 +145,23 @@
   if max>cfg_export_boundary:
     sys.stderr.write('Exported %d/%d files\n' % (count,max))
 
-def sanitize_name(name,what="branch"):
+def sanitize_name(name,what="branch", mapping={}):
   """Sanitize input roughly according to git-check-ref-format(1)"""
 
+  # NOTE: Do not update this transform to work around
+  # incompatibilities on your platform. If you change it and it starts
+  # modifying names which previously were not touched it will break
+  # preexisting setups which are doing incremental imports.
+  #
+  # Use the -B and -T options to mangle branch and tag names
+  # instead. If you have a source repository where this is too much
+  # work to do manually, write a tool that does it for you.
+
   def dot(name):
     if name[0] == '.': return '_'+name[1:]
     return name
 
-  n=name
+  n=mapping.get(name,name)
   p=re.compile('([[ ~^:?\\\\*]|\.\.)')
   n=p.sub('_', n)
   if n[-1] in ('/', '.'): n=n[:-1]+'_'
@@ -170,11 +179,11 @@
   return filename
 
 def export_commit(ui,repo,revision,old_marks,max,count,authors,
-                  branchesmap,sob,brmap,hgtags,notes,encoding='',fn_encoding=''):
+                  branchesmap,sob,brmap,hgtags,encoding='',fn_encoding=''):
   def get_branchname(name):
     if brmap.has_key(name):
       return brmap[name]
-    n=sanitize_name(branchesmap.get(name,name))
+    n=sanitize_name(name, "branch", branchesmap)
     brmap[name]=n
     return n
 
@@ -235,28 +244,34 @@
   export_file_contents(ctx,man,changed,hgtags,fn_encoding)
   wr()
 
-  count=checkpoint(count)
-  count=generate_note(user,time,timezone,revision,ctx,count,notes)
-  return count
+  return checkpoint(count)
 
-def generate_note(user,time,timezone,revision,ctx,count,notes):
-  if not notes:
-    return count
+def export_note(ui,repo,revision,count,authors,encoding,is_first):
+  (revnode,_,user,(time,timezone),_,_,_,_)=get_changeset(ui,repo,revision,authors,encoding)
+
+  parents = [p for p in repo.changelog.parentrevs(revision) if p >= 0]
+
   wr('commit refs/notes/hg')
   wr('committer %s %d %s' % (user,time,timezone))
   wr('data 0')
+  if is_first:
+    wr('from refs/notes/hg^0')
   wr('N inline :%d' % (revision+1))
-  hg_hash=ctx.hex()
+  hg_hash=repo.changectx(str(revision)).hex()
   wr('data %d' % (len(hg_hash)))
   wr_no_nl(hg_hash)
   wr()
   return checkpoint(count)
-  
+
+  wr('data %d' % (len(desc)+1)) # wtf?
+  wr(desc)
+  wr()
+
 def export_tags(ui,repo,old_marks,mapping_cache,count,authors,tagsmap):
   l=repo.tagslist()
   for tag,node in l:
     # Remap the branch name
-    tag=sanitize_name(tagsmap.get(tag,tag),"tag")
+    tag=sanitize_name(tag,"tag",tagsmap)
     # ignore latest revision
     if tag=='tip': continue
     # ignore tags to nodes that are missing (ie, 'in the future')
@@ -281,6 +296,7 @@
 def load_mapping(name, filename):
   cache={}
   if not os.path.exists(filename):
+    sys.stderr.write('Could not open mapping file [%s]\n' % (filename))
     return cache
   f=open(filename,'r')
   l=0
@@ -311,7 +327,7 @@
       break
   return tip
 
-def verify_heads(ui,repo,cache,force):
+def verify_heads(ui,repo,cache,force,branchesmap):
   branches={}
   for bn, heads in repo.branchmap().iteritems():
     branches[bn] = branchtip(repo, heads)
@@ -321,8 +337,9 @@
   # get list of hg's branches to verify, don't take all git has
   for _,_,b in l:
     b=get_branch(b)
-    sha1=get_git_sha1(b)
-    c=cache.get(b)
+    sanitized_name=sanitize_name(b,"branch",branchesmap)
+    sha1=get_git_sha1(sanitized_name)
+    c=cache.get(sanitized_name)
     if sha1!=c:
       sys.stderr.write('Error: Branch [%s] modified outside hg-fast-export:'
         '\n%s (repo) != %s (cache)\n' % (b,sha1,c))
@@ -343,6 +360,10 @@
 def hg2git(repourl,m,marksfile,mappingfile,headsfile,tipfile,
            authors={},branchesmap={},tagsmap={},
            sob=False,force=False,hgtags=False,notes=False,encoding='',fn_encoding=''):
+  def check_cache(filename, contents):
+    if len(contents) == 0:
+      sys.stderr.write('Warning: %s does not contain any data, this will probably make an incremental import fail\n' % filename)
+
   _max=int(m)
 
   old_marks=load_cache(marksfile,lambda s: int(s)-1)
@@ -350,9 +371,15 @@
   heads_cache=load_cache(headsfile)
   state_cache=load_cache(tipfile)
 
+  if len(state_cache) != 0:
+    for (name, data) in [(marksfile, old_marks),
+                         (mappingfile, mapping_cache),
+                         (headsfile, state_cache)]:
+      check_cache(name, data)
+
   ui,repo=setup_repo(repourl)
 
-  if not verify_heads(ui,repo,heads_cache,force):
+  if not verify_heads(ui,repo,heads_cache,force,branchesmap):
     return 1
 
   try:
@@ -374,7 +401,10 @@
   brmap={}
   for rev in range(min,max):
     c=export_commit(ui,repo,rev,old_marks,max,c,authors,branchesmap,
-                    sob,brmap,hgtags,notes,encoding,fn_encoding)
+                    sob,brmap,hgtags,encoding,fn_encoding)
+  if notes:
+    for rev in range(min,max):
+      c=export_note(ui,repo,rev,c,authors, encoding, rev == min and min != 0)
 
   state_cache['tip']=max
   state_cache['repo']=repourl
--- a/extra/fast-export/hg-fast-export.sh	Tue Jul 19 13:49:56 2016 +0100
+++ b/extra/fast-export/hg-fast-export.sh	Mon Oct 10 12:56:28 2016 +0100
@@ -48,8 +48,16 @@
       echo "$LONG_USAGE"
       exit 0
 esac
-. "$(git --exec-path)/git-sh-setup"
-cd_to_toplevel
+
+IS_BARE=$(git rev-parse --is-bare-repository) \
+    || (echo "Could not find git repo" ; exit 1)
+if test "z$IS_BARE" != ztrue; then
+   # This is not a bare repo, cd to the toplevel
+   TOPLEVEL=$(git rev-parse --show-toplevel) \
+       || (echo "Could not find git repo toplevel" ; exit 1)
+   cd $TOPLEVEL || exit 1
+fi
+GIT_DIR=$(git rev-parse --git-dir) || (echo "Could not find git repo" ; exit 1)
 
 while case "$#" in 0) break ;; esac
 do
--- a/extra/fast-export/hg-reset.sh	Tue Jul 19 13:49:56 2016 +0100
+++ b/extra/fast-export/hg-reset.sh	Mon Oct 10 12:56:28 2016 +0100
@@ -24,8 +24,15 @@
 	-r	Mercurial repository to use
 "
 
-. "$(git --exec-path)/git-sh-setup"
-cd_to_toplevel
+IS_BARE=$(git rev-parse --is-bare-repository) \
+    || (echo "Could not find git repo" ; exit 1)
+if test "z$IS_BARE" != ztrue; then
+   # This is not a bare repo, cd to the toplevel
+   TOPLEVEL=$(git rev-parse --show-toplevel) \
+       || (echo "Could not find git repo toplevel" ; exit 1)
+   cd $TOPLEVEL || exit 1
+fi
+GIT_DIR=$(git rev-parse --git-dir) || (echo "Could not find git repo" ; exit 1)
 
 while case "$#" in 0) break ;; esac
 do
--- a/extra/fast-export/hg2git.py	Tue Jul 19 13:49:56 2016 +0100
+++ b/extra/fast-export/hg2git.py	Mon Oct 10 12:56:28 2016 +0100
@@ -7,6 +7,7 @@
 import re
 import os
 import sys
+import subprocess
 
 # default git branch name
 cfg_master='master'
@@ -105,12 +106,10 @@
 def get_git_sha1(name,type='heads'):
   try:
     # use git-rev-parse to support packed refs
-    cmd="git rev-parse --verify refs/%s/%s 2>%s" % (type,name,os.devnull)
-    p=os.popen(cmd)
-    l=p.readline()
-    p.close()
+    ref="refs/%s/%s" % (type,name)
+    l=subprocess.check_output(["git", "rev-parse", "--verify", "--quiet", ref])
     if l == None or len(l) == 0:
       return None
     return l[0:40]
-  except IOError:
+  except subprocess.CalledProcessError:
     return None
--- a/extra/fast-export/svn-archive.c	Tue Jul 19 13:49:56 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,240 +0,0 @@
-/*
- * svn-archive.c
- * ----------
- *  Walk through a given revision of a local Subversion repository and export 
- *  all of the contents as a tarfile.
- *
- * Author: Chris Lee <clee@kde.org>
- * License: MIT <http://www.opensource.org/licenses/mit-license.php>
- */
-
-#define _XOPEN_SOURCE
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <time.h>
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-#include <apr_general.h>
-#include <apr_strings.h>
-#include <apr_getopt.h>
-#include <apr_lib.h>
-
-#include <svn_types.h>
-#include <svn_pools.h>
-#include <svn_repos.h>
-#include <svn_fs.h>
-
-#undef SVN_ERR
-#define SVN_ERR(expr) SVN_INT_ERR(expr)
-#define apr_sane_push(arr, contents) *(char **)apr_array_push(arr) = contents
-
-#define TRUNK "/trunk"
-
-static time_t archive_time;
-
-time_t get_epoch(char *svn_date)
-{
-    struct tm tm = {0};
-    char *date = malloc(strlen(svn_date) * sizeof(char *));
-    strncpy(date, svn_date, strlen(svn_date) - 8);
-    strptime(date, "%Y-%m-%dT%H:%M:%S", &tm);
-    free(date);
-    return mktime(&tm);
-}
-
-int tar_header(apr_pool_t *pool, char *path, char *node, size_t f_size)
-{
-    char          buf[512];
-    unsigned int  i, checksum;
-    svn_boolean_t is_dir;
-
-    memset(buf, 0, sizeof(buf));
-
-    if ((strlen(path) == 0) && (strlen(node) == 0)) {
-        return 0;
-    }
-
-    if (strlen(node) == 0) {
-        is_dir = 1;
-    } else {
-        is_dir = 0;
-    }
-
-    if (strlen(path) == 0) {
-        strncpy(buf, apr_psprintf(pool, "%s", node), 99);
-    } else if (strlen(path) + strlen(node) < 100) {
-        strncpy(buf, apr_psprintf(pool, "%s/%s", path+1, node), 99);
-    } else {
-        fprintf(stderr, "really long file path...\n");
-        strncpy(&buf[0], node, 99);
-        strncpy(&buf[345], path+1, 154);
-    }
-
-    strncpy(&buf[100], apr_psprintf(pool, "%07o", (is_dir ? 0755 : 0644)), 7);
-    strncpy(&buf[108], apr_psprintf(pool, "%07o", 1000), 7);
-    strncpy(&buf[116], apr_psprintf(pool, "%07o", 1000), 7);
-    strncpy(&buf[124], apr_psprintf(pool, "%011lo", f_size), 11);
-    strncpy(&buf[136], apr_psprintf(pool, "%011lo", archive_time), 11);
-    strncpy(&buf[156], (is_dir ? "5" : "0"), 1);
-    strncpy(&buf[257], "ustar  ", 8);
-    strncpy(&buf[265], "clee", 31);
-    strncpy(&buf[297], "clee", 31);
-    // strncpy(&buf[329], apr_psprintf(pool, "%07o", 0), 7);
-    // strncpy(&buf[337], apr_psprintf(pool, "%07o", 0), 7);
-
-    strncpy(&buf[148], "        ", 8);
-    checksum = 0;
-    for (i = 0; i < sizeof(buf); i++) {
-        checksum += buf[i];
-    }
-    strncpy(&buf[148], apr_psprintf(pool, "%07o", checksum & 0x1fffff), 7);
-
-    fwrite(buf, sizeof(char), sizeof(buf), stdout);
-
-    return 0;
-}
-
-int tar_footer()
-{
-    char block[1024];
-    memset(block, 0, sizeof(block));
-    fwrite(block, sizeof(char), sizeof(block), stdout);
-}
-
-int dump_blob(svn_fs_root_t *root, char *prefix, char *path, char *node, apr_pool_t *pool)
-{
-    char           *full_path, buf[512];
-    apr_size_t     len;
-    svn_stream_t   *stream;
-    svn_filesize_t stream_length;
-
-    full_path = apr_psprintf(pool, "%s%s/%s", prefix, path, node);
-
-    SVN_ERR(svn_fs_file_length(&stream_length, root, full_path, pool));
-    SVN_ERR(svn_fs_file_contents(&stream, root, full_path, pool));
-
-    tar_header(pool, path, node, stream_length);
-
-    do {
-        len = sizeof(buf);
-        memset(buf, '\0', sizeof(buf));
-        SVN_ERR(svn_stream_read(stream, buf, &len));
-        fwrite(buf, sizeof(char), sizeof(buf), stdout);
-    } while (len == sizeof(buf));
-
-    return 0;
-}
-
-int dump_tree(svn_fs_root_t *root, char *prefix, char *path, apr_pool_t *pool)
-{
-    const void       *key;
-    void             *val;
-    char             *node, *subpath, *full_path;
-
-    apr_pool_t       *subpool;
-    apr_hash_t       *dir_entries;
-    apr_hash_index_t *i;
-
-    svn_boolean_t    is_dir;
-
-    tar_header(pool, path, "", 0);
-
-    SVN_ERR(svn_fs_dir_entries(&dir_entries, root, apr_psprintf(pool, "%s/%s", prefix, path), pool));
-
-    subpool = svn_pool_create(pool);
-
-    for (i = apr_hash_first(pool, dir_entries); i; i = apr_hash_next(i)) {
-        svn_pool_clear(subpool);
-        apr_hash_this(i, &key, NULL, &val);
-        node = (char *)key;
-
-        subpath = apr_psprintf(subpool, "%s/%s", path, node);
-        full_path = apr_psprintf(subpool, "%s%s", prefix, subpath);
-
-        svn_fs_is_dir(&is_dir, root, full_path, subpool);
-
-        if (is_dir) {
-            dump_tree(root, prefix, subpath, subpool);
-        } else {
-            dump_blob(root, prefix, path, node, subpool);
-        }
-    }
-
-    svn_pool_destroy(subpool);
-
-    return 0;
-}
-
-int crawl_filesystem(char *repos_path, char *root_path, apr_pool_t *pool)
-{
-    char                 *path;
-
-    apr_hash_t           *props;
-    apr_hash_index_t     *i;
-
-    svn_repos_t          *repos;
-    svn_fs_t             *fs;
-    svn_string_t         *svndate;
-    svn_revnum_t         youngest_rev, export_rev;
-    svn_fs_root_t        *fs_root;
-
-    SVN_ERR(svn_fs_initialize(pool));
-    SVN_ERR(svn_repos_open(&repos, repos_path, pool));
-    if ((fs = svn_repos_fs(repos)) == NULL)
-      return -1;
-    SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));
-
-    export_rev = youngest_rev;
-
-    SVN_ERR(svn_fs_revision_root(&fs_root, fs, export_rev, pool));
-    SVN_ERR(svn_fs_revision_proplist(&props, fs, export_rev, pool));
-
-    svndate = apr_hash_get(props, "svn:date", APR_HASH_KEY_STRING);
-    archive_time = get_epoch((char *)svndate->data);
-
-    fprintf(stderr, "Exporting archive of r%ld... \n", export_rev);
-
-    dump_tree(fs_root, root_path, "", pool);
-
-    tar_footer();
-
-    fprintf(stderr, "done!\n");
-
-    return 0;
-}
-
-int main(int argc, char *argv[])
-{
-    apr_pool_t           *pool;
-    apr_getopt_t         *options;
-
-    apr_getopt_option_t long_options[] = {
-        { "help",     'h', 0 },
-        { "prefix",   'p', 0 },
-        { "basename", 'b', 0 },
-        { "revision", 'r', 0 },
-        { NULL,       0,   0 }
-    };
-
-    if (argc < 2) {
-        fprintf(stderr, "usage: %s REPOS_PATH [prefix]\n", argv[0]);
-        return -1;
-    }
-
-    if (apr_initialize() != APR_SUCCESS) {
-        fprintf(stderr, "You lose at apr_initialize().\n");
-        return -1;
-    }
-
-    pool = svn_pool_create(NULL);
-
-    crawl_filesystem(argv[1], (argc == 3 ? argv[2] : TRUNK), pool);
-
-    apr_terminate();
-
-    return 0;
-}
--- a/extra/fast-export/svn-fast-export.c	Tue Jul 19 13:49:56 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,187 +0,0 @@
-/*
- * svn-fast-export.c
- * ----------
- *  Walk through each revision of a local Subversion repository and export it
- *  in a stream that git-fast-import can consume.
- *
- * Author: Chris Lee <clee@kde.org>
- * License: MIT <http://www.opensource.org/licenses/mit-license.php>
- */
-
-#define _XOPEN_SOURCE
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <time.h>
-
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-#include <apr_lib.h>
-#include <apr_getopt.h>
-#include <apr_general.h>
-
-#include <svn_fs.h>
-#include <svn_repos.h>
-#include <svn_pools.h>
-#include <svn_types.h>
-
-#undef SVN_ERR
-#define SVN_ERR(expr) SVN_INT_ERR(expr)
-#define apr_sane_push(arr, contents) *(char **)apr_array_push(arr) = contents
-
-#define TRUNK "/trunk/"
-
-time_t get_epoch(char *svn_date)
-{
-    struct tm tm = {0};
-    char *date = malloc(strlen(svn_date) * sizeof(char *));
-    strncpy(date, svn_date, strlen(svn_date) - 8);
-    strptime(date, "%Y-%m-%dT%H:%M:%S", &tm);
-    free(date);
-    return mktime(&tm);
-}
-
-int dump_blob(svn_fs_root_t *root, char *full_path, apr_pool_t *pool)
-{
-    apr_size_t     len;
-    svn_stream_t   *stream, *outstream;
-    svn_filesize_t stream_length;
-
-    SVN_ERR(svn_fs_file_length(&stream_length, root, full_path, pool));
-    SVN_ERR(svn_fs_file_contents(&stream, root, full_path, pool));
-
-    fprintf(stdout, "data %lu\n", stream_length);
-    fflush(stdout);
-
-    SVN_ERR(svn_stream_for_stdout(&outstream, pool));
-    SVN_ERR(svn_stream_copy(stream, outstream, pool));
-
-    fprintf(stdout, "\n");
-    fflush(stdout);
-
-    return 0;
-}
-
-int export_revision(svn_revnum_t rev, svn_fs_t *fs, apr_pool_t *pool)
-{
-    unsigned int         mark;
-    const void           *key;
-    void                 *val;
-    char                 *path, *file_change;
-    apr_pool_t           *revpool;
-    apr_hash_t           *changes, *props;
-    apr_hash_index_t     *i;
-    apr_array_header_t   *file_changes;
-    svn_string_t         *author, *committer, *svndate, *svnlog;
-    svn_boolean_t        is_dir;
-    svn_fs_root_t        *fs_root;
-    svn_fs_path_change_t *change;
-
-    fprintf(stderr, "Exporting revision %ld... ", rev);
-
-    SVN_ERR(svn_fs_revision_root(&fs_root, fs, rev, pool));
-    SVN_ERR(svn_fs_paths_changed(&changes, fs_root, pool));
-    SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, pool));
-
-    revpool = svn_pool_create(pool);
-
-    file_changes = apr_array_make(pool, apr_hash_count(changes), sizeof(char *));
-    mark = 1;
-    for (i = apr_hash_first(pool, changes); i; i = apr_hash_next(i)) {
-        svn_pool_clear(revpool);
-        apr_hash_this(i, &key, NULL, &val);
-        path = (char *)key;
-        change = (svn_fs_path_change_t *)val;
-
-        SVN_ERR(svn_fs_is_dir(&is_dir, fs_root, path, revpool));
-
-        if (is_dir || strncmp(TRUNK, path, strlen(TRUNK))) {
-            continue;
-        }
-
-        if (change->change_kind == svn_fs_path_change_delete) {
-            apr_sane_push(file_changes, (char *)svn_string_createf(pool, "D %s", path + strlen(TRUNK))->data);
-        } else {
-            apr_sane_push(file_changes, (char *)svn_string_createf(pool, "M 644 :%u %s", mark, path + strlen(TRUNK))->data);
-            fprintf(stdout, "blob\nmark :%u\n", mark++);
-            dump_blob(fs_root, (char *)path, revpool);
-        }
-    }
-
-    if (file_changes->nelts == 0) {
-        fprintf(stderr, "skipping.\n");
-        svn_pool_destroy(revpool);
-        return 0;
-    }
-
-    author = apr_hash_get(props, "svn:author", APR_HASH_KEY_STRING);
-    if (svn_string_isempty(author))
-        author = svn_string_create("nobody", pool);
-    svndate = apr_hash_get(props, "svn:date", APR_HASH_KEY_STRING);
-    svnlog = apr_hash_get(props, "svn:log", APR_HASH_KEY_STRING);
-
-    fprintf(stdout, "commit refs/heads/master\n");
-    fprintf(stdout, "committer %s <%s@localhost> %ld -0000\n", author->data, author->data, get_epoch((char *)svndate->data));
-    fprintf(stdout, "data %d\n", svnlog->len);
-    fputs(svnlog->data, stdout);
-    fprintf(stdout, "\n");
-    fputs(apr_array_pstrcat(pool, file_changes, '\n'), stdout);
-    fprintf(stdout, "\n\n");
-    fflush(stdout);
-
-    svn_pool_destroy(revpool);
-
-    fprintf(stderr, "done!\n");
-
-    return 0;
-}
-
-int crawl_revisions(char *repos_path)
-{
-    apr_pool_t   *pool, *subpool;
-    svn_fs_t     *fs;
-    svn_repos_t  *repos;
-    svn_revnum_t youngest_rev, min_rev, max_rev, rev;
-
-    pool = svn_pool_create(NULL);
-
-    SVN_ERR(svn_fs_initialize(pool));
-    SVN_ERR(svn_repos_open(&repos, repos_path, pool));
-    if ((fs = svn_repos_fs(repos)) == NULL)
-        return -1;
-    SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));
-
-    min_rev = 1;
-    max_rev = youngest_rev;
-
-    subpool = svn_pool_create(pool);
-    for (rev = min_rev; rev <= max_rev; rev++) {
-        svn_pool_clear(subpool);
-        export_revision(rev, fs, subpool);
-    }
-
-    svn_pool_destroy(pool);
-
-    return 0;
-}
-
-int main(int argc, char *argv[])
-{
-    if (argc != 2) {
-        fprintf(stderr, "usage: %s REPOS_PATH\n", argv[0]);
-        return -1;
-    }
-
-    if (apr_initialize() != APR_SUCCESS) {
-        fprintf(stderr, "You lose at apr_initialize().\n");
-        return -1;
-    }
-
-    crawl_revisions(argv[1]);
-
-    apr_terminate();
-
-    return 0;
-}
--- a/extra/fast-export/svn-fast-export.py	Tue Jul 19 13:49:56 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-#!/usr/bin/python
-#
-# svn-fast-export.py
-# ----------
-#  Walk through each revision of a local Subversion repository and export it
-#  in a stream that git-fast-import can consume.
-#
-# Author: Chris Lee <clee@kde.org>
-# License: MIT <http://www.opensource.org/licenses/mit-license.php>
-
-trunk_path = '/trunk/'
-branches_path = '/branches/'
-tags_path = '/tags/'
-
-first_rev = 1
-final_rev = 0
-
-import sys, os.path
-from optparse import OptionParser
-from time import mktime, strptime
-from svn.fs import svn_fs_file_length, svn_fs_file_contents, svn_fs_is_dir, svn_fs_revision_root, svn_fs_youngest_rev, svn_fs_revision_proplist, svn_fs_paths_changed
-from svn.core import svn_pool_create, svn_pool_clear, svn_pool_destroy, svn_stream_for_stdout, svn_stream_copy, svn_stream_close, run_app
-from svn.repos import svn_repos_open, svn_repos_fs
-
-ct_short = ['M', 'A', 'D', 'R', 'X']
-
-def dump_file_blob(root, full_path, pool):
-    stream_length = svn_fs_file_length(root, full_path, pool)
-    stream = svn_fs_file_contents(root, full_path, pool)
-    sys.stdout.write("data %s\n" % stream_length)
-    sys.stdout.flush()
-    ostream = svn_stream_for_stdout(pool)
-    svn_stream_copy(stream, ostream, pool)
-    svn_stream_close(ostream)
-    sys.stdout.write("\n")
-
-
-def export_revision(rev, repo, fs, pool):
-    sys.stderr.write("Exporting revision %s... " % rev)
-
-    revpool = svn_pool_create(pool)
-    svn_pool_clear(revpool)
-
-    # Open a root object representing the youngest (HEAD) revision.
-    root = svn_fs_revision_root(fs, rev, revpool)
-
-    # And the list of what changed in this revision.
-    changes = svn_fs_paths_changed(root, revpool)
-
-    i = 1
-    marks = {}
-    file_changes = []
-
-    for path, change_type in changes.iteritems():
-        c_t = ct_short[change_type.change_kind]
-        if svn_fs_is_dir(root, path, revpool):
-            continue
-
-        if not path.startswith(trunk_path):
-            # We don't handle branches. Or tags. Yet.
-            pass
-        else:
-            if c_t == 'D':
-                file_changes.append("D %s" % path.replace(trunk_path, ''))
-            else:
-                marks[i] = path.replace(trunk_path, '')
-                file_changes.append("M 644 :%s %s" % (i, marks[i]))
-                sys.stdout.write("blob\nmark :%s\n" % i)
-                dump_file_blob(root, path, revpool)
-                i += 1
-
-    # Get the commit author and message
-    props = svn_fs_revision_proplist(fs, rev, revpool)
-
-    # Do the recursive crawl.
-    if props.has_key('svn:author'):
-        author = "%s <%s@localhost>" % (props['svn:author'], props['svn:author'])
-    else:
-        author = 'nobody <nobody@localhost>'
-
-    if len(file_changes) == 0:
-        svn_pool_destroy(revpool)
-        sys.stderr.write("skipping.\n")
-        return
-
-    svndate = props['svn:date'][0:-8]
-    commit_time = mktime(strptime(svndate, '%Y-%m-%dT%H:%M:%S'))
-    sys.stdout.write("commit refs/heads/master\n")
-    sys.stdout.write("committer %s %s -0000\n" % (author, int(commit_time)))
-    sys.stdout.write("data %s\n" % len(props['svn:log']))
-    sys.stdout.write(props['svn:log'])
-    sys.stdout.write("\n")
-    sys.stdout.write('\n'.join(file_changes))
-    sys.stdout.write("\n\n")
-
-    svn_pool_destroy(revpool)
-
-    sys.stderr.write("done!\n")
-
-    #if rev % 1000 == 0:
-    #    sys.stderr.write("gc: %s objects\n" % len(gc.get_objects()))
-    #    sleep(5)
-
-
-def crawl_revisions(pool, repos_path):
-    """Open the repository at REPOS_PATH, and recursively crawl all its
-    revisions."""
-    global final_rev
-
-    # Open the repository at REPOS_PATH, and get a reference to its
-    # versioning filesystem.
-    repos_obj = svn_repos_open(repos_path, pool)
-    fs_obj = svn_repos_fs(repos_obj)
-
-    # Query the current youngest revision.
-    youngest_rev = svn_fs_youngest_rev(fs_obj, pool)
-
-
-    first_rev = 1
-    if final_rev == 0:
-        final_rev = youngest_rev
-    for rev in xrange(first_rev, final_rev + 1):
-        export_revision(rev, repos_obj, fs_obj, pool)
-
-
-if __name__ == '__main__':
-    usage = '%prog [options] REPOS_PATH'
-    parser = OptionParser()
-    parser.set_usage(usage)
-    parser.add_option('-f', '--final-rev', help='Final revision to import', 
-                      dest='final_rev', metavar='FINAL_REV', type='int')
-    parser.add_option('-t', '--trunk-path', help='Path in repo to /trunk',
-                      dest='trunk_path', metavar='TRUNK_PATH')
-    parser.add_option('-b', '--branches-path', help='Path in repo to /branches',
-                      dest='branches_path', metavar='BRANCHES_PATH')
-    parser.add_option('-T', '--tags-path', help='Path in repo to /tags',
-                      dest='tags_path', metavar='TAGS_PATH')
-    (options, args) = parser.parse_args()
-
-    if options.trunk_path != None:
-        trunk_path = options.trunk_path
-    if options.branches_path != None:
-        branches_path = options.branches_path
-    if options.tags_path != None:
-        tags_path = options.tags_path
-    if options.final_rev != None:
-        final_rev = options.final_rev
-
-    if len(args) != 1:
-        parser.print_help()
-        sys.exit(2)
-
-    # Canonicalize (enough for Subversion, at least) the repository path.
-    repos_path = os.path.normpath(args[0])
-    if repos_path == '.': 
-        repos_path = ''
-
-    # Call the app-wrapper, which takes care of APR initialization/shutdown
-    # and the creation and cleanup of our top-level memory pool.
-    run_app(crawl_revisions, repos_path)