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

Skip to content

Commit d1e4f48

Browse files
Amrouche Hamzanicolas-grekas
Amrouche Hamza
authored andcommitted
[Process] Allow writing portable "prepared" command lines
1 parent b0facfe commit d1e4f48

File tree

2 files changed

+57
-3
lines changed

2 files changed

+57
-3
lines changed

src/Symfony/Component/Process/Process.php

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,18 +258,21 @@ public function start(callable $callback = null, array $env = array())
258258
$this->hasCallback = null !== $callback;
259259
$descriptors = $this->getDescriptors();
260260

261+
if ($this->env) {
262+
$env += $this->env;
263+
}
264+
261265
if (is_array($commandline = $this->commandline)) {
262266
$commandline = implode(' ', array_map(array($this, 'escapeArgument'), $commandline));
263267

264268
if ('\\' !== DIRECTORY_SEPARATOR) {
265269
// exec is mandatory to deal with sending a signal to the process
266270
$commandline = 'exec '.$commandline;
267271
}
272+
} else {
273+
$commandline = $this->replacePlaceholders($commandline, $env);
268274
}
269275

270-
if ($this->env) {
271-
$env += $this->env;
272-
}
273276
$env += $this->getDefaultEnv();
274277

275278
$options = array('suppress_errors' => true);
@@ -1549,6 +1552,29 @@ private function escapeArgument(string $argument): string
15491552
return '"'.str_replace(array('"', '^', '%', '!', "\n"), array('""', '"^^"', '"^%"', '"^!"', '!LF!'), $argument).'"';
15501553
}
15511554

1555+
private function replacePlaceholders(string $commandline, array $env)
1556+
{
1557+
$pattern = '\\' === DIRECTORY_SEPARATOR ? '!%s!' : '${%s}';
1558+
1559+
return preg_replace_callback('/\{\{ ?([_a-zA-Z0-9]++) ?\}\}/', function ($m) use ($pattern, $commandline, $env) {
1560+
if (!isset($env[$m[1]]) || false === $env[$m[1]]) {
1561+
foreach ($env as $k => $v) {
1562+
if (false === $v) {
1563+
unset($env[$k]);
1564+
}
1565+
}
1566+
if (!$env) {
1567+
throw new InvalidArgumentException(sprintf('Invalid command line "%s": no values provided for any placeholders.', $commandline));
1568+
}
1569+
$env = implode('", "', array_keys($env));
1570+
1571+
throw new InvalidArgumentException(sprintf('Invalid command line "%s": no value provided for placeholder "%s", did you mean "%s"?', $commandline, $m[1], $env));
1572+
}
1573+
1574+
return sprintf($pattern, $m[1]);
1575+
}, $commandline);
1576+
}
1577+
15521578
private function getDefaultEnv()
15531579
{
15541580
$env = array();

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

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

1477+
public function testPreparedCommand()
1478+
{
1479+
$p = new Process('echo {{ abc }}DEF');
1480+
$p->run(null, array('abc' => 'ABC'));
1481+
1482+
$this->assertSame('ABCDEF', rtrim($p->getOutput()));
1483+
}
1484+
1485+
/**
1486+
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
1487+
* @expectedExceptionMessage Invalid command line "echo {{ abc }}": no value provided for placeholder "abc", did you mean "bcd"?
1488+
*/
1489+
public function testPreparedCommandWithMissingValue()
1490+
{
1491+
$p = new Process('echo {{ abc }}');
1492+
$p->run(null, array('bcd' => 'BCD'));
1493+
}
1494+
1495+
/**
1496+
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
1497+
* @expectedExceptionMessage Invalid command line "echo {{ abc }}": no values provided for any placeholders.
1498+
*/
1499+
public function testPreparedCommandWithNoValues()
1500+
{
1501+
$p = new Process('echo {{ abc }}');
1502+
$p->run();
1503+
}
1504+
14771505
public function testEnvArgument()
14781506
{
14791507
$env = array('FOO' => 'Foo', 'BAR' => 'Bar');

0 commit comments

Comments
 (0)