Page MenuHomeSealhub

No OneTemporary

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

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)

Event Timeline