6 our @ISA = qw(SVN::Delta::Editor);
10 use autouse 'SVK::Util' => qw( slurp_fh tmpfile mimetype_is_text catfile );
12 sub set_target_revision {
13 my ($self, $revision) = @_;
17 my ($self, $baserev) = @_;
22 my ($self, $path, $pdir, $from_path, $from_rev, $pool) = @_;
23 $self->{info}{$path}{fpool} = $pool;
24 if (defined $from_path) {
25 $self->{info}{$path}{from_path} = $from_path;
26 $self->{info}{$path}{copied} = 1;
28 $self->{info}{$path}{added} = 1;
34 my ($self, $path, $pdir, $rev, $pool) = @_;
35 $self->{info}{$path}{from_path} = $path;
36 $self->{info}{$path}{fpool} = $pool;
42 my ($self, $path, $checksum, $pool) = @_;
44 my $info = $self->{info}{$path};
45 $info->{base} = $self->{cb_basecontent}($info->{from_path}, $info->{fpool})
46 unless $info->{added};
48 unless ($self->{external}) {
49 my $newtype = $info->{prop} && $info->{prop}{'svn:mime-type'};
50 my $is_text = !$newtype || mimetype_is_text ($newtype);
51 if ($is_text && !$info->{added}) {
52 my $basetype = $self->{cb_baseprop}->($info->{from_path}, 'svn:mime-type', $pool);
53 $is_text = !$basetype || mimetype_is_text ($basetype);
56 confess("Cannot display: file marked as a binary type.\n");
60 if ($self->{external}) {
61 my $tmp = tmpfile ('diff');
62 slurp_fh ($info->{base}, $tmp)
66 $info->{new} = $new = tmpfile ('diff');
70 open $new, '>', \$info->{new};
73 return [SVN::TxDelta::apply ($info->{base}, $new,
74 undef, undef, $pool)];
78 my ($self, $path, $checksum, $pool) = @_;
80 my $info = $self->{info}{$path};
82 if (exists $info->{new}) {
83 no warnings 'uninitialized';
84 my $rpath = $self->{report} ? catfile($self->{report}, $path) : $path;
85 my @label = map { $self->{$_} || $self->{"cb_$_"}->($path) } qw/llabel rlabel/;
86 my $showpath = ($self->{lpath} ne $self->{rpath});
87 my @showpath = map { $showpath ? $self->{$_} : undef } qw/lpath rpath/;
88 if ($self->{external}) {
89 # XXX: the 2nd file could be - and save some disk IO
90 my @content = map { ($info->{$_}->filename) } qw/base new/;
91 @content = reverse @content if $self->{reverse};
92 (system (split (/ /, $self->{external}),
93 '-L', _full_label ($rpath, $showpath[0], $label[0]),
95 '-L', _full_label ($rpath, $showpath[1], $label[1]),
96 $content[1]) >= 0) or die loc("Could not run %1: %2", $self->{external}, $?);
100 $info->{base} = $self->{cb_basecontent}($info->{from_path}, $info->{fpool})
101 unless $info->{added};
102 my @content = ($info->{base}, \$self->{info}{$path}{new});
103 @content = reverse @content if $self->{reverse};
104 $self->output_diff ($rpath, @label, @showpath, @content);
108 # $self->output_prop_diff ($path, $pool);
109 delete $self->{info}{$path};
114 my ($self, $path) = @_;
115 my $pool = $self->{info}{$path}{fpool};
116 my $name = "svn:executable";
118 return undef if $self->{info}{$path}{added};
120 my $prop = $self->{cb_baseprop}->($path, $name, $pool);
122 return "100644" unless defined($prop);
124 return "100755" if (length($prop) > 0);
131 my ($self, $path, $oldmode) = @_;
132 my $name = "svn:executable";
134 return undef if $self->{info}{$path}{deleted};
136 my $prop = $self->{info}{$path}{prop}{$name};
139 $changed = 0 unless defined($prop);
140 $changed = 1 if $self->{info}{$path}{added};
142 return $oldmode unless $changed;
144 return "100755" if (length($prop) > 0);
150 my ($self, $path, $llabel, $rlabel, $lpath, $rpath) = splice(@_, 0, 6);
151 my $fh = $self->_output_fh;
153 my $ofile = $self->{info}{$path}{added} ? "/dev/null": "a/$path";
154 my $nfile = $self->{info}{$path}{deleted} ? "/dev/null": "b/$path";
156 my $osha1 = $self->{info}{$path}{added} ? "0000000": "1234567";
157 my $nsha1 = $self->{info}{$path}{deleted} ? "0000000": "7654321";
159 my $omode = $self->oldfilemode($path);
160 my $nmode = $self->newfilemode($path, $omode);
165 if (defined($omode) and defined($nmode)) {
166 if ($omode ne $nmode) {
167 $mode = "old mode $omode\nnew mode $nmode\n";
169 } elsif (defined($omode)) {
170 $mode = "deleted file mode $omode\n";
171 } elsif (defined($nmode)) {
172 $mode = "new file mode $nmode\n";
176 "diff --git $ofile $nfile\n",
179 "index $osha1..$nsha1\n"
182 unshift @_, $self->_output_fh;
183 push @_, $ofile, $nfile;
185 goto &{$self->can('_output_diff_content')};
188 # _output_diff_content($fh, $ltext, $rtext, $llabel, $rlabel)
189 sub _output_diff_content {
190 my ($fh, $ltext, $rtext, $llabel, $rlabel) = @_;
192 my ($lfh, $lfn) = tmpfile ('diff');
193 my ($rfh, $rfn) = tmpfile ('diff');
195 slurp_fh ($ltext => $lfh); close ($lfh);
196 slurp_fh ($rtext => $rfh); close ($rfh);
198 my $diff = SVN::Core::diff_file_diff( $lfn, $rfn );
200 SVN::Core::diff_file_output_unified(
201 $fh, $diff, $lfn, $rfn, $llabel, $rlabel
207 sub output_prop_diff {
208 my ($self, $path, $pool) = @_;
209 if ($self->{info}{$path}{prop}) {
210 my $rpath = $self->{report} ? catfile($self->{report}, $path) : $path;
211 $self->_print("\n", loc("Property changes on: %1\n", $rpath), ('_' x 67), "\n");
212 for (sort keys %{$self->{info}{$path}{prop}}) {
213 $self->_print(loc("Name: %1\n", $_));
215 $baseprop = $self->{cb_baseprop}->($path, $_, $pool)
216 unless $self->{info}{$path}{added};
219 map { (length || /\n$/) ? "$_\n" : $_ }
220 ($baseprop||''), ($self->{info}{$path}{prop}{$_}||'');
221 @args = reverse @args if $self->{reverse};
224 open my $fh, '>', \$diff;
225 _output_diff_content($fh, @args, '', '');
226 $diff =~ s/.*\n.*\n//;
227 $diff =~ s/^\@.*\n//mg;
229 $self->_print($diff);
236 my ($self, $path, $pdir, @arg) = @_;
237 # $self->{info}{$path}{added} = 1;
242 my ($self, $path, $pdir, $rev, @arg) = @_;
246 sub close_directory {
247 my ($self, $path, $pool) = @_;
248 # $self->output_prop_diff ($path, $pool);
249 delete $self->{info}{$path};
253 my ($self, $path, $revision, $pdir, $pool) = @_;
255 my $fullpath = "$self->{oldbranch}/$path";
257 if ($self->{oldroot}->is_file($fullpath)) {
258 $self->{info}{$path}{from_path} = $path;
259 $self->{info}{$path}{deleted} = 1;
260 $self->{info}{$path}{fpool} = $pool;
261 $self->{info}{$path}{new} = '';
262 $self->close_file($path, undef, $pool);
266 my $entries = $self->{oldroot}->dir_entries($fullpath);
267 foreach my $c (keys %{$entries}) {
268 $self->delete_entry("$path/$c", $revision, $path, $pool);
272 sub change_file_prop {
273 my ($self, $path, $name, $value) = @_;
274 $self->{info}{$path}{prop}{$name} = $value;
277 sub change_dir_prop {
278 my ($self, $path, $name, $value) = @_;
282 my ($self, @arg) = @_;
287 $self->{output} or return print @_;
288 ${ $self->{output} } .= $_ for @_;
295 $self->{output} or return \*{select()};
297 open my $fh, '>>', $self->{output};
303 Chia-liang Kao E<lt>clkao@clkao.orgE<gt>
307 Copyright 2003-2005 by Chia-liang Kao E<lt>clkao@clkao.orgE<gt>.
309 This program is free software; you can redistribute it and/or modify it
310 under the same terms as Perl itself.
312 See L<http://www.perl.com/perl/misc/Artistic.html>