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:
parent
042070d0fd
commit
0c5837b246
@ -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
|
||||
|
6
src/Psalm/Internal/Fork/ForkMessage.php
Normal file
6
src/Psalm/Internal/Fork/ForkMessage.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace Psalm\Internal\Fork;
|
||||
|
||||
interface ForkMessage
|
||||
{
|
||||
}
|
16
src/Psalm/Internal/Fork/ForkProcessDoneMessage.php
Normal file
16
src/Psalm/Internal/Fork/ForkProcessDoneMessage.php
Normal 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;
|
||||
}
|
||||
}
|
6
src/Psalm/Internal/Fork/ForkTaskDoneMessage.php
Normal file
6
src/Psalm/Internal/Fork/ForkTaskDoneMessage.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace Psalm\Internal\Fork;
|
||||
|
||||
class ForkTaskDoneMessage implements ForkMessage
|
||||
{
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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');
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user