Example #1
0
 protected function extract($file, $path)
 {
     $processError = null;
     // Try to use unrar on *nix
     if (!Platform::isWindows()) {
         $command = 'unrar x ' . ProcessExecutor::escape($file) . ' ' . ProcessExecutor::escape($path) . ' >/dev/null && chmod -R u+w ' . ProcessExecutor::escape($path);
         if (0 === $this->process->execute($command, $ignoredOutput)) {
             return;
         }
         $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
     }
     if (!class_exists('RarArchive')) {
         // php.ini path is added to the error message to help users find the correct file
         $iniMessage = IniHelper::getMessage();
         $error = "Could not decompress the archive, enable the PHP rar extension or install unrar.\n" . $iniMessage . "\n" . $processError;
         if (!Platform::isWindows()) {
             $error = "Could not decompress the archive, enable the PHP rar extension.\n" . $iniMessage;
         }
         throw new \RuntimeException($error);
     }
     $rarArchive = RarArchive::open($file);
     if (false === $rarArchive) {
         throw new \UnexpectedValueException('Could not open RAR archive: ' . $file);
     }
     $entries = $rarArchive->getEntries();
     if (false === $entries) {
         throw new \RuntimeException('Could not retrieve RAR archive entries');
     }
     foreach ($entries as $entry) {
         if (false === $entry->extract($path)) {
             throw new \RuntimeException('Could not extract entry');
         }
     }
     $rarArchive->close();
 }
Example #2
0
 /**
  * runs a process on the commandline
  *
  * @param  string $command the command to execute
  * @param  mixed  $output  the output will be written into this var if passed by ref
  *                         if a callable is passed it will be used as output handler
  * @param  string $cwd     the working directory
  * @return int    statuscode
  */
 public function execute($command, &$output = null, $cwd = null)
 {
     if ($this->io && $this->io->isDebug()) {
         $safeCommand = preg_replace_callback('{://(?P<user>[^:/\\s]+):(?P<password>[^@\\s/]+)@}i', function ($m) {
             if (preg_match('{^[a-f0-9]{12,}$}', $m['user'])) {
                 return '://***:***@';
             }
             return '://' . $m['user'] . ':***@';
         }, $command);
         $this->io->writeError('Executing command (' . ($cwd ?: 'CWD') . '): ' . $safeCommand);
     }
     // make sure that null translate to the proper directory in case the dir is a symlink
     // and we call a git command, because msysgit does not handle symlinks properly
     if (null === $cwd && Platform::isWindows() && false !== strpos($command, 'git') && getcwd()) {
         $cwd = realpath(getcwd());
     }
     $this->captureOutput = count(func_get_args()) > 1;
     $this->errorOutput = null;
     $process = new Process($command, $cwd, null, null, static::getTimeout());
     $callback = is_callable($output) ? $output : array($this, 'outputHandler');
     $process->run($callback);
     if ($this->captureOutput && !is_callable($output)) {
         $output = $process->getOutput();
     }
     $this->errorOutput = $process->getErrorOutput();
     return $process->getExitCode();
 }
Example #3
0
 private function getCmd($cmd)
 {
     if (Platform::isWindows()) {
         return strtr($cmd, "'", '"');
     }
     return $cmd;
 }
Example #4
0
 protected function extract($file, $path)
 {
     $processError = null;
     if (self::$hasSystemUnzip && !(class_exists('ZipArchive') && Platform::isWindows())) {
         $command = 'unzip ' . ProcessExecutor::escape($file) . ' -d ' . ProcessExecutor::escape($path);
         if (!Platform::isWindows()) {
             $command .= ' && chmod -R u+w ' . ProcessExecutor::escape($path);
         }
         try {
             if (0 === $this->process->execute($command, $ignoredOutput)) {
                 return;
             }
             $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
         } catch (\Exception $e) {
             $processError = 'Failed to execute ' . $command . "\n\n" . $e->getMessage();
         }
         if (!class_exists('ZipArchive')) {
             throw new \RuntimeException($processError);
         }
     }
     $zipArchive = new ZipArchive();
     if (true !== ($retval = $zipArchive->open($file))) {
         throw new \UnexpectedValueException(rtrim($this->getErrorMessage($retval, $file) . "\n" . $processError), $retval);
     }
     if (true !== $zipArchive->extractTo($path)) {
         throw new \RuntimeException(rtrim("There was an error extracting the ZIP file, it is either corrupted or using an invalid format.\n" . $processError));
     }
     $zipArchive->close();
 }
Example #5
0
 /**
  * {@inheritdoc}
  */
 public function download(PackageInterface $package, $path)
 {
     $url = $package->getDistUrl();
     $realUrl = realpath($url);
     if (false === $realUrl || !file_exists($realUrl) || !is_dir($realUrl)) {
         throw new \RuntimeException(sprintf('Source path "%s" is not found for package %s', $url, $package->getName()));
     }
     if (strpos(realpath($path) . DIRECTORY_SEPARATOR, $realUrl . DIRECTORY_SEPARATOR) === 0) {
         throw new \RuntimeException(sprintf('Package %s cannot install to "%s" inside its source at "%s"', $package->getName(), realpath($path), $realUrl));
     }
     $fileSystem = new Filesystem();
     $this->filesystem->removeDirectory($path);
     $this->io->writeError(sprintf('  - Installing <info>%s</info> (<comment>%s</comment>)', $package->getName(), $package->getFullPrettyVersion()));
     try {
         if (Platform::isWindows()) {
             // Implement symlinks as NTFS junctions on Windows
             $this->filesystem->junction($realUrl, $path);
             $this->io->writeError(sprintf('    Junctioned from %s', $url));
         } else {
             $shortestPath = $this->filesystem->findShortestPath($path, $realUrl);
             $fileSystem->symlink($shortestPath, $path);
             $this->io->writeError(sprintf('    Symlinked from %s', $url));
         }
     } catch (IOException $e) {
         $fileSystem->mirror($realUrl, $path);
         $this->io->writeError(sprintf('    Mirrored from %s', $url));
     }
     $this->io->writeError('');
 }
Example #6
0
 public function setUp()
 {
     if (Platform::isWindows()) {
         $this->markTestSkipped('Skip test on Windows');
     }
     $this->testDir = $this->getUniqueTmpDirectory();
 }
Example #7
0
 private function extractUsingExt($file, $targetFilepath)
 {
     $archiveFile = gzopen($file, 'rb');
     $targetFile = fopen($targetFilepath, 'wb');
     while ($string = gzread($archiveFile, 4096)) {
         fwrite($targetFile, $string, Platform::strlen($string));
     }
     gzclose($archiveFile);
     fclose($targetFile);
 }
Example #8
0
 protected function installCode(PackageInterface $package)
 {
     parent::installCode($package);
     $isWindows = Platform::isWindows();
     $php_bin = $this->binDir . ($isWindows ? '/composer-php.bat' : '/composer-php');
     if (!$isWindows) {
         $php_bin = '/usr/bin/env ' . $php_bin;
     }
     $installPath = $this->getInstallPath($package);
     $vars = array('os' => $isWindows ? 'windows' : 'linux', 'php_bin' => $php_bin, 'pear_php' => $installPath, 'php_dir' => $installPath, 'bin_dir' => $installPath . '/bin', 'data_dir' => $installPath . '/data', 'version' => $package->getPrettyVersion());
     $packageArchive = $this->getInstallPath($package) . '/' . pathinfo($package->getDistUrl(), PATHINFO_BASENAME);
     $pearExtractor = new PearPackageExtractor($packageArchive);
     $pearExtractor->extractTo($this->getInstallPath($package), array('php' => '/', 'script' => '/bin', 'data' => '/data'), $vars);
     $this->io->writeError('    Cleaning up', true, IOInterface::VERBOSE);
     $this->filesystem->unlink($packageArchive);
 }
Example #9
0
 public function installBinaries(PackageInterface $package, $installPath, $warnOnOverwrite = true)
 {
     $binaries = $this->getBinaries($package);
     if (!$binaries) {
         return;
     }
     foreach ($binaries as $bin) {
         $binPath = $installPath . '/' . $bin;
         if (!file_exists($binPath)) {
             $this->io->writeError('    <warning>Skipped installation of bin ' . $bin . ' for package ' . $package->getName() . ': file not found in package</warning>');
             continue;
         }
         // in case a custom installer returned a relative path for the
         // $package, we can now safely turn it into a absolute path (as we
         // already checked the binary's existence). The following helpers
         // will require absolute paths to work properly.
         $binPath = realpath($binPath);
         $this->initializeBinDir();
         $link = $this->binDir . '/' . basename($bin);
         if (file_exists($link)) {
             if (is_link($link)) {
                 // likely leftover from a previous install, make sure
                 // that the target is still executable in case this
                 // is a fresh install of the vendor.
                 Silencer::call('chmod', $link, 0777 & ~umask());
             }
             if ($warnOnOverwrite) {
                 $this->io->writeError('    Skipped installation of bin ' . $bin . ' for package ' . $package->getName() . ': name conflicts with an existing file');
             }
             continue;
         }
         if ($this->binCompat === "auto") {
             if (Platform::isWindows()) {
                 $this->installFullBinaries($binPath, $link, $bin, $package);
             } else {
                 $this->installSymlinkBinaries($binPath, $link);
             }
         } elseif ($this->binCompat === "full") {
             $this->installFullBinaries($binPath, $link, $bin, $package);
         }
         Silencer::call('chmod', $link, 0777 & ~umask());
     }
 }
 protected function extract($file, $path)
 {
     $targetFilepath = $path . DIRECTORY_SEPARATOR . basename(substr($file, 0, -3));
     // Try to use gunzip on *nix
     if (!Platform::isWindows()) {
         $command = 'gzip -cd ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath);
         if (0 === $this->process->execute($command, $ignoredOutput)) {
             return;
         }
         if (extension_loaded('zlib')) {
             // Fallback to using the PHP extension.
             $this->extractUsingExt($file, $targetFilepath);
             return;
         }
         $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
         throw new \RuntimeException($processError);
     }
     // Windows version of PHP has built-in support of gzip functions
     $this->extractUsingExt($file, $targetFilepath);
 }
 protected function extract($file, $path)
 {
     $processError = null;
     if (self::$hasSystemUnzip) {
         $command = 'unzip ' . ProcessExecutor::escape($file) . ' -d ' . ProcessExecutor::escape($path);
         if (!Platform::isWindows()) {
             $command .= ' && chmod -R u+w ' . ProcessExecutor::escape($path);
         }
         try {
             if (0 === $this->process->execute($command, $ignoredOutput)) {
                 return;
             }
             $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
         } catch (\Exception $e) {
             $processError = 'Failed to execute ' . $command . "\n\n" . $e->getMessage();
         }
     }
     if (!class_exists('ZipArchive')) {
         // php.ini path is added to the error message to help users find the correct file
         $iniPath = php_ini_loaded_file();
         if ($iniPath) {
             $iniMessage = 'The php.ini used by your command-line PHP is: ' . $iniPath;
         } else {
             $iniMessage = 'A php.ini file does not exist. You will have to create one.';
         }
         $error = "Could not decompress the archive, enable the PHP zip extension or install unzip.\n" . $iniMessage . ($processError ? "\n" . $processError : '');
         throw new \RuntimeException($error);
     }
     $zipArchive = new ZipArchive();
     if (true !== ($retval = $zipArchive->open($file))) {
         throw new \UnexpectedValueException(rtrim($this->getErrorMessage($retval, $file) . "\n" . $processError), $retval);
     }
     if (true !== $zipArchive->extractTo($path)) {
         $this->io->writeError("<warn>As there is no 'unzip' command installed zip files are being unpacked using the PHP zip extension.</warn>");
         $this->io->writeError("<warn>This may cause invalid reports of corrupted archives. Installing 'unzip' may remediate them.</warn>");
         throw new \RuntimeException("There was an error extracting the ZIP file, it is either corrupted or using an invalid format");
     }
     $zipArchive->close();
 }
Example #12
0
 protected function extract($file, $path)
 {
     $processError = null;
     // try to use unzip on *nix
     if (!Platform::isWindows()) {
         $command = 'unzip ' . ProcessExecutor::escape($file) . ' -d ' . ProcessExecutor::escape($path) . ' && chmod -R u+w ' . ProcessExecutor::escape($path);
         try {
             if (0 === $this->process->execute($command, $ignoredOutput)) {
                 return;
             }
             $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
         } catch (\Exception $e) {
             $processError = 'Failed to execute ' . $command . "\n\n" . $e->getMessage();
         }
     }
     if (!class_exists('ZipArchive')) {
         // php.ini path is added to the error message to help users find the correct file
         $iniPath = php_ini_loaded_file();
         if ($iniPath) {
             $iniMessage = 'The php.ini used by your command-line PHP is: ' . $iniPath;
         } else {
             $iniMessage = 'A php.ini file does not exist. You will have to create one.';
         }
         $error = "Could not decompress the archive, enable the PHP zip extension or install unzip.\n" . $iniMessage . "\n" . $processError;
         if (!Platform::isWindows()) {
             $error = "Could not decompress the archive, enable the PHP zip extension.\n" . $iniMessage;
         }
         throw new \RuntimeException($error);
     }
     $zipArchive = new ZipArchive();
     if (true !== ($retval = $zipArchive->open($file))) {
         throw new \UnexpectedValueException(rtrim($this->getErrorMessage($retval, $file) . "\n" . $processError), $retval);
     }
     if (true !== $zipArchive->extractTo($path)) {
         throw new \RuntimeException("There was an error extracting the ZIP file. Corrupt file?");
     }
     $zipArchive->close();
 }
Example #13
0
 private function getCmd($cmd)
 {
     return Platform::isWindows() ? strtr($cmd, "'", '"') : $cmd;
 }
Example #14
0
 /**
  * {@inheritDoc}
  */
 private function hintCommonErrors($exception)
 {
     $io = $this->getIO();
     Silencer::suppress();
     try {
         $composer = $this->getComposer(false, true);
         if ($composer) {
             $config = $composer->getConfig();
             $minSpaceFree = 1024 * 1024;
             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 = 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>', true, IOInterface::QUIET);
             }
         }
     } catch (\Exception $e) {
     }
     Silencer::restore();
     if (Platform::isWindows() && 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>', true, IOInterface::QUIET);
         $io->writeError('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details</error>', true, IOInterface::QUIET);
     }
     if (false !== strpos($exception->getMessage(), 'fork failed - Cannot allocate memory')) {
         $io->writeError('<error>The following exception is caused by a lack of memory and not having swap configured</error>', true, IOInterface::QUIET);
         $io->writeError('<error>Check https://getcomposer.org/doc/articles/troubleshooting.md#proc-open-fork-failed-errors for details</error>', true, IOInterface::QUIET);
     }
 }
Example #15
0
 /**
  * Removes a Windows NTFS junction.
  *
  * @param  string $junction
  * @return bool
  */
 public function removeJunction($junction)
 {
     if (!Platform::isWindows()) {
         return false;
     }
     $junction = rtrim(str_replace('/', DIRECTORY_SEPARATOR, $junction), DIRECTORY_SEPARATOR);
     if (!$this->isJunction($junction)) {
         throw new IOException(sprintf('%s is not a junction and thus cannot be removed as one', $junction));
     }
     $cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape($junction));
     clearstatcache(true, $junction);
     return $this->getProcess()->execute($cmd, $output) === 0;
 }
Example #16
0
    private function winCompat($cmd)
    {
        if (Platform::isWindows()) {
            $cmd = str_replace('cd ', 'cd /D ', $cmd);
            $cmd = str_replace('composerPath', getcwd().'/composerPath', $cmd);

            return str_replace('""', '', strtr($cmd, "'", '"'));
        }

        return $cmd;
    }
Example #17
0
 /**
  * Returns a setting
  *
  * @param  string            $key
  * @param  int               $flags Options (see class constants)
  * @throws \RuntimeException
  * @return mixed
  */
 public function get($key, $flags = 0)
 {
     switch ($key) {
         case 'vendor-dir':
         case 'bin-dir':
         case 'process-timeout':
         case 'data-dir':
         case 'cache-dir':
         case 'cache-files-dir':
         case 'cache-repo-dir':
         case 'cache-vcs-dir':
         case 'cafile':
         case 'capath':
             // convert foo-bar to COMPOSER_FOO_BAR and check if it exists since it overrides the local config
             $env = 'COMPOSER_' . strtoupper(strtr($key, '-', '_'));
             $val = rtrim($this->process($this->getComposerEnv($env) ?: $this->config[$key], $flags), '/\\');
             $val = Platform::expandPath($val);
             if (substr($key, -4) !== '-dir') {
                 return $val;
             }
             return ($flags & self::RELATIVE_PATHS) == self::RELATIVE_PATHS ? $val : $this->realpath($val);
         case 'cache-ttl':
             return (int) $this->config[$key];
         case 'cache-files-maxsize':
             if (!preg_match('/^\\s*([0-9.]+)\\s*(?:([kmg])(?:i?b)?)?\\s*$/i', $this->config[$key], $matches)) {
                 throw new \RuntimeException("Could not parse the value of 'cache-files-maxsize': {$this->config[$key]}");
             }
             $size = $matches[1];
             if (isset($matches[2])) {
                 switch (strtolower($matches[2])) {
                     case 'g':
                         $size *= 1024;
                         // intentional fallthrough
                     // intentional fallthrough
                     case 'm':
                         $size *= 1024;
                         // intentional fallthrough
                     // intentional fallthrough
                     case 'k':
                         $size *= 1024;
                         break;
                 }
             }
             return $size;
         case 'cache-files-ttl':
             if (isset($this->config[$key])) {
                 return (int) $this->config[$key];
             }
             return (int) $this->config['cache-ttl'];
         case 'home':
             $val = preg_replace('#^(\\$HOME|~)(/|$)#', rtrim(getenv('HOME') ?: getenv('USERPROFILE'), '/\\') . '/', $this->config[$key]);
             return rtrim($this->process($val, $flags), '/\\');
         case 'bin-compat':
             $value = $this->getComposerEnv('COMPOSER_BIN_COMPAT') ?: $this->config[$key];
             if (!in_array($value, array('auto', 'full'))) {
                 throw new \RuntimeException("Invalid value for 'bin-compat': {$value}. Expected auto, full");
             }
             return $value;
         case 'discard-changes':
             if ($env = $this->getComposerEnv('COMPOSER_DISCARD_CHANGES')) {
                 if (!in_array($env, array('stash', 'true', 'false', '1', '0'), true)) {
                     throw new \RuntimeException("Invalid value for COMPOSER_DISCARD_CHANGES: {$env}. Expected 1, 0, true, false or stash");
                 }
                 if ('stash' === $env) {
                     return 'stash';
                 }
                 // convert string value to bool
                 return $env !== 'false' && (bool) $env;
             }
             if (!in_array($this->config[$key], array(true, false, 'stash'), true)) {
                 throw new \RuntimeException("Invalid value for 'discard-changes': {$this->config[$key]}. Expected true, false or stash");
             }
             return $this->config[$key];
         case 'github-protocols':
             $protos = $this->config['github-protocols'];
             if ($this->config['secure-http'] && false !== ($index = array_search('git', $protos))) {
                 unset($protos[$index]);
             }
             if (reset($protos) === 'http') {
                 throw new \RuntimeException('The http protocol for github is not available anymore, update your config\'s github-protocols to use "https", "git" or "ssh"');
             }
             return $protos;
         case 'disable-tls':
             return $this->config[$key] !== 'false' && (bool) $this->config[$key];
         case 'secure-http':
             return $this->config[$key] !== 'false' && (bool) $this->config[$key];
         default:
             if (!isset($this->config[$key])) {
                 return null;
             }
             return $this->process($this->config[$key], $flags);
     }
 }
Example #18
0
 /**
  * opens a url in your system default browser
  *
  * @param string $url
  */
 private function openBrowser($url)
 {
     $url = ProcessExecutor::escape($url);
     if (Platform::isWindows()) {
         return passthru('start "web" explorer "' . $url . '"');
     }
     passthru('which xdg-open', $linux);
     passthru('which open', $osx);
     if (0 === $linux) {
         passthru('xdg-open ' . $url);
     } elseif (0 === $osx) {
         passthru('open ' . $url);
     } else {
         $this->getIO()->writeError('no suitable browser opening command found, open yourself: ' . $url);
     }
 }
Example #19
0
 /**
  * @param Event $event
  * @param bool  $lazy
  *
  * @throws LintErrorException
  * @throws RequiresDependencyException
  */
 public static function yaml(Event $event, $lazy = false)
 {
     $bin = self::getOption('lint-yaml-bin', $event);
     $includes = self::getOption('lint-yaml-include', $event);
     $excludes = self::getOption('lint-yaml-exclude', $event);
     $logPrepend = self::getOption('lint-yaml-log-prepend', $event);
     if (Platform::isWindows()) {
         self::lintFinder($event, $includes, $excludes, '*.yml', $bin, $logPrepend, $lazy);
     } else {
         self::lintLinuxFind($event, $includes, $excludes, '*.yml', $bin, $logPrepend, $lazy);
     }
 }
Example #20
0
 /**
  * Initializes path repository.
  *
  * @param array       $repoConfig
  * @param IOInterface $io
  * @param Config      $config
  */
 public function __construct(array $repoConfig, IOInterface $io, Config $config)
 {
     if (!isset($repoConfig['url'])) {
         throw new \RuntimeException('You must specify the `url` configuration for the path repository');
     }
     $this->loader = new ArrayLoader(null, true);
     $this->url = Platform::expandPath($repoConfig['url']);
     $this->process = new ProcessExecutor($io);
     $this->versionGuesser = new VersionGuesser($config, $this->process, new VersionParser());
     $this->repoConfig = $repoConfig;
     $this->options = isset($repoConfig['options']) ? $repoConfig['options'] : array();
     parent::__construct();
 }
 /**
  * {@inheritDoc}
  */
 public function remove(PackageInterface $package, $path)
 {
     /**
      * For junctions don't blindly rely on Filesystem::removeDirectory as it may be overzealous. If a process
      * inadvertently locks the file the removal will fail, but it would fall back to recursive delete which
      * is disastrous within a junction. So in that case we have no other real choice but to fail hard.
      */
     if (Platform::isWindows() && $this->filesystem->isJunction($path)) {
         $this->io->writeError("  - Removing junction for <info>" . $package->getName() . "</info> (<comment>" . $package->getFullPrettyVersion() . "</comment>)");
         if (!$this->filesystem->removeJunction($path)) {
             $this->io->writeError("<warn>Could not remove junction at " . $path . " - is another process locking it?</warn>");
             throw new \RuntimeException('Could not reliably remove junction for package ' . $package->getName());
         }
     } else {
         parent::remove($package, $path);
     }
 }
Example #22
0
 public static function create($repoConfig, $port, $path, ProcessExecutor $process, IOInterface $io)
 {
     return new Perforce($repoConfig, $port, $path, $process, Platform::isWindows(), $io);
 }
Example #23
0
 /**
  * delete symbolic link implementation (commonly known as "unlink()")
  *
  * symbolic links on windows which link to directories need rmdir instead of unlink
  *
  * @param string $path
  *
  * @return bool
  */
 private function unlinkImplementation($path)
 {
     if (Platform::isWindows() && is_dir($path) && is_link($path)) {
         return rmdir($path);
     }
     return unlink($path);
 }
Example #24
0
 public function testWindows()
 {
     // Compare 2 common tests for Windows to the built-in Windows test
     $this->assertEquals('\\' === DIRECTORY_SEPARATOR, Platform::isWindows());
     $this->assertEquals(defined('PHP_WINDOWS_VERSION_MAJOR'), Platform::isWindows());
 }
Example #25
0
 /**
  * @param  string $home
  * @return string
  */
 protected static function getDataDir($home)
 {
     $homeEnv = getenv('COMPOSER_HOME');
     if ($homeEnv) {
         return $homeEnv;
     }
     if (Platform::isWindows()) {
         return strtr($home, '\\', '/');
     }
     $userDir = self::getUserDir();
     if ($home !== $userDir . '/.composer' && self::useXdg()) {
         $xdgData = getenv('XDG_DATA_HOME') ?: $userDir . '/.local/share';
         return $xdgData . '/composer';
     }
     return $home;
 }
Example #26
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $this->versionParser = new VersionParser();
     if ($input->getOption('tree')) {
         $this->initStyles($output);
     }
     $composer = $this->getComposer(false);
     $io = $this->getIO();
     if ($input->getOption('installed')) {
         $io->writeError('<warning>You are using the deprecated option "installed". Only installed packages are shown by default now. The --all option can be used to show all packages.</warning>');
     }
     if ($input->getOption('outdated')) {
         $input->setOption('latest', true);
     }
     if ($input->getOption('direct') && ($input->getOption('all') || $input->getOption('available') || $input->getOption('platform'))) {
         $io->writeError('The --direct (-D) option is not usable in combination with --all, --platform (-p) or --available (-a)');
         return 1;
     }
     if ($input->getOption('tree') && ($input->getOption('all') || $input->getOption('available'))) {
         $io->writeError('The --tree (-t) option is not usable in combination with --all or --available (-a)');
         return 1;
     }
     // init repos
     $platformOverrides = array();
     if ($composer) {
         $platformOverrides = $composer->getConfig()->get('platform') ?: array();
     }
     $platformRepo = new PlatformRepository(array(), $platformOverrides);
     $phpVersion = $platformRepo->findPackage('php', '*')->getVersion();
     if ($input->getOption('self')) {
         $package = $this->getComposer()->getPackage();
         $repos = $installedRepo = new ArrayRepository(array($package));
     } elseif ($input->getOption('platform')) {
         $repos = $installedRepo = $platformRepo;
     } elseif ($input->getOption('available')) {
         $installedRepo = $platformRepo;
         if ($composer) {
             $repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
         } else {
             $defaultRepos = RepositoryFactory::defaultRepos($io);
             $repos = new CompositeRepository($defaultRepos);
             $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
         }
     } elseif ($input->getOption('all') && $composer) {
         $localRepo = $composer->getRepositoryManager()->getLocalRepository();
         $installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
         $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
     } elseif ($input->getOption('all')) {
         $defaultRepos = RepositoryFactory::defaultRepos($io);
         $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
         $installedRepo = $platformRepo;
         $repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
     } else {
         $repos = $installedRepo = $this->getComposer()->getRepositoryManager()->getLocalRepository();
     }
     if ($composer) {
         $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'show', $input, $output);
         $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
     }
     if ($input->getOption('latest') && null === $composer) {
         $io->writeError('No composer.json found in the current directory, disabling "latest" option');
         $input->setOption('latest', false);
     }
     $packageFilter = $input->getArgument('package');
     // show single package or single version
     if ($packageFilter && false === strpos($packageFilter, '*') || !empty($package)) {
         if (empty($package)) {
             list($package, $versions) = $this->getPackage($installedRepo, $repos, $input->getArgument('package'), $input->getArgument('version'));
             if (!$package) {
                 throw new \InvalidArgumentException('Package ' . $input->getArgument('package') . ' not found');
             }
         } else {
             $versions = array($package->getPrettyVersion() => $package->getVersion());
         }
         if ($input->getOption('tree')) {
             $this->displayPackageTree($package, $installedRepo, $repos);
         } else {
             $latestPackage = null;
             if ($input->getOption('latest')) {
                 $latestPackage = $this->findLatestPackage($package, $composer, $phpVersion);
             }
             $this->printMeta($package, $versions, $installedRepo, $latestPackage);
             $this->printLinks($package, 'requires');
             $this->printLinks($package, 'devRequires', 'requires (dev)');
             if ($package->getSuggests()) {
                 $io->write("\n<info>suggests</info>");
                 foreach ($package->getSuggests() as $suggested => $reason) {
                     $io->write($suggested . ' <comment>' . $reason . '</comment>');
                 }
             }
             $this->printLinks($package, 'provides');
             $this->printLinks($package, 'conflicts');
             $this->printLinks($package, 'replaces');
         }
         return;
     }
     // show tree view if requested
     if ($input->getOption('tree')) {
         $rootRequires = $this->getRootRequires();
         foreach ($installedRepo->getPackages() as $package) {
             if (in_array($package->getName(), $rootRequires, true)) {
                 $this->displayPackageTree($package, $installedRepo, $repos);
             }
         }
         return 0;
     }
     if ($repos instanceof CompositeRepository) {
         $repos = $repos->getRepositories();
     } elseif (!is_array($repos)) {
         $repos = array($repos);
     }
     // list packages
     $packages = array();
     if (null !== $packageFilter) {
         $packageFilter = '{^' . str_replace('\\*', '.*?', preg_quote($packageFilter)) . '$}i';
     }
     $packageListFilter = array();
     if ($input->getOption('direct')) {
         $packageListFilter = $this->getRootRequires();
     }
     foreach ($repos as $repo) {
         if ($repo === $platformRepo) {
             $type = '<info>platform</info>:';
         } elseif ($repo === $installedRepo || $installedRepo instanceof CompositeRepository && in_array($repo, $installedRepo->getRepositories(), true)) {
             $type = '<info>installed</info>:';
         } else {
             $type = '<comment>available</comment>:';
         }
         if ($repo instanceof ComposerRepository && $repo->hasProviders()) {
             foreach ($repo->getProviderNames() as $name) {
                 if (!$packageFilter || preg_match($packageFilter, $name)) {
                     $packages[$type][$name] = $name;
                 }
             }
         } else {
             foreach ($repo->getPackages() as $package) {
                 if (!isset($packages[$type][$package->getName()]) || !is_object($packages[$type][$package->getName()]) || version_compare($packages[$type][$package->getName()]->getVersion(), $package->getVersion(), '<')) {
                     if (!$packageFilter || preg_match($packageFilter, $package->getName())) {
                         if (!$packageListFilter || in_array($package->getName(), $packageListFilter, true)) {
                             $packages[$type][$package->getName()] = $package;
                         }
                     }
                 }
             }
         }
     }
     $showAllTypes = $input->getOption('all');
     $showLatest = $input->getOption('latest');
     $showMinorOnly = $input->getOption('minor-only');
     $indent = $showAllTypes ? '  ' : '';
     $latestPackages = array();
     foreach (array('<info>platform</info>:' => true, '<comment>available</comment>:' => false, '<info>installed</info>:' => true) as $type => $showVersion) {
         if (isset($packages[$type])) {
             if ($showAllTypes) {
                 $io->write($type);
             }
             ksort($packages[$type]);
             $nameLength = $versionLength = $latestLength = 0;
             foreach ($packages[$type] as $package) {
                 if (is_object($package)) {
                     $nameLength = max($nameLength, strlen($package->getPrettyName()));
                     if ($showVersion) {
                         $versionLength = max($versionLength, strlen($package->getFullPrettyVersion()));
                         if ($showLatest) {
                             $latestPackage = $this->findLatestPackage($package, $composer, $phpVersion, $showMinorOnly);
                             if ($latestPackage === false) {
                                 continue;
                             }
                             $latestPackages[$package->getPrettyName()] = $latestPackage;
                             $latestLength = max($latestLength, strlen($latestPackage->getFullPrettyVersion()));
                         }
                     }
                 } else {
                     $nameLength = max($nameLength, $package);
                 }
             }
             list($width) = $this->getApplication()->getTerminalDimensions();
             if (null === $width) {
                 // In case the width is not detected, we're probably running the command
                 // outside of a real terminal, use space without a limit
                 $width = PHP_INT_MAX;
             }
             if (Platform::isWindows()) {
                 $width--;
             }
             if ($input->getOption('path') && null === $composer) {
                 $io->writeError('No composer.json found in the current directory, disabling "path" option');
                 $input->setOption('path', false);
             }
             $writePath = !$input->getOption('name-only') && $input->getOption('path');
             $writeVersion = !$input->getOption('name-only') && !$input->getOption('path') && $showVersion && $nameLength + $versionLength + 3 <= $width;
             $writeLatest = $writeVersion && $showLatest && $nameLength + $versionLength + $latestLength + 3 <= $width;
             $writeDescription = !$input->getOption('name-only') && !$input->getOption('path') && $nameLength + $versionLength + $latestLength + 24 <= $width;
             foreach ($packages[$type] as $package) {
                 if (is_object($package)) {
                     $latestPackackage = null;
                     if ($showLatest && isset($latestPackages[$package->getPrettyName()])) {
                         $latestPackackage = $latestPackages[$package->getPrettyName()];
                     }
                     if ($input->getOption('outdated') && $latestPackackage && $latestPackackage->getFullPrettyVersion() === $package->getFullPrettyVersion() && !$latestPackackage->isAbandoned()) {
                         continue;
                     }
                     $io->write($indent . str_pad($package->getPrettyName(), $nameLength, ' '), false);
                     if ($writeVersion) {
                         $io->write(' ' . str_pad($package->getFullPrettyVersion(), $versionLength, ' '), false);
                     }
                     if ($writeLatest && $latestPackackage) {
                         $latestVersion = $latestPackackage->getFullPrettyVersion();
                         $style = $this->getVersionStyle($latestPackackage, $package);
                         $io->write(' <' . $style . '>' . str_pad($latestVersion, $latestLength, ' ') . '</' . $style . '>', false);
                     }
                     if ($writeDescription) {
                         $description = strtok($package->getDescription(), "\r\n");
                         $remaining = $width - $nameLength - $versionLength - 4;
                         if ($writeLatest) {
                             $remaining -= $latestLength;
                         }
                         if (strlen($description) > $remaining) {
                             $description = substr($description, 0, $remaining - 3) . '...';
                         }
                         $io->write(' ' . $description, false);
                     }
                     if ($writePath) {
                         $path = strtok(realpath($composer->getInstallationManager()->getInstallPath($package)), "\r\n");
                         $io->write(' ' . $path, false);
                     }
                     if ($latestPackackage && $latestPackackage->isAbandoned()) {
                         $replacement = is_string($latestPackackage->getReplacementPackage()) ? 'Use ' . $latestPackackage->getReplacementPackage() . ' instead' : 'No replacement was suggested';
                         $io->writeError('');
                         $io->writeError(sprintf("<warning>Package %s is abandoned, you should avoid using it. %s.</warning>", $package->getPrettyName(), $replacement), false);
                     }
                 } else {
                     $io->write($indent . $package, false);
                 }
                 $io->write('');
             }
             if ($showAllTypes) {
                 $io->write('');
             }
         }
     }
 }
 protected function normalizePath($path)
 {
     if (Platform::isWindows() && strlen($path) > 0) {
         $basePath = $path;
         $removed = array();
         while (!is_dir($basePath) && $basePath !== '\\') {
             array_unshift($removed, basename($basePath));
             $basePath = dirname($basePath);
         }
         if ($basePath === '\\') {
             return $path;
         }
         $path = rtrim(realpath($basePath) . '/' . implode('/', $removed), '/');
     }
     return $path;
 }
Example #28
0
 /**
  * Get file content or copy action.
  *
  * @param string $originUrl         The origin URL
  * @param string $fileUrl           The file URL
  * @param array  $additionalOptions context options
  * @param string $fileName          the local filename
  * @param bool   $progress          Display the progression
  *
  * @throws TransportException|\Exception
  * @throws TransportException            When the file could not be downloaded
  *
  * @return bool|string
  */
 protected function get($originUrl, $fileUrl, $additionalOptions = array(), $fileName = null, $progress = true)
 {
     if (strpos($originUrl, '.github.com') === strlen($originUrl) - 11) {
         $originUrl = 'github.com';
     }
     $this->scheme = parse_url($fileUrl, PHP_URL_SCHEME);
     $this->bytesMax = 0;
     $this->originUrl = $originUrl;
     $this->fileUrl = $fileUrl;
     $this->fileName = $fileName;
     $this->progress = $progress;
     $this->lastProgress = null;
     $this->retryAuthFailure = true;
     $this->lastHeaders = array();
     $this->redirects = 1;
     // The first request counts.
     // capture username/password from URL if there is one
     if (preg_match('{^https?://(.+):(.+)@([^/]+)}i', $fileUrl, $match)) {
         $this->io->setAuthentication($originUrl, urldecode($match[1]), urldecode($match[2]));
     }
     $tempAdditionalOptions = $additionalOptions;
     if (isset($tempAdditionalOptions['retry-auth-failure'])) {
         $this->retryAuthFailure = (bool) $tempAdditionalOptions['retry-auth-failure'];
         unset($tempAdditionalOptions['retry-auth-failure']);
     }
     $isRedirect = false;
     if (isset($tempAdditionalOptions['redirects'])) {
         $this->redirects = $tempAdditionalOptions['redirects'];
         $isRedirect = true;
         unset($tempAdditionalOptions['redirects']);
     }
     $options = $this->getOptionsForUrl($originUrl, $tempAdditionalOptions);
     unset($tempAdditionalOptions);
     $userlandFollow = isset($options['http']['follow_location']) && !$options['http']['follow_location'];
     $origFileUrl = $fileUrl;
     if (isset($options['github-token'])) {
         // only add the access_token if it is actually a github URL (in case we were redirected to S3)
         if (preg_match('{^https?://([a-z0-9-]+\\.)*github\\.com/}', $fileUrl)) {
             $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token=' . $options['github-token'];
         }
         unset($options['github-token']);
     }
     if (isset($options['gitlab-token'])) {
         $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token=' . $options['gitlab-token'];
         unset($options['gitlab-token']);
     }
     if (isset($options['bitbucket-token'])) {
         $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token=' . $options['bitbucket-token'];
         unset($options['bitbucket-token']);
     }
     if (isset($options['http'])) {
         $options['http']['ignore_errors'] = true;
     }
     if ($this->degradedMode && substr($fileUrl, 0, 21) === 'http://packagist.org/') {
         // access packagist using the resolved IPv4 instead of the hostname to force IPv4 protocol
         $fileUrl = 'http://' . gethostbyname('packagist.org') . substr($fileUrl, 20);
         $degradedPackagist = true;
     }
     $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet')));
     $actualContextOptions = stream_context_get_options($ctx);
     $usingProxy = !empty($actualContextOptions['http']['proxy']) ? ' using proxy ' . $actualContextOptions['http']['proxy'] : '';
     $this->io->writeError((substr($origFileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $origFileUrl . $usingProxy, true, IOInterface::DEBUG);
     unset($origFileUrl, $actualContextOptions);
     // Check for secure HTTP, but allow insecure Packagist calls to $hashed providers as file integrity is verified with sha256
     if ((substr($fileUrl, 0, 23) !== 'http://packagist.org/p/' || false === strpos($fileUrl, '$') && false === strpos($fileUrl, '%24')) && empty($degradedPackagist) && $this->config) {
         $this->config->prohibitUrlByConfig($fileUrl, $this->io);
     }
     if ($this->progress && !$isRedirect) {
         $this->io->writeError("    Downloading: <comment>Connecting...</comment>", false);
     }
     $errorMessage = '';
     $errorCode = 0;
     $result = false;
     set_error_handler(function ($code, $msg) use(&$errorMessage) {
         if ($errorMessage) {
             $errorMessage .= "\n";
         }
         $errorMessage .= preg_replace('{^file_get_contents\\(.*?\\): }', '', $msg);
     });
     try {
         $result = file_get_contents($fileUrl, false, $ctx);
         $contentLength = !empty($http_response_header[0]) ? $this->findHeaderValue($http_response_header, 'content-length') : null;
         if ($contentLength && Platform::strlen($result) < $contentLength) {
             // alas, this is not possible via the stream callback because STREAM_NOTIFY_COMPLETED is documented, but not implemented anywhere in PHP
             throw new TransportException('Content-Length mismatch');
         }
         if (PHP_VERSION_ID < 50600 && !empty($options['ssl']['peer_fingerprint'])) {
             // Emulate fingerprint validation on PHP < 5.6
             $params = stream_context_get_params($ctx);
             $expectedPeerFingerprint = $options['ssl']['peer_fingerprint'];
             $peerFingerprint = TlsHelper::getCertificateFingerprint($params['options']['ssl']['peer_certificate']);
             // Constant time compare??!
             if ($expectedPeerFingerprint !== $peerFingerprint) {
                 throw new TransportException('Peer fingerprint did not match');
             }
         }
     } catch (\Exception $e) {
         if ($e instanceof TransportException && !empty($http_response_header[0])) {
             $e->setHeaders($http_response_header);
             $e->setStatusCode($this->findStatusCode($http_response_header));
         }
         if ($e instanceof TransportException && $result !== false) {
             $e->setResponse($result);
         }
         $result = false;
     }
     if ($errorMessage && !ini_get('allow_url_fopen')) {
         $errorMessage = 'allow_url_fopen must be enabled in php.ini (' . $errorMessage . ')';
     }
     restore_error_handler();
     if (isset($e) && !$this->retry) {
         if (!$this->degradedMode && false !== strpos($e->getMessage(), 'Operation timed out')) {
             $this->degradedMode = true;
             $this->io->writeError(array('<error>' . $e->getMessage() . '</error>', '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>'));
             return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
         }
         throw $e;
     }
     $statusCode = null;
     $contentType = null;
     if (!empty($http_response_header[0])) {
         $statusCode = $this->findStatusCode($http_response_header);
         $contentType = $this->findHeaderValue($http_response_header, 'content-type');
     }
     // check for bitbucket login page asking to authenticate
     if ($originUrl === 'bitbucket.org' && substr($fileUrl, -4) === '.zip' && preg_match('{^text/html\\b}i', $contentType)) {
         $result = false;
         if ($this->retryAuthFailure) {
             $this->promptAuthAndRetry(401);
         }
     }
     // handle 3xx redirects for php<5.6, 304 Not Modified is excluded
     $hasFollowedRedirect = false;
     if ($userlandFollow && $statusCode >= 300 && $statusCode <= 399 && $statusCode !== 304 && $this->redirects < $this->maxRedirects) {
         $hasFollowedRedirect = true;
         $result = $this->handleRedirect($http_response_header, $additionalOptions, $result);
     }
     // fail 4xx and 5xx responses and capture the response
     if ($statusCode && $statusCode >= 400 && $statusCode <= 599) {
         if (!$this->retry) {
             if ($this->progress && !$this->retry && !$isRedirect) {
                 $this->io->overwriteError("    Downloading: <error>Failed</error>");
             }
             $e = new TransportException('The "' . $this->fileUrl . '" file could not be downloaded (' . $http_response_header[0] . ')', $statusCode);
             $e->setHeaders($http_response_header);
             $e->setResponse($result);
             $e->setStatusCode($statusCode);
             throw $e;
         }
         $result = false;
     }
     if ($this->progress && !$this->retry && !$isRedirect) {
         $this->io->overwriteError("    Downloading: " . ($result === false ? '<error>Failed</error>' : '<comment>100%</comment>'));
     }
     // decode gzip
     if ($result && extension_loaded('zlib') && substr($fileUrl, 0, 4) === 'http' && !$hasFollowedRedirect) {
         $decode = 'gzip' === strtolower($this->findHeaderValue($http_response_header, 'content-encoding'));
         if ($decode) {
             try {
                 if (PHP_VERSION_ID >= 50400) {
                     $result = zlib_decode($result);
                 } else {
                     // work around issue with gzuncompress & co that do not work with all gzip checksums
                     $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,' . base64_encode($result));
                 }
                 if (!$result) {
                     throw new TransportException('Failed to decode zlib stream');
                 }
             } catch (\Exception $e) {
                 if ($this->degradedMode) {
                     throw $e;
                 }
                 $this->degradedMode = true;
                 $this->io->writeError(array('<error>Failed to decode response: ' . $e->getMessage() . '</error>', '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>'));
                 return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
             }
         }
     }
     // handle copy command if download was successful
     if (false !== $result && null !== $fileName && !$isRedirect) {
         if ('' === $result) {
             throw new TransportException('"' . $this->fileUrl . '" appears broken, and returned an empty 200 response');
         }
         $errorMessage = '';
         set_error_handler(function ($code, $msg) use(&$errorMessage) {
             if ($errorMessage) {
                 $errorMessage .= "\n";
             }
             $errorMessage .= preg_replace('{^file_put_contents\\(.*?\\): }', '', $msg);
         });
         $result = (bool) file_put_contents($fileName, $result);
         restore_error_handler();
         if (false === $result) {
             throw new TransportException('The "' . $this->fileUrl . '" file could not be written to ' . $fileName . ': ' . $errorMessage);
         }
     }
     // Handle SSL cert match issues
     if (false === $result && false !== strpos($errorMessage, 'Peer certificate') && PHP_VERSION_ID < 50600) {
         // Certificate name error, PHP doesn't support subjectAltName on PHP < 5.6
         // The procedure to handle sAN for older PHP's is:
         //
         // 1. Open socket to remote server and fetch certificate (disabling peer
         //    validation because PHP errors without giving up the certificate.)
         //
         // 2. Verifying the domain in the URL against the names in the sAN field.
         //    If there is a match record the authority [host/port], certificate
         //    common name, and certificate fingerprint.
         //
         // 3. Retry the original request but changing the CN_match parameter to
         //    the common name extracted from the certificate in step 2.
         //
         // 4. To prevent any attempt at being hoodwinked by switching the
         //    certificate between steps 2 and 3 the fingerprint of the certificate
         //    presented in step 3 is compared against the one recorded in step 2.
         if (CaBundle::isOpensslParseSafe()) {
             $certDetails = $this->getCertificateCnAndFp($this->fileUrl, $options);
             if ($certDetails) {
                 $this->peerCertificateMap[$this->getUrlAuthority($this->fileUrl)] = $certDetails;
                 $this->retry = true;
             }
         } else {
             $this->io->writeError(sprintf('<error>Your version of PHP, %s, is affected by CVE-2013-6420 and cannot safely perform certificate validation, we strongly suggest you upgrade.</error>', PHP_VERSION));
         }
     }
     if ($this->retry) {
         $this->retry = false;
         $result = $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
         if ($this->storeAuth && $this->config) {
             $authHelper = new AuthHelper($this->io, $this->config);
             $authHelper->storeAuth($this->originUrl, $this->storeAuth);
             $this->storeAuth = false;
         }
         return $result;
     }
     if (false === $result) {
         $e = new TransportException('The "' . $this->fileUrl . '" file could not be downloaded: ' . $errorMessage, $errorCode);
         if (!empty($http_response_header[0])) {
             $e->setHeaders($http_response_header);
         }
         if (!$this->degradedMode && false !== strpos($e->getMessage(), 'Operation timed out')) {
             $this->degradedMode = true;
             $this->io->writeError(array('<error>' . $e->getMessage() . '</error>', '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>'));
             return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress);
         }
         throw $e;
     }
     if (!empty($http_response_header[0])) {
         $this->lastHeaders = $http_response_header;
     }
     return $result;
 }
 /**
  * {@inheritDoc}
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     // Open file in editor
     if ($input->getOption('editor')) {
         $editor = escapeshellcmd(getenv('EDITOR'));
         if (!$editor) {
             if (Platform::isWindows()) {
                 $editor = 'notepad';
             } else {
                 foreach (array('editor', 'vim', 'vi', 'nano', 'pico', 'ed') as $candidate) {
                     if (exec('which ' . $candidate)) {
                         $editor = $candidate;
                         break;
                     }
                 }
             }
         }
         $file = $input->getOption('auth') ? $this->authConfigFile->getPath() : $this->configFile->getPath();
         system($editor . ' ' . $file . (Platform::isWindows() ? '' : ' > `tty`'));
         return 0;
     }
     if (!$input->getOption('global')) {
         $this->config->merge($this->configFile->read());
         $this->config->merge(array('config' => $this->authConfigFile->exists() ? $this->authConfigFile->read() : array()));
     }
     // List the configuration of the file settings
     if ($input->getOption('list')) {
         $this->listConfiguration($this->config->all(), $this->config->raw(), $output);
         return 0;
     }
     $settingKey = $input->getArgument('setting-key');
     if (!$settingKey) {
         return 0;
     }
     // If the user enters in a config variable, parse it and save to file
     if (array() !== $input->getArgument('setting-value') && $input->getOption('unset')) {
         throw new \RuntimeException('You can not combine a setting value with --unset');
     }
     // show the value if no value is provided
     if (array() === $input->getArgument('setting-value') && !$input->getOption('unset')) {
         $data = $this->config->all();
         if (preg_match('/^repos?(?:itories)?(?:\\.(.+))?/', $settingKey, $matches)) {
             if (empty($matches[1])) {
                 $value = isset($data['repositories']) ? $data['repositories'] : array();
             } else {
                 if (!isset($data['repositories'][$matches[1]])) {
                     throw new \InvalidArgumentException('There is no ' . $matches[1] . ' repository defined');
                 }
                 $value = $data['repositories'][$matches[1]];
             }
         } elseif (strpos($settingKey, '.')) {
             $bits = explode('.', $settingKey);
             $data = $data['config'];
             $match = false;
             foreach ($bits as $bit) {
                 $key = isset($key) ? $key . '.' . $bit : $bit;
                 $match = false;
                 if (isset($data[$key])) {
                     $match = true;
                     $data = $data[$key];
                     unset($key);
                 }
             }
             if (!$match) {
                 throw new \RuntimeException($settingKey . ' is not defined.');
             }
             $value = $data;
         } elseif (isset($data['config'][$settingKey])) {
             $value = $this->config->get($settingKey, $input->getOption('absolute') ? 0 : Config::RELATIVE_PATHS);
         } else {
             throw new \RuntimeException($settingKey . ' is not defined');
         }
         if (is_array($value)) {
             $value = json_encode($value);
         }
         $this->getIO()->write($value);
         return 0;
     }
     $values = $input->getArgument('setting-value');
     // what the user is trying to add/change
     $booleanValidator = function ($val) {
         return in_array($val, array('true', 'false', '1', '0'), true);
     };
     $booleanNormalizer = function ($val) {
         return $val !== 'false' && (bool) $val;
     };
     // handle config values
     $uniqueConfigValues = array('process-timeout' => array('is_numeric', 'intval'), 'use-include-path' => array($booleanValidator, $booleanNormalizer), 'preferred-install' => array(function ($val) {
         return in_array($val, array('auto', 'source', 'dist'), true);
     }, function ($val) {
         return $val;
     }), 'store-auths' => array(function ($val) {
         return in_array($val, array('true', 'false', 'prompt'), true);
     }, function ($val) {
         if ('prompt' === $val) {
             return 'prompt';
         }
         return $val !== 'false' && (bool) $val;
     }), 'notify-on-install' => array($booleanValidator, $booleanNormalizer), 'vendor-dir' => array('is_string', function ($val) {
         return $val;
     }), 'bin-dir' => array('is_string', function ($val) {
         return $val;
     }), 'archive-dir' => array('is_string', function ($val) {
         return $val;
     }), 'archive-format' => array('is_string', function ($val) {
         return $val;
     }), 'data-dir' => array('is_string', function ($val) {
         return $val;
     }), 'cache-dir' => array('is_string', function ($val) {
         return $val;
     }), 'cache-files-dir' => array('is_string', function ($val) {
         return $val;
     }), 'cache-repo-dir' => array('is_string', function ($val) {
         return $val;
     }), 'cache-vcs-dir' => array('is_string', function ($val) {
         return $val;
     }), 'cache-ttl' => array('is_numeric', 'intval'), 'cache-files-ttl' => array('is_numeric', 'intval'), 'cache-files-maxsize' => array(function ($val) {
         return preg_match('/^\\s*([0-9.]+)\\s*(?:([kmg])(?:i?b)?)?\\s*$/i', $val) > 0;
     }, function ($val) {
         return $val;
     }), 'bin-compat' => array(function ($val) {
         return in_array($val, array('auto', 'full'));
     }, function ($val) {
         return $val;
     }), 'discard-changes' => array(function ($val) {
         return in_array($val, array('stash', 'true', 'false', '1', '0'), true);
     }, function ($val) {
         if ('stash' === $val) {
             return 'stash';
         }
         return $val !== 'false' && (bool) $val;
     }), 'autoloader-suffix' => array('is_string', function ($val) {
         return $val === 'null' ? null : $val;
     }), 'sort-packages' => array($booleanValidator, $booleanNormalizer), 'optimize-autoloader' => array($booleanValidator, $booleanNormalizer), 'classmap-authoritative' => array($booleanValidator, $booleanNormalizer), 'prepend-autoloader' => array($booleanValidator, $booleanNormalizer), 'disable-tls' => array($booleanValidator, $booleanNormalizer), 'secure-http' => array($booleanValidator, $booleanNormalizer), 'cafile' => array(function ($val) {
         return file_exists($val) && is_readable($val);
     }, function ($val) {
         return $val === 'null' ? null : $val;
     }), 'capath' => array(function ($val) {
         return is_dir($val) && is_readable($val);
     }, function ($val) {
         return $val === 'null' ? null : $val;
     }), 'github-expose-hostname' => array($booleanValidator, $booleanNormalizer));
     $multiConfigValues = array('github-protocols' => array(function ($vals) {
         if (!is_array($vals)) {
             return 'array expected';
         }
         foreach ($vals as $val) {
             if (!in_array($val, array('git', 'https', 'ssh'))) {
                 return 'valid protocols include: git, https, ssh';
             }
         }
         return true;
     }, function ($vals) {
         return $vals;
     }), 'github-domains' => array(function ($vals) {
         if (!is_array($vals)) {
             return 'array expected';
         }
         return true;
     }, function ($vals) {
         return $vals;
     }), 'gitlab-domains' => array(function ($vals) {
         if (!is_array($vals)) {
             return 'array expected';
         }
         return true;
     }, function ($vals) {
         return $vals;
     }));
     foreach ($uniqueConfigValues as $name => $callbacks) {
         if ($settingKey === $name) {
             if ($input->getOption('unset')) {
                 return $this->configSource->removeConfigSetting($settingKey);
             }
             list($validator, $normalizer) = $callbacks;
             if (1 !== count($values)) {
                 throw new \RuntimeException('You can only pass one value. Example: php composer.phar config process-timeout 300');
             }
             if (true !== ($validation = $validator($values[0]))) {
                 throw new \RuntimeException(sprintf('"%s" is an invalid value' . ($validation ? ' (' . $validation . ')' : ''), $values[0]));
             }
             return $this->configSource->addConfigSetting($settingKey, $normalizer($values[0]));
         }
     }
     foreach ($multiConfigValues as $name => $callbacks) {
         if ($settingKey === $name) {
             if ($input->getOption('unset')) {
                 return $this->configSource->removeConfigSetting($settingKey);
             }
             list($validator, $normalizer) = $callbacks;
             if (true !== ($validation = $validator($values))) {
                 throw new \RuntimeException(sprintf('%s is an invalid value' . ($validation ? ' (' . $validation . ')' : ''), json_encode($values)));
             }
             return $this->configSource->addConfigSetting($settingKey, $normalizer($values));
         }
     }
     // handle repositories
     if (preg_match('/^repos?(?:itories)?\\.(.+)/', $settingKey, $matches)) {
         if ($input->getOption('unset')) {
             return $this->configSource->removeRepository($matches[1]);
         }
         if (2 === count($values)) {
             return $this->configSource->addRepository($matches[1], array('type' => $values[0], 'url' => $values[1]));
         }
         if (1 === count($values)) {
             $value = strtolower($values[0]);
             if (true === $booleanValidator($value)) {
                 if (false === $booleanNormalizer($value)) {
                     return $this->configSource->addRepository($matches[1], false);
                 }
             } else {
                 $value = JsonFile::parseJson($values[0]);
                 return $this->configSource->addRepository($matches[1], $value);
             }
         }
         throw new \RuntimeException('You must pass the type and a url. Example: php composer.phar config repositories.foo vcs https://bar.com');
     }
     // handle platform
     if (preg_match('/^platform\\.(.+)/', $settingKey, $matches)) {
         if ($input->getOption('unset')) {
             return $this->configSource->removeConfigSetting($settingKey);
         }
         return $this->configSource->addConfigSetting($settingKey, $values[0]);
     }
     // handle github-oauth
     if (preg_match('/^(github-oauth|gitlab-oauth|http-basic)\\.(.+)/', $settingKey, $matches)) {
         if ($input->getOption('unset')) {
             $this->authConfigSource->removeConfigSetting($matches[1] . '.' . $matches[2]);
             $this->configSource->removeConfigSetting($matches[1] . '.' . $matches[2]);
             return;
         }
         if ($matches[1] === 'github-oauth' || $matches[1] === 'gitlab-oauth') {
             if (1 !== count($values)) {
                 throw new \RuntimeException('Too many arguments, expected only one token');
             }
             $this->configSource->removeConfigSetting($matches[1] . '.' . $matches[2]);
             $this->authConfigSource->addConfigSetting($matches[1] . '.' . $matches[2], $values[0]);
         } elseif ($matches[1] === 'http-basic') {
             if (2 !== count($values)) {
                 throw new \RuntimeException('Expected two arguments (username, password), got ' . count($values));
             }
             $this->configSource->removeConfigSetting($matches[1] . '.' . $matches[2]);
             $this->authConfigSource->addConfigSetting($matches[1] . '.' . $matches[2], array('username' => $values[0], 'password' => $values[1]));
         }
         return;
     }
     throw new \InvalidArgumentException('Setting ' . $settingKey . ' does not exist or is not supported by this command');
 }
Example #30
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $this->versionParser = new VersionParser();
     if ($input->getOption('tree')) {
         $this->initStyles($output);
     }
     $composer = $this->getComposer(false);
     $io = $this->getIO();
     if ($input->getOption('tree') && !$input->getOption('installed')) {
         $io->writeError('The --tree (-t) option is only usable in combination with --installed (-i) or by passing a single package name to show, assuming -i');
         $input->setOption('installed', true);
     }
     // init repos
     $platformOverrides = array();
     if ($composer) {
         $platformOverrides = $composer->getConfig()->get('platform') ?: array();
     }
     $platformRepo = new PlatformRepository(array(), $platformOverrides);
     if ($input->getOption('self')) {
         $package = $this->getComposer()->getPackage();
         $repos = $installedRepo = new ArrayRepository(array($package));
     } elseif ($input->getOption('platform')) {
         $repos = $installedRepo = $platformRepo;
     } elseif ($input->getOption('installed')) {
         $repos = $installedRepo = $this->getComposer()->getRepositoryManager()->getLocalRepository();
     } elseif ($input->getOption('available')) {
         $installedRepo = $platformRepo;
         if ($composer) {
             $repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
         } else {
             $defaultRepos = Factory::createDefaultRepositories($io);
             $repos = new CompositeRepository($defaultRepos);
             $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
         }
     } elseif ($composer) {
         $localRepo = $composer->getRepositoryManager()->getLocalRepository();
         $installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
         $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
     } else {
         $defaultRepos = Factory::createDefaultRepositories($io);
         $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
         $installedRepo = $platformRepo;
         $repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));
     }
     if ($composer) {
         $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'show', $input, $output);
         $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
     }
     // show single package or single version
     if ($input->getArgument('package') || !empty($package)) {
         $versions = array();
         if (empty($package)) {
             list($package, $versions) = $this->getPackage($installedRepo, $repos, $input->getArgument('package'), $input->getArgument('version'));
             if (!$package) {
                 throw new \InvalidArgumentException('Package ' . $input->getArgument('package') . ' not found');
             }
         } else {
             $versions = array($package->getPrettyVersion() => $package->getVersion());
         }
         if ($input->getOption('tree')) {
             $this->displayPackageTree($package, $installedRepo, $repos, $output);
         } else {
             $this->printMeta($package, $versions, $installedRepo, $repos);
             $this->printLinks($package, 'requires');
             $this->printLinks($package, 'devRequires', 'requires (dev)');
             if ($package->getSuggests()) {
                 $io->write("\n<info>suggests</info>");
                 foreach ($package->getSuggests() as $suggested => $reason) {
                     $io->write($suggested . ' <comment>' . $reason . '</comment>');
                 }
             }
             $this->printLinks($package, 'provides');
             $this->printLinks($package, 'conflicts');
             $this->printLinks($package, 'replaces');
         }
         return;
     }
     // show tree view if requested
     if ($input->getOption('tree')) {
         $rootPackage = $this->getComposer()->getPackage();
         $rootRequires = array_map('strtolower', array_keys(array_merge($rootPackage->getRequires(), $rootPackage->getDevRequires())));
         foreach ($installedRepo->getPackages() as $package) {
             if (in_array($package->getName(), $rootRequires, true)) {
                 $this->displayPackageTree($package, $installedRepo, $repos, $output);
             }
         }
         return 0;
     }
     if ($repos instanceof CompositeRepository) {
         $repos = $repos->getRepositories();
     } elseif (!is_array($repos)) {
         $repos = array($repos);
     }
     // list packages
     $packages = array();
     foreach ($repos as $repo) {
         if ($repo === $platformRepo) {
             $type = '<info>platform</info>:';
         } elseif ($repo === $installedRepo || $installedRepo instanceof CompositeRepository && in_array($repo, $installedRepo->getRepositories(), true)) {
             $type = '<info>installed</info>:';
         } else {
             $type = '<comment>available</comment>:';
         }
         if ($repo instanceof ComposerRepository && $repo->hasProviders()) {
             foreach ($repo->getProviderNames() as $name) {
                 $packages[$type][$name] = $name;
             }
         } else {
             foreach ($repo->getPackages() as $package) {
                 if (!isset($packages[$type][$package->getName()]) || !is_object($packages[$type][$package->getName()]) || version_compare($packages[$type][$package->getName()]->getVersion(), $package->getVersion(), '<')) {
                     $packages[$type][$package->getName()] = $package;
                 }
             }
         }
     }
     $showAllTypes = !$input->getOption('platform') && !$input->getOption('installed') && !$input->getOption('available');
     $indent = $showAllTypes ? '  ' : '';
     foreach (array('<info>platform</info>:' => true, '<comment>available</comment>:' => false, '<info>installed</info>:' => true) as $type => $showVersion) {
         if (isset($packages[$type])) {
             if ($showAllTypes) {
                 $io->write($type);
             }
             ksort($packages[$type]);
             $nameLength = $versionLength = 0;
             foreach ($packages[$type] as $package) {
                 if (is_object($package)) {
                     $nameLength = max($nameLength, strlen($package->getPrettyName()));
                     $versionLength = max($versionLength, strlen($package->getFullPrettyVersion()));
                 } else {
                     $nameLength = max($nameLength, $package);
                 }
             }
             list($width) = $this->getApplication()->getTerminalDimensions();
             if (null === $width) {
                 // In case the width is not detected, we're probably running the command
                 // outside of a real terminal, use space without a limit
                 $width = PHP_INT_MAX;
             }
             if (Platform::isWindows()) {
                 $width--;
             }
             if ($input->getOption('path') && null === $composer) {
                 $io->writeError('No composer.json found in the current directory, disabling "path" option');
                 $input->setOption('path', false);
             }
             $writePath = !$input->getOption('name-only') && $input->getOption('path');
             $writeVersion = !$input->getOption('name-only') && !$input->getOption('path') && $showVersion && $nameLength + $versionLength + 3 <= $width;
             $writeDescription = !$input->getOption('name-only') && !$input->getOption('path') && $nameLength + ($showVersion ? $versionLength : 0) + 24 <= $width;
             foreach ($packages[$type] as $package) {
                 if (is_object($package)) {
                     $io->write($indent . str_pad($package->getPrettyName(), $nameLength, ' '), false);
                     if ($writeVersion) {
                         $io->write(' ' . str_pad($package->getFullPrettyVersion(), $versionLength, ' '), false);
                     }
                     if ($writeDescription) {
                         $description = strtok($package->getDescription(), "\r\n");
                         $remaining = $width - $nameLength - $versionLength - 4;
                         if (strlen($description) > $remaining) {
                             $description = substr($description, 0, $remaining - 3) . '...';
                         }
                         $io->write(' ' . $description, false);
                     }
                     if ($writePath) {
                         $path = strtok(realpath($composer->getInstallationManager()->getInstallPath($package)), "\r\n");
                         $io->write(' ' . $path, false);
                     }
                 } else {
                     $io->write($indent . $package, false);
                 }
                 $io->write('');
             }
             if ($showAllTypes) {
                 $io->write('');
             }
         }
     }
 }