function createPathLinks($rep, $path, $rev, $peg = '') { global $vars, $config; $pathComponents = explode('/', htmlentities($path, ENT_QUOTES, 'UTF-8')); $count = count($pathComponents); // The number of links depends on the last item. It's empty if we're looking // at a directory, and non-empty if we're looking at a file. if (empty($pathComponents[$count - 1])) { $limit = $count - 2; $dir = true; } else { $limit = $count - 1; $dir = false; } $passRevString = createRevAndPegString($rev, $peg); $pathSoFar = '/'; $pathSoFarURL = $config->getURL($rep, $pathSoFar, 'dir') . $passRevString; $vars['pathlinks'] = '<a href="' . $pathSoFarURL . '" class="root"><span>(root)</span></a>/'; for ($n = 1; $n < $limit; $n++) { $pathSoFar .= html_entity_decode($pathComponents[$n]) . '/'; $pathSoFarURL = $config->getURL($rep, $pathSoFar, 'dir') . $passRevString; $vars['pathlinks'] .= '<a href="' . $pathSoFarURL . '#' . anchorForPath($pathSoFar) . '">' . $pathComponents[$n] . '</a>/'; } if (!empty($pathComponents[$n])) { $pegrev = $peg ? ' <a class="peg" href="' . '?' . htmlspecialchars(str_replace('&peg=' . $peg, '', $_SERVER['QUERY_STRING']), ENT_NOQUOTES) . '">@ ' . $peg . '</a>' : ''; if ($dir) { $vars['pathlinks'] .= '<span class="dir">' . $pathComponents[$n] . '/' . $pegrev . '</span>'; } else { $vars['pathlinks'] .= '<span class="file">' . $pathComponents[$n] . $pegrev . '</span>'; } } }
$ppath = $path; } $prevrev = @$history->entries[1]->rev; $vars['path'] = htmlentities($ppath, ENT_QUOTES, 'UTF-8'); $vars['rev1'] = $rev; $vars['rev2'] = $prevrev; $vars['prevrev'] = $prevrev; if ($history) { $vars['log'] = xml_entities($history->entries[0]->msg); $vars['date'] = $history->entries[0]->date; $vars['author'] = $history->entries[0]->author; $vars['rev'] = $vars['rev1'] = $history->entries[0]->rev; $vars['peg'] = $peg; } createPathLinks($rep, $ppath, $passrev, $peg); $passRevString = createRevAndPegString($passrev, $peg); if ($rev != $youngest) { $vars['goyoungesturl'] = $config->getURL($rep, $path, 'diff') . ($peg ? 'peg=' . $peg : ''); $vars['goyoungestlink'] = '<a href="' . $vars['goyoungesturl'] . '">' . $lang['GOYOUNGEST'] . '</a>'; } $vars['revurl'] = $config->getURL($rep, $path, 'revision') . $passRevString; $vars['revlink'] = '<a href="' . $vars['revurl'] . '">' . $lang['LASTMOD'] . '</a>'; $vars['logurl'] = $config->getURL($rep, $path, 'log') . $passRevString; $vars['loglink'] = '<a href="' . $vars['logurl'] . '">' . $lang['VIEWLOG'] . '</a>'; $vars['filedetailurl'] = $config->getURL($rep, $path, 'file') . $passRevString; $vars['filedetaillink'] = '<a href="' . $vars['filedetailurl'] . '">' . $lang['FILEDETAIL'] . '</a>'; $vars['blameurl'] = $config->getURL($rep, $path, 'blame') . $passRevString; $vars['blamelink'] = '<a href="' . $vars['blameurl'] . '">' . $lang['BLAME'] . '</a>'; if ($rep->isRssEnabled()) { $vars['rssurl'] = $config->getURL($rep, $path, 'rss') . ($peg ? 'peg=' . $peg : ''); $vars['rsslink'] = '<a href="' . $vars['rssurl'] . '">' . $lang['RSSFEED'] . '</a>';
$path2 = '/'; } } $rev1 = checkRevision($rev1); $rev2 = checkRevision($rev2); // Choose a sensible comparison order unless told not to if (!$manualorder && is_numeric($rev1) && is_numeric($rev2) && $rev1 > $rev2) { $temppath = $path1; $path1 = $path2; $path2 = $temppath; $temprev = $rev1; $rev1 = $rev2; $rev2 = $temprev; } $vars['rev1url'] = $config->getURL($rep, $path1, 'revision') . createRevAndPegString($rev1, $rev1); $vars['rev2url'] = $config->getURL($rep, $path2, 'revision') . createRevAndPegString($rev2, $rev2); $url = $config->getURL($rep, '/', 'comp'); $vars['reverselink'] = '<a href="' . $url . 'compare%5B%5D=' . urlencode($path2) . '@' . $rev2 . '&compare%5B%5D=' . urlencode($path1) . '@' . $rev1 . '&manualorder=1' . ($ignoreWhitespace ? '&ignorews=1' : '') . '">' . $lang['REVCOMP'] . '</a>'; if (!$ignoreWhitespace) { $vars['ignorewhitespacelink'] = '<a href="' . $url . 'compare%5B%5D=' . urlencode($path1) . '@' . $rev1 . '&compare%5B%5D=' . urlencode($path2) . '@' . $rev2 . ($manualorder ? '&manualorder=1' : '') . '&ignorews=1">' . $lang['IGNOREWHITESPACE'] . '</a>'; } else { $vars['regardwhitespacelink'] = '<a href="' . $url . 'compare%5B%5D=' . urlencode($path1) . '@' . $rev1 . '&compare%5B%5D=' . urlencode($path2) . '@' . $rev2 . ($manualorder ? '&manualorder=1' : '') . '">' . $lang['REGARDWHITESPACE'] . '</a>'; } if ($rev1 == 0) { $rev1 = 'HEAD'; } if ($rev2 == 0) { $rev2 = 'HEAD'; } $vars['repname'] = $rep->getDisplayName(); $vars['action'] = $lang['PATHCOMPARISON'];
$vars['filedetaillink'] = '<a href="' . $vars['filedetailurl'] . '">' . $lang['FILEDETAIL'] . '</a>'; $vars['blameurl'] = $config->getURL($rep, $path, 'blame') . $passRevString; $vars['blamelink'] = '<a href="' . $vars['blameurl'] . '">' . $lang['BLAME'] . '</a>'; } if ($rep->isRssEnabled()) { $vars['rssurl'] = $config->getURL($rep, $path, 'rss') . ($peg ? 'peg=' . $peg : ''); $vars['rsslink'] = '<a href="' . $vars['rssurl'] . '">' . $lang['RSSFEED'] . '</a>'; } $changes = $logEntry ? $logEntry->mods : array(); if (!is_array($changes)) { $changes = array(); } usort($changes, 'SVNLogEntry_compare'); $row = 0; $prevRevString = createRevAndPegString($rev - 1, $rev - 1); $thisRevString = createRevAndPegString($rev, $peg ? $peg : $rev); foreach ($changes as $file) { $linkRevString = $file->action == 'D' ? $prevRevString : $thisRevString; // NOTE: This is a hack (runs `svn info` on each path) to see if it's a file. // `svn log --verbose --xml` should really provide this info, but doesn't yet. $isFile = $svnrep->isFile($file->path, $rev); if (!$isFile && $file->path != '/') { $file->path .= '/'; } $listing[] = array('path' => $file->path, 'added' => $file->action == 'A', 'deleted' => $file->action == 'D', 'modified' => $file->action == 'M', 'detailurl' => $config->getURL($rep, $file->path, $isFile ? 'file' : 'dir') . $linkRevString, 'logurl' => $config->getURL($rep, $file->path, 'log') . $linkRevString . ($isFile ? '' : '&isdir=1'), 'diffurl' => $isFile && $file->action == 'M' ? $config->getURL($rep, $file->path, 'diff') . $linkRevString : '', 'blameurl' => $isFile && $file->action == 'M' ? $config->getURL($rep, $file->path, 'blame') . $linkRevString : '', 'rowparity' => $row); $row = 1 - $row; } if (isset($prevRev)) { $vars['compareurl'] = $config->getURL($rep, '/', 'comp') . 'compare[]=' . urlencode($prevPath) . '@' . $prevRev . '&compare[]=' . urlencode($path) . '@' . $rev; $vars['comparelink'] = '<a href="' . $vars['compareurl'] . '">' . $lang['DIFFPREV'] . '</a>'; }
// If a recent-enough cached version exists, use it and avoid the work below if (file_exists($cache) && filemtime($cache) >= $history->curEntry->committime) { readfile($cache); exit; } } // Generate RSS 2.0 feed $rss = '<?xml version="1.0" encoding="utf-8"?>'; $rss .= '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel>'; $rss .= '<title>' . htmlspecialchars($rep->getDisplayName() . ($path ? ' - ' . $path : '')) . '</title>'; $rss .= '<description>' . htmlspecialchars($lang['RSSFEEDTITLE'] . ' - ' . $repname) . '</description>'; $rss .= '<lastBuildDate>' . date('r') . '</lastBuildDate>'; // RFC 2822 date format $rss .= '<generator>WebSVN ' . $vars['version'] . '</generator>'; // URL for matching WebSVN log page $rss .= '<link>' . getFullURL($baseurl . $config->getURL($rep, $path, 'log') . (@$_REQUEST['isdir'] == 1 ? 'isdir=1&' : '') . 'max=' . $max . '&' . createRevAndPegString($passrev, $peg)) . '</link>'; // URL where this original RSS feed can be found $rss .= '<atom:link href="' . htmlspecialchars(getFullURL($_SERVER['REQUEST_URI'])) . '" rel="self" type="application/rss+xml" />' . "\n"; if ($history && is_array($history->entries)) { foreach ($history->entries as $r) { $wordLimit = 10; // Display only up to the first 10 words of the log message $title = trim($r->msg); $words = explode(' ', $title, $wordLimit + 1); if (count($words) > $wordLimit) { $title = implode(' ', array_slice($words, 0, $wordLimit)) . ' ...'; } $title = $lang['REV'] . ' ' . $r->rev . ' -- ' . $title; $description = '<div><strong>' . $r->author . ' -- ' . count($r->mods) . ' ' . $lang['FILESMODIFIED'] . '</strong><br/>' . nl2br(create_anchors(str_replace('<', '<', $r->msg))) . '</div>'; if (!$quiet) { usort($r->mods, 'SVNLogEntry_compare');
if ($isDir) { $hidden .= '<input type="hidden" name="isdir" value="' . $isDir . '" />'; } $hidden .= '<input type="hidden" name="peg" value="' . $peg . '" />'; $hidden .= '<input type="hidden" name="logsearch" value="1" />'; $vars['logsearch_form'] = '<form action="' . $url . '" method="get">' . $hidden; $vars['logsearch_startbox'] = '<input name="sr" size="5" value="' . $startrev . '" />'; $vars['logsearch_endbox'] = '<input name="er" size="5" value="' . $endrev . '" />'; $vars['logsearch_maxbox'] = '<input name="max" size="5" value="' . ($max == 0 ? '' : $max) . '" />'; $vars['logsearch_inputbox'] = '<input name="search" value="' . htmlentities($search, ENT_QUOTES, 'UTF-8') . '" />'; $vars['logsearch_showall'] = '<input type="checkbox" name="all" value="1"' . ($all ? ' checked="checked"' : '') . ' />'; $vars['logsearch_submit'] = '<input type="submit" value="' . $lang['GO'] . '" />'; $vars['logsearch_endform'] = '</form>'; // If a filter is in place, produce a link to clear all filter parameters if ($page !== 1 || $all || $dosearch || $fromRev || $startrev !== $rev || $endrev !== 1 || $max !== 40) { $url = $config->getURL($rep, $path, 'log') . $isDirString . createRevAndPegString($rev, $peg); $vars['logsearch_clearloglink'] = '<a href="' . $url . '">' . $lang['CLEARLOG'] . '</a>'; } // Create form elements for comparing selected revisions $url = $config->getURL($rep, '/', 'comp'); $hidden = $config->multiViews ? '<input type="hidden" name="op" value="log" />' : ''; $vars['compare_form'] = '<form action="' . $url . '" method="post">' . $hidden; $vars['compare_submit'] = '<input type="submit" value="' . $lang['COMPAREREVS'] . '" />'; $vars['compare_endform'] = '</form>'; $vars['showageinsteadofdate'] = $config->showAgeInsteadOfDate; if (!$rep->hasReadAccess($path, false)) { $vars['error'] = $lang['NOACCESS']; } } $vars['template'] = 'log'; $template = $rep ? $rep->getTemplatePath() : $config->getTemplatePath();