← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 18:42:36 2015
Reported on Fri Jul 31 18:48:15 2015

Filename/var/www/foswikidev/core/lib/Foswiki/Store/Rcs/RcsWrapHandler.pm
StatementsExecuted 79362 statements in 609ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
2632711389ms4.75sFoswiki::Store::Rcs::RcsWrapHandler::::getRevisionFoswiki::Store::Rcs::RcsWrapHandler::getRevision
2669311291ms552msFoswiki::Store::Rcs::RcsWrapHandler::::newFoswiki::Store::Rcs::RcsWrapHandler::new
1116.49ms11.2msFoswiki::Store::Rcs::RcsWrapHandler::::BEGIN@23Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@23
11116µs29µsFoswiki::Store::Rcs::RcsWrapHandler::::BEGIN@19Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@19
1119µs14µsFoswiki::Store::Rcs::RcsWrapHandler::::BEGIN@20Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@20
1119µs35µsFoswiki::Store::Rcs::RcsWrapHandler::::BEGIN@21Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@21
1116µs6µsFoswiki::Store::Rcs::RcsWrapHandler::::BEGIN@28Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@28
1115µs5µsFoswiki::Store::Rcs::RcsWrapHandler::::BEGIN@26Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@26
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::_deleteRevisionFoswiki::Store::Rcs::RcsWrapHandler::_deleteRevision
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::_lockFoswiki::Store::Rcs::RcsWrapHandler::_lock
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::_numRevisionsFoswiki::Store::Rcs::RcsWrapHandler::_numRevisions
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::ciFoswiki::Store::Rcs::RcsWrapHandler::ci
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::deleteRevisionFoswiki::Store::Rcs::RcsWrapHandler::deleteRevision
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::finishFoswiki::Store::Rcs::RcsWrapHandler::finish
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::getInfoFoswiki::Store::Rcs::RcsWrapHandler::getInfo
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::getRevisionAtTimeFoswiki::Store::Rcs::RcsWrapHandler::getRevisionAtTime
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::initBinaryFoswiki::Store::Rcs::RcsWrapHandler::initBinary
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::initTextFoswiki::Store::Rcs::RcsWrapHandler::initText
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::parseRevisionDiffFoswiki::Store::Rcs::RcsWrapHandler::parseRevisionDiff
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::repRevFoswiki::Store::Rcs::RcsWrapHandler::repRev
0000s0sFoswiki::Store::Rcs::RcsWrapHandler::::revisionDiffFoswiki::Store::Rcs::RcsWrapHandler::revisionDiff
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2
3=begin TML
4
5---+ package Foswiki::Store::Rcs::RcsWrapHandler
6
7This class implements the pure methods of the Foswiki::Store::Rcs::Handler
8superclass. See the superclass for detailed documentation of the methods.
9
10Wrapper around the RCS commands required by Foswiki.
11An object of this class is created for each file stored under RCS.
12
13For readers who are familiar with Foswiki version 1.0, this class
14is analagous to the old =Foswiki::Store::RcsWrap=.
15
16=cut
17
18package Foswiki::Store::Rcs::RcsWrapHandler;
19229µs243µs
# spent 29µs (16+13) within Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@19 which was called: # once (16µs+13µs) by Foswiki::Store::RcsWrap::BEGIN@26 at line 19
use strict;
# spent 29µs making 1 call to Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@19 # spent 13µs making 1 call to strict::import
20224µs218µs
# spent 14µs (9+4) within Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@20 which was called: # once (9µs+4µs) by Foswiki::Store::RcsWrap::BEGIN@26 at line 20
use warnings;
# spent 14µs making 1 call to Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@20 # spent 4µs making 1 call to warnings::import
21227µs262µs
# spent 35µs (9+26) within Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@21 which was called: # once (9µs+26µs) by Foswiki::Store::RcsWrap::BEGIN@26 at line 21
use Assert;
# spent 35µs making 1 call to Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@21 # spent 26µs making 1 call to Exporter::import
22
232157µs111.2ms
# spent 11.2ms (6.49+4.74) within Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@23 which was called: # once (6.49ms+4.74ms) by Foswiki::Store::RcsWrap::BEGIN@26 at line 23
use Foswiki::Store::Rcs::Handler ();
# spent 11.2ms making 1 call to Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@23
2418µsour @ISA = ('Foswiki::Store::Rcs::Handler');
25
26264µs15µs
# spent 5µs within Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@26 which was called: # once (5µs+0s) by Foswiki::Store::RcsWrap::BEGIN@26 at line 26
use Foswiki::Sandbox ();
# spent 5µs making 1 call to Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@26
27
28
# spent 6µs within Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@28 which was called: # once (6µs+0s) by Foswiki::Store::RcsWrap::BEGIN@26 at line 36
BEGIN {
291600ns if ( $Foswiki::cfg{UseLocale} ) {
30 require locale;
31 import locale();
32 }
33
3412µs *_decode = \&Foswiki::Store::decode;
3515µs *_encode = \&Foswiki::Store::encode;
3612.21ms16µs}
# spent 6µs making 1 call to Foswiki::Store::Rcs::RcsWrapHandler::BEGIN@28
37
38
# spent 552ms (291+261) within Foswiki::Store::Rcs::RcsWrapHandler::new which was called 26693 times, avg 21µs/call: # 26693 times (291ms+261ms) by Foswiki::Store::RcsWrap::getHandler at line 30 of /var/www/foswikidev/core/lib/Foswiki/Store/RcsWrap.pm, avg 21µs/call
sub new {
3926693286ms26693261ms return shift->SUPER::new(@_);
# spent 261ms making 26693 calls to Foswiki::Store::Rcs::Handler::new, avg 10µs/call
40}
41
42=begin TML
43
44---++ ObjectMethod finish()
45Break circular references.
46
47=cut
48
49# Note to developers; please undef *all* fields in the object explicitly,
50# whether they are references or not. That way this method is "golden
51# documentation" of the live fields in the object.
52sub finish {
53 my $this = shift;
54 $this->SUPER::finish();
55 undef $this->{binary};
56}
57
58# implements Rcs::Handler
59sub initBinary {
60 my ($this) = @_;
61
62 $this->{binary} = 1;
63
64 $this->mkPathTo( $this->{file} );
65
66 return if $this->revisionHistoryExists();
67
68 my ( $rcsOutput, $exit ) = Foswiki::Sandbox->sysCommand(
69 $Foswiki::cfg{RCS}{initBinaryCmd},
70 FILENAME => _encode( $this->{file} )
71 );
72 if ($exit) {
73 throw Error::Simple( $Foswiki::cfg{RCS}{initBinaryCmd} . ' of '
74 . $this->hidePath( $this->{file} )
75 . ' failed: '
76 . $rcsOutput );
77 }
78 elsif ( !$this->revisionHistoryExists() ) {
79
80 # Sometimes (on Windows?) rcs file not formed, so check for it
81 throw Error::Simple( $Foswiki::cfg{RCS}{initBinaryCmd} . ' of '
82 . $this->hidePath( $this->{rcsFile} )
83 . ' failed to create history file' );
84 }
85}
86
87# implements Rcs::Handler
88sub initText {
89 my ($this) = @_;
90 $this->{binary} = 0;
91
92 $this->mkPathTo( $this->{file} );
93
94 return if $this->revisionHistoryExists();
95
96 my ( $rcsOutput, $exit, $stdErr ) =
97 Foswiki::Sandbox->sysCommand( $Foswiki::cfg{RCS}{initTextCmd},
98 FILENAME => _encode( $this->{file} ) );
99 if ($exit) {
100 $rcsOutput ||= '';
101 throw Error::Simple( $Foswiki::cfg{RCS}{initTextCmd} . ' of '
102 . $this->hidePath( $this->{file} )
103 . ' failed: '
104 . $rcsOutput );
105 }
106 elsif ( !$this->revisionHistoryExists() ) {
107
108 # Sometimes (on Windows?) rcs file not formed, so check for it
109 throw Error::Simple( $Foswiki::cfg{RCS}{initTextCmd} . ' of '
110 . $this->hidePath( $this->{rcsFile} )
111 . ' failed to create history file' );
112 }
113}
114
115# implements Rcs::Handler
116
117# Designed for calling *only* from the Handler superclass and this class
118sub ci {
119 my ( $this, $isStream, $data, $comment, $user, $date ) = @_;
120
121 _lock($this);
122 if ($isStream) {
123 $this->saveStream($data);
124 }
125 else {
126 $this->saveFile( $this->{file}, $data );
127 }
128
129 $comment = 'none' unless $comment;
130
131 my ( $cmd, $rcsOutput, $exit, $stderr );
132 if ( defined($date) ) {
133 require Foswiki::Time;
134 $date = Foswiki::Time::formatTime( $date, '$rcs', 'gmtime' );
135 $cmd = $Foswiki::cfg{RCS}{ciDateCmd};
136 ( $rcsOutput, $exit, $stderr ) = Foswiki::Sandbox->sysCommand(
137 $cmd,
138 USERNAME => $user,
139 FILENAME => _encode( $this->{file} ),
140 COMMENT => $comment,
141 DATE => $date
142 );
143 }
144 else {
145 $cmd = $Foswiki::cfg{RCS}{ciCmd};
146 ( $rcsOutput, $exit, $stderr ) = Foswiki::Sandbox->sysCommand(
147 $cmd,
148 USERNAME => $user,
149 FILENAME => _encode( $this->{file} ),
150 COMMENT => $comment
151 );
152 }
153 $rcsOutput ||= '';
154
155 if ($exit) {
156 throw Error::Simple( $cmd . ' of '
157 . $this->hidePath( $this->{file} )
158 . ' failed: '
159 . $exit . ' '
160 . $rcsOutput
161 . ( (DEBUG) ? $stderr : '' ) );
162 }
163 chmod( $Foswiki::cfg{Store}{filePermission}, _encode( $this->{file} ) );
164}
165
166# implements Rcs::Handler
167sub repRev {
168 my ( $this, $text, $comment, $user, $date ) = @_;
169
170 my $rev = $this->_numRevisions() || 0;
171
172 $comment ||= 'none';
173
174 # update repository with same userName and date
175 if ( $rev <= 1 ) {
176
177 # initial revision, so delete repository file and start again
178 unlink $this->{rcsFile};
179 }
180 else {
181 _deleteRevision( $this, $rev );
182 }
183
184 $this->saveFile( $this->{file}, $text );
185 require Foswiki::Time;
186 $date = Foswiki::Time::formatTime( $date, '$rcs', 'gmtime' );
187
188 _lock($this);
189 my ( $rcsOut, $exit ) = Foswiki::Sandbox->sysCommand(
190 $Foswiki::cfg{RCS}{ciDateCmd},
191 DATE => $date,
192 USERNAME => $user,
193 FILENAME => _encode( $this->{file} ),
194 COMMENT => $comment
195 );
196 if ($exit) {
197 $rcsOut = $Foswiki::cfg{RCS}{ciDateCmd} . "\n" . $rcsOut;
198 return $rcsOut;
199 }
200 chmod( $Foswiki::cfg{Store}{filePermission}, _encode( $this->{file} ) );
201}
202
203# implements Rcs::Handler
204sub deleteRevision {
205 my ($this) = @_;
206 my $rev = $this->_numRevisions();
207 return if ( $rev <= 1 );
208 return _deleteRevision( $this, $rev );
209}
210
211sub _deleteRevision {
212 my ( $this, $rev ) = @_;
213
214 # delete latest revision (unlock (may not be needed), delete revision)
215 my ( $rcsOut, $exit ) =
216 Foswiki::Sandbox->sysCommand( $Foswiki::cfg{RCS}{unlockCmd},
217 FILENAME => _encode( $this->{file} ) );
218 if ($exit) {
219 throw Error::Simple(
220 $Foswiki::cfg{RCS}{unlockCmd} . ' failed: ' . $rcsOut );
221 }
222
223 chmod( $Foswiki::cfg{Store}{filePermission}, _encode( $this->{file} ) );
224
225 ( $rcsOut, $exit ) = Foswiki::Sandbox->sysCommand(
226 $Foswiki::cfg{RCS}{delRevCmd},
227 REVISION => '1.' . $rev,
228 FILENAME => _encode( $this->{file} )
229 );
230
231 if ($exit) {
232 throw Error::Simple( $Foswiki::cfg{RCS}{delRevCmd} . ' of '
233 . $this->hidePath( $this->{file} )
234 . ' failed: '
235 . $rcsOut );
236 }
237
238 # Update the checkout
239 $rev--;
240 ( $rcsOut, $exit ) = Foswiki::Sandbox->sysCommand(
241 $Foswiki::cfg{RCS}{coCmd},
242 REVISION => '1.' . $rev,
243 FILENAME => _encode( $this->{file} )
244 );
245
246 if ($exit) {
247 throw Error::Simple( $Foswiki::cfg{RCS}{coCmd} . ' of '
248 . $this->hidePath( $this->{file} )
249 . ' failed: '
250 . $rcsOut );
251 }
252 $this->saveFile( $this->{file}, $rcsOut );
253}
254
255# implements Rcs::Handler
256
# spent 4.75s (389ms+4.36) within Foswiki::Store::Rcs::RcsWrapHandler::getRevision which was called 26327 times, avg 180µs/call: # 26327 times (389ms+4.36s) by Foswiki::Store::Rcs::Store::readTopic at line 114 of /var/www/foswikidev/core/lib/Foswiki/Store/Rcs/Store.pm, avg 180µs/call
sub getRevision {
2572632712.9ms my ( $this, $version ) = @_;
258
259 # If there is no revision history, or if $version is not given,
260 # or there is a checkin pending, then consult the .txt
26126327308ms526544.36s if ( !$this->revisionHistoryExists()
# spent 3.21s making 26327 calls to Foswiki::Store::Rcs::Handler::getRevision, avg 122µs/call # spent 1.14s making 26327 calls to Foswiki::Store::Rcs::Handler::revisionHistoryExists, avg 43µs/call
262 || !$version
263 || !$this->noCheckinPending() )
264 {
265
266 # Get the latest rev from the cache
267 return ( $this->SUPER::getRevision($version) );
268 }
269
270 # We've been asked for an explicit rev. The rev might be outside the
271 # range of revs in RCS. RCS will return the latest, though it reports
272 # the rev retrieved to STDERR (no use to us, as we have no access
273 # to STDERR)
274
275 # SMELL: we need to determine if the rev we are returning is the latest.
276 # co prints the retrieved revision, but unfortunately it prints it
277 # to STDERR, which the Sandbox can't retrieve.
278
279 my $tmpfile;
280 my $tmpRevFile;
281 my $coCmd = $Foswiki::cfg{RCS}{coCmd};
282 my $file = _encode( $this->{file} );
283 if ( $Foswiki::cfg{RCS}{coMustCopy} ) {
284
285 # Need to take temporary copy of topic, check it out to file,
286 # then read that. Need to put RCS into binary mode to avoid
287 # extra \r appearing and read from binmode file rather than
288 # stdout to avoid early file read termination
289 # See http://twiki.org/cgi-bin/view/Codev/DakarRcsWrapProblem
290 # for evidence that this code is needed.
291 $tmpfile = Foswiki::Store::Rcs::Handler::mkTmpFilename($this);
292 $tmpRevFile = $tmpfile . ',v';
293 $this->_copyFile( $this->{rcsFile}, $tmpRevFile );
294 my ( $rcsOutput, $status ) =
295 Foswiki::Sandbox->sysCommand( $Foswiki::cfg{RCS}{tmpBinaryCmd},
296 FILENAME => $tmpRevFile );
297 if ($status) {
298 throw Error::Simple(
299 $Foswiki::cfg{RCS}{tmpBinaryCmd} . ' failed: ' . $rcsOutput );
300 }
301 $file = $tmpfile;
302 $coCmd =~ s/-p%REVISION/-r%REVISION/;
303 }
304 my ( $text, $status, $stderr ) = Foswiki::Sandbox->sysCommand(
305 $coCmd,
306 REVISION => '1.' . $version,
307 FILENAME => $file
308 );
309
310 # The loaded version is reported on STDERR
311 my $isLatest = 0;
312 if ( defined $stderr
313 && $stderr =~ /revision 1\.(\d+)/s )
314 {
315 $isLatest = ( $version >= $1 );
316 }
317
318 # otherwise we will have to resort to numRevisions to tell if
319 # this is the latest rev, which is expensive. By returning false
320 # for isLatest we will force a reload upstairs if the latest rev
321 # is required.
322
323 if ($tmpfile) {
324 $text = $this->readFile($tmpfile);
325 for ( $tmpfile, $tmpRevFile ) {
326 my $f = Foswiki::Sandbox::untaintUnchecked($_);
327 unlink $f or warn "Could not delete $f: $!";
328 }
329 }
330
331 return ( $text, $isLatest );
332}
333
334# implements Rcs::Handler
335sub getInfo {
336 my ( $this, $version ) = @_;
337
338 my $numRevs = $this->_numRevisions() || 0;
339 if ( ( $this->noCheckinPending() )
340 && ( !$version || $version > $numRevs ) )
341 {
342 $version = $numRevs;
343 }
344 else {
345 $version = $numRevs + 1
346 unless ( $version && $version <= $numRevs );
347 }
348 my ( $rcsOut, $exit ) = Foswiki::Sandbox->sysCommand(
349 $Foswiki::cfg{RCS}{infoCmd},
350 REVISION => '1.' . $version,
351 FILENAME => _encode( $this->{rcsFile} )
352 );
353 if ( !$exit ) {
354 if ( $rcsOut =~
355 /^.*?date: ([^;]+); author: ([^;]*);[^\n]*\n([^\n]*)\n/s )
356 {
357 require Foswiki::Time;
358 my $info = {
359 version => $version,
360 date => Foswiki::Time::parseTime($1),
361 author => $2,
362 comment => $3,
363 };
364 if ( $rcsOut =~ /revision 1.([0-9]*)/ ) {
365 $info->{version} = $1;
366 }
367 return $info;
368 }
369 }
370
371 return $this->SUPER::getInfo($version);
372}
373
374# implements Rcs::Handler
375sub _numRevisions {
376 my $this = shift;
377
378 unless ( $this->revisionHistoryExists() ) {
379
380 # If there is no history, there can only be one.
381 return 1 if $this->storedDataExists();
382 return 0;
383 }
384
385 my ( $rcsOutput, $exit ) =
386 Foswiki::Sandbox->sysCommand( $Foswiki::cfg{RCS}{histCmd},
387 FILENAME => _encode( $this->{rcsFile} ) );
388 if ($exit) {
389 throw Error::Simple( 'RCS: '
390 . $Foswiki::cfg{RCS}{histCmd} . ' of '
391 . $this->hidePath( $this->{rcsFile} )
392 . ' failed: '
393 . $rcsOutput );
394 }
395 if ( $rcsOutput =~ /head:\s+\d+\.(\d+)\n/ ) {
396 return $1;
397 }
398 if ( $rcsOutput =~ /total revisions: (\d+)\n/ ) {
399 return $1;
400 }
401 return 1;
402}
403
404# implements Rcs::Handler
405# rev1 is the lower, rev2 is the higher revision
406sub revisionDiff {
407 my ( $this, $rev1, $rev2, $contextLines ) = @_;
408 my $tmp = '';
409 my $exit;
410 if ( $rev1 eq '1' && $rev2 eq '1' ) {
411 my $text = $this->getRevision(1);
412 $tmp = "1a1\n";
413 foreach ( split( /\r?\n/, $text ) ) {
414 $tmp = "$tmp> $_\n";
415 }
416 }
417 else {
418 $contextLines = 3 unless defined($contextLines);
419 ( $tmp, $exit ) = Foswiki::Sandbox->sysCommand(
420 $Foswiki::cfg{RCS}{diffCmd},
421 REVISION1 => '1.' . $rev1,
422 REVISION2 => '1.' . $rev2,
423 FILENAME => _encode( $this->{rcsFile} ),
424 CONTEXT => $contextLines
425 );
426
427 # prevent diffing TOPICINFO
428 $tmp =~ s/^.%META:TOPICINFO\{(.*)\}%\n//mg;
429
430 # comment out because we get a non-zero status for a good result!
431 #if( $exit ) {
432 # throw Error::Simple( 'RCS: '.$Foswiki::cfg{RCS}{diffCmd}.
433 # ' failed: '.$! );
434 #}
435 }
436
437 return parseRevisionDiff($tmp);
438}
439
440=begin TML
441
442---++ StaticMethod parseRevisionDiff( $text ) -> \@diffArray
443
444| Description: | parse the text into an array of diff cells |
445| #Description: | unlike Algorithm::Diff I concatinate lines of the same diffType that are sqential (this might be something that should be left up to the renderer) |
446| Parameter: =$text= | currently unified or rcsdiff format |
447| Return: =\@diffArray= | reference to an array of [ diffType, $right, $left ] |
448| TODO: | move into Rcs::Handler and add indirection in Store |
449
450=cut
451
452sub parseRevisionDiff {
453 my ($text) = @_;
454
455 my ($diffFormat) = 'normal'; #or rcs, unified...
456 my (@diffArray) = ();
457
458 $diffFormat = 'unified' if ( $text =~ /^---/s );
459
460 $text =~ s/\r//go; # cut CR
461
462 my $lineNumber = 1;
463 if ( $diffFormat eq 'unified' ) {
464 foreach ( split( /\r?\n/, $text ) ) {
465 if ( $lineNumber > 2 ) { #skip the first 2 lines (filenames)
466 if (/@@ [-+]([0-9]+)([,0-9]+)? [-+]([0-9]+)(,[0-9]+)? @@/) {
467
468 #line number
469 push @diffArray, [ 'l', $1, $3 ];
470 }
471 elsif (/^\-(.*)$/) {
472 push @diffArray, [ '-', $1, '' ];
473 }
474 elsif (/^\+(.*)$/) {
475 push @diffArray, [ '+', '', $1 ];
476 }
477 else {
478 s/^ (.*)$/$1/go;
479 push @diffArray, [ 'u', $_, $_ ];
480 }
481 }
482 $lineNumber++;
483 }
484 }
485 else {
486
487 #'normal' rcsdiff output
488 foreach ( split( /\r?\n/, $text ) ) {
489 if (/^([0-9]+)[0-9\,]*([acd])([0-9]+)/) {
490
491 #line number
492 push @diffArray, [ 'l', $1, $3 ];
493 }
494 elsif (/^< (.*)$/) {
495 push @diffArray, [ '-', $1, '' ];
496 }
497 elsif (/^> (.*)$/) {
498 push @diffArray, [ '+', '', $1 ];
499 }
500 else {
501
502 #push @diffArray, ['u', '', ''];
503 }
504 }
505 }
506 return \@diffArray;
507}
508
509sub _lock {
510 my $this = shift;
511
512 return unless $this->revisionHistoryExists();
513
514 # Try and get a lock on the file
515 my ( $rcsOutput, $exit ) =
516 Foswiki::Sandbox->sysCommand( $Foswiki::cfg{RCS}{lockCmd},
517 FILENAME => _encode( $this->{file} ) );
518
519 if ($exit) {
520
521 # if the lock has been set more than 24h ago, let's try to break it
522 # and then retry. Should not happen unless in Cairo upgrade
523 # scenarios - see Item2102
524 if ( ( time - ( stat( _encode( $this->{rcsFile} ) ) )[9] ) > 3600 ) {
525 warn 'Automatic recovery: breaking lock for ' . $this->{file};
526 Foswiki::Sandbox->sysCommand(
527 $Foswiki::cfg{RCS}{breaklockCmd},
528 FILENAME => _encode( $this->{file} )
529 );
530 ( $rcsOutput, $exit ) =
531 Foswiki::Sandbox->sysCommand( $Foswiki::cfg{RCS}{lockCmd},
532 FILENAME => _encode( $this->{file} ) );
533 }
534 if ($exit) {
535
536 # still no luck - bailing out
537 $rcsOutput ||= '';
538 throw Error::Simple( 'RCS: '
539 . $Foswiki::cfg{RCS}{lockCmd}
540 . ' failed: '
541 . $rcsOutput );
542 }
543 }
544 chmod( $Foswiki::cfg{Store}{filePermission}, _encode( $this->{file} ) );
545}
546
547# implements Rcs::Handler
548sub getRevisionAtTime {
549 my ( $this, $date ) = @_;
550
551 unless ( $this->revisionHistoryExists() ) {
552 return ( $date >= ( stat( _encode( $this->{file} ) ) )[9] ) ? 1 : undef;
553 }
554
555 require Foswiki::Time;
556 my $sdate = Foswiki::Time::formatTime( $date, '$rcs', 'gmtime' );
557 my ( $rcsOutput, $exit ) = Foswiki::Sandbox->sysCommand(
558 $Foswiki::cfg{RCS}{rlogDateCmd},
559 DATE => $sdate,
560 FILENAME => _encode( $this->{file} )
561 );
562
563 my $version = undef;
564 if ( $rcsOutput =~ m/revision \d+\.(\d+)/ ) {
565 $version = $1;
566 }
567
568 if ( $version && !$this->noCheckinPending() ) {
569
570 # Check the file date
571 $version++ if ( $date >= ( stat( _encode( $this->{file} ) ) )[9] );
572 }
573 return $version;
574}
575
57613µs1;
577__END__