Merge pull request #4827 from curry684/issue-4203
Added more graceful warning suppression utilitypull/4834/head
commit
5c944d45ac
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
namespace Composer\Autoload;
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
use Composer\Util\Silencer;
|
||||||
use Symfony\Component\Finder\Finder;
|
use Symfony\Component\Finder\Finder;
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ class ClassMapGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$contents = @php_strip_whitespace($path);
|
$contents = Silencer::call('php_strip_whitespace', $path);
|
||||||
if (!$contents) {
|
if (!$contents) {
|
||||||
if (!file_exists($path)) {
|
if (!file_exists($path)) {
|
||||||
throw new \Exception('File does not exist');
|
throw new \Exception('File does not exist');
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer;
|
||||||
|
|
||||||
use Composer\IO\IOInterface;
|
use Composer\IO\IOInterface;
|
||||||
use Composer\Util\Filesystem;
|
use Composer\Util\Filesystem;
|
||||||
|
use Composer\Util\Silencer;
|
||||||
use Symfony\Component\Finder\Finder;
|
use Symfony\Component\Finder\Finder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,7 +45,7 @@ class Cache
|
||||||
$this->filesystem = $filesystem ?: new Filesystem();
|
$this->filesystem = $filesystem ?: new Filesystem();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(!is_dir($this->root) && !@mkdir($this->root, 0777, true))
|
(!is_dir($this->root) && !Silencer::call('mkdir', $this->root, 0777, true))
|
||||||
|| !is_writable($this->root)
|
|| !is_writable($this->root)
|
||||||
) {
|
) {
|
||||||
$this->io->writeError('<warning>Cannot create cache directory ' . $this->root . ', or directory is not writable. Proceeding without cache</warning>');
|
$this->io->writeError('<warning>Cannot create cache directory ' . $this->root . ', or directory is not writable. Proceeding without cache</warning>');
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
namespace Composer\Command;
|
namespace Composer\Command;
|
||||||
|
|
||||||
|
use Composer\Util\Silencer;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
@ -142,7 +143,7 @@ EOT
|
||||||
? ($this->config->get('home') . '/config.json')
|
? ($this->config->get('home') . '/config.json')
|
||||||
: ($input->getOption('file') ?: trim(getenv('COMPOSER')) ?: 'composer.json');
|
: ($input->getOption('file') ?: trim(getenv('COMPOSER')) ?: 'composer.json');
|
||||||
|
|
||||||
// create global composer.json if this was invoked using `composer global config`
|
// Create global composer.json if this was invoked using `composer global config`
|
||||||
if ($configFile === 'composer.json' && !file_exists($configFile) && realpath(getcwd()) === realpath($this->config->get('home'))) {
|
if ($configFile === 'composer.json' && !file_exists($configFile) && realpath(getcwd()) === realpath($this->config->get('home'))) {
|
||||||
file_put_contents($configFile, "{\n}\n");
|
file_put_contents($configFile, "{\n}\n");
|
||||||
}
|
}
|
||||||
|
@ -157,16 +158,16 @@ EOT
|
||||||
$this->authConfigFile = new JsonFile($authConfigFile, null, $io);
|
$this->authConfigFile = new JsonFile($authConfigFile, null, $io);
|
||||||
$this->authConfigSource = new JsonConfigSource($this->authConfigFile, true);
|
$this->authConfigSource = new JsonConfigSource($this->authConfigFile, true);
|
||||||
|
|
||||||
// initialize the global file if it's not there
|
// Initialize the global file if it's not there, ignoring any warnings or notices
|
||||||
if ($input->getOption('global') && !$this->configFile->exists()) {
|
if ($input->getOption('global') && !$this->configFile->exists()) {
|
||||||
touch($this->configFile->getPath());
|
touch($this->configFile->getPath());
|
||||||
$this->configFile->write(array('config' => new \ArrayObject));
|
$this->configFile->write(array('config' => new \ArrayObject));
|
||||||
@chmod($this->configFile->getPath(), 0600);
|
Silencer::call('chmod', $this->configFile->getPath(), 0600);
|
||||||
}
|
}
|
||||||
if ($input->getOption('global') && !$this->authConfigFile->exists()) {
|
if ($input->getOption('global') && !$this->authConfigFile->exists()) {
|
||||||
touch($this->authConfigFile->getPath());
|
touch($this->authConfigFile->getPath());
|
||||||
$this->authConfigFile->write(array('http-basic' => new \ArrayObject, 'github-oauth' => new \ArrayObject, 'gitlab-oauth' => new \ArrayObject));
|
$this->authConfigFile->write(array('http-basic' => new \ArrayObject, 'github-oauth' => new \ArrayObject, 'gitlab-oauth' => new \ArrayObject));
|
||||||
@chmod($this->authConfigFile->getPath(), 0600);
|
Silencer::call('chmod', $this->authConfigFile->getPath(), 0600);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->configFile->exists()) {
|
if (!$this->configFile->exists()) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ use Composer\Repository\CompositeRepository;
|
||||||
use Composer\Repository\FilesystemRepository;
|
use Composer\Repository\FilesystemRepository;
|
||||||
use Composer\Repository\InstalledFilesystemRepository;
|
use Composer\Repository\InstalledFilesystemRepository;
|
||||||
use Composer\Script\ScriptEvents;
|
use Composer\Script\ScriptEvents;
|
||||||
|
use Composer\Util\Silencer;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
@ -224,10 +225,10 @@ EOT
|
||||||
chdir($oldCwd);
|
chdir($oldCwd);
|
||||||
$vendorComposerDir = $composer->getConfig()->get('vendor-dir').'/composer';
|
$vendorComposerDir = $composer->getConfig()->get('vendor-dir').'/composer';
|
||||||
if (is_dir($vendorComposerDir) && $fs->isDirEmpty($vendorComposerDir)) {
|
if (is_dir($vendorComposerDir) && $fs->isDirEmpty($vendorComposerDir)) {
|
||||||
@rmdir($vendorComposerDir);
|
Silencer::call('rmdir', $vendorComposerDir);
|
||||||
$vendorDir = $composer->getConfig()->get('vendor-dir');
|
$vendorDir = $composer->getConfig()->get('vendor-dir');
|
||||||
if (is_dir($vendorDir) && $fs->isDirEmpty($vendorDir)) {
|
if (is_dir($vendorDir) && $fs->isDirEmpty($vendorDir)) {
|
||||||
@rmdir($vendorDir);
|
Silencer::call('rmdir', $vendorDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer\Config;
|
||||||
|
|
||||||
use Composer\Json\JsonFile;
|
use Composer\Json\JsonFile;
|
||||||
use Composer\Json\JsonManipulator;
|
use Composer\Json\JsonManipulator;
|
||||||
|
use Composer\Util\Silencer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSON Configuration Source
|
* JSON Configuration Source
|
||||||
|
@ -173,7 +174,7 @@ class JsonConfigSource implements ConfigSourceInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($newFile) {
|
if ($newFile) {
|
||||||
@chmod($this->file->getPath(), 0600);
|
Silencer::call('chmod', $this->file->getPath(), 0600);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
namespace Composer\Console;
|
namespace Composer\Console;
|
||||||
|
|
||||||
|
use Composer\Util\Silencer;
|
||||||
use Symfony\Component\Console\Application as BaseApplication;
|
use Symfony\Component\Console\Application as BaseApplication;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
@ -64,7 +65,7 @@ class Application extends BaseApplication
|
||||||
}
|
}
|
||||||
|
|
||||||
if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) {
|
if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) {
|
||||||
date_default_timezone_set(@date_default_timezone_get());
|
date_default_timezone_set(Silencer::call('date_default_timezone_get'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$shutdownRegistered) {
|
if (!$shutdownRegistered) {
|
||||||
|
@ -203,21 +204,23 @@ class Application extends BaseApplication
|
||||||
{
|
{
|
||||||
$io = $this->getIO();
|
$io = $this->getIO();
|
||||||
|
|
||||||
|
Silencer::suppress();
|
||||||
try {
|
try {
|
||||||
$composer = $this->getComposer(false, true);
|
$composer = $this->getComposer(false, true);
|
||||||
if ($composer) {
|
if ($composer) {
|
||||||
$config = $composer->getConfig();
|
$config = $composer->getConfig();
|
||||||
|
|
||||||
$minSpaceFree = 1024 * 1024;
|
$minSpaceFree = 1024 * 1024;
|
||||||
if ((($df = @disk_free_space($dir = $config->get('home'))) !== false && $df < $minSpaceFree)
|
if ((($df = disk_free_space($dir = $config->get('home'))) !== false && $df < $minSpaceFree)
|
||||||
|| (($df = @disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree)
|
|| (($df = disk_free_space($dir = $config->get('vendor-dir'))) !== false && $df < $minSpaceFree)
|
||||||
|| (($df = @disk_free_space($dir = sys_get_temp_dir())) !== false && $df < $minSpaceFree)
|
|| (($df = disk_free_space($dir = sys_get_temp_dir())) !== false && $df < $minSpaceFree)
|
||||||
) {
|
) {
|
||||||
$io->writeError('<error>The disk hosting '.$dir.' is full, this may be the cause of the following exception</error>');
|
$io->writeError('<error>The disk hosting '.$dir.' is full, this may be the cause of the following exception</error>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
}
|
}
|
||||||
|
Silencer::restore();
|
||||||
|
|
||||||
if (defined('PHP_WINDOWS_VERSION_BUILD') && false !== strpos($exception->getMessage(), 'The system cannot find the path specified')) {
|
if (defined('PHP_WINDOWS_VERSION_BUILD') && false !== strpos($exception->getMessage(), 'The system cannot find the path specified')) {
|
||||||
$io->writeError('<error>The following exception may be caused by a stale entry in your cmd.exe AutoRun</error>');
|
$io->writeError('<error>The following exception may be caused by a stale entry in your cmd.exe AutoRun</error>');
|
||||||
|
|
|
@ -22,6 +22,7 @@ use Composer\Repository\WritableRepositoryInterface;
|
||||||
use Composer\Util\Filesystem;
|
use Composer\Util\Filesystem;
|
||||||
use Composer\Util\ProcessExecutor;
|
use Composer\Util\ProcessExecutor;
|
||||||
use Composer\Util\RemoteFilesystem;
|
use Composer\Util\RemoteFilesystem;
|
||||||
|
use Composer\Util\Silencer;
|
||||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||||
use Composer\EventDispatcher\EventDispatcher;
|
use Composer\EventDispatcher\EventDispatcher;
|
||||||
use Composer\Autoload\AutoloadGenerator;
|
use Composer\Autoload\AutoloadGenerator;
|
||||||
|
@ -163,9 +164,9 @@ class Factory
|
||||||
foreach ($dirs as $dir) {
|
foreach ($dirs as $dir) {
|
||||||
if (!file_exists($dir . '/.htaccess')) {
|
if (!file_exists($dir . '/.htaccess')) {
|
||||||
if (!is_dir($dir)) {
|
if (!is_dir($dir)) {
|
||||||
@mkdir($dir, 0777, true);
|
Silencer::call('mkdir', $dir, 0777, true);
|
||||||
}
|
}
|
||||||
@file_put_contents($dir . '/.htaccess', 'Deny from all');
|
Silencer::call('file_put_contents', $dir . '/.htaccess', 'Deny from all');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ use Composer\Repository\InstalledRepositoryInterface;
|
||||||
use Composer\Package\PackageInterface;
|
use Composer\Package\PackageInterface;
|
||||||
use Composer\Util\Filesystem;
|
use Composer\Util\Filesystem;
|
||||||
use Composer\Util\ProcessExecutor;
|
use Composer\Util\ProcessExecutor;
|
||||||
|
use Composer\Util\Silencer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Package installation manager.
|
* Package installation manager.
|
||||||
|
@ -130,7 +131,7 @@ class LibraryInstaller implements InstallerInterface
|
||||||
if (strpos($package->getName(), '/')) {
|
if (strpos($package->getName(), '/')) {
|
||||||
$packageVendorDir = dirname($downloadPath);
|
$packageVendorDir = dirname($downloadPath);
|
||||||
if (is_dir($packageVendorDir) && $this->filesystem->isDirEmpty($packageVendorDir)) {
|
if (is_dir($packageVendorDir) && $this->filesystem->isDirEmpty($packageVendorDir)) {
|
||||||
@rmdir($packageVendorDir);
|
Silencer::call('rmdir', $packageVendorDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,7 +234,7 @@ class LibraryInstaller implements InstallerInterface
|
||||||
// likely leftover from a previous install, make sure
|
// likely leftover from a previous install, make sure
|
||||||
// that the target is still executable in case this
|
// that the target is still executable in case this
|
||||||
// is a fresh install of the vendor.
|
// is a fresh install of the vendor.
|
||||||
@chmod($link, 0777 & ~umask());
|
Silencer::call('chmod', $link, 0777 & ~umask());
|
||||||
}
|
}
|
||||||
$this->io->writeError(' Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file');
|
$this->io->writeError(' Skipped installation of bin '.$bin.' for package '.$package->getName().': name conflicts with an existing file');
|
||||||
continue;
|
continue;
|
||||||
|
@ -248,7 +249,7 @@ class LibraryInstaller implements InstallerInterface
|
||||||
} elseif ($this->binCompat === "full") {
|
} elseif ($this->binCompat === "full") {
|
||||||
$this->installFullBinaries($binPath, $link, $bin, $package);
|
$this->installFullBinaries($binPath, $link, $bin, $package);
|
||||||
}
|
}
|
||||||
@chmod($link, 0777 & ~umask());
|
Silencer::call('chmod', $link, 0777 & ~umask());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,7 +299,7 @@ class LibraryInstaller implements InstallerInterface
|
||||||
|
|
||||||
// attempt removing the bin dir in case it is left empty
|
// attempt removing the bin dir in case it is left empty
|
||||||
if ((is_dir($this->binDir)) && ($this->filesystem->isDirEmpty($this->binDir))) {
|
if ((is_dir($this->binDir)) && ($this->filesystem->isDirEmpty($this->binDir))) {
|
||||||
@rmdir($this->binDir);
|
Silencer::call('rmdir', $this->binDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -886,7 +886,7 @@ class RemoteFilesystem
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($caBundlePaths as $caBundle) {
|
foreach ($caBundlePaths as $caBundle) {
|
||||||
if (@is_readable($caBundle) && $this->validateCaFile($caBundle)) {
|
if (Silencer::call('is_readable', $caBundle) && $this->validateCaFile($caBundle)) {
|
||||||
return $caPath = $caBundle;
|
return $caPath = $caBundle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporarily suppress PHP error reporting, usually warnings and below.
|
||||||
|
*
|
||||||
|
* @author Niels Keurentjes <niels.keurentjes@omines.com>
|
||||||
|
*/
|
||||||
|
class Silencer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var int[] Unpop stack
|
||||||
|
*/
|
||||||
|
private static $stack = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suppresses given mask or errors.
|
||||||
|
*
|
||||||
|
* @param int|null $mask Error levels to suppress, default value NULL indicates all warnings and below.
|
||||||
|
* @return int The old error reporting level.
|
||||||
|
*/
|
||||||
|
public static function suppress($mask = null)
|
||||||
|
{
|
||||||
|
if (!isset($mask)) {
|
||||||
|
$mask = E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED | E_STRICT;
|
||||||
|
}
|
||||||
|
array_push(self::$stack, $old = error_reporting());
|
||||||
|
error_reporting($old & ~$mask);
|
||||||
|
return $old;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores a single state.
|
||||||
|
*/
|
||||||
|
public static function restore()
|
||||||
|
{
|
||||||
|
if (!empty(self::$stack))
|
||||||
|
error_reporting(array_pop(self::$stack));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls a specified function while silencing warnings and below.
|
||||||
|
*
|
||||||
|
* Future improvement: when PHP requirements are raised add Callable type hint (5.4) and variadic parameters (5.6)
|
||||||
|
*
|
||||||
|
* @param callable $callable Function to execute.
|
||||||
|
* @return mixed Return value of the callback.
|
||||||
|
* @throws \Exception Any exceptions from the callback are rethrown.
|
||||||
|
*/
|
||||||
|
public static function call($callable /*, ...$parameters */)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
self::suppress();
|
||||||
|
$result = call_user_func_array($callable, array_slice(func_get_args(), 1));
|
||||||
|
self::restore();
|
||||||
|
return $result;
|
||||||
|
} catch(\Exception $e) {
|
||||||
|
// Use a finally block for this when requirements are raised to PHP 5.5
|
||||||
|
self::restore();
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Test\Util;
|
||||||
|
|
||||||
|
use Composer\Util\Silencer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SilencerTest
|
||||||
|
*
|
||||||
|
* @author Niels Keurentjes <niels.keurentjes@omines.com>
|
||||||
|
*/
|
||||||
|
class SilencerTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Test succeeds when no warnings are emitted externally, and original level is restored.
|
||||||
|
*/
|
||||||
|
public function testSilencer()
|
||||||
|
{
|
||||||
|
$before = error_reporting();
|
||||||
|
|
||||||
|
// Check warnings are suppressed correctly
|
||||||
|
Silencer::suppress();
|
||||||
|
@trigger_error('Test', E_USER_WARNING);
|
||||||
|
Silencer::restore();
|
||||||
|
|
||||||
|
// Check all parameters and return values are passed correctly in a silenced call.
|
||||||
|
$result = Silencer::call(function($a, $b, $c) {
|
||||||
|
@trigger_error('Test', E_USER_WARNING);
|
||||||
|
return $a * $b * $c;
|
||||||
|
}, 2, 3, 4);
|
||||||
|
$this->assertEquals(24, $result);
|
||||||
|
|
||||||
|
// Check the error reporting setting was restored correctly
|
||||||
|
$this->assertEquals($before, error_reporting());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether exception from silent callbacks are correctly forwarded.
|
||||||
|
*/
|
||||||
|
public function testSilencedException()
|
||||||
|
{
|
||||||
|
$verification = microtime();
|
||||||
|
$this->setExpectedException('\RuntimeException', $verification);
|
||||||
|
Silencer::call(function() use ($verification) {
|
||||||
|
throw new \RuntimeException($verification);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue