Skip to content

Commit

Permalink
#532 - initial attempt at progress logger using Symfony Console
Browse files Browse the repository at this point in the history
  • Loading branch information
mrook committed Oct 23, 2016
1 parent 378f1b3 commit 2628e8e
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 19 deletions.
52 changes: 33 additions & 19 deletions classes/phing/Project.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ class Project
const MSG_WARN = 1;
const MSG_ERR = 0;

/** contains the targets */
/**
* contains the targets
* @var Target[]
*/
private $targets = array();
/** global filterset (future use) */
private $globalFilterSet = array();
Expand Down Expand Up @@ -112,6 +115,11 @@ class Project
*/
private $keepGoingMode = false;

/**
* @var string[]
*/
private $executedTargetNames = array();

/**
* Constructor, sets any default vars.
*/
Expand Down Expand Up @@ -702,13 +710,21 @@ public function addOrReplaceTarget($targetName, &$target)

/**
* Returns the available targets
* @return array
* @return Target[]
*/
public function getTargets()
{
return $this->targets;
}

/**
* @return string[]
*/
public function getExecutedTargetNames()
{
return $this->executedTargetNames;
}

/**
* Create a new task instance and return reference to it. This method is
* sorta factory like. A _local_ instance is created and a reference returned to
Expand Down Expand Up @@ -864,6 +880,8 @@ public function createDataType($typeName)
*/
public function executeTargets($targetNames)
{
$this->executedTargetNames = $targetNames;

foreach ($targetNames as $tname) {
$this->executeTarget($tname);
}
Expand All @@ -886,7 +904,7 @@ public function executeTarget($targetName)

// invoke topological sort of the target tree and run all targets
// until targetName occurs.
$sortedTargets = $this->_topoSort($targetName, $this->targets);
$sortedTargets = $this->topoSort($targetName);

$curIndex = (int) 0;
$curTarget = null;
Expand Down Expand Up @@ -949,19 +967,16 @@ public function resolveFile($fileName, $rootDir = null)

/**
* Topologically sort a set of Targets.
* @param string $root is the (String) name of the root Target. The sort is
* @param string $rootTarget is the (String) name of the root Target. The sort is
* created in such a way that the sequence of Targets until the root
* target is the minimum possible such sequence.
* @param array $targets is a array representing a "name to Target" mapping
* @throws BuildException
* @throws Exception
* @return array of Strings with the names of the targets in
* sorted order.
* @return Target[] targets in sorted order
*/
public function _topoSort($root, &$targets)
public function topoSort($rootTarget)
{

$root = (string) $root;
$rootTarget = (string) $rootTarget;
$ret = array();
$state = array();
$visiting = array();
Expand All @@ -974,15 +989,15 @@ public function _topoSort($root, &$targets)
// dependency tree, not just on the Targets that depend on the
// build Target.

$this->_tsort($root, $targets, $state, $visiting, $ret);
$this->_tsort($rootTarget, $state, $visiting, $ret);

$retHuman = "";
for ($i = 0, $_i = count($ret); $i < $_i; $i++) {
$retHuman .= $ret[$i]->toString() . " ";
}
$this->log("Build sequence for target '$root' is: $retHuman", Project::MSG_VERBOSE);
$this->log("Build sequence for target '$rootTarget' is: $retHuman", Project::MSG_VERBOSE);

$keys = array_keys($targets);
$keys = array_keys($this->targets);
while ($keys) {
$curTargetName = (string) array_shift($keys);
if (!isset($state[$curTargetName])) {
Expand All @@ -992,7 +1007,7 @@ public function _topoSort($root, &$targets)
}

if ($st === null) {
$this->_tsort($curTargetName, $targets, $state, $visiting, $ret);
$this->_tsort($curTargetName, $state, $visiting, $ret);
} elseif ($st === "VISITING") {
throw new Exception("Unexpected node in visiting state: $curTargetName");
}
Expand Down Expand Up @@ -1026,22 +1041,21 @@ public function _topoSort($root, &$targets)

/**
* @param $root
* @param $targets
* @param $state
* @param $visiting
* @param $ret
* @throws BuildException
* @throws Exception
*/
public function _tsort($root, &$targets, &$state, &$visiting, &$ret)
public function _tsort($root, &$state, &$visiting, &$ret)
{
$state[$root] = "VISITING";
$visiting[] = $root;

if (!isset($targets[$root]) || !($targets[$root] instanceof Target)) {
if (!isset($this->targets[$root]) || !($this->targets[$root] instanceof Target)) {
$target = null;
} else {
$target = $targets[$root];
$target = $this->targets[$root];
}

// make sure we exist
Expand All @@ -1066,7 +1080,7 @@ public function _tsort($root, &$targets, &$state, &$visiting, &$ret)
}
if ($m === null) {
// not been visited
$this->_tsort($cur, $targets, $state, $visiting, $ret);
$this->_tsort($cur, $state, $visiting, $ret);
} elseif ($m == "VISITING") {
// currently visiting this node, so have a cycle
throw $this->_makeCircularException($cur, $visiting);
Expand Down
165 changes: 165 additions & 0 deletions classes/phing/listener/ProgressLogger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?php

use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Output\ConsoleOutput;

class ProgressLogger extends AnsiColorLogger
{
/**
* @var ProgressBar
*/
private $bar;

private $numTargets = 0;
private $remTargets = 0;
private $numTasks = 0;
private $remTasks = 0;

public function __construct()
{
parent::__construct();

$this->bar = new ProgressBar(new ConsoleOutput());
$this->bar->setBarWidth(80);
$this->bar->setFormat("<fg=cyan>Buildfile: %buildfile%</>\n" .
" <fg=green>%current%/%max% [%bar%] %percent:3s%% %elapsed:6s%</>\n" .
"<fg=cyan>[%target% %task%] %message%</>");
$this->bar->setProgressCharacter('|');
$this->bar->setMessage('', 'target');
$this->bar->setMessage('', 'task');
}

/**
* Fired before any targets are started.
*
* @param BuildEvent $event The BuildEvent
*/
public function buildStarted(BuildEvent $event)
{
echo "\n";

$this->bar->setMessage($event->getProject()->getProperty("phing.file"), 'buildfile');

parent::buildStarted($event);
}

/**
* Fired after the last target has finished.
*
* @param BuildEvent $event The BuildEvent
* @see BuildEvent::getException()
*/
public function buildFinished(BuildEvent $event)
{
$this->bar->finish();
echo "\n";

parent::buildFinished($event);
}

/**
* Fired when a target is started.
*
* @param BuildEvent $event The BuildEvent
* @see BuildEvent::getTarget()
*/
public function targetStarted(BuildEvent $event)
{
$this->bar->setMessage($event->getTarget()->getName(), 'target');
$this->determineDepth($event);
}

/**
* Fired when a target has finished.
*
* @param BuildEvent $event The BuildEvent
* @see BuildEvent#getException()
*/
public function targetFinished(BuildEvent $event)
{
$this->remTargets--;
}

/**
* Fired when a task is started.
*
* @param BuildEvent $event The BuildEvent
* @see BuildEvent::getTask()
*/
public function taskStarted(BuildEvent $event)
{
// ignore tasks in root
if ($event->getTarget()->getName() == "") {
return;
}

$this->bar->setMessage($event->getTask()->getTaskName(), 'task');

$this->determineDepth($event);
}

/**
* Fired when a task has finished.
*
* @param BuildEvent $event The BuildEvent
* @see BuildEvent::getException()
*/
public function taskFinished(BuildEvent $event)
{
// ignore tasks in root
if ($event->getTarget()->getName() == "") {
return;
}

$this->remTasks--;
$this->bar->advance();
}

/**
* Fired whenever a message is logged.
*
* @param BuildEvent $event The BuildEvent
* @see BuildEvent::getMessage()
*/
public function messageLogged(BuildEvent $event)
{
$priority = $event->getPriority();
if ($priority <= $this->msgOutputLevel) {
$this->bar->setMessage($event->getMessage());
}
}

/**
* @param BuildEvent $event
* @throws Exception
*/
protected function determineDepth(BuildEvent $event)
{
if ($this->numTargets == 0) {
$this->numTasks = 0;
$this->numTargets = 0;

$project = $event->getProject();

$executedTargetNames = $project->getExecutedTargetNames();

foreach ($executedTargetNames as $targetName) {
$targets = $project->topoSort($targetName);

foreach ($targets as $target) {
if ($target->getName() == "") {
continue;
}

$tasks = $target->getTasks();
$this->numTasks += count($tasks);
$this->numTargets++;
}
}

$this->remTargets = $this->numTargets;
$this->remTasks = $this->numTasks;
$this->bar->start($this->numTasks);
}
}
}

0 comments on commit 2628e8e

Please sign in to comment.