Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2892564
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
9 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/infrastructure/diff/view/PHUIDiffGraphView.php b/src/infrastructure/diff/view/PHUIDiffGraphView.php
index ed4b0acf57..76ae0b2045 100644
--- a/src/infrastructure/diff/view/PHUIDiffGraphView.php
+++ b/src/infrastructure/diff/view/PHUIDiffGraphView.php
@@ -1,213 +1,213 @@
<?php
final class PHUIDiffGraphView extends Phobject {
private $isHead = true;
private $isTail = true;
public function setIsHead($is_head) {
$this->isHead = $is_head;
return $this;
}
public function getIsHead() {
return $this->isHead;
}
public function setIsTail($is_tail) {
$this->isTail = $is_tail;
return $this;
}
public function getIsTail() {
return $this->isTail;
}
public function renderRawGraph(array $parents) {
// This keeps our accumulated information about each line of the
// merge/branch graph.
$graph = array();
// This holds the next commit we're looking for in each column of the
// graph.
$threads = array();
// This is the largest number of columns any row has, i.e. the width of
// the graph.
$count = 0;
foreach ($parents as $cursor => $parent_list) {
$joins = array();
$splits = array();
// Look for some thread which has this commit as the next commit. If
// we find one, this commit goes on that thread. Otherwise, this commit
// goes on a new thread.
$line = '';
$found = false;
$pos = count($threads);
$thread_count = $pos;
for ($n = 0; $n < $thread_count; $n++) {
-
if (empty($threads[$n])) {
$line .= ' ';
continue;
}
if ($threads[$n] == $cursor) {
if ($found) {
$line .= ' ';
$joins[] = $n;
- unset($threads[$n]);
+ $threads[$n] = false;
} else {
$line .= 'o';
$found = true;
$pos = $n;
}
} else {
// We render a "|" for any threads which have a commit that we haven't
// seen yet, this is later drawn as a vertical line.
$line .= '|';
}
}
// If we didn't find the thread this commit goes on, start a new thread.
// We use "o" to mark the commit for the rendering engine, or "^" to
// indicate that there's nothing after it so the line from the commit
// upward should not be drawn.
if (!$found) {
if ($this->getIsHead()) {
$line .= '^';
} else {
$line .= 'o';
foreach ($graph as $k => $meta) {
// Go back across all the lines we've already drawn and add a
// "|" to the end, since this is connected to some future commit
// we don't know about.
for ($jj = strlen($meta['line']); $jj <= $count; $jj++) {
$graph[$k]['line'] .= '|';
}
}
}
}
// Update the next commit on this thread to the commit's first parent.
// This might have the effect of making a new thread.
$threads[$pos] = head($parent_list);
// If we made a new thread, increase the thread count.
$count = max($pos + 1, $count);
// Now, deal with splits (merges). I picked this terms opposite to the
// underlying repository term to confuse you.
foreach (array_slice($parent_list, 1) as $parent) {
$found = false;
// Try to find the other parent(s) in our existing threads. If we find
// them, split to that thread.
foreach ($threads as $idx => $thread_commit) {
if ($thread_commit == $parent) {
$found = true;
$splits[] = $idx;
+ break;
}
}
// If we didn't find the parent, we don't know about it yet. Find the
// first free thread and add it as the "next" commit in that thread.
// This might create a new thread.
if (!$found) {
for ($n = 0; $n < $count; $n++) {
if (empty($threads[$n])) {
break;
}
}
$threads[$n] = $parent;
$splits[] = $n;
$count = max($n + 1, $count);
}
}
$graph[] = array(
'line' => $line,
'split' => $splits,
'join' => $joins,
);
}
// If this is the last page in history, replace any "o" characters at the
// bottom of columns with "x" characters so we do not draw a connecting
// line downward, and replace "^" with an "X" for repositories with
// exactly one commit.
if ($this->getIsTail() && $graph) {
$terminated = array();
foreach (array_reverse(array_keys($graph)) as $key) {
$line = $graph[$key]['line'];
$len = strlen($line);
for ($ii = 0; $ii < $len; $ii++) {
$c = $line[$ii];
if ($c == 'o') {
// If we've already terminated this thread, we don't need to add
// a terminator.
if (isset($terminated[$ii])) {
continue;
}
$terminated[$ii] = true;
// If this thread is joinining some other node here, we don't want
// to terminate it.
if (isset($graph[$key + 1])) {
$joins = $graph[$key + 1]['join'];
if (in_array($ii, $joins)) {
continue;
}
}
$graph[$key]['line'][$ii] = 'x';
} else if ($c != ' ') {
$terminated[$ii] = true;
} else {
unset($terminated[$ii]);
}
}
}
$last = array_pop($graph);
$last['line'] = str_replace('^', 'X', $last['line']);
$graph[] = $last;
}
return array($graph, $count);
}
public function renderGraph(array $parents) {
list($graph, $count) = $this->renderRawGraph($parents);
// Render into tags for the behavior.
foreach ($graph as $k => $meta) {
$graph[$k] = javelin_tag(
'div',
array(
'sigil' => 'commit-graph',
'meta' => $meta,
),
'');
}
Javelin::initBehavior(
'diffusion-commit-graph',
array(
'count' => $count,
));
return $graph;
}
}
diff --git a/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php b/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php
index 9bcf9645a3..2b9e4f8097 100644
--- a/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php
+++ b/src/infrastructure/diff/view/__tests__/PHUIDiffGraphViewTestCase.php
@@ -1,94 +1,117 @@
<?php
final class PHUIDiffGraphViewTestCase extends PhabricatorTestCase {
public function testTailTermination() {
$nodes = array(
'A' => array('B'),
'B' => array('C', 'D', 'E'),
'E' => array(),
'D' => array(),
'C' => array('F', 'G'),
'G' => array(),
'F' => array(),
);
$graph = $this->newGraph($nodes);
$picture = array(
'^',
'o',
'||x',
'|x ',
'o ',
'|x ',
'x ',
);
$this->assertGraph($picture, $graph, pht('Terminating Tree'));
}
public function testReverseTree() {
$nodes = array(
'A' => array('B'),
'C' => array('B'),
'B' => array('D'),
'E' => array('D'),
'F' => array('D'),
'D' => array('G'),
'G' => array(),
);
$graph = $this->newGraph($nodes);
$picture = array(
'^',
'|^',
'o ',
- '|^',
- '||^',
- 'o ',
- 'x',
+ '| ^',
+ '| |^',
+ 'o ',
+ 'x ',
);
$this->assertGraph($picture, $graph, pht('Reverse Tree'));
}
public function testJoinTerminateTree() {
$nodes = array(
'A' => array('D'),
'B' => array('C'),
'C' => array('D'),
'D' => array(),
);
$graph = $this->newGraph($nodes);
$picture = array(
'^',
'|^',
'|o',
'x ',
);
- $this->assertGraph($picture, $graph, pht('Reverse Tree'));
+ $this->assertGraph($picture, $graph, pht('Terminated Tree'));
+ }
+
+ public function testThreeWayGraphJoin() {
+ $nodes = array(
+ 'A' => array('D', 'C', 'B'),
+ 'B' => array('D'),
+ 'C' => array('B', 'E', 'F'),
+ 'D' => array(),
+ 'E' => array(),
+ 'F' => array(),
+ );
+
+ $graph = $this->newGraph($nodes);
+ $picture = array(
+ '^',
+ '||o',
+ '|o|',
+ 'x| ||',
+ ' | x|',
+ ' | x',
+ );
+
+ $this->assertGraph($picture, $graph, pht('Three-Way Tree'));
}
private function newGraph(array $nodes) {
return id(new PHUIDiffGraphView())
->setIsHead(true)
->setIsTail(true)
->renderRawGraph($nodes);
}
private function assertGraph($picture, $graph, $label) {
list($data, $count) = $graph;
$lines = ipull($data, 'line');
$picture = implode("\n", $picture);
$lines = implode("\n", $lines);
$this->assertEqual($picture, $lines, $label);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 17:00 (2 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1126738
Default Alt Text
(9 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment