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