The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package CGI::Kwiki::Backup::Rcs;
$VERSION = '0.18';
use strict;
use base 'CGI::Kwiki::Backup';
use File::Spec;

use constant RCS_DIR => 'metabase/rcs';

sub file_path {
    my ($self, $page_id) = @_;
    RCS_DIR . '/' . $self->escape($page_id) . ',v';
}

my $user_name = '';
sub new {
    my ($class) = shift;
    my $self = $class->SUPER::new(@_);
    unless (-d RCS_DIR) {
        mkdir RCS_DIR;
        umask 0000;
        chmod 0777, RCS_DIR;
        $user_name = 'kwiki-install';
        for my $page_id ($self->database->pages) {
            $self->commit($page_id);
        }
    }
    return $self;
}
    
sub commit {
    my ($self, $page_id) = @_;
    my $rcs_file_path = $self->file_path($page_id);
    if (not -f $rcs_file_path) {
        $self->shell("rcs -q -i $rcs_file_path < /dev/null");
    }
    my $msg = $self->escape($user_name || $self->metadata->edit_by);
    my $page_file_path = $self->database->file_path($page_id);
    $self->shell(qq{ci -q -l -m"$msg" $page_file_path $rcs_file_path});
}

sub has_history {
    my ($self, $page_id) = @_;
    $page_id ||= $self->cgi->page_id;
    -f $self->file_path($page_id);
}

sub history {
    my ($self, $page_id) = @_;
    $page_id ||= $self->cgi->page_id;
    my $rcs_file_path = $self->file_path($page_id);
    open RLOG, "rlog -zLT $rcs_file_path |"
      or DIE $!; 
    binmode(RLOG, ':utf8') if $self->use_utf8;
    local $/;
    my $input = <RLOG>;
    close RLOG;
    (my $rlog = $input) =~ s/\n=+$.*\Z//ms;
    my @rlog = split /^-+\n/m, $rlog;
    shift(@rlog);
    my $history = [];
    for (@rlog) {
        /^revision\s+(\S+).*?
         ^date:\s+(.+?);.*?\n
         (.*)
        /xms or die "Couldn't parse rlog for '$page_id':\n$rlog";
        push @$history,
          {
            revision => $1,
            file_rev => $1,
            date => $2,
            edit_by => $self->unescape($3),
          };
    }
    return $history;
}

sub file_rev {
    my ($self, $page_id, $revision) = @_;
    return $revision;
}

sub fetch {
    my ($self, $page_id, $revision) = @_;
    my $rcs_file_path = $self->file_path($page_id);
    
    local($/, *CO);
    open CO, qq{co -q -p$revision $rcs_file_path |}
      or die $!;
    binmode(CO, ':utf8') if $self->use_utf8;
    <CO>;
}

sub diff {
    my ($self, $page_id, $r1, $r2, $context) = @_;
    $context ||= 1000000;
    my $rcs_file_path = $self->file_path($page_id);

    local(*RCSDIFF);
    open RCSDIFF, qq{rcsdiff -q -r$r1 -r$r2 --unified=$context $rcs_file_path |}
      or die "rcsdiff failed:\n$!";
    binmode(RCSDIFF, ':utf8') if $self->use_utf8;
    my $line1 = <RCSDIFF>;
    my $line2 = <RCSDIFF>;
    $line2 =~ s/\+/%2B/g; # counter ->unescape
    local $/;
    return($self->unescape($line1) . $self->unescape($line2) . <RCSDIFF>);
}

sub shell {
    my ($self, $command) = @_;
    use Cwd;
    $! = undef;
    system($command) == 0 
      or die "$command failed: $! | " . Cwd::cwd();
}

1;