File Coverage

lib/Kwiki/Archive/Rcs.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Kwiki::Archive::Rcs;
2 1     1   26731 use Kwiki::Archive -Base;
  0            
  0            
3             our $VERSION = '0.16';
4              
5             sub show_revisions {
6             my $page = $self->pages->current;
7             my $rcs_text = io($self->assert_file_path($page))->all
8             or return 0;
9             $rcs_text =~ /^head\s+1\.(\d+)/
10             or return 0;
11             $1 > 1 ? $1 : 0;
12             }
13              
14             sub assert_file_path {
15             my $page = shift;
16             my $file_path = $self->file_path($page);
17             $self->commit($page) unless -e $file_path;
18             return $file_path;
19             }
20              
21             sub file_path {
22             my $page = shift;
23             $self->plugin_directory . '/' . $page->id . ',v';
24             }
25              
26             sub commit {
27             my $page = shift;
28             my $props = $self->page_properties($page);
29             my $rcs_file_path = $self->file_path($page);
30             $self->shell("rcs -q -i -U $rcs_file_path < /dev/null")
31             unless -f $rcs_file_path;
32             my $msg = $self->$csv_encode($props);
33             my $page_file_path = $page->io;
34             eval {
35             $self->shell(qq{ci -q -l -m"$msg" $page_file_path $rcs_file_path 2>/dev/null});
36             };
37             if ($@) {
38             $self->force_unlock_rcs_file($rcs_file_path);
39             $self->shell(qq{ci -q -l -m"$msg" $page_file_path $rcs_file_path});
40             }
41             }
42              
43             # XXX This is needed because sometimes rcs gets different user name under
44             # apache.
45             sub force_unlock_rcs_file {
46             my $rcs_file = shift;
47             $self->shell("rcs -q -U -M -u $rcs_file < /dev/null 2>/dev/null");
48             }
49              
50             sub fetch_metadata {
51             my $page = shift;
52             my $rev = shift;
53             my $rcs_file_path = $self->assert_file_path($page);
54             my $rlog = io("rlog -zLT -r $rev $rcs_file_path |") or die $!;
55             $rlog->utf8 if $self->has_utf8;
56             $self->parse_metadata($rlog->all);
57             }
58              
59             sub parse_metadata {
60             my $log = shift;
61             $log =~ /
62             ^revision\s+(\S+).*?
63             ^date:\s+(.+?);.*?\n
64             (.*)
65             /xms or die "Couldn't parse rlog:\n$log";
66              
67             my $revision_id = $1;
68             my $archive_date = $2;
69             my $msg = $3;
70             chomp $msg;
71              
72             my $metadata =
73             $self->$csv_decode($msg) ||
74             $self->$older_decode($msg) ||
75             $self->$oldest_decode($msg);
76             $revision_id =~ s/^1\.//;
77             $metadata->{revision_id} = $revision_id;
78             $metadata->{edit_time} ||= $archive_date;
79             $metadata->{edit_unixtime} ||= do {
80             require Date::Manip;
81             Date::Manip::UnixDate(Date::Manip::ParseDate($archive_date), "%s");
82             };
83             return $metadata;
84             }
85              
86             sub history {
87             my $page = shift;
88             my $rcs_file_path = $self->assert_file_path($page);
89             my $rlog = io("rlog -zLT $rcs_file_path |") or die $!;
90             $rlog->utf8 if $self->has_utf8;
91              
92             my $input = $rlog->all;
93             $input =~ s/
94             \n=+$
95             .*\Z
96             //msx;
97             my @rlog = split /^-+\n/m, $input;
98             shift(@rlog);
99              
100             return [
101             map $self->parse_metadata($_), @rlog
102             ];
103             }
104              
105             sub fetch {
106             my $page = shift;
107             my $revision_id = shift;
108             return unless $revision_id =~ /^\d+$/;
109             my $revision = "1.$revision_id";
110             my $rcs_file_path = $self->assert_file_path($page);
111             local($/, *CO);
112             open CO, qq{co -q -p$revision $rcs_file_path |}
113             or die $!;
114             binmode(CO, ':utf8') if $self->has_utf8;
115             scalar ;
116             }
117              
118             sub shell {
119             my ($command) = @_;
120             use Cwd;
121             $! = undef;
122             system($command) == 0
123             or die "$command failed:\n$?\nin " . Cwd::cwd();
124             }
125              
126             my sub csv_encode {
127             my $hash = shift;
128             join ',', map {
129             my $key = $_;
130             my $value = $self->uri_escape($hash->{$key});
131             "$key:$value";
132             } sort keys %$hash;
133             }
134              
135             my sub csv_decode {
136             my $string = shift;
137             return unless $string =~ /edit_time:/;
138             return {
139             map {
140             my ($key, $value) = split ':', $_, 2;
141             $value = $self->uri_unescape($value);
142             ($key, $value);
143             } split /(?
144             };
145             }
146              
147             my sub older_decode {
148             my $string = shift;
149             return unless $string =~ /,/;
150             my ($edit_by, $edit_time, $edit_unixtime) = split ',', $string;
151             return {
152             edit_by => $self->uri_unescape($edit_by),
153             edit_time => $edit_time,
154             edit_unixtime => $edit_unixtime,
155             };
156             }
157              
158             my sub oldest_decode {
159             my $string = shift;
160             if ($string =~ /^[\d\.]{7,}$/) {
161             return {edit_address => $string};
162             }
163             else {
164             return {edit_by => $string};
165             }
166             }
167            
168             __DATA__