From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:16
Hi,
I've fixed the git-svn tests for SVN 1.7 and tested with SVN 1.7.5. SVN 1.7
changed its expectations of path and URL formats and git-svn did not comply
with them. The new code uses SVN's own canonicalization routines where
available. This has been reported in several places...
https://bugs.gentoo.org/show_bug.cgi?id=418431http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=678764http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=661094http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=678137https://trac.macports.org/ticket/32753
It also split the internal classes out of git-svn.perl and into their own
modules in perl/Git/ to make them easier to work on. They compile alone, but
remain heavily intertwined with each other and git-svn. I didn't want to go
very far down that rabbit hole.
This makes the tests pass, but I'm pretty sure plenty of canonicalization
problems remain untested. Hopefully by attacking the problem at the root (ie.
in the Git::SVN and Git::SVN::Ra accessors) it will wipe out a range of problems.
t9100-git-svn-basic.sh tests 11-13 continue to fail for what look like
unrelated reasons to do with SVN and symlinks.
There's a lot of work in this change, so I felt it better to submit the
patches as a link to a git repository rather than attach a pile of patches.
Here is my repository, the work is in the fix-canonical branch.
https://github.com/schwern/git
Here's a summary of what was done.
* Changed git-svn's main canonicalization routines to use SVN's API.
* Replaced other ad-hoc canonicalization routines with git-svn's
single routine.
* Moved all the Git:: classes inside git-svn into their own .pm files
in perl/Git. They compile, but don't do much more than that alone.
They're still heavily dependent on git-svn. It's a start.
* Added Git::SVN->url, Git::SVN->path and Git::SVN::Ra->url to replace
code grabbing at hash keys.
* Made the above automatically canonicalize their path or url.
* Found some key locations which were not canonicalizing.
* Made the process of adding a new Perl module easier by having the
Makefile.PL scan for .pm files.
--
Alligator sandwich, and make it snappy!
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:54:16
Hi!
Michael G Schwern wrote:
I've fixed the git-svn tests for SVN 1.7 and tested with SVN 1.7.5.
Thanks. git-svn is not maintained by Junio but by Eric and others on
the list. I'm cc-ing Eric and Ben Walton so they can benefit from
your work.
SVN 1.7
changed its expectations of path and URL formats and git-svn did not comply
with them. The new code uses SVN's own canonicalization routines where
available. This has been reported in several places...
https://bugs.gentoo.org/show_bug.cgi?id=418431http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=678764http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=661094http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=678137https://trac.macports.org/ticket/32753
It also split the internal classes out of git-svn.perl and into their own
modules in perl/Git/ to make them easier to work on. They compile alone, but
remain heavily intertwined with each other and git-svn. I didn't want to go
very far down that rabbit hole.
This makes the tests pass, but I'm pretty sure plenty of canonicalization
problems remain untested. Hopefully by attacking the problem at the root (ie.
in the Git::SVN and Git::SVN::Ra accessors) it will wipe out a range of problems.
t9100-git-svn-basic.sh tests 11-13 continue to fail for what look like
unrelated reasons to do with SVN and symlinks.
There's a lot of work in this change, so I felt it better to submit the
patches as a link to a git repository rather than attach a pile of patches.
Here is my repository, the work is in the fix-canonical branch.
https://github.com/schwern/git
It is indeed quite the intimidating pile of patches, so I do not think
we will be able to apply it all in one chunk as-is. :(
My advice would be to send five or so of the patches that you would
like to be reviewed first, inline, one per message, in reply to this
message so we can start to work on that. Presumably the patches do
not regress git-svn's behavior but only make it saner, so even if this
is not a complete fix it should allow us to get started. See
Documentation/SubmittingPatches for more hints.
Thanks and hope that helps,
Jonathan
From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:16
On 2012.7.17 10:44 AM, Jonathan Nieder wrote:
Michael G Schwern wrote:
quoted
I've fixed the git-svn tests for SVN 1.7 and tested with SVN 1.7.5.
Thanks. git-svn is not maintained by Junio but by Eric and others on
the list. I'm cc-ing Eric and Ben Walton so they can benefit from
your work.
Thanks.
quoted
There's a lot of work in this change, so I felt it better to submit the
patches as a link to a git repository rather than attach a pile of patches.
Here is my repository, the work is in the fix-canonical branch.
https://github.com/schwern/git
It is indeed quite the intimidating pile of patches, so I do not think
we will be able to apply it all in one chunk as-is. :(
My advice would be to send five or so of the patches that you would
like to be reviewed first, inline, one per message, in reply to this
message so we can start to work on that. Presumably the patches do
not regress git-svn's behavior but only make it saner, so even if this
is not a complete fix it should allow us to get started. See
Documentation/SubmittingPatches for more hints.
Yes, the refactorings are all as rote as I could make them and only lightly
touch the code enough to make the canonicalization possible... with a bit more
work than was strictly necessary around the Perl build system.
Let me do a bit of rebase work to make things work better as a series of
submissions and I'll get back to you.
I'm new here, and I'll play nice, but let me go on record to state that Git
asking for individual emails with inline patches feels like Sendmail Corp
asking to be faxed an email thread. I was kinda hoping SubmittingPatches
wasn't serious about that and it was some sort of policy artifact that was
never updated. :-/
--
151. The proper way to report to my Commander is "Specialist Schwarz,
reporting as ordered, Sir" not "You can't prove a thing!"
-- The 213 Things Skippy Is No Longer Allowed To Do In The U.S. Army
http://skippyslist.com/list/
From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:16
On 2012.7.17 10:44 AM, Jonathan Nieder wrote:
My advice would be to send five or so of the patches that you would
like to be reviewed first, inline, one per message, in reply to this
message so we can start to work on that. Presumably the patches do
not regress git-svn's behavior but only make it saner, so even if this
is not a complete fix it should allow us to get started. See
Documentation/SubmittingPatches for more hints.
Ok, here goes.
First patch overhauls perl/Makefile.PL to make it easier to add .pm files,
which I'm going to be doing a lot of. Instead of having to manually add to
the %pm hash, it scans for .pm files.
It also moves Error.pm into a bundle directory. This both makes it just
another directory to scan (or not scan), but it also makes it possible to
bundle additional modules in the future. ExtUtils::MakeMaker uses this
technique itself.
You still have to remember to add them to the other Makefile.
This is available as a branch.
https://github.com/schwern/git/tree/git-svn/easier_modules
From 47a723a860cded6b16a716ea74c5bc029ee5b0ac Mon Sep 17 00:00:00 2001
From: "Michael G. Schwern" <redacted>
Date: Thu, 12 Jul 2012 00:05:38 -0700
Subject: [PATCH 01/11] Make the process of adding a module less blecherous.
* Scan for .pm files and build %pms rather than having to do it by hand.
* Move the bundled Error into its own directory so we can bundle other modules.
In addition...
* Add all the .pm files to the all dependency in the alternative Makefile
---
perl/Makefile | 6 ++--
perl/Makefile.PL | 42 +++++++++++++----------
perl/{private-Error.pm => bundles/Error/Error.pm} | 0
perl/bundles/README | 10 ++++++
4 files changed, 36 insertions(+), 22 deletions(-)
rename perl/{private-Error.pm => bundles/Error/Error.pm} (100%)
create mode 100644 perl/bundles/README
@@ -2,11 +2,16 @@ use strict;usewarnings;use ExtUtils::MakeMaker;use Getopt::Long;+use File::Find;++# Don't forget to update the perl/Makefile, too.+# Don't forget to test with NO_PERL_MAKEMAKER=YesPlease# Sanity: die at first unknown optionGetopt::Long::Configureqw/ pass_through /;-GetOptions("localedir=s"=>\my$localedir);+my$localedir='';+GetOptions("localedir=s"=>\$localedir);sub MY::postamble {return<<'MAKE_FRAG';
@@ -24,27 +29,25 @@ endifMAKE_FRAG}-# XXX. When editing this list:-#-# * Please update perl/Makefile, too.-# * Don't forget to test with NO_PERL_MAKEMAKER=YesPlease-my%pm=(-'Git.pm'=>'$(INST_LIBDIR)/Git.pm',-'Git/I18N.pm'=>'$(INST_LIBDIR)/Git/I18N.pm',-'Git/SVN/Memoize/YAML.pm'=>'$(INST_LIBDIR)/Git/SVN/Memoize/YAML.pm',-'Git/SVN/Fetcher.pm'=>'$(INST_LIBDIR)/Git/SVN/Fetcher.pm',-'Git/SVN/Editor.pm'=>'$(INST_LIBDIR)/Git/SVN/Editor.pm',-'Git/SVN/Prompt.pm'=>'$(INST_LIBDIR)/Git/SVN/Prompt.pm',-'Git/SVN/Ra.pm'=>'$(INST_LIBDIR)/Git/SVN/Ra.pm',-);-+my@pmlibdirs=("Git");# We come with our own bundled Error.pm. It's not in the set of default# Perl modules so install it if it's not available on the system yet.-eval{requireError};-if ($@ || $Error::VERSION < 0.15009) {-$pm{'private-Error.pm'}='$(INST_LIBDIR)/Error.pm';+if ( !eval { require Error } || $Error::VERSION < 0.15009) {+push@pmlibdirs,"bundles/Error";}++# Find all the .pm files in @pmlibdirs which includes our bundled modules.+my%pms;+findsub{+returnunless/\.pm$/;++my$inst=$File::Find::name;+$inst=~s{bundles/[^/]+/?}{};+$pms{$File::Find::name}='$(INST_LIBDIR)/'.$inst;+},@pmlibdirs;++# redirect stdout, otherwise the message "Writing perl.mak for Git"# disrupts the output for the target 'instlibdir'openSTDOUT,">&STDERR";
@@ -52,8 +55,9 @@ open STDOUT, ">&STDERR";WriteMakefile(NAME=>'Git',VERSION_FROM=>'Git.pm',-PM=>\%pm,+PM=>\%pms,PM_FILTER=>qq[\$(PERL)-pe"s<\\Q++LOCALEDIR++\\E><$localedir>"],MAKEFILE=>'perl.mak',INSTALLSITEMAN3DIR=>'$(SITEPREFIX)/share/man/man3');+
diff --git a/perl/private-Error.pm b/perl/bundles/Error/Error.pmsimilarity index 100%rename from perl/private-Error.pmrename to perl/bundles/Error/Error.pmdiff --git a/perl/bundles/README b/perl/bundles/READMEnew file mode 100644index 0000000..8a9ce39--- /dev/null+++ b/perl/bundles/README
@@ -0,0 +1,10 @@+This is any Perl modules we might want to bundle because Perl doesn't (or didn't)+ship with them. Each directory is a distribution containing all the PM files.++For example, if you wanted to bundle URI...+1) mkdir bundles/URI/++2) build URI & cp -r blib/lib/* into bundles/URI++3) add bundles/URI to @pmlibdirs in the Makefile.PL with the+ appropriate check for existance and high enough version
--
1.7.11.1
--
Alligator sandwich, and make it snappy!
From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:16
From 683a230e439f1d5ac2727ce4c2a74e93804fc72b Mon Sep 17 00:00:00 2001
From: "Michael G. Schwern" <redacted>
Date: Wed, 11 Jul 2012 22:16:01 -0700
Subject: [PATCH 03/11] Fix Git::SVN so it can at least compile alone.
It's still very intertwined with git-svn, but that's a lot of work. This
gets things working and tests passing again (as well as they were).
This required some parallel refactorings...
* fatal() moved out of git-svn into a new Git::SVN::Utils
* The $can_compress lexical moved into Git::SVN::Utils::can_compress()
* The $_prefix variable which stores the --prefix option is wrapped
in a function (rather than made global) so access to it can be
controlled. Git::SVN does not rely on this function being
available so it can work without git-svn loaded. In general,
the options should be put back together into a hash and accessed
via an options() function.
* A new tree of unit tests for the Git::SVN modules has been created.
It doesn't work with the existing Makefile, that can be worried
about later.
* Move initialization of Git::SVN globals into Git::SVN
* Have Git::SVN load the Git command* functions on its own
---
git-svn.perl | 33 ++++++++++++++++++---------------
perl/Git/SVN.pm | 29 ++++++++++++++++++++---------
perl/Git/SVN/Utils.pm | 19 +++++++++++++++++++
perl/Makefile | 2 ++
t/Git-SVN/00compile.t | 9 +++++++++
t/Git-SVN/Utils/can_compress.t | 11 +++++++++++
t/Git-SVN/Utils/fatal.t | 34 ++++++++++++++++++++++++++++++++++
7 files changed, 113 insertions(+), 24 deletions(-)
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
@@ -10,6 +10,9 @@ use vars qw/ $AUTHOR $VERSION$AUTHOR='Eric Wong <normalperson@yhbt.net>';$VERSION='@@GIT_VERSION@@';+useGit::SVN;+useGit::SVN::Utilsqw(fatal can_compress);+# From which subdir have we been invoked?my$cmd_dir_prefix=eval{command_oneline([qw/rev-parse --show-prefix/],STDERR=>0)
@@ -17,10 +20,8 @@ my $cmd_dir_prefix = eval {my$git_dir_user_set=1ifdefined$ENV{GIT_DIR};$ENV{GIT_DIR}||='.git';-$Git::SVN::default_repo_id='svn';-$Git::SVN::default_ref_id=$ENV{GIT_SVN_ID}||'git-svn';+$Git::SVN::Ra::_log_window_size=100;-$Git::SVN::_minimize_url='unset';if(!exists$ENV{SVN_SSH}&&exists$ENV{GIT_SSH}){$ENV{SVN_SSH}=$ENV{GIT_SSH};
@@ -35,8 +36,6 @@ $Git::SVN::Log::TZ = $ENV{TZ};$ENV{TZ}='UTC';$|=1;# unbuffer STDOUT-subfatal(@){printSTDERR"@_\n";exit1}-# All SVN commands do it. Otherwise we may die on SIGPIPE when the remote# repository decides to close the connection which we expect to be kept alive.$SIG{PIPE}='IGNORE';
@@ -66,7 +65,7 @@ sub _req_svn {fatal"Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)";}}-my$can_compress=eval{requireCompress::Zlib;1};+useCarpqw/croak/;useDigest::MD5;useIO::Fileqw//;
@@ -89,7 +88,7 @@ BEGIN {foreach(qw/commandcommand_onelinecommand_noisycommand_output_pipecommand_input_pipecommand_close_pipecommand_bidi_pipecommand_close_bidi_pipe/){-formy$package(qw(Git::SVN::Migration Git::SVN::Log Git::SVN),+formy$package(qw(Git::SVN::Migration Git::SVN::Log),__PACKAGE__){*{"${package}::$_"}=\&{"Git::$_"};}
@@ -109,7 +108,10 @@ my ($_stdin, $_help, $_edit,$_merge,$_strategy,$_preserve_merges,$_dry_run,$_local,$_prefix,$_no_checkout,$_url,$_verbose,$_git_format,$_commit_url,$_tag,$_merge_info,$_interactive);-$Git::SVN::_follow_parent=1;++# This is a refactoring artifact so Git::SVN can get at this variable.+subopt_prefix{return$_prefix||''}+$Git::SVN::Fetcher::_placeholder_filename=".gitignore";$_q||=0;my%remote_opts=('username=s'=>\$Git::SVN::Prompt::_username,
@@ -1578,7 +1580,7 @@ sub cmd_reset {}subcmd_gc{-if(!$can_compress){+if(!can_compress()){warn"Compress::Zlib could not be found; unhandled.log "."files will not be compressed.\n";}
@@ -2020,7 +2022,7 @@ sub md5sum {}subgc_directory{-if($can_compress&&-f$_&&basename($_)eq"unhandled.log"){+if(can_compress()&&-f$_&&basename($_)eq"unhandled.log"){my$out_filename=$_.".gz";openmy$in_fh,"<",$_ordie"Unable to open $_: $!\n";binmode$in_fh;
@@ -2042,6 +2044,7 @@ sub gc_directory {packageGit::SVN::Log;usestrict;usewarnings;+useGit::SVN::Utilsqw(fatal);usePOSIXqw/strftime/;useconstantcommit_log_separator=>('-'x72)."\n";usevarsqw/$TZ$limit$color$pager$non_recursive$verbose$oneline
@@ -2140,15 +2143,15 @@ sub config_pager {subrun_pager{returnunlessdefined$pager;pipemy($rfd,$wfd)orreturn;-defined(my$pid=fork)or::fatal"Can't fork: $!";+defined(my$pid=fork)orfatal"Can't fork: $!";if(!$pid){openSTDOUT,'>&',$wfdor-::fatal"Can't redirect to stdout: $!";+fatal"Can't redirect to stdout: $!";return;}-openSTDIN,'<&',$rfdor::fatal"Can't redirect stdin: $!";+openSTDIN,'<&',$rfdorfatal"Can't redirect stdin: $!";$ENV{LESS}||='FRSX';-exec$pageror::fatal"Can't run pager: $! ($pager)";+exec$pagerorfatal"Can't run pager: $! ($pager)";}subformat_svn_date{
@@ -2297,7 +2300,7 @@ sub cmd_show_log {}elsif($::_revision=~ /^\d+$/){$r_min=$r_max=$::_revision;}else{-::fatal"-r$::_revision is not supported, use ",+fatal"-r$::_revision is not supported, use ","standard 'git log' arguments instead";}}
@@ -20,6 +22,14 @@ BEGIN {$can_use_yaml=eval{requireGit::SVN::Memoize::YAML;1};}+useGitqw(commandcommand_onelinecommand_noisycommand_output_pipe
command_close_pipe);
+use Git::SVN::Utils qw(fatal can_compress);
+
+our $_follow_parent = 1;
+our $_minimize_url = 'unset';
+our $default_repo_id = 'svn';
+our $default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn';
+
my ($_gc_nr, $_gc_period);
# properties that we do not log:
@@ -840,8 +850,8 @@ sub assert_index_clean { command_noisy('read-tree', $treeish); $x = command_oneline('write-tree'); if ($y ne $x) {- ::fatal "trees ($treeish) $y != $x\n",- "Something is seriously wrong...";+ fatal "trees ($treeish) $y != $x\n",+ "Something is seriously wrong..."; } }); }
@@ -1196,7 +1206,7 @@ sub mkemptydirs { my %empty_dirs = (); my $gz_file = "$self->{dir}/unhandled.log.gz"; if (-f $gz_file) {- if (!$can_compress) {+ if (!can_compress()) { warn "Compress::Zlib could not be found; ", "empty directories in $gz_file will not be read\n"; } else {
@@ -1879,7 +1889,7 @@ sub set_tree { my ($self, $tree) = (shift, shift); my $log_entry = ::get_commit_entry($tree); unless ($self->{last_rev}) {- ::fatal("Must have an existing revision to commit");+ fatal("Must have an existing revision to commit"); } my %ed_opts = ( r => $self->{last_rev}, log => $log_entry->{log},
@@ -2237,12 +2247,13 @@ sub find_rev_after { sub _new { my ($class, $repo_id, $ref_id, $path) = @_; unless (defined $repo_id && length $repo_id) {- $repo_id = $Git::SVN::default_repo_id;+ $repo_id = $default_repo_id; } unless (defined $ref_id && length $ref_id) {- $_prefix = '' unless defined($_prefix);+ # Access the prefix option from the git-svn main program if it's loaded.+ my $prefix = defined &::opt_prefix ? ::opt_prefix() : ""; $_[2] = $ref_id =- "refs/remotes/$_prefix$Git::SVN::default_ref_id";+ "refs/remotes/$prefix$default_ref_id"; } $_[1] = $repo_id; my $dir = "$ENV{GIT_DIR}/svn/$ref_id";
@@ -0,0 +1,11 @@+#!/usr/bin/perl++usestrict;+usewarnings;++useTest::More'no_plan';++useGit::SVN::Utilsqw(can_compress);++# !! is the "convert this to boolean" operator.+is!!can_compress(),!!eval{requireCompress::Zlib};
@@ -0,0 +1,34 @@+#!/usr/bin/perl++usestrict;+usewarnings;++useTest::More'no_plan';++BEGIN{+ # Override exit at BEGIN time before Git::SVN::Utils is loaded+ # so it will see our local exit later.+*CORE::GLOBAL::exit=sub(;$){+return@_?CORE::exit($_[0]):CORE::exit();+};+}++useGit::SVN::Utilsqw(fatal);++# fatal()+{+ # Capture the exit code and prevent exit.+my$exit_status;+nowarnings'redefine';+local*CORE::GLOBAL::exit=sub{$exit_status=$_[0]||0};++ # Trap fatal's message to STDERR+my$stderr;+closeSTDERR;+okopenSTDERR,">", \$stderr;++fatal"Some","Stuff","Happened";++is$stderr,"Some Stuff Happened\n";+is$exit_status,1;+}
From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:16
From 5f0b609e9b0a70c86c46b48f0b180c96c3355a14 Mon Sep 17 00:00:00 2001
From: "Michael G. Schwern" <redacted>
Date: Tue, 17 Jul 2012 15:40:03 -0700
Subject: [PATCH 04/11] Extract Git::SVN::Log from git-svn.
This is a straight cut & paste. Next commit will make it work. This will
make it easier to see the differences in Git::SVN::Log.
---
git-svn.perl | 387 ---------------------------------------------------
perl/Git/SVN/Log.pm | 388 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 388 insertions(+), 387 deletions(-)
create mode 100644 perl/Git/SVN/Log.pm
@@ -2041,393 +2041,6 @@ sub gc_directory {}-packageGit::SVN::Log;-usestrict;-usewarnings;-useGit::SVN::Utilsqw(fatal);-usePOSIXqw/strftime/;-useconstantcommit_log_separator=>('-'x72)."\n";-usevarsqw/$TZ$limit$color$pager$non_recursive$verbose$oneline-%rusers$show_commit$incremental/;-my$l_fmt;--subcmt_showable{-my($c)=@_;-return1ifdefined$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@logwhile($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]);-}-returndefined$c->{r};-}--sublog_use_color{-return$color||Git->repository->get_colorbool('color.diff');-}--subgit_svn_log_cmd{-my($r_min,$r_max,@args)=@_;-my$head='HEAD';-my(@files,@log_opts);-foreachmy$x(@args){-if($xeq'--'||@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);-$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'iflog_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_mineq$c_max){-push@cmd,'--max-count=1',$c_min;-}else{-push@cmd,'--boundary',"$c_min..$c_max";-}-}-return(@cmd,@files);-}--# adapted from pager.c-subconfig_pager{-if(!-t*STDOUT){-$ENV{GIT_PAGER_IN_USE}='false';-$pager=undef;-return;-}-chomp($pager=command_oneline(qw(var GIT_PAGER)));-if($pagereq'cat'){-$pager=undef;-}-$ENV{GIT_PAGER_IN_USE}=defined($pager);-}--subrun_pager{-returnunlessdefined$pager;-pipemy($rfd,$wfd)orreturn;-defined(my$pid=fork)orfatal"Can't fork: $!";-if(!$pid){-openSTDOUT,'>&',$wfdor-fatal"Can't redirect to stdout: $!";-return;-}-openSTDIN,'<&',$rfdorfatal"Can't redirect stdin: $!";-$ENV{LESS}||='FRSX';-exec$pagerorfatal"Can't run pager: $! ($pager)";-}--subformat_svn_date{-my$t=shift||time;-my$gmoff=Git::SVN::get_tz($t);-returnstrftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)",localtime($t));-}--subparse_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;-}--subset_local_timezone{-if(defined$TZ){-$ENV{TZ}=$TZ;-}else{-delete$ENV{TZ};-}-}--subtz_to_s_offset{-my($tz)=@_;-$tz=~s/(\d\d)$//;-return($1*60)+($tz*3600);-}--subget_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);-}--subprocess_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);-return0;-}-return1if$r_min==$r_max;-if($r_min<$r_max){-# we need to reverse the print order-return0if(defined$limit&&--$limit<0);-push@$defer,$c;-return1;-}-if($r_min!=$r_max){-return1if($r_min<$c->{r});-return1if($r_max>$c->{r});-}-}-return0if(defined$limit&&--$limit<0);-show_commit($c);-return1;-}--subshow_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);-}-}--subshow_commit_changed_paths{-my($c)=@_;-returnunless$c->{changed};-print"Changed paths:\n",@{$c->{changed}};-}--subshow_commit_normal{-my($c)=@_;-printcommit_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";--}-foreachmy$x(qw/raw stat diff/){-if($c->{$x}){-print"\n";-print$_foreach@{$c->{$x}}-}-}-}--subcmd_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){-printcommit_log_separatorunless$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-gotoout;-}-$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)foreachreverse@k;-}-out:-close$log;-printcommit_log_separatorunless$incremental||$oneline;-}--subcmd_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]);--foreachmy$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);-}-packageGit::SVN::Migration;# these version numbers do NOT correspond to actual version numbers# of git nor git-svn. They are just relative.
@@ -0,0 +1,388 @@+packageGit::SVN::Log;+usestrict;+usewarnings;+useGit::SVN::Utilsqw(fatal);+usePOSIXqw/strftime/;+useconstantcommit_log_separator=>('-'x72)."\n";+usevarsqw/$TZ$limit$color$pager$non_recursive$verbose$oneline+%rusers$show_commit$incremental/;+my$l_fmt;++subcmt_showable{+my($c)=@_;+return1ifdefined$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-filecommit/,$c->{c});++# shift off the headers+shift@logwhile($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]);+}+returndefined$c->{r};+}++sublog_use_color{+return$color||Git->repository->get_colorbool('color.diff');+}++subgit_svn_log_cmd{+my($r_min,$r_max,@args)=@_;+my$head='HEAD';+my(@files,@log_opts);+foreachmy$x(@args){+if($xeq'--'||@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);+$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'iflog_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_mineq$c_max){+push@cmd,'--max-count=1',$c_min;+}else{+push@cmd,'--boundary',"$c_min..$c_max";+}+}+return(@cmd,@files);+}++# adapted from pager.c+subconfig_pager{+if(!-t*STDOUT){+$ENV{GIT_PAGER_IN_USE}='false';+$pager=undef;+return;+}+chomp($pager=command_oneline(qw(varGIT_PAGER)));+if($pagereq'cat'){+$pager=undef;+}+$ENV{GIT_PAGER_IN_USE}=defined($pager);+}++subrun_pager{+returnunlessdefined$pager;+pipemy($rfd,$wfd)orreturn;+defined(my$pid=fork)orfatal"Can't fork: $!";+if(!$pid){+openSTDOUT,'>&',$wfdor+fatal"Can't redirect to stdout: $!";+return;+}+openSTDIN,'<&',$rfdorfatal"Can't redirect stdin: $!";+$ENV{LESS}||='FRSX';+exec$pagerorfatal"Can't run pager: $! ($pager)";+}++subformat_svn_date{+my$t=shift||time;+my$gmoff=Git::SVN::get_tz($t);+returnstrftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)",localtime($t));+}++subparse_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;+}++subset_local_timezone{+if(defined$TZ){+$ENV{TZ}=$TZ;+}else{+delete$ENV{TZ};+}+}++subtz_to_s_offset{+my($tz)=@_;+$tz=~s/(\d\d)$//;+return($1*60)+($tz*3600);+}++subget_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);+}++subprocess_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);+return0;+}+return1if$r_min==$r_max;+if($r_min<$r_max){+# we need to reverse the print order+return0if(defined$limit&&--$limit<0);+push@$defer,$c;+return1;+}+if($r_min!=$r_max){+return1if($r_min<$c->{r});+return1if($r_max>$c->{r});+}+}+return0if(defined$limit&&--$limit<0);+show_commit($c);+return1;+}++subshow_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);+}+}++subshow_commit_changed_paths{+my($c)=@_;+returnunless$c->{changed};+print"Changed paths:\n",@{$c->{changed}};+}++subshow_commit_normal{+my($c)=@_;+printcommit_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='1line';+}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";++}+foreachmy$x(qw/rawstatdiff/){+if($c->{$x}){+print"\n";+print$_foreach@{$c->{$x}}+}+}+}++subcmd_show_log{+my(@args)=@_;+my($r_min,$r_max);+my$r_last=-1;#preventdupes+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){+printcommit_log_separatorunless$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+gotoout;+}+$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+fileschanged,\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)foreachreverse@k;+}+out:+close$log;+printcommit_log_separatorunless$incremental||$oneline;+}++subcmd_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;#distinctshakeys++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]);++foreachmy$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;
From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:16
From 8f70be0424a770c299b6a0c5bf99e4030e5e4d92 Mon Sep 17 00:00:00 2001
From: "Michael G. Schwern" <redacted>
Date: Thu, 12 Jul 2012 16:58:53 -0700
Subject: [PATCH 05/11] Make Git::SVN::Log work.
Changes to Git::SVN::Log to make it compile....
* Change the $_git_format lexical only used by Git::SVN::Log into a
Git::SVN::Log global
* Have it load the Git command functions itself
---
git-svn.perl | 8 +++++---
perl/Git/SVN/Log.pm | 10 +++++++++-
perl/Makefile | 1 +
t/Git-SVN/00compile.t | 4 +++-
4 files changed, 18 insertions(+), 5 deletions(-)
@@ -11,6 +11,8 @@ $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';$VERSION='@@GIT_VERSION@@';useGit::SVN;+useGit::SVN::Log;+useGit::SVN::Utilsqw(fatal can_compress);# From which subdir have we been invoked?
@@ -88,7 +90,7 @@ BEGIN {foreach(qw/commandcommand_onelinecommand_noisycommand_output_pipecommand_input_pipecommand_close_pipecommand_bidi_pipecommand_close_bidi_pipe/){-formy$package(qw(Git::SVN::Migration Git::SVN::Log),+formy$package(qw(Git::SVN::Migration),__PACKAGE__){*{"${package}::$_"}=\&{"Git::$_"};}
@@ -107,7 +109,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 variable.subopt_prefix{return$_prefix||''}
@@ -271,7 +273,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,
@@ -1,12 +1,17 @@packageGit::SVN::Log;+usestrict;usewarnings;++useGitqw(commandcommand_onelinecommand_output_pipecommand_close_pipe);useGit::SVN::Utilsqw(fatal);usePOSIXqw/strftime/;useconstantcommit_log_separator=>('-'x72)."\n";usevarsqw/$TZ$limit$color$pager$non_recursive$verbose$oneline%rusers$show_commit$incremental/;-my$l_fmt;++# Options set in git-svn+our$_git_format;subcmt_showable{my($c)=@_;
@@ -52,6 +57,7 @@ sub git_svn_log_cmd {}my($url,$rev,$uuid,$gs)=::working_head_info($head);+requireGit::SVN;$gs||=Git::SVN->_new;my@cmd=(qw/log--abbrev-commit--pretty=raw--default/,$gs->refname);
@@ -2043,252 +2043,6 @@ sub gc_directory {}-packageGit::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.-usestrict;-usewarnings;-useCarpqw/croak/;-useFile::Pathqw/mkpath/;-useFile::Basenameqw/dirname basename/;-usevarsqw/$_minimize/;--submigrate_from_v0{-my$git_dir=$ENV{GIT_DIR};-returnundefunless-d$git_dir;-my($fh,$ctx)=command_output_pipe(qw/rev-parse --symbolic --all/);-my$migrated=0;-while(<$fh>){-chomp;-my($id,$orig_ref)=($_,$_);-nextunless$id=~s#^refs/heads/(.+)-HEAD$#$1#;-nextunless-f"$git_dir/$id/info/url";-my$new_ref="refs/remotes/$id";-if(::verify_ref("$new_ref^0")){-printSTDERR"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;-}-printSTDERR"Migrating from v0 layout...\n"if!$migrated;-printSTDERR"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);-printSTDERR"Done migrating from v0 layout...\n"if$migrated;-$migrated;-}--submigrate_from_v1{-my$git_dir=$ENV{GIT_DIR};-my$migrated=0;-return$migratedunless-d$git_dir;-my$svn_dir="$git_dir/svn";--# just in case somebody used 'svn' as their $id at some point...-return$migratedif-d$svn_dir&&!-f"$svn_dir/info/url";--printSTDERR"Migrating from a git-svn v1 layout...\n";-mkpath([$svn_dir]);-printSTDERR"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=$_;-nextunless$x=~s#^refs/remotes/##;-chomp$x;-nextunless-f"$git_dir/$x/info/url";-my$u=eval{::file_to_s("$git_dir/$x/info/url")};-nextunless$u;-my$dn=dirname("$git_dir/svn/$x");-mkpath([$dn])unless-d$dn;-if($xeq'svn'){# they used 'svn' as GIT_SVN_ID:-mkpath(["$git_dir/svn/svn"]);-printSTDERR" - $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)-foreachmy$f(qw/unhandled.log index .rev_db/){-rename"$git_dir/$x/$f","$git_dir/svn/$x/$f";-}-}else{-printSTDERR" - $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);-printSTDERR"Done migrating from a git-svn v1 layout\n";-$migrated;-}--subread_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,$_);-}-}--submigrate_from_v2{-my@cfg=command(qw/config -l/);-returnifgrep/^svn-remote\..+\.url=/,@cfg;-my%l_map;-read_old_urls(\%l_map,'',"$ENV{GIT_DIR}/svn");-my$migrated=0;--foreachmy$ref_id(sortkeys%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;-}--subminimize_connections{-my$r=Git::SVN::read_all_remotes();-my$new_urls={};-my$root_repos={};-foreachmy$repo_id(keys%$r){-my$url=$r->{$repo_id}->{url}ornext;-my$fetch=$r->{$repo_id}->{fetch}ornext;-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(/|$)##;-foreachmy$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;-};-nextif$@;-}-my$new=$root_path;-$new.=length$path?"/$path":'';-eval{-$root_ra->get_log([$new],$last_rev,$last_rev,-0,0,1,sub{});-};-nextif$@;-$new_urls->{$ra->{repos_root}}->{$new}=-{ref_id=>$ref_id,-old_repo_id=>$repo_id,-old_path=>$path};-}-}--my@emptied;-foreachmy$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};-foreachmy$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";-printSTDERR<<EOF;-Thefollowing[svn-remote]sectionsinyourconfigfile($file)areempty-andcanbesafelyremoved:-EOF-printSTDERR"[svn-remote \"$_\"]\n"foreach@emptied;-}-}--submigration_check{-migrate_from_v0();-migrate_from_v1();-migrate_from_v2();-minimize_connections()if$_minimize;-}-packageGit::IndexInfo;usestrict;usewarnings;
@@ -0,0 +1,247 @@+packageGit::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.+usestrict;+usewarnings;+useCarpqw/croak/;+useFile::Pathqw/mkpath/;+useFile::Basenameqw/dirnamebasename/;+usevarsqw/$_minimize/;++submigrate_from_v0{+my$git_dir=$ENV{GIT_DIR};+returnundefunless-d$git_dir;+my($fh,$ctx)=command_output_pipe(qw/rev-parse--symbolic--all/);+my$migrated=0;+while(<$fh>){+chomp;+my($id,$orig_ref)=($_,$_);+nextunless$id=~s#^refs/heads/(.+)-HEAD$#$1#;+nextunless-f"$git_dir/$id/info/url";+my$new_ref="refs/remotes/$id";+if(::verify_ref("$new_ref^0")){+printSTDERR"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;+}+printSTDERR"Migrating from v0 layout...\n"if!$migrated;+printSTDERR"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);+printSTDERR"Done migrating from v0 layout...\n"if$migrated;+$migrated;+}++submigrate_from_v1{+my$git_dir=$ENV{GIT_DIR};+my$migrated=0;+return$migratedunless-d$git_dir;+my$svn_dir="$git_dir/svn";++# just in case somebody used 'svn' as their $id at some point...+return$migratedif-d$svn_dir&&!-f"$svn_dir/info/url";++printSTDERR"Migrating from a git-svn v1 layout...\n";+mkpath([$svn_dir]);+printSTDERR"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=$_;+nextunless$x=~s#^refs/remotes/##;+chomp$x;+nextunless-f"$git_dir/$x/info/url";+my$u=eval{::file_to_s("$git_dir/$x/info/url")};+nextunless$u;+my$dn=dirname("$git_dir/svn/$x");+mkpath([$dn])unless-d$dn;+if($xeq'svn'){#theyused'svn'asGIT_SVN_ID:+mkpath(["$git_dir/svn/svn"]);+printSTDERR" - $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)+foreachmy$f(qw/unhandled.logindex.rev_db/){+rename"$git_dir/$x/$f","$git_dir/svn/$x/$f";+}+}else{+printSTDERR" - $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);+printSTDERR"Done migrating from a git-svn v1 layout\n";+$migrated;+}++subread_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,$_);+}+}++submigrate_from_v2{+my@cfg=command(qw/config-l/);+returnifgrep/^svn-remote\..+\.url=/,@cfg;+my%l_map;+read_old_urls(\%l_map,'',"$ENV{GIT_DIR}/svn");+my$migrated=0;++foreachmy$ref_id(sortkeys%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;+}++subminimize_connections{+my$r=Git::SVN::read_all_remotes();+my$new_urls={};+my$root_repos={};+foreachmy$repo_id(keys%$r){+my$url=$r->{$repo_id}->{url}ornext;+my$fetch=$r->{$repo_id}->{fetch}ornext;+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(/|$)##;+foreachmy$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;+};+nextif$@;+}+my$new=$root_path;+$new.=length$path?"/$path":'';+eval{+$root_ra->get_log([$new],$last_rev,$last_rev,+0,0,1,sub{});+};+nextif$@;+$new_urls->{$ra->{repos_root}}->{$new}=+{ref_id=>$ref_id,+old_repo_id=>$repo_id,+old_path=>$path};+}+}++my@emptied;+foreachmy$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};+foreachmy$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";+printSTDERR<<EOF;+Thefollowing[svn-remote]sectionsinyourconfigfile($file)areempty+andcanbesafelyremoved:+EOF+printSTDERR"[svn-remote \"$_\"]\n"foreach@emptied;+}+}++submigration_check{+migrate_from_v0();+migrate_from_v1();+migrate_from_v2();+minimize_connections()if$_minimize;+}++1;
From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:16
From cb1a73929da15e87fa3dcc41c4cfa9ca592081fa Mon Sep 17 00:00:00 2001
From: "Michael G. Schwern" <redacted>
Date: Thu, 12 Jul 2012 17:14:24 -0700
Subject: [PATCH 07/11] Fix Git::SVN::Migration after its move.
Also...
* eliminate the big "import all the Git command functions" loop, nothing needs it
any more
* only load Git::SVN::Migration if we need it
---
git-svn.perl | 28 +++++++++++++++-------------
perl/Git/SVN/Migration.pm | 16 +++++++++++++++-
perl/Makefile | 1 +
t/Git-SVN/00compile.t | 3 ++-
4 files changed, 33 insertions(+), 15 deletions(-)
@@ -11,7 +11,6 @@ $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';$VERSION='@@GIT_VERSION@@';useGit::SVN;-useGit::SVN::Log;useGit::SVN::Utilsqw(fatal can_compress);
@@ -77,24 +76,26 @@ use File::Spec;useFile::Find;useGetopt::Longqw/:config gnu_getopt no_ignore_case auto_abbrev/;useIPC::Open3;-useGit;++useGitqw(+git_cmd_try+command+command_oneline+command_noisy+command_output_pipe+command_close_pipe+command_bidi_pipe+command_close_bidi_pipe+);+useGit::SVN::Editorqw//;useGit::SVN::Fetcherqw//;-useGit::SVN::Raqw//;+useGit::SVN::Log;useGit::SVN::Promptqw//;+useGit::SVN::Raqw//;useMemoize;# core since 5.8.0, Jul 2002BEGIN{-# import functions from Git into our packages, en masse-nostrict'refs';-foreach(qw/commandcommand_onelinecommand_noisycommand_output_pipe-command_input_pipecommand_close_pipe-command_bidi_pipecommand_close_bidi_pipe/){-formy$package(qw(Git::SVN::Migration),-__PACKAGE__){-*{"${package}::$_"}=\&{"Git::$_"};-}-}Memoize::memoize'Git::config';Memoize::memoize'Git::config_bool';}
@@ -365,6 +366,7 @@ if (defined $_authors_prog) {}unless($cmd=~ /^(?:clone|init|multi-init|commit-diff)$/){+requireGit::SVN::Migration;Git::SVN::Migration::migration_check();}Git::SVN::init_vars();
@@ -32,12 +32,22 @@ package Git::SVN::Migration;# 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.+usestrict;usewarnings;+useCarpqw/croak/;useFile::Pathqw/mkpath/;useFile::Basenameqw/dirnamebasename/;-usevarsqw/$_minimize/;++our$_minimize;++useGitqw(+command+command_noisy+command_output_pipe+command_close_pipe+);submigrate_from_v0{my$git_dir=$ENV{GIT_DIR};
@@ -146,6 +156,7 @@ sub migrate_from_v2 {read_old_urls(\%l_map,'',"$ENV{GIT_DIR}/svn");my$migrated=0;+requireGit::SVN;foreachmy$ref_id(sortkeys%l_map){eval{Git::SVN->init($l_map{$ref_id},'',undef,$ref_id)};if($@){
@@ -157,6 +168,9 @@ sub migrate_from_v2 {}subminimize_connections{+requireGit::SVN;+requireGit::SVN::Ra;+my$r=Git::SVN::read_all_remotes();my$new_urls={};my$root_repos={};
From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:16
From 9ff49d9e91c9741d501620ac47f78d8ff8ef9983 Mon Sep 17 00:00:00 2001
From: "Michael G. Schwern" <redacted>
Date: Tue, 17 Jul 2012 15:51:53 -0700
Subject: [PATCH 08/11] Cut & paste Git::IndexInfo into its own file.
No other changes, those are next commit so they can be seen in the diff.
---
git-svn.perl | 32 --------------------------------
perl/Git/IndexInfo.pm | 33 +++++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+), 32 deletions(-)
create mode 100644 perl/Git/IndexInfo.pm
@@ -2045,64 +2045,6 @@ sub gc_directory {}-packageGit::SVN::GlobSpec;-usestrict;-usewarnings;--subnew{-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";-formy$part(split(m|/|,$glob)){-if($part=~ /\*/&&$partne"*"){-die"Invalid pattern in '$glob': $part\n";-}elsif($pattern_ok&&$part=~ /[{}]/&&-$part!~/^\{[^{}]+\}/){-die"Invalid pattern in '$glob': $part\n";-}-if($parteq"*"){-die$die_msgif$stateeq"right";-$state="pattern";-push(@patterns,"[^/]*");-}elsif($pattern_ok&&$part=~ /^\{(.*)\}$/){-die$die_msgif$stateeq"right";-$state="pattern";-my$p=quotemeta($1);-$p=~s/\\,/|/g;-push(@patterns,"(?:$p)");-}else{-if($stateeq"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;-}--subfull_path{-my($self,$path)=@_;-return(length$self->{left}?"$self->{left}/":'').-$path.(length$self->{right}?"/$self->{right}":'');-}-__END__Datastructures:
@@ -0,0 +1,59 @@+packageGit::SVN::GlobSpec;+usestrict;+usewarnings;++subnew{+my($class,$glob,$pattern_ok)=@_;+my$re=$glob;+$re=~s!/+$!!g;#noneedfortrailingslashes+my(@left,@right,@patterns);+my$state="left";+my$die_msg="Only one set of wildcard directories ".+"(e.g. '*' or '*/*/*') is supported: '$glob'\n";+formy$part(split(m|/|,$glob)){+if($part=~/\*/&&$partne"*"){+die"Invalid pattern in '$glob': $part\n";+}elsif($pattern_ok&&$part=~/[{}]/&&+$part!~/^\{[^{}]+\}/){+die"Invalid pattern in '$glob': $part\n";+}+if($parteq"*"){+die$die_msgif$stateeq"right";+$state="pattern";+push(@patterns,"[^/]*");+}elsif($pattern_ok&&$part=~/^\{(.*)\}$/){+die$die_msgif$stateeq"right";+$state="pattern";+my$p=quotemeta($1);+$p=~s/\\,/|/g;+push(@patterns,"(?:$p)");+}else{+if($stateeq"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;+}++subfull_path{+my($self,$path)=@_;+return(length$self->{left}?"$self->{left}/":'').+$path.(length$self->{right}?"/$self->{right}":'');+}++1;
From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:16
From 5152b76800f076ba0bd528664f62d3c67966fa4e Mon Sep 17 00:00:00 2001
From: "Michael G. Schwern" <redacted>
Date: Thu, 12 Jul 2012 17:25:25 -0700
Subject: [PATCH 11/11] Fix Git::SVN::GlobSpec so it works.
Only used in one place in Git::SVN, load it on demand.
That should be all the Git classes out of git-svn.
---
perl/Git/SVN.pm | 5 ++++-
perl/Git/SVN/GlobSpec.pm | 1 +
perl/Makefile | 1 +
t/Git-SVN/00compile.t | 3 ++-
4 files changed, 8 insertions(+), 2 deletions(-)
@@ -202,11 +202,14 @@ sub read_all_remotes {."must start with 'refs/'\n")unless$remote_ref=~m{^refs/};$local_ref=uri_decode($local_ref);++requireGit::SVN::GlobSpec;my$rs={t=>$t,remote=>$remote,path=>Git::SVN::GlobSpec->new($local_ref,1),-ref=>Git::SVN::GlobSpec->new($remote_ref,0)};+ref=>Git::SVN::GlobSpec->new($remote_ref,0)+};if(length($rs->{ref}->{right})!=0){die"The '*' glob character must be the last ","character of '$remote_ref'\n";
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:54:16
Hi,
Michael G Schwern wrote:
Ok, here goes.
First patch overhauls perl/Makefile.PL to make it easier to add .pm files,
which I'm going to be doing a lot of. Instead of having to manually add to
the %pm hash, it scans for .pm files.
An excellent goal.
It also moves Error.pm into a bundle directory. This both makes it just
another directory to scan (or not scan), but it also makes it possible to
bundle additional modules in the future. ExtUtils::MakeMaker uses this
technique itself.
This is not so much "also" as "as an example to demonstrate the
technique", no? I guess I'd prefer it to be in a separate patch, but
this way's fine, too.
[...]
From 47a723a860cded6b16a716ea74c5bc029ee5b0ac Mon Sep 17 00:00:00 2001
From: "Michael G. Schwern" <redacted>
Date: Thu, 12 Jul 2012 00:05:38 -0700
Subject: [PATCH 01/11] Make the process of adding a module less blecherous.
* Scan for .pm files and build %pms rather than having to do it by hand.
* Move the bundled Error into its own directory so we can bundle other modules.
In addition...
* Add all the .pm files to the all dependency in the alternative Makefile
---
You'll probably hate this. Because we have a bunch of patches to
incorporate, I think it's worth spending the time to make that go as
smoothly as possible for later patches.
- the "From 47a723..." line is for your mailer. Please do not
include it in the body of your message.
- likewise for the From: and Date: lines which are redundant next to
the corresponding fields in the mail header
- comments that are useful for posterity, like
This patch overhauls perl/Makefile.PL to make it easier to add .pm files,
which I'm going to be doing a lot of. Instead of having to manually add to
the %pm hash, it scans for .pm files.
should go above the triple-dash marker, while comments that are
less useful, like "Hi", go after the triple-dash.
- using a different subject line for each patch makes the reader's
life much easier, so please do use the subject lines from your
commits in the mail header.
The git-format-patch(1) manpage has some instructions for using
Thunderbird to send patches, which should take care of all this
automatically.
If everything is right, then maintainers will love you because they
can save a bunch of your patches that look ready into a single mbox
and apply them all at once with "git am".
As Documentation/SubmittingPatches explains under "MUA specific
hints", you can test that a patch is being sent correctly by emailing
it to yourself, saving as an mbox, and trying to apply it with "git am
<path to mbox file>". If the resulting commit is as expected, then
you've succeeded.
The word "bundles/" left me a little nervous, because I (ignorantly)
imagined that this might be some specialized facility like Python eggs
or Ruby gems. Is the intent that this directory contains CPAN modules
we want to be able to depend on? Is there really any intention of
having more of them than Error.pm?
Before this patch, in the default case (with MakeMaker), "make
install" wrote a manpage in <mandir>/man3/private-Error.3pm. Does it
still do so after the patch? Will people who have installation
scripts that expected that manpage have to change them, and if so, is
the new behavior better to make up for that effort?
[...]
quoted hunk
--- a/perl/Makefile.PL+++ b/perl/Makefile.PL
@@ -2,11 +2,16 @@ use strict;usewarnings;use ExtUtils::MakeMaker;use Getopt::Long;+use File::Find;++# Don't forget to update the perl/Makefile, too.+# Don't forget to test with NO_PERL_MAKEMAKER=YesPlease
Now the reader will have no reason to be looking at this file, so
these comments are pretty much useless. In an ideal world, "make
test" in the MakeMaker build would automatically "grep perl/Makefile"
to catch modules that are not listed there, but that can wait, I
imagine.
Alternatively, maybe there could be a perl/modules.list that both
makefiles read? That way, if I drop in an unrelated .pm file for
reference while coding the build system would not be confused by
it, and since both build systems would use the same module list
there would be no risk of it falling out of date.
Thanks for some food for thought, and hope that helps,
Jonathan
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:54:16
Hi,
Michael G Schwern wrote:
From 683a230e439f1d5ac2727ce4c2a74e93804fc72b Mon Sep 17 00:00:00 2001
From: "Michael G. Schwern" <redacted>
Date: Wed, 11 Jul 2012 22:16:01 -0700
Just like with patch 1, the mail body should lose the above.
Subject: [PATCH 03/11] Fix Git::SVN so it can at least compile alone.
Did I miss patch 2?
It's still very intertwined with git-svn, but that's a lot of work. This
gets things working and tests passing again (as well as they were).
This required some parallel refactorings...
* fatal() moved out of git-svn into a new Git::SVN::Utils
It seems like a lot is going on in the one patch. Probably most of
the changes are good, but if this causes a regression we would have no
choice but to revert the whole thing, which would be unfeasible
because of later patches building on it.
So in other words, a patch like this that makes a lot of changes at
once would make life very hard for the maintainer, I imagine.
What is the motivation behind these changes? Can they be untangled
from each other and applied one at a time, in such a way that each
incremental change looks obviously correct?
Since I'm missing the patch that created Git/SVN.pm in the first
place, I can't tell --- did that patch break the build and this one
fixes it? In that case, the order of the two patches should be
swapped to ensure "git bisect" is still usable.
Sorry, I wish I had better news to mix in with all this. I am
thrilled to see this is making the internal APIs saner and adding
tests so I hope we can get it in in a way that makes regressions
unlikely.
Thanks,
Jonathan
From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:16
On 2012.7.17 5:01 PM, Jonathan Nieder wrote:
quoted
It also moves Error.pm into a bundle directory. This both makes it just
another directory to scan (or not scan), but it also makes it possible to
bundle additional modules in the future. ExtUtils::MakeMaker uses this
technique itself.
This is not so much "also" as "as an example to demonstrate the
technique", no? I guess I'd prefer it to be in a separate patch, but
this way's fine, too.
I wrote the MakeMaker system so I was just cribbing off that. It made more
sense to build a list of directories to scan and then scan them than to add
individual file exceptions later. I could put it in a separate patch, but it
would require some bending.
You'll probably hate this. Because we have a bunch of patches to
incorporate, I think it's worth spending the time to make that go as
smoothly as possible for later patches.
Sorry. I have lots of experience with git but very little with the email
submission tools. I've always either just done everything via repositories or
used Github.
It sounds like I should figure out the git-send-email tool and do this very
slowly.
The word "bundles/" left me a little nervous, because I (ignorantly)
imagined that this might be some specialized facility like Python eggs
or Ruby gems.
Nope, just copy .pm files in.
Is the intent that this directory contains CPAN modules
we want to be able to depend on?
Yes.
Is there really any intention of having more of them than Error.pm?
No idea, this is my first look at the code, but now it's possible. In my
experience, if there's a barrier to using CPAN modules then people won't use
them. They'll rewrite the functionality poorly.
Before this patch, in the default case (with MakeMaker), "make
install" wrote a manpage in <mandir>/man3/private-Error.3pm. Does it
still do so after the patch? Will people who have installation
scripts that expected that manpage have to change them, and if so, is
the new behavior better to make up for that effort?
The man page is now man3/bundles::Error::Error.3 which is equally as incorrect
as man3/private-Error.3. It is possible to correct that so it's man3/Error.3,
but that's going to require some effort. Basically its in the same boat as
PM. Once you have to change one you have to change them all.
Why do install scripts have specific code to look for that man page?
If it's going to be trouble I can put Error.pm back. It's just something I
did in passing.
quoted
+# Don't forget to update the perl/Makefile, too.
+# Don't forget to test with NO_PERL_MAKEMAKER=YesPlease
Now the reader will have no reason to be looking at this file, so
these comments are pretty much useless. In an ideal world, "make
test" in the MakeMaker build would automatically "grep perl/Makefile"
to catch modules that are not listed there, but that can wait, I
imagine.
Alternatively, maybe there could be a perl/modules.list that both
makefiles read? That way, if I drop in an unrelated .pm file for
reference while coding the build system would not be confused by
it, and since both build systems would use the same module list
there would be no risk of it falling out of date.
Ideally, that second Makefile would go away. Parallel build systems are extra
work and generate bugs.
The log suggests it might have something to do with people wanting to build
with an ActiveState Perl on Cygwin or something? MakeMaker builds different
Makefiles depending on the OS, so it may be as simple as telling Makefile.PL
what flavor of make you're using.
--
emacs -- THAT'S NO EDITOR... IT'S AN OPERATING SYSTEM!
From: Jonathan Nieder <hidden> Date: 2016-06-15 22:54:16
Thanks for the reply. Quick clarifications:
Michael G Schwern wrote:
The man page is now man3/bundles::Error::Error.3 which is equally as incorrect
as man3/private-Error.3. It is possible to correct that so it's man3/Error.3,
but that's going to require some effort. Basically its in the same boat as
PM. Once you have to change one you have to change them all.
Why do install scripts have specific code to look for that man page?
To delete it. :)
[...]
Ideally, that second Makefile would go away. Parallel build systems are extra
work and generate bugs.
Agreed --- I'd love to see the NO_PERL_MAKEMAKER option go away.
The log suggests it might have something to do with people wanting to build
with an ActiveState Perl on Cygwin or something? MakeMaker builds different
Makefiles depending on the OS, so it may be as simple as telling Makefile.PL
what flavor of make you're using.
I think the main user is the ordinary Git for Windows build (which
uses perl 5.8.8, from mingw or msys I imagine). If you have the
Windows expertise to help them or know someone who could, I'm sure
they'd be happy to switch their git build to use MakeMaker.
Website: http://msysgit.github.com/
Thanks,
Jonathan
From: Eric Wong <hidden> Date: 2016-06-15 22:54:17
Michael G Schwern [off-list ref] wrote:
Hi Michael, thanks for taking your time to help with this.
I agree with everything Jonathan said (and thank him for taking
the time to point you in the right direction).
I too (very strongly) prefer email for code review. I doubt I would've
ever gotten involved if git were run differently. I'm actually
disappointed the mailing list culture that built git hasn't rubbed off
to other projects that adopt git.
quoted hunk
+++ b/t/Git-SVN/00compile.t
+use Test::More tests => 2;
I prefer not declaring test counts and using done_testing() instead.
done_testing() is favorable to me in at least 2 ways:
* done_testing() closely matches the behavior of the existing
sh-based test suite in git (which calls test_done)
* maintaining test counts leads to unnecessary merge conflicts
Skipping the tests on old versions of Test::More (< 0.88) is acceptable
to me (especially since integration tests provide the real coverage
already).
quoted hunk
+++ b/t/Git-SVN/Utils/can_compress.t
+use Test::More 'no_plan';
no_plan is the worst way to use Test::More, I think.
From: Michael G Schwern <hidden> Date: 2016-06-15 22:54:17
On 2012.7.18 3:58 AM, Eric Wong wrote:
I agree with everything Jonathan said (and thank him for taking
the time to point you in the right direction).
Thanks, you guys have been very nice to my flailing and failing. I'm going to
back off and send out a sort of overview email so we can figure out how best
to chunk this up.
quoted
+++ b/t/Git-SVN/00compile.t
quoted
+use Test::More tests => 2;
I prefer not declaring test counts and using done_testing() instead.
done_testing() is favorable to me in at least 2 ways:
* done_testing() closely matches the behavior of the existing
sh-based test suite in git (which calls test_done)
* maintaining test counts leads to unnecessary merge conflicts
Yes, I concur 100%. So much that I went back in my time machine and added
done_testing() to Test::More! Also I killed Hitler, so now WWII ends in 1945.
Things seem to have turned out for the better.
I love it when people advocate my features back to me. :) I didn't use
done_testing because I didn't know your stance on using non-5.8 core versions
of modules.
Skipping the tests on old versions of Test::More (< 0.88) is acceptable
to me (especially since integration tests provide the real coverage
already).
It is very easy to bundle an uninstalled copy of Test::More, probably easier
than putting in the code necessary to check for it and skip it. A lot of Perl
modules do it. The usual thing is to put it into t/lib/ and add "use lib
't/lib'" to the tests. I don't see any reason why that basic technique
wouldn't work here, with some minor changes to match the Git test suite.
I can help you with that, but I'd like to get through this SVN 1.7 fix first.
--
Being faith-based doesn't trump reality.
-- Bruce Sterling
From: Ben Walton <hidden> Date: 2016-06-15 22:54:18
Hi Michael,
quoted
I've fixed the git-svn tests for SVN 1.7 and tested with SVN 1.7.5.
Thanks. git-svn is not maintained by Junio but by Eric and others on
the list. I'm cc-ing Eric and Ben Walton so they can benefit from
your work.
This is fantastic. It's been on my todo list but not a priority for
me. I'm glad you've taken the time to scratch this itch though.
I'll try to run through this series in the next few days and I can
also do some test builds on solaris to see how it plays there.
Thanks
-Ben
--
Ben Walton
Systems Programmer - CHASS
University of Toronto
C:416.407.5610 | W:416.978.4302