summaryrefslogtreecommitdiff
path: root/git-svn.perl
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2007-02-03 13:29:17 -0800
committerEric Wong <normalperson@yhbt.net>2007-02-23 00:57:11 -0800
commit4bb9ed0466e9ca6b72b3d9c454a743aea862b1f4 (patch)
tree11bd52283e4152c1035484eb6aa85bfbc6f4dc90 /git-svn.perl
parent9fa00b655cfd67bf344668a0d913f90ec9a8141d (diff)
downloadgit-4bb9ed0466e9ca6b72b3d9c454a743aea862b1f4.tar.gz
git-svn: prepare multi-init for wildcard support
Update the tests since we no longer write so many things to the config. Signed-off-by: Eric Wong <normalperson@yhbt.net>
Diffstat (limited to 'git-svn.perl')
-rwxr-xr-xgit-svn.perl124
1 files changed, 117 insertions, 7 deletions
diff --git a/git-svn.perl b/git-svn.perl
index 66b4c20fd9..6874eabffa 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -367,9 +367,10 @@ sub cmd_multi_init {
sub cmd_multi_fetch {
my $remotes = Git::SVN::read_all_remotes();
foreach my $repo_id (sort keys %$remotes) {
- my $url = $remotes->{$repo_id}->{url} or next;
- my $fetch = $remotes->{$repo_id}->{fetch} or next;
- Git::SVN::fetch_all($repo_id, $url, $fetch);
+ if ($remotes->{$repo_id}->{url} &&
+ $remotes->{$repo_id}->{fetch}) {
+ Git::SVN::fetch_all($repo_id, $remotes);
+ }
}
}
@@ -479,9 +480,12 @@ sub complete_url_ls_init {
# don't try to init already existing refs
unless ($gs) {
print "init $url/$path => $ref\n";
- $gs = Git::SVN->init($url, $path, undef, $ref);
+ $gs = Git::SVN->init($url, $path, undef, $ref, 1);
+ }
+ if ($gs) {
+ $remote_id = $gs->{repo_id};
+ last;
}
- $remote_id ||= $gs->{repo_id} if $gs;
}
if (defined $remote_id) {
$remote_path = "$ra->{svn_path}/$repo_path/*";
@@ -489,7 +493,7 @@ sub complete_url_ls_init {
$remote_path =~ s#^/##g;
my ($n) = ($switch =~ /^--(\w+)/);
command_noisy('config', "svn-remote.$remote_id.$n",
- $remote_path);
+ "$remote_path:refs/remotes/$pfx*");
}
}
@@ -660,9 +664,48 @@ BEGIN {
my %LOCKFILES;
END { unlink keys %LOCKFILES if %LOCKFILES }
+sub resolve_local_globs {
+ my ($url, $fetch, $glob_spec) = @_;
+ return unless defined $glob_spec;
+ my $ref = $glob_spec->{ref};
+ my $path = $glob_spec->{path};
+ foreach (command(qw#for-each-ref --format=%(refname) refs/remotes#)) {
+ next unless m#^refs/remotes/$ref->{regex}$#;
+ my $p = $1;
+ my $pathname = $path->full_path($p);
+ my $refname = $ref->full_path($p);
+ if (my $existing = $fetch->{$pathname}) {
+ if ($existing ne $refname) {
+ die "Refspec conflict:\n",
+ "existing: refs/remotes/$existing\n",
+ " globbed: refs/remotes/$refname\n";
+ }
+ my $u = (::cmt_metadata("refs/remotes/$refname"))[0];
+ $u =~ s!^\Q$url\E/?!! or die
+ "refs/remotes/$refname: '$url' not found in '$u'\n";
+ if ($pathname ne $u) {
+ warn "W: Refspec glob conflict ",
+ "(ref: refs/remotes/$refname):\n",
+ "expected path: $pathname\n",
+ " real path: $u\n",
+ "Continuing ahead with $u\n";
+ next;
+ }
+ } else {
+ warn "Globbed ($path->{glob}:$ref->{glob}): ",
+ "$pathname == $refname\n";
+ $fetch->{$pathname} = $refname;
+ }
+ }
+}
+
sub fetch_all {
- my ($repo_id, $url, $fetch) = @_;
+ my ($repo_id, $remotes) = @_;
+ my $fetch = $remotes->{$repo_id}->{fetch};
+ my $url = $remotes->{$repo_id}->{url};
my @gs;
+ resolve_local_globs($url, $fetch, $remotes->{$repo_id}->{branches});
+ resolve_local_globs($url, $fetch, $remotes->{$repo_id}->{tags});
my $ra = Git::SVN::Ra->new($url);
my $head = $ra->get_latest_revnum;
my $base = $head;
@@ -685,6 +728,16 @@ sub read_all_remotes {
$r->{$1}->{fetch}->{$2} = $3;
} elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
$r->{$1}->{url} = $2;
+ } elsif (m!^(.+)\.(branches|tags)=
+ (.*):refs/remotes/(.+)\s*$/!x) {
+ my ($p, $g) = ($3, $4);
+ my $rs = $r->{$1}->{$2} = {
+ path => Git::SVN::GlobSpec->new($p),
+ ref => Git::SVN::GlobSpec->new($g) };
+ if (length($rs->{ref}->{right}) != 0) {
+ die "The '*' glob character must be the last ",
+ "character of '$g'\n";
+ }
}
}
$r;
@@ -3072,10 +3125,67 @@ sub DESTROY {
command_close_pipe($self->{gui}, $self->{ctx});
}
+package Git::SVN::GlobSpec;
+use strict;
+use warnings;
+
+sub new {
+ my ($class, $glob) = @_;
+ warn "glob: $glob\n";
+ my $re = $glob;
+ $re =~ s!/+$!!g; # no need for trailing slashes
+ my $nr = ($re =~ s!^(.*/?)\*(/?.*)$!\(\[^/\]+\)!g);
+ my ($left, $right) = ($1, $2);
+ if ($nr > 1) {
+ warn "Only one '*' wildcard expansion ",
+ "is supported (got $nr): '$glob'\n";
+ } elsif ($nr == 0) {
+ warn "One '*' is needed for glob: '$glob'\n";
+ }
+ $re = quotemeta($left) . $re . quotemeta($right);
+ $left =~ s!/+$!!g;
+ $right =~ s!^/+!!g;
+ bless { left => $left, right => $right,
+ regex => qr/$re/, glob => $glob }, $class;
+}
+
+sub full_path {
+ my ($self, $path) = @_;
+ return (length $self->{left} ? "$self->{left}/" : '') .
+ $path . (length $self->{right} ? "/$self->{right}" : '');
+}
+
__END__
Data structures:
+
+$remotes = { # returned by read_all_remotes()
+ 'svn' => {
+ # svn-remote.svn.url=https://svn.musicpd.org
+ url => 'https://svn.musicpd.org',
+ # svn-remote.svn.fetch=mpd/trunk:trunk
+ fetch => {
+ 'mpd/trunk' => 'trunk',
+ },
+ # svn-remote.svn.tags=mpd/tags/*:tags/*
+ tags => {
+ path => {
+ left => 'mpd/tags',
+ right => '',
+ regex => qr!mpd/tags/([^/]+)$!,
+ glob => 'tags/*',
+ },
+ ref => {
+ left => 'tags',
+ right => '',
+ regex => qr!tags/([^/]+)$!,
+ glob => 'tags/*',
+ },
+ }
+ }
+};
+
$log_entry hashref as returned by libsvn_log_entry()
{
log => 'whitespace-formatted log entry