Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion src/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,10 @@ public function restoreDefaults()

$parallel = self::getConfigData('parallel');
if ($parallel !== null) {
if ($parallel === 'auto') {
$parallel = self::detectNumberOfProcessors();
}

$this->parallel = max((int) $parallel, 1);
}
}
Expand Down Expand Up @@ -1185,7 +1189,12 @@ public function processLongArgument(string $arg, int $pos)
break;
}

$this->parallel = max((int) substr($arg, 9), 1);
$value = substr($arg, 9);
if ($value === 'auto') {
$value = self::detectNumberOfProcessors();
}

$this->parallel = max((int) $value, 1);
$this->overriddenDefaults['parallel'] = true;
} elseif (substr($arg, 0, 9) === 'severity=') {
$this->errorSeverity = (int) substr($arg, 9);
Expand Down Expand Up @@ -1721,6 +1730,40 @@ public static function getAllConfigData()
}


/**
* Detect the number of CPU cores available.
*
* @return int
*/
private static function detectNumberOfProcessors()
{
if (PHP_OS_FAMILY === 'Windows') {
$count = getenv('NUMBER_OF_PROCESSORS');
if (is_string($count) === true && preg_match('`\d+`', $count, $matches) === 1) {
return max((int) $matches[0], 1);
}

return 1;
}

if (function_exists('shell_exec') === true) {
// Linux, macOS with coreutils, and most modern Unix-like systems.
$count = shell_exec('nproc 2>/dev/null');
if (is_string($count) === true && preg_match('`\d+`', $count, $matches) === 1) {
return max((int) $matches[0], 1);
}

// MacOS / BSD fallback.
$count = shell_exec('sysctl -n hw.ncpu 2>/dev/null');
if (is_string($count) === true && preg_match('`\d+`', $count, $matches) === 1) {
return max((int) $matches[0], 1);
}
}

return 1;
}


/**
* Prepares the gathered config data for display.
*
Expand Down
1 change: 1 addition & 0 deletions src/Util/Help.php
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ private function getAllOptions()
'parallel' => [
'argument' => '--parallel=<processes>',
'description' => 'The number of files to be checked simultaneously. Defaults to 1 (no parallel processing).' . "\n"
. 'Set to "auto" to use a number of processes equal to the number of detected CPU cores.' . "\n"
. 'If enabled, this option only takes effect if the PHP PCNTL (Process Control) extension is available.',
],
'suffix' => [
Expand Down
104 changes: 104 additions & 0 deletions tests/Core/Config/ParallelTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php
/**
* Tests for the \PHP_CodeSniffer\Config parallel value.
*
* @copyright 2025 PHPCSStandards and contributors
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/HEAD/licence.txt BSD Licence
*/

namespace PHP_CodeSniffer\Tests\Core\Config;

use PHP_CodeSniffer\Config;
use PHP_CodeSniffer\Tests\Core\Config\AbstractRealConfigTestCase;

/**
* Tests for the \PHP_CodeSniffer\Config parallel value.
*
* @covers \PHP_CodeSniffer\Config::processLongArgument
* @covers \PHP_CodeSniffer\Config::restoreDefaults
*/
final class ParallelTest extends AbstractRealConfigTestCase
{


/**
* Test that parallel defaults to 1 when no value is provided.
*
* @return void
*/
public function testParallelDefault()
{
$config = new Config(['--standard=PSR1']);
$this->assertSame(1, $config->parallel);
}


/**
* Test that parallel can be set from a CLI argument.
*
* @return void
*/
public function testParallelCanBeSetFromCLI()
{
$_SERVER['argv'] = [
'phpcs',
'--standard=PSR1',
'--parallel=8',
];

$config = new Config();
$this->assertSame(8, $config->parallel);
}


/**
* Test that parallel can be set from a CodeSniffer.conf file.
*
* @return void
*/
public function testParallelCanBeSetFromConfFile()
{
$this->setStaticConfigProperty('configData', ['parallel' => '4']);

$config = new Config(['--standard=PSR1']);
$this->assertSame(4, $config->parallel);
}


/**
* Test that "auto" passed on the CLI resolves to a non-0 positive integer.
*
* @return void
*/
public function testParallelInputHandlingForAutoFromCLI()
{
$_SERVER['argv'] = [
'phpcs',
'--standard=PSR1',
'--parallel=auto',
];

$config = new Config();

// Can't test the exact value as "auto" will resolve differently depending on the machine running the tests.
$this->assertIsInt($config->parallel);
$this->assertGreaterThan(0, $config->parallel);
}


/**
* Test that "auto" set in the CodeSniffer.conf file resolves to a non-0 positive integer.
*
* @return void
*/
public function testParallelInputHandlingForAutoFromConfFile()
{
$this->setStaticConfigProperty('configData', ['parallel' => 'auto']);

$config = new Config(['--standard=PSR1']);

// Can't test the exact value as "auto" will resolve differently depending on the machine running the tests.
$this->assertIsInt($config->parallel);
$this->assertGreaterThan(0, $config->parallel);
}
}
Loading