[dev] Patch for svn chora
Jason Rust
jrust at rustyparts.com
Tue Nov 4 16:38:10 PST 2003
Attached is a patch that implements a lot of missing features (or things
that were broken) for svn repositories using chora. Details of the
patch are:
* Implements the annotate feature for svn
* Implements the patchset feature for svn. Since patchsets are native
to svn this feature is always enabled for svn repositories. In
addition, diffing all files of a patchset is also native to svn, so a
link shows up in svn repositories to show all diffs.
* Hides the branch history link for svn repositories since you can't
determine branches from the log history.
* cvsgraph doesn't support svn so that link is not shown in svn
repositories.
* Fixed a small typo in VC.php that was killing several pages
-Jason
--
http://www.rustyparts.com/
guaranteed never to rust!
-------------- next part --------------
? chora_svn.patch
Index: chora/cvsgraph.php
===================================================================
RCS file: /repository/chora/cvsgraph.php,v
retrieving revision 1.7
diff -u -r1.7 cvsgraph.php
--- chora/cvsgraph.php 16 Sep 2003 23:04:03 -0000 1.7
+++ chora/cvsgraph.php 5 Nov 2003 00:15:45 -0000
@@ -14,8 +14,8 @@
@define('CHORA_BASE', dirname(__FILE__));
require_once CHORA_BASE . '/lib/base.php';
-// Exit if cvsgraph isn't active.
-if (empty($conf['paths']['cvsgraph'])) {
+// Exit if cvsgraph isn't active or it's not supported.
+if (empty($conf['paths']['cvsgraph']) || is_a($VC, 'VC_svn')) {
header('Location: ' . Chora::url('cvs', $where));
exit;
}
Index: chora/history.php
===================================================================
RCS file: /repository/chora/history.php,v
retrieving revision 1.45
diff -u -r1.45 history.php
--- chora/history.php 14 Oct 2003 19:01:50 -0000 1.45
+++ chora/history.php 5 Nov 2003 00:15:45 -0000
@@ -11,6 +11,12 @@
define('CHORA_BASE', dirname(__FILE__));
require_once CHORA_BASE . '/lib/base.php';
+// Exit if it's not supported.
+if (is_a($VC, 'VC_svn')) {
+ header('Location: ' . Chora::url('cvs', $where));
+ exit;
+}
+
/* Spawn the file object */
$fl = &$VC->getFileObject($where);
Index: chora/patchsets.php
===================================================================
RCS file: /repository/chora/patchsets.php,v
retrieving revision 1.8
diff -u -r1.8 patchsets.php
--- chora/patchsets.php 14 Oct 2003 19:01:51 -0000 1.8
+++ chora/patchsets.php 5 Nov 2003 00:15:46 -0000
@@ -12,8 +12,8 @@
@define('CHORA_BASE', dirname(__FILE__));
require_once CHORA_BASE . '/lib/base.php';
-// Exit if cvsps isn't active.
-if (empty($conf['paths']['cvsps'])) {
+// Exit if cvsps isn't active or it's not a subversion repository.
+if (empty($conf['paths']['cvsps']) && !is_a($VC, 'VC_svn')) {
header('Location: ' . Chora::url('cvs', $where));
exit;
}
@@ -35,12 +35,20 @@
$commitDate = strftime('%c', $patchset['date']);
$readableDate = VC_File::readableTime($patchset['date'], true);
$author = Chora::showAuthorName($patchset['author'], true);
+ if (is_a($VC, 'VC_svn')) {
+ // Subversion supports patchset diffs natively
+ $allDiffsLink = Horde::link(Chora::url('diff', dirname($where), array('r1' => $id - 1, 'r2' => $id, 'ty' => 'u')), _("Diff All Files")) . _("Diff All Files") . '</a>';
+ }
+ else {
+ // Not supported in any other VC systems yet
+ $allDiffsLink = '';
+ }
$files = array();
$dir = dirname($where);
foreach ($patchset['members'] as $member) {
$file = array();
- $mywhere = $dir . DIRECTORY_SEPARATOR . $member['file'];
+ $mywhere = is_a($VC, 'VC_svn') ? $member['file'] : $dir . DIRECTORY_SEPARATOR . $member['file'];
$file['file'] = Horde::link(Chora::url('patchsets', $mywhere), $member['file']) . $member['file'] . '</a>';
if ($member['from'] == 'INITIAL') {
$file['from'] = '<i>' . _("New File") . '</i>';
Index: chora/lib/Chora.php
===================================================================
RCS file: /repository/chora/lib/Chora.php,v
retrieving revision 1.51
diff -u -r1.51 Chora.php
--- chora/lib/Chora.php 14 Oct 2003 19:02:00 -0000 1.51
+++ chora/lib/Chora.php 5 Nov 2003 00:15:47 -0000
@@ -397,11 +397,14 @@
$current = str_replace('.php', '', basename($current));
$views[] = $current == 'cvs' ? '<i>' . _("Logs") . '</i>' : Horde::link(Chora::url('cvs', $where), _("Logs")) . _("Logs") . '</a>';
- if (!empty($GLOBALS['conf']['paths']['cvsps'])) {
+ // Subversion supports patchsets natively
+ if (!empty($GLOBALS['conf']['paths']['cvsps']) || is_a($GLOBALS['VC'], 'VC_svn')) {
$views[] = $current == 'patchsets' ? '<i>' . _("Patchsets") . '</i>' : Horde::link(Chora::url('patchsets', $where), _("Patchsets")) . _("Patchsets") . '</a>';
}
- $views[] = $current == 'history' ? '<i>' . _("Branches") . '</i>' : Horde::link(Chora::url('history', $where), _("Branches")) . _("Branches") . '</a>';
- if (!empty($GLOBALS['conf']['paths']['cvsgraph'])) {
+ if (!is_a($GLOBALS['VC'], 'VC_svn')) {
+ $views[] = $current == 'history' ? '<i>' . _("Branches") . '</i>' : Horde::link(Chora::url('history', $where), _("Branches")) . _("Branches") . '</a>';
+ }
+ if (!empty($GLOBALS['conf']['paths']['cvsgraph']) && !is_a($GLOBALS['VC'], 'VC_svn')) {
$views[] = $current == 'cvsgraph' ? '<i>' . _("Graph") . '</i>' : Horde::link(Chora::url('cvsgraph', $where), _("Graph")) . _("Graph") . '</a>';
}
$views[] = $current == 'stats' ? '<i>' . _("Statistics") . '</i>' : Horde::link(Chora::url('stats', $where), _("Statistics")) . _("Statistics") . '</a>';
Index: chora/templates/patchsets/ps.inc
===================================================================
RCS file: /repository/chora/templates/patchsets/ps.inc,v
retrieving revision 1.2
diff -u -r1.2 ps.inc
--- chora/templates/patchsets/ps.inc 24 Aug 2003 14:54:56 -0000 1.2
+++ chora/templates/patchsets/ps.inc 5 Nov 2003 00:15:48 -0000
@@ -4,7 +4,7 @@
<table width="100%" cellspacing="0" cellpadding="4" class="diff-back">
<tr class="item"><td align="left"><span class="title"><?php printf(_("PatchSet %s</span> by %s"), $id, $author) ?></td><td align="right">
-<?php // echo _("Diff All Files") ?></a>
+<?php echo $allDiffsLink; ?></a>
</td></tr>
<tr valign="top" class="diff-back">
Index: framework/VC/VC.php
===================================================================
RCS file: /repository/framework/VC/VC.php,v
retrieving revision 1.2
diff -u -r1.2 VC.php
--- framework/VC/VC.php 30 Oct 2003 23:38:17 -0000 1.2
+++ framework/VC/VC.php 5 Nov 2003 00:15:48 -0000
@@ -282,7 +282,7 @@
*/
function sizeof($val)
{
- if (!VC_Revison::valid($val)) {
+ if (!VC_Revision::valid($val)) {
return false;
}
Index: framework/VC/VC/svn.php
===================================================================
RCS file: /repository/framework/VC/VC/svn.php,v
retrieving revision 1.3
diff -u -r1.3 svn.php
--- framework/VC/VC/svn.php 30 Oct 2003 23:38:18 -0000 1.3
+++ framework/VC/VC/svn.php 5 Nov 2003 00:15:49 -0000
@@ -121,6 +121,34 @@
function doAnnotate($rev)
{
+ /* Make sure that the file values for this object is valid */
+ if (is_a($this->file, 'PEAR_Error')) {
+ return false;
+ }
+
+ if (!VC_Revision::valid($rev)) {
+ return false;
+ }
+
+ $pipe = popen($GLOBALS['conf']['paths']['svn'] . ' annotate -r 1:' . $rev . ' ' . $this->file->queryFullPath() . ' 2>&1', 'r');
+
+ $lines = array();
+ $lineno = 1;
+ while (!feof($pipe)) {
+ $line = fgets($pipe, 4096);
+ if (preg_match('/^\s+(\d+)\s+(\w+)\s(.*)$/', $line, $regs)) {
+ $entry = array();
+ $entry['rev'] = $regs[1];
+ $entry['author'] = $regs[2];
+ $entry['date'] = _("Not Implemented");
+ $entry['line'] = $regs[3];
+ $entry['lineno'] = $lineno++;
+ $lines[] = $entry;
+ }
+ }
+
+ pclose($pipe);
+ return $lines;
}
}
@@ -459,6 +487,8 @@
$this->logs = array();
$this->quicklog = $quicklog;
$this->revs = array();
+ $this->revsym = array();
+ $this->symrev = array();
$this->branches = array();
}
@@ -504,7 +534,8 @@
*/
function isAtticFile()
{
- return substr($this->dir, -5) == 'Attic';
+ // Not implemented yet
+ return false;
}
/**
@@ -630,14 +661,9 @@
function getBrowseInfo()
{
/* XXX: $flag = ($this->quicklog ? '-r HEAD ' : ''; */
- $Q = OS_WINDOWS ? '"' : "'";
-
- $cmd = $GLOBALS['conf']['paths']['svn'] . ' log ' . $flag . $this->queryFullPath() . ' 2>&1';
-
+ $cmd = $GLOBALS['conf']['paths']['svn'] . ' log -v ' . $flag . $this->queryFullPath() . ' 2>&1';
$pipe = popen($cmd, 'r');
-
fgets($pipe);
-
while (!feof($pipe)) {
$log = &new SVNLib_Log($this->rep, $this);
$err = $log->processLog($pipe);
@@ -653,7 +679,6 @@
}
pclose($pipe);
-
return true;
}
@@ -690,7 +715,7 @@
*/
class SVNLib_Log {
- var $rep, $file, $tags, $rev, $date, $log, $author, $state, $lines, $branches;
+ var $rep, $file, $files, $tags, $rev, $date, $log, $author, $state, $lines, $branches;
/**
*
@@ -711,15 +736,18 @@
}
preg_match('/^rev ([0-9]*): ([^ ]*) \| (.*) \(.*\) \| ([0-9]*) lines?$/', $line, $matches);
-
$this->rev = $matches[1];
$this->author = $matches[2];
$this->date = strtotime($matches[3]);
-
$size = $matches[4];
fgets($pipe);
+ $this->files = array();
+ while (($line = trim(fgets($pipe))) != '') {
+ $this->files[] = $line;
+ }
+
for ($i = 0; $i != $size; ++$i) {
$this->log = $this->log . chop(fgets($pipe)) . "\n";
}
@@ -848,75 +876,36 @@
*/
function getPatchsets($repository)
{
- /* Call cvsps to retrieve all patchsets for this file. */
- $Q = OS_WINDOWS ? '"' : "'" ;
- $cmd = $GLOBALS['conf']['paths']['svn'] . ' -u --cvs-direct --root ' . $Q . $repository . $Q . ' -f ' . $Q . $this->_name . $Q . ' ' . $Q . $this->_dir . $Q;
- exec($cmd, $return_array, $retval);
- if ($retval) {
- return PEAR::raiseError(_("Failed to spawn cvsps to retrieve patchset information"));
- }
+ $fileOb = &new SVNLib_File($this->_file);
+ Chora::checkError($fileOb->getBrowseInfo());
$this->_patchsets = array();
- $state = 'begin';
- foreach ($return_array as $line) {
- $line = trim($line);
- if ($line == '---------------------') {
- $state = 'begin';
- continue;
- }
-
- switch ($state) {
- case 'begin':
- $id = str_replace('PatchSet ', '', $line);
- $this->_patchsets[$id] = array();
- $state = 'info';
- break;
-
- case 'info':
- $info = explode(':', $line, 2);
- switch ($info[0]) {
- case 'Date':
- $this->_patchsets[$id]['date'] = trim($info[1]);
- break;
-
- case 'Author':
- $this->_patchsets[$id]['author'] = trim($info[1]);
- break;
-
- case 'Branch':
- $this->_patchsets[$id]['branch'] = trim($info[1]);
- break;
-
- case 'Tag':
- $this->_patchsets[$id]['tag'] = trim($info[1]);
- break;
-
- case 'Log':
- $state = 'log';
- $this->_patchsets[$id]['log'] = '';
- break;
- }
- break;
-
- case 'log':
- if ($line == 'Members:') {
- $state = 'members';
- $this->_patchsets[$id]['log'] = trim($this->_patchsets[$id]['log']);
- $this->_patchsets[$id]['members'] = array();
+ foreach ($fileOb->logs as $rev => $log) {
+ $this->_patchsets[$rev] = array();
+ $this->_patchsets[$rev]['date'] = $log->queryDate();
+ $this->_patchsets[$rev]['author'] = $log->queryAuthor();
+ $this->_patchsets[$rev]['branch'] = '';
+ $this->_patchsets[$rev]['tag'] = '';
+ $this->_patchsets[$rev]['log'] = $log->queryLog();
+ $this->_patchsets[$rev]['members'] = array();
+ foreach ($log->files as $file) {
+ $action = substr($file, 0, 1);
+ $file = preg_replace('/.*?\s(.*?)(\s|$).*/', '\\1', $file);
+ $to = $rev;
+ if ($action == 'A') {
+ $from = 'INITIAL';
+ } elseif ($action == 'D') {
+ $from = $to;
+ $to = '(DEAD)';
} else {
- $this->_patchsets[$id]['log'] .= $line . "\n";
+ // This technically isn't the previous revision,
+ // but it works for diffing purposes
+ $from = $to - 1;
}
- break;
- case 'members':
- if (!empty($line)) {
- $parts = explode(':', $line);
- $revs = explode('->', $parts[1]);
- $this->_patchsets[$id]['members'][] = array('file' => $parts[0],
- 'from' => $revs[0],
- 'to' => $revs[1]);
- }
- break;
+ $this->_patchsets[$rev]['members'][] = array('file' => $file,
+ 'from' => $from,
+ 'to' => $to);
}
}
More information about the dev
mailing list