Julien Cristau wrote:
> On Sun, Nov  4, 2012 at 11:30:04 -0800, Jonathan Nieder wrote:

>> Please unblock git/1:1.7.10.4-2 to get fixes to
>>
>>   #678137 -- incompatibility with SVN 1.7
>>
>> and
>>
>>   #587650 -- "Byte order is not compatible at ../../lib/Storable.pm"
>>              errors when accessing git-svn repositories created with
>>              perl/squeeze
[...]
> The first of those is big, and svn 1.7 is not in wheezy...

In light of [1], I'm happy to skip

  b8c78e2a git svn: work around SVN 1.7 mishandling of svn:special changes

in a tpu upload.  Proposed upload attached.  What do you think?

Thanks,
Jonathan

[1] http://svn.apache.org/viewvc?view=revision&revision=1406870
From: Jonathan Nieder <jrnie...@gmail.com>
Date: Fri, 12 Oct 2012 13:26:39 -0700
Subject: debian: use YAML as platform-independent .git/svn/.caches format

On 32-bit arches, attempts to use "git svn fetch" on repositories
cloned using older perl currently produce

    Byte order is not compatible at ../../lib/Storable.pm (autosplit
    into ../../lib/auto/Storable/_retrieve.al) line 380, at
    /usr/share/perl/5.12/Memoize/Storable.pm line 21

because the byteorder changed from 1234 to 12345678 when perl's
use64bit compile-time option was enabled.

Wait --- isn't Memoize::Storable's nstore option supposed to shield
users from such changing platform details?  Unfortunately the 'nstore'
option has no effect due to a typo in its implementation (bug#677292).

Rather than coming up with a transition plan to account for git
repositories shared between machines with and without a fix to that
bug, let's move away from Memoize::Storable completely.  A patch
applied upstream in 1.7.11 teaches 'git svn' to use libyaml when
available to read and write its caches under a new filename with a
simpler, platform-independent format.  The Debian packaging can
complete the fix by adding a run-time dependency by git-svn on
libyaml-perl.

[jn: backport for wheezy: adjust version number and position in
 debian/diff]

Analysis-by: Tim Retout <dioc...@debian.org>
Signed-off-by: Jonathan Nieder <jrnie...@gmail.com>
---
 debian/changelog                                   |  11 +
 debian/control                                     |   4 +-
 ...-YAML-format-for-mergeinfo-cache-when-poss.diff | 294 +++++++++++++++++++++
 3 files changed, 307 insertions(+), 2 deletions(-)
 create mode 100644 
debian/diff/0013-git-svn-use-YAML-format-for-mergeinfo-cache-when-poss.diff

diff --git a/debian/changelog b/debian/changelog
index 7558b3ab..575cd06a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,14 @@
+git (1:1.7.10.4-1+wheezy1) testing; urgency=low
+
+  * debian/diff/0013-git-svn-use-YAML-format-...diff: new from 1.7.11:
+    git svn: use YAML format for mergeinfo cache when possible.
+  * debian/control: git-svn: Depends: libyaml-perl for platform- and
+    version-independent .git/svn/.caches format; Build-Depends:
+    libyaml-perl for tests (thx Tim Retout for the analysis; closes:
+    #587650).
+
+ -- Jonathan Nieder <jrnie...@gmail.com>  Sun, 18 Nov 2012 11:45:41 -0800
+
 git (1:1.7.10.4-1) unstable; urgency=low
 
   * new upstream point release (thx Jonathan Nieder).
diff --git a/debian/control b/debian/control
index e1f1a442..a8e188a2 100644
--- a/debian/control
+++ b/debian/control
@@ -5,7 +5,7 @@ Maintainer: Gerrit Pape <p...@smarden.org>
 Uploaders: Jonathan Nieder <jrnie...@gmail.com>
 Build-Depends: libz-dev,
  libcurl4-gnutls-dev | libcurl3-gnutls-dev, libexpat1-dev,
- subversion, libsvn-perl | libsvn-core-perl,
+ subversion, libsvn-perl | libsvn-core-perl, libyaml-perl,
  tcl8.5, gettext,
  cvs, cvsps, libdbd-sqlite3-perl,
  unzip, libio-pty-perl,
@@ -147,7 +147,7 @@ Description: fast, scalable, distributed revision control 
system (cvs interopera
 
 Package: git-svn
 Architecture: all
-Depends: git (>> ${source:Upstream-Version}), git (<< 
${source:Upstream-Version}-.), libsvn-perl | libsvn-core-perl, libwww-perl, 
libterm-readkey-perl
+Depends: git (>> ${source:Upstream-Version}), git (<< 
${source:Upstream-Version}-.), libsvn-perl | libsvn-core-perl, libyaml-perl, 
libwww-perl, libterm-readkey-perl
 Suggests: git-doc, subversion
 Replaces: cogito (<< 0.16rc2-0)
 Description: fast, scalable, distributed revision control system (svn 
interoperability)
diff --git 
a/debian/diff/0013-git-svn-use-YAML-format-for-mergeinfo-cache-when-poss.diff 
b/debian/diff/0013-git-svn-use-YAML-format-for-mergeinfo-cache-when-poss.diff
new file mode 100644
index 00000000..a0f1dfdb
--- /dev/null
+++ 
b/debian/diff/0013-git-svn-use-YAML-format-for-mergeinfo-cache-when-poss.diff
@@ -0,0 +1,294 @@
+From db8445cce70a6bdb014fb04624ebcce7f39ad905 Mon Sep 17 00:00:00 2001
+From: Jonathan Nieder <jrnie...@gmail.com>
+Date: Sat, 9 Jun 2012 17:35:35 -0500
+Subject: git-svn: use YAML format for mergeinfo cache when possible
+
+Since v1.7.0-rc2~11 (git-svn: persistent memoization, 2010-01-30),
+git-svn has maintained some private per-repository caches in
+.git/svn/.caches to avoid refetching and recalculating some
+mergeinfo-related information with every "git svn fetch".
+
+These caches use the 'nstore' format from the perl core module
+Storable, which can be read and written quickly and was designed for
+transfer over the wire (the 'n' stands for 'network').  This format is
+supposed to be endianness-independent and independent of
+floating-point representation.
+
+Unfortunately the format is *not* independent of the perl version ---
+new perl versions will write files that very old perl cannot read.
+Worse, the format is not independent of the size of a perl integer.
+So if you toggle perl's use64bitint compile-time option, then using
+'git svn fetch' on your old repositories produces errors like this:
+
+       Byte order is not compatible at ../../lib/Storable.pm (autosplit
+       into ../../lib/auto/Storable/_retrieve.al) line 380, at
+       /usr/share/perl/5.12/Memoize/Storable.pm line 21
+
+That is, upgrading perl to a version that uses use64bitint for the
+first time makes git-svn suddenly refuse to fetch in existing
+repositories.  Removing .git/svn/.caches lets git-svn recover.
+
+It's time to switch to a platform independent serializer backend with
+better compatibility guarantees.  This patch uses YAML::Any.
+
+Other choices were considered:
+
+ - thawing data from Data::Dumper involves "eval".  Doing that without
+   creating a security risk is fussy.
+
+ - the JSON API works on scalars in memory and doesn't provide a
+   standard way to serialize straight to disk.
+
+YAML::Any is reasonably fast and has a pleasant API.  In most
+backends, LoadFile() reads the entire file into a scalar anyway and
+converts it as a second step, but having an interface that allows the
+deserialization to happen on the fly without a temporary is still a
+comfort.
+
+YAML::Any is not a core perl module, so we take care to use it when
+and only when it is available.  Installations without that module
+should fall back to using Storable with all its quirks, keeping their
+cache files in
+
+       .git/svn/.caches/*.db
+
+Installations with YAML peacefully coexist by keeping a separate set
+of cache files in
+
+       .git/svn/.caches/*.yaml.
+
+In most cases, switching between is a one-time thing, so it doesn't
+seem worth the complication to migrate existing caches.
+
+The upshot: after this patch, as long as YAML::Any is installed you
+can move your git repository between machines with different perl
+installations and "git svn fetch" will work fine.  If you do not have
+YAML::Any, the behavior is unchanged (and in particular does not get
+any worse).
+
+[jn: update fallback NO_PERL_MAKEMAKER rules, too, thanks to Adam
+ Roben; tweak log message to take
+ https://rt.cpan.org/Public/Bug/Display.html?id=77790 into account,
+ thanks to Tim Retout]
+
+Reported-by: Sandro Weiser <sandro.wei...@informatik.tu-chemnitz.de>
+Reported-by: Bdale Garbee <bd...@gag.com>
+Signed-off-by: Jonathan Nieder <jrnie...@gmail.com>
+Signed-off-by: Eric Wong <normalper...@yhbt.net>
+Signed-off-by: Jonathan Nieder <jrnie...@gmail.com>
+---
+ git-svn.perl                 |   31 +++++++++++---
+ perl/Git/SVN/Memoize/YAML.pm |   93 ++++++++++++++++++++++++++++++++++++++++++
+ perl/Makefile                |    8 +++-
+ perl/Makefile.PL             |    1 +
+ 4 files changed, 125 insertions(+), 8 deletions(-)
+ create mode 100644 perl/Git/SVN/Memoize/YAML.pm
+
+diff --git a/git-svn.perl b/git-svn.perl
+index ca038ec..77bab24 100755
+--- a/git-svn.perl
++++ b/git-svn.perl
+@@ -2031,6 +2031,10 @@ package Git::SVN;
+ use Time::Local;
+ use Memoize;  # core since 5.8.0, Jul 2002
+ use Memoize::Storable;
++my $can_use_yaml;
++BEGIN {
++      $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1};
++}
+ 
+ my ($_gc_nr, $_gc_period);
+ 
+@@ -3553,6 +3557,17 @@ sub has_no_changes {
+               command_oneline("rev-parse", "$commit~1^{tree}"));
+ }
+ 
++sub tie_for_persistent_memoization {
++      my $hash = shift;
++      my $path = shift;
++
++      if ($can_use_yaml) {
++              tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml";
++      } else {
++              tie %$hash => 'Memoize::Storable', "$path.db", 'nstore';
++      }
++}
++
+ # The GIT_DIR environment variable is not always set until after the command
+ # line arguments are processed, so we can't memoize in a BEGIN block.
+ {
+@@ -3565,22 +3580,26 @@ sub has_no_changes {
+               my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
+               mkpath([$cache_path]) unless -d $cache_path;
+ 
+-              tie my %lookup_svn_merge_cache => 'Memoize::Storable',
+-                  "$cache_path/lookup_svn_merge.db", 'nstore';
++              my %lookup_svn_merge_cache;
++              my %check_cherry_pick_cache;
++              my %has_no_changes_cache;
++
++              tie_for_persistent_memoization(\%lookup_svn_merge_cache,
++                  "$cache_path/lookup_svn_merge");
+               memoize 'lookup_svn_merge',
+                       SCALAR_CACHE => 'FAULT',
+                       LIST_CACHE => ['HASH' => \%lookup_svn_merge_cache],
+               ;
+ 
+-              tie my %check_cherry_pick_cache => 'Memoize::Storable',
+-                  "$cache_path/check_cherry_pick.db", 'nstore';
++              tie_for_persistent_memoization(\%check_cherry_pick_cache,
++                  "$cache_path/check_cherry_pick");
+               memoize 'check_cherry_pick',
+                       SCALAR_CACHE => 'FAULT',
+                       LIST_CACHE => ['HASH' => \%check_cherry_pick_cache],
+               ;
+ 
+-              tie my %has_no_changes_cache => 'Memoize::Storable',
+-                  "$cache_path/has_no_changes.db", 'nstore';
++              tie_for_persistent_memoization(\%has_no_changes_cache,
++                  "$cache_path/has_no_changes");
+               memoize 'has_no_changes',
+                       SCALAR_CACHE => ['HASH' => \%has_no_changes_cache],
+                       LIST_CACHE => 'FAULT',
+diff --git a/perl/Git/SVN/Memoize/YAML.pm b/perl/Git/SVN/Memoize/YAML.pm
+new file mode 100644
+index 0000000..9676b8f
+--- /dev/null
++++ b/perl/Git/SVN/Memoize/YAML.pm
+@@ -0,0 +1,93 @@
++package Git::SVN::Memoize::YAML;
++use warnings;
++use strict;
++use YAML::Any ();
++
++# based on Memoize::Storable.
++
++sub TIEHASH {
++      my $package = shift;
++      my $filename = shift;
++      my $truehash = (-e $filename) ? YAML::Any::LoadFile($filename) : {};
++      my $self = {FILENAME => $filename, H => $truehash};
++      bless $self => $package;
++}
++
++sub STORE {
++      my $self = shift;
++      $self->{H}{$_[0]} = $_[1];
++}
++
++sub FETCH {
++      my $self = shift;
++      $self->{H}{$_[0]};
++}
++
++sub EXISTS {
++      my $self = shift;
++      exists $self->{H}{$_[0]};
++}
++
++sub DESTROY {
++      my $self = shift;
++      YAML::Any::DumpFile($self->{FILENAME}, $self->{H});
++}
++
++sub SCALAR {
++      my $self = shift;
++      scalar(%{$self->{H}});
++}
++
++sub FIRSTKEY {
++      'Fake hash from Git::SVN::Memoize::YAML';
++}
++
++sub NEXTKEY {
++      undef;
++}
++
++1;
++__END__
++
++=head1 NAME
++
++Git::SVN::Memoize::YAML - store Memoized data in YAML format
++
++=head1 SYNOPSIS
++
++    use Memoize;
++    use Git::SVN::Memoize::YAML;
++
++    tie my %cache => 'Git::SVN::Memoize::YAML', $filename;
++    memoize('slow_function', SCALAR_CACHE => [HASH => \%cache]);
++    slow_function(arguments);
++
++=head1 DESCRIPTION
++
++This module provides a class that can be used to tie a hash to a
++YAML file.  The file is read when the hash is initialized and
++rewritten when the hash is destroyed.
++
++The intent is to allow L<Memoize> to back its cache with a file in
++YAML format, just like L<Memoize::Storable> allows L<Memoize> to
++back its cache with a file in Storable format.  Unlike the Storable
++format, the YAML format is platform-independent and fairly stable.
++
++Carps on error.
++
++=head1 DIAGNOSTICS
++
++See L<YAML::Any>.
++
++=head1 DEPENDENCIES
++
++L<YAML::Any> from CPAN.
++
++=head1 INCOMPATIBILITIES
++
++None reported.
++
++=head1 BUGS
++
++The entire cache is read into a Perl hash when loading the file,
++so this is not very scalable.
+diff --git a/perl/Makefile b/perl/Makefile
+index 3e21766..fec6546 100644
+--- a/perl/Makefile
++++ b/perl/Makefile
+@@ -24,17 +24,21 @@ ifdef NO_PERL_MAKEMAKER
+ instdir_SQ = $(subst ','\'',$(prefix)/lib)
+ $(makfile): ../GIT-CFLAGS Makefile
+       echo all: private-Error.pm Git.pm Git/I18N.pm > $@
+-      echo '  mkdir -p blib/lib/Git' >> $@
++      echo '  mkdir -p blib/lib/Git/SVN/Memoize' >> $@
+       echo '  $(RM) blib/lib/Git.pm; cp Git.pm blib/lib/' >> $@
+       echo '  $(RM) blib/lib/Git/I18N.pm; cp Git/I18N.pm blib/lib/Git/' >> $@
++      echo '  $(RM) blib/lib/Git/SVN/Memoize/YAML.pm' >> $@
++      echo '  cp Git/SVN/Memoize/YAML.pm blib/lib/Git/SVN/Memoize/' >> $@
+       echo '  $(RM) blib/lib/Error.pm' >> $@
+       '$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
+       echo '  cp private-Error.pm blib/lib/Error.pm' >> $@
+       echo install: >> $@
+       echo '  mkdir -p "$$(DESTDIR)$(instdir_SQ)"' >> $@
+-      echo '  mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@
++      echo '  mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git/SVN/Memoize"' >> $@
+       echo '  $(RM) "$$(DESTDIR)$(instdir_SQ)/Git.pm"; cp Git.pm 
"$$(DESTDIR)$(instdir_SQ)"' >> $@
+       echo '  $(RM) "$$(DESTDIR)$(instdir_SQ)/Git/I18N.pm"; cp Git/I18N.pm 
"$$(DESTDIR)$(instdir_SQ)/Git"' >> $@
++      echo '  $(RM) "$$(DESTDIR)$(instdir_SQ)/Git/SVN/Memoize/YAML.pm"' >> $@
++      echo '  cp Git/SVN/Memoize/YAML.pm 
"$$(DESTDIR)$(instdir_SQ)/Git/SVN/Memoize"' >> $@
+       echo '  $(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
+       '$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
+       echo '  cp private-Error.pm "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@
+diff --git a/perl/Makefile.PL b/perl/Makefile.PL
+index 456d45b..321dfe1 100644
+--- a/perl/Makefile.PL
++++ b/perl/Makefile.PL
+@@ -27,6 +27,7 @@ MAKE_FRAG
+ 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',
+ );
+ 
+ # We come with our own bundled Error.pm. It's not in the set of default
+-- 
+1.7.10.4
+
-- 
1.8.0

Reply via email to