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} + {/foreach} +{foreach $changes.renames as $oldname => $newname} + +{/foreach} +{foreach $changes.additions as $filename} + +{/foreach} +{foreach $changes.patches as $filename} +{assign $ndiff = count($diff.files[$filename]['chunks'])} + +{/foreach} +{foreach $changes.properties as $filename => $properties} + +{/foreach} +
D{$filename}{if !empty($diff.files[$filename])} ({trans 'full'}){/if}
R{$oldname} -> {$newname}
A{$filename}{if !empty($diff.files[$filename])} ({trans 'full'}){/if}
M{$filename}{if !empty($diff.files[$filename])} ({blocktrans $ndiff}{$ndiff} diff{plural}{$ndiff} diffs{/blocktrans}){/if}
P{$filename} + +{foreach $properties as $key => $value} + +{if $value == null} + +{else} + +{/if} + +{/foreach} +
{$key}{trans 'removed'}{$value}
+
-{/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