Add diffstat information.
authorMichael M Slusarz <slusarz@curecanti.org>
Wed, 17 Jun 2009 05:57:44 +0000 (23:57 -0600)
committerMichael M Slusarz <slusarz@curecanti.org>
Wed, 17 Jun 2009 06:48:42 +0000 (00:48 -0600)
Diffstat info added to single patchset, diff, and browsefile screens.
Currently, only git supports.  CVS uses a different way to generate this
info (see queryChangedLines()), but should eventually be changed to the
same mechanism - this diff information should not live directly in the
log object, but rather in the file objects inside of the master log
object.

chora/browsefile.php
chora/diff.php
chora/patchsets.php
chora/templates/diff/hr/header.inc
chora/templates/log/rev.inc
chora/templates/patchsets/ps_single.inc
chora/themes/screen.css
framework/Vcs/lib/Horde/Vcs.php
framework/Vcs/lib/Horde/Vcs/Git.php

index 0c1854f..dd35aa1 100644 (file)
@@ -61,6 +61,16 @@ while (list(,$lg) = each($logs)) {
     $rev = $lg->queryRevision();
     $branch_info = $lg->queryBranch();
 
+    $added = $deleted = null;
+    $fileinfo = $lg->queryFiles($where);
+    if ($fileinfo && isset($fileinfo['added'])) {
+        $added = $fileinfo['added'];
+        $deleted = $fileinfo['deleted'];
+    }
+
+    // TODO: Remove in favor of getting info from queryFiles()
+    $changedlines = $lg->queryChangedLines();
+
     $textUrl = Chora::url('co', $where, array('r' => $rev));
     $commitDate = Chora::formatDate($lg->queryDate());
     $readableDate = Chora::readableTime($lg->queryDate(), true);
index 12fb38a..8f02517 100644 (file)
@@ -61,14 +61,19 @@ $log_messages = array();
 foreach ($VC->getRevisionRange($fl, $r1, $r2) as $val) {
     $clog = $fl->queryLogs($val);
     if (!is_null($clog)) {
-        $log_messages[] = array(
+        $fileinfo = $clog->queryFiles($where);
+        $stats = ($fileinfo && isset($fileinfo['added']))
+            ? array('added' => $fileinfo['added'], 'deleted' => $fileinfo['deleted'])
+            : array();
+
+        $log_messages[] = array_merge(array(
             'rev' => $val,
             'msg' => Chora::formatLogMessage($clog->queryLog()),
             'author' => Chora::showAuthorName($clog->queryAuthor(), true),
             'branchinfo' => $clog->queryBranch(),
             'date' => Chora::formatDate($clog->queryDate()),
             'tags' => Chora::getTags($clog, $where),
-        );
+        ), $stats);
     }
 }
 
index c454ebf..17dcde2 100644 (file)
@@ -89,6 +89,11 @@ while (list($id, $patchset) = each($patchsets)) {
             $file['to'] = Horde::link(Chora::url('co', $member['file'], array('r' => $member['to'])), $member['to']) . htmlspecialchars($VC->abbrev($member['to'])) . '</a>';
         }
 
+        if (isset($member['added'])) {
+            $file['added'] = $member['added'];
+            $file['deleted'] = $member['deleted'];
+        }
+
         $files[] = $file;
     }
 
index 244cbe0..ed51a37 100644 (file)
@@ -50,6 +50,7 @@
    </li>
 <?php endif; ?>
    <?php if (!empty($val['tags'])): ?><li class="tags"><?php echo _("Tags:") ?> <?php echo implode(', ', $val['tags']) ?></li><?php endif; ?>
+   <?php if (isset($val['added'])): ?><li><?php echo _("Statistics:") ?> <span class="diffadd">+<?php echo htmlspecialchars($val['added']) ?></span> <?php echo _("lines") ?>, <span class="diffdel">-<?php echo htmlspecialchars($val['deleted']) ?></span> <?php echo _("lines") ?></li><?php endif; ?>
   </ul>
   <a href="<?php echo Chora::url('co', $where, array('r' => $val['rev'])) ?>" title="<?php echo htmlspecialchars($val['rev']) ?>"><?php echo htmlspecialchars($VC->abbrev($val['rev'])) ?></a>: <?php echo $val['msg'] ?>
   <div class="diffclear"></div>
index cdf066d..7019491 100644 (file)
@@ -9,8 +9,11 @@
 <?php foreach (array_diff($branch_info, array($onb)) as $val): ?>
   <span class="branch"><?php echo Horde::link(Chora::url('browsefile', $where, array('onb' => $val))) . htmlspecialchars($val) ?></a></span>
 <?php endforeach; ?>
-<?php if (!empty($lg->lines)): ?>
-  <small>(<?php printf('%s lines', $lg->lines) ?>)</small>
+<?php if (!empty($changedlines)): ?>
+  <small>(<?php printf('%s lines', htmlspecialchars($changedlines)) ?>)</small>
+<?php endif; ?>
+<?php if (!is_null($added)): ?>
+    <small>(<span class="diffadd">+<?php echo $added ?></span>, <span class="diffdel">-<?php echo $deleted ?></span> <?php echo _("lines") ?>)</small>
 <?php endif; ?>
 </td>
  <td class="ago" sortval="<?php echo (int)$lg->queryDate() ?>"><a title="<?php echo $readableDate ?>"><?php echo $commitDate ?></a></td>
index c8eacbe..4f0cab2 100644 (file)
@@ -25,6 +25,6 @@
 
 <ul class="singlepsfiles">
 <?php foreach ($files as $file): ?>
- <li><?php echo $file['file'] . ': ' . $file['from'] . ' -> ' . $file['to'] . ' ' . $file['diff'] ?></li>
+ <li><?php echo $file['file'] . (isset($file['added']) ? (' (<span class="diffadd">+' . $file['added'] . '</span>, <span class="diffdel">-' . $file['deleted'] . '</span>) ') : '') . ': ' . $file['from'] . ' -> ' . $file['to'] . ' ' . $file['diff'] ?></li>
 <?php endforeach; ?>
 </ul>
index b060a32..f2248d3 100644 (file)
@@ -170,6 +170,14 @@ ul.singlepsfiles li {
     padding-bottom: 4px;
 }
 
+/* Diff stat information. */
+.diffadd {
+    color: blue;
+}
+.diffdel {
+    color: red;
+}
+
 /* Checkout. */
 div.checkout {
     padding: 3px;
index 343b05c..ab50b38 100644 (file)
@@ -1029,7 +1029,9 @@ abstract class Horde_Vcs_File
      */
     public function queryLogs($rev = null)
     {
-        return is_null($rev) ? $this->_logs : (isset($this->_logs[$rev]) ? $this->_logs[$rev] : null);
+        return is_null($rev)
+            ? $this->_logs
+            : (isset($this->_logs[$rev]) ? $this->_logs[$rev] : null);
     }
 
     /**
@@ -1059,6 +1061,7 @@ abstract class Horde_Vcs_Log
 {
     protected $_rep;
     protected $_file;
+    protected $_files;
     protected $_rev;
     protected $_author;
     protected $_tags = array();
@@ -1163,6 +1166,16 @@ abstract class Horde_Vcs_Log
         return $symBranches;
     }
 
+    /**
+     * TODO
+     */
+    public function queryFiles($file = null)
+    {
+        return is_null($file)
+            ? $this->_files
+            : (isset($this->_files[$file]) ? $this->_files[$file] : null);
+    }
+
 }
 
 /**
index d288f55..ca3de1f 100644 (file)
@@ -625,11 +625,6 @@ class Horde_Vcs_Log_Git extends Horde_Vcs_Log
     protected $_parent = null;
 
     /**
-     * @var array
-     */
-    protected $_files = array();
-
-    /**
      * Constructor.
      *
      * @throws Horde_Vcs_Exception
@@ -638,8 +633,21 @@ class Horde_Vcs_Log_Git extends Horde_Vcs_Log
     {
         parent::__construct($rep, $fl, $rev);
 
+        /* Get diff statistics. */
+        $stats = array();
+        $cmd = $rep->getCommand() . ' diff-tree --numstat ' . escapeshellarg($rev);
+        exec($cmd, $output);
+
+        reset($output);
+        // Skip the first entry (it is the revision number)
+        next($output);
+        while (list(,$v) = each($output)) {
+            $tmp = explode("\t", $v);
+            $stats[$tmp[2]] = array_slice($tmp, 0, 2);
+        }
+
         // @TODO use Commit, CommitDate, and Merge properties
-        $cmd = $rep->getCommand() . ' whatchanged --no-color --pretty=format:"Rev:%H%nParents:%P%nAuthor:%an <%ae>%nAuthorDate:%at%nRefs:%d%n%n%s%n%b" --no-abbrev -n 1 ' . $rev;
+        $cmd = $rep->getCommand() . ' whatchanged --no-color --pretty=format:"Rev:%H%nParents:%P%nAuthor:%an <%ae>%nAuthorDate:%at%nRefs:%d%n%n%s%n%b" --no-abbrev -n 1 ' . escapeshellarg($rev);
         $pipe = popen($cmd, 'r');
         if (!is_resource($pipe)) {
             throw new Horde_Vcs_Exception('Unable to run ' . $cmd . ': ' . error_get_last());
@@ -713,7 +721,12 @@ class Horde_Vcs_Log_Git extends Horde_Vcs_Log
         // http://www.kernel.org/pub/software/scm/git/docs/git-diff-tree.html
         while ($line) {
             preg_match('/:(\d+) (\d+) (\w+) (\w+) (.+)\t(.+)(\t(.+))?/', $line, $matches);
-            $this->_files[$matches[6]] = array(
+
+            $statinfo = isset($stats[$matches[6]])
+                ? array('added' => $stats[$matches[6]][0], 'deleted' => $stats[$matches[6]][1])
+                : array();
+
+            $this->_files[$matches[6]] = array_merge(array(
                 'srcMode' => $matches[1],
                 'dstMode' => $matches[2],
                 'srcSha1' => $matches[3],
@@ -721,7 +734,7 @@ class Horde_Vcs_Log_Git extends Horde_Vcs_Log
                 'status' => $matches[5],
                 'srcPath' => $matches[6],
                 'dstPath' => isset($matches[7]) ? $matches[7] : ''
-            );
+            ), $statinfo);
 
             $line = fgets($pipe);
         }
@@ -748,14 +761,6 @@ class Horde_Vcs_Log_Git extends Horde_Vcs_Log
     /**
      * TODO
      */
-    public function queryFiles()
-    {
-        return $this->_files;
-    }
-
-    /**
-     * TODO
-     */
     public function queryParent()
     {
         return $this->_parent;
@@ -831,12 +836,16 @@ class Horde_Vcs_Patchset_Git extends Horde_Vcs_Patchset
                     $from = $log->queryParent();
                 }
 
-                $this->_patchsets[$rev]['members'][] = array(
+                $statinfo = isset($file['added'])
+                    ? array('added' => $file['added'], 'deleted' => $file['deleted'])
+                    : array();
+
+                $this->_patchsets[$rev]['members'][] = array_merge(array(
                     'file' => $file['srcPath'],
                     'from' => $from,
                     'status' => $status,
                     'to' => $to,
-                );
+                ), $statinfo);
             }
         }
     }