/** * 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); }); }
/** * @param IOInterface $io * @param string $cacheDir location of the cache * @param string $whitelist List of characters that are allowed in path names (used in a regex character class) * @param Filesystem $filesystem optional filesystem instance */ public function __construct(IOInterface $io, $cacheDir, $whitelist = 'a-z0-9.', Filesystem $filesystem = null) { $this->io = $io; $this->root = rtrim($cacheDir, '/\\') . '/'; $this->whitelist = $whitelist; $this->filesystem = $filesystem ?: new Filesystem(); if (!is_dir($this->root) && !Silencer::call('mkdir', $this->root, 0777, true) || !is_writable($this->root)) { $this->io->writeError('<warning>Cannot create cache directory ' . $this->root . ', or directory is not writable. Proceeding without cache</warning>'); $this->enabled = false; } }
protected static function getUniqueTmpDirectory() { $attempts = 5; $root = sys_get_temp_dir(); do { $unique = $root . DIRECTORY_SEPARATOR . uniqid('composer-test-' . rand(1000, 9000)); if (!file_exists($unique) && Silencer::call('mkdir', $unique, 0777)) { return realpath($unique); } } while (--$attempts); throw new \RuntimeException('Failed to create a unique temporary directory.'); }
public function __construct() { static $shutdownRegistered = false; if (function_exists('ini_set') && extension_loaded('xdebug')) { ini_set('xdebug.show_exception_trace', false); ini_set('xdebug.scream', false); } if (function_exists('date_default_timezone_set') && function_exists('date_default_timezone_get')) { date_default_timezone_set(Silencer::call('date_default_timezone_get')); } if (!$shutdownRegistered) { $shutdownRegistered = true; register_shutdown_function(function () { $lastError = error_get_last(); if ($lastError && $lastError['message'] && (strpos($lastError['message'], 'Allowed memory') !== false || strpos($lastError['message'], 'exceeded memory') !== false)) { echo "\n" . 'Check https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors for more info on how to handle out of memory errors.'; } }); } parent::__construct('Composer', Composer::VERSION); }
/** * @param IOInterface|null $io * @return Config */ public static function createConfig(IOInterface $io = null, $cwd = null) { $cwd = $cwd ?: getcwd(); $config = new Config(true, $cwd); // determine and add main dirs to the config $home = self::getHomeDir(); $config->merge(array('config' => array('home' => $home, 'cache-dir' => self::getCacheDir($home), 'data-dir' => self::getDataDir($home)))); // Protect directory against web access. Since HOME could be // the www-data's user home and be web-accessible it is a // potential security risk $dirs = array($config->get('home'), $config->get('cache-dir'), $config->get('data-dir')); foreach ($dirs as $dir) { if (!file_exists($dir . '/.htaccess')) { if (!is_dir($dir)) { Silencer::call('mkdir', $dir, 0777, true); } Silencer::call('file_put_contents', $dir . '/.htaccess', 'Deny from all'); } } // load global config $file = new JsonFile($config->get('home') . '/config.json'); if ($file->exists()) { if ($io && $io->isDebug()) { $io->writeError('Loading config file ' . $file->getPath()); } $config->merge($file->read()); } $config->setConfigSource(new JsonConfigSource($file)); // load global auth file $file = new JsonFile($config->get('home') . '/auth.json'); if ($file->exists()) { if ($io && $io->isDebug()) { $io->writeError('Loading config file ' . $file->getPath()); } $config->merge(array('config' => $file->read())); } $config->setAuthConfigSource(new JsonConfigSource($file, true)); // load COMPOSER_AUTH environment variable if set if ($composerAuthEnv = getenv('COMPOSER_AUTH')) { $authData = json_decode($composerAuthEnv, true); if (is_null($authData)) { throw new \UnexpectedValueException('COMPOSER_AUTH environment variable is malformed, should be a valid JSON object'); } if ($io && $io->isDebug()) { $io->writeError('Loading auth config from COMPOSER_AUTH'); } $config->merge(array('config' => $authData)); } return $config; }
/** * {@inheritDoc} */ public function doRun(InputInterface $input, OutputInterface $output) { $this->disablePluginsByDefault = $input->hasParameterOption('--no-plugins'); $io = $this->io = new ConsoleIO($input, $output, $this->getHelperSet()); ErrorHandler::register($io); // switch working dir if ($newWorkDir = $this->getNewWorkingDir($input)) { $oldWorkingDir = getcwd(); chdir($newWorkDir); $io->writeError('Changed CWD to ' . getcwd(), true, IOInterface::DEBUG); } // determine command name to be executed without including plugin commands $commandName = ''; if ($name = $this->getCommandName($input)) { try { $commandName = $this->find($name)->getName(); } catch (\InvalidArgumentException $e) { } } if (!$this->disablePluginsByDefault && !$this->hasPluginCommands && 'global' !== $commandName) { try { foreach ($this->getPluginCommands() as $command) { if ($this->has($command->getName())) { $io->writeError('<warning>Plugin command ' . $command->getName() . ' (' . get_class($command) . ') would override a Composer command and has been skipped</warning>'); } else { $this->add($command); } } } catch (NoSslException $e) { // suppress these as they are not relevant at this point } $this->hasPluginCommands = true; } // determine command name to be executed incl plugin commands, and check if it's a proxy command $isProxyCommand = false; if ($name = $this->getCommandName($input)) { try { $command = $this->find($name); $commandName = $command->getName(); $isProxyCommand = $command instanceof Command\BaseCommand && $command->isProxyCommand(); } catch (\InvalidArgumentException $e) { } } if (!$isProxyCommand) { $io->writeError(sprintf('Running %s (%s) with %s on %s', Composer::VERSION, Composer::RELEASE_DATE, defined('HHVM_VERSION') ? 'HHVM ' . HHVM_VERSION : 'PHP ' . PHP_VERSION, php_uname('s') . ' / ' . php_uname('r')), true, IOInterface::DEBUG); if (PHP_VERSION_ID < 50302) { $io->writeError('<warning>Composer only officially supports PHP 5.3.2 and above, you will most likely encounter problems with your PHP ' . PHP_VERSION . ', upgrading is strongly recommended.</warning>'); } if (extension_loaded('xdebug') && !getenv('COMPOSER_DISABLE_XDEBUG_WARN')) { $io->writeError('<warning>You are running composer with xdebug enabled. This has a major impact on runtime performance. See https://getcomposer.org/xdebug</warning>'); } if (defined('COMPOSER_DEV_WARNING_TIME') && $commandName !== 'self-update' && $commandName !== 'selfupdate' && time() > COMPOSER_DEV_WARNING_TIME) { $io->writeError(sprintf('<warning>Warning: This development build of composer is over 60 days old. It is recommended to update it by running "%s self-update" to get the latest version.</warning>', $_SERVER['PHP_SELF'])); } if (getenv('COMPOSER_NO_INTERACTION')) { $input->setInteractive(false); } if (!Platform::isWindows() && function_exists('exec') && !getenv('COMPOSER_ALLOW_SUPERUSER')) { if (function_exists('posix_getuid') && posix_getuid() === 0) { if ($commandName !== 'self-update' && $commandName !== 'selfupdate') { $io->writeError('<warning>Do not run Composer as root/super user! See https://getcomposer.org/root for details</warning>'); } if ($uid = (int) getenv('SUDO_UID')) { // Silently clobber any sudo credentials on the invoking user to avoid privilege escalations later on // ref. https://github.com/composer/composer/issues/5119 Silencer::call('exec', "sudo -u \\#{$uid} sudo -K > /dev/null 2>&1"); } } // Silently clobber any remaining sudo leases on the current user as well to avoid privilege escalations Silencer::call('exec', 'sudo -K > /dev/null 2>&1'); } // Check system temp folder for usability as it can cause weird runtime issues otherwise Silencer::call(function () use($io) { $tempfile = sys_get_temp_dir() . '/temp-' . md5(microtime()); if (!(file_put_contents($tempfile, __FILE__) && file_get_contents($tempfile) == __FILE__ && unlink($tempfile) && !file_exists($tempfile))) { $io->writeError(sprintf('<error>PHP temp directory (%s) does not exist or is not writable to Composer. Set sys_temp_dir in your php.ini</error>', sys_get_temp_dir())); } }); // add non-standard scripts as own commands $file = Factory::getComposerFile(); if (is_file($file) && is_readable($file) && is_array($composer = json_decode(file_get_contents($file), true))) { if (isset($composer['scripts']) && is_array($composer['scripts'])) { foreach ($composer['scripts'] as $script => $dummy) { if (!defined('Composer\\Script\\ScriptEvents::' . str_replace('-', '_', strtoupper($script)))) { if ($this->has($script)) { $io->writeError('<warning>A script named ' . $script . ' would override a Composer command and has been skipped</warning>'); } else { $this->add(new Command\ScriptAliasCommand($script)); } } } } } } try { if ($input->hasParameterOption('--profile')) { $startTime = microtime(true); $this->io->enableDebugging($startTime); } $result = parent::doRun($input, $output); if (isset($oldWorkingDir)) { chdir($oldWorkingDir); } if (isset($startTime)) { $io->writeError('<info>Memory usage: ' . round(memory_get_usage() / 1024 / 1024, 2) . 'MB (peak: ' . round(memory_get_peak_usage() / 1024 / 1024, 2) . 'MB), time: ' . round(microtime(true) - $startTime, 2) . 's'); } restore_error_handler(); return $result; } catch (ScriptExecutionException $e) { return $e->getCode(); } catch (\Exception $e) { $this->hintCommonErrors($e); restore_error_handler(); throw $e; } }
/** * {@inheritDoc} */ public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) { if (!$repo->hasPackage($package)) { throw new \InvalidArgumentException('Package is not installed: ' . $package); } $this->removeCode($package); $this->binaryInstaller->removeBinaries($package); $repo->removePackage($package); $downloadPath = $this->getPackageBasePath($package); if (strpos($package->getName(), '/')) { $packageVendorDir = dirname($downloadPath); if (is_dir($packageVendorDir) && $this->filesystem->isDirEmpty($packageVendorDir)) { Silencer::call('rmdir', $packageVendorDir); } } }
public function installProject(IOInterface $io, Config $config, InputInterface $input, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repository = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false, $noInstall = false, $ignorePlatformReqs = false, $secureHttp = true) { $oldCwd = getcwd(); // we need to manually load the configuration to pass the auth credentials to the io interface! $io->loadConfiguration($config); $this->suggestedPackagesReporter = new SuggestedPackagesReporter($io); if ($packageName !== null) { $installedFromVcs = $this->installRootPackage($io, $config, $packageName, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repository, $disablePlugins, $noScripts, $keepVcs, $noProgress, $ignorePlatformReqs, $secureHttp); } else { $installedFromVcs = false; } $composer = Factory::create($io, null, $disablePlugins); $composer->getDownloadManager()->setOutputProgress(!$noProgress); $fs = new Filesystem(); if ($noScripts === false) { // dispatch event $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_ROOT_PACKAGE_INSTALL, $installDevPackages); } $rootPackageConfig = $composer->getConfig(); $this->updatePreferredOptions($rootPackageConfig, $input, $preferSource, $preferDist); // install dependencies of the created project if ($noInstall === false) { $installer = Installer::create($io, $composer); $installer->setPreferSource($preferSource)->setPreferDist($preferDist)->setDevMode($installDevPackages)->setRunScripts(!$noScripts)->setIgnorePlatformRequirements($ignorePlatformReqs)->setSuggestedPackagesReporter($this->suggestedPackagesReporter); if ($disablePlugins) { $installer->disablePlugins(); } $status = $installer->run(); if (0 !== $status) { return $status; } } $hasVcs = $installedFromVcs; if (!$keepVcs && $installedFromVcs && (!$io->isInteractive() || $io->askConfirmation('<info>Do you want to remove the existing VCS (.git, .svn..) history?</info> [<comment>Y,n</comment>]? ', true))) { $finder = new Finder(); $finder->depth(0)->directories()->in(getcwd())->ignoreVCS(false)->ignoreDotFiles(false); foreach (array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg') as $vcsName) { $finder->name($vcsName); } try { $dirs = iterator_to_array($finder); unset($finder); foreach ($dirs as $dir) { if (!$fs->removeDirectory($dir)) { throw new \RuntimeException('Could not remove ' . $dir); } } } catch (\Exception $e) { $io->writeError('<error>An error occurred while removing the VCS metadata: ' . $e->getMessage() . '</error>'); } $hasVcs = false; } // rewriting self.version dependencies with explicit version numbers if the package's vcs metadata is gone if (!$hasVcs) { $package = $composer->getPackage(); $configSource = new JsonConfigSource(new JsonFile('composer.json')); foreach (BasePackage::$supportedLinkTypes as $type => $meta) { foreach ($package->{'get' . $meta['method']}() as $link) { if ($link->getPrettyConstraint() === 'self.version') { $configSource->addLink($type, $link->getTarget(), $package->getPrettyVersion()); } } } } if ($noScripts === false) { // dispatch event $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_CREATE_PROJECT_CMD, $installDevPackages); } chdir($oldCwd); $vendorComposerDir = $composer->getConfig()->get('vendor-dir') . '/composer'; if (is_dir($vendorComposerDir) && $fs->isDirEmpty($vendorComposerDir)) { Silencer::call('rmdir', $vendorComposerDir); $vendorDir = $composer->getConfig()->get('vendor-dir'); if (is_dir($vendorDir) && $fs->isDirEmpty($vendorDir)) { Silencer::call('rmdir', $vendorDir); } } return 0; }
protected function manipulateJson($method, $args, $fallback) { $args = func_get_args(); // remove method & fallback array_shift($args); $fallback = array_pop($args); if ($this->file->exists()) { $contents = file_get_contents($this->file->getPath()); } elseif ($this->authConfig) { $contents = "{\n}\n"; } else { $contents = "{\n \"config\": {\n }\n}\n"; } $manipulator = new JsonManipulator($contents); $newFile = !$this->file->exists(); // override manipulator method for auth config files if ($this->authConfig && $method === 'addConfigSetting') { $method = 'addSubNode'; list($mainNode, $name) = explode('.', $args[0], 2); $args = array($mainNode, $name, $args[1]); } elseif ($this->authConfig && $method === 'removeConfigSetting') { $method = 'removeSubNode'; list($mainNode, $name) = explode('.', $args[0], 2); $args = array($mainNode, $name); } // try to update cleanly if (call_user_func_array(array($manipulator, $method), $args)) { file_put_contents($this->file->getPath(), $manipulator->getContents()); } else { // on failed clean update, call the fallback and rewrite the whole file $config = $this->file->read(); $this->arrayUnshiftRef($args, $config); call_user_func_array($fallback, $args); $this->file->write($config); } if ($newFile) { Silencer::call('chmod', $this->file->getPath(), 0600); } }
public function removeBinaries(PackageInterface $package) { $this->initializeBinDir(); $binaries = $this->getBinaries($package); if (!$binaries) { return; } foreach ($binaries as $bin) { $link = $this->binDir . '/' . basename($bin); if (is_link($link) || file_exists($link)) { $this->filesystem->unlink($link); } if (file_exists($link . '.bat')) { $this->filesystem->unlink($link . '.bat'); } } // attempt removing the bin dir in case it is left empty if (is_dir($this->binDir) && $this->filesystem->isDirEmpty($this->binDir)) { Silencer::call('rmdir', $this->binDir); } }
/** * @param IOInterface|null $io * @return Config */ public static function createConfig(IOInterface $io = null, $cwd = null) { $cwd = $cwd ?: getcwd(); $config = new Config(true, $cwd); // determine and add main dirs to the config $home = self::getHomeDir(); $config->merge(array('config' => array('home' => $home, 'cache-dir' => self::getCacheDir($home), 'data-dir' => self::getDataDir($home)))); // Protect directory against web access. Since HOME could be // the www-data's user home and be web-accessible it is a // potential security risk $dirs = array($config->get('home'), $config->get('cache-dir'), $config->get('data-dir')); foreach ($dirs as $dir) { if (!file_exists($dir . '/.htaccess')) { if (!is_dir($dir)) { Silencer::call('mkdir', $dir, 0777, true); } Silencer::call('file_put_contents', $dir . '/.htaccess', 'Deny from all'); } } // load global config $file = new JsonFile($config->get('home') . '/config.json'); if ($file->exists()) { if ($io && $io->isDebug()) { $io->writeError('Loading config file ' . $file->getPath()); } $config->merge($file->read()); } $config->setConfigSource(new JsonConfigSource($file)); // load global auth file $file = new JsonFile($config->get('home') . '/auth.json'); if ($file->exists()) { if ($io && $io->isDebug()) { $io->writeError('Loading config file ' . $file->getPath()); } $config->merge(array('config' => $file->read())); } $config->setAuthConfigSource(new JsonConfigSource($file, true)); return $config; }
/** * Copy a file out of the cache */ public function copyTo($file, $target) { $file = preg_replace('{[^' . $this->whitelist . ']}i', '-', $file); if ($this->enabled && file_exists($this->root . $file)) { try { touch($this->root . $file, filemtime($this->root . $file), time()); } catch (\ErrorException $e) { // fallback in case the above failed due to incorrect ownership // see https://github.com/composer/composer/issues/4070 Silencer::call('touch', $this->root . $file); } $this->io->writeError('Reading ' . $this->root . $file . ' from cache', true, IOInterface::DEBUG); return copy($this->root . $file, $target); } return false; }
/** * Load composer and the composer class loader. * * @SuppressWarnings(PHPMD.ShortVariable) */ public static function createComposer(IOInterface $io) { chdir(COMPOSER_DIR_ABSOULTE); // try to increase memory limit static::increaseMemoryLimit(); // register composer class loader static::registerComposerClassLoader(); // create composer factory /** @var \Composer\Factory $factory */ $factory = new Factory(); // create composer if (class_exists('\\Composer\\Util\\Silencer')) { $composer = Silencer::call(array($factory, 'createComposer'), $io); } else { $composer = $factory->createComposer($io); } return $composer; }
/** * This method was adapted from Sslurp. * https://github.com/EvanDotPro/Sslurp * * (c) Evan Coury <*****@*****.**> * * For the full copyright and license information, please see below: * * Copyright (c) 2013, Evan Coury * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @return string */ private function getSystemCaRootBundlePath() { static $caPath = null; if ($caPath !== null) { return $caPath; } // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that. // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. $envCertFile = getenv('SSL_CERT_FILE'); if ($envCertFile && is_readable($envCertFile) && $this->validateCaFile($envCertFile)) { // Possibly throw exception instead of ignoring SSL_CERT_FILE if it's invalid? return $caPath = $envCertFile; } $configured = ini_get('openssl.cafile'); if ($configured && strlen($configured) > 0 && is_readable($configured) && $this->validateCaFile($configured)) { return $caPath = $configured; } $caBundlePaths = array('/etc/pki/tls/certs/ca-bundle.crt', '/etc/ssl/certs/ca-certificates.crt', '/etc/ssl/ca-bundle.pem', '/usr/local/share/certs/ca-root-nss.crt', '/usr/ssl/certs/ca-bundle.crt', '/opt/local/share/curl/curl-ca-bundle.crt', '/usr/local/share/curl/curl-ca-bundle.crt', '/usr/share/ssl/certs/ca-bundle.crt', '/etc/ssl/cert.pem', '/usr/local/etc/ssl/cert.pem'); foreach ($caBundlePaths as $caBundle) { if (Silencer::call('is_readable', $caBundle) && $this->validateCaFile($caBundle)) { return $caPath = $caBundle; } } foreach ($caBundlePaths as $caBundle) { $caBundle = dirname($caBundle); if (is_dir($caBundle) && glob($caBundle . '/*')) { return $caPath = $caBundle; } } return $caPath = __DIR__ . '/../../../res/cacert.pem'; // Bundled with Composer, last resort }
/** * Extract the classes in the given file * * @param string $path The file to check * @throws \RuntimeException * @return array The found classes */ private static function findClasses($path) { $extraTypes = PHP_VERSION_ID < 50400 ? '' : '|trait'; if (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>=')) { $extraTypes .= '|enum'; } try { $contents = Silencer::call('php_strip_whitespace', $path); if (!$contents) { if (!file_exists($path)) { throw new \Exception('File does not exist'); } if (!is_readable($path)) { throw new \Exception('File is not readable'); } } } catch (\Exception $e) { throw new \RuntimeException('Could not scan for classes inside ' . $path . ": \n" . $e->getMessage(), 0, $e); } // return early if there is no chance of matching anything in this file if (!preg_match('{\\b(?:class|interface' . $extraTypes . ')\\s}i', $contents)) { return array(); } // strip heredocs/nowdocs $contents = preg_replace('{<<<\\s*(\'?)(\\w+)\\1(?:\\r\\n|\\n|\\r)(?:.*?)(?:\\r\\n|\\n|\\r)\\2(?=\\r\\n|\\n|\\r|;)}s', 'null', $contents); // strip strings $contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents); // strip leading non-php code if needed if (substr($contents, 0, 2) !== '<?') { $contents = preg_replace('{^.+?<\\?}s', '<?', $contents, 1, $replacements); if ($replacements === 0) { return array(); } } // strip non-php blocks in the file $contents = preg_replace('{\\?>.+<\\?}s', '?><?', $contents); // strip trailing non-php code if needed $pos = strrpos($contents, '?>'); if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) { $contents = substr($contents, 0, $pos); } preg_match_all('{ (?: \\b(?<![\\$:>])(?P<type>class|interface' . $extraTypes . ') \\s++ (?P<name>[a-zA-Z_\\x7f-\\xff:][a-zA-Z0-9_\\x7f-\\xff:\\-]*+) | \\b(?<![\\$:>])(?P<ns>namespace) (?P<nsname>\\s++[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*+(?:\\s*+\\\\\\s*+[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*+)*+)? \\s*+ [\\{;] ) }ix', $contents, $matches); $classes = array(); $namespace = ''; for ($i = 0, $len = count($matches['type']); $i < $len; $i++) { if (!empty($matches['ns'][$i])) { $namespace = str_replace(array(' ', "\t", "\r", "\n"), '', $matches['nsname'][$i]) . '\\'; } else { $name = $matches['name'][$i]; if ($name[0] === ':') { // This is an XHP class, https://github.com/facebook/xhp $name = 'xhp' . substr(str_replace(array('-', ':'), array('_', '__'), $name), 1); } elseif ($matches['type'][$i] === 'enum') { // In Hack, something like: // enum Foo: int { HERP = '123'; } // The regex above captures the colon, which isn't part of // the class name. $name = rtrim($name, ':'); } $classes[] = ltrim($namespace . $name, '\\'); } } return $classes; }
/** * {@inheritDoc} */ protected function initialize(InputInterface $input, OutputInterface $output) { parent::initialize($input, $output); if ($input->getOption('global') && null !== $input->getOption('file')) { throw new \RuntimeException('--file and --global can not be combined'); } $io = $this->getIO(); $this->config = Factory::createConfig($io); // Get the local composer.json, global config.json, or if the user // passed in a file to use $configFile = $input->getOption('global') ? $this->config->get('home') . '/config.json' : ($input->getOption('file') ?: trim(getenv('COMPOSER')) ?: 'composer.json'); // 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'))) { file_put_contents($configFile, "{\n}\n"); } $this->configFile = new JsonFile($configFile, null, $io); $this->configSource = new JsonConfigSource($this->configFile); $authConfigFile = $input->getOption('global') ? $this->config->get('home') . '/auth.json' : dirname(realpath($configFile)) . '/auth.json'; $this->authConfigFile = new JsonFile($authConfigFile, null, $io); $this->authConfigSource = new JsonConfigSource($this->authConfigFile, true); // Initialize the global file if it's not there, ignoring any warnings or notices if ($input->getOption('global') && !$this->configFile->exists()) { touch($this->configFile->getPath()); $this->configFile->write(array('config' => new \ArrayObject())); Silencer::call('chmod', $this->configFile->getPath(), 0600); } if ($input->getOption('global') && !$this->authConfigFile->exists()) { touch($this->authConfigFile->getPath()); $this->authConfigFile->write(array('http-basic' => new \ArrayObject(), 'github-oauth' => new \ArrayObject(), 'gitlab-oauth' => new \ArrayObject())); Silencer::call('chmod', $this->authConfigFile->getPath(), 0600); } if (!$this->configFile->exists()) { throw new \RuntimeException(sprintf('File "%s" cannot be found in the current directory', $configFile)); } }
protected function initialize() { parent::initialize(); $versionParser = new VersionParser(); // Add each of the override versions as options. // Later we might even replace the extensions instead. foreach ($this->overrides as $override) { // Check that it's a platform package. if (!preg_match(self::PLATFORM_PACKAGE_REGEX, $override['name'])) { throw new \InvalidArgumentException('Invalid platform package name in config.platform: ' . $override['name']); } $version = $versionParser->normalize($override['version']); $package = new CompletePackage($override['name'], $version, $override['version']); $package->setDescription('Package overridden via config.platform'); $package->setExtra(array('config.platform' => true)); parent::addPackage($package); } $prettyVersion = PluginInterface::PLUGIN_API_VERSION; $version = $versionParser->normalize($prettyVersion); $composerPluginApi = new CompletePackage('composer-plugin-api', $version, $prettyVersion); $composerPluginApi->setDescription('The Composer Plugin API'); $this->addPackage($composerPluginApi); try { $prettyVersion = PHP_VERSION; $version = $versionParser->normalize($prettyVersion); } catch (\UnexpectedValueException $e) { $prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', PHP_VERSION); $version = $versionParser->normalize($prettyVersion); } $php = new CompletePackage('php', $version, $prettyVersion); $php->setDescription('The PHP interpreter'); $this->addPackage($php); if (PHP_INT_SIZE === 8) { $php64 = new CompletePackage('php-64bit', $version, $prettyVersion); $php64->setDescription('The PHP interpreter, 64bit'); $this->addPackage($php64); } // The AF_INET6 constant is only defined if ext-sockets is available but IPv6 support might still be available. if (defined('AF_INET6') || function_exists('inet_pton') && Silencer::call('inet_pton', '::') !== false) { $phpIpv6 = new CompletePackage('ext-network-ipv6', $version, $prettyVersion); $phpIpv6->setDescription('PHP IPv6 support'); $this->addPackage($phpIpv6); } $loadedExtensions = get_loaded_extensions(); // Extensions scanning foreach ($loadedExtensions as $name) { if (in_array($name, array('standard', 'Core'))) { continue; } $extraDescription = null; $reflExt = new \ReflectionExtension($name); try { $prettyVersion = $reflExt->getVersion(); $version = $versionParser->normalize($prettyVersion); } catch (\UnexpectedValueException $e) { $extraDescription = ' (actual version: ' . $prettyVersion . ')'; if (preg_match('{^(\\d+\\.\\d+\\.\\d+(?:\\.\\d+)?)}', $prettyVersion, $match)) { $prettyVersion = $match[1]; } else { $prettyVersion = '0'; } $version = $versionParser->normalize($prettyVersion); } $packageName = $this->buildPackageName($name); $ext = new CompletePackage($packageName, $version, $prettyVersion); $ext->setDescription('The ' . $name . ' PHP extension' . $extraDescription); $this->addPackage($ext); } // Another quick loop, just for possible libraries // Doing it this way to know that functions or constants exist before // relying on them. foreach ($loadedExtensions as $name) { $prettyVersion = null; $description = 'The ' . $name . ' PHP library'; switch ($name) { case 'curl': $curlVersion = curl_version(); $prettyVersion = $curlVersion['version']; break; case 'iconv': $prettyVersion = ICONV_VERSION; break; case 'intl': $name = 'ICU'; if (defined('INTL_ICU_VERSION')) { $prettyVersion = INTL_ICU_VERSION; } else { $reflector = new \ReflectionExtension('intl'); ob_start(); $reflector->info(); $output = ob_get_clean(); preg_match('/^ICU version => (.*)$/m', $output, $matches); $prettyVersion = $matches[1]; } break; case 'libxml': $prettyVersion = LIBXML_DOTTED_VERSION; break; case 'openssl': $prettyVersion = preg_replace_callback('{^(?:OpenSSL\\s*)?([0-9.]+)([a-z]*).*}', function ($match) { if (empty($match[2])) { return $match[1]; } // OpenSSL versions add another letter when they reach Z. // e.g. OpenSSL 0.9.8zh 3 Dec 2015 if (!preg_match('{^z*[a-z]$}', $match[2])) { // 0.9.8abc is garbage return 0; } $len = strlen($match[2]); $patchVersion = ($len - 1) * 26; // All Z $patchVersion += ord($match[2][$len - 1]) - 96; return $match[1] . '.' . $patchVersion; }, OPENSSL_VERSION_TEXT); $description = OPENSSL_VERSION_TEXT; break; case 'pcre': $prettyVersion = preg_replace('{^(\\S+).*}', '$1', PCRE_VERSION); break; case 'uuid': $prettyVersion = phpversion('uuid'); break; case 'xsl': $prettyVersion = LIBXSLT_DOTTED_VERSION; break; default: // None handled extensions have no special cases, skip continue 2; } try { $version = $versionParser->normalize($prettyVersion); } catch (\UnexpectedValueException $e) { continue; } $lib = new CompletePackage('lib-' . $name, $version, $prettyVersion); $lib->setDescription($description); $this->addPackage($lib); } if (defined('HHVM_VERSION')) { try { $prettyVersion = HHVM_VERSION; $version = $versionParser->normalize($prettyVersion); } catch (\UnexpectedValueException $e) { $prettyVersion = preg_replace('#^([^~+-]+).*$#', '$1', HHVM_VERSION); $version = $versionParser->normalize($prettyVersion); } $hhvm = new CompletePackage('hhvm', $version, $prettyVersion); $hhvm->setDescription('The HHVM Runtime (64bit)'); $this->addPackage($hhvm); } }