1
0
Fork 0

Add basic progress bar capability while waiting for jobs to complete

pull/8952/head
Jordi Boggiano 2020-06-05 10:01:48 +02:00
parent b1e15c7725
commit 9f380d606c
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
5 changed files with 72 additions and 40 deletions

View File

@ -14,6 +14,7 @@ namespace Composer\IO;
use Composer\Question\StrictConfirmationQuestion;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@ -253,6 +254,15 @@ class ConsoleIO extends BaseIO
}
}
/**
* @param int $max
* @return ProgressBar
*/
public function getProgressBar($max = 0)
{
return new ProgressBar($this->getErrorOutput(), $max);
}
/**
* {@inheritDoc}
*/

View File

@ -13,6 +13,7 @@
namespace Composer\Installer;
use Composer\IO\IOInterface;
use Composer\IO\ConsoleIO;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
use Composer\Repository\RepositoryInterface;
@ -330,7 +331,14 @@ class InstallationManager
// execute all prepare => installs/updates/removes => cleanup steps
if (!empty($promises)) {
$this->loop->wait($promises);
$progress = null;
if ($io instanceof ConsoleIO && !$io->isDebug()) {
$progress = $io->getProgressBar();
}
$this->loop->wait($promises, $progress);
if ($progress) {
$progress->clear();
}
}
} catch (\Exception $e) {
$runCleanup();

View File

@ -267,21 +267,12 @@ class HttpDownloader
public function markJobDone()
{
$this->runningJobs--;
foreach ($this->jobs as $job) {
if ($job['status'] === self::STATUS_QUEUED) {
$this->startJob($job['id']);
if ($this->runningJobs >= $this->maxJobs) {
return;
}
}
}
}
public function wait($index = null)
{
while (true) {
if (!$this->hasActiveJob($index)) {
if (!$this->countActiveJobs($index)) {
return;
}
@ -299,26 +290,37 @@ class HttpDownloader
/**
* @internal
*
* @return int number of active (queued or started) jobs
*/
public function hasActiveJob($index = null)
public function countActiveJobs($index = null)
{
if ($this->runningJobs < $this->maxJobs) {
foreach ($this->jobs as $job) {
if ($job['status'] === self::STATUS_QUEUED && $this->runningJobs < $this->maxJobs) {
$this->startJob($job['id']);
}
}
}
if ($this->curl) {
$this->curl->tick();
}
if (null !== $index) {
return $this->jobs[$index]['status'] < self::STATUS_COMPLETED;
return $this->jobs[$index]['status'] < self::STATUS_COMPLETED ? 1 : 0;
}
$active = 0;
foreach ($this->jobs as $job) {
if ($job['status'] < self::STATUS_COMPLETED) {
return true;
$active++;
} elseif (!$job['sync']) {
unset($this->jobs[$job['id']]);
}
}
return false;
return $active;
}
private function getResponse($index)

View File

@ -14,6 +14,7 @@ namespace Composer\Util;
use Composer\Util\HttpDownloader;
use React\Promise\Promise;
use Symfony\Component\Console\Helper\ProgressBar;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
@ -36,7 +37,7 @@ class Loop
}
}
public function wait(array $promises)
public function wait(array $promises, ProgressBar $progress = null)
{
/** @var \Exception|null */
$uncaught = null;
@ -50,21 +51,32 @@ class Loop
$this->currentPromises = $promises;
while (true) {
$hasActiveJob = false;
if ($progress) {
$totalJobs = 0;
if ($this->httpDownloader) {
if ($this->httpDownloader->hasActiveJob()) {
$hasActiveJob = true;
}
$totalJobs += $this->httpDownloader->countActiveJobs();
}
if ($this->processExecutor) {
if ($this->processExecutor->hasActiveJob()) {
$hasActiveJob = true;
}
$totalJobs += $this->processExecutor->countActiveJobs();
}
$progress->start($totalJobs);
}
while (true) {
$activeJobs = 0;
if ($this->httpDownloader) {
$activeJobs += $this->httpDownloader->countActiveJobs();
}
if ($this->processExecutor) {
$activeJobs += $this->processExecutor->countActiveJobs();
}
if (!$hasActiveJob) {
if ($progress) {
$progress->setProgress($progress->getMaxSteps() - $activeJobs);
}
if (!$activeJobs) {
break;
}

View File

@ -250,7 +250,7 @@ class ProcessExecutor
public function wait($index = null)
{
while (true) {
if (!$this->hasActiveJob($index)) {
if (!$this->countActiveJobs($index)) {
return;
}
@ -268,8 +268,10 @@ class ProcessExecutor
/**
* @internal
*
* @return int number of active (queued or started) jobs
*/
public function hasActiveJob($index = null)
public function countActiveJobs($index = null)
{
// tick
foreach ($this->jobs as $job) {
@ -278,21 +280,28 @@ class ProcessExecutor
call_user_func($job['resolve'], $job['process']);
}
}
if ($this->runningJobs < $this->maxJobs) {
if ($job['status'] === self::STATUS_QUEUED) {
$this->startJob($job['id']);
}
}
}
if (null !== $index) {
return $this->jobs[$index]['status'] < self::STATUS_COMPLETED;
return $this->jobs[$index]['status'] < self::STATUS_COMPLETED ? 1 : 0;
}
$active = 0;
foreach ($this->jobs as $job) {
if ($job['status'] < self::STATUS_COMPLETED) {
return true;
$active++;
} else {
unset($this->jobs[$job['id']]);
}
}
return false;
return $active;
}
/**
@ -301,15 +310,6 @@ class ProcessExecutor
public function markJobDone()
{
$this->runningJobs--;
foreach ($this->jobs as $job) {
if ($job['status'] === self::STATUS_QUEUED) {
$this->startJob($job['id']);
if ($this->runningJobs >= $this->maxJobs) {
return;
}
}
}
}
public function splitLines($output)