$AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
$VERSION = '@@GIT_VERSION@@';
+my $git_dir_user_set = 1 if defined $ENV{GIT_DIR};
$ENV{GIT_DIR} ||= '.git';
$Git::SVN::default_repo_id = 'svn';
$Git::SVN::default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn';
%remote_opts );
my ($_trunk, $_tags, $_branches);
+my %icv;
my %init_opts = ( 'template=s' => \$_template, 'shared:s' => \$_shared,
'trunk|T=s' => \$_trunk, 'tags|t=s' => \$_tags,
'branches|b=s' => \$_branches, 'prefix=s' => \$_prefix,
+ 'no-metadata' => sub { $icv{noMetadata} = 1 },
+ 'use-svm-props' => sub { $icv{useSvmProps} = 1 },
+ 'use-svnsync-props' => sub { $icv{useSvnsyncProps} = 1 },
+ 'rewrite-root=s' => sub { $icv{rewriteRoot} = $_[1] },
%remote_opts );
my %cmt_opts = ( 'edit|e' => \$_edit,
'rmdir' => \$SVN::Git::Editor::_rmdir,
my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version,
'minimize-connections' => \$Git::SVN::Migration::_minimize,
'id|i=s' => \$Git::SVN::default_ref_id,
- 'svn-remote|remote|R=s' => \$Git::SVN::default_repo_id);
+ 'svn-remote|remote|R=s' => sub {
+ $Git::SVN::no_reuse_existing = 1;
+ $Git::SVN::default_repo_id = $_[1] });
exit 1 if (!$rv && $cmd ne 'log');
usage(0) if $_help;
version() if $_version;
usage(1) unless defined $cmd;
load_authors() if $_authors;
+
+# make sure we're always running
+unless ($cmd =~ /(?:clone|init|multi-init)$/) {
+ unless (-d $ENV{GIT_DIR}) {
+ if ($git_dir_user_set) {
+ die "GIT_DIR=$ENV{GIT_DIR} explicitly set, ",
+ "but it is not a directory\n";
+ }
+ my $git_dir = delete $ENV{GIT_DIR};
+ chomp(my $cdup = command_oneline(qw/rev-parse --show-cdup/));
+ unless (length $cdup) {
+ die "Already at toplevel, but $git_dir ",
+ "not found '$cdup'\n";
+ }
+ chdir $cdup or die "Unable to chdir up to '$cdup'\n";
+ unless (-d $git_dir) {
+ die "$git_dir still not found after going to ",
+ "'$cdup'\n";
+ }
+ $ENV{GIT_DIR} = $git_dir;
+ }
+}
unless ($cmd =~ /^(?:clone|init|multi-init|commit-diff)$/) {
Git::SVN::Migration::migration_check();
}
}
command_noisy(@init_db);
}
+ my $set;
+ my $pfx = "svn-remote.$Git::SVN::default_repo_id";
+ foreach my $i (keys %icv) {
+ die "'$set' and '$i' cannot both be set\n" if $set;
+ next unless defined $icv{$i};
+ command_noisy('config', "$pfx.$i", $icv{$i});
+ $set = $i;
+ }
}
sub init_subdir {
my $repo_path = shift or return;
mkpath([$repo_path]) unless -d $repo_path;
chdir $repo_path or die "Couldn't chdir to $repo_path: $!\n";
- $ENV{GIT_DIR} = $repo_path . "/.git";
+ $ENV{GIT_DIR} = '.git';
}
sub cmd_clone {
$url !~ m#^[a-z\+]+://#) {
$path = $url;
}
- warn "--path: $path\n" if defined $path;
$path = basename($url) if !defined $path || !length $path;
- warn "++path: $path\n" if defined $path;
- mkpath([$path]);
- chdir $path or die "Couldn't chdir to $path\n";
- cmd_init(@_);
+ cmd_init($url, $path);
Git::SVN::fetch_all($Git::SVN::default_repo_id);
}
}
sub cmd_show_ignore {
- my $gs = Git::SVN->new;
+ my $url = (::working_head_info('HEAD'))[0];
+ my $gs = Git::SVN->find_by_url($url) || Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
$gs->traverse_ignore(\*STDOUT, '', $r);
}
unless (defined $_trunk || defined $_branches || defined $_tags) {
usage(1);
}
- do_git_init_db();
$_prefix = '' unless defined $_prefix;
if (defined $url) {
$url =~ s#/+$##;
init_subdir(@_);
}
+ do_git_init_db();
if (defined $_trunk) {
my $trunk_ref = $_prefix . 'trunk';
# try both old-style and new-style lookups:
use warnings;
use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
$_repack $_repack_flags $_use_svm_props $_head
- $_use_svnsync_props/;
+ $_use_svnsync_props $no_reuse_existing/;
use Carp qw/croak/;
use File::Path qw/mkpath/;
use File::Copy qw/copy/;
sub find_existing_remote {
my ($url, $remotes) = @_;
+ return undef if $no_reuse_existing;
my $existing;
foreach my $repo_id (keys %$remotes) {
my $u = $remotes->{$repo_id}->{url} or next;
sub find_by_url { # repos_root and, path are optional
my ($class, $full_url, $repos_root, $path) = @_;
+ return undef unless defined $full_url;
my $remotes = read_all_remotes();
if (defined $full_url && defined $repos_root && !defined $path) {
$path = $full_url;
$svm = {
source => tmp_config('--get', "$section.svm-source"),
uuid => tmp_config('--get', "$section.svm-uuid"),
+ replace => tmp_config('--get', "$section.svm-replace"),
}
};
- $self->{svm} = $svm if ($svm && $svm->{source} && $svm->{uuid});
+ if ($svm && $svm->{source} && $svm->{uuid} && $svm->{replace}) {
+ $self->{svm} = $svm;
+ }
$self->{svm};
}
return $ra if $self->svm;
my @err = ( "useSvmProps set, but failed to read SVM properties\n",
- "(svm:source, svm:mirror, svm:mirror) ",
+ "(svm:source, svm:uuid) ",
"from the following URLs:\n" );
sub read_svm_props {
- my ($self, $props) = @_;
+ my ($self, $ra, $path, $r) = @_;
+ my $props = ($ra->get_dir($path, $r))[2];
my $src = $props->{'svm:source'};
- my $mirror = $props->{'svm:mirror'};
my $uuid = $props->{'svm:uuid'};
- return undef if (!$src || !$mirror || !$uuid);
+ return undef if (!$src || !$uuid);
- chomp($src, $mirror, $uuid);
+ chomp($src, $uuid);
$uuid =~ m{^[0-9a-f\-]{30,}$}
or die "doesn't look right - svm:uuid is '$uuid'\n";
- # don't know what a '!' is there for, also the
- # username is of no interest
- $src =~ s{/?!$}{$mirror};
+
+ # the '!' is used to mark the repos_root!/relative/path
+ $src =~ s{/?!/?}{/};
$src =~ s{/+$}{}; # no trailing slashes please
+ # username is of no interest
$src =~ s{(^[a-z\+]*://)[^/@]*@}{$1};
+ my $replace = $ra->{url};
+ $replace .= "/$path" if length $path;
+
my $section = "svn-remote.$self->{repo_id}";
- tmp_config('--add', "$section.svm-source", $src);
- tmp_config('--add', "$section.svm-uuid", $uuid);
- $self->{svm} = { source => $src , uuid => $uuid };
- return 1;
+ tmp_config("$section.svm-source", $src);
+ tmp_config("$section.svm-replace", $replace);
+ tmp_config("$section.svm-uuid", $uuid);
+ $self->{svm} = {
+ source => $src,
+ uuid => $uuid,
+ replace => $replace
+ };
}
my $r = $ra->get_latest_revnum;
my $path = $self->{path};
- my @tried_a = ($path);
+ my %tried;
while (length $path) {
- if ($self->read_svm_props(($ra->get_dir($path, $r))[2])) {
- return $ra;
+ unless ($tried{"$self->{url}/$path"}) {
+ return $ra if $self->read_svm_props($ra, $path, $r);
+ $tried{"$self->{url}/$path"} = 1;
}
- $path =~ s#/?[^/]+$## && push @tried_a, $path;
- }
- if ($self->read_svm_props(($ra->get_dir('', $r))[2])) {
- return $ra;
+ $path =~ s#/?[^/]+$##;
}
+ die "Path: '$path' should be ''\n" if $path ne '';
+ return $ra if $self->read_svm_props($ra, $path, $r);
+ $tried{"$self->{url}/$path"} = 1;
if ($ra->{repos_root} eq $self->{url}) {
- die @err, map { " $self->{url}/$_\n" } @tried_a, "\n";
+ die @err, (map { " $_\n" } keys %tried), "\n";
}
# nope, make sure we're connected to the repository root:
my $ok;
my @tried_b;
$path = $ra->{svn_path};
- $path =~ s#/?[^/]+$##; # we already tried this one above
$ra = Git::SVN::Ra->new($ra->{repos_root});
while (length $path) {
- $ok = $self->read_svm_props(($ra->get_dir($path, $r))[2]);
- last if $ok;
- $path =~ s#/?[^/]+$## && push @tried_b, $path;
+ unless ($tried{"$ra->{url}/$path"}) {
+ $ok = $self->read_svm_props($ra, $path, $r);
+ last if $ok;
+ $tried{"$ra->{url}/$path"} = 1;
+ }
+ $path =~ s#/?[^/]+$##;
}
- $ok = $self->read_svm_props(($ra->get_dir('', $r))[2]) unless $ok;
+ die "Path: '$path' should be ''\n" if $path ne '';
+ $ok ||= $self->read_svm_props($ra, $path, $r);
+ $tried{"$ra->{url}/$path"} = 1;
if (!$ok) {
- die @err, map { " $self->{url}/$_\n" } @tried_a, "\n",
- map { " $ra->{url}/$_\n" } @tried_b, "\n"
+ die @err, (map { " $_\n" } keys %tried), "\n";
}
Git::SVN::Ra->new($self->{url});
}
}
if (defined $r0 && defined $parent) {
print STDERR "Found branch parent: ($self->{ref_id}) $parent\n";
- $self->assert_index_clean($parent);
my $ed;
if ($self->ra->can_do_switch) {
+ $self->assert_index_clean($parent);
print STDERR "Following parent with do_switch\n";
# do_switch works with svn/trunk >= r22312, but that
# is not included with SVN 1.4.3 (the latest version
"options set!\n";
}
my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$};
- if ($uuid ne $self->{svm}->{uuid}) {
+ # we don't want "SVM: initializing mirror for junk" ...
+ return undef if $r == 0;
+ my $svm = $self->svm;
+ if ($uuid ne $svm->{uuid}) {
die "UUID mismatch on SVM path:\n",
- "expected: $self->{svm}->{uuid}\n",
+ "expected: $svm->{uuid}\n",
" got: $uuid\n";
}
- my $full_url = $self->{svm}->{source};
- $full_url .= "/$self->{path}" if length $self->{path};
+ my $full_url = $self->full_url;
+ $full_url =~ s#^\Q$svm->{replace}\E(/|$)#$svm->{source}$1# or
+ die "Failed to replace '$svm->{replace}' with ",
+ "'$svm->{source}' in $full_url\n";
+ # throw away username for storing in records
+ remove_username($full_url);
$log_entry{metadata} = "$full_url\@$r $uuid";
$log_entry{svm_revision} = $r;
$email ||= "$author\@$uuid"
my ($rev_list, $ctx) = command_output_pipe("rev-list", $self->refname);
my $latest;
my $full_url = $self->full_url;
+ remove_username($full_url);
my $svn_uuid;
while (<$rev_list>) {
chomp;
my $c = $_;
die "Non-SHA1: $c\n" unless $c =~ /^$::sha1$/o;
my ($url, $rev, $uuid) = ::cmt_metadata($c);
+ remove_username($url);
# ignore merges (from set-tree)
next if (!defined $rev || !$uuid);
$f
}
+sub remove_username {
+ $_[0] =~ s{^([^:]*://)[^@]+@}{$1};
+}
+
package Git::SVN::Prompt;
use strict;
use warnings;
my ($class, $url) = @_;
$url =~ s!/+$!!;
return $RA if ($RA && $RA->{url} eq $url);
+ $RA->{pool}->clear if $RA;
SVN::_Core::svn_config_ensure($config_dir, undef);
my ($baton, $callbacks) = SVN::Core::auth_open_helper([
my $new = ($rev_a == $rev_b);
my $path = $gs->{path};
+ if ($new && -e $gs->{index}) {
+ unlink $gs->{index} or die
+ "Couldn't unlink index: $gs->{index}: $!\n";
+ }
my $pool = SVN::Pool->new;
$editor->set_path_strip($path);
my (@pc) = split m#/#, $path;