[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