Skip to content

Commit c80f425

Browse files
authored
Merge pull request #75 from asgrim/adjust-timeouts-for-process-invokations
Adjust timeouts for invoked processes
2 parents eaf77ea + 6e527a2 commit c80f425

File tree

4 files changed

+84
-50
lines changed

4 files changed

+84
-50
lines changed

src/Building/UnixBuild.php

+20-10
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
use Php\Pie\Downloading\DownloadedPackage;
88
use Php\Pie\Platform\TargetPhp\PhpizePath;
99
use Php\Pie\Platform\TargetPlatform;
10+
use Php\Pie\Util\Process;
1011
use Symfony\Component\Console\Output\OutputInterface;
11-
use Symfony\Component\Process\Process;
1212

1313
use function count;
1414
use function file_exists;
@@ -18,6 +18,10 @@
1818
/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
1919
final class UnixBuild implements Build
2020
{
21+
private const PHPIZE_TIMEOUT_SECS = 60; // 1 minute
22+
private const CONFIGURE_TIMEOUT_SECS = 120; // 2 minutes
23+
private const MAKE_TIMEOUT_SECS = 600; // 10 minutes
24+
2125
/** {@inheritDoc} */
2226
public function __invoke(
2327
DownloadedPackage $downloadedPackage,
@@ -72,23 +76,29 @@ public function __invoke(
7276

7377
private function phpize(PhpizePath $phpize, DownloadedPackage $downloadedPackage): string
7478
{
75-
return (new Process([$phpize->phpizeBinaryPath], $downloadedPackage->extractedSourcePath))
76-
->mustRun()
77-
->getOutput();
79+
return Process::run(
80+
[$phpize->phpizeBinaryPath],
81+
$downloadedPackage->extractedSourcePath,
82+
self::PHPIZE_TIMEOUT_SECS,
83+
);
7884
}
7985

8086
/** @param list<non-empty-string> $configureOptions */
8187
private function configure(DownloadedPackage $downloadedPackage, array $configureOptions = []): string
8288
{
83-
return (new Process(['./configure', ...$configureOptions], $downloadedPackage->extractedSourcePath))
84-
->mustRun()
85-
->getOutput();
89+
return Process::run(
90+
['./configure', ...$configureOptions],
91+
$downloadedPackage->extractedSourcePath,
92+
self::CONFIGURE_TIMEOUT_SECS,
93+
);
8694
}
8795

8896
private function make(DownloadedPackage $downloadedPackage): string
8997
{
90-
return (new Process(['make'], $downloadedPackage->extractedSourcePath))
91-
->mustRun()
92-
->getOutput();
98+
return Process::run(
99+
['make'],
100+
$downloadedPackage->extractedSourcePath,
101+
self::MAKE_TIMEOUT_SECS,
102+
);
93103
}
94104
}

src/Installing/UnixInstall.php

+8-4
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
use Php\Pie\Downloading\DownloadedPackage;
88
use Php\Pie\ExtensionType;
99
use Php\Pie\Platform\TargetPlatform;
10+
use Php\Pie\Util\Process;
1011
use RuntimeException;
1112
use Symfony\Component\Console\Output\OutputInterface;
12-
use Symfony\Component\Process\Process;
1313

1414
use function array_unshift;
1515
use function file_exists;
@@ -19,6 +19,8 @@
1919
/** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */
2020
final class UnixInstall implements Install
2121
{
22+
private const MAKE_INSTALL_TIMEOUT_SECS = 60; // 1 minute
23+
2224
public function __invoke(DownloadedPackage $downloadedPackage, TargetPlatform $targetPlatform, OutputInterface $output): string
2325
{
2426
$targetExtensionPath = $targetPlatform->phpBinaryPath->extensionPath();
@@ -44,9 +46,11 @@ public function __invoke(DownloadedPackage $downloadedPackage, TargetPlatform $t
4446
array_unshift($makeInstallCommand, 'sudo');
4547
}
4648

47-
$makeInstallOutput = (new Process($makeInstallCommand, $downloadedPackage->extractedSourcePath))
48-
->mustRun()
49-
->getOutput();
49+
$makeInstallOutput = Process::run(
50+
$makeInstallCommand,
51+
$downloadedPackage->extractedSourcePath,
52+
self::MAKE_INSTALL_TIMEOUT_SECS,
53+
);
5054

5155
if ($output->isVeryVerbose()) {
5256
$output->writeln($makeInstallOutput);

src/Platform/TargetPhp/PhpBinaryPath.php

+18-36
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
use Composer\Util\Platform;
99
use Php\Pie\Platform\Architecture;
1010
use Php\Pie\Platform\OperatingSystem;
11+
use Php\Pie\Util\Process;
1112
use RuntimeException;
1213
use Symfony\Component\Process\PhpExecutableFinder;
13-
use Symfony\Component\Process\Process;
1414
use Webmozart\Assert\Assert;
1515

1616
use function array_combine;
@@ -58,9 +58,7 @@ private static function assertValidLookingPhpBinary(string $phpBinaryPath): void
5858

5959
// This is somewhat of a rudimentary check that the target PHP really is a PHP instance; not sure why you
6060
// WOULDN'T want to use a real PHP, but this should stop obvious hiccups at least (rather than for security)
61-
$testOutput = trim((new Process([$phpBinaryPath, '-r', 'echo "PHP";']))
62-
->mustRun()
63-
->getOutput());
61+
$testOutput = Process::run([$phpBinaryPath, '-r', 'echo "PHP";']);
6462

6563
if ($testOutput !== 'PHP') {
6664
throw Exception\InvalidPhpBinaryPath::fromInvalidPhpBinary($phpBinaryPath);
@@ -118,7 +116,7 @@ public function extensionPath(): string
118116
*/
119117
public function extensions(): array
120118
{
121-
$extVersionsRawJson = trim((new Process([
119+
$extVersionsList = Process::run([
122120
$this->phpBinaryPath,
123121
'-r',
124122
<<<'PHP'
@@ -141,13 +139,11 @@ static function ($k, $v) {
141139
$extVersions
142140
));
143141
PHP,
144-
]))
145-
->mustRun()
146-
->getOutput());
142+
]);
147143

148144
$pairs = array_map(
149145
static fn (string $row) => explode(':', $row),
150-
explode("\n", $extVersionsRawJson),
146+
explode("\n", $extVersionsList),
151147
);
152148

153149
return array_combine(
@@ -158,13 +154,11 @@ static function ($k, $v) {
158154

159155
public function operatingSystem(): OperatingSystem
160156
{
161-
$winOrNot = trim((new Process([
157+
$winOrNot = Process::run([
162158
$this->phpBinaryPath,
163159
'-r',
164160
'echo \\defined(\'PHP_WINDOWS_VERSION_BUILD\') ? \'win\' : \'not\';',
165-
]))
166-
->mustRun()
167-
->getOutput());
161+
]);
168162
Assert::stringNotEmpty($winOrNot, 'Could not determine PHP version');
169163

170164
return $winOrNot === 'win' ? OperatingSystem::Windows : OperatingSystem::NonWindows;
@@ -173,13 +167,11 @@ public function operatingSystem(): OperatingSystem
173167
/** @return non-empty-string */
174168
public function version(): string
175169
{
176-
$phpVersion = trim((new Process([
170+
$phpVersion = Process::run([
177171
$this->phpBinaryPath,
178172
'-r',
179173
'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION . "." . PHP_RELEASE_VERSION;',
180-
]))
181-
->mustRun()
182-
->getOutput());
174+
]);
183175
Assert::stringNotEmpty($phpVersion, 'Could not determine PHP version');
184176

185177
// normalizing the version will throw an exception if it is not a valid version
@@ -191,13 +183,11 @@ public function version(): string
191183
/** @return non-empty-string */
192184
public function majorMinorVersion(): string
193185
{
194-
$phpVersion = trim((new Process([
186+
$phpVersion = Process::run([
195187
$this->phpBinaryPath,
196188
'-r',
197189
'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;',
198-
]))
199-
->mustRun()
200-
->getOutput());
190+
]);
201191
Assert::stringNotEmpty($phpVersion, 'Could not determine PHP version');
202192

203193
// normalizing the version will throw an exception if it is not a valid version
@@ -208,27 +198,23 @@ public function majorMinorVersion(): string
208198

209199
public function machineType(): Architecture
210200
{
211-
$phpMachineType = trim((new Process([
201+
$phpMachineType = Process::run([
212202
$this->phpBinaryPath,
213203
'-r',
214204
'echo php_uname("m");',
215-
]))
216-
->mustRun()
217-
->getOutput());
205+
]);
218206
Assert::stringNotEmpty($phpMachineType, 'Could not determine PHP machine type');
219207

220208
return Architecture::parseArchitecture($phpMachineType);
221209
}
222210

223211
public function phpIntSize(): int
224212
{
225-
$phpIntSize = trim((new Process([
213+
$phpIntSize = Process::run([
226214
$this->phpBinaryPath,
227215
'-r',
228216
'echo PHP_INT_SIZE;',
229-
]))
230-
->mustRun()
231-
->getOutput());
217+
]);
232218
Assert::stringNotEmpty($phpIntSize, 'Could not fetch PHP_INT_SIZE');
233219
Assert::same($phpIntSize, (string) (int) $phpIntSize, 'PHP_INT_SIZE was not an integer processed %2$s from %s');
234220

@@ -238,12 +224,10 @@ public function phpIntSize(): int
238224
/** @return non-empty-string */
239225
public function phpinfo(): string
240226
{
241-
$phpInfo = trim((new Process([
227+
$phpInfo = Process::run([
242228
$this->phpBinaryPath,
243229
'-i',
244-
]))
245-
->mustRun()
246-
->getOutput());
230+
]);
247231

248232
Assert::stringNotEmpty($phpInfo, sprintf('Could not run phpinfo using %s', $this->phpBinaryPath));
249233

@@ -264,9 +248,7 @@ public function phpConfigPath(): string|null
264248
/** @param non-empty-string $phpConfig */
265249
public static function fromPhpConfigExecutable(string $phpConfig): self
266250
{
267-
$phpExecutable = trim((new Process([$phpConfig, '--php-binary']))
268-
->mustRun()
269-
->getOutput());
251+
$phpExecutable = Process::run([$phpConfig, '--php-binary']);
270252
Assert::stringNotEmpty($phpExecutable, 'Could not find path to PHP executable.');
271253

272254
self::assertValidLookingPhpBinary($phpExecutable);

src/Util/Process.php

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Php\Pie\Util;
6+
7+
use Symfony\Component\Process\Exception\ProcessFailedException;
8+
use Symfony\Component\Process\Process as SymfonyProcess;
9+
10+
use function trim;
11+
12+
final class Process
13+
{
14+
/** @psalm-suppress UnusedConstructor */
15+
private function __construct()
16+
{
17+
}
18+
19+
/**
20+
* Just a helper to invoke a Symfony Process command with a simplified API
21+
* for the common invocations we have in PIE.
22+
*
23+
* Things to note:
24+
* - uses mustRun (i.e. throws exception if command execution fails)
25+
* - very short timeout by default (5 seconds)
26+
* - output is trimmed
27+
*
28+
* @param list<string> $command
29+
*
30+
* @throws ProcessFailedException
31+
*/
32+
public static function run(array $command, string|null $workingDirectory = null, int|null $timeout = 5): string
33+
{
34+
return trim((new SymfonyProcess($command, $workingDirectory, timeout: $timeout))
35+
->mustRun()
36+
->getOutput());
37+
}
38+
}

0 commit comments

Comments
 (0)