commit
366e98288e
|
@ -29,4 +29,12 @@ abstract class Command extends BaseCommand
|
|||
{
|
||||
return $this->getApplication()->getComposer($required);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Composer\IO\ConsoleIO
|
||||
*/
|
||||
protected function getIO()
|
||||
{
|
||||
return $this->getApplication()->getIO();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ use Symfony\Component\Console\Input\InputInterface;
|
|||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
|
||||
/**
|
||||
* Install a package as new project into new directory.
|
||||
|
@ -86,7 +87,7 @@ EOT
|
|||
if (null === $repositoryUrl) {
|
||||
$sourceRepo = new ComposerRepository(array('url' => 'http://packagist.org'));
|
||||
} elseif (".json" === substr($repositoryUrl, -5)) {
|
||||
$sourceRepo = new FilesystemRepository(new JsonFile($repositoryUrl));
|
||||
$sourceRepo = new FilesystemRepository(new JsonFile($repositoryUrl, new RemoteFilesystem($io)));
|
||||
} elseif (0 === strpos($repositoryUrl, 'http')) {
|
||||
$sourceRepo = new ComposerRepository(array('url' => $repositoryUrl));
|
||||
} else {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
namespace Composer\Command;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\Util\StreamContextFactory;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
|
@ -40,9 +40,8 @@ EOT
|
|||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$ctx = StreamContextFactory::getContext();
|
||||
|
||||
$latest = trim(file_get_contents('http://getcomposer.org/version', false, $ctx));
|
||||
$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));
|
||||
|
@ -50,7 +49,7 @@ EOT
|
|||
$remoteFilename = 'http://getcomposer.org/composer.phar';
|
||||
$localFilename = $_SERVER['argv'][0];
|
||||
|
||||
copy($remoteFilename, $localFilename, $ctx);
|
||||
$rfs->copy('getcomposer.org', $remoteFilename, $localFilename);
|
||||
} else {
|
||||
$output->writeln("<info>You are using the latest composer version.</info>");
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ use Symfony\Component\Console\Input\InputArgument;
|
|||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\Json\JsonValidationException;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
|
||||
/**
|
||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||
|
@ -55,7 +56,7 @@ EOT
|
|||
|
||||
$laxValid = false;
|
||||
try {
|
||||
$json = new JsonFile($file);
|
||||
$json = new JsonFile($file, new RemoteFilesystem($this->getIO()));
|
||||
$json->read();
|
||||
|
||||
$json->validateSchema(JsonFile::LAX_SCHEMA);
|
||||
|
|
|
@ -74,7 +74,6 @@ class FileDownloader implements DownloaderInterface
|
|||
$url = $this->processUrl($url);
|
||||
|
||||
$this->rfs->copy($package->getSourceUrl(), $url, $fileName);
|
||||
$this->io->write('');
|
||||
|
||||
if (!file_exists($fileName)) {
|
||||
throw new \UnexpectedValueException($url.' could not be saved to '.$fileName.', make sure the'
|
||||
|
|
|
@ -16,6 +16,7 @@ use Composer\Json\JsonFile;
|
|||
use Composer\IO\IOInterface;
|
||||
use Composer\Repository\RepositoryManager;
|
||||
use Composer\Util\ProcessExecutor;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
|
||||
/**
|
||||
* Creates an configured instance of composer.
|
||||
|
@ -38,7 +39,7 @@ class Factory
|
|||
$composerFile = getenv('COMPOSER') ?: 'composer.json';
|
||||
}
|
||||
|
||||
$file = new JsonFile($composerFile);
|
||||
$file = new JsonFile($composerFile, new RemoteFilesystem($io));
|
||||
if (!$file->exists()) {
|
||||
if ($composerFile === 'composer.json') {
|
||||
$message = 'Composer could not find a composer.json file in '.getcwd();
|
||||
|
@ -98,7 +99,7 @@ class Factory
|
|||
|
||||
// init locker
|
||||
$lockFile = substr($composerFile, -5) === '.json' ? substr($composerFile, 0, -4).'lock' : $composerFile . '.lock';
|
||||
$locker = new Package\Locker(new JsonFile($lockFile), $rm, md5_file($composerFile));
|
||||
$locker = new Package\Locker(new JsonFile($lockFile, new RemoteFilesystem($io)), $rm, md5_file($composerFile));
|
||||
|
||||
// initialize composer
|
||||
$composer = new Composer();
|
||||
|
|
|
@ -17,6 +17,7 @@ use Composer\Composer;
|
|||
use JsonSchema\Validator;
|
||||
use Seld\JsonLint\JsonParser;
|
||||
use Composer\Util\StreamContextFactory;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
|
||||
/**
|
||||
* Reads/writes json files.
|
||||
|
@ -34,15 +35,22 @@ class JsonFile
|
|||
const JSON_UNESCAPED_UNICODE = 256;
|
||||
|
||||
private $path;
|
||||
private $rfs;
|
||||
|
||||
/**
|
||||
* Initializes json file reader/parser.
|
||||
*
|
||||
* @param string $lockFile path to a lockfile
|
||||
* @param RemoteFilesystem $rfs required for loading http/https json files
|
||||
*/
|
||||
public function __construct($path)
|
||||
public function __construct($path, RemoteFilesystem $rfs = null)
|
||||
{
|
||||
$this->path = $path;
|
||||
|
||||
if (null === $rfs && preg_match('{^https?://}i', $path)) {
|
||||
throw new \InvalidArgumentException('http urls require a RemoteFilesystem instance to be passed');
|
||||
}
|
||||
$this->rfs = $rfs;
|
||||
}
|
||||
|
||||
public function getPath()
|
||||
|
@ -67,15 +75,14 @@ class JsonFile
|
|||
*/
|
||||
public function read()
|
||||
{
|
||||
$ctx = StreamContextFactory::getContext(array(
|
||||
'http' => array(
|
||||
'header' => 'User-Agent: Composer/'.Composer::VERSION."\r\n"
|
||||
)
|
||||
));
|
||||
|
||||
$json = file_get_contents($this->path, false, $ctx);
|
||||
if (!$json) {
|
||||
throw new \RuntimeException('Could not read '.$this->path.', you are probably offline');
|
||||
try {
|
||||
if ($this->rfs) {
|
||||
$json = $this->rfs->getContents($this->path, $this->path, false);
|
||||
} else {
|
||||
$json = file_get_contents($this->path);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new \RuntimeException('Could not read '.$this->path.', you are probably offline ('.$e->getMessage().')');
|
||||
}
|
||||
|
||||
return static::parseJson($json);
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace Composer\Repository;
|
|||
use Composer\Package\Loader\ArrayLoader;
|
||||
use Composer\Package\LinkConstraint\VersionConstraint;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
|
||||
/**
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
|
@ -22,9 +24,10 @@ use Composer\Json\JsonFile;
|
|||
class ComposerRepository extends ArrayRepository
|
||||
{
|
||||
protected $url;
|
||||
protected $io;
|
||||
protected $packages;
|
||||
|
||||
public function __construct(array $config)
|
||||
public function __construct(array $config, IOInterface $io)
|
||||
{
|
||||
if (!preg_match('{^\w+://}', $config['url'])) {
|
||||
// assume http as the default protocol
|
||||
|
@ -36,12 +39,13 @@ class ComposerRepository extends ArrayRepository
|
|||
}
|
||||
|
||||
$this->url = $config['url'];
|
||||
$this->io = $io;
|
||||
}
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
$json = new JsonFile($this->url.'/packages.json');
|
||||
$json = new JsonFile($this->url.'/packages.json', new RemoteFilesystem($this->io));
|
||||
$packages = $json->read();
|
||||
if (!$packages) {
|
||||
throw new \UnexpectedValueException('Could not parse package list from the '.$this->url.' repository');
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
|
||||
namespace Composer\Repository;
|
||||
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Package\Loader\ArrayLoader;
|
||||
use Composer\Util\StreamContextFactory;
|
||||
use Composer\Util\RemoteFilesystem;
|
||||
use Composer\Downloader\TransportException;
|
||||
|
||||
/**
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
|
@ -23,9 +25,10 @@ class PearRepository extends ArrayRepository
|
|||
{
|
||||
private $url;
|
||||
private $channel;
|
||||
private $streamContext;
|
||||
private $io;
|
||||
private $rfs;
|
||||
|
||||
public function __construct(array $config)
|
||||
public function __construct(array $config, IOInterface $io, RemoteFilesystem $rfs = null)
|
||||
{
|
||||
if (!preg_match('{^https?://}', $config['url'])) {
|
||||
$config['url'] = 'http://'.$config['url'];
|
||||
|
@ -36,20 +39,17 @@ class PearRepository extends ArrayRepository
|
|||
}
|
||||
|
||||
$this->url = rtrim($config['url'], '/');
|
||||
|
||||
$this->channel = !empty($config['channel']) ? $config['channel'] : null;
|
||||
$this->io = $io;
|
||||
$this->rfs = $rfs ?: new RemoteFilesystem($this->io);
|
||||
}
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
set_error_handler(function($severity, $message, $file, $line) {
|
||||
throw new \ErrorException($message, $severity, $severity, $file, $line);
|
||||
});
|
||||
$this->streamContext = StreamContextFactory::getContext();
|
||||
$this->io->write('Initializing PEAR repository '.$this->url);
|
||||
$this->fetchFromServer();
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
protected function fetchFromServer()
|
||||
|
@ -68,7 +68,7 @@ class PearRepository extends ArrayRepository
|
|||
try {
|
||||
$packagesLink = str_replace("info.xml", "packagesinfo.xml", $link);
|
||||
$this->fetchPear2Packages($this->url . $packagesLink);
|
||||
} catch (\ErrorException $e) {
|
||||
} catch (TransportException $e) {
|
||||
if (false === strpos($e->getMessage(), '404')) {
|
||||
throw $e;
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ class PearRepository extends ArrayRepository
|
|||
|
||||
/**
|
||||
* @param string $categoryLink
|
||||
* @throws ErrorException
|
||||
* @throws TransportException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function fetchPearPackages($categoryLink)
|
||||
|
@ -99,7 +99,7 @@ class PearRepository extends ArrayRepository
|
|||
|
||||
try {
|
||||
$releasesXML = $this->requestXml($allReleasesLink);
|
||||
} catch (\ErrorException $e) {
|
||||
} catch (TransportException $e) {
|
||||
if (strpos($e->getMessage(), '404')) {
|
||||
continue;
|
||||
}
|
||||
|
@ -120,8 +120,8 @@ class PearRepository extends ArrayRepository
|
|||
);
|
||||
|
||||
try {
|
||||
$deps = file_get_contents($releaseLink . "/deps.".$pearVersion.".txt", false, $this->streamContext);
|
||||
} catch (\ErrorException $e) {
|
||||
$deps = $this->rfs->getContents($this->url, $releaseLink . "/deps.".$pearVersion.".txt", false);
|
||||
} catch (TransportException $e) {
|
||||
if (strpos($e->getMessage(), '404')) {
|
||||
continue;
|
||||
}
|
||||
|
@ -226,6 +226,7 @@ class PearRepository extends ArrayRepository
|
|||
{
|
||||
$loader = new ArrayLoader();
|
||||
$packagesXml = $this->requestXml($packagesLink);
|
||||
|
||||
$informations = $packagesXml->getElementsByTagName('pi');
|
||||
foreach ($informations as $information) {
|
||||
$package = $information->getElementsByTagName('p')->item(0);
|
||||
|
@ -289,7 +290,7 @@ class PearRepository extends ArrayRepository
|
|||
*/
|
||||
private function requestXml($url)
|
||||
{
|
||||
$content = file_get_contents($url, false, $this->streamContext);
|
||||
$content = $this->rfs->getContents($this->url, $url, false);
|
||||
if (!$content) {
|
||||
throw new \UnexpectedValueException('The PEAR channel at '.$url.' did not respond.');
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace Composer\Util;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Downloader\TransportException;
|
||||
|
||||
|
@ -101,26 +102,50 @@ class RemoteFilesystem
|
|||
}
|
||||
|
||||
$result = @file_get_contents($fileUrl, false, $ctx);
|
||||
if (null !== $fileName) {
|
||||
$result = @file_put_contents($fileName, $result) ? true : false;
|
||||
}
|
||||
|
||||
// fix for 5.4.0 https://bugs.php.net/bug.php?id=61336
|
||||
if (!empty($http_response_header[0]) && preg_match('{^HTTP/\S+ 404}i', $http_response_header[0])) {
|
||||
$result = false;
|
||||
}
|
||||
|
||||
// decode gzip
|
||||
if (false !== $result && extension_loaded('zlib') && substr($fileUrl, 0, 4) === 'http') {
|
||||
$decode = false;
|
||||
foreach ($http_response_header as $header) {
|
||||
if (preg_match('{^content-encoding: *gzip *$}i', $header)) {
|
||||
$decode = true;
|
||||
continue;
|
||||
} elseif (preg_match('{^HTTP/}i', $header)) {
|
||||
$decode = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($decode) {
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle copy command if download was successful
|
||||
if (false !== $result && null !== $fileName) {
|
||||
$result = (Boolean) @file_put_contents($fileName, $result);
|
||||
}
|
||||
|
||||
// avoid overriding if content was loaded by a sub-call to get()
|
||||
if (null === $this->result) {
|
||||
$this->result = $result;
|
||||
}
|
||||
|
||||
if ($this->progress) {
|
||||
$this->io->overwrite(" Downloading", false);
|
||||
$this->io->write('');
|
||||
}
|
||||
|
||||
if (false === $this->result) {
|
||||
throw new TransportException("The '$fileUrl' file could not be downloaded");
|
||||
throw new TransportException('The "'.$fileUrl.'" file could not be downloaded');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +163,7 @@ class RemoteFilesystem
|
|||
{
|
||||
switch ($notificationCode) {
|
||||
case STREAM_NOTIFY_FAILURE:
|
||||
throw new TransportException(trim($message), $messageCode);
|
||||
throw new TransportException('The "'.$this->fileUrl.'" file could not be downloaded ('.trim($message).')', $messageCode);
|
||||
break;
|
||||
|
||||
case STREAM_NOTIFY_AUTH_REQUIRED:
|
||||
|
@ -184,17 +209,21 @@ class RemoteFilesystem
|
|||
}
|
||||
}
|
||||
|
||||
protected function getOptionsForUrl($url)
|
||||
protected function getOptionsForUrl($originUrl)
|
||||
{
|
||||
$options = array();
|
||||
if ($this->io->hasAuthorization($url)) {
|
||||
$auth = $this->io->getAuthorization($url);
|
||||
$options['http']['header'] = 'User-Agent: Composer/'.Composer::VERSION."\r\n";
|
||||
if (extension_loaded('zlib')) {
|
||||
$options['http']['header'] .= 'Accept-Encoding: gzip'."\r\n";
|
||||
}
|
||||
|
||||
if ($this->io->hasAuthorization($originUrl)) {
|
||||
$auth = $this->io->getAuthorization($originUrl);
|
||||
$authStr = base64_encode($auth['username'] . ':' . $auth['password']);
|
||||
$options['http'] = array('header' => "Authorization: Basic $authStr\r\n");
|
||||
$options['http']['header'] .= "Authorization: Basic $authStr\r\n";
|
||||
} elseif (null !== $this->io->getLastUsername()) {
|
||||
$authStr = base64_encode($this->io->getLastUsername() . ':' . $this->io->getLastPassword());
|
||||
$options['http'] = array('header' => "Authorization: Basic $authStr\r\n");
|
||||
$this->io->setAuthorization($url, $this->io->getLastUsername(), $this->io->getLastPassword());
|
||||
$options['http']['header'] .= "Authorization: Basic $authStr\r\n";
|
||||
$this->io->setAuthorization($originUrl, $this->io->getLastUsername(), $this->io->getLastPassword());
|
||||
}
|
||||
|
||||
return $options;
|
||||
|
|
|
@ -31,7 +31,8 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase
|
|||
->will($this->returnValue(null))
|
||||
;
|
||||
|
||||
$this->assertEquals(array(), $this->callGetOptionsForUrl($io, array('http://example.org')));
|
||||
$res = $this->callGetOptionsForUrl($io, array('http://example.org'));
|
||||
$this->assertTrue(isset($res['http']['header']) && false !== strpos($res['http']['header'], 'User-Agent'), 'getOptions must return an array with a header containing a User-Agent');
|
||||
}
|
||||
|
||||
public function testGetOptionsForUrlWithAuthorization()
|
||||
|
|
Loading…
Reference in New Issue