1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Implement dots progress bar

This commit is contained in:
Ilija Tovilo 2019-05-25 19:24:40 +02:00 committed by Matthew Brown
parent 042070d0fd
commit 0c5837b246
15 changed files with 166 additions and 50 deletions

View File

@ -231,6 +231,12 @@ class Analyzer
$file_analyzer->analyze(null);
};
$this->progress->start(count($this->files_to_analyze));
$task_done_closure = function (): void {
$this->progress->taskDone(true);
};
if ($pool_size > 1 && count($this->files_to_analyze) > $pool_size) {
$process_file_paths = [];
@ -292,7 +298,8 @@ class Analyzer
'class_method_locations' => $file_reference_provider->getAllClassMethodLocations(),
'class_property_locations' => $file_reference_provider->getAllClassPropertyLocations(),
];
}
},
$task_done_closure
);
$this->progress->debug('Forking analysis' . "\n");
@ -373,6 +380,7 @@ class Analyzer
foreach ($this->files_to_analyze as $file_path => $_) {
$analysis_worker($i, $file_path);
++$i;
$task_done_closure();
}
foreach (IssueBuffer::getIssuesData() as $issue_data) {
@ -380,6 +388,8 @@ class Analyzer
}
}
$this->progress->finish();
$codebase = $project_analyzer->getCodebase();
if ($codebase->find_unused_code

View File

@ -0,0 +1,6 @@
<?php
namespace Psalm\Internal\Fork;
interface ForkMessage
{
}

View File

@ -0,0 +1,16 @@
<?php
namespace Psalm\Internal\Fork;
class ForkProcessDoneMessage implements ForkMessage
{
/** @var mixed */
public $data;
/**
* @param mixed $data
*/
public function __construct($data)
{
$this->data = $data;
}
}

View File

@ -0,0 +1,6 @@
<?php
namespace Psalm\Internal\Fork;
class ForkTaskDoneMessage implements ForkMessage
{
}

View File

@ -24,6 +24,9 @@ class Pool
/** @var bool */
private $did_have_error = false;
/** @var ?\Closure(): void */
private $task_done_closure;
/**
* @param array[] $process_task_data_iterator
* An array of task data items to be divided up among the
@ -35,6 +38,8 @@ class Pool
* This closure must return an array (to be gathered).
* @param \Closure $shutdown_closure
* A closure to execute upon shutting down a child
* @param ?\Closure(): void $task_done_closure
* A closure to execute when a task is done
*
* @psalm-suppress MixedAssignment
*/
@ -42,9 +47,11 @@ class Pool
array $process_task_data_iterator,
\Closure $startup_closure,
\Closure $task_closure,
\Closure $shutdown_closure
\Closure $shutdown_closure,
?\Closure $task_done_closure = null
) {
$pool_size = count($process_task_data_iterator);
$this->task_done_closure = $task_done_closure;
\assert(
$pool_size > 1,
@ -124,6 +131,8 @@ class Pool
$task_data_iterator = array_values($process_task_data_iterator)[$proc_id];
foreach ($task_data_iterator as $i => $task_data) {
$task_closure($i, $task_data);
$task_done_message = new ForkTaskDoneMessage();
fwrite($write_stream, base64_encode(serialize($task_done_message)) . PHP_EOL);
}
// Execute each child's shutdown closure before
@ -131,7 +140,8 @@ class Pool
$results = $shutdown_closure();
// Serialize this child's produced results and send them to the parent.
fwrite($write_stream, serialize($results ?: []));
$process_done_message = new ForkProcessDoneMessage($results ?: []);
fwrite($write_stream, base64_encode(serialize($process_done_message)) . PHP_EOL);
fclose($write_stream);
@ -205,8 +215,11 @@ class Pool
// Create an array for the content received on each stream,
// indexed by resource id.
/** @var array<int, string> $content */
$content = array_fill_keys(array_keys($streams), '');
$terminationMessages = [];
// Read the data off of all the stream.
while (count($streams) > 0) {
$needs_read = array_values($streams);
@ -227,6 +240,23 @@ class Pool
$content[intval($file)] .= $buffer;
}
if (strpos($buffer, PHP_EOL) === strlen($buffer) - 1) {
$serializedMessage = $content[intval($file)];
$content[intval($file)] = '';
$message = unserialize(base64_decode($serializedMessage));
if ($message instanceof ForkProcessDoneMessage) {
$terminationMessages[] = $message->data;
} elseif ($message instanceof ForkTaskDoneMessage) {
if ($this->task_done_closure !== null) {
($this->task_done_closure)();
}
} else {
error_log('Child should return ForkMessage - response type=' . gettype($message));
$this->did_have_error = true;
}
}
// If the stream has closed, stop trying to select on it.
if (feof($file)) {
fclose($file);
@ -235,30 +265,7 @@ class Pool
}
}
// Unmarshal the content into its original form.
return array_values(
array_map(
/**
* @param string $data
*
* @return array
*/
function ($data) {
/** @var array */
$result = unserialize($data);
/** @psalm-suppress DocblockTypeContradiction */
if (!\is_array($result)) {
error_log(
'Child terminated without returning a serialized array - response type=' . gettype($result)
);
$this->did_have_error = true;
}
return $result;
},
$content
)
);
return array_values($terminationMessages);
}
/**

View File

@ -1,5 +1,4 @@
<?php
namespace Psalm\Progress;
class DebugProgress extends Progress
@ -11,16 +10,16 @@ class DebugProgress extends Progress
public function debug(string $message): void
{
fwrite(STDERR, $message);
$this->write($message);
}
public function startScanningFiles(): void
{
fwrite(STDERR, 'Scanning files...' . "\n");
$this->write('Scanning files...' . "\n");
}
public function startAnalyzingFiles(): void
{
fwrite(STDERR, 'Analyzing files...' . "\n");
$this->write('Analyzing files...' . "\n");
}
}

View File

@ -1,16 +1,71 @@
<?php
namespace Psalm\Progress;
class DefaultProgress extends Progress
{
public const NUMBER_OF_COLUMNS = 60;
/** @var int|null */
private $number_of_tasks;
/** @var int */
private $progress = 0;
public function startScanningFiles(): void
{
fwrite(STDERR, 'Scanning files...' . "\n");
$this->write('Scanning files...' . "\n");
}
public function startAnalyzingFiles(): void
{
fwrite(STDERR, 'Analyzing files...' . "\n");
$this->write('Analyzing files...' . "\n");
}
public function start(int $number_of_tasks): void
{
$this->number_of_tasks = $number_of_tasks;
$this->progress = 0;
}
public function taskDone(bool $successful): void
{
if ($successful) {
$this->write('.');
} else {
$this->write('F');
}
++$this->progress;
if (($this->progress % self::NUMBER_OF_COLUMNS) !== 0) {
return;
}
$this->printOverview();
$this->write(PHP_EOL);
}
public function finish(): void
{
$this->write(PHP_EOL);
}
private function printOverview(): void
{
if ($this->number_of_tasks === null) {
throw new \LogicException('Progress::start() should be called before Progress::startDone()');
}
$leadingSpaces = 1 + strlen((string) $this->number_of_tasks) - strlen((string) $this->progress);
$percentage = round($this->progress / $this->number_of_tasks * 100);
$message = sprintf(
'%s%s / %s (%s%%)',
str_repeat(' ', $leadingSpaces),
$this->progress,
$this->number_of_tasks,
$percentage
);
$this->write($message);
}
}

View File

@ -1,5 +1,4 @@
<?php
namespace Psalm\Progress;
abstract class Progress
@ -20,4 +19,21 @@ abstract class Progress
public function startAnalyzingFiles(): void
{
}
public function start(int $number_of_tasks): void
{
}
public function taskDone(bool $successful): void
{
}
public function finish(): void
{
}
protected function write(string $message): void
{
fwrite(STDERR, $message);
}
}

View File

@ -5,6 +5,7 @@ use Psalm\Internal\Analyzer\FileAnalyzer;
use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Internal\Provider\Providers;
use Psalm\Tests\Internal\Provider;
use Psalm\Tests\Progress\VoidProgress;
use Psalm\Tests\TestConfig;
class CachedStorageTest extends \Psalm\Tests\TestCase
@ -37,7 +38,7 @@ class CachedStorageTest extends \Psalm\Tests\TestCase
true,
ProjectAnalyzer::TYPE_CONSOLE,
1,
null
new VoidProgress()
);
$this->project_analyzer->setPhpVersion('7.3');
}

View File

@ -5,6 +5,7 @@ use Psalm\Internal\Analyzer\FileAnalyzer;
use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Internal\Provider\Providers;
use Psalm\Tests\Internal\Provider;
use Psalm\Tests\Progress\VoidProgress;
use Psalm\Tests\TestConfig;
class ErrorAfterUpdateTest extends \Psalm\Tests\TestCase
@ -37,7 +38,7 @@ class ErrorAfterUpdateTest extends \Psalm\Tests\TestCase
true,
ProjectAnalyzer::TYPE_CONSOLE,
1,
null
new VoidProgress()
);
$this->project_analyzer->setPhpVersion('7.3');
}

View File

@ -5,6 +5,7 @@ use Psalm\Internal\Analyzer\FileAnalyzer;
use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Internal\Provider\Providers;
use Psalm\Tests\Internal\Provider;
use Psalm\Tests\Progress\VoidProgress;
use Psalm\Tests\TestConfig;
class ErrorFixTest extends \Psalm\Tests\TestCase
@ -38,7 +39,7 @@ class ErrorFixTest extends \Psalm\Tests\TestCase
true,
ProjectAnalyzer::TYPE_CONSOLE,
1,
null
new VoidProgress()
);
$this->project_analyzer->setPhpVersion('7.3');
}

View File

@ -5,6 +5,7 @@ use Psalm\Internal\Analyzer\FileAnalyzer;
use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Internal\Provider\Providers;
use Psalm\Tests\Internal\Provider;
use Psalm\Tests\Progress\VoidProgress;
use Psalm\Tests\TestConfig;
class TemporaryUpdateTest extends \Psalm\Tests\TestCase
@ -38,7 +39,7 @@ class TemporaryUpdateTest extends \Psalm\Tests\TestCase
true,
ProjectAnalyzer::TYPE_CONSOLE,
1,
null
new VoidProgress()
);
$this->project_analyzer->setPhpVersion('7.3');
}

View File

@ -7,6 +7,7 @@ use Psalm\Internal\Analyzer\FileAnalyzer;
use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Internal\Provider\Providers;
use Psalm\Tests\Internal\Provider;
use Psalm\Tests\Progress\VoidProgress;
use Psalm\Tests\TestConfig;
class CompletionTest extends \Psalm\Tests\TestCase
@ -39,7 +40,7 @@ class CompletionTest extends \Psalm\Tests\TestCase
true,
ProjectAnalyzer::TYPE_CONSOLE,
1,
null
new VoidProgress()
);
$this->project_analyzer->setPhpVersion('7.3');
$this->project_analyzer->getCodebase()->store_node_types = true;

View File

@ -7,6 +7,7 @@ use Psalm\Internal\Analyzer\FileAnalyzer;
use Psalm\Internal\Analyzer\ProjectAnalyzer;
use Psalm\Internal\Provider\Providers;
use Psalm\Tests\Internal\Provider;
use Psalm\Tests\Progress\VoidProgress;
use Psalm\Tests\TestConfig;
class SymbolLookupTest extends \Psalm\Tests\TestCase
@ -39,7 +40,7 @@ class SymbolLookupTest extends \Psalm\Tests\TestCase
true,
ProjectAnalyzer::TYPE_CONSOLE,
1,
null
new VoidProgress()
);
$this->project_analyzer->setPhpVersion('7.3');

View File

@ -1,17 +1,12 @@
<?php
namespace Psalm\Tests\Progress;
use Psalm\Progress\Progress;
use Psalm\Progress\DefaultProgress;
class EchoProgress extends Progress
class EchoProgress extends DefaultProgress
{
public function startScanningFiles(): void
protected function write(string $message): void
{
echo 'Scanning files...' . "\n";
}
public function startAnalyzingFiles(): void
{
echo 'Analyzing files...' . "\n";
echo $message;
}
}