summaryrefslogtreecommitdiff
path: root/perl/Git
diff options
context:
space:
mode:
Diffstat (limited to 'perl/Git')
-rw-r--r--perl/Git/SVN.pm27
-rw-r--r--perl/Git/SVN/Editor.pm41
-rw-r--r--perl/Git/SVN/Fetcher.pm11
-rw-r--r--perl/Git/SVN/Ra.pm8
4 files changed, 71 insertions, 16 deletions
diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
index d9a52a52df..152fb7e927 100644
--- a/perl/Git/SVN.pm
+++ b/perl/Git/SVN.pm
@@ -9,11 +9,10 @@ use vars qw/$_no_metadata
$_use_log_author $_add_author_from $_localtime/;
use Carp qw/croak/;
use File::Path qw/mkpath/;
-use File::Copy qw/copy/;
use IPC::Open3;
use Memoize; # core since 5.8.0, Jul 2002
-use Memoize::Storable;
use POSIX qw(:signal_h);
+use Time::Local;
use Git qw(
command
@@ -32,11 +31,7 @@ use Git::SVN::Utils qw(
add_path_to_url
);
-my $can_use_yaml;
-BEGIN {
- $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1};
-}
-
+my $memo_backend;
our $_follow_parent = 1;
our $_minimize_url = 'unset';
our $default_repo_id = 'svn';
@@ -1332,7 +1327,7 @@ sub parse_svn_date {
$ENV{TZ} = 'UTC';
my $epoch_in_UTC =
- POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900);
+ Time::Local::timelocal($S, $M, $H, $d, $m - 1, $Y - 1900);
# Determine our local timezone (including DST) at the
# time of $epoch_in_UTC. $Git::SVN::Log::TZ stored the
@@ -1578,7 +1573,16 @@ sub tie_for_persistent_memoization {
my $hash = shift;
my $path = shift;
- if ($can_use_yaml) {
+ unless ($memo_backend) {
+ if (eval { require Git::SVN::Memoize::YAML; 1}) {
+ $memo_backend = 1;
+ } else {
+ require Memoize::Storable;
+ $memo_backend = -1;
+ }
+ }
+
+ if ($memo_backend > 0) {
tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml";
} else {
tie %$hash => 'Memoize::Storable', "$path.db", 'nstore';
@@ -2188,8 +2192,9 @@ sub rev_map_set {
# both of these options make our .rev_db file very, very important
# and we can't afford to lose it because rebuild() won't work
if ($self->use_svm_props || $self->no_metadata) {
+ require File::Copy;
$sync = 1;
- copy($db, $db_lock) or die "rev_map_set(@_): ",
+ File::Copy::copy($db, $db_lock) or die "rev_map_set(@_): ",
"Failed to copy: ",
"$db => $db_lock ($!)\n";
} else {
@@ -2365,7 +2370,7 @@ sub _new {
# Older repos imported by us used $GIT_DIR/svn/foo instead of
# $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo
- if ($ref_id =~ m{^refs/remotes/(.*)}) {
+ if ($ref_id =~ m{^refs/remotes/(.+)}) {
my $old_dir = "$ENV{GIT_DIR}/svn/$1";
if (-d $old_dir && ! -d $dir) {
$dir = $old_dir;
diff --git a/perl/Git/SVN/Editor.pm b/perl/Git/SVN/Editor.pm
index 34e8af966c..c50176eec9 100644
--- a/perl/Git/SVN/Editor.pm
+++ b/perl/Git/SVN/Editor.pm
@@ -5,7 +5,6 @@ use warnings;
use SVN::Core;
use SVN::Delta;
use Carp qw/croak/;
-use IO::File;
use Git qw/command command_oneline command_noisy command_output_pipe
command_input_pipe command_close_pipe
command_bidi_pipe command_close_bidi_pipe/;
@@ -288,6 +287,40 @@ sub apply_autoprops {
}
}
+sub check_attr {
+ my ($attr,$path) = @_;
+ my $val = command_oneline("check-attr", $attr, "--", $path);
+ if ($val) { $val =~ s/^[^:]*:\s*[^:]*:\s*(.*)\s*$/$1/; }
+ return $val;
+}
+
+sub apply_manualprops {
+ my ($self, $file, $fbat) = @_;
+ my $pending_properties = check_attr( "svn-properties", $file );
+ if ($pending_properties eq "") { return; }
+ # Parse the list of properties to set.
+ my @props = split(/;/, $pending_properties);
+ # TODO: get existing properties to compare to
+ # - this fails for add so currently not done
+ # my $existing_props = ::get_svnprops($file);
+ my $existing_props = {};
+ # TODO: caching svn properties or storing them in .gitattributes
+ # would make that faster
+ foreach my $prop (@props) {
+ # Parse 'name=value' syntax and set the property.
+ if ($prop =~ /([^=]+)=(.*)/) {
+ my ($n,$v) = ($1,$2);
+ for ($n, $v) {
+ s/^\s+//; s/\s+$//;
+ }
+ my $existing = $existing_props->{$n};
+ if (!defined($existing) || $existing ne $v) {
+ $self->change_file_prop($fbat, $n, $v);
+ }
+ }
+ }
+}
+
sub A {
my ($self, $m, $deletions) = @_;
my ($dir, $file) = split_path($m->{file_b});
@@ -296,6 +329,7 @@ sub A {
undef, -1);
print "\tA\t$m->{file_b}\n" unless $::_q;
$self->apply_autoprops($file, $fbat);
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
}
@@ -311,6 +345,7 @@ sub C {
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
$upa, $self->{r});
print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
}
@@ -333,6 +368,7 @@ sub R {
$upa, $self->{r});
print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
$self->apply_autoprops($file, $fbat);
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
@@ -348,6 +384,7 @@ sub M {
my $fbat = $self->open_file($self->repo_path($m->{file_b}),
$pbat,$self->{r},$self->{pool});
print "\t$m->{chg}\t$m->{file_b}\n" unless $::_q;
+ $self->apply_manualprops($m->{file_b}, $fbat);
$self->chg_file($fbat, $m);
$self->close_file($fbat,undef,$self->{pool});
}
@@ -548,7 +585,7 @@ The interface will change as git-svn evolves.
=head1 DEPENDENCIES
Subversion perl bindings,
-the core L<Carp> and L<IO::File> modules,
+the core L<Carp> module,
and git's L<Git> helper module.
C<Git::SVN::Editor> has not been tested using callers other than
diff --git a/perl/Git/SVN/Fetcher.pm b/perl/Git/SVN/Fetcher.pm
index 10edb27732..d8c21ad915 100644
--- a/perl/Git/SVN/Fetcher.pm
+++ b/perl/Git/SVN/Fetcher.pm
@@ -7,7 +7,6 @@ use warnings;
use SVN::Delta;
use Carp qw/croak/;
use File::Basename qw/dirname/;
-use IO::File qw//;
use Git qw/command command_oneline command_noisy command_output_pipe
command_input_pipe command_close_pipe
command_bidi_pipe command_close_bidi_pipe/;
@@ -322,6 +321,14 @@ sub apply_textdelta {
# (but $base does not,) so dup() it for reading in close_file
open my $dup, '<&', $fh or croak $!;
my $base = $::_repository->temp_acquire("git_blob_${$}_$suffix");
+ # close_file may call temp_acquire on 'svn_hash', but because of the
+ # call chain, if the temp_acquire call from close_file ends up being the
+ # call that first creates the 'svn_hash' temp file, then the FileHandle
+ # that's created as a result will end up in an SVN::Pool that we clear
+ # in SVN::Ra::gs_fetch_loop_common. Avoid that by making sure the
+ # 'svn_hash' FileHandle is already created before close_file is called.
+ my $tmp_fh = $::_repository->temp_acquire('svn_hash');
+ $::_repository->temp_release($tmp_fh, 1);
if ($fb->{blob}) {
my ($base_is_link, $size);
@@ -600,7 +607,7 @@ developing git-svn.
=head1 DEPENDENCIES
L<SVN::Delta> from the Subversion perl bindings,
-the core L<Carp>, L<File::Basename>, and L<IO::File> modules,
+the core L<Carp> and L<File::Basename> modules,
and git's L<Git> helper module.
C<Git::SVN::Fetcher> has not been tested using callers other than
diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm
index 622535e217..4a499fcb38 100644
--- a/perl/Git/SVN/Ra.pm
+++ b/perl/Git/SVN/Ra.pm
@@ -3,7 +3,6 @@ use vars qw/@ISA $config_dir $_ignore_refs_regex $_log_window_size/;
use strict;
use warnings;
use Memoize;
-use SVN::Client;
use Git::SVN::Utils qw(
canonicalize_url
canonicalize_path
@@ -42,6 +41,7 @@ END {
}
sub _auth_providers () {
+ require SVN::Client;
my @rv = (
SVN::Client::get_simple_provider(),
SVN::Client::get_ssl_server_trust_file_provider(),
@@ -247,7 +247,10 @@ sub get_log {
$ret;
}
+# uncommon, only for ancient SVN (<= 1.4.2)
sub trees_match {
+ require IO::File;
+ require SVN::Client;
my ($self, $url1, $rev1, $url2, $rev2) = @_;
my $ctx = SVN::Client->new(auth => _auth_providers);
my $out = IO::File->new_tmpfile;
@@ -391,6 +394,9 @@ sub longest_common_path {
sub gs_fetch_loop_common {
my ($self, $base, $head, $gsv, $globs) = @_;
return if ($base > $head);
+ # Make sure the cat_blob open2 FileHandle is created before calling
+ # SVN::Pool::new_default so that it does not incorrectly end up in the pool.
+ $::_repository->_open_cat_blob_if_needed;
my $gpool = SVN::Pool->new_default;
my $ra_url = $self->url;
my $reload_ra = sub {