git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Extract remaining classes from git-svn
@ 2012-07-27  0:25 Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 1/8] Prepare Git::SVN::Log for extraction " Michael G. Schwern
                   ` (9 more replies)
  0 siblings, 10 replies; 16+ messages in thread
From: Michael G. Schwern @ 2012-07-27  0:25 UTC (permalink / raw)
  To: git, gitster; +Cc: robbat2, bwalton, normalperson, jrnieder, schwern

This series of patches extracts the remaining classes from git-svn.  They're
all simple extractions and functionally have no change.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 1/8] Prepare Git::SVN::Log for extraction from git-svn.
  2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
@ 2012-07-27  0:26 ` Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 2/8] Extract Git::SVN::Log " Michael G. Schwern
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Michael G. Schwern @ 2012-07-27  0:26 UTC (permalink / raw)
  To: git, gitster; +Cc: robbat2, bwalton, normalperson, jrnieder, schwern

From: "Michael G. Schwern" <schwern@pobox.com>

* Load Git command functions itself.

* Can't access the git-svn switch lexical any more, but its only used by
  Git::SVN::Log so turn it into a Git::SVN::Log global.

* Load Git::SVN as needed.  No need to load it always, its only used twice.

* Moved a state variable to the routine it's used for. (Drive by refactoring)
---
 git-svn.perl | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index ef10f6f..e16475b 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -87,7 +87,7 @@ BEGIN {
 	foreach (qw/command command_oneline command_noisy command_output_pipe
 	            command_input_pipe command_close_pipe
 	            command_bidi_pipe command_close_bidi_pipe/) {
-		for my $package ( qw(Git::SVN::Migration Git::SVN::Log),
+		for my $package ( qw(Git::SVN::Migration),
 			__PACKAGE__) {
 			*{"${package}::$_"} = \&{"Git::$_"};
 		}
@@ -106,7 +106,7 @@ my ($_stdin, $_help, $_edit,
 	$_version, $_fetch_all, $_no_rebase, $_fetch_parent,
 	$_merge, $_strategy, $_preserve_merges, $_dry_run, $_local,
 	$_prefix, $_no_checkout, $_url, $_verbose,
-	$_git_format, $_commit_url, $_tag, $_merge_info, $_interactive);
+	$_commit_url, $_tag, $_merge_info, $_interactive);
 
 # This is a refactoring artifact so Git::SVN can get at this git-svn switch.
 sub opt_prefix { return $_prefix || '' }
@@ -270,7 +270,7 @@ my %cmd = (
 		    { 'url' => \$_url, } ],
 	'blame' => [ \&Git::SVN::Log::cmd_blame,
 	            "Show what revision and author last modified each line of a file",
-		    { 'git-format' => \$_git_format } ],
+		    { 'git-format' => \$Git::SVN::Log::_git_format } ],
 	'reset' => [ \&cmd_reset,
 		     "Undo fetches back to the specified SVN revision",
 		     { 'revision|r=s' => \$_revision,
@@ -2044,11 +2044,14 @@ package Git::SVN::Log;
 use strict;
 use warnings;
 use Git::SVN::Utils qw(fatal);
+use Git qw(command command_oneline command_output_pipe command_close_pipe);
 use POSIX qw/strftime/;
 use constant commit_log_separator => ('-' x 72) . "\n";
 use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
             %rusers $show_commit $incremental/;
-my $l_fmt;
+
+# Option set in git-svn
+our $_git_format;
 
 sub cmt_showable {
 	my ($c) = @_;
@@ -2094,6 +2097,8 @@ sub git_svn_log_cmd {
 	}
 
 	my ($url, $rev, $uuid, $gs) = ::working_head_info($head);
+
+	require Git::SVN;
 	$gs ||= Git::SVN->_new;
 	my @cmd = (qw/log --abbrev-commit --pretty=raw --default/,
 	           $gs->refname);
@@ -2155,6 +2160,7 @@ sub run_pager {
 
 sub format_svn_date {
 	my $t = shift || time;
+	require Git::SVN;
 	my $gmoff = Git::SVN::get_tz($t);
 	return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
 }
@@ -2225,6 +2231,7 @@ sub process_commit {
 	return 1;
 }
 
+my $l_fmt;
 sub show_commit {
 	my $c = shift;
 	if ($oneline) {
-- 
1.7.11.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 2/8] Extract Git::SVN::Log from git-svn.
  2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 1/8] Prepare Git::SVN::Log for extraction " Michael G. Schwern
@ 2012-07-27  0:26 ` Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 3/8] Prepare Git::SVN::Migration for extraction " Michael G. Schwern
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Michael G. Schwern @ 2012-07-27  0:26 UTC (permalink / raw)
  To: git, gitster; +Cc: robbat2, bwalton, normalperson, jrnieder, schwern

From: "Michael G. Schwern" <schwern@pobox.com>

Straight cut & paste.

Also noticed Git::SVN::Ra wasn't in the compile test.  It is now.
---
 git-svn.perl          | 395 +-------------------------------------------------
 perl/Git/SVN/Log.pm   | 395 ++++++++++++++++++++++++++++++++++++++++++++++++++
 perl/Makefile         |   1 +
 t/Git-SVN/00compile.t |   6 +-
 4 files changed, 401 insertions(+), 396 deletions(-)
 create mode 100644 perl/Git/SVN/Log.pm

diff --git a/git-svn.perl b/git-svn.perl
index e16475b..7c8da44 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -11,6 +11,7 @@ $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
 $VERSION = '@@GIT_VERSION@@';
 
 use Git::SVN;
+use Git::SVN::Log;
 use Git::SVN::Utils qw(fatal can_compress);
 
 # From which subdir have we been invoked?
@@ -2040,400 +2041,6 @@ sub gc_directory {
 }
 
 
-package Git::SVN::Log;
-use strict;
-use warnings;
-use Git::SVN::Utils qw(fatal);
-use Git qw(command command_oneline command_output_pipe command_close_pipe);
-use POSIX qw/strftime/;
-use constant commit_log_separator => ('-' x 72) . "\n";
-use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
-            %rusers $show_commit $incremental/;
-
-# Option set in git-svn
-our $_git_format;
-
-sub cmt_showable {
-	my ($c) = @_;
-	return 1 if defined $c->{r};
-
-	# big commit message got truncated by the 16k pretty buffer in rev-list
-	if ($c->{l} && $c->{l}->[-1] eq "...\n" &&
-				$c->{a_raw} =~ /\@([a-f\d\-]+)>$/) {
-		@{$c->{l}} = ();
-		my @log = command(qw/cat-file commit/, $c->{c});
-
-		# shift off the headers
-		shift @log while ($log[0] ne '');
-		shift @log;
-
-		# TODO: make $c->{l} not have a trailing newline in the future
-		@{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log;
-
-		(undef, $c->{r}, undef) = ::extract_metadata(
-				(grep(/^git-svn-id: /, @log))[-1]);
-	}
-	return defined $c->{r};
-}
-
-sub log_use_color {
-	return $color || Git->repository->get_colorbool('color.diff');
-}
-
-sub git_svn_log_cmd {
-	my ($r_min, $r_max, @args) = @_;
-	my $head = 'HEAD';
-	my (@files, @log_opts);
-	foreach my $x (@args) {
-		if ($x eq '--' || @files) {
-			push @files, $x;
-		} else {
-			if (::verify_ref("$x^0")) {
-				$head = $x;
-			} else {
-				push @log_opts, $x;
-			}
-		}
-	}
-
-	my ($url, $rev, $uuid, $gs) = ::working_head_info($head);
-
-	require Git::SVN;
-	$gs ||= Git::SVN->_new;
-	my @cmd = (qw/log --abbrev-commit --pretty=raw --default/,
-	           $gs->refname);
-	push @cmd, '-r' unless $non_recursive;
-	push @cmd, qw/--raw --name-status/ if $verbose;
-	push @cmd, '--color' if log_use_color();
-	push @cmd, @log_opts;
-	if (defined $r_max && $r_max == $r_min) {
-		push @cmd, '--max-count=1';
-		if (my $c = $gs->rev_map_get($r_max)) {
-			push @cmd, $c;
-		}
-	} elsif (defined $r_max) {
-		if ($r_max < $r_min) {
-			($r_min, $r_max) = ($r_max, $r_min);
-		}
-		my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min);
-		my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max);
-		# If there are no commits in the range, both $c_max and $c_min
-		# will be undefined.  If there is at least 1 commit in the
-		# range, both will be defined.
-		return () if !defined $c_min || !defined $c_max;
-		if ($c_min eq $c_max) {
-			push @cmd, '--max-count=1', $c_min;
-		} else {
-			push @cmd, '--boundary', "$c_min..$c_max";
-		}
-	}
-	return (@cmd, @files);
-}
-
-# adapted from pager.c
-sub config_pager {
-	if (! -t *STDOUT) {
-		$ENV{GIT_PAGER_IN_USE} = 'false';
-		$pager = undef;
-		return;
-	}
-	chomp($pager = command_oneline(qw(var GIT_PAGER)));
-	if ($pager eq 'cat') {
-		$pager = undef;
-	}
-	$ENV{GIT_PAGER_IN_USE} = defined($pager);
-}
-
-sub run_pager {
-	return unless defined $pager;
-	pipe my ($rfd, $wfd) or return;
-	defined(my $pid = fork) or fatal "Can't fork: $!";
-	if (!$pid) {
-		open STDOUT, '>&', $wfd or
-		                     fatal "Can't redirect to stdout: $!";
-		return;
-	}
-	open STDIN, '<&', $rfd or fatal "Can't redirect stdin: $!";
-	$ENV{LESS} ||= 'FRSX';
-	exec $pager or fatal "Can't run pager: $! ($pager)";
-}
-
-sub format_svn_date {
-	my $t = shift || time;
-	require Git::SVN;
-	my $gmoff = Git::SVN::get_tz($t);
-	return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
-}
-
-sub parse_git_date {
-	my ($t, $tz) = @_;
-	# Date::Parse isn't in the standard Perl distro :(
-	if ($tz =~ s/^\+//) {
-		$t += tz_to_s_offset($tz);
-	} elsif ($tz =~ s/^\-//) {
-		$t -= tz_to_s_offset($tz);
-	}
-	return $t;
-}
-
-sub set_local_timezone {
-	if (defined $TZ) {
-		$ENV{TZ} = $TZ;
-	} else {
-		delete $ENV{TZ};
-	}
-}
-
-sub tz_to_s_offset {
-	my ($tz) = @_;
-	$tz =~ s/(\d\d)$//;
-	return ($1 * 60) + ($tz * 3600);
-}
-
-sub get_author_info {
-	my ($dest, $author, $t, $tz) = @_;
-	$author =~ s/(?:^\s*|\s*$)//g;
-	$dest->{a_raw} = $author;
-	my $au;
-	if ($::_authors) {
-		$au = $rusers{$author} || undef;
-	}
-	if (!$au) {
-		($au) = ($author =~ /<([^>]+)\@[^>]+>$/);
-	}
-	$dest->{t} = $t;
-	$dest->{tz} = $tz;
-	$dest->{a} = $au;
-	$dest->{t_utc} = parse_git_date($t, $tz);
-}
-
-sub process_commit {
-	my ($c, $r_min, $r_max, $defer) = @_;
-	if (defined $r_min && defined $r_max) {
-		if ($r_min == $c->{r} && $r_min == $r_max) {
-			show_commit($c);
-			return 0;
-		}
-		return 1 if $r_min == $r_max;
-		if ($r_min < $r_max) {
-			# we need to reverse the print order
-			return 0 if (defined $limit && --$limit < 0);
-			push @$defer, $c;
-			return 1;
-		}
-		if ($r_min != $r_max) {
-			return 1 if ($r_min < $c->{r});
-			return 1 if ($r_max > $c->{r});
-		}
-	}
-	return 0 if (defined $limit && --$limit < 0);
-	show_commit($c);
-	return 1;
-}
-
-my $l_fmt;
-sub show_commit {
-	my $c = shift;
-	if ($oneline) {
-		my $x = "\n";
-		if (my $l = $c->{l}) {
-			while ($l->[0] =~ /^\s*$/) { shift @$l }
-			$x = $l->[0];
-		}
-		$l_fmt ||= 'A' . length($c->{r});
-		print 'r',pack($l_fmt, $c->{r}),' | ';
-		print "$c->{c} | " if $show_commit;
-		print $x;
-	} else {
-		show_commit_normal($c);
-	}
-}
-
-sub show_commit_changed_paths {
-	my ($c) = @_;
-	return unless $c->{changed};
-	print "Changed paths:\n", @{$c->{changed}};
-}
-
-sub show_commit_normal {
-	my ($c) = @_;
-	print commit_log_separator, "r$c->{r} | ";
-	print "$c->{c} | " if $show_commit;
-	print "$c->{a} | ", format_svn_date($c->{t_utc}), ' | ';
-	my $nr_line = 0;
-
-	if (my $l = $c->{l}) {
-		while ($l->[$#$l] eq "\n" && $#$l > 0
-		                          && $l->[($#$l - 1)] eq "\n") {
-			pop @$l;
-		}
-		$nr_line = scalar @$l;
-		if (!$nr_line) {
-			print "1 line\n\n\n";
-		} else {
-			if ($nr_line == 1) {
-				$nr_line = '1 line';
-			} else {
-				$nr_line .= ' lines';
-			}
-			print $nr_line, "\n";
-			show_commit_changed_paths($c);
-			print "\n";
-			print $_ foreach @$l;
-		}
-	} else {
-		print "1 line\n";
-		show_commit_changed_paths($c);
-		print "\n";
-
-	}
-	foreach my $x (qw/raw stat diff/) {
-		if ($c->{$x}) {
-			print "\n";
-			print $_ foreach @{$c->{$x}}
-		}
-	}
-}
-
-sub cmd_show_log {
-	my (@args) = @_;
-	my ($r_min, $r_max);
-	my $r_last = -1; # prevent dupes
-	set_local_timezone();
-	if (defined $::_revision) {
-		if ($::_revision =~ /^(\d+):(\d+)$/) {
-			($r_min, $r_max) = ($1, $2);
-		} elsif ($::_revision =~ /^\d+$/) {
-			$r_min = $r_max = $::_revision;
-		} else {
-			fatal "-r$::_revision is not supported, use ",
-				"standard 'git log' arguments instead";
-		}
-	}
-
-	config_pager();
-	@args = git_svn_log_cmd($r_min, $r_max, @args);
-	if (!@args) {
-		print commit_log_separator unless $incremental || $oneline;
-		return;
-	}
-	my $log = command_output_pipe(@args);
-	run_pager();
-	my (@k, $c, $d, $stat);
-	my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
-	while (<$log>) {
-		if (/^${esc_color}commit (?:- )?($::sha1_short)/o) {
-			my $cmt = $1;
-			if ($c && cmt_showable($c) && $c->{r} != $r_last) {
-				$r_last = $c->{r};
-				process_commit($c, $r_min, $r_max, \@k) or
-								goto out;
-			}
-			$d = undef;
-			$c = { c => $cmt };
-		} elsif (/^${esc_color}author (.+) (\d+) ([\-\+]?\d+)$/o) {
-			get_author_info($c, $1, $2, $3);
-		} elsif (/^${esc_color}(?:tree|parent|committer) /o) {
-			# ignore
-		} elsif (/^${esc_color}:\d{6} \d{6} $::sha1_short/o) {
-			push @{$c->{raw}}, $_;
-		} elsif (/^${esc_color}[ACRMDT]\t/) {
-			# we could add $SVN->{svn_path} here, but that requires
-			# remote access at the moment (repo_path_split)...
-			s#^(${esc_color})([ACRMDT])\t#$1   $2 #o;
-			push @{$c->{changed}}, $_;
-		} elsif (/^${esc_color}diff /o) {
-			$d = 1;
-			push @{$c->{diff}}, $_;
-		} elsif ($d) {
-			push @{$c->{diff}}, $_;
-		} elsif (/^\ .+\ \|\s*\d+\ $esc_color[\+\-]*
-		          $esc_color*[\+\-]*$esc_color$/x) {
-			$stat = 1;
-			push @{$c->{stat}}, $_;
-		} elsif ($stat && /^ \d+ files changed, \d+ insertions/) {
-			push @{$c->{stat}}, $_;
-			$stat = undef;
-		} elsif (/^${esc_color}    (git-svn-id:.+)$/o) {
-			($c->{url}, $c->{r}, undef) = ::extract_metadata($1);
-		} elsif (s/^${esc_color}    //o) {
-			push @{$c->{l}}, $_;
-		}
-	}
-	if ($c && defined $c->{r} && $c->{r} != $r_last) {
-		$r_last = $c->{r};
-		process_commit($c, $r_min, $r_max, \@k);
-	}
-	if (@k) {
-		($r_min, $r_max) = ($r_max, $r_min);
-		process_commit($_, $r_min, $r_max) foreach reverse @k;
-	}
-out:
-	close $log;
-	print commit_log_separator unless $incremental || $oneline;
-}
-
-sub cmd_blame {
-	my $path = pop;
-
-	config_pager();
-	run_pager();
-
-	my ($fh, $ctx, $rev);
-
-	if ($_git_format) {
-		($fh, $ctx) = command_output_pipe('blame', @_, $path);
-		while (my $line = <$fh>) {
-			if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
-				# Uncommitted edits show up as a rev ID of
-				# all zeros, which we can't look up with
-				# cmt_metadata
-				if ($1 !~ /^0+$/) {
-					(undef, $rev, undef) =
-						::cmt_metadata($1);
-					$rev = '0' if (!$rev);
-				} else {
-					$rev = '0';
-				}
-				$rev = sprintf('%-10s', $rev);
-				$line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
-			}
-			print $line;
-		}
-	} else {
-		($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD',
-						  '--', $path);
-		my ($sha1);
-		my %authors;
-		my @buffer;
-		my %dsha; #distinct sha keys
-
-		while (my $line = <$fh>) {
-			push @buffer, $line;
-			if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
-				$dsha{$1} = 1;
-			}
-		}
-
-		my $s2r = ::cmt_sha2rev_batch([keys %dsha]);
-
-		foreach my $line (@buffer) {
-			if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
-				$rev = $s2r->{$1};
-				$rev = '0' if (!$rev)
-			}
-			elsif ($line =~ /^author (.*)/) {
-				$authors{$rev} = $1;
-				$authors{$rev} =~ s/\s/_/g;
-			}
-			elsif ($line =~ /^\t(.*)$/) {
-				printf("%6s %10s %s\n", $rev, $authors{$rev}, $1);
-			}
-		}
-	}
-	command_close_pipe($fh, $ctx);
-}
-
 package Git::SVN::Migration;
 # these version numbers do NOT correspond to actual version numbers
 # of git nor git-svn.  They are just relative.
diff --git a/perl/Git/SVN/Log.pm b/perl/Git/SVN/Log.pm
new file mode 100644
index 0000000..3cc1c6f
--- /dev/null
+++ b/perl/Git/SVN/Log.pm
@@ -0,0 +1,395 @@
+package Git::SVN::Log;
+use strict;
+use warnings;
+use Git::SVN::Utils qw(fatal);
+use Git qw(command command_oneline command_output_pipe command_close_pipe);
+use POSIX qw/strftime/;
+use constant commit_log_separator => ('-' x 72) . "\n";
+use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
+            %rusers $show_commit $incremental/;
+
+# Option set in git-svn
+our $_git_format;
+
+sub cmt_showable {
+	my ($c) = @_;
+	return 1 if defined $c->{r};
+
+	# big commit message got truncated by the 16k pretty buffer in rev-list
+	if ($c->{l} && $c->{l}->[-1] eq "...\n" &&
+				$c->{a_raw} =~ /\@([a-f\d\-]+)>$/) {
+		@{$c->{l}} = ();
+		my @log = command(qw/cat-file commit/, $c->{c});
+
+		# shift off the headers
+		shift @log while ($log[0] ne '');
+		shift @log;
+
+		# TODO: make $c->{l} not have a trailing newline in the future
+		@{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log;
+
+		(undef, $c->{r}, undef) = ::extract_metadata(
+				(grep(/^git-svn-id: /, @log))[-1]);
+	}
+	return defined $c->{r};
+}
+
+sub log_use_color {
+	return $color || Git->repository->get_colorbool('color.diff');
+}
+
+sub git_svn_log_cmd {
+	my ($r_min, $r_max, @args) = @_;
+	my $head = 'HEAD';
+	my (@files, @log_opts);
+	foreach my $x (@args) {
+		if ($x eq '--' || @files) {
+			push @files, $x;
+		} else {
+			if (::verify_ref("$x^0")) {
+				$head = $x;
+			} else {
+				push @log_opts, $x;
+			}
+		}
+	}
+
+	my ($url, $rev, $uuid, $gs) = ::working_head_info($head);
+
+	require Git::SVN;
+	$gs ||= Git::SVN->_new;
+	my @cmd = (qw/log --abbrev-commit --pretty=raw --default/,
+	           $gs->refname);
+	push @cmd, '-r' unless $non_recursive;
+	push @cmd, qw/--raw --name-status/ if $verbose;
+	push @cmd, '--color' if log_use_color();
+	push @cmd, @log_opts;
+	if (defined $r_max && $r_max == $r_min) {
+		push @cmd, '--max-count=1';
+		if (my $c = $gs->rev_map_get($r_max)) {
+			push @cmd, $c;
+		}
+	} elsif (defined $r_max) {
+		if ($r_max < $r_min) {
+			($r_min, $r_max) = ($r_max, $r_min);
+		}
+		my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min);
+		my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max);
+		# If there are no commits in the range, both $c_max and $c_min
+		# will be undefined.  If there is at least 1 commit in the
+		# range, both will be defined.
+		return () if !defined $c_min || !defined $c_max;
+		if ($c_min eq $c_max) {
+			push @cmd, '--max-count=1', $c_min;
+		} else {
+			push @cmd, '--boundary', "$c_min..$c_max";
+		}
+	}
+	return (@cmd, @files);
+}
+
+# adapted from pager.c
+sub config_pager {
+	if (! -t *STDOUT) {
+		$ENV{GIT_PAGER_IN_USE} = 'false';
+		$pager = undef;
+		return;
+	}
+	chomp($pager = command_oneline(qw(var GIT_PAGER)));
+	if ($pager eq 'cat') {
+		$pager = undef;
+	}
+	$ENV{GIT_PAGER_IN_USE} = defined($pager);
+}
+
+sub run_pager {
+	return unless defined $pager;
+	pipe my ($rfd, $wfd) or return;
+	defined(my $pid = fork) or fatal "Can't fork: $!";
+	if (!$pid) {
+		open STDOUT, '>&', $wfd or
+		                     fatal "Can't redirect to stdout: $!";
+		return;
+	}
+	open STDIN, '<&', $rfd or fatal "Can't redirect stdin: $!";
+	$ENV{LESS} ||= 'FRSX';
+	exec $pager or fatal "Can't run pager: $! ($pager)";
+}
+
+sub format_svn_date {
+	my $t = shift || time;
+	require Git::SVN;
+	my $gmoff = Git::SVN::get_tz($t);
+	return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t));
+}
+
+sub parse_git_date {
+	my ($t, $tz) = @_;
+	# Date::Parse isn't in the standard Perl distro :(
+	if ($tz =~ s/^\+//) {
+		$t += tz_to_s_offset($tz);
+	} elsif ($tz =~ s/^\-//) {
+		$t -= tz_to_s_offset($tz);
+	}
+	return $t;
+}
+
+sub set_local_timezone {
+	if (defined $TZ) {
+		$ENV{TZ} = $TZ;
+	} else {
+		delete $ENV{TZ};
+	}
+}
+
+sub tz_to_s_offset {
+	my ($tz) = @_;
+	$tz =~ s/(\d\d)$//;
+	return ($1 * 60) + ($tz * 3600);
+}
+
+sub get_author_info {
+	my ($dest, $author, $t, $tz) = @_;
+	$author =~ s/(?:^\s*|\s*$)//g;
+	$dest->{a_raw} = $author;
+	my $au;
+	if ($::_authors) {
+		$au = $rusers{$author} || undef;
+	}
+	if (!$au) {
+		($au) = ($author =~ /<([^>]+)\@[^>]+>$/);
+	}
+	$dest->{t} = $t;
+	$dest->{tz} = $tz;
+	$dest->{a} = $au;
+	$dest->{t_utc} = parse_git_date($t, $tz);
+}
+
+sub process_commit {
+	my ($c, $r_min, $r_max, $defer) = @_;
+	if (defined $r_min && defined $r_max) {
+		if ($r_min == $c->{r} && $r_min == $r_max) {
+			show_commit($c);
+			return 0;
+		}
+		return 1 if $r_min == $r_max;
+		if ($r_min < $r_max) {
+			# we need to reverse the print order
+			return 0 if (defined $limit && --$limit < 0);
+			push @$defer, $c;
+			return 1;
+		}
+		if ($r_min != $r_max) {
+			return 1 if ($r_min < $c->{r});
+			return 1 if ($r_max > $c->{r});
+		}
+	}
+	return 0 if (defined $limit && --$limit < 0);
+	show_commit($c);
+	return 1;
+}
+
+my $l_fmt;
+sub show_commit {
+	my $c = shift;
+	if ($oneline) {
+		my $x = "\n";
+		if (my $l = $c->{l}) {
+			while ($l->[0] =~ /^\s*$/) { shift @$l }
+			$x = $l->[0];
+		}
+		$l_fmt ||= 'A' . length($c->{r});
+		print 'r',pack($l_fmt, $c->{r}),' | ';
+		print "$c->{c} | " if $show_commit;
+		print $x;
+	} else {
+		show_commit_normal($c);
+	}
+}
+
+sub show_commit_changed_paths {
+	my ($c) = @_;
+	return unless $c->{changed};
+	print "Changed paths:\n", @{$c->{changed}};
+}
+
+sub show_commit_normal {
+	my ($c) = @_;
+	print commit_log_separator, "r$c->{r} | ";
+	print "$c->{c} | " if $show_commit;
+	print "$c->{a} | ", format_svn_date($c->{t_utc}), ' | ';
+	my $nr_line = 0;
+
+	if (my $l = $c->{l}) {
+		while ($l->[$#$l] eq "\n" && $#$l > 0
+		                          && $l->[($#$l - 1)] eq "\n") {
+			pop @$l;
+		}
+		$nr_line = scalar @$l;
+		if (!$nr_line) {
+			print "1 line\n\n\n";
+		} else {
+			if ($nr_line == 1) {
+				$nr_line = '1 line';
+			} else {
+				$nr_line .= ' lines';
+			}
+			print $nr_line, "\n";
+			show_commit_changed_paths($c);
+			print "\n";
+			print $_ foreach @$l;
+		}
+	} else {
+		print "1 line\n";
+		show_commit_changed_paths($c);
+		print "\n";
+
+	}
+	foreach my $x (qw/raw stat diff/) {
+		if ($c->{$x}) {
+			print "\n";
+			print $_ foreach @{$c->{$x}}
+		}
+	}
+}
+
+sub cmd_show_log {
+	my (@args) = @_;
+	my ($r_min, $r_max);
+	my $r_last = -1; # prevent dupes
+	set_local_timezone();
+	if (defined $::_revision) {
+		if ($::_revision =~ /^(\d+):(\d+)$/) {
+			($r_min, $r_max) = ($1, $2);
+		} elsif ($::_revision =~ /^\d+$/) {
+			$r_min = $r_max = $::_revision;
+		} else {
+			fatal "-r$::_revision is not supported, use ",
+				"standard 'git log' arguments instead";
+		}
+	}
+
+	config_pager();
+	@args = git_svn_log_cmd($r_min, $r_max, @args);
+	if (!@args) {
+		print commit_log_separator unless $incremental || $oneline;
+		return;
+	}
+	my $log = command_output_pipe(@args);
+	run_pager();
+	my (@k, $c, $d, $stat);
+	my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
+	while (<$log>) {
+		if (/^${esc_color}commit (?:- )?($::sha1_short)/o) {
+			my $cmt = $1;
+			if ($c && cmt_showable($c) && $c->{r} != $r_last) {
+				$r_last = $c->{r};
+				process_commit($c, $r_min, $r_max, \@k) or
+								goto out;
+			}
+			$d = undef;
+			$c = { c => $cmt };
+		} elsif (/^${esc_color}author (.+) (\d+) ([\-\+]?\d+)$/o) {
+			get_author_info($c, $1, $2, $3);
+		} elsif (/^${esc_color}(?:tree|parent|committer) /o) {
+			# ignore
+		} elsif (/^${esc_color}:\d{6} \d{6} $::sha1_short/o) {
+			push @{$c->{raw}}, $_;
+		} elsif (/^${esc_color}[ACRMDT]\t/) {
+			# we could add $SVN->{svn_path} here, but that requires
+			# remote access at the moment (repo_path_split)...
+			s#^(${esc_color})([ACRMDT])\t#$1   $2 #o;
+			push @{$c->{changed}}, $_;
+		} elsif (/^${esc_color}diff /o) {
+			$d = 1;
+			push @{$c->{diff}}, $_;
+		} elsif ($d) {
+			push @{$c->{diff}}, $_;
+		} elsif (/^\ .+\ \|\s*\d+\ $esc_color[\+\-]*
+		          $esc_color*[\+\-]*$esc_color$/x) {
+			$stat = 1;
+			push @{$c->{stat}}, $_;
+		} elsif ($stat && /^ \d+ files changed, \d+ insertions/) {
+			push @{$c->{stat}}, $_;
+			$stat = undef;
+		} elsif (/^${esc_color}    (git-svn-id:.+)$/o) {
+			($c->{url}, $c->{r}, undef) = ::extract_metadata($1);
+		} elsif (s/^${esc_color}    //o) {
+			push @{$c->{l}}, $_;
+		}
+	}
+	if ($c && defined $c->{r} && $c->{r} != $r_last) {
+		$r_last = $c->{r};
+		process_commit($c, $r_min, $r_max, \@k);
+	}
+	if (@k) {
+		($r_min, $r_max) = ($r_max, $r_min);
+		process_commit($_, $r_min, $r_max) foreach reverse @k;
+	}
+out:
+	close $log;
+	print commit_log_separator unless $incremental || $oneline;
+}
+
+sub cmd_blame {
+	my $path = pop;
+
+	config_pager();
+	run_pager();
+
+	my ($fh, $ctx, $rev);
+
+	if ($_git_format) {
+		($fh, $ctx) = command_output_pipe('blame', @_, $path);
+		while (my $line = <$fh>) {
+			if ($line =~ /^\^?([[:xdigit:]]+)\s/) {
+				# Uncommitted edits show up as a rev ID of
+				# all zeros, which we can't look up with
+				# cmt_metadata
+				if ($1 !~ /^0+$/) {
+					(undef, $rev, undef) =
+						::cmt_metadata($1);
+					$rev = '0' if (!$rev);
+				} else {
+					$rev = '0';
+				}
+				$rev = sprintf('%-10s', $rev);
+				$line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/;
+			}
+			print $line;
+		}
+	} else {
+		($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD',
+						  '--', $path);
+		my ($sha1);
+		my %authors;
+		my @buffer;
+		my %dsha; #distinct sha keys
+
+		while (my $line = <$fh>) {
+			push @buffer, $line;
+			if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
+				$dsha{$1} = 1;
+			}
+		}
+
+		my $s2r = ::cmt_sha2rev_batch([keys %dsha]);
+
+		foreach my $line (@buffer) {
+			if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) {
+				$rev = $s2r->{$1};
+				$rev = '0' if (!$rev)
+			}
+			elsif ($line =~ /^author (.*)/) {
+				$authors{$rev} = $1;
+				$authors{$rev} =~ s/\s/_/g;
+			}
+			elsif ($line =~ /^\t(.*)$/) {
+				printf("%6s %10s %s\n", $rev, $authors{$rev}, $1);
+			}
+		}
+	}
+	command_close_pipe($fh, $ctx);
+}
+
+1;
diff --git a/perl/Makefile b/perl/Makefile
index 461f233..8493d76 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -30,6 +30,7 @@ modules += Git/SVN
 modules += Git/SVN/Memoize/YAML
 modules += Git/SVN/Fetcher
 modules += Git/SVN/Editor
+modules += Git/SVN/Log
 modules += Git/SVN/Prompt
 modules += Git/SVN/Ra
 modules += Git/SVN/Utils
diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t
index 97475d9..37626f4 100644
--- a/t/Git-SVN/00compile.t
+++ b/t/Git-SVN/00compile.t
@@ -3,7 +3,9 @@
 use strict;
 use warnings;
 
-use Test::More tests => 2;
+use Test::More tests => 4;
 
-require_ok 'Git::SVN::Utils';
 require_ok 'Git::SVN';
+require_ok 'Git::SVN::Utils';
+require_ok 'Git::SVN::Ra';
+require_ok 'Git::SVN::Log';
-- 
1.7.11.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 3/8] Prepare Git::SVN::Migration for extraction from git-svn.
  2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 1/8] Prepare Git::SVN::Log for extraction " Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 2/8] Extract Git::SVN::Log " Michael G. Schwern
@ 2012-07-27  0:26 ` Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 4/8] Extract Git::SVN::Migration " Michael G. Schwern
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Michael G. Schwern @ 2012-07-27  0:26 UTC (permalink / raw)
  To: git, gitster; +Cc: robbat2, bwalton, normalperson, jrnieder, schwern

From: "Michael G. Schwern" <schwern@pobox.com>

* Load Git command functions on its own.
* Load Git::SVN modules on its own.

Drive by refactorings...
* Use our() instead of use vars.
* Eliminate the auto loading of Git functions.
---
 git-svn.perl | 36 ++++++++++++++++++++++++------------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index 7c8da44..db60984 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -14,6 +14,18 @@ use Git::SVN;
 use Git::SVN::Log;
 use Git::SVN::Utils qw(fatal can_compress);
 
+use Git qw(
+    git_cmd_try
+    command
+    command_oneline
+    command_noisy
+    command_output_pipe
+    command_close_pipe
+    command_bidi_pipe
+    command_close_bidi_pipe
+);
+
+
 # From which subdir have we been invoked?
 my $cmd_dir_prefix = eval {
 	command_oneline([qw/rev-parse --show-prefix/], STDERR => 0)
@@ -75,7 +87,6 @@ use File::Spec;
 use File::Find;
 use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
 use IPC::Open3;
-use Git;
 use Git::SVN::Editor qw//;
 use Git::SVN::Fetcher qw//;
 use Git::SVN::Ra qw//;
@@ -83,16 +94,6 @@ use Git::SVN::Prompt qw//;
 use Memoize;  # core since 5.8.0, Jul 2002
 
 BEGIN {
-	# import functions from Git into our packages, en masse
-	no strict 'refs';
-	foreach (qw/command command_oneline command_noisy command_output_pipe
-	            command_input_pipe command_close_pipe
-	            command_bidi_pipe command_close_bidi_pipe/) {
-		for my $package ( qw(Git::SVN::Migration),
-			__PACKAGE__) {
-			*{"${package}::$_"} = \&{"Git::$_"};
-		}
-	}
 	Memoize::memoize 'Git::config';
 	Memoize::memoize 'Git::config_bool';
 }
@@ -2080,7 +2081,14 @@ use warnings;
 use Carp qw/croak/;
 use File::Path qw/mkpath/;
 use File::Basename qw/dirname basename/;
-use vars qw/$_minimize/;
+
+our $_minimize;
+use Git qw(
+	command
+	command_noisy
+	command_output_pipe
+	command_close_pipe
+);
 
 sub migrate_from_v0 {
 	my $git_dir = $ENV{GIT_DIR};
@@ -2189,6 +2197,7 @@ sub migrate_from_v2 {
 	read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn");
 	my $migrated = 0;
 
+	require Git::SVN;
 	foreach my $ref_id (sort keys %l_map) {
 		eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) };
 		if ($@) {
@@ -2200,6 +2209,9 @@ sub migrate_from_v2 {
 }
 
 sub minimize_connections {
+	require Git::SVN;
+	require Git::SVN::Ra;
+
 	my $r = Git::SVN::read_all_remotes();
 	my $new_urls = {};
 	my $root_repos = {};
-- 
1.7.11.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 4/8] Extract Git::SVN::Migration from git-svn.
  2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
                   ` (2 preceding siblings ...)
  2012-07-27  0:26 ` [PATCH 3/8] Prepare Git::SVN::Migration for extraction " Michael G. Schwern
@ 2012-07-27  0:26 ` Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 5/8] Load all the modules in one place and before running code Michael G. Schwern
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Michael G. Schwern @ 2012-07-27  0:26 UTC (permalink / raw)
  To: git, gitster; +Cc: robbat2, bwalton, normalperson, jrnieder, schwern

From: "Michael G. Schwern" <schwern@pobox.com>

Straight cut & paste.
---
 git-svn.perl              | 258 +---------------------------------------------
 perl/Git/SVN/Migration.pm | 258 ++++++++++++++++++++++++++++++++++++++++++++++
 perl/Makefile             |   1 +
 t/Git-SVN/00compile.t     |   3 +-
 4 files changed, 262 insertions(+), 258 deletions(-)
 create mode 100644 perl/Git/SVN/Migration.pm

diff --git a/git-svn.perl b/git-svn.perl
index db60984..3741e2e 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -12,6 +12,7 @@ $VERSION = '@@GIT_VERSION@@';
 
 use Git::SVN;
 use Git::SVN::Log;
+use Git::SVN::Migration;
 use Git::SVN::Utils qw(fatal can_compress);
 
 use Git qw(
@@ -2042,263 +2043,6 @@ sub gc_directory {
 }
 
 
-package Git::SVN::Migration;
-# these version numbers do NOT correspond to actual version numbers
-# of git nor git-svn.  They are just relative.
-#
-# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD
-#
-# v1 layout: .git/$id/info/url, refs/remotes/$id
-#
-# v2 layout: .git/svn/$id/info/url, refs/remotes/$id
-#
-# v3 layout: .git/svn/$id, refs/remotes/$id
-#            - info/url may remain for backwards compatibility
-#            - this is what we migrate up to this layout automatically,
-#            - this will be used by git svn init on single branches
-# v3.1 layout (auto migrated):
-#            - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink
-#              for backwards compatibility
-#
-# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id
-#            - this is only created for newly multi-init-ed
-#              repositories.  Similar in spirit to the
-#              --use-separate-remotes option in git-clone (now default)
-#            - we do not automatically migrate to this (following
-#              the example set by core git)
-#
-# v5 layout: .rev_db.$UUID => .rev_map.$UUID
-#            - newer, more-efficient format that uses 24-bytes per record
-#              with no filler space.
-#            - use xxd -c24 < .rev_map.$UUID to view and debug
-#            - This is a one-way migration, repositories updated to the
-#              new format will not be able to use old git-svn without
-#              rebuilding the .rev_db.  Rebuilding the rev_db is not
-#              possible if noMetadata or useSvmProps are set; but should
-#              be no problem for users that use the (sensible) defaults.
-use strict;
-use warnings;
-use Carp qw/croak/;
-use File::Path qw/mkpath/;
-use File::Basename qw/dirname basename/;
-
-our $_minimize;
-use Git qw(
-	command
-	command_noisy
-	command_output_pipe
-	command_close_pipe
-);
-
-sub migrate_from_v0 {
-	my $git_dir = $ENV{GIT_DIR};
-	return undef unless -d $git_dir;
-	my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
-	my $migrated = 0;
-	while (<$fh>) {
-		chomp;
-		my ($id, $orig_ref) = ($_, $_);
-		next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#;
-		next unless -f "$git_dir/$id/info/url";
-		my $new_ref = "refs/remotes/$id";
-		if (::verify_ref("$new_ref^0")) {
-			print STDERR "W: $orig_ref is probably an old ",
-			             "branch used by an ancient version of ",
-				     "git-svn.\n",
-				     "However, $new_ref also exists.\n",
-				     "We will not be able ",
-				     "to use this branch until this ",
-				     "ambiguity is resolved.\n";
-			next;
-		}
-		print STDERR "Migrating from v0 layout...\n" if !$migrated;
-		print STDERR "Renaming ref: $orig_ref => $new_ref\n";
-		command_noisy('update-ref', $new_ref, $orig_ref);
-		command_noisy('update-ref', '-d', $orig_ref, $orig_ref);
-		$migrated++;
-	}
-	command_close_pipe($fh, $ctx);
-	print STDERR "Done migrating from v0 layout...\n" if $migrated;
-	$migrated;
-}
-
-sub migrate_from_v1 {
-	my $git_dir = $ENV{GIT_DIR};
-	my $migrated = 0;
-	return $migrated unless -d $git_dir;
-	my $svn_dir = "$git_dir/svn";
-
-	# just in case somebody used 'svn' as their $id at some point...
-	return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url";
-
-	print STDERR "Migrating from a git-svn v1 layout...\n";
-	mkpath([$svn_dir]);
-	print STDERR "Data from a previous version of git-svn exists, but\n\t",
-	             "$svn_dir\n\t(required for this version ",
-	             "($::VERSION) of git-svn) does not exist.\n";
-	my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
-	while (<$fh>) {
-		my $x = $_;
-		next unless $x =~ s#^refs/remotes/##;
-		chomp $x;
-		next unless -f "$git_dir/$x/info/url";
-		my $u = eval { ::file_to_s("$git_dir/$x/info/url") };
-		next unless $u;
-		my $dn = dirname("$git_dir/svn/$x");
-		mkpath([$dn]) unless -d $dn;
-		if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID:
-			mkpath(["$git_dir/svn/svn"]);
-			print STDERR " - $git_dir/$x/info => ",
-			                "$git_dir/svn/$x/info\n";
-			rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or
-			       croak "$!: $x";
-			# don't worry too much about these, they probably
-			# don't exist with repos this old (save for index,
-			# and we can easily regenerate that)
-			foreach my $f (qw/unhandled.log index .rev_db/) {
-				rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f";
-			}
-		} else {
-			print STDERR " - $git_dir/$x => $git_dir/svn/$x\n";
-			rename "$git_dir/$x", "$git_dir/svn/$x" or
-			       croak "$!: $x";
-		}
-		$migrated++;
-	}
-	command_close_pipe($fh, $ctx);
-	print STDERR "Done migrating from a git-svn v1 layout\n";
-	$migrated;
-}
-
-sub read_old_urls {
-	my ($l_map, $pfx, $path) = @_;
-	my @dir;
-	foreach (<$path/*>) {
-		if (-r "$_/info/url") {
-			$pfx .= '/' if $pfx && $pfx !~ m!/$!;
-			my $ref_id = $pfx . basename $_;
-			my $url = ::file_to_s("$_/info/url");
-			$l_map->{$ref_id} = $url;
-		} elsif (-d $_) {
-			push @dir, $_;
-		}
-	}
-	foreach (@dir) {
-		my $x = $_;
-		$x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o;
-		read_old_urls($l_map, $x, $_);
-	}
-}
-
-sub migrate_from_v2 {
-	my @cfg = command(qw/config -l/);
-	return if grep /^svn-remote\..+\.url=/, @cfg;
-	my %l_map;
-	read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn");
-	my $migrated = 0;
-
-	require Git::SVN;
-	foreach my $ref_id (sort keys %l_map) {
-		eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) };
-		if ($@) {
-			Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id);
-		}
-		$migrated++;
-	}
-	$migrated;
-}
-
-sub minimize_connections {
-	require Git::SVN;
-	require Git::SVN::Ra;
-
-	my $r = Git::SVN::read_all_remotes();
-	my $new_urls = {};
-	my $root_repos = {};
-	foreach my $repo_id (keys %$r) {
-		my $url = $r->{$repo_id}->{url} or next;
-		my $fetch = $r->{$repo_id}->{fetch} or next;
-		my $ra = Git::SVN::Ra->new($url);
-
-		# skip existing cases where we already connect to the root
-		if (($ra->{url} eq $ra->{repos_root}) ||
-		    ($ra->{repos_root} eq $repo_id)) {
-			$root_repos->{$ra->{url}} = $repo_id;
-			next;
-		}
-
-		my $root_ra = Git::SVN::Ra->new($ra->{repos_root});
-		my $root_path = $ra->{url};
-		$root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##;
-		foreach my $path (keys %$fetch) {
-			my $ref_id = $fetch->{$path};
-			my $gs = Git::SVN->new($ref_id, $repo_id, $path);
-
-			# make sure we can read when connecting to
-			# a higher level of a repository
-			my ($last_rev, undef) = $gs->last_rev_commit;
-			if (!defined $last_rev) {
-				$last_rev = eval {
-					$root_ra->get_latest_revnum;
-				};
-				next if $@;
-			}
-			my $new = $root_path;
-			$new .= length $path ? "/$path" : '';
-			eval {
-				$root_ra->get_log([$new], $last_rev, $last_rev,
-			                          0, 0, 1, sub { });
-			};
-			next if $@;
-			$new_urls->{$ra->{repos_root}}->{$new} =
-			        { ref_id => $ref_id,
-				  old_repo_id => $repo_id,
-				  old_path => $path };
-		}
-	}
-
-	my @emptied;
-	foreach my $url (keys %$new_urls) {
-		# see if we can re-use an existing [svn-remote "repo_id"]
-		# instead of creating a(n ugly) new section:
-		my $repo_id = $root_repos->{$url} || $url;
-
-		my $fetch = $new_urls->{$url};
-		foreach my $path (keys %$fetch) {
-			my $x = $fetch->{$path};
-			Git::SVN->init($url, $path, $repo_id, $x->{ref_id});
-			my $pfx = "svn-remote.$x->{old_repo_id}";
-
-			my $old_fetch = quotemeta("$x->{old_path}:".
-			                          "$x->{ref_id}");
-			command_noisy(qw/config --unset/,
-			              "$pfx.fetch", '^'. $old_fetch . '$');
-			delete $r->{$x->{old_repo_id}}->
-			       {fetch}->{$x->{old_path}};
-			if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) {
-				command_noisy(qw/config --unset/,
-				              "$pfx.url");
-				push @emptied, $x->{old_repo_id}
-			}
-		}
-	}
-	if (@emptied) {
-		my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config";
-		print STDERR <<EOF;
-The following [svn-remote] sections in your config file ($file) are empty
-and can be safely removed:
-EOF
-		print STDERR "[svn-remote \"$_\"]\n" foreach @emptied;
-	}
-}
-
-sub migration_check {
-	migrate_from_v0();
-	migrate_from_v1();
-	migrate_from_v2();
-	minimize_connections() if $_minimize;
-}
-
 package Git::IndexInfo;
 use strict;
 use warnings;
diff --git a/perl/Git/SVN/Migration.pm b/perl/Git/SVN/Migration.pm
new file mode 100644
index 0000000..75d7429
--- /dev/null
+++ b/perl/Git/SVN/Migration.pm
@@ -0,0 +1,258 @@
+package Git::SVN::Migration;
+# these version numbers do NOT correspond to actual version numbers
+# of git nor git-svn.  They are just relative.
+#
+# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD
+#
+# v1 layout: .git/$id/info/url, refs/remotes/$id
+#
+# v2 layout: .git/svn/$id/info/url, refs/remotes/$id
+#
+# v3 layout: .git/svn/$id, refs/remotes/$id
+#            - info/url may remain for backwards compatibility
+#            - this is what we migrate up to this layout automatically,
+#            - this will be used by git svn init on single branches
+# v3.1 layout (auto migrated):
+#            - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink
+#              for backwards compatibility
+#
+# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id
+#            - this is only created for newly multi-init-ed
+#              repositories.  Similar in spirit to the
+#              --use-separate-remotes option in git-clone (now default)
+#            - we do not automatically migrate to this (following
+#              the example set by core git)
+#
+# v5 layout: .rev_db.$UUID => .rev_map.$UUID
+#            - newer, more-efficient format that uses 24-bytes per record
+#              with no filler space.
+#            - use xxd -c24 < .rev_map.$UUID to view and debug
+#            - This is a one-way migration, repositories updated to the
+#              new format will not be able to use old git-svn without
+#              rebuilding the .rev_db.  Rebuilding the rev_db is not
+#              possible if noMetadata or useSvmProps are set; but should
+#              be no problem for users that use the (sensible) defaults.
+use strict;
+use warnings;
+use Carp qw/croak/;
+use File::Path qw/mkpath/;
+use File::Basename qw/dirname basename/;
+
+our $_minimize;
+use Git qw(
+	command
+	command_noisy
+	command_output_pipe
+	command_close_pipe
+);
+
+sub migrate_from_v0 {
+	my $git_dir = $ENV{GIT_DIR};
+	return undef unless -d $git_dir;
+	my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
+	my $migrated = 0;
+	while (<$fh>) {
+		chomp;
+		my ($id, $orig_ref) = ($_, $_);
+		next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#;
+		next unless -f "$git_dir/$id/info/url";
+		my $new_ref = "refs/remotes/$id";
+		if (::verify_ref("$new_ref^0")) {
+			print STDERR "W: $orig_ref is probably an old ",
+			             "branch used by an ancient version of ",
+				     "git-svn.\n",
+				     "However, $new_ref also exists.\n",
+				     "We will not be able ",
+				     "to use this branch until this ",
+				     "ambiguity is resolved.\n";
+			next;
+		}
+		print STDERR "Migrating from v0 layout...\n" if !$migrated;
+		print STDERR "Renaming ref: $orig_ref => $new_ref\n";
+		command_noisy('update-ref', $new_ref, $orig_ref);
+		command_noisy('update-ref', '-d', $orig_ref, $orig_ref);
+		$migrated++;
+	}
+	command_close_pipe($fh, $ctx);
+	print STDERR "Done migrating from v0 layout...\n" if $migrated;
+	$migrated;
+}
+
+sub migrate_from_v1 {
+	my $git_dir = $ENV{GIT_DIR};
+	my $migrated = 0;
+	return $migrated unless -d $git_dir;
+	my $svn_dir = "$git_dir/svn";
+
+	# just in case somebody used 'svn' as their $id at some point...
+	return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url";
+
+	print STDERR "Migrating from a git-svn v1 layout...\n";
+	mkpath([$svn_dir]);
+	print STDERR "Data from a previous version of git-svn exists, but\n\t",
+	             "$svn_dir\n\t(required for this version ",
+	             "($::VERSION) of git-svn) does not exist.\n";
+	my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
+	while (<$fh>) {
+		my $x = $_;
+		next unless $x =~ s#^refs/remotes/##;
+		chomp $x;
+		next unless -f "$git_dir/$x/info/url";
+		my $u = eval { ::file_to_s("$git_dir/$x/info/url") };
+		next unless $u;
+		my $dn = dirname("$git_dir/svn/$x");
+		mkpath([$dn]) unless -d $dn;
+		if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID:
+			mkpath(["$git_dir/svn/svn"]);
+			print STDERR " - $git_dir/$x/info => ",
+			                "$git_dir/svn/$x/info\n";
+			rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or
+			       croak "$!: $x";
+			# don't worry too much about these, they probably
+			# don't exist with repos this old (save for index,
+			# and we can easily regenerate that)
+			foreach my $f (qw/unhandled.log index .rev_db/) {
+				rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f";
+			}
+		} else {
+			print STDERR " - $git_dir/$x => $git_dir/svn/$x\n";
+			rename "$git_dir/$x", "$git_dir/svn/$x" or
+			       croak "$!: $x";
+		}
+		$migrated++;
+	}
+	command_close_pipe($fh, $ctx);
+	print STDERR "Done migrating from a git-svn v1 layout\n";
+	$migrated;
+}
+
+sub read_old_urls {
+	my ($l_map, $pfx, $path) = @_;
+	my @dir;
+	foreach (<$path/*>) {
+		if (-r "$_/info/url") {
+			$pfx .= '/' if $pfx && $pfx !~ m!/$!;
+			my $ref_id = $pfx . basename $_;
+			my $url = ::file_to_s("$_/info/url");
+			$l_map->{$ref_id} = $url;
+		} elsif (-d $_) {
+			push @dir, $_;
+		}
+	}
+	foreach (@dir) {
+		my $x = $_;
+		$x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o;
+		read_old_urls($l_map, $x, $_);
+	}
+}
+
+sub migrate_from_v2 {
+	my @cfg = command(qw/config -l/);
+	return if grep /^svn-remote\..+\.url=/, @cfg;
+	my %l_map;
+	read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn");
+	my $migrated = 0;
+
+	require Git::SVN;
+	foreach my $ref_id (sort keys %l_map) {
+		eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) };
+		if ($@) {
+			Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id);
+		}
+		$migrated++;
+	}
+	$migrated;
+}
+
+sub minimize_connections {
+	require Git::SVN;
+	require Git::SVN::Ra;
+
+	my $r = Git::SVN::read_all_remotes();
+	my $new_urls = {};
+	my $root_repos = {};
+	foreach my $repo_id (keys %$r) {
+		my $url = $r->{$repo_id}->{url} or next;
+		my $fetch = $r->{$repo_id}->{fetch} or next;
+		my $ra = Git::SVN::Ra->new($url);
+
+		# skip existing cases where we already connect to the root
+		if (($ra->{url} eq $ra->{repos_root}) ||
+		    ($ra->{repos_root} eq $repo_id)) {
+			$root_repos->{$ra->{url}} = $repo_id;
+			next;
+		}
+
+		my $root_ra = Git::SVN::Ra->new($ra->{repos_root});
+		my $root_path = $ra->{url};
+		$root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##;
+		foreach my $path (keys %$fetch) {
+			my $ref_id = $fetch->{$path};
+			my $gs = Git::SVN->new($ref_id, $repo_id, $path);
+
+			# make sure we can read when connecting to
+			# a higher level of a repository
+			my ($last_rev, undef) = $gs->last_rev_commit;
+			if (!defined $last_rev) {
+				$last_rev = eval {
+					$root_ra->get_latest_revnum;
+				};
+				next if $@;
+			}
+			my $new = $root_path;
+			$new .= length $path ? "/$path" : '';
+			eval {
+				$root_ra->get_log([$new], $last_rev, $last_rev,
+			                          0, 0, 1, sub { });
+			};
+			next if $@;
+			$new_urls->{$ra->{repos_root}}->{$new} =
+			        { ref_id => $ref_id,
+				  old_repo_id => $repo_id,
+				  old_path => $path };
+		}
+	}
+
+	my @emptied;
+	foreach my $url (keys %$new_urls) {
+		# see if we can re-use an existing [svn-remote "repo_id"]
+		# instead of creating a(n ugly) new section:
+		my $repo_id = $root_repos->{$url} || $url;
+
+		my $fetch = $new_urls->{$url};
+		foreach my $path (keys %$fetch) {
+			my $x = $fetch->{$path};
+			Git::SVN->init($url, $path, $repo_id, $x->{ref_id});
+			my $pfx = "svn-remote.$x->{old_repo_id}";
+
+			my $old_fetch = quotemeta("$x->{old_path}:".
+			                          "$x->{ref_id}");
+			command_noisy(qw/config --unset/,
+			              "$pfx.fetch", '^'. $old_fetch . '$');
+			delete $r->{$x->{old_repo_id}}->
+			       {fetch}->{$x->{old_path}};
+			if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) {
+				command_noisy(qw/config --unset/,
+				              "$pfx.url");
+				push @emptied, $x->{old_repo_id}
+			}
+		}
+	}
+	if (@emptied) {
+		my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config";
+		print STDERR <<EOF;
+The following [svn-remote] sections in your config file ($file) are empty
+and can be safely removed:
+EOF
+		print STDERR "[svn-remote \"$_\"]\n" foreach @emptied;
+	}
+}
+
+sub migration_check {
+	migrate_from_v0();
+	migrate_from_v1();
+	migrate_from_v2();
+	minimize_connections() if $_minimize;
+}
+
+1;
diff --git a/perl/Makefile b/perl/Makefile
index 8493d76..ff83848 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -31,6 +31,7 @@ modules += Git/SVN/Memoize/YAML
 modules += Git/SVN/Fetcher
 modules += Git/SVN/Editor
 modules += Git/SVN/Log
+modules += Git/SVN/Migration
 modules += Git/SVN/Prompt
 modules += Git/SVN/Ra
 modules += Git/SVN/Utils
diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t
index 37626f4..1307b65 100644
--- a/t/Git-SVN/00compile.t
+++ b/t/Git-SVN/00compile.t
@@ -3,9 +3,10 @@
 use strict;
 use warnings;
 
-use Test::More tests => 4;
+use Test::More tests => 5;
 
 require_ok 'Git::SVN';
 require_ok 'Git::SVN::Utils';
 require_ok 'Git::SVN::Ra';
 require_ok 'Git::SVN::Log';
+require_ok 'Git::SVN::Migration';
-- 
1.7.11.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 5/8] Load all the modules in one place and before running code.
  2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
                   ` (3 preceding siblings ...)
  2012-07-27  0:26 ` [PATCH 4/8] Extract Git::SVN::Migration " Michael G. Schwern
@ 2012-07-27  0:26 ` Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 6/8] Move Git::IndexInfo into its own file Michael G. Schwern
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Michael G. Schwern @ 2012-07-27  0:26 UTC (permalink / raw)
  To: git, gitster; +Cc: robbat2, bwalton, normalperson, jrnieder, schwern

From: "Michael G. Schwern" <schwern@pobox.com>

Just makes the code easier to follow.  No functional change.

Also eliminate an unused lexical $SVN.
---
 git-svn.perl | 44 +++++++++++++++++++++-----------------------
 1 file changed, 21 insertions(+), 23 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index 3741e2e..fc49ad6 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -10,11 +10,26 @@ use vars qw/	$AUTHOR $VERSION
 $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
 $VERSION = '@@GIT_VERSION@@';
 
+use Carp qw/croak/;
+use Digest::MD5;
+use IO::File qw//;
+use File::Basename qw/dirname basename/;
+use File::Path qw/mkpath/;
+use File::Spec;
+use File::Find;
+use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
+use IPC::Open3;
+use Memoize;
+
 use Git::SVN;
+use Git::SVN::Editor;
+use Git::SVN::Fetcher;
+use Git::SVN::Ra;
+use Git::SVN::Prompt;
 use Git::SVN::Log;
 use Git::SVN::Migration;
-use Git::SVN::Utils qw(fatal can_compress);
 
+use Git::SVN::Utils qw(fatal can_compress);
 use Git qw(
     git_cmd_try
     command
@@ -26,6 +41,11 @@ use Git qw(
     command_close_bidi_pipe
 );
 
+BEGIN {
+	Memoize::memoize 'Git::config';
+	Memoize::memoize 'Git::config_bool';
+}
+
 
 # From which subdir have we been invoked?
 my $cmd_dir_prefix = eval {
@@ -79,28 +99,6 @@ sub _req_svn {
 	}
 }
 
-use Carp qw/croak/;
-use Digest::MD5;
-use IO::File qw//;
-use File::Basename qw/dirname basename/;
-use File::Path qw/mkpath/;
-use File::Spec;
-use File::Find;
-use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
-use IPC::Open3;
-use Git::SVN::Editor qw//;
-use Git::SVN::Fetcher qw//;
-use Git::SVN::Ra qw//;
-use Git::SVN::Prompt qw//;
-use Memoize;  # core since 5.8.0, Jul 2002
-
-BEGIN {
-	Memoize::memoize 'Git::config';
-	Memoize::memoize 'Git::config_bool';
-}
-
-my ($SVN);
-
 $sha1 = qr/[a-f\d]{40}/;
 $sha1_short = qr/[a-f\d]{4,40}/;
 my ($_stdin, $_help, $_edit,
-- 
1.7.11.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 6/8] Move Git::IndexInfo into its own file.
  2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
                   ` (4 preceding siblings ...)
  2012-07-27  0:26 ` [PATCH 5/8] Load all the modules in one place and before running code Michael G. Schwern
@ 2012-07-27  0:26 ` Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 7/8] Extract Git::SVN::GlobSpec from git-svn Michael G. Schwern
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Michael G. Schwern @ 2012-07-27  0:26 UTC (permalink / raw)
  To: git, gitster; +Cc: robbat2, bwalton, normalperson, jrnieder, schwern

From: "Michael G. Schwern" <schwern@pobox.com>

Straight cut & paste.  Didn't require any fixing.
---
 git-svn.perl            | 32 --------------------------------
 perl/Git/IndexInfo.pm   | 33 +++++++++++++++++++++++++++++++++
 perl/Git/SVN/Fetcher.pm |  1 +
 perl/Makefile           |  1 +
 t/Git-SVN/00compile.t   |  3 ++-
 5 files changed, 37 insertions(+), 33 deletions(-)
 create mode 100644 perl/Git/IndexInfo.pm

diff --git a/git-svn.perl b/git-svn.perl
index fc49ad6..0856a77 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -2041,38 +2041,6 @@ sub gc_directory {
 }
 
 
-package Git::IndexInfo;
-use strict;
-use warnings;
-use Git qw/command_input_pipe command_close_pipe/;
-
-sub new {
-	my ($class) = @_;
-	my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/);
-	bless { gui => $gui, ctx => $ctx, nr => 0}, $class;
-}
-
-sub remove {
-	my ($self, $path) = @_;
-	if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") {
-		return ++$self->{nr};
-	}
-	undef;
-}
-
-sub update {
-	my ($self, $mode, $hash, $path) = @_;
-	if (print { $self->{gui} } $mode, ' ', $hash, "\t", $path, "\0") {
-		return ++$self->{nr};
-	}
-	undef;
-}
-
-sub DESTROY {
-	my ($self) = @_;
-	command_close_pipe($self->{gui}, $self->{ctx});
-}
-
 package Git::SVN::GlobSpec;
 use strict;
 use warnings;
diff --git a/perl/Git/IndexInfo.pm b/perl/Git/IndexInfo.pm
new file mode 100644
index 0000000..a43108c
--- /dev/null
+++ b/perl/Git/IndexInfo.pm
@@ -0,0 +1,33 @@
+package Git::IndexInfo;
+use strict;
+use warnings;
+use Git qw/command_input_pipe command_close_pipe/;
+
+sub new {
+	my ($class) = @_;
+	my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/);
+	bless { gui => $gui, ctx => $ctx, nr => 0}, $class;
+}
+
+sub remove {
+	my ($self, $path) = @_;
+	if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") {
+		return ++$self->{nr};
+	}
+	undef;
+}
+
+sub update {
+	my ($self, $mode, $hash, $path) = @_;
+	if (print { $self->{gui} } $mode, ' ', $hash, "\t", $path, "\0") {
+		return ++$self->{nr};
+	}
+	undef;
+}
+
+sub DESTROY {
+	my ($self) = @_;
+	command_close_pipe($self->{gui}, $self->{ctx});
+}
+
+1;
diff --git a/perl/Git/SVN/Fetcher.pm b/perl/Git/SVN/Fetcher.pm
index ef8e9ed..76fae9b 100644
--- a/perl/Git/SVN/Fetcher.pm
+++ b/perl/Git/SVN/Fetcher.pm
@@ -57,6 +57,7 @@ sub new {
 	$self->{file_prop} = {};
 	$self->{absent_dir} = {};
 	$self->{absent_file} = {};
+	require Git::IndexInfo;
 	$self->{gii} = $git_svn->tmp_index_do(sub { Git::IndexInfo->new });
 	$self->{pathnameencoding} = Git::config('svn.pathnameencoding');
 	$self;
diff --git a/perl/Makefile b/perl/Makefile
index ff83848..2428e59 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -26,6 +26,7 @@ instdir_SQ = $(subst ','\'',$(prefix)/lib)
 
 modules += Git
 modules += Git/I18N
+modules += Git/IndexInfo
 modules += Git/SVN
 modules += Git/SVN/Memoize/YAML
 modules += Git/SVN/Fetcher
diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t
index 1307b65..5419438 100644
--- a/t/Git-SVN/00compile.t
+++ b/t/Git-SVN/00compile.t
@@ -3,10 +3,11 @@
 use strict;
 use warnings;
 
-use Test::More tests => 5;
+use Test::More tests => 6;
 
 require_ok 'Git::SVN';
 require_ok 'Git::SVN::Utils';
 require_ok 'Git::SVN::Ra';
 require_ok 'Git::SVN::Log';
 require_ok 'Git::SVN::Migration';
+require_ok 'Git::IndexInfo';
-- 
1.7.11.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 7/8] Extract Git::SVN::GlobSpec from git-svn.
  2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
                   ` (5 preceding siblings ...)
  2012-07-27  0:26 ` [PATCH 6/8] Move Git::IndexInfo into its own file Michael G. Schwern
@ 2012-07-27  0:26 ` Michael G. Schwern
  2012-07-27  0:26 ` [PATCH 8/8] Fix indents to match style Michael G. Schwern
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 16+ messages in thread
From: Michael G. Schwern @ 2012-07-27  0:26 UTC (permalink / raw)
  To: git, gitster; +Cc: robbat2, bwalton, normalperson, jrnieder, schwern

From: "Michael G. Schwern" <schwern@pobox.com>

Straight cut & paste.  That's the last class.

* Make Git::SVN load it on its own, its the only thing that needs it.
---
 git-svn.perl             | 59 ------------------------------------------------
 perl/Git/SVN.pm          |  2 ++
 perl/Git/SVN/GlobSpec.pm | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
 perl/Makefile            |  1 +
 t/Git-SVN/00compile.t    |  3 ++-
 5 files changed, 64 insertions(+), 60 deletions(-)
 create mode 100644 perl/Git/SVN/GlobSpec.pm

diff --git a/git-svn.perl b/git-svn.perl
index 0856a77..584e93a 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -2040,65 +2040,6 @@ sub gc_directory {
 	}
 }
 
-
-package Git::SVN::GlobSpec;
-use strict;
-use warnings;
-
-sub new {
-	my ($class, $glob, $pattern_ok) = @_;
-	my $re = $glob;
-	$re =~ s!/+$!!g; # no need for trailing slashes
-	my (@left, @right, @patterns);
-	my $state = "left";
-	my $die_msg = "Only one set of wildcard directories " .
-				"(e.g. '*' or '*/*/*') is supported: '$glob'\n";
-	for my $part (split(m|/|, $glob)) {
-		if ($part =~ /\*/ && $part ne "*") {
-			die "Invalid pattern in '$glob': $part\n";
-		} elsif ($pattern_ok && $part =~ /[{}]/ &&
-			 $part !~ /^\{[^{}]+\}/) {
-			die "Invalid pattern in '$glob': $part\n";
-		}
-		if ($part eq "*") {
-			die $die_msg if $state eq "right";
-			$state = "pattern";
-			push(@patterns, "[^/]*");
-		} elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) {
-			die $die_msg if $state eq "right";
-			$state = "pattern";
-			my $p = quotemeta($1);
-			$p =~ s/\\,/|/g;
-			push(@patterns, "(?:$p)");
-		} else {
-			if ($state eq "left") {
-				push(@left, $part);
-			} else {
-				push(@right, $part);
-				$state = "right";
-			}
-		}
-	}
-	my $depth = @patterns;
-	if ($depth == 0) {
-		die "One '*' is needed in glob: '$glob'\n";
-	}
-	my $left = join('/', @left);
-	my $right = join('/', @right);
-	$re = join('/', @patterns);
-	$re = join('\/',
-		   grep(length, quotemeta($left), "($re)", quotemeta($right)));
-	my $left_re = qr/^\/\Q$left\E(\/|$)/;
-	bless { left => $left, right => $right, left_regex => $left_re,
-	        regex => qr/$re/, glob => $glob, depth => $depth }, $class;
-}
-
-sub full_path {
-	my ($self, $path) = @_;
-	return (length $self->{left} ? "$self->{left}/" : '') .
-	       $path . (length $self->{right} ? "/$self->{right}" : '');
-}
-
 __END__
 
 Data structures:
diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
index 2e0d7f0..b8b3474 100644
--- a/perl/Git/SVN.pm
+++ b/perl/Git/SVN.pm
@@ -207,6 +207,8 @@ sub read_all_remotes {
 			    . "must start with 'refs/'\n")
 				unless $remote_ref =~ m{^refs/};
 			$local_ref = uri_decode($local_ref);
+
+			require Git::SVN::GlobSpec;
 			my $rs = {
 			    t => $t,
 			    remote => $remote,
diff --git a/perl/Git/SVN/GlobSpec.pm b/perl/Git/SVN/GlobSpec.pm
new file mode 100644
index 0000000..96cfd98
--- /dev/null
+++ b/perl/Git/SVN/GlobSpec.pm
@@ -0,0 +1,59 @@
+package Git::SVN::GlobSpec;
+use strict;
+use warnings;
+
+sub new {
+	my ($class, $glob, $pattern_ok) = @_;
+	my $re = $glob;
+	$re =~ s!/+$!!g; # no need for trailing slashes
+	my (@left, @right, @patterns);
+	my $state = "left";
+	my $die_msg = "Only one set of wildcard directories " .
+				"(e.g. '*' or '*/*/*') is supported: '$glob'\n";
+	for my $part (split(m|/|, $glob)) {
+		if ($part =~ /\*/ && $part ne "*") {
+			die "Invalid pattern in '$glob': $part\n";
+		} elsif ($pattern_ok && $part =~ /[{}]/ &&
+			 $part !~ /^\{[^{}]+\}/) {
+			die "Invalid pattern in '$glob': $part\n";
+		}
+		if ($part eq "*") {
+			die $die_msg if $state eq "right";
+			$state = "pattern";
+			push(@patterns, "[^/]*");
+		} elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) {
+			die $die_msg if $state eq "right";
+			$state = "pattern";
+			my $p = quotemeta($1);
+			$p =~ s/\\,/|/g;
+			push(@patterns, "(?:$p)");
+		} else {
+			if ($state eq "left") {
+				push(@left, $part);
+			} else {
+				push(@right, $part);
+				$state = "right";
+			}
+		}
+	}
+	my $depth = @patterns;
+	if ($depth == 0) {
+		die "One '*' is needed in glob: '$glob'\n";
+	}
+	my $left = join('/', @left);
+	my $right = join('/', @right);
+	$re = join('/', @patterns);
+	$re = join('\/',
+		   grep(length, quotemeta($left), "($re)", quotemeta($right)));
+	my $left_re = qr/^\/\Q$left\E(\/|$)/;
+	bless { left => $left, right => $right, left_regex => $left_re,
+	        regex => qr/$re/, glob => $glob, depth => $depth }, $class;
+}
+
+sub full_path {
+	my ($self, $path) = @_;
+	return (length $self->{left} ? "$self->{left}/" : '') .
+	       $path . (length $self->{right} ? "/$self->{right}" : '');
+}
+
+1;
diff --git a/perl/Makefile b/perl/Makefile
index 2428e59..22e3e81 100644
--- a/perl/Makefile
+++ b/perl/Makefile
@@ -31,6 +31,7 @@ modules += Git/SVN
 modules += Git/SVN/Memoize/YAML
 modules += Git/SVN/Fetcher
 modules += Git/SVN/Editor
+modules += Git/SVN/GlobSpec
 modules += Git/SVN/Log
 modules += Git/SVN/Migration
 modules += Git/SVN/Prompt
diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t
index 5419438..c92fee4 100644
--- a/t/Git-SVN/00compile.t
+++ b/t/Git-SVN/00compile.t
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 6;
+use Test::More tests => 7;
 
 require_ok 'Git::SVN';
 require_ok 'Git::SVN::Utils';
@@ -11,3 +11,4 @@ require_ok 'Git::SVN::Ra';
 require_ok 'Git::SVN::Log';
 require_ok 'Git::SVN::Migration';
 require_ok 'Git::IndexInfo';
+require_ok 'Git::SVN::GlobSpec';
-- 
1.7.11.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH 8/8] Fix indents to match style.
  2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
                   ` (6 preceding siblings ...)
  2012-07-27  0:26 ` [PATCH 7/8] Extract Git::SVN::GlobSpec from git-svn Michael G. Schwern
@ 2012-07-27  0:26 ` Michael G. Schwern
  2012-07-27  0:27 ` Extract remaining classes from git-svn Michael G Schwern
  2012-07-28  0:40 ` Eric Wong
  9 siblings, 0 replies; 16+ messages in thread
From: Michael G. Schwern @ 2012-07-27  0:26 UTC (permalink / raw)
  To: git, gitster; +Cc: robbat2, bwalton, normalperson, jrnieder, schwern

From: "Michael G. Schwern" <schwern@pobox.com>

---
 git-svn.perl | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index 584e93a..4d173d4 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -31,14 +31,14 @@ use Git::SVN::Migration;
 
 use Git::SVN::Utils qw(fatal can_compress);
 use Git qw(
-    git_cmd_try
-    command
-    command_oneline
-    command_noisy
-    command_output_pipe
-    command_close_pipe
-    command_bidi_pipe
-    command_close_bidi_pipe
+	git_cmd_try
+	command
+	command_oneline
+	command_noisy
+	command_output_pipe
+	command_close_pipe
+	command_bidi_pipe
+	command_close_bidi_pipe
 );
 
 BEGIN {
-- 
1.7.11.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: Extract remaining classes from git-svn
  2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
                   ` (7 preceding siblings ...)
  2012-07-27  0:26 ` [PATCH 8/8] Fix indents to match style Michael G. Schwern
@ 2012-07-27  0:27 ` Michael G Schwern
  2012-07-27 11:29   ` Erik Faye-Lund
  2012-07-28  0:40 ` Eric Wong
  9 siblings, 1 reply; 16+ messages in thread
From: Michael G Schwern @ 2012-07-27  0:27 UTC (permalink / raw)
  To: git; +Cc: gitster, robbat2, bwalton, normalperson, jrnieder

On 2012.7.26 5:25 PM, Michael G. Schwern wrote:
> This series of patches extracts the remaining classes from git-svn.  They're
> all simple extractions and functionally have no change.

PS  This is on top of the previous Git::SVN extraction patch series.


-- 
100. Claymore mines are not filled with yummy candy, and it is wrong
     to tell new soldiers that they are.
    -- The 213 Things Skippy Is No Longer Allowed To Do In The U.S. Army
           http://skippyslist.com/list/

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Extract remaining classes from git-svn
  2012-07-27  0:27 ` Extract remaining classes from git-svn Michael G Schwern
@ 2012-07-27 11:29   ` Erik Faye-Lund
  2012-07-27 19:00     ` Michael G Schwern
  0 siblings, 1 reply; 16+ messages in thread
From: Erik Faye-Lund @ 2012-07-27 11:29 UTC (permalink / raw)
  To: Michael G Schwern; +Cc: git, gitster, robbat2, bwalton, normalperson, jrnieder

On Fri, Jul 27, 2012 at 2:27 AM, Michael G Schwern <schwern@pobox.com> wrote:
> On 2012.7.26 5:25 PM, Michael G. Schwern wrote:
>> This series of patches extracts the remaining classes from git-svn.  They're
>> all simple extractions and functionally have no change.
>
> PS  This is on top of the previous Git::SVN extraction patch series.
>

Nice :-)

Do you have somewhere I can pull this from? I have a git-svn topic
that I suspect will be much easier to maintain on top of these
patches.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Extract remaining classes from git-svn
  2012-07-27 11:29   ` Erik Faye-Lund
@ 2012-07-27 19:00     ` Michael G Schwern
  0 siblings, 0 replies; 16+ messages in thread
From: Michael G Schwern @ 2012-07-27 19:00 UTC (permalink / raw)
  To: kusmabite; +Cc: git, gitster, robbat2, bwalton, normalperson, jrnieder

On 2012.7.27 4:29 AM, Erik Faye-Lund wrote:
> On Fri, Jul 27, 2012 at 2:27 AM, Michael G Schwern <schwern@pobox.com> wrote:
>> On 2012.7.26 5:25 PM, Michael G. Schwern wrote:
>>> This series of patches extracts the remaining classes from git-svn.  They're
>>> all simple extractions and functionally have no change.
>>
>> PS  This is on top of the previous Git::SVN extraction patch series.
>>
> 
> Nice :-)
> 
> Do you have somewhere I can pull this from? I have a git-svn topic
> that I suspect will be much easier to maintain on top of these
> patches.

Why yes I do!
https://github.com/schwern/git

The git-svn branches should be fairly self explanatory and they stack on top
of each other.  I'll probably be doing a lot of rebasing still, but there
should be little content change up to git-svn/canonicalize-accessors.  Up to
there passes tests with SVN 1.6.

Things get a little fuzzy after that.


-- 
24. Must not tell any officer that I am smarter than they are, especially
    if it's true.
    -- The 213 Things Skippy Is No Longer Allowed To Do In The U.S. Army
           http://skippyslist.com/list/

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Extract remaining classes from git-svn
  2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
                   ` (8 preceding siblings ...)
  2012-07-27  0:27 ` Extract remaining classes from git-svn Michael G Schwern
@ 2012-07-28  0:40 ` Eric Wong
  2012-07-28  4:05   ` Junio C Hamano
  9 siblings, 1 reply; 16+ messages in thread
From: Eric Wong @ 2012-07-28  0:40 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, robbat2, bwalton, jrnieder, Michael G. Schwern

"Michael G. Schwern" <schwern@pobox.com> wrote:
> This series of patches extracts the remaining classes from git-svn.  They're
> all simple extractions and functionally have no change.

I've also pushed this to the "extract-remaining" series which
also includes everything that's currently in my master.

I squashed Michael's 8/8 trivial change into 3/8 to avoid introducing
a needless commit.  (I don't feel strongly about indentation for
alignment purposes in use() statements much, but since he submitted
the change...)


The following changes since commit cdd159b2f56c9e69e37bbb8f5af301abd93e5407:

  Merge branch 'jc/test-lib-source-build-options-early' (2012-07-25 15:47:08 -0700)

are available in the git repository at:


  git://bogomips.org/git-svn extract-remaining

for you to fetch changes up to 3d9be15fc2b8c8198253ae1c4dcaa343b74c3b8d:

  Extract Git::SVN::GlobSpec from git-svn. (2012-07-27 22:36:19 +0000)

----------------------------------------------------------------
Junio C Hamano (1):
      perl: detect new files in MakeMaker builds

Michael G. Schwern (14):
      Quiet warning if Makefile.PL is run with -w and no --localedir
      Don't lose Error.pm if $@ gets clobbered.
      The Makefile.PL will now find .pm files itself.
      Extract some utilities from git-svn to allow extracting Git::SVN.
      Prepare Git::SVN for extraction into its own file.
      Extract Git::SVN from git-svn into its own .pm file.
      Move initialization of Git::SVN variables into Git::SVN.
      Prepare Git::SVN::Log for extraction from git-svn.
      Extract Git::SVN::Log from git-svn.
      Prepare Git::SVN::Migration for extraction from git-svn.
      Extract Git::SVN::Migration from git-svn.
      Load all the modules in one place and before running code.
      Move Git::IndexInfo into its own file.
      Extract Git::SVN::GlobSpec from git-svn.

 Makefile                       |    7 +
 git-svn.perl                   | 3119 +---------------------------------------
 perl/.gitignore                |    1 +
 perl/Git/IndexInfo.pm          |   33 +
 perl/Git/SVN.pm                | 2326 ++++++++++++++++++++++++++++++
 perl/Git/SVN/Fetcher.pm        |    1 +
 perl/Git/SVN/GlobSpec.pm       |   59 +
 perl/Git/SVN/Log.pm            |  395 +++++
 perl/Git/SVN/Migration.pm      |  258 ++++
 perl/Git/SVN/Utils.pm          |   59 +
 perl/Makefile                  |    9 +
 perl/Makefile.PL               |   35 +-
 t/Git-SVN/00compile.t          |   14 +
 t/Git-SVN/Utils/can_compress.t |   11 +
 t/Git-SVN/Utils/fatal.t        |   34 +
 15 files changed, 3272 insertions(+), 3089 deletions(-)
 create mode 100644 perl/Git/IndexInfo.pm
 create mode 100644 perl/Git/SVN.pm
 create mode 100644 perl/Git/SVN/GlobSpec.pm
 create mode 100644 perl/Git/SVN/Log.pm
 create mode 100644 perl/Git/SVN/Migration.pm
 create mode 100644 perl/Git/SVN/Utils.pm
 create mode 100644 t/Git-SVN/00compile.t
 create mode 100644 t/Git-SVN/Utils/can_compress.t
 create mode 100644 t/Git-SVN/Utils/fatal.t

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Extract remaining classes from git-svn
  2012-07-28  0:40 ` Eric Wong
@ 2012-07-28  4:05   ` Junio C Hamano
  2012-07-28  4:12     ` Eric Wong
  0 siblings, 1 reply; 16+ messages in thread
From: Junio C Hamano @ 2012-07-28  4:05 UTC (permalink / raw)
  To: Eric Wong; +Cc: git, robbat2, bwalton, jrnieder, Michael G. Schwern

Eric Wong <normalperson@yhbt.net> writes:

> "Michael G. Schwern" <schwern@pobox.com> wrote:
>> This series of patches extracts the remaining classes from git-svn.  They're
>> all simple extractions and functionally have no change.
>
> I've also pushed this to the "extract-remaining" series which
> also includes everything that's currently in my master.

Do you mean this should go in 1.7.12-rc1, or your master is for
1.7.12 and this is for post 1.7.12 but you are pushing it out to
help other developers who are working on git-svn as a preview?

I didn't look at these follow-up patches, but if you say they are
fit for the upcoming release, that is good enough for me.  Just
checking which way you want us to go.

Thanks.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Extract remaining classes from git-svn
  2012-07-28  4:05   ` Junio C Hamano
@ 2012-07-28  4:12     ` Eric Wong
  2012-07-28  4:25       ` Junio C Hamano
  0 siblings, 1 reply; 16+ messages in thread
From: Eric Wong @ 2012-07-28  4:12 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, robbat2, bwalton, jrnieder, Michael G. Schwern

Junio C Hamano <gitster@pobox.com> wrote:
> Eric Wong <normalperson@yhbt.net> writes:
> 
> > "Michael G. Schwern" <schwern@pobox.com> wrote:
> >> This series of patches extracts the remaining classes from git-svn.  They're
> >> all simple extractions and functionally have no change.
> >
> > I've also pushed this to the "extract-remaining" series which
> > also includes everything that's currently in my master.
> 
> Do you mean this should go in 1.7.12-rc1, or your master is for
> 1.7.12 and this is for post 1.7.12 but you are pushing it out to
> help other developers who are working on git-svn as a preview?

I'm comfortable with this series so far, so going into 1.7.12 is fine.
I pushed to a different branch because I didn't want to change the
commit on my previous pull request, sorry if I wasn't clear :x

> I didn't look at these follow-up patches, but if you say they are
> fit for the upcoming release, that is good enough for me.  Just
> checking which way you want us to go.

I looked at them a few times and things seem good.  I wouldn't
mind an extra set of eyes, though :)

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: Extract remaining classes from git-svn
  2012-07-28  4:12     ` Eric Wong
@ 2012-07-28  4:25       ` Junio C Hamano
  0 siblings, 0 replies; 16+ messages in thread
From: Junio C Hamano @ 2012-07-28  4:25 UTC (permalink / raw)
  To: Eric Wong; +Cc: git, robbat2, bwalton, jrnieder, Michael G. Schwern

Eric Wong <normalperson@yhbt.net> writes:

> Junio C Hamano <gitster@pobox.com> wrote:
>> Eric Wong <normalperson@yhbt.net> writes:
>> 
>> > "Michael G. Schwern" <schwern@pobox.com> wrote:
>> >> This series of patches extracts the remaining classes from git-svn.  They're
>> >> all simple extractions and functionally have no change.
>> >
>> > I've also pushed this to the "extract-remaining" series which
>> > also includes everything that's currently in my master.
>> 
>> Do you mean this should go in 1.7.12-rc1, or your master is for
>> 1.7.12 and this is for post 1.7.12 but you are pushing it out to
>> help other developers who are working on git-svn as a preview?
>
> I'm comfortable with this series so far, so going into 1.7.12 is fine.

OK.  Thanks.

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2012-07-28  4:25 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-07-27  0:25 Extract remaining classes from git-svn Michael G. Schwern
2012-07-27  0:26 ` [PATCH 1/8] Prepare Git::SVN::Log for extraction " Michael G. Schwern
2012-07-27  0:26 ` [PATCH 2/8] Extract Git::SVN::Log " Michael G. Schwern
2012-07-27  0:26 ` [PATCH 3/8] Prepare Git::SVN::Migration for extraction " Michael G. Schwern
2012-07-27  0:26 ` [PATCH 4/8] Extract Git::SVN::Migration " Michael G. Schwern
2012-07-27  0:26 ` [PATCH 5/8] Load all the modules in one place and before running code Michael G. Schwern
2012-07-27  0:26 ` [PATCH 6/8] Move Git::IndexInfo into its own file Michael G. Schwern
2012-07-27  0:26 ` [PATCH 7/8] Extract Git::SVN::GlobSpec from git-svn Michael G. Schwern
2012-07-27  0:26 ` [PATCH 8/8] Fix indents to match style Michael G. Schwern
2012-07-27  0:27 ` Extract remaining classes from git-svn Michael G Schwern
2012-07-27 11:29   ` Erik Faye-Lund
2012-07-27 19:00     ` Michael G Schwern
2012-07-28  0:40 ` Eric Wong
2012-07-28  4:05   ` Junio C Hamano
2012-07-28  4:12     ` Eric Wong
2012-07-28  4:25       ` Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).