feature #24763 [Process] Allow writing portable "prepared" command lines (Simperfit)
This PR was merged into the 4.1-dev branch.
Discussion
----------
[Process] Allow writing portable "prepared" command lines
| Q | A
| ------------- | ---
| Branch? | 4.1
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #23778
| License | MIT
| Doc PR | symfony/symfony-docs#9295
This give the opportunity to create process commands that allow to changes only the values instead of changing the code.
Commits
-------
d1e4f489d1
[Process] Allow writing portable "prepared" command lines
This commit is contained in:
commit
136408937b
@ -258,6 +258,10 @@ class Process implements \IteratorAggregate
|
|||||||
$this->hasCallback = null !== $callback;
|
$this->hasCallback = null !== $callback;
|
||||||
$descriptors = $this->getDescriptors();
|
$descriptors = $this->getDescriptors();
|
||||||
|
|
||||||
|
if ($this->env) {
|
||||||
|
$env += $this->env;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_array($commandline = $this->commandline)) {
|
if (is_array($commandline = $this->commandline)) {
|
||||||
$commandline = implode(' ', array_map(array($this, 'escapeArgument'), $commandline));
|
$commandline = implode(' ', array_map(array($this, 'escapeArgument'), $commandline));
|
||||||
|
|
||||||
@ -265,11 +269,10 @@ class Process implements \IteratorAggregate
|
|||||||
// exec is mandatory to deal with sending a signal to the process
|
// exec is mandatory to deal with sending a signal to the process
|
||||||
$commandline = 'exec '.$commandline;
|
$commandline = 'exec '.$commandline;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$commandline = $this->replacePlaceholders($commandline, $env);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->env) {
|
|
||||||
$env += $this->env;
|
|
||||||
}
|
|
||||||
$env += $this->getDefaultEnv();
|
$env += $this->getDefaultEnv();
|
||||||
|
|
||||||
$options = array('suppress_errors' => true);
|
$options = array('suppress_errors' => true);
|
||||||
@ -1549,6 +1552,29 @@ class Process implements \IteratorAggregate
|
|||||||
return '"'.str_replace(array('"', '^', '%', '!', "\n"), array('""', '"^^"', '"^%"', '"^!"', '!LF!'), $argument).'"';
|
return '"'.str_replace(array('"', '^', '%', '!', "\n"), array('""', '"^^"', '"^%"', '"^!"', '!LF!'), $argument).'"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function replacePlaceholders(string $commandline, array $env)
|
||||||
|
{
|
||||||
|
$pattern = '\\' === DIRECTORY_SEPARATOR ? '!%s!' : '${%s}';
|
||||||
|
|
||||||
|
return preg_replace_callback('/\{\{ ?([_a-zA-Z0-9]++) ?\}\}/', function ($m) use ($pattern, $commandline, $env) {
|
||||||
|
if (!isset($env[$m[1]]) || false === $env[$m[1]]) {
|
||||||
|
foreach ($env as $k => $v) {
|
||||||
|
if (false === $v) {
|
||||||
|
unset($env[$k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$env) {
|
||||||
|
throw new InvalidArgumentException(sprintf('Invalid command line "%s": no values provided for any placeholders.', $commandline));
|
||||||
|
}
|
||||||
|
$env = implode('", "', array_keys($env));
|
||||||
|
|
||||||
|
throw new InvalidArgumentException(sprintf('Invalid command line "%s": no value provided for placeholder "%s", did you mean "%s"?', $commandline, $m[1], $env));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf($pattern, $m[1]);
|
||||||
|
}, $commandline);
|
||||||
|
}
|
||||||
|
|
||||||
private function getDefaultEnv()
|
private function getDefaultEnv()
|
||||||
{
|
{
|
||||||
$env = array();
|
$env = array();
|
||||||
|
@ -1474,6 +1474,34 @@ EOTXT;
|
|||||||
yield array('éÉèÈàÀöä');
|
yield array('éÉèÈàÀöä');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testPreparedCommand()
|
||||||
|
{
|
||||||
|
$p = new Process('echo {{ abc }}DEF');
|
||||||
|
$p->run(null, array('abc' => 'ABC'));
|
||||||
|
|
||||||
|
$this->assertSame('ABCDEF', rtrim($p->getOutput()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Invalid command line "echo {{ abc }}": no value provided for placeholder "abc", did you mean "bcd"?
|
||||||
|
*/
|
||||||
|
public function testPreparedCommandWithMissingValue()
|
||||||
|
{
|
||||||
|
$p = new Process('echo {{ abc }}');
|
||||||
|
$p->run(null, array('bcd' => 'BCD'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage Invalid command line "echo {{ abc }}": no values provided for any placeholders.
|
||||||
|
*/
|
||||||
|
public function testPreparedCommandWithNoValues()
|
||||||
|
{
|
||||||
|
$p = new Process('echo {{ abc }}');
|
||||||
|
$p->run();
|
||||||
|
}
|
||||||
|
|
||||||
public function testEnvArgument()
|
public function testEnvArgument()
|
||||||
{
|
{
|
||||||
$env = array('FOO' => 'Foo', 'BAR' => 'Bar');
|
$env = array('FOO' => 'Foo', 'BAR' => 'Bar');
|
||||||
|
Reference in New Issue
Block a user