jablonka.czprosek.czf

websvn

Subversion Repositories:
[/] [include/] [svnlook.php] - Blame information for rev 5

 

Line No. Rev Author Line
11simandl<?php
2// WebSVN - Subversion repository viewing via the web using PHP
3// Copyright (C) 2004-2006 Tim Armes
4//
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18//
19// --
20//
21// svn-look.php
22//
23// Svn bindings
24//
25// These binding currently use the svn command line to achieve their goal. Once a proper
26// SWIG binding has been produced for PHP, there'll be an option to use that instead.
27 
28require_once("include/utils.php");
29 
30// {{{ Classes for retaining log information ---
31 
32$debugxml = false;
33 
34class SVNMod {
35 var $action = '';
36 var $copyfrom = '';
37 var $copyrev = '';
38 var $path = '';
39}
40 
41class SVNListEntry {
42 var $rev = 1;
43 var $author = '';
44 var $date = '';
45 var $committime;
46 var $age = '';
47 var $file = '';
48 var $isdir = false;
49}
50 
51class SVNList {
52 var $entries; // Array of entries
53 var $curEntry; // Current entry
54 
55 var $path = ''; // The path of the list
56}
57 
58class SVNLogEntry {
59 var $rev = 1;
60 var $author = '';
61 var $date = '';
62 var $committime;
63 var $age = '';
64 var $msg = '';
65 var $path = '';
66 
67 var $mods;
68 var $curMod;
69}
70 
71function SVNLogEntry_compare($a, $b) {
72 return strnatcasecmp($a->path, $b->path);
73}
74 
75class SVNLog {
76 var $entries; // Array of entries
77 var $curEntry; // Current entry
78 
79 var $path = ''; // Temporary variable used to trace path history
80 
81 // findEntry
82 //
83 // Return the entry for a given revision
84 
85 function findEntry($rev) {
86 foreach ($this->entries as $index => $entry) {
87 if ($entry->rev == $rev) {
88 return $index;
89 }
90 }
91 }
92}
93 
94// }}}
95 
96// {{{ XML parsing functions---
97 
98$curTag = '';
99 
100$curList = 0;
101 
102// {{{ listStartElement
103 
104function listStartElement($parser, $name, $attrs) {
105 global $curList, $curTag, $debugxml;
106 
107 switch ($name) {
108 case "LIST":
109 if ($debugxml) print "Starting list\n";
110 
111 if (sizeof($attrs)) {
112 while (list($k, $v) = each($attrs)) {
113 switch ($k) {
114 case "PATH":
115 if ($debugxml) print "Path $v\n";
116 $curList->path = $v;
117 break;
118 }
119 }
120 }
121 break;
122 
123 case "ENTRY":
124 if ($debugxml) print "Creating new entry\n";
125 $curList->curEntry = new SVNListEntry;
126 
127 if (sizeof($attrs)) {
128 while (list($k, $v) = each($attrs)) {
129 switch ($k) {
130 case "KIND":
131 if ($debugxml) print "Kind $v\n";
132 $curList->curEntry->isdir = ($v == 'dir');
133 break;
134 }
135 }
136 }
137 break;
138 
139 case "COMMIT":
140 if ($debugxml) print "Commit\n";
141 
142 if (sizeof($attrs)) {
143 while (list($k, $v) = each($attrs)) {
144 switch ($k) {
145 case "REVISION":
146 if ($debugxml) print "Revision $v\n";
147 $curList->curEntry->rev = $v;
148 break;
149 }
150 }
151 }
152 break;
153 
154 default:
155 $curTag = $name;
156 break;
157 }
158}
159 
160// }}}
161 
162// {{{ listEndElement
163 
164function listEndElement($parser, $name) {
165 global $curList, $debugxml, $curTag;
166 
167 switch ($name) {
168 case "ENTRY":
169 if ($debugxml) print "Ending new list entry\n";
170 if ($curList->curEntry->isdir) {
1713simandl $curList->curEntry->file .= '/';
1721simandl }
173 $curList->entries[] = $curList->curEntry;
174 $curList->curEntry = null;
175 break;
176 }
177 
178 $curTag = "";
179}
180 
181// }}}
182 
183// {{{ listCharacterData
184 
185function listCharacterData($parser, $data) {
186 global $curList, $curTag, $lang, $debugxml;
187 
188 switch ($curTag) {
189 case "NAME":
190 if ($debugxml) print "Name: $data\n";
191 if (empty($data)) return;
192 $curList->curEntry->file .= $data;
193 break;
194 
195 case "AUTHOR":
196 if ($debugxml) print "Author: $data\n";
197 if (empty($data)) return;
198 $curList->curEntry->author .= htmlentities($data, ENT_COMPAT, "UTF-8");
199 break;
200 
201 case "DATE":
202 if ($debugxml) print "Date: $data\n";
203 $data = trim($data);
204 if (empty($data)) return;
205 
2063simandl $y = 0;
207 $mo = 0;
208 $d = 0;
209 $h = 0;
210 $m = 0;
211 $s = 0;
2121simandl sscanf($data, "%d-%d-%dT%d:%d:%d.", $y, $mo, $d, $h, $m, $s);
213 
214 $mo = substr("00".$mo, -2);
215 $d = substr("00".$d, -2);
216 $h = substr("00".$h, -2);
217 $m = substr("00".$m, -2);
218 $s = substr("00".$s, -2);
219 
2203simandl $committime = strtotime("$y-$mo-$d $h:$m:$s GMT");
2211simandl 
2223simandl $curList->curEntry->date = strftime('%Y-%m-%d %H:%M:%S', $committime);
223 
2241simandl $curList->curEntry->committime = $committime;
225 $curtime = time();
226 
227 // Get the number of seconds since the commit
228 $agesecs = $curtime - $committime;
229 if ($agesecs < 0) $agesecs = 0;
230 
231 $curList->curEntry->age = datetimeFormatDuration($agesecs, true, true);
232 
233 break;
234 }
235}
236 
237// }}}
238 
239$curLog = 0;
240 
241// {{{ logStartElement
242 
243function logStartElement($parser, $name, $attrs) {
244 global $curLog, $curTag, $debugxml;
245 
246 switch ($name) {
247 case "LOGENTRY":
248 if ($debugxml) print "Creating new log entry\n";
249 $curLog->curEntry = new SVNLogEntry;
250 $curLog->curEntry->mods = array();
251 
252 $curLog->curEntry->path = $curLog->path;
253 
254 if (sizeof($attrs)) {
255 while (list($k, $v) = each($attrs)) {
256 switch ($k) {
257 case "REVISION":
258 if ($debugxml) print "Revision $v\n";
259 $curLog->curEntry->rev = $v;
260 break;
261 }
262 }
263 }
264 break;
265 
266 case "PATH":
267 if ($debugxml) print "Creating new path\n";
268 $curLog->curEntry->curMod = new SVNMod;
269 
270 if (sizeof($attrs)) {
271 while (list($k, $v) = each($attrs)) {
272 switch ($k) {
273 case "ACTION":
274 if ($debugxml) print "Action $v\n";
275 $curLog->curEntry->curMod->action = $v;
276 break;
277 
278 case "COPYFROM-PATH":
279 if ($debugxml) print "Copy from: $v\n";
280 $curLog->curEntry->curMod->copyfrom = $v;
281 break;
282 
283 case "COPYFROM-REV":
284 $curLog->curEntry->curMod->copyrev = $v;
285 break;
286 }
287 }
288 }
289 
290 $curTag = $name;
291 break;
292 
293 default:
294 $curTag = $name;
295 break;
296 }
297}
298 
299// }}}
300 
301// {{{ logEndElement
302 
303function logEndElement($parser, $name) {
304 global $curLog, $debugxml, $curTag;
305 
306 switch ($name) {
307 case "LOGENTRY":
308 if ($debugxml) print "Ending new log entry\n";
309 $curLog->entries[] = $curLog->curEntry;
310 break;
311 
312 case "PATH":
313 if ($debugxml) print "Ending path\n";
314 $curLog->curEntry->mods[] = $curLog->curEntry->curMod;
315 break;
316 
317 case "MSG":
318 $curLog->curEntry->msg = trim($curLog->curEntry->msg);
319 if ($debugxml) print "Completed msg = '".$curLog->curEntry->msg."'\n";
320 break;
321 }
322 
323 $curTag = "";
324}
325 
326// }}}
327 
328// {{{ logCharacterData
329 
330function logCharacterData($parser, $data) {
331 global $curLog, $curTag, $lang, $debugxml;
332 
333 switch ($curTag) {
334 case "AUTHOR":
335 if ($debugxml) print "Author: $data\n";
336 if (empty($data)) return;
337 $curLog->curEntry->author .= htmlentities($data, ENT_COMPAT, "UTF-8");
338 break;
339 
340 case "DATE":
341 if ($debugxml) print "Date: $data\n";
342 $data = trim($data);
343 if (empty($data)) return;
344 
3453simandl $y = 0;
346 $mo = 0;
347 $d = 0;
348 $h = 0;
349 $m = 0;
350 $s = 0;
3511simandl sscanf($data, "%d-%d-%dT%d:%d:%d.", $y, $mo, $d, $h, $m, $s);
352 
353 $mo = substr("00".$mo, -2);
354 $d = substr("00".$d, -2);
355 $h = substr("00".$h, -2);
356 $m = substr("00".$m, -2);
357 $s = substr("00".$s, -2);
358 
3593simandl $committime = strtotime("$y-$mo-$d $h:$m:$s GMT");
3601simandl 
3613simandl $curLog->curEntry->date = strftime('%Y-%m-%d %H:%M:%S', $committime);
362 
3631simandl $curLog->curEntry->committime = $committime;
364 $curtime = time();
365 
366 // Get the number of seconds since the commit
367 $agesecs = $curtime - $committime;
368 if ($agesecs < 0) $agesecs = 0;
369 
370 $curLog->curEntry->age = datetimeFormatDuration($agesecs, true, true);
371 
372 break;
373 
374 case "MSG":
375 if ($debugxml) print "Msg: '$data'\n";
376 $curLog->curEntry->msg .= htmlentities($data, ENT_COMPAT, "UTF-8");
377 break;
378 
379 case "PATH":
380 if ($debugxml) print "Path name: '$data'\n";
381 $data = trim($data);
382 if (empty($data)) return;
383 
384 $curLog->curEntry->curMod->path .= $data;
385 
386 // The XML returned when a file is renamed/branched in inconsistant. In the case
387 // of a branch, the path information doesn't include the leafname. In the case of
388 // a rename, it does. Ludicrous.
389 
390 if (!empty($curLog->path)) {
391 $pos = strrpos($curLog->path, "/");
392 $curpath = substr($curLog->path, 0, $pos);
393 $leafname = substr($curLog->path, $pos + 1);
394 } else {
395 $curpath = "";
396 $leafname = "";
397 }
398 
399 if ($curLog->curEntry->curMod->action == "A") {
400 if ($debugxml) print "Examining added path '".$curLog->curEntry->curMod->copyfrom."' - Current path = '$curpath', leafname = '$leafname'\n";
401 if ($data == $curLog->path) { // For directories and renames
402 if ($debugxml) print "New path for comparison: '".$curLog->curEntry->curMod->copyfrom."'\n";
403 $curLog->path = $curLog->curEntry->curMod->copyfrom;
404 } else if ($data == $curpath || $data == $curpath."/") { // Logs of files that have moved due to branching
405 if ($debugxml) print "New path for comparison: '".$curLog->curEntry->curMod->copyfrom."/$leafname'\n";
406 $curLog->path = $curLog->curEntry->curMod->copyfrom."/$leafname";
407 }
408 }
409 break;
410 }
411}
412 
413// }}}
414 
415// }}}
416 
417// {{{ internal functions (_topLevel and _listSort)
418 
419// Function returns true if the give entry in a directory tree is at the top level
420 
421function _topLevel($entry) {
422 // To be at top level, there must be one space before the entry
423 return (strlen($entry) > 1 && $entry{0} == " " && $entry{1} != " ");
424}
425 
4263simandl// Function to sort two given directory entries.
427// Directories go at the top if config option alphabetic is not set
4281simandl 
429function _listSort($e1, $e2) {
4303simandl global $config;
4311simandl 
4323simandl if (!$config->isAlphabeticOrder()) {
433 $isDir1 = $e1->file{strlen($e1->file) - 1} == "/";
434 $isDir2 = $e2->file{strlen($e2->file) - 1} == "/";
4351simandl 
4363simandl if ($isDir1 && !$isDir2) return -1;
437 if ($isDir2 && !$isDir1) return 1;
438 }
439 
4401simandl return strnatcasecmp($e1->file, $e2->file);
441}
442 
443// }}}
444 
445// {{{ encodePath
446 
447// Function to encode a URL without encoding the /'s
448 
449function encodePath($uri) {
450 global $config;
451 
452 $uri = str_replace(DIRECTORY_SEPARATOR, "/", $uri);
453 
454 $parts = explode('/', $uri);
455 for ($i = 0; $i < count($parts); $i++) {
456 if ( function_exists("mb_detect_encoding") && function_exists("mb_convert_encoding")) {
457 $parts[$i] = mb_convert_encoding($parts[$i], "UTF-8", mb_detect_encoding($parts[$i]));
458 }
459 
4603simandl // do not urlencode the 'svn+ssh://' part!
461 if ($i != 0 || $parts[$i] != 'svn+ssh:') {
462 $parts[$i] = rawurlencode($parts[$i]);
463 }
4641simandl }
465 
466 $uri = implode('/', $parts);
467 
468 // Quick hack. Subversion seems to have a bug surrounding the use of %3A instead of :
469 
470 $uri = str_replace("%3A" ,":", $uri);
471 
472 // Correct for Window share names
4733simandl if ($config->serverIsWindows) {
4741simandl if (substr($uri, 0,2) == "//") {
475 $uri = "\\".substr($uri, 2, strlen($uri));
476 }
477 
478 if (substr($uri, 0,10)=="file://///" ) {
479 $uri="file:///\\".substr($uri, 10, strlen($uri));
480 }
481 }
482 
483 return $uri;
484}
485 
486// }}}
487 
488// The SVNRepository class
489 
490class SVNRepository {
491 var $repConfig;
4923simandl var $geshi = null;
4931simandl 
494 function SVNRepository($repConfig) {
495 $this->repConfig = $repConfig;
496 }
497 
498 // {{{ highlightLine
499 //
500 // Distill line-spanning syntax highlighting so that each line can stand alone
501 // (when invoking on the first line, $attributes should be an empty array)
502 // Invoked to make sure all open syntax highlighting tags (<font>, <i>, <b>, etc.)
503 // are closed at the end of each line and re-opened on the next line
504 
505 function highlightLine($line, &$attributes) {
506 $hline = "";
507 
508 // Apply any highlighting in effect from the previous line
509 foreach ($attributes as $attr) {
510 $hline.=$attr['text'];
511 }
512 
513 // append the new line
514 $hline.=$line;
515 
516 // update attributes
517 for ($line = strstr($line, "<"); $line; $line = strstr(substr($line,1), "<")) {
518 if (substr($line,1,1) == "/") { // if this closes a tag, remove most recent corresponding opener
519 $tagNamLen = strcspn($line, "> \t", 2);
520 $tagNam = substr($line,2,$tagNamLen);
521 foreach (array_reverse(array_keys($attributes)) as $k) {
522 if ($attributes[$k]['tag'] == $tagNam) {
523 unset($attributes[$k]);
524 break;
525 }
526 }
527 } else { // if this opens a tag, add it to the list
528 $tagNamLen = strcspn($line, "> \t", 1);
529 $tagNam = substr($line,1,$tagNamLen);
530 $tagLen = strcspn($line, ">") + 1;
531 $attributes[] = array('tag' => $tagNam, 'text' => substr($line,0,$tagLen));
532 }
533 }
534 
535 // close any still-open tags
536 foreach (array_reverse($attributes) as $attr) {
537 $hline.="</".$attr['tag'].">";
538 }
539 
540 // XXX: this just simply replaces [ and ] with their entities to prevent
541 // it from being parsed by the template parser; maybe something more
542 // elegant is in order?
543 $hline = str_replace('[', '&#91;', str_replace(']', '&#93;', $hline) );
544 return $hline;
545 }
546 
547 // }}}
548 
549 // {{{ getFileContents
550 //
551 // Dump the content of a file to the given filename
552 
553 function getFileContents($path, $filename, $rev = 0, $pipe = "", $perLineHighlighting = false) {
554 global $config, $extEnscript;
555 
5563simandl $highlighted = false;
557 
5581simandl // If there's no filename, we'll just deliver the contents as it is to the user
559 if ($filename == "") {
5603simandl $path = encodepath($this->getSvnpath($path));
561 passthruCommand($config->svn." cat ".$this->repConfig->svnParams().quote($path.'@'.$rev).' '.$pipe);
562 return $highlighted;
5631simandl }
564 
565 // Get the file contents info
566 
567 $ext = strrchr($path, ".");
568 $l = @$extEnscript[$ext];
569 
570 if ($l == "php") {
571 // Output the file to the filename
5723simandl $path = encodepath($this->getSvnpath($path));
573 $cmd = $config->svn." cat ".$this->repConfig->svnParams().quote($path.'@'.$rev).' > '.quote($filename);
574 $retcode = 0;
575 execCommand($cmd, $retcode);
576 if ($retcode != 0) {
577 print'Unable to call svn command "'.$config->svn.'"';
578 exit(0);
579 }
5801simandl 
581 // Get the file as a string (memory hogging, but we have no other options)
582 $content = highlight_file($filename, true);
583 
584 // Destroy the previous version, and replace it with the highlighted version
585 $f = fopen($filename, "w");
586 if ($f) {
5873simandl $highlighted = true;
5881simandl // The highlight file function doesn't deal with line endings very nicely at all. We'll have to do it
589 // by hand.
590 
591 // Remove the first line generated by highlight()
592 $pos = strpos($content, "\n");
593 $content = substr($content, $pos+1);
594 
595 $content = explode("<br />", $content);
596 
597 if ($perLineHighlighting) {
598 // If we need each line independently highlighted (e.g. for diff or blame)
5993simandl // then we'll need to filter the output of the highlighter
6001simandl // to make sure tags like <font>, <i> or <b> don't span lines
601 
602 // $attributes is used to remember what highlighting attributes
603 // are in effect from one line to the next
604 $attributes = array(); // start with no attributes in effect
605 
606 foreach ($content as $line) {
6073simandl fputs($f, $this->highlightLine(rtrim($line), $attributes)."\n");
6081simandl }
609 } else {
610 foreach ($content as $line) {
611 fputs($f, rtrim($line)."\n");
612 }
613 }
614 
615 fclose($f);
616 }
617 
618 } else {
6193simandl $tempname = $filename;
620 if ($perLineHighlighting) {
621 $tempname = tempnam('temp', '');
622 }
623 $highlighted = true;
624 if ($config->useGeshi && $geshiLang = $this->highlightLanguageUsingGeshi($ext)) {
625 $this->applyGeshi($path, $tempname, $rev, $geshiLang);
6261simandl 
627 } else if ($config->useEnscript) {
628 // Get the files, feed it through enscript, then remove the enscript headers using sed
629 //
630 // Note that the sec command returns only the part of the file between <PRE> and </PRE>.
631 // It's complicated because it's designed not to return those lines themselves.
632 
6333simandl $path = encodepath($this->getSvnpath($path));
634 $cmd = $config->svn." cat ".$this->repConfig->svnParams().quote($path.'@'.$rev).' | '.
635 $config->enscript." --language=html ".
636 ($l ? "--color --pretty-print=$l" : "")." -o - | ".
637 $config->sed." -n ".$config->quote."1,/^<PRE.$/!{/^<\\/PRE.$/,/^<PRE.$/!p;}".$config->quote." > $tempname";
638 $retcode = 0;
639 execCommand($cmd, $retcode);
640 if ($retcode != 0) {
641 print'Unable to call svn command "'.$config->svn.'"';
642 if ($tempname != $filename) {
643 @unlink($tempname);
644 }
645 exit(0);
646 }
6471simandl 
648 } else {
6493simandl $highlighted = false;
650 $path = encodepath(str_replace(DIRECTORY_SEPARATOR, "/", $this->getSvnpath($path)));
651 $cmd = $config->svn." cat ".$this->repConfig->svnParams().quote($path.'@'.$rev).' > '.quote($filename);
652 $retcode = 0;
653 execCommand($cmd, $retcode);
654 if ($retcode != 0) {
655 print'Unable to call svn command "'.$config->svn.'"';
656 if ($tempname != $filename) {
657 @unlink($tempname);
658 }
659 exit(0);
660 }
6611simandl }
6623simandl 
663 if ($highlighted && $perLineHighlighting) {
664 // If we need each line independently highlighted (e.g. for diff or blame)
665 // then we'll need to filter the output of the highlighter
666 // to make sure tags like <font>, <i> or <b> don't span lines
667 
668 $dst = fopen($filename, 'w');
669 if ($dst) {
670 $content = file_get_contents($tempname);
671 $content = explode('<br />', $content);
672 
673 // $attributes is used to remember what highlighting attributes
674 // are in effect from one line to the next
675 $attributes = array(); // start with no attributes in effect
676 
677 foreach ($content as $line) {
678 fputs($dst, $this->highlightLine(trim($line), $attributes)."\n");
679 }
680 fclose($dst);
681 }
682 }
683 if ($tempname != $filename) {
684 @unlink($tempname);
685 }
6861simandl }
6873simandl return $highlighted;
6881simandl }
689 
690 // }}}
691 
6923simandl // {{{ highlightLanguageUsingGeshi
693 //
694 // check if geshi can highlight the given extension and return the language
695 
696 function highlightLanguageUsingGeshi($ext) {
697 global $extGeshi;
698 if (substr($ext, 0, 1) == '.') $ext = substr($ext, 1);
699 
700 foreach ($extGeshi as $lang => $extensions) {
701 if (in_array($ext, $extensions)) {
702 if ($this->geshi === null) {
703 require_once 'lib/geshi.php';
704 $this->geshi = new GeSHi();
705 } else {
706 $this->geshi->error = false;
707 }
708 $this->geshi->set_language($lang);
709 if ($this->geshi->error() === false) {
710 return $lang;
711 }
712 }
713 }
714 return '';
715 
716 
717 }
718 
719 // }}}
720 
7211simandl // {{{ applyGeshi
722 //
723 // perform syntax highlighting using geshi
724 
7253simandl function applyGeshi($path, $filename, $rev, $lang, $return = false) {
7261simandl global $config;
727 
728 // Output the file to the filename
7293simandl $path = encodepath($this->getSvnpath($path));
730 $cmd = $config->svn." cat ".$this->repConfig->svnParams().quote($path.'@'.$rev).' > '.quote($filename);
731 $retcode = 0;
732 execCommand($cmd, $retcode);
733 if ($retcode != 0) {
734 print'Unable to call svn command "'.$config->svn.'"';
735 exit(0);
736 }
7371simandl 
738 $source = file_get_contents($filename);
7393simandl if ($this->geshi === null) {
740 require_once 'lib/geshi.php';
741 $this->geshi = new GeSHi();
742 }
743 $this->geshi->set_source($source);
744 $this->geshi->set_language($lang);
745 $this->geshi->set_header_type(GESHI_HEADER_DIV);
746 $this->geshi->set_overall_class('geshi');
747 $this->geshi->set_tab_width($this->repConfig->getExpandTabsBy());
748 
7491simandl if ($return) {
7503simandl return $this->geshi->parse_code();
7511simandl } else {
752 $f = @fopen($filename, 'w');
7533simandl fwrite($f, $this->geshi->parse_code());
7541simandl fclose($f);
755 }
756 }
757 
758 // }}}
759 
760 // {{{ listFileContents
761 //
762 // Print the contents of a file without filling up Apache's memory
763 
764 function listFileContents($path, $rev = 0) {
765 global $config, $extEnscript;
766 
767 $pre = false;
768 
769 // Get the file contents info
770 
771 $ext = strrchr($path, ".");
772 $l = @$extEnscript[$ext];
773 
774 // Deal with php highlighting internally
775 if ($l == "php") {
776 $tmp = tempnam("temp", "wsvn");
777 
778 // Output the file to a temporary file
7793simandl $path = encodepath($this->getSvnpath($path));
780 $cmd = $config->svn." cat ".$this->repConfig->svnParams().quote($path.'@'.$rev).' > '.$tmp;
781 $retcode = 0;
782 execCommand($cmd, $retcode);
783 if ($retcode != 0) {
784 print'Unable to call svn command "'.$config->svn.'"';
785 @unlink($tmp);
786 exit(0);
787 }
7881simandl $tmpStr = file_get_contents($tmp);
789 $tmpStr = str_replace(array("\r\n"), array("\n"), $tmpStr);
790 highlight_string($tmpStr);
791 @unlink($tmp);
7923simandl } else if ($config->useGeshi && $geshiLang = $this->highlightLanguageUsingGeshi($ext)) {
7931simandl $tmp = tempnam("temp", "wsvn");
7943simandl print toOutputEncoding($this->applyGeshi($path, $tmp, $rev, $geshiLang, true), $this->repConfig->getContentEncoding());
795 @unlink($tmp);
7961simandl } else {
797 if ($config->useEnscript) {
7983simandl $path = encodepath($this->getSvnpath($path));
799 $cmd = $config->svn." cat ".$this->repConfig->svnParams().quote($path.'@'.$rev).' | '.
8001simandl $config->enscript." --language=html ".
801 ($l ? "--color --pretty-print=$l" : "")." -o - | ".
8023simandl $config->sed." -n ".$config->quote."/^<PRE.$/,/^<\\/PRE.$/p".$config->quote;
8031simandl } else {
8043simandl $path = encodepath($this->getSvnpath($path));
805 $cmd = $config->svn." cat ".$this->repConfig->svnParams().quote($path.'@'.$rev);
8061simandl $pre = true;
807 }
808 
8093simandl if ($result = popenCommand($cmd, "r")) {
810 if ($pre) echo "<pre>";
8111simandl 
8123simandl $contentEncoding = $this->repConfig->getContentEncoding();
8131simandl while (!feof($result)) {
814 $line = fgets($result, 1024);
815 if ($pre) $line = replaceEntities($line, $this->repConfig);
8163simandl else $line = toOutputEncoding($line, $contentEncoding);
8171simandl 
818 print hardspace($line);
819 }
820 
8213simandl if ($pre) echo "</pre>";
8221simandl 
823 pclose($result);
824 }
825 }
826 }
827 
828 // }}}
829 
830 // {{{ getBlameDetails
831 //
832 // Dump the blame content of a file to the given filename
833 
834 function getBlameDetails($path, $filename, $rev = 0) {
835 global $config;
836 
8373simandl $path = encodepath($this->getSvnpath($path));
838 $cmd = $config->svn." blame ".$this->repConfig->svnParams().quote($path.'@'.$rev).' > '.quote($filename);
8391simandl 
8403simandl $retcode = 0;
841 execCommand($cmd, $retcode);
842 if ($retcode != 0) {
843 print'Unable to call svn command "'.$config->svn.'"';
844 exit(0);
845 }
8461simandl }
847 
848 // }}}
849 
850 // {{{ getProperty
851 
852 function getProperty($path, $property, $rev = 0) {
853 global $config;
854 
8553simandl $path = encodepath($this->getSvnpath($path));
8561simandl 
857 if ($rev > 0) {
8583simandl $rev = '@'.$rev;
8591simandl } else {
860 $rev = '';
861 }
862 
8633simandl $ret = runCommand($config->svn." propget $property ".$this->repConfig->svnParams().quote($path.$rev), true);
8641simandl 
865 // Remove the surplus newline
866 if (count($ret)) {
867 unset($ret[count($ret) - 1]);
868 }
869 
870 return implode("\n", $ret);
871 }
872 
873 // }}}
874 
875 // {{{ exportDirectory
876 //
877 // Exports the directory to the given location
878 
879 function exportDirectory($path, $filename, $rev = 0) {
880 global $config;
881 
8823simandl $path = encodepath($this->getSvnpath($path));
883 $cmd = $config->svn." export ".$this->repConfig->svnParams().quote($path.'@'.$rev).' '.quote($filename);
8841simandl 
8853simandl $retcode = 0;
886 execCommand($cmd, $retcode);
887 if ($retcode != 0) {
888 print'Unable to call svn command "'.$config->svn.'"';
889 exit(0);
890 }
8911simandl }
892 
893 // }}}
894 
895 // {{{ getList
896 
897 function getList($path, $rev = 0) {
898 global $config, $curList, $vars, $lang;
899 
900 $xml_parser = xml_parser_create("UTF-8");
901 xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true);
902 xml_set_element_handler($xml_parser, "listStartElement", "listEndElement");
903 xml_set_character_data_handler($xml_parser, "listCharacterData");
904 
905 // Since directories returned by svn log don't have trailing slashes (:-(), we need to remove
906 // the trailing slash from the path for comparison purposes
907 
908 if ($path{strlen($path) - 1} == "/" && $path != "/") {
909 $path = substr($path, 0, -1);
910 }
911 
912 $curList = new SVNList;
913 $curList->entries = array();
914 $curList->path = $path;
915 
916 // Get the list info
9173simandl $path = encodepath($this->getSvnpath($path));
9181simandl 
919 if ($rev == 0) {
920 $headlog = $this->getLog("/", "", "", true, 1);
9213simandl if (is_string($headlog)) {
922 echo $headlog;
923 exit;
924 }
9251simandl if (isset($headlog->entries[0])) $rev = $headlog->entries[0]->rev;
926 }
927 
9283simandl $cmd = quoteCommand($config->svn.' list --xml '.$this->repConfig->svnParams().quote($path.'@'.$rev));
9291simandl 
930 $descriptorspec = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
931 
932 $resource = proc_open($cmd, $descriptorspec, $pipes);
933 
934 if (!is_resource($resource)) {
935 echo "<p>".$lang['BADCMD'].": <code>".$cmd."</code></p>";
936 exit;
937 }
938 
939 $handle = $pipes[1];
940 $firstline = true;
941 while (!feof($handle)) {
942 $line = fgets($handle);
943 if (!xml_parse($xml_parser, $line, feof($handle))) {
9443simandl $errorMsg = sprintf("XML error: %s (%d) at line %d column %d byte %d\ncmd: %s",
9451simandl xml_error_string(xml_get_error_code($xml_parser)),
946 xml_get_error_code($xml_parser),
947 xml_get_current_line_number($xml_parser),
948 xml_get_current_column_number($xml_parser),
949 xml_get_current_byte_index($xml_parser),
9503simandl $cmd);
951 if (xml_get_error_code($xml_parser) != 5) {
952 // errors can contain sensitive info! don't echo this ~J
953 error_log($errorMsg);
9541simandl exit;
955 } else {
9563simandl break;
9571simandl }
958 }
959 }
960 
9613simandl $error = '';
9621simandl while (!feof($pipes[2])) {
963 $error .= fgets($pipes[2]);
964 }
965 
966 $error = toOutputEncoding(trim($error));
967 
968 fclose($pipes[0]);
969 fclose($pipes[1]);
970 fclose($pipes[2]);
971 
972 proc_close($resource);
973 
974 if (!empty($error)) {
9753simandl echo '<p>'.$lang['BADCMD'].': <code>'.$cmd.'</code></p><p>'.nl2br($error).'</p>';
9761simandl exit;
977 }
978 
979 xml_parser_free($xml_parser);
980 
9813simandl // Sort the entries into alphabetical order
9821simandl usort($curList->entries, "_listSort");
983 
984 return $curList;
985 }
986 
987 // }}}
988 
989 // {{{ getLog
990 
991 function getLog($path, $brev = "", $erev = 1, $quiet = false, $limit = 2) {
992 global $config, $curLog, $vars, $lang;
993 
994 $xml_parser = xml_parser_create("UTF-8");
995 xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true);
996 xml_set_element_handler($xml_parser, "logStartElement", "logEndElement");
997 xml_set_character_data_handler($xml_parser, "logCharacterData");
998 
999 // Since directories returned by svn log don't have trailing slashes (:-(), we need to remove
1000 // the trailing slash from the path for comparison purposes
1001 
1002 if ($path{strlen($path) - 1} == "/" && $path != "/") {
1003 $path = substr($path, 0, -1);
1004 }
1005 
1006 $curLog = new SVNLog;
1007 $curLog->entries = array();
1008 $curLog->path = $path;
1009 
1010 $revStr = "";
1011 
1012 if ($brev && $erev) {
1013 $revStr = "-r$brev:$erev";
1014 } else if ($brev) {
1015 $revStr = "-r$brev:1";
1016 }
1017 
1018 if (($config->subversionMajorVersion > 1 || $config->subversionMinorVersion >=2) && $limit != 0) {
1019 $revStr .= " --limit $limit";
1020 }
1021 
1022 // Get the log info
10233simandl $path = encodepath($this->getSvnpath($path));
10241simandl $info = "--verbose";
1025 if ($quiet) $info = "--quiet";
1026 
10273simandl $pegRev = '';
1028 if ($brev) {
1029 $pegRev = '@'.$brev;
1030 }
1031 $cmd = quoteCommand($config->svn." log --xml $info $revStr ".$this->repConfig->svnParams().quote($path.$pegRev));
10321simandl 
1033 $descriptorspec = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
1034 
1035 $resource = proc_open($cmd, $descriptorspec, $pipes);
1036 
1037 if (!is_resource($resource)) {
1038 echo "<p>".$lang['BADCMD'].": <code>".$cmd."</code></p>";
1039 exit;
1040 }
1041 
1042 $handle = $pipes[1];
1043 $firstline = true;
1044 while (!feof($handle)) {
1045 $line = fgets($handle);
1046 if (!xml_parse($xml_parser, $line, feof($handle))) {
10473simandl $errorMsg = sprintf("XML error: %s (%d) at line %d column %d byte %d\ncmd: %s",
10481simandl xml_error_string(xml_get_error_code($xml_parser)),
1049 xml_get_error_code($xml_parser),
1050 xml_get_current_line_number($xml_parser),
1051 xml_get_current_column_number($xml_parser),
1052 xml_get_current_byte_index($xml_parser),
10533simandl $cmd);
1054 if (xml_get_error_code($xml_parser) != 5) {
1055 // errors can contain sensitive info! don't echo this ~J
1056 error_log($errorMsg);
10571simandl exit;
1058 } else {
10593simandl break;
10601simandl }
1061 }
1062 }
1063 
10643simandl $error = '';
10651simandl while (!feof($pipes[2])) {
1066 $error .= fgets($pipes[2]);
1067 }
1068 
1069 $error = toOutputEncoding(trim($error));
1070 
1071 fclose($pipes[0]);
1072 fclose($pipes[1]);
1073 fclose($pipes[2]);
1074 
1075 proc_close($resource);
1076 
1077 if (!empty($error)) {
10783simandl return '<p>'.$lang['BADCMD'].': <code>'.$cmd.'</code></p><p>'.nl2br($error).'</p>';
10791simandl }
1080 
1081 xml_parser_free($xml_parser);
1082 
1083 foreach ($curLog->entries as $entryKey => $entry) {
1084 $fullModAccess = true;
1085 $anyModAccess = (count($entry->mods) == 0);
1086 foreach ($entry->mods as $modKey => $mod) {
1087 $access = $this->repConfig->hasReadAccess($mod->path);
1088 if ($access) {
1089 $anyModAccess = true;
1090 } else {
1091 // hide modified entry when access is prohibited
1092 unset($curLog->entries[$entryKey]->mods[$modKey]);
1093 $fullModAccess = false;
1094 }
1095 }
1096 if (!$fullModAccess) {
1097 // hide commit message when access to any of the entries is prohibited
1098 $curLog->entries[$entryKey]->msg = '';
1099 }
1100 if (!$anyModAccess) {
1101 // hide author and date when access to all of the entries is prohibited
1102 $curLog->entries[$entryKey]->author = '';
1103 $curLog->entries[$entryKey]->date = '';
1104 $curLog->entries[$entryKey]->committime = '';
1105 $curLog->entries[$entryKey]->age = '';
1106 }
1107 }
1108 
1109 return $curLog;
1110 }
1111 
1112 // }}}
1113 
11143simandl function isFile($path, $rev = 0) {
1115 global $config;
1116 
1117 $path = encodepath($this->getSvnpath($path));
1118 if ($rev != 0) {
1119 $rev = '@'.$rev;
1120 } else {
1121 $rev = '';
1122 }
1123 $cmd = $config->svn." info --xml ".$this->repConfig->svnParams().quote($path.$rev);
1124 $output = runCommand($cmd, true);
1125 
1126 return strpos(implode(' ', $output), 'kind="file"') !== false;
1127 }
1128 
1129 // {{{ getSvnpath
1130 
1131 function getSvnpath( $path ) {
1132 if ($this->repConfig->subpath === null) {
1133 return $this->repConfig->path.$path;
1134 } else {
1135 $path = preg_replace('|^/?'.$this->repConfig->subpath.'|', '', $path);
1136 return $this->repConfig->path.'/'.$this->repConfig->subpath.$path;
1137 }
1138 }
1139 
1140 // }}}
1141 
11421simandl}
1143 
1144// {{{ initSvnVersion
1145 
11463simandlfunction initSvnVersion() {
11471simandl global $config;
1148 
1149 $ret = runCommand($config->svn_noparams." --version", false);
1150 
1151 if (preg_match("~([0-9]?)\.([0-9]?)\.([0-9]?)~",$ret[0],$matches)) {
11523simandl $config->setSubversionVersion($matches[0]);
1153 $config->setSubversionMajorVersion($matches[1]);
1154 $config->setSubversionMinorVersion($matches[2]);
11551simandl }
1156}
1157 
1158// }}}

Powered by WebSVN 2.2.1