path.c: refactor relative_path(), not only strip prefix
[gitweb.git] / perl / Git / SVN.pm
index d0087b2897dcec7a21d2b8c406499ab3427bcb8a..5273ee886764423df0bacfa9b2fbc9b27c4852c4 100644 (file)
@@ -11,7 +11,6 @@ package Git::SVN;
 use File::Path qw/mkpath/;
 use File::Copy qw/copy/;
 use IPC::Open3;
-use Time::Local;
 use Memoize;  # core since 5.8.0, Jul 2002
 use Memoize::Storable;
 use POSIX qw(:signal_h);
@@ -22,6 +21,7 @@ package Git::SVN;
     command_noisy
     command_output_pipe
     command_close_pipe
+    get_tz_offset
 );
 use Git::SVN::Utils qw(
        fatal
@@ -460,7 +460,6 @@ sub new {
        }
        {
                my $path = $self->path;
-               $path =~ s{/+}{/}g;
                $path =~ s{\A/}{};
                $path =~ s{/\z}{};
                $self->path($path);
@@ -491,7 +490,7 @@ sub refname {
        #
        # Additionally, % must be escaped because it is used for escaping
        # and we want our escaped refname to be reversible
-       $refname =~ s{([ \%~\^:\?\*\[\t])}{uc sprintf('%%%02x',ord($1))}eg;
+       $refname =~ s{([ \%~\^:\?\*\[\t])}{sprintf('%%%02X',ord($1))}eg;
 
        # no slash-separated component can begin with a dot .
        # /.* becomes /%2E*
@@ -1312,14 +1311,6 @@ sub get_untracked {
        \@out;
 }
 
-sub get_tz {
-       # some systmes don't handle or mishandle %z, so be creative.
-       my $t = shift || time;
-       my $gm = timelocal(gmtime($t));
-       my $sign = qw( + + - )[ $t <=> $gm ];
-       return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]);
-}
-
 # parse_svn_date(DATE)
 # --------------------
 # Given a date (in UTC) from Subversion, return a string in the format
@@ -1352,7 +1343,7 @@ sub parse_svn_date {
                        delete $ENV{TZ};
                }
 
-               my $our_TZ = get_tz();
+               my $our_TZ = get_tz_offset();
 
                # This converts $epoch_in_UTC into our local timezone.
                my ($sec, $min, $hour, $mday, $mon, $year,
@@ -1502,13 +1493,18 @@ sub lookup_svn_merge {
        my @merged_commit_ranges;
        # find the tip
        for my $range ( @ranges ) {
+               if ($range =~ /[*]$/) {
+                       warn "W: Ignoring partial merge in svn:mergeinfo "
+                               ."dirprop: $source:$range\n";
+                       next;
+               }
                my ($bottom, $top) = split "-", $range;
                $top ||= $bottom;
                my $bottom_commit = $gs->find_rev_after( $bottom, 1, $top );
                my $top_commit = $gs->find_rev_before( $top, 1, $bottom );
 
                unless ($top_commit and $bottom_commit) {
-                       warn "W:unknown path/rev in svn:mergeinfo "
+                       warn "W: unknown path/rev in svn:mergeinfo "
                                ."dirprop: $source:$range\n";
                        next;
                }
@@ -1635,6 +1631,24 @@ sub tie_for_persistent_memoization {
                Memoize::unmemoize 'has_no_changes';
        }
 
+       sub clear_memoized_mergeinfo_caches {
+               die "Only call this method in non-memoized context" if ($memoized);
+
+               my $cache_path = "$ENV{GIT_DIR}/svn/.caches/";
+               return unless -d $cache_path;
+
+               for my $cache_file (("$cache_path/lookup_svn_merge",
+                                    "$cache_path/check_cherry_pick",
+                                    "$cache_path/has_no_changes")) {
+                       for my $suffix (qw(yaml db)) {
+                               my $file = "$cache_file.$suffix";
+                               next unless -e $file;
+                               unlink($file) or die "unlink($file) failed: $!\n";
+                       }
+               }
+       }
+
+
        Memoize::memoize 'Git::SVN::repos_root';
 }
 
@@ -1662,7 +1676,6 @@ sub parents_exclude {
                                if ( $commit eq $excluded ) {
                                        push @excluded, $commit;
                                        $found++;
-                                       last;
                                }
                                else {
                                        push @new, $commit;
@@ -1696,14 +1709,14 @@ sub find_extra_svn_parents {
        my @merge_tips;
        my $url = $self->url;
        my $uuid = $self->ra_uuid;
-       my %ranges;
+       my @all_ranges;
        for my $merge ( @merges ) {
                my ($tip_commit, @ranges) =
                        lookup_svn_merge( $uuid, $url, $merge );
                unless (!$tip_commit or
                                grep { $_ eq $tip_commit } @$parents ) {
                        push @merge_tips, $tip_commit;
-                       $ranges{$tip_commit} = \@ranges;
+                       push @all_ranges, @ranges;
                } else {
                        push @merge_tips, undef;
                }
@@ -1718,8 +1731,6 @@ sub find_extra_svn_parents {
                my $spec = shift @merges;
                next unless $merge_tip and $excluded{$merge_tip};
 
-               my $ranges = $ranges{$merge_tip};
-
                # check out 'new' tips
                my $merge_base;
                eval {
@@ -1741,7 +1752,7 @@ sub find_extra_svn_parents {
                my (@incomplete) = check_cherry_pick(
                        $merge_base, $merge_tip,
                        $parents,
-                       @$ranges,
+                       @all_ranges,
                       );
 
                if ( @incomplete ) {
@@ -2127,8 +2138,13 @@ sub rev_map_set {
 
        sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)
             or croak "Couldn't open $db_lock: $!\n";
-       $update_ref eq 'reset' ? _rev_map_reset($fh, $rev, $commit) :
-                                _rev_map_set($fh, $rev, $commit);
+       if ($update_ref eq 'reset') {
+               clear_memoized_mergeinfo_caches();
+               _rev_map_reset($fh, $rev, $commit);
+       } else {
+               _rev_map_set($fh, $rev, $commit);
+       }
+
        if ($sync) {
                $fh->flush or die "Couldn't flush $db_lock: $!\n";
                $fh->sync or die "Couldn't sync $db_lock: $!\n";
@@ -2312,11 +2328,11 @@ sub path {
 
        if (@_) {
                my $path = shift;
-               $self->{path} = canonicalize_path($path);
+               $self->{_path} = canonicalize_path($path);
                return;
        }
 
-       return $self->{path};
+       return $self->{_path};
 }
 
 sub url {
@@ -2358,7 +2374,7 @@ sub map_path {
 
 sub uri_encode {
        my ($f) = @_;
-       $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg;
+       $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#sprintf("%%%02X",ord($1))#eg;
        $f
 }