git-svn: cleanup: put SVN workarounds into their own namespace
authorEric Wong <normalperson@yhbt.net>
Wed, 10 Jan 2007 09:22:38 +0000 (01:22 -0800)
committerEric Wong <normalperson@yhbt.net>
Fri, 23 Feb 2007 08:57:08 +0000 (00:57 -0800)
Force some svn_ra functions to use a temporary pool via wrapper

This cleans up the code a bit by removing explicit instances of
pool allocation and deallocation and providing wrapper functions
that make use of temporary pools.

I've also added an explicit pool usage when creating the commit
editor for commit-diff where get_commit_editor can be called
multiple times with the same pool previously.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
git-svn.perl

index fcef05c2eec30a116cb7d7a44d3d5ebf087759a2..5a3a8777097e135ab072000df4d2b844fd913c5b 100755 (executable)
@@ -4,7 +4,7 @@
 use warnings;
 use strict;
 use vars qw/   $AUTHOR $VERSION
-               $SVN_URL $SVN_INFO $SVN_WC $SVN_UUID
+               $SVN_URL
                $GIT_SVN_INDEX $GIT_SVN
                $GIT_DIR $GIT_SVN_DIR $REVDB/;
 $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
@@ -38,6 +38,7 @@ require SVN::Delta;
 if ($SVN::Core::VERSION lt '1.1.0') {
        fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)\n";
 }
+push @Git::SVN::Ra::ISA, 'SVN::Ra';
 push @SVN::Git::Editor::ISA, 'SVN::Delta::Editor';
 push @SVN::Git::Fetcher::ISA, 'SVN::Delta::Editor';
 use Carp qw/croak/;
@@ -63,16 +64,16 @@ my $_esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
 my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
        $_find_copies_harder, $_l, $_cp_similarity, $_cp_remote,
        $_repack, $_repack_nr, $_repack_flags, $_q,
-       $_message, $_file, $_follow_parent, $_no_metadata,
+       $_message, $_file, $_no_metadata,
        $_template, $_shared, $_no_default_regex, $_no_graft_copy,
        $_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,
        $_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m,
        $_merge, $_strategy, $_dry_run, $_ignore_nodate, $_non_recursive,
-       $_config_dir,
        $_pager, $_color, $_prefix);
 my (@_branch_from, %tree_map, %users, %rusers, %equiv);
 my ($_svn_can_do_switch);
 my @repo_path_split_cache;
+use vars qw/$_follow_parent/;
 
 my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext,
                'branch|b=s' => \@_branch_from,
@@ -83,7 +84,7 @@ my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext,
                'no-metadata' => \$_no_metadata,
                'quiet|q' => \$_q,
                'username=s' => \$Git::SVN::Prompt::_username,
-               'config-dir=s' => \$_config_dir,
+               'config-dir=s' => \$Git::SVN::Ra::config_dir,
                'no-auth-cache' => \$Git::SVN::Prompt::_no_auth_cache,
                'ignore-nodate' => \$_ignore_nodate,
                'repack-flags|repack-args|repack-opts=s' => \$_repack_flags);
@@ -131,7 +132,7 @@ my %cmd = (
                        { %multi_opts, %init_opts,
                         'revision|r=i' => \$_revision,
                         'username=s' => \$Git::SVN::Prompt::_username,
-                        'config-dir=s' => \$_config_dir,
+                        'config-dir=s' => \$Git::SVN::Ra::config_dir,
                         'no-auth-cache' => \$Git::SVN::Prompt::_no_auth_cache,
                         'prefix=s' => \$_prefix,
                        } ],
@@ -236,6 +237,7 @@ sub rebuild {
        my ($rev_list, $ctx) = command_output_pipe("rev-list",
                                                   "refs/remotes/$GIT_SVN");
        my $latest;
+       my $svn_uuid;
        while (<$rev_list>) {
                chomp;
                my $c = $_;
@@ -251,7 +253,7 @@ sub rebuild {
 
                # if we merged or otherwise started elsewhere, this is
                # how we break out of it
-               next if (defined $SVN_UUID && ($uuid ne $SVN_UUID));
+               next if (defined $svn_uuid && ($uuid ne $svn_uuid));
                next if (defined $SVN_URL && defined $url && ($url ne $SVN_URL));
 
                unless (defined $latest) {
@@ -259,7 +261,7 @@ sub rebuild {
                                croak "SVN repository location required: $url\n";
                        }
                        $SVN_URL ||= $url;
-                       $SVN_UUID ||= $uuid;
+                       $svn_uuid ||= $uuid;
                        setup_git_svn();
                        $latest = $rev;
                }
@@ -310,7 +312,7 @@ sub fetch {
 sub fetch_lib {
        my (@parents) = @_;
        $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url");
-       $SVN ||= libsvn_connect($SVN_URL);
+       $SVN ||= Git::SVN::Ra->new($SVN_URL);
        my ($last_rev, $last_commit) = svn_grab_base_rev();
        my ($base, $head) = libsvn_parse_revision($last_rev);
        if ($base > $head) {
@@ -322,7 +324,6 @@ sub fetch_lib {
        # after processing a revision and SVN stuff seems to leak
        my $inc = 1000;
        my ($min, $max) = ($base, $head < $base+$inc ? $head : $base+$inc);
-       read_uuid();
        if (defined $last_commit) {
                unless (-e $GIT_SVN_INDEX) {
                        command_noisy('read-tree', $last_commit);
@@ -352,8 +353,7 @@ sub fetch_lib {
                        # performance sucks with it enabled, so it's much
                        # faster to fetch revision ranges instead of relying
                        # on the limiter.
-                       libsvn_get_log(libsvn_dup_ra($SVN), [''],
-                                       $min, $max, 0, 1, 1,
+                       $SVN->dup->get_log([''], $min, $max, 0, 1, 1,
                                sub {
                                        my $log_msg;
                                        if ($last_commit) {
@@ -378,7 +378,7 @@ sub fetch_lib {
                $min = $max + 1;
                $max += $inc;
                $max = $head if ($max > $head);
-               $SVN = libsvn_connect($SVN_URL);
+               $SVN = Git::SVN::Ra->new($SVN_URL);
        }
        restore_index($index);
        return { revision => $last_rev, commit => $last_commit };
@@ -424,8 +424,6 @@ sub commit_lib {
                                " current: $fetched->{revision}\n";
                exit 1;
        }
-       read_uuid();
-       my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();
        my $commit_msg = "$GIT_SVN_DIR/.svn-commit.tmp.$$";
 
        my $repo;
@@ -437,9 +435,10 @@ sub commit_lib {
                # can't track down... (it's probably in the SVN code)
                defined(my $pid = open my $fh, '-|') or croak $!;
                if (!$pid) {
+                       my $pool = SVN::Pool->new;
                        my $ed = SVN::Git::Editor->new(
                                        {       r => $r_last,
-                                               ra => libsvn_dup_ra($SVN),
+                                               ra => $SVN->dup,
                                                c => $c,
                                                svn_path => $SVN->{svn_path},
                                        },
@@ -451,8 +450,7 @@ sub commit_lib {
                                                                $log_msg->{msg},
                                                                $r_last,
                                                                $cmt_last)
-                                               },
-                                               @lock)
+                                               }, $pool)
                                        );
                        my $mods = libsvn_checkout_tree($cmt_last, $c, $ed);
                        if (@$mods == 0) {
@@ -461,6 +459,7 @@ sub commit_lib {
                        } else {
                                $ed->close_edit;
                        }
+                       $pool->clear;
                        exit 0;
                }
                my ($r_new, $cmt_new, $no);
@@ -534,7 +533,7 @@ sub dcommit {
 sub show_ignore {
        $SVN_URL ||= file_to_s("$GIT_SVN_DIR/info/url");
        my $repo;
-       $SVN ||= libsvn_connect($SVN_URL);
+       $SVN ||= Git::SVN::Ra->new($SVN_URL);
        my $r = defined $_revision ? $_revision : $SVN->get_latest_revnum;
        libsvn_traverse_ignore(\*STDOUT, '', $r);
 }
@@ -716,16 +715,16 @@ sub commit_diff {
                $_message ||= get_commit_message($tb,
                                        "$GIT_DIR/.svn-commit.tmp.$$")->{msg};
        }
-       $SVN ||= libsvn_connect($SVN_URL);
+       $SVN ||= Git::SVN::Ra->new($SVN_URL);
        if ($r eq 'HEAD') {
                $r = $SVN->get_latest_revnum;
        } elsif ($r !~ /^\d+$/) {
                die "revision argument: $r not understood by git-svn\n";
        }
-       my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();
        my $rev_committed;
+       my $pool = SVN::Pool->new;
        my $ed = SVN::Git::Editor->new({        r => $r,
-                                               ra => libsvn_dup_ra($SVN),
+                                               ra => $SVN->dup,
                                                c => $tb,
                                                svn_path => $SVN->{svn_path}
                                        },
@@ -733,7 +732,8 @@ sub commit_diff {
                                        sub {
                                                $rev_committed = $_[0];
                                                print "Committed $_[0]\n";
-                                       }, @lock)
+                                       },
+                                       $pool)
                                );
        eval {
                my $mods = libsvn_checkout_tree($ta, $tb, $ed);
@@ -744,6 +744,7 @@ sub commit_diff {
                        $ed->close_edit;
                }
        };
+       $pool->clear;
        fatal "$@\n" if $@;
        $_message = $_file = undef;
        return $rev_committed;
@@ -1012,7 +1013,7 @@ sub graft_file_copy_lib {
        my $tree_paths = $l_map->{$u};
        my $pfx = common_prefix([keys %$tree_paths]);
        my ($repo, $path) = repo_path_split($u.$pfx);
-       $SVN = libsvn_connect($repo);
+       $SVN = Git::SVN::Ra->new($repo);
 
        my ($base, $head) = libsvn_parse_revision();
        my $inc = 1000;
@@ -1020,14 +1021,11 @@ sub graft_file_copy_lib {
        my $eh = $SVN::Error::handler;
        $SVN::Error::handler = \&libsvn_skip_unknown_revs;
        while (1) {
-               my $pool = SVN::Pool->new;
-               libsvn_get_log(libsvn_dup_ra($SVN), [$path],
-                              $min, $max, 0, 2, 1,
+               $SVN->dup->get_log([$path], $min, $max, 0, 2, 1,
                        sub {
                                libsvn_graft_file_copies($grafts, $tree_paths,
                                                        $path, @_);
-                       }, $pool);
-               $pool->clear;
+                       });
                last if ($max >= $head);
                $min = $max + 1;
                $max += $inc;
@@ -1095,13 +1093,6 @@ sub graft_merge_msg {
        }
 }
 
-sub read_uuid {
-       return if $SVN_UUID;
-       my $pool = SVN::Pool->new;
-       $SVN_UUID = $SVN->get_uuid($pool);
-       $pool->clear;
-}
-
 sub verify_ref {
        my ($ref) = @_;
        eval { command_oneline([ 'rev-parse', '--verify', $ref ],
@@ -1119,7 +1110,7 @@ sub repo_path_split {
                        return ($u, $full_url);
                }
        }
-       my $tmp = libsvn_connect($full_url);
+       my $tmp = Git::SVN::Ra->new($full_url);
        return ($tmp->{repos_root}, $tmp->{svn_path});
 }
 
@@ -1371,10 +1362,10 @@ sub git_commit {
                        }
                        next if $skip;
                        my ($url_p, $r_p, $uuid_p) = cmt_metadata($p);
-                       next if (($SVN_UUID eq $uuid_p) &&
+                       next if (($SVN->uuid eq $uuid_p) &&
                                                ($log_msg->{revision} > $r_p));
                        next if (defined $url_p && defined $SVN_URL &&
-                                               ($SVN_UUID eq $uuid_p) &&
+                                               ($SVN->uuid eq $uuid_p) &&
                                                ($url_p eq $SVN_URL));
                        push @tmp_parents, $p;
                }
@@ -1394,8 +1385,8 @@ sub git_commit {
                                                                or croak $!;
        print $msg_fh $log_msg->{msg} or croak $!;
        unless ($_no_metadata) {
-               print $msg_fh "\ngit-svn-id: $SVN_URL\@$log_msg->{revision}",
-                                       " $SVN_UUID\n" or croak $!;
+               print $msg_fh "\ngit-svn-id: $SVN_URL\@$log_msg->{revision} ",
+                                       $SVN->uuid,"\n" or croak $!;
        }
        $msg_fh->flush == 0 or croak $!;
        close $msg_fh or croak $!;
@@ -1429,7 +1420,7 @@ sub set_commit_env {
                $author = '(no author)';
        }
        my ($name,$email) = defined $users{$author} ?  @{$users{$author}}
-                               : ($author,"$author\@$SVN_UUID");
+                               : ($author,$author . '@' . $SVN->uuid);
        $ENV{GIT_AUTHOR_NAME} = $ENV{GIT_COMMITTER_NAME} = $name;
        $ENV{GIT_AUTHOR_EMAIL} = $ENV{GIT_COMMITTER_EMAIL} = $email;
        $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_msg->{date};
@@ -1589,7 +1580,6 @@ sub init_vars {
        $REVDB = "$GIT_SVN_DIR/.rev_db";
        $GIT_SVN_INDEX = "$GIT_SVN_DIR/index";
        $SVN_URL = undef;
-       $SVN_WC = "$GIT_SVN_DIR/tree";
        %tree_map = ();
 }
 
@@ -2042,60 +2032,6 @@ sub _read_password {
 
 package main;
 
-sub libsvn_connect {
-       my ($url) = @_;
-       SVN::_Core::svn_config_ensure($_config_dir, undef);
-       my ($baton, $callbacks) = SVN::Core::auth_open_helper([
-           SVN::Client::get_simple_provider(),
-           SVN::Client::get_ssl_server_trust_file_provider(),
-           SVN::Client::get_simple_prompt_provider(
-             \&Git::SVN::Prompt::simple, 2),
-           SVN::Client::get_ssl_client_cert_prompt_provider(
-             \&Git::SVN::Prompt::ssl_client_cert, 2),
-           SVN::Client::get_ssl_client_cert_pw_prompt_provider(
-             \&Git::SVN::Prompt::ssl_client_cert_pw, 2),
-           SVN::Client::get_username_provider(),
-           SVN::Client::get_ssl_server_trust_prompt_provider(
-             \&Git::SVN::Prompt::ssl_server_trust),
-           SVN::Client::get_username_prompt_provider(
-             \&Git::SVN::username, 2),
-         ]);
-       my $config = SVN::Core::config_get_config($_config_dir);
-       my $ra = SVN::Ra->new(url => $url, auth => $baton,
-                             config => $config,
-                             pool => SVN::Pool->new,
-                             auth_provider_callbacks => $callbacks);
-       $ra->{svn_path} = $url;
-       $ra->{repos_root} = $ra->get_repos_root;
-       $ra->{svn_path} =~ s#^\Q$ra->{repos_root}\E/*##;
-       push @repo_path_split_cache, qr/^(\Q$ra->{repos_root}\E)/;
-       return $ra;
-}
-
-sub libsvn_can_do_switch {
-       unless (defined $_svn_can_do_switch) {
-               my $pool = SVN::Pool->new;
-               my $rep = eval {
-                       $SVN->do_switch(1, '', 0, $SVN->{url},
-                                       SVN::Delta::Editor->new, $pool);
-               };
-               if ($@) {
-                       $_svn_can_do_switch = 0;
-               } else {
-                       $rep->abort_report($pool);
-                       $_svn_can_do_switch = 1;
-               }
-               $pool->clear;
-       }
-       $_svn_can_do_switch;
-}
-
-sub libsvn_dup_ra {
-       my ($ra) = @_;
-       SVN::Ra->new(map { $_ => $ra->{$_} } qw/config url
-                    auth auth_provider_callbacks repos_root svn_path/);
-}
-
 sub uri_encode {
        my ($f) = @_;
        $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg;
@@ -2165,14 +2101,12 @@ sub libsvn_log_entry {
        }
 
        # revprops (make this optional? it's an extra network trip...)
-       my $pool = SVN::Pool->new;
-       my $rp = $SVN->rev_proplist($rev, $pool);
+       my $rp = $SVN->rev_proplist($rev);
        foreach (sort keys %$rp) {
                next if /^svn:(?:author|date|log)$/;
                print $un "  rev_prop: ", uri_encode($_), ' ',
                          uri_encode($rp->{$_}), "\n";
        }
-       $pool->clear;
        close $un or croak $!;
 
        { revision => $rev, date => "+0000 $Y-$m-$d $H:$M:$S",
@@ -2182,15 +2116,9 @@ sub libsvn_log_entry {
 
 sub libsvn_fetch {
        my ($last_commit, $paths, $rev, $author, $date, $msg) = @_;
-       my $pool = SVN::Pool->new;
        my $ed = SVN::Git::Fetcher->new({ c => $last_commit, q => $_q });
-       my $reporter = $SVN->do_update($rev, '', 1, $ed, $pool);
-       my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
        my (undef, $last_rev, undef) = cmt_metadata($last_commit);
-       $reporter->set_path('', $last_rev, 0, @lock, $pool);
-       $reporter->finish_report($pool);
-       $pool->clear;
-       unless ($ed->{git_commit_ok}) {
+       unless ($SVN->gs_do_update($last_rev, $rev, '', 1, $ed)) {
                die "SVN connection failed somewhere...\n";
        }
        libsvn_log_entry($rev, $author, $date, $msg, [$last_commit], $ed);
@@ -2250,8 +2178,7 @@ sub libsvn_parse_revision {
 sub libsvn_traverse_ignore {
        my ($fh, $path, $r) = @_;
        $path =~ s#^/+##g;
-       my $pool = SVN::Pool->new;
-       my ($dirent, undef, $props) = $SVN->get_dir($path, $r, $pool);
+       my ($dirent, undef, $props) = $SVN->get_dir($path, $r);
        my $p = $path;
        $p =~ s#^\Q$SVN->{svn_path}\E/##;
        print $fh length $p ? "\n# $p\n" : "\n# /\n";
@@ -2270,7 +2197,6 @@ sub libsvn_traverse_ignore {
                next if $dirent->{$_}->kind != $SVN::Node::dir;
                libsvn_traverse_ignore($fh, "$path/$_", $r);
        }
-       $pool->clear;
 }
 
 sub revisions_eq {
@@ -2278,10 +2204,7 @@ sub revisions_eq {
        return 1 if $r0 == $r1;
        my $nr = 0;
        # should be OK to use Pool here (r1 - r0) should be small
-       my $pool = SVN::Pool->new;
-       libsvn_get_log($SVN, [$path], $r0, $r1,
-                       0, 0, 1, sub {$nr++}, $pool);
-       $pool->clear;
+       $SVN->get_log([$path], $r0, $r1, 0, 0, 1, sub {$nr++});
        return 0 if ($nr > 1);
        return 1;
 }
@@ -2337,40 +2260,23 @@ sub libsvn_find_parent_branch {
                unlink $GIT_SVN_INDEX;
                print STDERR "Found branch parent: ($GIT_SVN) $parent\n";
                command_noisy('read-tree', $parent);
-               unless (libsvn_can_do_switch()) {
+               unless ($SVN->can_do_switch) {
                        return _libsvn_new_tree($paths, $rev, $author, $date,
                                                $msg, [$parent]);
                }
                # do_switch works with svn/trunk >= r22312, but that is not
                # included with SVN 1.4.2 (the latest version at the moment),
                # so we can't rely on it.
-               my $ra = libsvn_connect("$url/$branch_from");
+               my $ra = Git::SVN::Ra->new("$url/$branch_from");
                my $ed = SVN::Git::Fetcher->new({c => $parent, q => $_q });
-               my $pool = SVN::Pool->new;
-               my $reporter = $ra->do_switch($rev, '', 1, $SVN->{url},
-                                             $ed, $pool);
-               my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
-               $reporter->set_path('', $r0, 0, @lock, $pool);
-               $reporter->finish_report($pool);
-               $pool->clear;
-               unless ($ed->{git_commit_ok}) {
-                       die "SVN connection failed somewhere...\n";
-               }
+               $ra->gs_do_switch($r0, $rev, '', 1, $SVN->{url}, $ed) or
+                                  die "SVN connection failed somewhere...\n";
                return libsvn_log_entry($rev, $author, $date, $msg, [$parent]);
        }
        print STDERR "Nope, branch point not imported or unknown\n";
        return undef;
 }
 
-sub libsvn_get_log {
-       my ($ra, @args) = @_;
-       $args[4]-- if $args[4] && ! $_follow_parent;
-       if ($SVN::Core::VERSION le '1.2.0') {
-               splice(@args, 3, 1);
-       }
-       $ra->get_log(@args);
-}
-
 sub libsvn_new_tree {
        if (my $log_entry = libsvn_find_parent_branch(@_)) {
                return $log_entry;
@@ -2381,14 +2287,8 @@ sub libsvn_new_tree {
 
 sub _libsvn_new_tree {
        my ($paths, $rev, $author, $date, $msg, $parents) = @_;
-       my $pool = SVN::Pool->new;
        my $ed = SVN::Git::Fetcher->new({q => $_q});
-       my $reporter = $SVN->do_update($rev, '', 1, $ed, $pool);
-       my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
-       $reporter->set_path('', $rev, 1, @lock, $pool);
-       $reporter->finish_report($pool);
-       $pool->clear;
-       unless ($ed->{git_commit_ok}) {
+       unless ($SVN->gs_do_update($rev, $rev, '', 1, $ed)) {
                die "SVN connection failed somewhere...\n";
        }
        libsvn_log_entry($rev, $author, $date, $msg, $parents, $ed);
@@ -2474,21 +2374,18 @@ sub libsvn_commit_cb {
 
 sub libsvn_ls_fullurl {
        my $fullurl = shift;
-       my $ra = libsvn_connect($fullurl);
+       my $ra = Git::SVN::Ra->new($fullurl);
        my @ret;
-       my $pool = SVN::Pool->new;
        my $r = defined $_revision ? $_revision : $ra->get_latest_revnum;
-       my ($dirent, undef, undef) = $ra->get_dir('', $r, $pool);
+       my ($dirent, undef, undef) = $ra->get_dir('', $r);
        foreach my $d (sort keys %$dirent) {
                if ($dirent->{$d}->kind == $SVN::Node::dir) {
                        push @ret, "$d/"; # add '/' for compat with cli svn
                }
        }
-       $pool->clear;
        return @ret;
 }
 
-
 sub libsvn_skip_unknown_revs {
        my $err = shift;
        my $errno = $err->apr_err();
@@ -2866,9 +2763,7 @@ sub rmdirs {
 
 sub open_or_add_dir {
        my ($self, $full_path, $baton) = @_;
-       my $p = SVN::Pool->new;
-       my $t = $self->{ra}->check_path($full_path, $self->{r}, $p);
-       $p->clear;
+       my $t = $self->{ra}->check_path($full_path, $self->{r});
        if ($t == $SVN::Node::none) {
                return $self->add_directory($full_path, $baton,
                                                undef, -1, $self->{pool});
@@ -3023,6 +2918,135 @@ sub abort_edit {
        $self->{pool}->clear;
 }
 
+package Git::SVN::Ra;
+use vars qw/@ISA $config_dir/;
+use strict;
+use warnings;
+my ($can_do_switch);
+
+BEGIN {
+       # enforce temporary pool usage for some simple functions
+       my $e;
+       foreach (qw/get_latest_revnum rev_proplist get_file
+                   check_path get_dir get_uuid get_repos_root/) {
+               $e .= "sub $_ {
+                       my \$self = shift;
+                       my \$pool = SVN::Pool->new;
+                       my \@ret = \$self->SUPER::$_(\@_,\$pool);
+                       \$pool->clear;
+                       wantarray ? \@ret : \$ret[0]; }\n";
+       }
+       eval $e;
+}
+
+sub new {
+       my ($class, $url) = @_;
+       SVN::_Core::svn_config_ensure($config_dir, undef);
+       my ($baton, $callbacks) = SVN::Core::auth_open_helper([
+           SVN::Client::get_simple_provider(),
+           SVN::Client::get_ssl_server_trust_file_provider(),
+           SVN::Client::get_simple_prompt_provider(
+             \&Git::SVN::Prompt::simple, 2),
+           SVN::Client::get_ssl_client_cert_prompt_provider(
+             \&Git::SVN::Prompt::ssl_client_cert, 2),
+           SVN::Client::get_ssl_client_cert_pw_prompt_provider(
+             \&Git::SVN::Prompt::ssl_client_cert_pw, 2),
+           SVN::Client::get_username_provider(),
+           SVN::Client::get_ssl_server_trust_prompt_provider(
+             \&Git::SVN::Prompt::ssl_server_trust),
+           SVN::Client::get_username_prompt_provider(
+             \&Git::SVN::Prompt::username, 2),
+         ]);
+       my $config = SVN::Core::config_get_config($config_dir);
+       my $self = SVN::Ra->new(url => $url, auth => $baton,
+                             config => $config,
+                             pool => SVN::Pool->new,
+                             auth_provider_callbacks => $callbacks);
+       $self->{svn_path} = $url;
+       $self->{repos_root} = $self->get_repos_root;
+       $self->{svn_path} =~ s#^\Q$self->{repos_root}\E/*##;
+       bless $self, $class;
+}
+
+sub DESTROY {
+       my $self = shift;
+       $self->{pool}->clear if $self->{pool};
+       $self->SUPER::DESTROY(@_);
+}
+
+sub dup {
+       my ($self) = @_;
+       my $dup = SVN::Ra->new(pool => SVN::Pool->new,
+                               map { $_ => $self->{$_} } qw/config url
+                    auth auth_provider_callbacks repos_root svn_path/);
+       bless $dup, ref $self;
+}
+
+sub get_log {
+       my ($self, @args) = @_;
+       my $pool = SVN::Pool->new;
+       $args[4]-- if $args[4] && ! $::_follow_parent;
+       splice(@args, 3, 1) if ($SVN::Core::VERSION le '1.2.0');
+       my $ret = $self->SUPER::get_log(@args, $pool);
+       $pool->clear;
+       $ret;
+}
+
+sub get_commit_editor {
+       my ($self, $msg, $cb, $pool) = @_;
+       my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();
+       $self->SUPER::get_commit_editor($msg, $cb, @lock, $pool);
+}
+
+sub uuid {
+       my ($self) = @_;
+       $self->{uuid} ||= $self->get_uuid;
+}
+
+sub gs_do_update {
+       my ($self, $rev_a, $rev_b, $path, $recurse, $editor) = @_;
+       my $pool = SVN::Pool->new;
+       my $reporter = $self->do_update($rev_b, $path, $recurse,
+                                       $editor, $pool);
+       my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
+       my $new = ($rev_a == $rev_b);
+       $reporter->set_path($path, $rev_a, $new, @lock, $pool);
+       $reporter->finish_report($pool);
+       $pool->clear;
+       $editor->{git_commit_ok};
+}
+
+sub gs_do_switch {
+       my ($self, $rev_a, $rev_b, $path, $recurse, $url_b, $editor) = @_;
+       my $pool = SVN::Pool->new;
+       my $reporter = $self->do_switch($rev_b, $path, $recurse,
+                                       $url_b, $editor, $pool);
+       my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
+       $reporter->set_path($path, $rev_a, 0, @lock, $pool);
+       $reporter->finish_report($pool);
+       $pool->clear;
+       $editor->{git_commit_ok};
+}
+
+sub can_do_switch {
+       my $self = shift;
+       unless (defined $can_do_switch) {
+               my $pool = SVN::Pool->new;
+               my $rep = eval {
+                       $self->do_switch(1, '', 0, $self->{url},
+                                        SVN::Delta::Editor->new, $pool);
+               };
+               if ($@) {
+                       $can_do_switch = 0;
+               } else {
+                       $rep->abort_report($pool);
+                       $can_do_switch = 1;
+               }
+               $pool->clear;
+       }
+       $can_do_switch;
+}
+
 __END__
 
 Data structures: