Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F10360384
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
28 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/ref/revision/ArcanistRevisionRef.php b/src/ref/revision/ArcanistRevisionRef.php
index c36845bd..6f73390d 100644
--- a/src/ref/revision/ArcanistRevisionRef.php
+++ b/src/ref/revision/ArcanistRevisionRef.php
@@ -1,209 +1,219 @@
<?php
final class ArcanistRevisionRef
extends ArcanistRef {
const HARDPOINT_COMMITMESSAGE = 'ref.revision.commitmessage';
const HARDPOINT_AUTHORREF = 'ref.revision.authorRef';
const HARDPOINT_BUILDABLEREF = 'ref.revision.buildableRef';
const HARDPOINT_PARENTREVISIONREFS = 'ref.revision.parentRevisionRefs';
private $parameters;
private $sources = array();
public function getRefDisplayName() {
return pht('Revision %s', $this->getMonogram());
}
protected function newHardpoints() {
$object_list = new ArcanistObjectListHardpoint();
return array(
$this->newHardpoint(self::HARDPOINT_COMMITMESSAGE),
$this->newHardpoint(self::HARDPOINT_AUTHORREF),
$this->newHardpoint(self::HARDPOINT_BUILDABLEREF),
$this->newTemplateHardpoint(
self::HARDPOINT_PARENTREVISIONREFS,
$object_list),
);
}
public static function newFromConduit(array $dict) {
$ref = new self();
$ref->parameters = $dict;
return $ref;
}
public static function newFromConduitQuery(array $dict) {
// Mangle an older "differential.query" result to look like a modern
// "differential.revision.search" result.
$status_name = idx($dict, 'statusName');
switch ($status_name) {
case 'Abandoned':
case 'Closed':
$is_closed = true;
break;
default:
$is_closed = false;
break;
}
$value_map = array(
'0' => 'needs-review',
'1' => 'needs-revision',
'2' => 'accepted',
'3' => 'published',
'4' => 'abandoned',
'5' => 'changes-planned',
);
$color_map = array(
'needs-review' => 'magenta',
'needs-revision' => 'red',
'accepted' => 'green',
'published' => 'cyan',
'abandoned' => null,
'changes-planned' => 'red',
);
$status_value = idx($value_map, idx($dict, 'status'));
$ansi_color = idx($color_map, $status_value);
+ $date_created = null;
+ if (isset($dict['dateCreated'])) {
+ $date_created = (int)$dict['dateCreated'];
+ }
+
$dict['fields'] = array(
'uri' => idx($dict, 'uri'),
'title' => idx($dict, 'title'),
'authorPHID' => idx($dict, 'authorPHID'),
'status' => array(
'name' => $status_name,
'closed' => $is_closed,
'value' => $status_value,
'color.ansi' => $ansi_color,
),
+ 'dateCreated' => $date_created,
);
return self::newFromConduit($dict);
}
public function getMonogram() {
return 'D'.$this->getID();
}
public function getStatusShortDisplayName() {
if ($this->isStatusNeedsReview()) {
return pht('Review');
}
return idxv($this->parameters, array('fields', 'status', 'name'));
}
public function getStatusDisplayName() {
return idxv($this->parameters, array('fields', 'status', 'name'));
}
public function getStatusANSIColor() {
return idxv($this->parameters, array('fields', 'status', 'color.ansi'));
}
+ public function getDateCreated() {
+ return idxv($this->parameters, array('fields', 'dateCreated'));
+ }
+
public function isStatusChangesPlanned() {
$status = $this->getStatus();
return ($status === 'changes-planned');
}
public function isStatusAbandoned() {
$status = $this->getStatus();
return ($status === 'abandoned');
}
public function isStatusPublished() {
$status = $this->getStatus();
return ($status === 'published');
}
public function isStatusAccepted() {
$status = $this->getStatus();
return ($status === 'accepted');
}
public function isStatusNeedsReview() {
$status = $this->getStatus();
return ($status === 'needs-review');
}
public function getStatus() {
return idxv($this->parameters, array('fields', 'status', 'value'));
}
public function isClosed() {
return idxv($this->parameters, array('fields', 'status', 'closed'));
}
public function getURI() {
$uri = idxv($this->parameters, array('fields', 'uri'));
if ($uri === null) {
// TODO: The "uri" field was added at the same time as this callsite,
// so we may not have it yet if the server is running an older version
// of Phabricator. Fake our way through.
$uri = '/'.$this->getMonogram();
}
return $uri;
}
public function getFullName() {
return pht('%s: %s', $this->getMonogram(), $this->getName());
}
public function getID() {
return (int)idx($this->parameters, 'id');
}
public function getPHID() {
return idx($this->parameters, 'phid');
}
public function getDiffPHID() {
return idxv($this->parameters, array('fields', 'diffPHID'));
}
public function getName() {
return idxv($this->parameters, array('fields', 'title'));
}
public function getAuthorPHID() {
return idxv($this->parameters, array('fields', 'authorPHID'));
}
public function addSource(ArcanistRevisionRefSource $source) {
$this->sources[] = $source;
return $this;
}
public function getSources() {
return $this->sources;
}
public function getCommitMessage() {
return $this->getHardpoint(self::HARDPOINT_COMMITMESSAGE);
}
public function getAuthorRef() {
return $this->getHardpoint(self::HARDPOINT_AUTHORREF);
}
public function getParentRevisionRefs() {
return $this->getHardpoint(self::HARDPOINT_PARENTREVISIONREFS);
}
public function getBuildableRef() {
return $this->getHardpoint(self::HARDPOINT_BUILDABLEREF);
}
protected function buildRefView(ArcanistRefView $view) {
$view
->setObjectName($this->getMonogram())
->setTitle($this->getName());
}
}
diff --git a/src/repository/graph/query/ArcanistCommitGraphQuery.php b/src/repository/graph/query/ArcanistCommitGraphQuery.php
index 98cbb35c..6369c4b5 100644
--- a/src/repository/graph/query/ArcanistCommitGraphQuery.php
+++ b/src/repository/graph/query/ArcanistCommitGraphQuery.php
@@ -1,69 +1,79 @@
<?php
abstract class ArcanistCommitGraphQuery
extends Phobject {
private $graph;
private $headHashes;
private $tailHashes;
private $exactHashes;
- private $stopAtGCA;
private $limit;
+ private $minimumEpoch;
+ private $maximumEpoch;
final public function setGraph(ArcanistCommitGraph $graph) {
$this->graph = $graph;
return $this;
}
final public function getGraph() {
return $this->graph;
}
final public function withHeadHashes(array $hashes) {
$this->headHashes = $hashes;
return $this;
}
final protected function getHeadHashes() {
return $this->headHashes;
}
final public function withTailHashes(array $hashes) {
$this->tailHashes = $hashes;
return $this;
}
final protected function getTailHashes() {
return $this->tailHashes;
}
final public function withExactHashes(array $hashes) {
$this->exactHashes = $hashes;
return $this;
}
final protected function getExactHashes() {
return $this->exactHashes;
}
- final public function withStopAtGCA($stop_gca) {
- $this->stopAtGCA = $stop_gca;
- return $this;
- }
-
final public function setLimit($limit) {
$this->limit = $limit;
return $this;
}
final protected function getLimit() {
return $this->limit;
}
+ final public function withEpochRange($min, $max) {
+ $this->minimumEpoch = $min;
+ $this->maximumEpoch = $max;
+ return $this;
+ }
+
+ final public function getMinimumEpoch() {
+ return $this->minimumEpoch;
+ }
+
+ final public function getMaximumEpoch() {
+ return $this->maximumEpoch;
+ }
+
final public function getRepositoryAPI() {
return $this->getGraph()->getRepositoryAPI();
}
abstract public function execute();
}
diff --git a/src/repository/graph/query/ArcanistGitCommitGraphQuery.php b/src/repository/graph/query/ArcanistGitCommitGraphQuery.php
index 028fbbe3..2491a549 100644
--- a/src/repository/graph/query/ArcanistGitCommitGraphQuery.php
+++ b/src/repository/graph/query/ArcanistGitCommitGraphQuery.php
@@ -1,150 +1,209 @@
<?php
final class ArcanistGitCommitGraphQuery
extends ArcanistCommitGraphQuery {
- private $queryFuture;
private $seen = array();
+ private $futures = array();
+ private $iterators = array();
+ private $cursors = array();
+ private $iteratorKey = 0;
public function execute() {
- $this->beginExecute();
- $this->continueExecute();
+ $this->newFutures();
+
+ $this->executeIterators();
return $this->seen;
}
- protected function beginExecute() {
+ private function newFutures() {
$head_hashes = $this->getHeadHashes();
$exact_hashes = $this->getExactHashes();
if (!$head_hashes && !$exact_hashes) {
throw new Exception(pht('Need head hashes or exact hashes!'));
}
$api = $this->getRepositoryAPI();
+ $ref_lists = array();
- $refs = array();
- if ($head_hashes !== null) {
- foreach ($head_hashes as $hash) {
- $refs[] = $hash;
+ if ($head_hashes) {
+ $refs = array();
+ if ($head_hashes !== null) {
+ foreach ($head_hashes as $hash) {
+ $refs[] = $hash;
+ }
}
- }
- $tail_hashes = $this->getTailHashes();
- if ($tail_hashes !== null) {
- foreach ($tail_hashes as $tail_hash) {
- $refs[] = sprintf('^%s^@', $tail_hash);
+ $tail_hashes = $this->getTailHashes();
+ if ($tail_hashes !== null) {
+ foreach ($tail_hashes as $tail_hash) {
+ $refs[] = sprintf('^%s^@', $tail_hash);
+ }
}
+
+ $ref_lists[] = $refs;
}
if ($exact_hashes !== null) {
- if (count($exact_hashes) > 1) {
- // If "A" is a parent of "B" and we search for exact hashes ["A", "B"],
- // the exclusion rule generated by "^B^@" is stronger than the inclusion
- // rule generated by "A" and we don't get "A" in the result set.
- throw new Exception(
- pht(
- 'TODO: Multiple exact hashes not supported under Git.'));
- }
foreach ($exact_hashes as $exact_hash) {
- $refs[] = $exact_hash;
- $refs[] = sprintf('^%s^@', $exact_hash);
+ $ref_list = array();
+ $ref_list[] = $exact_hash;
+ $ref_list[] = sprintf('^%s^@', $exact_hash);
+ $ref_list[] = '--';
+ $ref_lists[] = $ref_list;
}
}
- $refs[] = '--';
- $refs = implode("\n", $refs)."\n";
+ $flags = array();
+
+ $min_epoch = $this->getMinimumEpoch();
+ if ($min_epoch !== null) {
+ $flags[] = '--after';
+ $flags[] = date('c', $min_epoch);
+ }
+
+ $max_epoch = $this->getMaximumEpoch();
+ if ($max_epoch !== null) {
+ $flags[] = '--before';
+ $flags[] = date('c', $max_epoch);
+ }
+
+ foreach ($ref_lists as $ref_list) {
+ $ref_blob = implode("\n", $ref_list)."\n";
+
+ $fields = array(
+ '%e',
+ '%H',
+ '%P',
+ '%ct',
+ '%B',
+ );
+
+ $format = implode('%x02', $fields).'%x01';
+
+ $future = $api->newFuture(
+ 'log --format=%s %Ls --stdin',
+ $format,
+ $flags);
+ $future->write($ref_blob);
+ $future->setResolveOnError(true);
+
+ $this->futures[] = $future;
+ }
+ }
+
+ private function executeIterators() {
+ while ($this->futures || $this->iterators) {
+ $iterator_limit = 8;
- $fields = array(
- '%e',
- '%H',
- '%P',
- '%ct',
- '%B',
- );
+ while (count($this->iterators) < $iterator_limit) {
+ if (!$this->futures) {
+ break;
+ }
- $format = implode('%x02', $fields).'%x01';
+ $future = array_pop($this->futures);
+ $future->startFuture();
- $future = $api->newFuture(
- 'log --format=%s --stdin',
- $format);
- $future->write($refs);
- $future->setResolveOnError(true);
- $future->start();
+ $iterator = id(new LinesOfALargeExecFuture($future))
+ ->setDelimiter("\1");
+ $iterator->rewind();
- $lines = id(new LinesOfALargeExecFuture($future))
- ->setDelimiter("\1");
- $lines->rewind();
+ $iterator_key = $this->getNextIteratorKey();
+ $this->iterators[$iterator_key] = $iterator;
+ }
+
+ $limit = $this->getLimit();
- $this->queryFuture = $lines;
+ foreach ($this->iterators as $iterator_key => $iterator) {
+ $this->executeIterator($iterator_key, $iterator);
+
+ if ($limit) {
+ if (count($this->seen) >= $limit) {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private function getNextIteratorKey() {
+ return $this->iteratorKey++;
}
- protected function continueExecute() {
+ private function executeIterator($iterator_key, $lines) {
$graph = $this->getGraph();
$limit = $this->getLimit();
- $lines = $this->queryFuture;
+ $is_done = false;
while (true) {
if (!$lines->valid()) {
- return false;
+ $is_done = true;
+ break;
}
$line = $lines->current();
$lines->next();
if ($line === "\n") {
continue;
}
$fields = explode("\2", $line);
if (count($fields) !== 5) {
throw new Exception(
pht(
'Failed to split line "%s" from "git log".',
$line));
}
list($encoding, $hash, $parents, $commit_epoch, $message) = $fields;
// TODO: Handle encoding, see DiffusionLowLevelCommitQuery.
$node = $graph->getNode($hash);
if (!$node) {
$node = $graph->newNode($hash);
}
$this->seen[$hash] = $node;
$node
->setCommitMessage($message)
->setCommitEpoch((int)$commit_epoch);
if (strlen($parents)) {
$parents = explode(' ', $parents);
$parent_nodes = array();
foreach ($parents as $parent) {
$parent_node = $graph->getNode($parent);
if (!$parent_node) {
$parent_node = $graph->newNode($parent);
}
$parent_nodes[$parent] = $parent_node;
$parent_node->addChildNode($node);
+
}
$node->setParentNodes($parent_nodes);
} else {
$parents = array();
}
if ($limit) {
if (count($this->seen) >= $limit) {
break;
}
}
}
+
+ if ($is_done) {
+ unset($this->iterators[$iterator_key]);
+ }
}
}
diff --git a/src/repository/graph/query/ArcanistMercurialCommitGraphQuery.php b/src/repository/graph/query/ArcanistMercurialCommitGraphQuery.php
index 0a3836a9..aadd08ad 100644
--- a/src/repository/graph/query/ArcanistMercurialCommitGraphQuery.php
+++ b/src/repository/graph/query/ArcanistMercurialCommitGraphQuery.php
@@ -1,180 +1,210 @@
<?php
final class ArcanistMercurialCommitGraphQuery
extends ArcanistCommitGraphQuery {
private $seen = array();
private $queryFuture;
public function execute() {
$this->beginExecute();
$this->continueExecute();
return $this->seen;
}
protected function beginExecute() {
$head_hashes = $this->getHeadHashes();
$exact_hashes = $this->getExactHashes();
if (!$head_hashes && !$exact_hashes) {
throw new Exception(pht('Need head hashes or exact hashes!'));
}
$api = $this->getRepositoryAPI();
$revsets = array();
if ($head_hashes !== null) {
$revs = array();
foreach ($head_hashes as $hash) {
$revs[] = hgsprintf(
'ancestors(%s)',
$hash);
}
$revsets[] = $this->joinOrRevsets($revs);
}
$tail_hashes = $this->getTailHashes();
if ($tail_hashes !== null) {
$revs = array();
foreach ($tail_hashes as $tail_hash) {
$revs[] = hgsprintf(
'descendants(%s)',
$tail_hash);
}
$revsets[] = $this->joinOrRevsets($revs);
}
if ($revsets) {
$revsets = array(
- $this->joinAndRevsets($revs),
+ $this->joinAndRevsets($revsets),
);
}
if ($exact_hashes !== null) {
$revs = array();
foreach ($exact_hashes as $exact_hash) {
$revs[] = hgsprintf(
'%s',
$exact_hash);
}
- $revsets[] = array(
- $this->joinOrRevsets($revs),
- );
+ $revsets[] = $this->joinOrRevsets($revs);
}
- $revsets = $this->joinOrRevsets($revs);
+ $revsets = $this->joinOrRevsets($revsets);
$fields = array(
'', // Placeholder for "encoding".
'{node}',
'{parents}',
'{date|rfc822date}',
'{description|utf8}',
);
$template = implode("\2", $fields)."\1";
+ $flags = array();
+
+ $min_epoch = $this->getMinimumEpoch();
+ $max_epoch = $this->getMaximumEpoch();
+ if ($min_epoch !== null || $max_epoch !== null) {
+ $flags[] = '--date';
+
+ if ($min_epoch !== null) {
+ $min_epoch = date('c', $min_epoch);
+ }
+
+ if ($max_epoch !== null) {
+ $max_epoch = date('c', $max_epoch);
+ }
+
+ if ($min_epoch !== null && $max_epoch !== null) {
+ $flags[] = sprintf(
+ '%s to %s',
+ $min_epoch,
+ $max_epoch);
+ } else if ($min_epoch) {
+ $flags[] = sprintf(
+ '>%s',
+ $min_epoch);
+ } else {
+ $flags[] = sprintf(
+ '<%s',
+ $max_epoch);
+ }
+ }
+
$future = $api->newFuture(
- 'log --rev %s --template %s --',
+ 'log --rev %s --template %s %Ls --',
$revsets,
- $template);
+ $template,
+ $flags);
$future->setResolveOnError(true);
$future->start();
$lines = id(new LinesOfALargeExecFuture($future))
->setDelimiter("\1");
$lines->rewind();
$this->queryFuture = $lines;
}
protected function continueExecute() {
$graph = $this->getGraph();
$lines = $this->queryFuture;
$limit = $this->getLimit();
while (true) {
if (!$lines->valid()) {
return false;
}
$line = $lines->current();
$lines->next();
if ($line === "\n") {
continue;
}
$fields = explode("\2", $line);
if (count($fields) !== 5) {
throw new Exception(
pht(
'Failed to split line "%s" from "git log".',
$line));
}
list($encoding, $hash, $parents, $commit_epoch, $message) = $fields;
$node = $graph->getNode($hash);
if (!$node) {
$node = $graph->newNode($hash);
}
$this->seen[$hash] = $node;
$node
->setCommitMessage($message)
->setCommitEpoch((int)strtotime($commit_epoch));
if (strlen($parents)) {
$parents = explode(' ', $parents);
$parent_nodes = array();
foreach ($parents as $parent) {
$parent_node = $graph->getNode($parent);
if (!$parent_node) {
$parent_node = $graph->newNode($parent);
}
$parent_nodes[$parent] = $parent_node;
$parent_node->addChildNode($node);
}
$node->setParentNodes($parent_nodes);
} else {
$parents = array();
}
if ($limit) {
if (count($this->seen) >= $limit) {
break;
}
}
}
}
private function joinOrRevsets(array $revsets) {
return $this->joinRevsets($revsets, false);
}
private function joinAndRevsets(array $revsets) {
return $this->joinRevsets($revsets, true);
}
private function joinRevsets(array $revsets, $is_and) {
if (!$revsets) {
return array();
}
if (count($revsets) === 1) {
return head($revsets);
}
if ($is_and) {
return '('.implode(' and ', $revsets).')';
} else {
return '('.implode(' or ', $revsets).')';
}
}
}
diff --git a/src/workflow/ArcanistMarkersWorkflow.php b/src/workflow/ArcanistMarkersWorkflow.php
index ea9fe98d..d27ae2af 100644
--- a/src/workflow/ArcanistMarkersWorkflow.php
+++ b/src/workflow/ArcanistMarkersWorkflow.php
@@ -1,303 +1,297 @@
<?php
abstract class ArcanistMarkersWorkflow
extends ArcanistArcWorkflow {
private $nodes;
abstract protected function getWorkflowMarkerType();
public function runWorkflow() {
$api = $this->getRepositoryAPI();
$marker_type = $this->getWorkflowMarkerType();
$markers = $api->newMarkerRefQuery()
->withMarkerTypes(array($marker_type))
->execute();
$tail_hashes = $this->getTailHashes();
$heads = mpull($markers, 'getCommitHash');
$graph = $api->getGraph();
$limit = 1000;
$query = $graph->newQuery()
->withHeadHashes($heads)
->setLimit($limit + 1);
if ($tail_hashes) {
$query->withTailHashes($tail_hashes);
}
$nodes = $query->execute();
if (count($nodes) > $limit) {
// TODO: Show what we can.
throw new PhutilArgumentUsageException(
pht(
'Found more than %s unpublished commits which are ancestors of '.
'heads.',
new PhutilNumber($limit)));
}
// We may have some markers which point at commits which are already
// published. These markers won't be reached by following heads backwards
// until we reach published commits.
// Load these markers exactly so they don't vanish in the output.
// TODO: Mark these sets as published.
$disjoint_heads = array();
foreach ($heads as $head) {
if (!isset($nodes[$head])) {
$disjoint_heads[] = $head;
}
}
if ($disjoint_heads) {
+ $disjoint_nodes = $graph->newQuery()
+ ->withExactHashes($disjoint_heads)
+ ->execute();
- // TODO: Git currently can not query for more than one exact hash at a
- // time.
-
- foreach ($disjoint_heads as $disjoint_head) {
- $disjoint_nodes = $graph->newQuery()
- ->withExactHashes(array($disjoint_head))
- ->execute();
-
- $nodes += $disjoint_nodes;
- }
+ $nodes += $disjoint_nodes;
}
$state_refs = array();
foreach ($nodes as $node) {
$commit_ref = $node->getCommitRef();
$state_ref = id(new ArcanistWorkingCopyStateRef())
->setCommitRef($commit_ref);
$state_refs[$node->getCommitHash()] = $state_ref;
}
$this->loadHardpoints(
$state_refs,
ArcanistWorkingCopyStateRef::HARDPOINT_REVISIONREFS);
$partitions = $graph->newPartitionQuery()
->withHeads($heads)
->withHashes(array_keys($nodes))
->execute();
$revision_refs = array();
foreach ($state_refs as $hash => $state_ref) {
$revision_ids = mpull($state_ref->getRevisionRefs(), 'getID');
$revision_refs[$hash] = array_fuse($revision_ids);
}
$partition_sets = array();
$partition_vectors = array();
foreach ($partitions as $partition_key => $partition) {
$sets = $partition->newSetQuery()
->setWaypointMap($revision_refs)
->execute();
list($sets, $partition_vector) = $this->sortSets(
$graph,
$sets,
$markers);
$partition_sets[$partition_key] = $sets;
$partition_vectors[$partition_key] = $partition_vector;
}
$partition_vectors = msortv($partition_vectors, 'getSelf');
$partitions = array_select_keys(
$partitions,
array_keys($partition_vectors));
$partition_lists = array();
foreach ($partitions as $partition_key => $partition) {
$sets = $partition_sets[$partition_key];
$roots = array();
foreach ($sets as $set) {
if (!$set->getParentSets()) {
$roots[] = $set;
}
}
// TODO: When no parent of a set is in the node list, we should render
// a marker showing that the commit sequence is historic.
$row_lists = array();
foreach ($roots as $set) {
$view = id(new ArcanistCommitGraphSetTreeView())
->setRepositoryAPI($api)
->setRootSet($set)
->setMarkers($markers)
->setStateRefs($state_refs);
$row_lists[] = $view->draw();
}
$partition_lists[] = $row_lists;
}
$grid = id(new ArcanistGridView());
$grid->newColumn('marker');
$grid->newColumn('commits');
$grid->newColumn('status');
$grid->newColumn('revisions');
$grid->newColumn('messages')
->setMinimumWidth(12);
foreach ($partition_lists as $row_lists) {
foreach ($row_lists as $row_list) {
foreach ($row_list as $row) {
$grid->newRow($row);
}
}
}
echo tsprintf('%s', $grid->drawGrid());
}
final protected function hasMarkerTypeSupport($marker_type) {
$api = $this->getRepositoryAPI();
$types = $api->getSupportedMarkerTypes();
$types = array_fuse($types);
return isset($types[$marker_type]);
}
private function getTailHashes() {
$api = $this->getRepositoryAPI();
return $api->getPublishedCommitHashes();
}
private function sortSets(
ArcanistCommitGraph $graph,
array $sets,
array $markers) {
$marker_groups = mgroup($markers, 'getCommitHash');
$sets = mpull($sets, null, 'getSetID');
$active_markers = array();
foreach ($sets as $set_id => $set) {
foreach ($set->getHashes() as $hash) {
$markers = idx($marker_groups, $hash, array());
$has_active = false;
foreach ($markers as $marker) {
if ($marker->getIsActive()) {
$has_active = true;
break;
}
}
if ($has_active) {
$active_markers[$set_id] = $set;
break;
}
}
}
$stack = array_select_keys($sets, array_keys($active_markers));
while ($stack) {
$cursor = array_pop($stack);
foreach ($cursor->getParentSets() as $parent_id => $parent) {
if (isset($active_markers[$parent_id])) {
continue;
}
$active_markers[$parent_id] = $parent;
$stack[] = $parent;
}
}
$partition_epoch = 0;
$partition_names = array();
$vectors = array();
foreach ($sets as $set_id => $set) {
if (isset($active_markers[$set_id])) {
$has_active = 1;
} else {
$has_active = 0;
}
$max_epoch = 0;
$marker_names = array();
foreach ($set->getHashes() as $hash) {
$node = $graph->getNode($hash);
$max_epoch = max($max_epoch, $node->getCommitEpoch());
$markers = idx($marker_groups, $hash, array());
foreach ($markers as $marker) {
$marker_names[] = $marker->getName();
}
}
$partition_epoch = max($partition_epoch, $max_epoch);
if ($marker_names) {
$has_markers = 1;
natcasesort($marker_names);
$max_name = last($marker_names);
$partition_names[] = $max_name;
} else {
$has_markers = 0;
$max_name = '';
}
$vector = id(new PhutilSortVector())
->addInt($has_active)
->addInt($max_epoch)
->addInt($has_markers)
->addString($max_name);
$vectors[$set_id] = $vector;
}
$vectors = msortv_natural($vectors, 'getSelf');
$vector_keys = array_keys($vectors);
foreach ($sets as $set_id => $set) {
$child_sets = $set->getDisplayChildSets();
$child_sets = array_select_keys($child_sets, $vector_keys);
$set->setDisplayChildSets($child_sets);
}
$sets = array_select_keys($sets, $vector_keys);
if ($active_markers) {
$any_active = true;
} else {
$any_active = false;
}
if ($partition_names) {
$has_markers = 1;
natcasesort($partition_names);
$partition_name = last($partition_names);
} else {
$has_markers = 0;
$partition_name = '';
}
$partition_vector = id(new PhutilSortVector())
->addInt($any_active)
->addInt($partition_epoch)
->addInt($has_markers)
->addString($partition_name);
return array($sets, $partition_vector);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 8, 06:31 (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1034160
Default Alt Text
(28 KB)
Attached To
Mode
R118 Arcanist - fork
Attached
Detach File
Event Timeline
Log In to Comment