/** * Download the file and return its contents * * @param string $url The URL from where to download * @return string Contents of the URL */ public function getContents($url) { if (array_key_exists($url, $this->cache)) { return $this->cache[$url]; } return $this->cache[$url] = $this->remoteFileSystem->getContents($this->getOriginUrl($url), $url); }
/** * Read content from remote filesystem. * * @param $origin string server * @param $path string relative path to content * @throws \UnexpectedValueException * @return \SimpleXMLElement */ protected function requestContent($origin, $path) { $url = rtrim($origin, '/') . '/' . ltrim($path, '/'); $content = $this->rfs->getContents($origin, $url, false); if (!$content) { throw new \UnexpectedValueException('The PEAR channel at ' . $url . ' did not respond.'); } return str_replace('http://pear.php.net/rest/', 'https://pear.php.net/rest/', $content); }
/** * Read content from remote filesystem. * * @param $origin string server * @param $path string relative path to content * @return \SimpleXMLElement */ protected function requestContent($origin, $path) { $url = rtrim($origin, '/') . '/' . ltrim($path, '/'); $content = $this->rfs->getContents($origin, $url, false); if (!$content) { throw new \UnexpectedValueException('The PEAR channel at ' . $url . ' did not respond.'); } return $content; }
/** * @inheritDoc */ public function getContents($originUrl, $fileUrl, $progress = true, $options = array()) { $res = null; if (isset($options['http']['header'])) { $headers = $options['http']['header']; } elseif (isset($options['https']['header'])) { $headers = $options['https']['header']; } else { $headers = array(); } try { $this->req = new FetchRequest($fileUrl, $this->io, $this->config); foreach ($headers as $header) { list($key, $val) = explode(':', $header, 2); $this->req->addHeader($key, $val); } $res = $this->req->fetch(); } catch (\Exception $e) { $this->io->writeError((string) $e); } if (false === $res) { return parent::getContents($originUrl, $fileUrl, $progress, $options); } else { return $res; } }
protected function execute(InputInterface $input, OutputInterface $output) { $rfs = new RemoteFilesystem($this->getIO()); $latest = trim($rfs->getContents('getcomposer.org', 'http://getcomposer.org/version', false)); if (Composer::VERSION !== $latest) { $output->writeln(sprintf("Updating to version <info>%s</info>.", $latest)); $remoteFilename = 'http://getcomposer.org/composer.phar'; $localFilename = $_SERVER['argv'][0]; $tempFilename = basename($localFilename, '.phar') . '-temp.phar'; $rfs->copy('getcomposer.org', $remoteFilename, $tempFilename); try { chmod($tempFilename, 0777 & ~umask()); // test the phar validity $phar = new \Phar($tempFilename); // free the variable to unlock the file unset($phar); rename($tempFilename, $localFilename); } catch (\Exception $e) { @unlink($tempFilename); if (!$e instanceof \UnexpectedValueException && !$e instanceof \PharException) { throw $e; } $output->writeln('<error>The download is corrupted (' . $e->getMessage() . ').</error>'); $output->writeln('<error>Please re-run the self-update command to try again.</error>'); } } else { $output->writeln("<info>You are using the latest composer version.</info>"); } }
protected function execute(InputInterface $input, OutputInterface $output) { $baseUrl = (extension_loaded('openssl') ? 'https' : 'http') . '://' . self::HOMEPAGE; $config = Factory::createConfig(); $remoteFilesystem = new RemoteFilesystem($this->getIO(), $config); $cacheDir = $config->get('cache-dir'); $rollbackDir = $config->get('home'); $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0]; // check if current dir is writable and if not try the cache dir from settings $tmpDir = is_writable(dirname($localFilename)) ? dirname($localFilename) : $cacheDir; // check for permissions in local filesystem before start connection process if (!is_writable($tmpDir)) { throw new FilesystemException('Composer update failed: the "' . $tmpDir . '" directory used to download the temp file could not be written'); } if (!is_writable($localFilename)) { throw new FilesystemException('Composer update failed: the "' . $localFilename . '" file could not be written'); } if ($input->getOption('rollback')) { return $this->rollback($output, $rollbackDir, $localFilename); } $latestVersion = trim($remoteFilesystem->getContents(self::HOMEPAGE, $baseUrl . '/version', false)); $updateVersion = $input->getArgument('version') ?: $latestVersion; if (preg_match('{^[0-9a-f]{40}$}', $updateVersion) && $updateVersion !== $latestVersion) { $output->writeln('<error>You can not update to a specific SHA-1 as those phars are not available for download</error>'); return 1; } if (Composer::VERSION === $updateVersion) { $output->writeln('<info>You are already using composer version ' . $updateVersion . '.</info>'); return 0; } $tempFilename = $tmpDir . '/' . basename($localFilename, '.phar') . '-temp.phar'; $backupFile = sprintf('%s/%s-%s%s', $rollbackDir, strtr(Composer::RELEASE_DATE, ' :', '_-'), preg_replace('{^([0-9a-f]{7})[0-9a-f]{33}$}', '$1', Composer::VERSION), self::OLD_INSTALL_EXT); $output->writeln(sprintf("Updating to version <info>%s</info>.", $updateVersion)); $remoteFilename = $baseUrl . (preg_match('{^[0-9a-f]{40}$}', $updateVersion) ? '/composer.phar' : "/download/{$updateVersion}/composer.phar"); $remoteFilesystem->copy(self::HOMEPAGE, $remoteFilename, $tempFilename); if (!file_exists($tempFilename)) { $output->writeln('<error>The download of the new composer version failed for an unexpected reason</error>'); return 1; } // remove saved installations of composer if ($input->getOption('clean-backups')) { $finder = $this->getOldInstallationFinder($rollbackDir); $fs = new Filesystem(); foreach ($finder as $file) { $file = (string) $file; $output->writeln('<info>Removing: ' . $file . '</info>'); $fs->remove($file); } } if ($err = $this->setLocalPhar($localFilename, $tempFilename, $backupFile)) { $output->writeln('<error>The file is corrupted (' . $err->getMessage() . ').</error>'); $output->writeln('<error>Please re-run the self-update command to try again.</error>'); return 1; } if (file_exists($backupFile)) { $output->writeln('Use <info>composer self-update --rollback</info> to return to version ' . Composer::VERSION); } else { $output->writeln('<warning>A backup of the current version could not be written to ' . $backupFile . ', no rollback possible</warning>'); } }
/** * @param InputInterface $input The input instance * @param OutputInterface $output The output instance */ protected function execute(InputInterface $input, OutputInterface $output) { $verbose = $input->getOption('verbose'); $configFile = $input->getArgument('file'); $packagesFilter = $input->getArgument('packages'); $skipErrors = (bool) $input->getOption('skip-errors'); // load auth.json authentication information and pass it to the io interface $io = $this->getIO(); $io->loadConfiguration($this->getConfiguration()); if (preg_match('{^https?://}i', $configFile)) { $rfs = new RemoteFilesystem($io); $contents = $rfs->getContents(parse_url($configFile, PHP_URL_HOST), $configFile, false); $config = JsonFile::parseJson($contents, $configFile); } else { $file = new JsonFile($configFile); if (!$file->exists()) { $output->writeln('<error>File not found: ' . $configFile . '</error>'); return 1; } $config = $file->read(); } // disable packagist by default unset(Config::$defaultRepositories['packagist']); if (!($outputDir = $input->getArgument('output-dir'))) { $outputDir = isset($config['output-dir']) ? $config['output-dir'] : null; } if (null === $outputDir) { throw new \InvalidArgumentException('The output dir must be specified as second argument or be configured inside ' . $input->getArgument('file')); } $composer = $this->getApplication()->getComposer(true, $config); $packagesBuilder = new PackagesBuilder($output, $outputDir, $config, $skipErrors); $packagesBuilder->setPackagesFilter($packagesFilter); $packages = $packagesBuilder->select($composer, $verbose); if (isset($config['archive']['directory'])) { $downloads = new ArchiveBuilder($output, $outputDir, $config, $skipErrors); $downloads->setInputInterface($input)->setHelperSet($this->getApplication()->getHelperSet()); $downloads->dump($packages); } if (!$packagesBuilder->hasFilterForPackages()) { // in case of an active package filter we need to load the dumped packages.json and merge the // updated packages in $oldPackages = $packagesBuilder->load(); $packages += $oldPackages; ksort($packages); } $packagesBuilder->dump($packages); if ($htmlView = !$input->getOption('no-html-output')) { $htmlView = !isset($config['output-html']) || $config['output-html']; } if ($htmlView) { $web = new WebBuilder($output, $outputDir, $config, $skipErrors); $web->setRootPackage($composer->getPackage()); $web->dump($packages); } }
/** * @param InputInterface $input The input instance * @param OutputInterface $output The output instance */ protected function execute(InputInterface $input, OutputInterface $output) { $verbose = $input->getOption('verbose'); $configFile = $input->getArgument('file'); if (preg_match('{^https?://}i', $configFile)) { $rfs = new RemoteFilesystem($this->getIO()); $contents = $rfs->getContents(parse_url($configFile, PHP_URL_HOST), $configFile, false); $config = JsonFile::parseJson($contents, $configFile); } else { $file = new JsonFile($configFile); if (!$file->exists()) { $output->writeln('<error>File not found: ' . $configFile . '</error>'); return 1; } $config = $file->read(); } // disable packagist by default unset(Config::$defaultRepositories['packagist']); // fetch options $requireAll = isset($config['require-all']) && true === $config['require-all']; $requireDependencies = isset($config['require-dependencies']) && true === $config['require-dependencies']; if (!$requireAll && !isset($config['require'])) { $output->writeln('No explicit requires defined, enabling require-all'); $requireAll = true; } if (!($outputDir = $input->getArgument('output-dir'))) { $outputDir = isset($config['output-dir']) ? $config['output-dir'] : null; } if (null === $outputDir) { throw new \InvalidArgumentException('The output dir must be specified as second argument or be configured inside ' . $input->getArgument('file')); } $composer = $this->getApplication()->getComposer(true, $config); $packages = $this->selectPackages($composer, $output, $verbose, $requireAll, $requireDependencies); if ($htmlView = !$input->getOption('no-html-output')) { $htmlView = !isset($config['output-html']) || $config['output-html']; } if (isset($config['archive']['directory'])) { $skipErrors = (bool) $input->getOption('skip-errors'); $this->dumpDownloads($config, $packages, $output, $outputDir, $skipErrors); } $filename = $outputDir . '/packages.json'; $this->dumpJson($packages, $output, $filename); if ($htmlView) { $dependencies = array(); foreach ($packages as $package) { foreach ($package->getRequires() as $link) { $dependencies[$link->getTarget()][$link->getSource()] = $link->getSource(); } } $rootPackage = $composer->getPackage(); $twigTemplate = isset($config['twig-template']) ? $config['twig-template'] : null; $this->dumpWeb($packages, $output, $rootPackage, $outputDir, $twigTemplate, $dependencies); } }
/** * @return string * @throws \Exception */ protected function downloadComposer() { $this->output->writeln('<info>Could not find composer. Try to download it.</info>'); $io = new ConsoleIO($this->input, $this->output, $this->getCommand()->getHelperSet()); $rfs = new RemoteFilesystem($io); $composerInstaller = $rfs->getContents('getcomposer.org', 'https://getcomposer.org/installer', true); $tempComposerInstaller = $this->config['installationFolder'] . '/_composer_installer.php'; file_put_contents($tempComposerInstaller, $composerInstaller); if (OperatingSystem::isWindows()) { $installCommand = 'php ' . $tempComposerInstaller . ' --force'; } else { $installCommand = '/usr/bin/env php ' . $tempComposerInstaller . ' --force'; } $this->output->writeln('<comment>' . $installCommand . '</comment>'); exec($installCommand, $installationOutput, $returnStatus); unlink($tempComposerInstaller); $installationOutput = implode(PHP_EOL, $installationOutput); if ($returnStatus !== self::EXEC_STATUS_OK) { throw new \Exception('Installation failed.' . $installationOutput); } else { $this->output->writeln('<info>Successfully installed composer to Magento root</info>'); } return $this->config['installationFolder'] . '/composer.phar'; }
/** * Get the remote content. * * @param string $url The URL of content * * @return mixed The result */ protected function getContents($url) { return $this->remoteFilesystem->getContents($this->originUrl, $url, false); }
public function testGetContents() { $fs = new RemoteFilesystem($this->getMock('Composer\\IO\\IOInterface')); $this->assertContains('testGetContents', $fs->getContents('http://example.org', 'file://' . __FILE__)); }
private function updateGitHubInfo(RemoteFilesystem $rfs, Package $package, $owner, $repo, VcsRepository $repository) { $baseApiUrl = 'https://api.github.com/repos/' . $owner . '/' . $repo; $driver = $repository->getDriver(); if (!$driver instanceof GitHubDriver) { return; } $repoData = $driver->getRepoData(); try { $opts = ['http' => ['header' => ['Accept: application/vnd.github.v3.html']]]; $readme = $rfs->getContents('github.com', $baseApiUrl . '/readme', false, $opts); } catch (\Exception $e) { if (!$e instanceof \Composer\Downloader\TransportException || $e->getCode() !== 404) { return; } // 404s just mean no readme present so we proceed with the rest } if (!empty($readme)) { $elements = array('p', 'br', 'small', 'strong', 'b', 'em', 'i', 'strike', 'sub', 'sup', 'ins', 'del', 'ol', 'ul', 'li', 'h1', 'h2', 'h3', 'dl', 'dd', 'dt', 'pre', 'code', 'samp', 'kbd', 'q', 'blockquote', 'abbr', 'cite', 'table', 'thead', 'tbody', 'th', 'tr', 'td', 'a[href|target|rel|id]', 'img[src|title|alt|width|height|style]'); $config = \HTMLPurifier_Config::createDefault(); $config->set('HTML.Allowed', implode(',', $elements)); $config->set('Attr.EnableID', true); $config->set('Attr.AllowedFrameTargets', ['_blank']); $purifier = new \HTMLPurifier($config); $readme = $purifier->purify($readme); $dom = new \DOMDocument(); $dom->loadHTML('<?xml encoding="UTF-8">' . $readme); // Links can not be trusted, mark them nofollow and convert relative to absolute links $links = $dom->getElementsByTagName('a'); foreach ($links as $link) { $link->setAttribute('rel', 'nofollow noopener external'); if ('#' === substr($link->getAttribute('href'), 0, 1)) { $link->setAttribute('href', '#user-content-' . substr($link->getAttribute('href'), 1)); } elseif ('mailto:' === substr($link->getAttribute('href'), 0, 7)) { // do nothing } elseif (false === strpos($link->getAttribute('href'), '//')) { $link->setAttribute('href', 'https://github.com/' . $owner . '/' . $repo . '/blob/HEAD/' . $link->getAttribute('href')); } } // convert relative to absolute images $images = $dom->getElementsByTagName('img'); foreach ($images as $img) { if (false === strpos($img->getAttribute('src'), '//')) { $img->setAttribute('src', 'https://raw.github.com/' . $owner . '/' . $repo . '/HEAD/' . $img->getAttribute('src')); } } // remove first title as it's usually the project name which we don't need if ($dom->getElementsByTagName('h1')->length) { $first = $dom->getElementsByTagName('h1')->item(0); $first->parentNode->removeChild($first); } elseif ($dom->getElementsByTagName('h2')->length) { $first = $dom->getElementsByTagName('h2')->item(0); $first->parentNode->removeChild($first); } $readme = $dom->saveHTML(); $readme = substr($readme, strpos($readme, '<body>') + 6); $readme = substr($readme, 0, strrpos($readme, '</body>')); $package->setReadme($readme); } if (!empty($repoData['language'])) { $package->setLanguage($repoData['language']); } if (isset($repoData['stargazers_count'])) { $package->setGitHubStars($repoData['stargazers_count']); } if (isset($repoData['subscribers_count'])) { $package->setGitHubWatches($repoData['subscribers_count']); } if (isset($repoData['network_count'])) { $package->setGitHubForks($repoData['network_count']); } if (isset($repoData['open_issues_count'])) { $package->setGitHubOpenIssues($repoData['open_issues_count']); } }
/** * Retrieve the available versions of a package. * * NOTE: This method will become inaccessible as soon as the installation is complete. * * @param string $vendor The vendor name of the package. * * @param string $project The name of the package. * * @return JsonResponse * * @ApiDoc( * section="install", * statusCodes = { * 201 = "When everything worked out ok", * 406 = "When the installation is already complete" * }, * ) * @ApiDescription( * response={ * "versions" = { * "actualType" = "collection", * "subType" = "object", * "description" = "The list of versions", * "children" = { * "name" = { * "dataType" = "string", * "description" = "The name of the package" * }, * "version" = { * "dataType" = "string", * "description" = "The version of the package" * }, * "version_normalized" = { * "dataType" = "string", * "description" = "The normalized version of the package" * }, * "reference" = { * "dataType" = "string", * "description" = "The optional reference" * } * } * } * } * ) */ public function getProjectVersionsAction($vendor, $project) { $this->checkUninstalled(); $url = sprintf('https://packagist.org/packages/%s/%s.json', $vendor, $project); $rfs = new RemoteFilesystem($this->getInputOutput()); $results = $rfs->getContents($url, $url); $data = new JsonArray($results); $versions = []; foreach ($data->get('package/versions') as $information) { $version = ['name' => $information['name'], 'version' => $information['version'], 'version_normalized' => $information['version_normalized']]; $normalized = $information['version']; if ('dev-' === substr($normalized, 0, 4)) { if (isset($information['extra']['branch-alias'][$normalized])) { $version['version_normalized'] = $information['extra']['branch-alias'][$normalized]; } } if (isset($information['source']['reference'])) { $version['reference'] = $information['source']['reference']; } elseif (isset($information['dist']['reference'])) { $version['reference'] = $information['dist']['reference']; } $versions[] = $version; } return new JsonResponse(['status' => 'OK', 'versions' => $versions]); }
/** * Check online for the latest version available. * * @return string */ protected function getLatestVersion() { $latestVersion = trim($this->rfs->getContents($this->getOriginName(), $this->getBaseUrl() . '/version', false)); return $latestVersion; }
/** * @param InputInterface $input The input instance * @param OutputInterface $output The output instance * * @throws JsonValidationException * @throws ParsingException * @throws \Exception * * @return int */ protected function execute(InputInterface $input, OutputInterface $output) { $verbose = $input->getOption('verbose'); $configFile = $input->getArgument('file'); $packagesFilter = $input->getArgument('packages'); $repositoryUrl = $input->getOption('repository-url'); $skipErrors = (bool) $input->getOption('skip-errors'); // load auth.json authentication information and pass it to the io interface $io = $this->getIO(); $io->loadConfiguration($this->getConfiguration()); if (preg_match('{^https?://}i', $configFile)) { $rfs = new RemoteFilesystem($io); $contents = $rfs->getContents(parse_url($configFile, PHP_URL_HOST), $configFile, false); $config = JsonFile::parseJson($contents, $configFile); } else { $file = new JsonFile($configFile); if (!$file->exists()) { $output->writeln('<error>File not found: ' . $configFile . '</error>'); return 1; } $config = $file->read(); } try { $this->check($configFile); } catch (JsonValidationException $e) { foreach ($e->getErrors() as $error) { $output->writeln(sprintf('<error>%s</error>', $error)); } if (!$skipErrors) { throw $e; } $output->writeln(sprintf('<warning>%s: %s</warning>', get_class($e), $e->getMessage())); } catch (ParsingException $e) { if (!$skipErrors) { throw $e; } $output->writeln(sprintf('<warning>%s: %s</warning>', get_class($e), $e->getMessage())); } catch (\UnexpectedValueException $e) { if (!$skipErrors) { throw $e; } $output->writeln(sprintf('<warning>%s: %s</warning>', get_class($e), $e->getMessage())); } if ($repositoryUrl !== null && count($packagesFilter) > 0) { throw new \InvalidArgumentException('The arguments "package" and "repository-url" can not be used together.'); } // disable packagist by default unset(Config::$defaultRepositories['packagist']); if (!($outputDir = $input->getArgument('output-dir'))) { $outputDir = isset($config['output-dir']) ? $config['output-dir'] : null; } if (null === $outputDir) { throw new \InvalidArgumentException('The output dir must be specified as second argument or be configured inside ' . $input->getArgument('file')); } /** @var $application Application */ $application = $this->getApplication(); $composer = $application->getComposer(true, $config); $packageSelection = new PackageSelection($output, $outputDir, $config, $skipErrors); if ($repositoryUrl !== null) { $packageSelection->setRepositoryFilter($repositoryUrl); } else { $packageSelection->setPackagesFilter($packagesFilter); } $packages = $packageSelection->select($composer, $verbose); if (isset($config['archive']['directory'])) { $downloads = new ArchiveBuilder($output, $outputDir, $config, $skipErrors); $downloads->setComposer($composer); $downloads->setInput($input); $downloads->dump($packages); } if ($packageSelection->hasFilterForPackages() || $packageSelection->hasRepositoryFilter()) { // in case of an active filter we need to load the dumped packages.json and merge the // updated packages in $oldPackages = $packageSelection->load(); $packages += $oldPackages; ksort($packages); } $packagesBuilder = new PackagesBuilder($output, $outputDir, $config, $skipErrors); $packagesBuilder->dump($packages); if ($htmlView = !$input->getOption('no-html-output')) { $htmlView = !isset($config['output-html']) || $config['output-html']; } if ($htmlView) { $web = new WebBuilder($output, $outputDir, $config, $skipErrors); $web->setRootPackage($composer->getPackage()); $web->dump($packages); } return 0; }
/** * @param InputInterface $input The input instance * @param OutputInterface $output The output instance */ protected function execute(InputInterface $input, OutputInterface $output) { $verbose = $input->getOption('verbose'); $configFile = $input->getArgument('file'); $packagesFilter = $input->getArgument('packages'); $skipErrors = (bool) $input->getOption('skip-errors'); // load auth.json authentication information and pass it to the io interface $io = $this->getIO(); $io->loadConfiguration($this->getConfiguration()); if (preg_match('{^https?://}i', $configFile)) { $rfs = new RemoteFilesystem($io); $contents = $rfs->getContents(parse_url($configFile, PHP_URL_HOST), $configFile, false); $config = JsonFile::parseJson($contents, $configFile); } else { $file = new JsonFile($configFile); if (!$file->exists()) { $output->writeln('<error>File not found: ' . $configFile . '</error>'); return 1; } $config = $file->read(); } // disable packagist by default unset(Config::$defaultRepositories['packagist']); // fetch options $requireAll = isset($config['require-all']) && true === $config['require-all']; $requireDependencies = isset($config['require-dependencies']) && true === $config['require-dependencies']; $requireDevDependencies = isset($config['require-dev-dependencies']) && true === $config['require-dev-dependencies']; if (!$requireAll && !isset($config['require'])) { $output->writeln('No explicit requires defined, enabling require-all'); $requireAll = true; } $minimumStability = isset($config['minimum-stability']) ? $config['minimum-stability'] : 'dev'; if (!($outputDir = $input->getArgument('output-dir'))) { $outputDir = isset($config['output-dir']) ? $config['output-dir'] : null; } if (null === $outputDir) { throw new \InvalidArgumentException('The output dir must be specified as second argument or be configured inside ' . $input->getArgument('file')); } $composer = $this->getApplication()->getComposer(true, $config); $packages = $this->selectPackages($composer, $output, $verbose, $requireAll, $requireDependencies, $requireDevDependencies, $minimumStability, $skipErrors, $packagesFilter); if ($htmlView = !$input->getOption('no-html-output')) { $htmlView = !isset($config['output-html']) || $config['output-html']; } if (isset($config['archive']['directory'])) { $this->dumpDownloads($config, $packages, $input, $output, $outputDir, $skipErrors); } $filenamePrefix = $outputDir . '/include/all'; $filename = $outputDir . '/packages.json'; if (!empty($packagesFilter)) { // in case of an active package filter we need to load the dumped packages.json and merge the // updated packages in $oldPackages = $this->loadDumpedPackages($filename, $packagesFilter); $packages += $oldPackages; ksort($packages); } $packageFile = $this->dumpPackageIncludeJson($packages, $output, $filenamePrefix); $packageFileHash = hash_file('sha1', $packageFile); $includes = array('include/all$' . $packageFileHash . '.json' => array('sha1' => $packageFileHash)); $this->dumpPackagesJson($includes, $output, $filename); if ($htmlView) { $dependencies = array(); foreach ($packages as $package) { foreach ($package->getRequires() as $link) { $dependencies[$link->getTarget()][$link->getSource()] = $link->getSource(); } } $rootPackage = $composer->getPackage(); $twigTemplate = isset($config['twig-template']) ? $config['twig-template'] : null; $this->dumpWeb($packages, $output, $rootPackage, $outputDir, $twigTemplate, $dependencies); } }
/** * Tests that a BitBucket public download is correctly retrieved when `bitbucket-oauth` is configured. * * @param string $url * @param string $contents * @dataProvider provideBitbucketPublicDownloadUrls */ public function testBitBucketPublicDownloadWithAuthConfigured($url, $contents) { $io = $this ->getMockBuilder('Composer\IO\ConsoleIO') ->disableOriginalConstructor() ->getMock(); $config = $this ->getMockBuilder('Composer\Config') ->getMock(); $config ->method('get') ->withAnyParameters() ->willReturn(array()); $io ->method('hasAuthentication') ->with('bitbucket.org') ->willReturn(true); $io ->method('getAuthentication') ->with('bitbucket.org') ->willReturn(array( 'username' => 'x-token-auth', // This token is fake, but it matches a valid token's pattern. 'password' => '1A0yeK5Po3ZEeiiRiMWLivS0jirLdoGuaSGq9NvESFx1Fsdn493wUDXC8rz_1iKVRTl1GINHEUCsDxGh5lZ=' )); $rfs = new RemoteFilesystem($io, $config); $hostname = parse_url($url, PHP_URL_HOST); $result = $rfs->getContents($hostname, $url, false); $this->assertEquals($contents, $result); }
protected function execute(InputInterface $input, OutputInterface $output) { $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0]; $tempFilename = dirname($localFilename) . '/' . basename($localFilename, '.phar') . '-temp.phar'; // check for permissions in local filesystem before start connection process if (!is_writable($tempDirectory = dirname($tempFilename))) { throw new FilesystemException('imi-conrun update failed: the "' . $tempDirectory . '" directory used to download the temp file could not be written'); } if (!is_writable($localFilename)) { throw new FilesystemException('imi-conrun update failed: the "' . $localFilename . '" file could not be written'); } $io = new ConsoleIO($input, $output, $this->getHelperSet()); $rfs = new RemoteFilesystem($io); $loadUnstable = $input->getOption('unstable'); if ($loadUnstable) { $versionTxtUrl = 'https://raw.githubusercontent.com/iMi-digital/imi-conrun/develop/version.txt'; $remoteFilename = 'https://raw.githubusercontent.com/iMi-digital/imi-conrun/develop/imi-conrun.phar'; } else { $versionTxtUrl = 'https://raw.githubusercontent.com/iMi-digital/imi-conrun/master/version.txt'; $remoteFilename = 'https://raw.githubusercontent.com/iMi-digital/imi-conrun/master/imi-conrun.phar'; } $latest = trim($rfs->getContents('raw.githubusercontent.com', $versionTxtUrl, false)); if ($this->getApplication()->getVersion() !== $latest || $loadUnstable) { $output->writeln(sprintf("Updating to version <info>%s</info>.", $latest)); $rfs->copy('raw.github.com', $remoteFilename, $tempFilename); if (!file_exists($tempFilename)) { $output->writeln('<error>The download of the new imi-conrun version failed for an unexpected reason'); return 1; } try { \error_reporting(E_ALL); // supress notices @chmod($tempFilename, 0777 & ~umask()); // test the phar validity $phar = new \Phar($tempFilename); // free the variable to unlock the file unset($phar); @rename($tempFilename, $localFilename); $output->writeln('<info>Successfully updated imi-conrun</info>'); if ($loadUnstable) { $changeLogContent = $rfs->getContents('raw.github.com', 'https://raw.github.com/netz98/imi-conrun/develop/changes.txt', false); } else { $changeLogContent = $rfs->getContents('raw.github.com', 'https://raw.github.com/netz98/imi-conrun/master/changes.txt', false); } if ($changeLogContent) { $output->writeln($changeLogContent); } if ($loadUnstable) { $unstableFooterMessage = <<<UNSTABLE_FOOTER <comment> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! DEVELOPMENT VERSION. DO NOT USE IN PRODUCTION !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! </comment> UNSTABLE_FOOTER; $output->writeln($unstableFooterMessage); } $this->_exit(); } catch (\Exception $e) { @unlink($tempFilename); if (!$e instanceof \UnexpectedValueException && !$e instanceof \PharException) { throw $e; } $output->writeln('<error>The download is corrupted (' . $e->getMessage() . ').</error>'); $output->writeln('<error>Please re-run the self-update command to try again.</error>'); } } else { $output->writeln("<info>You are using the latest imi-conrun version.</info>"); } }
private function updateGitHubInfo(RemoteFilesystem $rfs, Package $package, $owner, $repo) { $baseApiUrl = 'https://api.github.com/repos/' . $owner . '/' . $repo; try { $repoData = JsonFile::parseJson($rfs->getContents('github.com', $baseApiUrl, false), $baseApiUrl); } catch (\Exception $e) { return; } try { $opts = ['http' => ['header' => ['Accept: application/vnd.github.v3.html']]]; $readme = $rfs->getContents('github.com', $baseApiUrl . '/readme', false, $opts); } catch (\Exception $e) { if (!$e instanceof \Composer\Downloader\TransportException || $e->getCode() !== 404) { return; } // 404s just mean no readme present so we proceed with the rest } if (!empty($readme)) { $config = \HTMLPurifier_Config::createDefault(); $config->set('HTML.Allowed', 'a[href|target|rel|id],strong,b,em,i,strike,pre,code,p,ol,ul,li,br,h1,h2,h3,img[src|title|alt|width|height|style]'); $config->set('Attr.EnableID', true); $config->set('Attr.AllowedFrameTargets', ['_blank']); $purifier = new \HTMLPurifier($config); $readme = $purifier->purify($readme); $dom = new \DOMDocument(); $dom->loadHTML('<?xml encoding="UTF-8">' . $readme); // Links can not be trusted $links = $dom->getElementsByTagName('a'); foreach ($links as $link) { $link->setAttribute('rel', 'nofollow'); if ('#' === substr($link->getAttribute('href'), 0, 1)) { $link->setAttribute('href', '#user-content-' . substr($link->getAttribute('href'), 1)); } elseif (false === strpos($link->getAttribute('href'), '//')) { $link->setAttribute('href', 'https://github.com/' . $owner . '/' . $repo . '/blob/HEAD/' . $link->getAttribute('href')); } } // remove first title as it's usually the project name which we don't need if ($dom->getElementsByTagName('h1')->length) { $first = $dom->getElementsByTagName('h1')->item(0); $first->parentNode->removeChild($first); } elseif ($dom->getElementsByTagName('h2')->length) { $first = $dom->getElementsByTagName('h2')->item(0); $first->parentNode->removeChild($first); } $readme = $dom->saveHTML(); $readme = substr($readme, strpos($readme, '<body>') + 6); $readme = substr($readme, 0, strrpos($readme, '</body>')); $package->setReadme($readme); } if (!empty($repoData['language'])) { $package->setLanguage($repoData['language']); } if (!empty($repoData['stargazers_count'])) { $package->setGitHubStars($repoData['stargazers_count']); } if (!empty($repoData['subscribers_count'])) { $package->setGitHubWatches($repoData['subscribers_count']); } if (!empty($repoData['network_count'])) { $package->setGitHubForks($repoData['network_count']); } if (!empty($repoData['open_issues_count'])) { $package->setGitHubOpenIssues($repoData['open_issues_count']); } }
/** * Decorate the package with stats from packagist. * * @param VersionedPackage $package The package version. * * @return VersionedPackage */ protected function decorateWithPackagistStats(VersionedPackage $package) { if (null === $this->decorateBaseUrl) { return $package; } $rfs = new RemoteFilesystem(new BufferIO()); $requestUrl = sprintf($this->decorateBaseUrl, $package->getName()); if (!($jsonData = $rfs->getContents($requestUrl, $requestUrl))) { $this->decorateBaseUrl = null; return $package; } try { $data = new JsonArray($jsonData); } catch (\RuntimeException $exception) { $this->decorateBaseUrl = null; return $package; } $metaPaths = ['downloads' => 'package/downloads/total', 'favers' => 'package/favers']; foreach ($metaPaths as $metaKey => $metaPath) { $package->addMetaData($metaKey, $data->get($metaPath)); } return $package; }
/** * Get the remote content. * * @param string $url The URL of content * * @return mixed The result */ protected function getContents($url) { $rfs = new RemoteFilesystem($this->io); return $rfs->getContents($this->url, $url, false); }