Rev Author Line No. Line
4988 kaklik 1 <?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 // revision.php
22 //
23 // Show the details for a given revision
24  
25 require_once 'include/setup.php';
26 require_once 'include/svnlook.php';
27 require_once 'include/utils.php';
28 require_once 'include/template.php';
29 require_once 'include/bugtraq.php';
30  
31 // Make sure that we have a repository
32 if (!$rep)
33 {
34 renderTemplate404('revision','NOREP');
35 }
36  
37 $svnrep = new SVNRepository($rep);
38  
39 $ppath = ($path == '' || $path[0] != '/') ? '/'.$path : $path;
40 createPathLinks($rep, $ppath, $rev, $peg);
41 $passRevString = createRevAndPegString($rev, $peg);
42  
43 // Find the youngest revision containing changes for the given path
44 $history = $svnrep->getLog($path, 'HEAD', 1, true, 2, ($path == '/') ? '' : $peg);
45  
46 if (!$history)
47 {
48 unset($vars['error']);
49 $history = $svnrep->getLog($path, '', '', true, 2, ($path == '/') ? '' : $peg);
50  
51 if (!$history)
52 {
53 renderTemplate404('revision','NOPATH');
54 }
55 }
56  
57 $youngest = ($history && isset($history->entries[0])) ? $history->entries[0]->rev : 0;
58 $vars['youngestrev'] = $youngest;
59  
60 // TODO The "youngest" rev is often incorrect when both path and rev are specified.
61 // If a path was last modified at rev M and the URL contains rev N, it uses rev N.
62  
63 // Unless otherwise specified, we get the log details of the latest change
64 $lastChangedRev = ($rev) ? $rev : $youngest;
65 $history = $svnrep->getLog($path, $lastChangedRev, 1, false, 2, $peg, true);
66  
67 if (!$history)
68 {
69 renderTemplate404('revision','NOPATH');
70 }
71  
72 if (empty($rev))
73 {
74 $rev = $lastChangedRev;
75 }
76  
77 // Generate links to newer and older revisions
78 $revurl = $config->getURL($rep, $path, 'revision');
79  
80 if ($rev < $youngest)
81 {
82 $vars['goyoungesturl'] = $config->getURL($rep, $path, 'revision');
83 $vars['goyoungestlink'] = '<a href="'.$vars['goyoungesturl'].'"'.($youngest ? ' title="'.$lang['REV'].' '.$youngest.'"' : '').'>'.$lang['GOYOUNGEST'].'</a>';
84  
85 $history2 = $svnrep->getLog($path, $rev, $youngest, true, 2, $peg);
86 if (isset($history2->entries[1]))
87 {
88 $nextRev = $history2->entries[1]->rev;
89 if ($nextRev != $youngest)
90 {
91 $vars['nextrev'] = $nextRev;
92 $vars['nextrevurl'] = $revurl.createRevAndPegString($nextRev, $path != '/' ? $peg ? $peg : $rev : '');
93 //echo 'NEXT='.$vars['nextrevurl'].'<br/>';
94 }
95 }
96  
97 unset($vars['error']);
98 }
99  
100 if (isset($history->entries[1]))
101 {
102 $prevRev = $history->entries[1]->rev;
103 $prevPath = $history->entries[1]->path;
104 $vars['prevrev'] = $prevRev;
105 $vars['prevrevurl'] = $revurl.createRevAndPegString($prevRev, $path != '/' ? ($peg ? $peg : $rev) : '');
106 //echo 'PREV='.$vars['prevrevurl'].'<br/>';
107 }
108  
109 // Save the entry from which we pull information for the current revision.
110 $logEntry = (isset($history->entries[0])) ? $history->entries[0] : null;
111  
112 $bugtraq = new Bugtraq($rep, $svnrep, $ppath);
113  
114 $vars['action'] = '';
115 $vars['rev'] = $rev;
116 $vars['peg'] = $peg;
117 $vars['path'] = str_replace('%2F', '/', rawurlencode($ppath));
118 $vars['safepath'] = escape($ppath);
119  
120 if ($logEntry)
121 {
122 $vars['date'] = $logEntry->date;
123 $vars['age'] = datetimeFormatDuration(time() - strtotime($logEntry->date));
124 $vars['author'] = $logEntry->author;
125 $vars['log'] = nl2br($bugtraq->replaceIDs(create_anchors(xml_entities($logEntry->msg))));
126 }
127  
128 $isDir = @$_REQUEST['isdir'] == 1 || $path == '' || $path == '/';
129 $vars['logurl'] = $config->getURL($rep, $path, 'log').$passRevString.($isDir ? '&amp;isdir=1' : '');
130 $vars['loglink'] = '<a href="'.$vars['logurl'].'">'.$lang['VIEWLOG'].'</a>';
131  
132 $dirPath = $isDir ? $path : dirname($path).'/';
133 $vars['directoryurl'] = $config->getURL($rep, $dirPath, 'dir').$passRevString.'#'.anchorForPath($dirPath);
134 $vars['directorylink'] = '<a href="'.$vars['directoryurl'].'">'.$lang['LISTING'].'</a>';
135  
136 if ($path != $dirPath)
137 {
138 $vars['filedetailurl'] = $config->getURL($rep, $path, 'file').$passRevString;
139 $vars['filedetaillink'] = '<a href="'.$vars['filedetailurl'].'">'.$lang['FILEDETAIL'].'</a>';
140 $vars['blameurl'] = $config->getURL($rep, $path, 'blame').$passRevString;
141 $vars['blamelink'] = '<a href="'.$vars['blameurl'].'">'.$lang['BLAME'].'</a>';
142 }
143  
144 if ($rep->isRssEnabled())
145 {
146 $vars['rssurl'] = $config->getURL($rep, $path, 'rss').createRevAndPegString('', $peg);
147 $vars['rsslink'] = '<a href="'.$vars['rssurl'].'">'.$lang['RSSFEED'].'</a>';
148 }
149  
150 $changes = $logEntry ? $logEntry->mods : array();
151  
152 if (!is_array($changes))
153 {
154 $changes = array();
155 }
156  
157 usort($changes, 'SVNLogEntry_compare');
158  
159 $row = 0;
160  
161 $prevRevString = createRevAndPegString($rev - 1, $rev - 1);
162 $thisRevString = createRevAndPegString($rev, $rev);
163  
164 foreach ($changes as $change)
165 {
166 $linkRevString = ($change->action == 'D') ? $prevRevString : $thisRevString;
167 $isDir = $change->isdir;
168  
169 if ($isDir !== null)
170 {
171 $isFile = !$isDir;
172 }
173 else
174 {
175 // NOTE: This is a hack (runs `svn info` on each path) to see if it's a file.
176 // `svn log --verbose --xml` should really provide this info, but does only in recent version?
177 $lastSeenRev = ($change->action == 'D') ? $rev - 1 : $rev;
178 $isFile = $svnrep->isFile($change->path, $lastSeenRev, $lastSeenRev);
179 }
180  
181 if (!$isFile && $change->path != '/')
182 {
183 $change->path .= '/';
184 }
185  
186 $resourceExisted = $change->action == 'M' || $change->copyfrom;
187 $listing[] = array(
188 'path' => str_replace('%2F', '/', rawurlencode($change->path)),
189 'safepath' => escape($change->path),
190 'oldpath' => str_replace('%2F', '/', rawurlencode($change->copyfrom)).($change->copyfrom ? '@'.$change->copyrev : ''),
191 'oldsafepath' => escape($change->copyfrom ? $change->copyfrom.'@'.$change->copyrev : ''),
192 'action' => $change->action,
193 'added' => $change->action == 'A',
194 'deleted' => $change->action == 'D',
195 'modified' => $change->action == 'M',
196 'detailurl' => $config->getURL($rep, $change->path, ($isFile ? 'file' : 'dir')).$linkRevString,
197 // For deleted resources, the log link points to the previous revision.
198 'logurl' => $config->getURL($rep, $change->path, 'log').$linkRevString.($isFile ? '' : '&amp;isdir=1'),
199 'diffurl' => $resourceExisted ? $config->getURL($rep, $change->path, 'diff').$linkRevString : '',
200 'blameurl' => $resourceExisted ? $config->getURL($rep, $change->path, 'blame').$linkRevString : '',
201 'rowparity' => $row,
202 'notinpath' => substr($change->path, 0, strlen($path)) != $path,
203 );
204  
205 $row = 1 - $row;
206 }
207  
208 if (isset($prevRev))
209 {
210 $vars['compareurl'] = $config->getURL($rep, '', 'comp').'compare[]='.rawurlencode($prevPath).'@'.$prevRev. '&amp;compare[]='.rawurlencode($path).'@'.$rev;
211 $vars['comparelink'] = '<a href="'.$vars['compareurl'].'">'.$lang['DIFFPREV'].'</a>';
212 }
213  
214 if (!$rep->hasReadAccess($path))
215 {
216 $vars['error'] = $lang['NOACCESS'];
217 sendHeaderForbidden();
218 }
219  
220 $vars['restricted'] = !$rep->hasReadAccess($path, false);
221  
222 renderTemplate('revision');