diff --git a/src/IDF/Scm.php b/src/IDF/Scm.php
index 60f010a..f474cd5 100644
--- a/src/IDF/Scm.php
+++ b/src/IDF/Scm.php
@@ -316,6 +316,34 @@ class IDF_Scm
throw new Pluf_Exception_NotImplemented();
}
+ /**
+ * Returns all recorded changes which lead to the particular commit
+ * or revision.
+ *
+ * Example output:
+ *
+ * stdClass object {
+ * 'additions' => array('path/to/file', 'path/to/directory', ...),
+ * 'deletions' => array('path/to/file', 'path/to/directory', ...),
+ * 'renames' => array('old/path/to/file' => 'new/path/to/file', ...)
+ * 'patches' => array('path/to/file', ...),
+ * 'properties' => array('path/to/file' => array(
+ * 'propname' => 'propvalue', 'deletedprop' => null, ...)
+ * ),
+ * ...)
+ * }
+ *
+ * Each member of the returned object is mandatory, but may contain
+ * an empty array if no changes were recorded.
+ *
+ * @param string A commit identifier
+ * @return object with arrays of individual changes
+ */
+ public function getChanges($commit)
+ {
+ throw new Pluf_Exception_NotImplemented();
+ }
+
/**
* Get latest changes.
*
diff --git a/src/IDF/Scm/Git.php b/src/IDF/Scm/Git.php
index 50edc78..ca05429 100644
--- a/src/IDF/Scm/Git.php
+++ b/src/IDF/Scm/Git.php
@@ -431,10 +431,10 @@ class IDF_Scm_Git extends IDF_Scm
}
}
$out = self::parseLog($log);
- $out[0]->changes = implode("\n", $change);
+ $out[0]->diff = implode("\n", $change);
} else {
$out = self::parseLog($out);
- $out[0]->changes = '';
+ $out[0]->diff = '';
}
$out[0]->branch = implode(', ', $this->inBranches($commit, null));
diff --git a/src/IDF/Scm/Mercurial.php b/src/IDF/Scm/Mercurial.php
index ad2f383..b52e9f9 100644
--- a/src/IDF/Scm/Mercurial.php
+++ b/src/IDF/Scm/Mercurial.php
@@ -359,7 +359,7 @@ class IDF_Scm_Mercurial extends IDF_Scm
}
}
$out = self::parseLog($log, 6);
- $out[0]->changes = implode("\n", $change);
+ $out[0]->diff = implode("\n", $change);
return $out[0];
}
diff --git a/src/IDF/Scm/Monotone.php b/src/IDF/Scm/Monotone.php
index 3afbd78..fb39d5b 100644
--- a/src/IDF/Scm/Monotone.php
+++ b/src/IDF/Scm/Monotone.php
@@ -599,6 +599,75 @@ class IDF_Scm_Monotone extends IDF_Scm
);
}
+ /**
+ * @see IDF_Scm::getChanges()
+ */
+ public function getChanges($commit)
+ {
+ $revs = $this->_resolveSelector($commit);
+ if (count($revs) == 0)
+ return null;
+
+ $revision = $revs[0];
+ $out = $this->stdio->exec(array('get_revision', $revision));
+ $stanzas = IDF_Scm_Monotone_BasicIO::parse($out);
+
+ $return = (object) array(
+ 'additions' => array(),
+ 'deletions' => array(),
+ 'renames' => array(),
+ 'patches' => array(),
+ 'properties' => array(),
+ );
+
+ foreach ($stanzas as $stanza) {
+ if ($stanza[0]['key'] == 'format_version' ||
+ $stanza[0]['key'] == 'old_revision' ||
+ $stanza[0]['key'] == 'new_manifest')
+ continue;
+
+ if ($stanza[0]['key'] == 'add_file' ||
+ $stanza[0]['key'] == 'add_dir') {
+ $return->additions[] = $stanza[0]['values'][0];
+ continue;
+ }
+
+ if ($stanza[0]['key'] == 'delete') {
+ $return->deletions[] = $stanza[0]['values'][0];
+ continue;
+ }
+
+ if ($stanza[0]['key'] == 'rename') {
+ $return->renames[$stanza[0]['values'][0]] =
+ $stanza[1]['values'][0];
+ continue;
+ }
+
+ if ($stanza[0]['key'] == 'patch') {
+ $return->patches[] = $stanza[0]['values'][0];
+ continue;
+ }
+
+ if ($stanza[0]['key'] == 'clear' ||
+ $stanza[0]['key'] == 'set') {
+
+ $filename = $stanza[0]['values'][0];
+ if (!array_key_exists($filename, $return->properties)) {
+ $return->properties[$filename] = array();
+ }
+ $key = $stanza[1]['values'][0];
+ $value = null;
+ if (isset($stanza[2])) {
+ $value = $stanza[2]['values'][0];
+ }
+ $return->properties[$filename][$key] = $value;
+ continue;
+ }
+ }
+
+ return $return;
+ }
+
/**
* @see IDF_Scm::getCommit()
*/
@@ -626,7 +695,7 @@ class IDF_Scm_Monotone extends IDF_Scm
$res['branch'] = implode(', ', $certs['branch']);
$res['commit'] = $revs[0];
- $res['changes'] = ($getdiff) ? $this->_getDiff($revs[0]) : '';
+ $res['diff'] = ($getdiff) ? $this->_getDiff($revs[0]) : '';
return (object) $res;
}
diff --git a/src/IDF/Scm/Svn.php b/src/IDF/Scm/Svn.php
index b0963a1..0144738 100644
--- a/src/IDF/Scm/Svn.php
+++ b/src/IDF/Scm/Svn.php
@@ -414,7 +414,7 @@ class IDF_Scm_Svn extends IDF_Scm
$res['date'] = gmdate('Y-m-d H:i:s', strtotime((string) $xml->logentry->date));
$res['title'] = (string) $xml->logentry->msg;
$res['commit'] = (string) $xml->logentry['revision'];
- $res['changes'] = ($getdiff) ? $this->getDiff($commit) : '';
+ $res['diff'] = ($getdiff) ? $this->getDiff($commit) : '';
$res['tree'] = '';
$res['branch'] = '';
return (object) $res;
diff --git a/src/IDF/Views/Source.php b/src/IDF/Views/Source.php
index ee2d680..6652d66 100644
--- a/src/IDF/Views/Source.php
+++ b/src/IDF/Views/Source.php
@@ -297,8 +297,9 @@ class IDF_Views_Source
$title = sprintf(__('%s Commit Details'), (string) $request->project);
$page_title = sprintf(__('%s Commit Details - %s'), (string) $request->project, $commit);
$rcommit = IDF_Commit::getOrAdd($cobject, $request->project);
- $diff = new IDF_Diff($cobject->changes);
+ $diff = new IDF_Diff($cobject->diff);
$diff->parse();
+ $changes = $scm->getChanges($commit);
$scmConf = $request->conf->getVal('scm', 'git');
$branches = $scm->getBranches();
$in_branches = $scm->inBranches($cobject->commit, '');
@@ -311,6 +312,7 @@ class IDF_Views_Source
'diff' => $diff,
'cobject' => $cobject,
'commit' => $commit,
+ 'changes' => $changes,
'branches' => $branches,
'tree_in' => $in_branches,
'tags' => $tags,
diff --git a/src/IDF/templates/idf/source/commit.html b/src/IDF/templates/idf/source/commit.html
index c04ab80..e918fee 100644
--- a/src/IDF/templates/idf/source/commit.html
+++ b/src/IDF/templates/idf/source/commit.html
@@ -18,20 +18,45 @@
{trans 'Message:'} | {issuetext $cobject.title, $request}{if isset($cobject.full_message)}
{issuetext $cobject.full_message, $request, true, false, true, true, true}{/if} |
-{if count($diff.files)}
-{trans 'Files:'} |
+{trans 'Changes:'} |
-{foreach $diff.files as $filename=>$diffdef}
-{assign $ndiff = count($diffdef['chunks'])}
-{$filename} ({blocktrans $ndiff}{$ndiff} diff{plural}{$ndiff} diffs{/blocktrans})
+
+{foreach $changes.deletions as $filename}
+D | {$filename}{if !empty($diff.files[$filename])} ({trans 'full'}){/if} |
{/foreach}
+{foreach $changes.renames as $oldname => $newname}
+R | {$oldname} -> {$newname} |
+{/foreach}
+{foreach $changes.additions as $filename}
+A | {$filename}{if !empty($diff.files[$filename])} ({trans 'full'}){/if} |
+{/foreach}
+{foreach $changes.patches as $filename}
+{assign $ndiff = count($diff.files[$filename]['chunks'])}
+M | {$filename}{if !empty($diff.files[$filename])} ({blocktrans $ndiff}{$ndiff} diff{plural}{$ndiff} diffs{/blocktrans}){/if} |
+{/foreach}
+{foreach $changes.properties as $filename => $properties}
+P | {$filename}
+
+{foreach $properties as $key => $value}
+{$key} |
+{if $value == null}
+ {trans 'removed'} |
+{else}
+ {$value} |
+{/if}
+
+{/foreach}
+
+ |
+{/foreach}
+
|
-{/if}
+
{if count($diff.files)}
-{trans 'Change Details'}
+{trans 'File differences'}
{$diff.as_html()}
{/if}{if count($diff.files) or $large_commit}
diff --git a/www/media/idf/css/style.css b/www/media/idf/css/style.css
index 273f539..ef64f05 100644
--- a/www/media/idf/css/style.css
+++ b/www/media/idf/css/style.css
@@ -504,6 +504,21 @@ table.commit th {
table.commit td, table.commit th {
padding: 3px;
}
+table.commit table.changes td {
+ padding: 2px;
+}
+table.commit table.changes table.properties {
+ margin: 0;
+}
+table.commit table.changes table.properties tr:nth-child(even) {
+ background: #E4E8E0;
+}
+table.commit table.changes table.properties td {
+ white-space: pre-wrap;
+}
+table.commit table.changes table.properties td.removed {
+ font-style: italic;
+}
/**
* syntax highlighting of diffs