Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c49cbb6

Browse files
author
Amrouche Hamza
committed
[Process] Allow writing portable "prepared" command lines
1 parent 0032368 commit c49cbb6

File tree

2 files changed

+89
-1
lines changed

2 files changed

+89
-1
lines changed

src/Symfony/Component/Process/Process.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,10 @@ public function start(callable $callback = null, array $env = array())
273273

274274
$options = array('suppress_errors' => true);
275275

276-
if ('\\' === DIRECTORY_SEPARATOR) {
276+
$windows = '\\' === DIRECTORY_SEPARATOR;
277+
$commandline = $this->replacePlaceholder($commandline, $windows, $env);
278+
279+
if ($windows) {
277280
$options['bypass_shell'] = true;
278281
$commandline = $this->prepareWindowsCommandLine($commandline, $env);
279282
} elseif (!$this->useFileHandles && $this->isSigchildEnabled()) {
@@ -1541,6 +1544,35 @@ private function escapeArgument(string $argument): string
15411544
return '"'.str_replace(array('"', '^', '%', '!', "\n"), array('""', '"^^"', '"^%"', '"^!"', '!LF!'), $argument).'"';
15421545
}
15431546

1547+
private function replacePlaceholder($commandLine, $windows, $env)
1548+
{
1549+
$toReplace = $windows ? array('!', '!') : array('$', '');
1550+
if (!preg_match_all('/\{([a-zA-Z0-9]+?)\}/', $commandLine, $matches)) {
1551+
return $commandLine;
1552+
}
1553+
1554+
$patterns = $replacements = array();
1555+
$isInEnv = false;
1556+
foreach ($matches as $match) {
1557+
$patterns[] = sprintf('/{%s}/', $match[0]);
1558+
$replacements[] = sprintf('%s%s%s', $toReplace[0], $match[0], $toReplace[1]);
1559+
if (isset($env[$match[0]])) {
1560+
$isInEnv = true;
1561+
unset($env[$match[0]]);
1562+
}
1563+
}
1564+
1565+
if (!$isInEnv) {
1566+
throw new InvalidArgumentException(sprintf('There are no passed env for the command line "%s", replacement cannot be done.', $commandLine));
1567+
}
1568+
1569+
if (!empty($env)) {
1570+
throw new InvalidArgumentException(sprintf('Placeholder%s "%s" %s exist.', count($env) > 1 ? 's' : '', implode(',', array_keys($env)), count($env) > 1 ? 'doesn\'t' : 'don\'t'));
1571+
}
1572+
1573+
return preg_replace($patterns, $replacements, $commandLine);
1574+
}
1575+
15441576
private function getDefaultEnv()
15451577
{
15461578
$env = getenv();

src/Symfony/Component/Process/Tests/ProcessTest.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,6 +1474,62 @@ public function provideEscapeArgument()
14741474
yield array('éÉèÈàÀöä');
14751475
}
14761476

1477+
public function testPreparedCommand()
1478+
{
1479+
$p = new Process('echo {abc}');
1480+
$p->run(null, array('abc' => 'ABC'));
1481+
1482+
$expected = <<<EOTXT
1483+
ABC\n
1484+
EOTXT;
1485+
$this->assertSame($expected, $p->getOutput());
1486+
}
1487+
1488+
/**
1489+
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
1490+
* @expectedExceptionMessage Placeholder "bcd" don't exist
1491+
*/
1492+
public function testPreparedCommandWithTooMuchEnv()
1493+
{
1494+
$p = new Process('echo {abc}');
1495+
$p->run(null, array('abc' => 'ABC', 'bcd' => 'ABC'));
1496+
1497+
$expected = <<<EOTXT
1498+
ABC\n
1499+
EOTXT;
1500+
$this->assertSame($expected, $p->getOutput());
1501+
}
1502+
1503+
/**
1504+
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
1505+
* @expectedExceptionMessage Placeholders "bcd,zaza" doesn't exist
1506+
*/
1507+
public function testPreparedCommandWithTwoMoreEnvs()
1508+
{
1509+
$p = new Process('echo {abc}');
1510+
$p->run(null, array('abc' => 'ABC', 'bcd' => 'ABC', 'zaza' => 'ABC'));
1511+
1512+
$expected = <<<EOTXT
1513+
ABC\n
1514+
EOTXT;
1515+
$this->assertSame($expected, $p->getOutput());
1516+
}
1517+
1518+
/**
1519+
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
1520+
* @expectedExceptionMessage There are no passed env for the command line "echo {abc}", replacement cannot be done.
1521+
*/
1522+
public function testPreparedCommandWithoutProvidedParam()
1523+
{
1524+
$p = new Process('echo {abc}');
1525+
$p->run(null, array('bcd' => 'ABC'));
1526+
1527+
$expected = <<<EOTXT
1528+
ABC
1529+
EOTXT;
1530+
$this->assertSame($expected, $p->getOutput());
1531+
}
1532+
14771533
public function testEnvArgument()
14781534
{
14791535
$env = array('FOO' => 'Foo', 'BAR' => 'Bar');

0 commit comments

Comments
 (0)