Skip to content

Commit

Permalink
Merge branch '2.1' into 2.2
Browse files Browse the repository at this point in the history
* 2.1:
  [HttpKernel] tweaked previous merge
  #7531: [HttpKernel][Config] FileLocator adds NULL as global resource path
  Fix autocompletion of command names when namespaces conflict
  Fix timeout in Process::stop method
  fixed CS
  Round stream_select fifth argument up.
  Fix Process timeout

Conflicts:
	src/Symfony/Component/Process/Process.php
	src/Symfony/Component/Process/ProcessBuilder.php
  • Loading branch information
fabpot committed Apr 7, 2013
2 parents 689653f + 12b7073 commit 2965a52
Show file tree
Hide file tree
Showing 8 changed files with 232 additions and 38 deletions.
42 changes: 21 additions & 21 deletions src/Symfony/Component/Console/Application.php
Expand Up @@ -492,20 +492,24 @@ public function getNamespaces()
*/
public function findNamespace($namespace)
{
$allNamespaces = array();
foreach ($this->getNamespaces() as $n) {
$allNamespaces[$n] = explode(':', $n);
}

$found = array();
$allNamespaces = $this->getNamespaces();
$found = '';
foreach (explode(':', $namespace) as $i => $part) {
$abbrevs = static::getAbbreviations(array_unique(array_values(array_filter(array_map(function ($p) use ($i) { return isset($p[$i]) ? $p[$i] : ''; }, $allNamespaces)))));
// select sub-namespaces matching the current namespace we found
$namespaces = array();
foreach ($allNamespaces as $n) {
if ('' === $found || 0 === strpos($n, $found)) {
$namespaces[$n] = explode(':', $n);
}
}

$abbrevs = static::getAbbreviations(array_unique(array_values(array_filter(array_map(function ($p) use ($i) { return isset($p[$i]) ? $p[$i] : ''; }, $namespaces)))));

if (!isset($abbrevs[$part])) {
$message = sprintf('There are no commands defined in the "%s" namespace.', $namespace);

if (1 <= $i) {
$part = implode(':', $found).':'.$part;
$part = $found.':'.$part;
}

if ($alternatives = $this->findAlternativeNamespace($part, $abbrevs)) {
Expand All @@ -521,14 +525,19 @@ public function findNamespace($namespace)
throw new \InvalidArgumentException($message);
}

// there are multiple matches, but $part is an exact match of one of them so we select it
if (in_array($part, $abbrevs[$part])) {
$abbrevs[$part] = array($part);
}

if (count($abbrevs[$part]) > 1) {
throw new \InvalidArgumentException(sprintf('The namespace "%s" is ambiguous (%s).', $namespace, $this->getAbbreviationSuggestions($abbrevs[$part])));
}

$found[] = $abbrevs[$part][0];
$found .= $found ? ':' . $abbrevs[$part][0] : $abbrevs[$part][0];
}

return implode(':', $found);
return $found;
}

/**
Expand Down Expand Up @@ -651,21 +660,12 @@ public static function getAbbreviations($names)
{
$abbrevs = array();
foreach ($names as $name) {
for ($len = strlen($name) - 1; $len > 0; --$len) {
for ($len = strlen($name); $len > 0; --$len) {
$abbrev = substr($name, 0, $len);
if (!isset($abbrevs[$abbrev])) {
$abbrevs[$abbrev] = array($name);
} else {
$abbrevs[$abbrev][] = $name;
}
$abbrevs[$abbrev][] = $name;
}
}

// Non-abbreviations always get entered, even if they aren't unique
foreach ($names as $name) {
$abbrevs[$name] = array($name);
}

return $abbrevs;
}

Expand Down
10 changes: 10 additions & 0 deletions src/Symfony/Component/Console/Tests/ApplicationTest.php
Expand Up @@ -345,6 +345,16 @@ public function testFindAlternativeNamespace()
}
}

public function testFindNamespaceDoesNotFailOnDeepSimilarNamespaces()
{
$application = $this->getMock('Symfony\Component\Console\Application', array('getNamespaces'));
$application->expects($this->once())
->method('getNamespaces')
->will($this->returnValue(array('foo:sublong', 'bar:sub')));

$this->assertEquals('foo:sublong', $application->findNamespace('f:sub'));
}

public function testSetCatchExceptions()
{
$application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
Expand Down
10 changes: 6 additions & 4 deletions src/Symfony/Component/HttpKernel/Config/FileLocator.php
Expand Up @@ -28,14 +28,16 @@ class FileLocator extends BaseFileLocator
* Constructor.
*
* @param KernelInterface $kernel A KernelInterface instance
* @param string $path The path the global resource directory
* @param string|array $paths A path or an array of paths where to look for resources
* @param null|string $path The path the global resource directory
* @param array $paths An array of paths where to look for resources
*/
public function __construct(KernelInterface $kernel, $path = null, array $paths = array())
{
$this->kernel = $kernel;
$this->path = $path;
$paths[] = $path;
if (null !== $path) {
$this->path = $path;
$paths[] = $path;
}

parent::__construct($paths);
}
Expand Down
47 changes: 47 additions & 0 deletions src/Symfony/Component/HttpKernel/Tests/Config/FileLocatorTest.php
@@ -0,0 +1,47 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\HttpKernel\Tests\Config;

use Symfony\Component\HttpKernel\Config\FileLocator;

class FileLocatorTest extends \PHPUnit_Framework_TestCase
{
public function testLocate()
{
$kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
$kernel
->expects($this->atLeastOnce())
->method('locateResource')
->with('@BundleName/some/path', null, true)
->will($this->returnValue('/bundle-name/some/path'));
$locator = new FileLocator($kernel);
$this->assertEquals('/bundle-name/some/path', $locator->locate('@BundleName/some/path'));

$kernel
->expects($this->never())
->method('locateResource');
$this->setExpectedException('LogicException');
$locator->locate('/some/path');
}

public function testLocateWithGlobalResourcePath()
{
$kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
$kernel
->expects($this->atLeastOnce())
->method('locateResource')
->with('@BundleName/some/path', '/global/resource/path', false);

$locator = new FileLocator($kernel, '/global/resource/path');
$locator->locate('@BundleName/some/path', null, false);
}
}
51 changes: 41 additions & 10 deletions src/Symfony/Component/Process/Process.php
Expand Up @@ -35,10 +35,14 @@ class Process
const STDOUT = 1;
const STDERR = 2;

// Timeout Precision in seconds.
const TIMEOUT_PRECISION = 0.2;

private $commandline;
private $cwd;
private $env;
private $stdin;
private $starttime;
private $timeout;
private $options;
private $exitcode;
Expand Down Expand Up @@ -228,6 +232,7 @@ public function start($callback = null)
throw new RuntimeException('Process is already running');
}

$this->starttime = microtime(true);
$this->stdout = '';
$this->stderr = '';
$this->incrementalOutputOffset = 0;
Expand Down Expand Up @@ -304,7 +309,7 @@ public function start($callback = null)
$w = $writePipes;
$e = null;

$n = @stream_select($r, $w, $e, $this->timeout);
$n = @stream_select($r, $w, $e, 0, ceil(static::TIMEOUT_PRECISION * 1E6));

if (false === $n) {
break;
Expand Down Expand Up @@ -337,6 +342,8 @@ public function start($callback = null)
unset($this->pipes[$type]);
}
}

$this->checkTimeout();
}

$this->updateStatus();
Expand All @@ -360,7 +367,7 @@ public function start($callback = null)
public function restart($callback = null)
{
if ($this->isRunning()) {
throw new \RuntimeException('Process is already running');
throw new RuntimeException('Process is already running');
}

$process = clone $this;
Expand Down Expand Up @@ -391,13 +398,15 @@ public function wait($callback = null)
if (defined('PHP_WINDOWS_VERSION_BUILD') && $this->fileHandles) {
$this->processFileHandles($callback, !$this->pipes);
}
$this->checkTimeout();

if ($this->pipes) {
$r = $this->pipes;
$w = null;
$e = null;

if (false === $n = @stream_select($r, $w, $e, $this->timeout)) {
// let's have a look if something changed in streams
if (false === $n = @stream_select($r, $w, $e, 0, ceil(static::TIMEOUT_PRECISION * 1E6))) {
$lastError = error_get_last();

// stream_select returns false when the `select` system call is interrupted by an incoming signal
Expand All @@ -407,10 +416,10 @@ public function wait($callback = null)

continue;
}
if (0 === $n) {
proc_terminate($this->process);

throw new RuntimeException('The process timed out.');
// nothing has changed
if (0 === $n) {
continue;
}

foreach ($r as $pipe) {
Expand Down Expand Up @@ -712,7 +721,7 @@ public function getStatus()
*/
public function stop($timeout = 10)
{
$timeoutMicro = (int) $timeout*10E6;
$timeoutMicro = (int) $timeout*1E6;
if ($this->isRunning()) {
proc_terminate($this->process);
$time = 0;
Expand All @@ -721,6 +730,10 @@ public function stop($timeout = 10)
usleep(1000);
}

if (!defined('PHP_WINDOWS_VERSION_BUILD') && $this->isRunning()) {
proc_terminate($this->process, SIGKILL);
}

foreach ($this->pipes as $pipe) {
fclose($pipe);
}
Expand Down Expand Up @@ -800,7 +813,7 @@ public function getTimeout()
*
* To disable the timeout, set this value to null.
*
* @param integer|null $timeout The timeout in seconds
* @param float|null $timeout The timeout in seconds
*
* @return self The current Process instance
*
Expand All @@ -814,10 +827,10 @@ public function setTimeout($timeout)
return $this;
}

$timeout = (integer) $timeout;
$timeout = (float) $timeout;

if ($timeout < 0) {
throw new InvalidArgumentException('The timeout value must be a valid positive integer.');
throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
}

$this->timeout = $timeout;
Expand Down Expand Up @@ -982,6 +995,24 @@ public function setEnhanceSigchildCompatibility($enhance)
return $this;
}

/**
* Performs a check between the timeout definition and the time the process
* started
*
* In case you run a background process (with the start method), you should
* trigger this method regularly to ensure the process timeout
*
* @throws RuntimeException In case the timeout was reached
*/
public function checkTimeout()
{
if (0 < $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
$this->stop(0);

throw new RuntimeException('The process timed-out.');
}
}

/**
* Builds up the callback used by wait().
*
Expand Down
6 changes: 3 additions & 3 deletions src/Symfony/Component/Process/ProcessBuilder.php
Expand Up @@ -103,7 +103,7 @@ public function setInput($stdin)
*
* To disable the timeout, set this value to null.
*
* @param integer|null
* @param float|null
*
* @return ProcessBuilder
*
Expand All @@ -117,10 +117,10 @@ public function setTimeout($timeout)
return $this;
}

$timeout = (integer) $timeout;
$timeout = (float) $timeout;

if ($timeout < 0) {
throw new InvalidArgumentException('The timeout value must be a valid positive integer.');
throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
}

$this->timeout = $timeout;
Expand Down

0 comments on commit 2965a52

Please sign in to comment.