Skip to content

Commit 524508c

Browse files
[Process] Allow merging env vars instead of replacing them
1 parent 5280d5d commit 524508c

File tree

4 files changed

+82
-32
lines changed

4 files changed

+82
-32
lines changed

src/Symfony/Component/Process/Process.php

+43-3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class Process implements \IteratorAggregate
7373
private $incrementalErrorOutputOffset = 0;
7474
private $tty;
7575
private $pty;
76+
private $inheritEnv = false;
7677

7778
private $useFileHandles = false;
7879
/** @var PipesInterface */
@@ -267,9 +268,22 @@ public function start(callable $callback = null)
267268
$descriptors = $this->getDescriptors();
268269

269270
$commandline = $this->commandline;
271+
$envline = '';
270272

273+
if (null !== $this->env && $this->inheritEnv) {
274+
if ('\\' === DIRECTORY_SEPARATOR && !empty($this->options['bypass_shell']) && !$this->enhanceWindowsCompatibility) {
275+
throw new LogicException('The "bypass_shell" option must be false to inherit environment variables while enhanced Windows compatibility is off');
276+
}
277+
$env = '\\' === DIRECTORY_SEPARATOR ? '(SET %s)&&' : 'export %s;';
278+
foreach ($this->env as $k => $v) {
279+
$envline .= sprintf($env, ProcessUtils::escapeArgument("$k=$v"));
280+
}
281+
$env = null;
282+
} else {
283+
$env = $this->env;
284+
}
271285
if ('\\' === DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
272-
$commandline = 'cmd /V:ON /E:ON /D /C "('.$commandline.')';
286+
$commandline = 'cmd /V:ON /E:ON /D /C "('.$envline.$commandline.')';
273287
foreach ($this->processPipes->getFiles() as $offset => $filename) {
274288
$commandline .= ' '.$offset.'>'.ProcessUtils::escapeArgument($filename);
275289
}
@@ -283,15 +297,17 @@ public function start(callable $callback = null)
283297
$descriptors[3] = array('pipe', 'w');
284298

285299
// See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
286-
$commandline = '{ ('.$this->commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
300+
$commandline = $envline.'{ ('.$this->commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
287301
$commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
288302

289303
// Workaround for the bug, when PTS functionality is enabled.
290304
// @see : https://bugs.php.net/69442
291305
$ptsWorkaround = fopen(__FILE__, 'r');
306+
} elseif ('' !== $envline) {
307+
$commandline = $envline.$commandline;
292308
}
293309

294-
$this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $this->env, $this->options);
310+
$this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $env, $this->options);
295311

296312
if (!is_resource($this->process)) {
297313
throw new RuntimeException('Unable to launch a new process.');
@@ -1197,6 +1213,30 @@ public function setEnhanceSigchildCompatibility($enhance)
11971213
return $this;
11981214
}
11991215

1216+
/**
1217+
* Sets whether environment variables will be inherited or not.
1218+
*
1219+
* @param bool $inheritEnv
1220+
*
1221+
* @return self The current Process instance
1222+
*/
1223+
public function inheritEnvironmentVariables($inheritEnv = true)
1224+
{
1225+
$this->inheritEnv = (bool) $inheritEnv;
1226+
1227+
return $this;
1228+
}
1229+
1230+
/**
1231+
* Returns whether environment variables will be inherited or not.
1232+
*
1233+
* @return bool
1234+
*/
1235+
public function areEnvironmentVariablesInherited()
1236+
{
1237+
return $this->inheritEnv;
1238+
}
1239+
12001240
/**
12011241
* Performs a check between the timeout definition and the time the process started.
12021242
*

src/Symfony/Component/Process/ProcessBuilder.php

+3-6
Original file line numberDiff line numberDiff line change
@@ -267,14 +267,11 @@ public function getProcess()
267267
$arguments = array_merge($this->prefix, $this->arguments);
268268
$script = implode(' ', array_map(array(__NAMESPACE__.'\\ProcessUtils', 'escapeArgument'), $arguments));
269269

270+
$process = new Process($script, $this->cwd, $this->env, $this->input, $this->timeout, $options);
271+
270272
if ($this->inheritEnv) {
271-
$env = array_replace($_ENV, $_SERVER, $this->env);
272-
} else {
273-
$env = $this->env;
273+
$process->inheritEnvironmentVariables();
274274
}
275-
276-
$process = new Process($script, $this->cwd, $env, $this->input, $this->timeout, $options);
277-
278275
if ($this->outputDisabled) {
279276
$process->disableOutput();
280277
}

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

+2-23
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,11 @@ class ProcessBuilderTest extends \PHPUnit_Framework_TestCase
1717
{
1818
public function testInheritEnvironmentVars()
1919
{
20-
$_ENV['MY_VAR_1'] = 'foo';
21-
2220
$proc = ProcessBuilder::create()
2321
->add('foo')
2422
->getProcess();
2523

26-
unset($_ENV['MY_VAR_1']);
27-
28-
$env = $proc->getEnv();
29-
$this->assertArrayHasKey('MY_VAR_1', $env);
30-
$this->assertEquals('foo', $env['MY_VAR_1']);
24+
$this->assertTrue($proc->areEnvironmentVariablesInherited());
3125
}
3226

3327
public function testAddEnvironmentVariables()
@@ -46,22 +40,7 @@ public function testAddEnvironmentVariables()
4640
;
4741

4842
$this->assertSame($env, $proc->getEnv());
49-
}
50-
51-
public function testProcessShouldInheritAndOverrideEnvironmentVars()
52-
{
53-
$_ENV['MY_VAR_1'] = 'foo';
54-
55-
$proc = ProcessBuilder::create()
56-
->setEnv('MY_VAR_1', 'bar')
57-
->add('foo')
58-
->getProcess();
59-
60-
unset($_ENV['MY_VAR_1']);
61-
62-
$env = $proc->getEnv();
63-
$this->assertArrayHasKey('MY_VAR_1', $env);
64-
$this->assertEquals('bar', $env['MY_VAR_1']);
43+
$this->assertFalse($proc->areEnvironmentVariablesInherited());
6544
}
6645

6746
/**

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

+34
Original file line numberDiff line numberDiff line change
@@ -1357,6 +1357,40 @@ public function testChainedProcesses()
13571357
$this->assertSame('456', $p2->getOutput());
13581358
}
13591359

1360+
public function testInheritEnvEnabled()
1361+
{
1362+
$process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('echo serialize($_SERVER);'), null, array('BAR' => 'BAZ'));
1363+
1364+
putenv('FOO=BAR');
1365+
1366+
$this->assertSame($process, $process->inheritEnvironmentVariables(1));
1367+
$this->assertTrue($process->areEnvironmentVariablesInherited());
1368+
1369+
$process->run();
1370+
1371+
$expected = array('BAR' => 'BAZ', 'FOO' => 'BAR');
1372+
$env = array_intersect_key(unserialize($process->getOutput()), $expected);
1373+
1374+
$this->assertSame($expected, $env);
1375+
}
1376+
1377+
public function testInheritEnvDisabled()
1378+
{
1379+
$process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('echo serialize($_SERVER);'), null, array('BAR' => 'BAZ'));
1380+
1381+
putenv('FOO=BAR');
1382+
1383+
$this->assertFalse($process->areEnvironmentVariablesInherited());
1384+
1385+
$process->run();
1386+
1387+
$expected = array('BAR' => 'BAZ', 'FOO' => 'BAR');
1388+
$env = array_intersect_key(unserialize($process->getOutput()), $expected);
1389+
unset($expected['FOO']);
1390+
1391+
$this->assertSame($expected, $env);
1392+
}
1393+
13601394
/**
13611395
* @param string $commandline
13621396
* @param null|string $cwd

0 commit comments

Comments
 (0)