X-Git-Url: https://sipb.mit.edu/gitweb.cgi/ikiwiki.git/blobdiff_plain/873c404f144c37adb1c9121b35dc372d5934ebbf..7aa10a2952a0d0ee8543f575966f7e4a780c993c:/IkiWiki/Plugin/cvs.pm diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm index 97a568c0e..841aec914 100644 --- a/IkiWiki/Plugin/cvs.pm +++ b/IkiWiki/Plugin/cvs.pm @@ -33,6 +33,7 @@ use warnings; use strict; use IkiWiki; +use URI::Escape q{uri_escape_utf8}; use File::chdir; @@ -140,7 +141,7 @@ EOF # VCS PLUGIN API CALLS sub rcs_update () { - return unless cvs_is_controlling; + return unless cvs_is_controlling(); cvs_runcvs('update', '-dP'); } @@ -151,7 +152,7 @@ sub rcs_prepedit ($) { # The file is relative to the srcdir. my $file=shift; - return unless cvs_is_controlling; + return unless cvs_is_controlling(); # For cvs, return the revision of the file when # editing begins. @@ -165,7 +166,7 @@ sub rcs_commit (@) { # The file is relative to the srcdir. my %params=@_; - return unless cvs_is_controlling; + return unless cvs_is_controlling(); # Check to see if the page has been changed by someone # else since rcs_prepedit was called. @@ -208,9 +209,6 @@ sub rcs_add ($) { my $parent=IkiWiki::dirname($file); my @files_to_add = ($file); - eval q{use File::MimeInfo}; - error($@) if $@; - until ((length($parent) == 0) || cvs_is_controlling("$config{srcdir}/$parent")){ push @files_to_add, $parent; $parent = IkiWiki::dirname($parent); @@ -218,21 +216,12 @@ sub rcs_add ($) { while ($file = pop @files_to_add) { if (@files_to_add == 0) { - # file - my $filemime = File::MimeInfo::default($file); - if (defined($filemime) && $filemime eq 'text/plain') { - cvs_runcvs('add', $file) || - warn("cvs add $file failed\n"); - } - else { - cvs_runcvs('add', '-kb', $file) || - warn("cvs add binary $file failed\n"); - } + cvs_runcvs('add', cvs_keyword_subst_args($file)) || + warn("cvs add file $file failed\n"); } else { - # directory cvs_runcvs('add', $file) || - warn("cvs add $file failed\n"); + warn("cvs add dir $file failed\n"); } } } @@ -241,7 +230,7 @@ sub rcs_remove ($) { # filename is relative to the root of the srcdir my $file=shift; - return unless cvs_is_controlling; + return unless cvs_is_controlling(); cvs_runcvs('rm', '-f', $file) || warn("cvs rm $file failed\n"); @@ -251,7 +240,7 @@ sub rcs_rename ($$) { # filenames relative to the root of the srcdir my ($src, $dest)=@_; - return unless cvs_is_controlling; + return unless cvs_is_controlling(); local $CWD = $config{srcdir}; @@ -267,7 +256,7 @@ sub rcs_recentchanges ($) { my $num = shift; my @ret; - return unless cvs_is_controlling; + return unless cvs_is_controlling(); eval q{use Date::Parse}; error($@) if $@; @@ -325,7 +314,10 @@ sub rcs_recentchanges ($) { $oldrev =~ s/INITIAL/0/; $newrev =~ s/\(DEAD\)//; my $diffurl = defined $config{diffurl} ? $config{diffurl} : ""; - $diffurl=~s/\[\[file\]\]/$page/g; + my $epage = join('/', + map { uri_escape_utf8($_) } split('/', $page) + ); + $diffurl=~s/\[\[file\]\]/$epage/g; $diffurl=~s/\[\[r1\]\]/$oldrev/g; $diffurl=~s/\[\[r2\]\]/$newrev/g; unshift @pages, { @@ -404,11 +396,15 @@ sub rcs_diff ($;$) { my @cvsps = `env TZ=UTC cvsps -q --cvs-direct -z 30 -g -s $rev`; my $blank_lines_seen = 0; + # skip log, get to the diff while (my $line = shift @cvsps) { $blank_lines_seen++ if ($line =~ /^$/); last if $blank_lines_seen == 2; } + @cvsps = @cvsps[0..$maxlines-1] + if defined $maxlines && @cvsps > $maxlines; + if (wantarray) { return @cvsps; } @@ -489,16 +485,63 @@ sub cvs_is_controlling { return (-d "$dir/CVS") ? 1 : 0; } +sub cvs_keyword_subst_args ($) { + my $file = shift; + + local $CWD = $config{srcdir}; + + eval q{use File::MimeInfo}; + error($@) if $@; + my $filemime = File::MimeInfo::default($file); + # if (-T $file) { + + defined($filemime) && $filemime eq 'text/plain' + ? return ('-kkv', $file) + : return ('-kb', $file); +} + sub cvs_runcvs(@) { my @cmd = @_; unshift @cmd, 'cvs', '-Q'; - local $CWD = $config{srcdir}; + # CVS can't operate outside a srcdir, so we're always setting $CWD. + # "local $CWD" restores the previous value when we go out of scope. + # Usually that's correct. But if we're removing the last file from + # a directory, the post-commit hook will exec in a working directory + # that's about to not exist (CVS will prune it). + # + # chdir() manually here, so we can selectively not chdir() back. + + my $oldcwd = $CWD; + chdir($config{srcdir}); + + eval q{ + use IPC::Open3; + use Symbol qw(gensym); + use IO::File; + }; + error($@) if $@; + + my $cvsout = ''; + my $cvserr = ''; + local *CATCHERR = IO::File->new_tmpfile; + my $pid = open3(gensym(), \*CATCHOUT, ">&CATCHERR", @cmd); + while (my $l = ) { + $cvsout .= $l + unless 1; + } + waitpid($pid, 0); + my $ret = $? >> 8; + seek CATCHERR, 0, 0; + while (my $l = ) { + $cvserr .= $l + unless $l =~ /^cvs commit: changing keyword expansion /; + } + + print STDOUT $cvsout; + print STDERR $cvserr; - open(my $savedout, ">&STDOUT"); - open(STDOUT, ">", "/dev/null"); - my $ret = system(@cmd); - open(STDOUT, ">&", $savedout); + chdir($oldcwd) if -d $oldcwd; return ($ret == 0) ? 1 : 0; }