From 2b08df51929c4c3135c0b2c80a5a8f4060cf9449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Haso=C5=88?= Date: Tue, 6 Mar 2012 10:11:45 +0100 Subject: [PATCH 01/36] Changed repository priority in the pool --- src/Composer/DependencyResolver/Pool.php | 2 +- .../DependencyResolver/DefaultPolicyTest.php | 4 +- .../Test/DependencyResolver/PoolTest.php | 39 ++++++++++++++++++- .../Test/DependencyResolver/RequestTest.php | 26 +++++++++++++ .../Test/DependencyResolver/SolverTest.php | 20 +++++++++- 5 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/Composer/DependencyResolver/Pool.php b/src/Composer/DependencyResolver/Pool.php index b5eeb26e7..24ef5427a 100644 --- a/src/Composer/DependencyResolver/Pool.php +++ b/src/Composer/DependencyResolver/Pool.php @@ -53,7 +53,7 @@ class Pool throw new \RuntimeException("Could not determine repository priority. The repository was not registered in the pool."); } - return $priority; + return -$priority; } /** diff --git a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php index 82f913d36..4bb7c9e33 100644 --- a/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php +++ b/tests/Composer/Test/DependencyResolver/DefaultPolicyTest.php @@ -80,7 +80,7 @@ class DefaultPolicyTest extends TestCase $this->assertEquals($expected, $selected); } - public function testSelectLastRepo() + public function testSelectFirstRepo() { $this->repoImportant = new ArrayRepository; @@ -88,8 +88,8 @@ class DefaultPolicyTest extends TestCase $this->repoImportant->addPackage($packageAImportant = $this->getPackage('A', '1.0')); $this->pool->addRepository($this->repoInstalled); - $this->pool->addRepository($this->repo); $this->pool->addRepository($this->repoImportant); + $this->pool->addRepository($this->repo); $literals = array(new Literal($packageA, true), new Literal($packageAImportant, true)); $expected = array(new Literal($packageAImportant, true)); diff --git a/tests/Composer/Test/DependencyResolver/PoolTest.php b/tests/Composer/Test/DependencyResolver/PoolTest.php index 643be0428..c98570534 100644 --- a/tests/Composer/Test/DependencyResolver/PoolTest.php +++ b/tests/Composer/Test/DependencyResolver/PoolTest.php @@ -54,7 +54,44 @@ class PoolTest extends TestCase $secondPriority = $pool->getPriority($secondRepository); $this->assertEquals(0, $firstPriority); - $this->assertEquals(1, $secondPriority); + $this->assertEquals(-1, $secondPriority); + } + + public function testWhatProvidesSamePackageForDifferentRepositories() + { + $pool = new Pool; + $firstRepository = new ArrayRepository; + $secondRepository = new ArrayRepository; + + $firstPackage = $this->getPackage('foo', '1'); + $secondPackage = $this->getPackage('foo', '1'); + $thirdPackage = $this->getPackage('foo', '2'); + + $firstRepository->addPackage($firstPackage); + $secondRepository->addPackage($secondPackage); + $secondRepository->addPackage($thirdPackage); + + $pool->addRepository($firstRepository); + $pool->addRepository($secondRepository); + + $this->assertEquals(array($firstPackage, $secondPackage, $thirdPackage), $pool->whatProvides('foo')); + } + + public function testWhatProvidesPackageWithConstraint() + { + $pool = new Pool; + $repository = new ArrayRepository; + + $firstPackage = $this->getPackage('foo', '1'); + $secondPackage = $this->getPackage('foo', '2'); + + $repository->addPackage($firstPackage); + $repository->addPackage($secondPackage); + + $pool->addRepository($repository); + + $this->assertEquals(array($firstPackage, $secondPackage), $pool->whatProvides('foo')); + $this->assertEquals(array($secondPackage), $pool->whatProvides('foo', $this->getVersionConstraint('==', '2'))); } public function testPackageById() diff --git a/tests/Composer/Test/DependencyResolver/RequestTest.php b/tests/Composer/Test/DependencyResolver/RequestTest.php index e5010e0e4..d11c3c427 100644 --- a/tests/Composer/Test/DependencyResolver/RequestTest.php +++ b/tests/Composer/Test/DependencyResolver/RequestTest.php @@ -47,6 +47,32 @@ class RequestTest extends TestCase $request->getJobs()); } + public function testRequestInstallSamePackageFromDifferentRepositories() + { + $pool = new Pool; + $repo1 = new ArrayRepository; + $repo2 = new ArrayRepository; + + $foo1 = $this->getPackage('foo', '1'); + $foo2 = $this->getPackage('foo', '1'); + + $repo1->addPackage($foo1); + $repo2->addPackage($foo2); + + $pool->addRepository($repo1); + $pool->addRepository($repo2); + + $request = new Request($pool); + $request->install('foo', $this->getVersionConstraint('=', '1')); + + $this->assertEquals( + array( + array('packages' => array($foo1, $foo2), 'cmd' => 'install', 'packageName' => 'foo'), + ), + $request->getJobs() + ); + } + public function testUpdateAll() { $pool = new Pool; diff --git a/tests/Composer/Test/DependencyResolver/SolverTest.php b/tests/Composer/Test/DependencyResolver/SolverTest.php index fe6782177..fc7dce7a1 100644 --- a/tests/Composer/Test/DependencyResolver/SolverTest.php +++ b/tests/Composer/Test/DependencyResolver/SolverTest.php @@ -9,7 +9,6 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Composer\Test\DependencyResolver; use Composer\Repository\ArrayRepository; @@ -70,6 +69,25 @@ class SolverTest extends TestCase } } + public function testSolverInstallSamePackageFromDifferentRepositories() + { + $repo1 = new ArrayRepository; + $repo2 = new ArrayRepository; + + $repo1->addPackage($foo1 = $this->getPackage('foo', '1')); + $repo2->addPackage($foo2 = $this->getPackage('foo', '1')); + + $this->pool->addRepository($this->repoInstalled); + $this->pool->addRepository($repo1); + $this->pool->addRepository($repo2); + + $this->request->install('foo'); + + $this->checkSolverResult(array( + array('job' => 'install', 'package' => $foo1), + )); + } + public function testSolverInstallWithDeps() { $this->repo->addPackage($packageA = $this->getPackage('A', '1.0')); From 9021c862375770e7e5b255137ff331af2e9ff261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Haso=C5=88?= Date: Tue, 6 Mar 2012 10:14:11 +0100 Subject: [PATCH 02/36] Added packagist repository as the last repository with the lowest priority --- src/Composer/Factory.php | 39 +++++++++++------ tests/Composer/Test/FactoryTest.php | 65 +++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 13 deletions(-) create mode 100644 tests/Composer/Test/FactoryTest.php diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index faab0add1..354b6bbdb 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -78,17 +78,7 @@ class Factory $rm = $this->createRepositoryManager($io); // load default repository unless it's explicitly disabled - $loadPackagist = true; - if (isset($packageConfig['repositories'])) { - foreach ($packageConfig['repositories'] as $repo) { - if (isset($repo['packagist']) && $repo['packagist'] === false) { - $loadPackagist = false; - } - } - } - if ($loadPackagist) { - $this->addPackagistRepository($rm); - } + $packageConfig = $this->addPackagistRepository($packageConfig); // load local repository $this->addLocalRepository($rm, $vendorDir); @@ -134,9 +124,32 @@ class Factory $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json'))); } - protected function addPackagistRepository(RepositoryManager $rm) + protected function addPackagistRepository(array $packageConfig) { - $rm->addRepository(new Repository\ComposerRepository(array('url' => 'http://packagist.org'))); + $loadPackagist = true; + $packagistConfig = array( + 'type' => 'composer', + 'url' => 'http://packagist.org' + ); + if (isset($packageConfig['repositories'])) { + foreach ($packageConfig['repositories'] as $key => $repo) { + if (isset($repo['packagist'])) { + if (true === $repo['packagist']) { + $packageConfig['repositories'][$key] = $packagistConfig; + } + + $loadPackagist = false; + } + } + } else { + $packageConfig['repositories'] = array(); + } + + if ($loadPackagist) { + $packageConfig['repositories'][] = $packagistConfig; + } + + return $packageConfig; } protected function createDownloadManager(IOInterface $io) diff --git a/tests/Composer/Test/FactoryTest.php b/tests/Composer/Test/FactoryTest.php new file mode 100644 index 000000000..2bb838fef --- /dev/null +++ b/tests/Composer/Test/FactoryTest.php @@ -0,0 +1,65 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Test; + +use Composer\Factory; + +class FactoryTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider dataAddPackagistRepository + */ + public function testAddPackagistRepository($expected, $config) + { + $factory = new Factory(); + + $ref = new \ReflectionMethod($factory, 'addPackagistRepository'); + $ref->setAccessible(true); + + $this->assertEquals($expected, $ref->invoke($factory, $config)); + } + + public function dataAddPackagistRepository() + { + $f = function() { + $repositories = func_get_args(); + return array('repositories' => $repositories); + }; + + $data = array(); + $data[] = array( + $f(array('type' => 'composer', 'url' => 'http://packagist.org')), + $f() + ); + + $data[] = array( + $f(array('packagist' => false)), + $f(array('packagist' => false)) + ); + + $data[] = array( + $f( + array('type' => 'vcs', 'url' => 'git://github.com/composer/composer.git'), + array('type' => 'composer', 'url' => 'http://packagist.org'), + array('type' => 'pear', 'url' => 'http://pear.composer.org') + ), + $f( + array('type' => 'vcs', 'url' => 'git://github.com/composer/composer.git'), + array('packagist' => true), + array('type' => 'pear', 'url' => 'http://pear.composer.org') + ) + ); + + return $data; + } +} From 6efbc7d531fb4075d49754810e837fbefe03fc8d Mon Sep 17 00:00:00 2001 From: Beau Simensen Date: Fri, 9 Mar 2012 23:49:21 -0800 Subject: [PATCH 03/36] Enhanced GitHub API/Private Repository support --- src/Composer/Repository/Vcs/GitHubDriver.php | 111 ++++++++- src/Composer/Repository/Vcs/VcsDriver.php | 9 +- src/Composer/Util/RemoteFilesystem.php | 22 +- .../Test/Repository/Vcs/GitHubDriverTest.php | 227 ++++++++++++++++++ .../Test/Util/RemoteFilesystemTest.php | 33 +-- 5 files changed, 347 insertions(+), 55 deletions(-) create mode 100644 tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 01371c1a2..db717e570 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -2,8 +2,10 @@ namespace Composer\Repository\Vcs; +use Composer\Downloader\TransportException; use Composer\Json\JsonFile; use Composer\IO\IOInterface; +use Composer\Util\ProcessExecutor; /** * @author Jordi Boggiano @@ -16,14 +18,30 @@ class GitHubDriver extends VcsDriver protected $branches; protected $rootIdentifier; protected $infoCache = array(); + protected $isPrivate = false; - public function __construct($url, IOInterface $io) + /** + * Git Driver + * + * @var GitDriver + */ + protected $gitDriver; + + /** + * Constructor + * + * @param string $url + * @param IOInterface $io + * @param ProcessExecutor $process + * @param callback $remoteFilesystemGenerator + */ + public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystemGenerator = null) { preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $url, $match); $this->owner = $match[1]; $this->repository = $match[2]; - parent::__construct($url, $io); + parent::__construct($url, $io, $process, $remoteFilesystemGenerator); } /** @@ -31,6 +49,7 @@ class GitHubDriver extends VcsDriver */ public function initialize() { + $this->fetchRootIdentifier(); } /** @@ -38,11 +57,9 @@ class GitHubDriver extends VcsDriver */ public function getRootIdentifier() { - if (null === $this->rootIdentifier) { - $repoData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository)); - $this->rootIdentifier = $repoData['master_branch'] ?: 'master'; + if ($this->gitDriver) { + return $this->gitDriver->getRootIdentifier(); } - return $this->rootIdentifier; } @@ -51,6 +68,9 @@ class GitHubDriver extends VcsDriver */ public function getUrl() { + if ($this->gitDriver) { + return $this->gitDriver->getUrl(); + } return $this->url; } @@ -59,9 +79,19 @@ class GitHubDriver extends VcsDriver */ public function getSource($identifier) { + if ($this->gitDriver) { + return $this->gitDriver->getSource($identifier); + } $label = array_search($identifier, $this->getTags()) ?: $identifier; + if ($this->isPrivate) { + // Private GitHub repositories should be accessed using the + // SSH version of the URL. + $url = $this->generateSshUrl(); + } else { + $url = $this->getUrl(); + } - return array('type' => 'git', 'url' => $this->getUrl(), 'reference' => $label); + return array('type' => 'git', 'url' => $url, 'reference' => $label); } /** @@ -69,6 +99,9 @@ class GitHubDriver extends VcsDriver */ public function getDist($identifier) { + if ($this->gitDriver) { + return $this->gitDriver->getDist($identifier); + } $label = array_search($identifier, $this->getTags()) ?: $identifier; $url = $this->getScheme() . '://github.com/'.$this->owner.'/'.$this->repository.'/zipball/'.$label; @@ -80,6 +113,9 @@ class GitHubDriver extends VcsDriver */ public function getComposerInformation($identifier) { + if ($this->gitDriver) { + return $this->gitDriver->getComposerInformation($identifier); + } if (!isset($this->infoCache[$identifier])) { $composer = $this->getContents($this->getScheme() . '://raw.github.com/'.$this->owner.'/'.$this->repository.'/'.$identifier.'/composer.json'); if (!$composer) { @@ -103,6 +139,9 @@ class GitHubDriver extends VcsDriver */ public function getTags() { + if ($this->gitDriver) { + return $this->gitDriver->getTags(); + } if (null === $this->tags) { $tagsData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/tags')); $this->tags = array(); @@ -119,6 +158,9 @@ class GitHubDriver extends VcsDriver */ public function getBranches() { + if ($this->gitDriver) { + return $this->gitDriver->getBranches(); + } if (null === $this->branches) { $branchData = JsonFile::parseJson($this->getContents($this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository.'/branches')); $this->branches = array(); @@ -137,4 +179,59 @@ class GitHubDriver extends VcsDriver { return extension_loaded('openssl') && preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $url); } + + /** + * Generate an SSH URL + * + * @return string + */ + protected function generateSshUrl() + { + return 'git@github.com:'.$this->owner.'/'.$this->repository.'.git'; + } + + /** + * Fetch root identifier from GitHub + * + * @throws TransportException + */ + protected function fetchRootIdentifier() + { + $repoDataUrl = $this->getScheme() . '://api.github.com/repos/'.$this->owner.'/'.$this->repository; + $attemptCounter = 0; + while (null === $this->rootIdentifier) { + if (5 == $attemptCounter++) { + throw new \RuntimeException("Either you have entered invalid credentials or this GitHub repository does not exists (404)"); + } + try { + $repoData = JsonFile::parseJson($this->getContents($repoDataUrl)); + $this->rootIdentifier = $repoData['master_branch'] ?: 'master'; + } catch (TransportException $e) { + switch($e->getCode()) { + case 401: + case 404: + $this->isPrivate = true; + if (!$this->io->isInteractive()) { + $this->gitDriver = new GitDriver( + $this->generateSshUrl(), + $this->io, + $this->process, + $this->remoteFilesystemGenerator + ); + $this->gitDriver->initialize(); + return; + } + $this->io->write('Authentication required ('.$this->url.'):'); + $username = $this->io->ask('Username: '); + $password = $this->io->askAndHideAnswer('Password: '); + $this->io->setAuthorization($this->url, $username, $password); + break; + + default: + throw $e; + break; + } + } + } + } } diff --git a/src/Composer/Repository/Vcs/VcsDriver.php b/src/Composer/Repository/Vcs/VcsDriver.php index a20e959fd..3bd847553 100644 --- a/src/Composer/Repository/Vcs/VcsDriver.php +++ b/src/Composer/Repository/Vcs/VcsDriver.php @@ -27,6 +27,7 @@ abstract class VcsDriver implements VcsDriverInterface protected $url; protected $io; protected $process; + protected $remoteFilesystemGenerator; /** * Constructor. @@ -34,12 +35,16 @@ abstract class VcsDriver implements VcsDriverInterface * @param string $url The URL * @param IOInterface $io The IO instance * @param ProcessExecutor $process Process instance, injectable for mocking + * @param callback $remoteFilesystemGenerator Generates Remote Filesystem, injectable for mocking */ - public function __construct($url, IOInterface $io, ProcessExecutor $process = null) + public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystemGenerator = null) { $this->url = $url; $this->io = $io; $this->process = $process ?: new ProcessExecutor; + $this->remoteFilesystemGenerator = $remoteFilesystemGenerator ?: function() use ($io) { + return new RemoteFilesystem($io); + }; } /** @@ -80,7 +85,7 @@ abstract class VcsDriver implements VcsDriverInterface */ protected function getContents($url) { - $rfs = new RemoteFilesystem($this->io); + $rfs = call_user_func($this->remoteFilesystemGenerator); return $rfs->getContents($this->url, $url, false); } diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 87d725037..4f91de7d9 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -80,13 +80,11 @@ class RemoteFilesystem * @param string $fileUrl The file URL * @param string $fileName the local filename * @param boolean $progress Display the progression - * @param boolean $firstCall Whether this is the first attempt at fetching this resource * * @throws TransportException When the file could not be downloaded */ - protected function get($originUrl, $fileUrl, $fileName = null, $progress = true, $firstCall = true) + protected function get($originUrl, $fileUrl, $fileName = null, $progress = true) { - $this->firstCall = $firstCall; $this->bytesMax = 0; $this->result = null; $this->originUrl = $originUrl; @@ -140,20 +138,12 @@ class RemoteFilesystem protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax) { switch ($notificationCode) { - case STREAM_NOTIFY_AUTH_REQUIRED: case STREAM_NOTIFY_FAILURE: - if (404 === $messageCode && !$this->firstCall) { - throw new TransportException("The '" . $this->fileUrl . "' URL not found", 404); - } + throw new TransportException(trim($message), $messageCode); + break; - // for private repository returning 404 error when the authorization is incorrect - $auth = $this->io->getAuthorization($this->originUrl); - $attemptAuthentication = $this->firstCall && 404 === $messageCode && null === $auth['username']; - - $this->firstCall = false; - - // get authorization informations - if (401 === $messageCode || $attemptAuthentication) { + case STREAM_NOTIFY_AUTH_REQUIRED: + if (401 === $messageCode) { if (!$this->io->isInteractive()) { $message = "The '" . $this->fileUrl . "' URL required authentication.\nYou must be using the interactive console"; @@ -165,7 +155,7 @@ class RemoteFilesystem $password = $this->io->askAndHideAnswer(' Password: '); $this->io->setAuthorization($this->originUrl, $username, $password); - $this->get($this->originUrl, $this->fileUrl, $this->fileName, $this->progress, false); + $this->get($this->originUrl, $this->fileUrl, $this->fileName, $this->progress); } break; diff --git a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php new file mode 100644 index 000000000..96506185c --- /dev/null +++ b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php @@ -0,0 +1,227 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Test\Repository\Vcs; + +use Composer\Downloader\TransportException; +use Composer\Repository\Vcs\GitHubDriver; + +/** + * @author Beau Simensen + */ +class GitHubDriverTest extends \PHPUnit_Framework_TestCase +{ + public function testPrivateRepository() + { + $repoUrl = 'http://github.com/composer/packagist'; + $repoApiUrl = 'https://api.github.com/repos/composer/packagist'; + $repoSshUrl = 'git@github.com:composer/packagist.git'; + $identifier = 'v0.0.0'; + $sha = 'SOMESHA'; + + $io = $this->getMock('Composer\IO\IOInterface'); + $io->expects($this->any()) + ->method('isInteractive') + ->will($this->returnValue(true)); + + $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem') + ->setConstructorArgs(array($io)) + ->getMock(); + + $remoteFilesystem->expects($this->at(0)) + ->method('getContents') + ->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false)) + ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404))); + + $io->expects($this->once()) + ->method('ask') + ->with($this->equalTo('Username: ')) + ->will($this->returnValue('someuser')); + + $io->expects($this->once()) + ->method('askAndHideAnswer') + ->with($this->equalTo('Password: ')) + ->will($this->returnValue('somepassword')); + + $io->expects($this->once()) + ->method('setAuthorization') + ->with($this->equalTo($repoUrl), 'someuser', 'somepassword'); + + $remoteFilesystem->expects($this->at(1)) + ->method('getContents') + ->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false)) + ->will($this->returnValue('{"master_branch": "test_master"}')); + + $gitHubDriver = new GitHubDriver($repoUrl, $io, null, function() use ($remoteFilesystem) { return $remoteFilesystem; }); + $gitHubDriver->initialize(); + $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha)); + + $this->assertEquals('test_master', $gitHubDriver->getRootIdentifier()); + + $dist = $gitHubDriver->getDist($identifier); + $this->assertEquals('zip', $dist['type']); + $this->assertEquals('https://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); + $this->assertEquals('v0.0.0', $dist['reference']); + + $source = $gitHubDriver->getSource($identifier); + $this->assertEquals('git', $source['type']); + $this->assertEquals($repoSshUrl, $source['url']); + $this->assertEquals('v0.0.0', $source['reference']); + + $dist = $gitHubDriver->getDist($sha); + $this->assertEquals('zip', $dist['type']); + $this->assertEquals('https://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); + $this->assertEquals('v0.0.0', $dist['reference']); + + $source = $gitHubDriver->getSource($sha); + $this->assertEquals('git', $source['type']); + $this->assertEquals($repoSshUrl, $source['url']); + $this->assertEquals('v0.0.0', $source['reference']); + } + + public function testPublicRepository() + { + $repoUrl = 'http://github.com/composer/packagist'; + $repoApiUrl = 'https://api.github.com/repos/composer/packagist'; + $identifier = 'v0.0.0'; + $sha = 'SOMESHA'; + + $io = $this->getMock('Composer\IO\IOInterface'); + $io->expects($this->any()) + ->method('isInteractive') + ->will($this->returnValue(true)); + + $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem') + ->setConstructorArgs(array($io)) + ->getMock(); + + $remoteFilesystem->expects($this->at(0)) + ->method('getContents') + ->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false)) + ->will($this->returnValue('{"master_branch": "test_master"}')); + + $gitHubDriver = new GitHubDriver($repoUrl, $io, null, function() use ($remoteFilesystem) { + return $remoteFilesystem; + }); + $gitHubDriver->initialize(); + $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha)); + + $this->assertEquals('test_master', $gitHubDriver->getRootIdentifier()); + + $dist = $gitHubDriver->getDist($identifier); + $this->assertEquals('zip', $dist['type']); + $this->assertEquals('https://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); + $this->assertEquals($identifier, $dist['reference']); + + $source = $gitHubDriver->getSource($identifier); + $this->assertEquals('git', $source['type']); + $this->assertEquals($repoUrl, $source['url']); + $this->assertEquals($identifier, $source['reference']); + + $dist = $gitHubDriver->getDist($sha); + $this->assertEquals('zip', $dist['type']); + $this->assertEquals('https://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); + $this->assertEquals($identifier, $dist['reference']); + + $source = $gitHubDriver->getSource($sha); + $this->assertEquals('git', $source['type']); + $this->assertEquals($repoUrl, $source['url']); + $this->assertEquals($identifier, $source['reference']); + } + + public function testPrivateRepositoryNoInteraction() + { + $repoUrl = 'http://github.com/composer/packagist'; + $repoApiUrl = 'https://api.github.com/repos/composer/packagist'; + $repoSshUrl = 'git@github.com:composer/packagist.git'; + $identifier = 'v0.0.0'; + $sha = 'SOMESHA'; + + $process = $this->getMockBuilder('Composer\Util\ProcessExecutor') + ->disableOriginalConstructor() + ->getMock(); + + $io = $this->getMock('Composer\IO\IOInterface'); + $io->expects($this->any()) + ->method('isInteractive') + ->will($this->returnValue(false)); + + $remoteFilesystem = $this->getMockBuilder('Composer\Util\RemoteFilesystem') + ->setConstructorArgs(array($io)) + ->getMock(); + + $remoteFilesystem->expects($this->at(0)) + ->method('getContents') + ->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false)) + ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404))); + + $process->expects($this->at(0)) + ->method('execute') + ->with($this->stringContains('git fetch origin')); + + $process->expects($this->at(1)) + ->method('execute') + ->with($this->stringContains('git tag')); + + $process->expects($this->at(2)) + ->method('splitLines') + ->will($this->returnValue(array($identifier))); + + $process->expects($this->at(3)) + ->method('execute') + ->with($this->stringContains('git branch')); + + $process->expects($this->at(4)) + ->method('splitLines') + ->will($this->returnValue(array(' test_master edf93f1fccaebd8764383dc12016d0a1a9672d89 Fix test & behavior'))); + + $process->expects($this->at(5)) + ->method('execute') + ->with($this->stringContains('git branch')); + + $process->expects($this->at(6)) + ->method('splitLines') + ->will($this->returnValue(array(' upstream/HEAD -> upstream/test_master'))); + + $gitHubDriver = new GitHubDriver($repoUrl, $io, $process, function() use ($remoteFilesystem) { + return $remoteFilesystem; + }); + $gitHubDriver->initialize(); + + $this->assertEquals('test_master', $gitHubDriver->getRootIdentifier()); + + // Dist is not available for GitDriver + $dist = $gitHubDriver->getDist($identifier); + $this->assertNull($dist); + + $source = $gitHubDriver->getSource($identifier); + $this->assertEquals('git', $source['type']); + $this->assertEquals($repoSshUrl, $source['url']); + $this->assertEquals($identifier, $source['reference']); + + // Dist is not available for GitDriver + $dist = $gitHubDriver->getDist($sha); + $this->assertNull($dist); + + $source = $gitHubDriver->getSource($sha); + $this->assertEquals('git', $source['type']); + $this->assertEquals($repoSshUrl, $source['url']); + $this->assertEquals($sha, $source['reference']); + } + + protected function setAttribute($object, $attribute, $value) + { + $attr = new \ReflectionProperty($object, $attribute); + $attr->setAccessible(true); + $attr->setValue($object, $value); + } +} diff --git a/tests/Composer/Test/Util/RemoteFilesystemTest.php b/tests/Composer/Test/Util/RemoteFilesystemTest.php index bee389941..97e50b848 100644 --- a/tests/Composer/Test/Util/RemoteFilesystemTest.php +++ b/tests/Composer/Test/Util/RemoteFilesystemTest.php @@ -105,41 +105,14 @@ class RemoteFilesystemTest extends \PHPUnit_Framework_TestCase public function testCallbackGetNotifyFailure404() { $fs = new RemoteFilesystem($this->getMock('Composer\IO\IOInterface')); - $this->setAttribute($fs, 'firstCall', false); try { - $this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, '', 404, 0, 0); + $this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, 'HTTP/1.1 404 Not Found', 404, 0, 0); $this->fail(); } catch (\Exception $e) { $this->assertInstanceOf('Composer\Downloader\TransportException', $e); - $this->assertContains('URL not found', $e->getMessage()); - } - } - - public function testCallbackGetNotifyFailure404FirstCall() - { - $io = $this->getMock('Composer\IO\IOInterface'); - $io - ->expects($this->once()) - ->method('getAuthorization') - ->will($this->returnValue(array('username' => null))) - ; - $io - ->expects($this->once()) - ->method('isInteractive') - ->will($this->returnValue(false)) - ; - - $fs = new RemoteFilesystem($io); - $this->setAttribute($fs, 'firstCall', true); - - try { - $this->callCallbackGet($fs, STREAM_NOTIFY_FAILURE, 0, '', 404, 0, 0); - $this->fail(); - } catch (\Exception $e) { - $this->assertInstanceOf('Composer\Downloader\TransportException', $e); - $this->assertContains('URL required authentication', $e->getMessage()); - $this->assertAttributeEquals(false, 'firstCall', $fs); + $this->assertEquals(404, $e->getCode()); + $this->assertContains('HTTP/1.1 404 Not Found', $e->getMessage()); } } From 340ac49d870c17b8c9782d721b1dd45383a10859 Mon Sep 17 00:00:00 2001 From: Beau Simensen Date: Sat, 10 Mar 2012 09:54:42 -0800 Subject: [PATCH 04/36] Change `callback` to `callable` --- src/Composer/Repository/Vcs/GitHubDriver.php | 2 +- src/Composer/Repository/Vcs/VcsDriver.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index db717e570..dd7bc1c99 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -33,7 +33,7 @@ class GitHubDriver extends VcsDriver * @param string $url * @param IOInterface $io * @param ProcessExecutor $process - * @param callback $remoteFilesystemGenerator + * @param callable $remoteFilesystemGenerator */ public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystemGenerator = null) { diff --git a/src/Composer/Repository/Vcs/VcsDriver.php b/src/Composer/Repository/Vcs/VcsDriver.php index 3bd847553..2ecfaebc2 100644 --- a/src/Composer/Repository/Vcs/VcsDriver.php +++ b/src/Composer/Repository/Vcs/VcsDriver.php @@ -35,7 +35,7 @@ abstract class VcsDriver implements VcsDriverInterface * @param string $url The URL * @param IOInterface $io The IO instance * @param ProcessExecutor $process Process instance, injectable for mocking - * @param callback $remoteFilesystemGenerator Generates Remote Filesystem, injectable for mocking + * @param callable $remoteFilesystemGenerator Generates Remote Filesystem, injectable for mocking */ public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystemGenerator = null) { From 1e9cb6bac898ebffea5fed61a322a415009c91a0 Mon Sep 17 00:00:00 2001 From: Beau Simensen Date: Sat, 10 Mar 2012 10:26:03 -0800 Subject: [PATCH 05/36] Use factory name instead of generator. --- src/Composer/Repository/Vcs/GitHubDriver.php | 8 ++++---- src/Composer/Repository/Vcs/VcsDriver.php | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index dd7bc1c99..6566d2b22 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -33,15 +33,15 @@ class GitHubDriver extends VcsDriver * @param string $url * @param IOInterface $io * @param ProcessExecutor $process - * @param callable $remoteFilesystemGenerator + * @param callable $remoteFilesystemFactory */ - public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystemGenerator = null) + public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystemFactory = null) { preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $url, $match); $this->owner = $match[1]; $this->repository = $match[2]; - parent::__construct($url, $io, $process, $remoteFilesystemGenerator); + parent::__construct($url, $io, $process, $remoteFilesystemFactory); } /** @@ -216,7 +216,7 @@ class GitHubDriver extends VcsDriver $this->generateSshUrl(), $this->io, $this->process, - $this->remoteFilesystemGenerator + $this->remoteFilesystemFactory ); $this->gitDriver->initialize(); return; diff --git a/src/Composer/Repository/Vcs/VcsDriver.php b/src/Composer/Repository/Vcs/VcsDriver.php index 2ecfaebc2..c2f65a7d8 100644 --- a/src/Composer/Repository/Vcs/VcsDriver.php +++ b/src/Composer/Repository/Vcs/VcsDriver.php @@ -27,7 +27,7 @@ abstract class VcsDriver implements VcsDriverInterface protected $url; protected $io; protected $process; - protected $remoteFilesystemGenerator; + protected $remoteFilesystemFactory; /** * Constructor. @@ -35,14 +35,14 @@ abstract class VcsDriver implements VcsDriverInterface * @param string $url The URL * @param IOInterface $io The IO instance * @param ProcessExecutor $process Process instance, injectable for mocking - * @param callable $remoteFilesystemGenerator Generates Remote Filesystem, injectable for mocking + * @param callable $remoteFilesystemFactory Remote Filesystem factory, injectable for mocking */ - public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystemGenerator = null) + public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystemFactory = null) { $this->url = $url; $this->io = $io; $this->process = $process ?: new ProcessExecutor; - $this->remoteFilesystemGenerator = $remoteFilesystemGenerator ?: function() use ($io) { + $this->remoteFilesystemFactory = $remoteFilesystemFactory ?: function() use ($io) { return new RemoteFilesystem($io); }; } @@ -85,7 +85,7 @@ abstract class VcsDriver implements VcsDriverInterface */ protected function getContents($url) { - $rfs = call_user_func($this->remoteFilesystemGenerator); + $rfs = call_user_func($this->remoteFilesystemFactory); return $rfs->getContents($this->url, $url, false); } From e763af7412c2b437d70e5d49b4fbeb7217c910da Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 11 Mar 2012 21:01:41 +0100 Subject: [PATCH 06/36] Set push url correctly for github clones --- src/Composer/Downloader/GitDownloader.php | 7 +++++++ .../Composer/Test/Downloader/GitDownloaderTest.php | 13 ++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index cceb4cf8b..e6949ea7a 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -34,6 +34,13 @@ class GitDownloader extends VcsDownloader }; $this->runCommand($commandCallable, $package->getSourceUrl(), $path); + + // set push url for github projects + if (preg_match('{^(?:https?|git)://github.com/([^/]+)/([^/]+?)(?:\.git)?$}', $package->getSourceUrl(), $match)) { + $pushUrl = 'git@github.com:'.$match[1].'/'.$match[2].'.git'; + $cmd = sprintf('cd %s && git remote set-url --push origin %s', escapeshellarg($path), escapeshellarg($pushUrl)); + $this->process->execute($cmd, $ignoredOutput); + } } /** diff --git a/tests/Composer/Test/Downloader/GitDownloaderTest.php b/tests/Composer/Test/Downloader/GitDownloaderTest.php index b6eed80a1..3decf991b 100644 --- a/tests/Composer/Test/Downloader/GitDownloaderTest.php +++ b/tests/Composer/Test/Downloader/GitDownloaderTest.php @@ -41,7 +41,6 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase public function testDownload() { - $expectedGitCommand = $this->getCmd("git clone 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'"); $packageMock = $this->getMock('Composer\Package\PackageInterface'); $packageMock->expects($this->any()) ->method('getSourceReference') @@ -50,6 +49,8 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase ->method('getSourceUrl') ->will($this->returnValue('https://example.com/composer/composer')); $processExecutor = $this->getMock('Composer\Util\ProcessExecutor'); + + $expectedGitCommand = $this->getCmd("git clone 'https://example.com/composer/composer' 'composerPath' && cd 'composerPath' && git checkout 'ref' && git reset --hard 'ref'"); $processExecutor->expects($this->once()) ->method('execute') ->with($this->equalTo($expectedGitCommand)) @@ -59,13 +60,13 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase $downloader->download($packageMock, 'composerPath'); } - public function testDownloadUsesVariousProtocolsForGithub() + public function testDownloadUsesVariousProtocolsAndSetsPushUrlForGithub() { $packageMock = $this->getMock('Composer\Package\PackageInterface'); $packageMock->expects($this->any()) ->method('getSourceReference') ->will($this->returnValue('ref')); - $packageMock->expects($this->once()) + $packageMock->expects($this->any()) ->method('getSourceUrl') ->will($this->returnValue('https://github.com/composer/composer')); $processExecutor = $this->getMock('Composer\Util\ProcessExecutor'); @@ -88,6 +89,12 @@ class GitDownloaderTest extends \PHPUnit_Framework_TestCase ->with($this->equalTo($expectedGitCommand)) ->will($this->returnValue(0)); + $expectedGitCommand = $this->getCmd("cd 'composerPath' && git remote set-url --push origin 'git@github.com:composer/composer.git'"); + $processExecutor->expects($this->at(3)) + ->method('execute') + ->with($this->equalTo($expectedGitCommand)) + ->will($this->returnValue(0)); + $downloader = $this->getDownloaderMock(null, $processExecutor); $downloader->download($packageMock, 'composerPath'); } From 1e5331dcc531881c4829b886e15ad8a05c7a4261 Mon Sep 17 00:00:00 2001 From: Beau Simensen Date: Mon, 12 Mar 2012 10:15:12 -0700 Subject: [PATCH 07/36] Added a branch alias for dev-master. --- composer.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 69d20af20..c98a8aa52 100644 --- a/composer.json +++ b/composer.json @@ -31,5 +31,10 @@ "autoload": { "psr-0": { "Composer": "src/" } }, - "bin": ["bin/composer"] + "bin": ["bin/composer"], + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + } } From 903eff10eb3fd8a9724807bdc118dd618e009c87 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 13 Mar 2012 22:07:22 -0500 Subject: [PATCH 08/36] Proofreading the first and second chapters of the very well-written docs Changes are mostly wording, rephrasing. I did remove some duplicate content between the intro and the basic usage --- doc/00-intro.md | 62 ++++++++++++++++++++++++------------- doc/01-basic-usage.md | 72 +++++++++++++++++++------------------------ 2 files changed, 73 insertions(+), 61 deletions(-) diff --git a/doc/00-intro.md b/doc/00-intro.md index 1169a06a0..d218c59a7 100644 --- a/doc/00-intro.md +++ b/doc/00-intro.md @@ -1,23 +1,30 @@ # Introduction Composer is a tool for dependency management in PHP. It allows you to declare -the dependencies of your project and will install them for you. +the dependent libraries your project needs and it will install them in your +project for you. ## Dependency management -One important distinction to make is that composer is not a package manager. It -deals with packages, but it manages them on a per-project basis. By default it -will never install anything globally. Thus, it is a dependency manager. +Composer is not a package manager. Yes, it deals with "packages" or libraries, but +it manages them on a per-project basis, installing them in a directory (e.g. `vendor`) +inside your project. By default it will never install anything globally. Thus, +it is a dependency manager. -This idea is not new by any means. Composer is strongly inspired by -node's [npm](http://npmjs.org/) and ruby's [bundler](http://gembundler.com/). -But there has not been such a tool for PHP so far. +This idea is not new and Composer is strongly inspired by node's [npm](http://npmjs.org/) +and ruby's [bundler](http://gembundler.com/). But there has not been such a tool +for PHP. -The problem that composer solves is the following. You have a project that -depends on a number of libraries. Some of those libraries have dependencies of -their own. You declare the things you depend on. Composer will then go ahead -and find out which versions of which packages need to be installed, and -install them. +The problem that composer solves is this: + +a) You have a project that depends on a number of libraries. + +b) Some of those libraries depend on other libraries . + +c) You declare the things you depend on + +d) Composer finds out which versions of which packages need to be installed, and + install them (meaning it downloads them into your project). ## Declaring dependencies @@ -32,37 +39,50 @@ which describes the project's dependencies. } } -We are simply stating that our project requires the `monolog/monolog` package, +We are simply stating that our project requires some `monolog/monolog` package, any version beginning with `1.0`. ## Installation -To actually get it, we need to do two things. The first one is installing -composer: +### 1) Downloading the Composer Executable + +To actually get Composer, we need to do two things. The first one is installing +composer (again, this mean downloading it into your project): $ curl -s http://getcomposer.org/installer | php This will just check a few PHP settings and then download `composer.phar` to -your working directory. This file is the composer binary. +your working directory. This file is the composer binary. It is a PHAR (PHP +archive), which is an archive format for PHP which can be run on the command +line, amongst other things. You can install composer to a specific directory by using the `--install-dir` option and providing a target directory (it can be an absolute or relative path): $ curl -s http://getcomposer.org/installer | php -- --install-dir=bin -After that we run the command for installing all dependencies: +You can place this file anywhere you wish. If you put it in your `PATH`, +you can access it globally. On unixy systems you can even make it +executable and invoke it without `php`. + +### 2) Using Composer + +Next, run the command the `install` command to calculate and download dependencies: $ php composer.phar install -This will download monolog and dump it into `vendor/monolog/monolog`. +This will download monolog into the `vendor/monolog/monolog` directory. ## Autoloading -After this you can just add the following line to your bootstrap code to get -autoloading: +Besides download the library, Composer also prepares an autoload file that's +capable of autoloading all of the classes in any of the libraries that it +downloads. To use it, just add the following line to your code's bootstrap +process: require 'vendor/.composer/autoload.php'; -That's all it takes to have a basic setup. +Woh! Now starting using monolog! To keep learning more about Composer, keep +reading the "Basic Usage" chapter. [Basic Usage](01-basic-usage.md) → diff --git a/doc/01-basic-usage.md b/doc/01-basic-usage.md index 8056ae713..7f090bfce 100644 --- a/doc/01-basic-usage.md +++ b/doc/01-basic-usage.md @@ -2,26 +2,11 @@ ## Installation -To install composer, simply run this command on the command line: +To install composer, you just need to download the `composer.phar` executable. $ curl -s http://getcomposer.org/installer | php -This will perform some checks on your environment to make sure you can -actually run it. - -Then it will download `composer.phar` and place it in your working directory. -`composer.phar` is the composer binary. It is a PHAR (PHP archive), which is -an archive format for PHP which can be run on the command line, amongst other -things. - -You can place this file anywhere you wish. If you put it in your `PATH`, -you can access it globally. On unixy systems you can even make it -executable and invoke it without `php`. - -You can install composer to a specific directory by using the `--install-dir` -option and providing a target directory (it can be an absolute or relative path): - - $ curl -s http://getcomposer.org/installer | php -- --install-dir=bin +For the details, see the [Introduction](00-intro.md) chapter. To check if composer is working, just run the PHAR through `php`: @@ -34,7 +19,7 @@ This should give you a list of available commands. > > $ curl -s http://getcomposer.org/installer | php -- --help -## Project setup +## `composer.json`: Project Setup To start using composer in your project, all you need is a `composer.json` file. This file describes the dependencies of your project and may contain @@ -43,6 +28,8 @@ other metadata as well. The [JSON format](http://json.org/) is quite easy to write. It allows you to define nested structures. +### The `require` Key + The first (and often only) thing you specify in `composer.json` is the `require` key. You're simply telling composer which packages your project depends on. @@ -53,12 +40,13 @@ depends on. } } -As you can see, `require` takes an object that maps package names to versions. +As you can see, `require` takes an object that maps **package names(()) (e.g. `monolog/monolog`) +to ** package versions** (e.g. `1.0.*`). -## Package names +### Package Names The package name consists of a vendor name and the project's name. Often these -will be identical. The vendor name exists to prevent naming clashes. It allows +will be identical - the vendor name just exists to prevent naming clashes. It allows two different people to create a library named `json`, which would then just be named `igorw/json` and `seldaek/json`. @@ -68,10 +56,10 @@ allows adding more related projects under the same namespace later on. If you are maintaining a library, this would make it really easy to split it up into smaller decoupled parts. -## Package versions +### Package Versions -We are also requiring the version `1.0.*` of monolog. This means any version -in the `1.0` development branch. It would match `1.0.0`, `1.0.2` and `1.0.20`. +We are requiring version `1.0.*` of monolog. This means any version in the `1.0` +development branch. It would match `1.0.0`, `1.0.2` or `1.0.20`. Version constraints can be specified in a few different ways. @@ -80,14 +68,14 @@ Version constraints can be specified in a few different ways. * **Range:** By using comparison operators you can specify ranges of valid versions. Valid operators are `>`, `>=`, `<`, `<=`. An example range would be - `>=1.0`. You can define multiple of these, separated by comma: `>=1.0,<2.0`. + `>=1.0`. You can define multiple ranges, separated by a comma: `>=1.0,<2.0`. * **Wildcard:** You can specify a pattern with a `*` wildcard. `1.0.*` is the equivalent of `>=1.0,<1.1-dev`. -## Installing dependencies +## Installing Dependencies -To fetch the defined dependencies into the local project, you simply run the +To fetch the defined dependencies into your local project, just run the `install` command of `composer.phar`. $ php composer.phar install @@ -104,29 +92,33 @@ In case of monolog it will put it into `vendor/monolog/monolog`. Another thing that the `install` command does is it adds a `composer.lock` file into your project root. -## Lock file +## `composer.json` - The Lock File After installing the dependencies, composer writes the list of the exact versions it installed into a `composer.lock` file. This locks the project to those specific versions. -**Commit your project's `composer.lock` into version control.** +**Commit your project's `composer.lock` (along with `composer.json`) into version control.** -The reason is that anyone who sets up the project should get the same version. -The `install` command will check if a lock file is present. If it is, it will -use the versions specified there. If not, it will resolve the dependencies and -create a lock file. +This is important because the `install` command checks if a lock file is present, +and if it is, it downloads the versions specified there (regardless of what `composer.json` +says). This means that anyone who sets up the project will download the exact +same version of the dependencies. -If any of the dependencies gets a new version, you can update to that version -by using the `update` command. This will fetch the latest matching versions and -also update the lock file. +If no `composer.json` lock file exists, it will read the dependencies and +versions from `composer.json` and create the lock file. + +This means that if any of the dependencies gets a new version, you won't be updated +automatically. To update to the new version, use `update` command. This will fetch +the latest matching versions (according to your `composer.json` file) and also update +the lock file with the new version. $ php composer.phar update ## Packagist [Packagist](http://packagist.org/) is the main composer repository. A composer -repository is basically a package source. A place where you can get packages +repository is basically a package source: a place where you can get packages from. Packagist aims to be the central repository that everybody uses. This means that you can automatically `require` any package that is available there. @@ -135,7 +127,8 @@ If you go to the [packagist website](http://packagist.org/) (packagist.org), you can browse and search for packages. Any open source project using composer should publish their packages on -packagist. +packagist. A library doesn't need to be on packagist to be used by composer, +but it makes life quite a bit simpler. ## Autoloading @@ -146,8 +139,7 @@ this file and you will get autoloading for free. require 'vendor/.composer/autoload.php'; -This makes it really easy to use third party code, because you only -have to add one line to `composer.json` and run `install`. For monolog, it +This makes it really easy to use third party code: For monolog, it means that we can just start using classes from it, and they will be autoloaded. From 37b4edc25d958f9f1c8c3f8fa14e4622bc41bdc1 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 14 Mar 2012 00:25:17 -0500 Subject: [PATCH 09/36] Fixing typo per @stof --- doc/01-basic-usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/01-basic-usage.md b/doc/01-basic-usage.md index 7f090bfce..450da9cad 100644 --- a/doc/01-basic-usage.md +++ b/doc/01-basic-usage.md @@ -92,7 +92,7 @@ In case of monolog it will put it into `vendor/monolog/monolog`. Another thing that the `install` command does is it adds a `composer.lock` file into your project root. -## `composer.json` - The Lock File +## `composer.lock` - The Lock File After installing the dependencies, composer writes the list of the exact versions it installed into a `composer.lock` file. This locks the project From 32adc8908d8b2255c7d7011e6938487740da1fac Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 14 Mar 2012 15:23:11 +0100 Subject: [PATCH 10/36] Fix line numbers in phars --- src/Composer/Compiler.php | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/Composer/Compiler.php b/src/Composer/Compiler.php index ca4875a97..3d3401a26 100644 --- a/src/Composer/Compiler.php +++ b/src/Composer/Compiler.php @@ -102,12 +102,11 @@ class Compiler { $path = str_replace(dirname(dirname(__DIR__)).DIRECTORY_SEPARATOR, '', $file->getRealPath()); + $content = file_get_contents($file); if ($strip) { - $content = php_strip_whitespace($file); + $content = $this->stripComments($content); } elseif ('LICENSE' === basename($file)) { - $content = "\n".file_get_contents($file)."\n"; - } else { - $content = file_get_contents($file); + $content = "\n".$content."\n"; } $content = str_replace('@package_version@', $this->version, $content); @@ -122,6 +121,32 @@ class Compiler $phar->addFromString('bin/composer', $content); } + /** + * Removes comments from a PHP source string. + * + * @param string $source A PHP string + * @return string The PHP string with the comments removed + */ + private function stripComments($source) + { + if (!function_exists('token_get_all')) { + return $source; + } + + $output = ''; + foreach (token_get_all($source) as $token) { + if (is_string($token)) { + $output .= $token; + } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) { + $output .= str_repeat("\n", substr_count($token[1], "\n")); + } else { + $output .= $token[1]; + } + } + + return $output; + } + private function getStub() { return <<<'EOF' From 4b24b972a789d387d96e97ab035300f35d8d6847 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 14 Mar 2012 15:35:08 +0100 Subject: [PATCH 11/36] Improve stripping --- src/Composer/Compiler.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Composer/Compiler.php b/src/Composer/Compiler.php index 3d3401a26..e6af59826 100644 --- a/src/Composer/Compiler.php +++ b/src/Composer/Compiler.php @@ -104,7 +104,7 @@ class Compiler $content = file_get_contents($file); if ($strip) { - $content = $this->stripComments($content); + $content = $this->stripWhitespace($content); } elseif ('LICENSE' === basename($file)) { $content = "\n".$content."\n"; } @@ -122,12 +122,12 @@ class Compiler } /** - * Removes comments from a PHP source string. + * Removes whitespace from a PHP source string while preserving line numbers. * * @param string $source A PHP string - * @return string The PHP string with the comments removed + * @return string The PHP string with the whitespace removed */ - private function stripComments($source) + private function stripWhitespace($source) { if (!function_exists('token_get_all')) { return $source; @@ -139,6 +139,14 @@ class Compiler $output .= $token; } elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) { $output .= str_repeat("\n", substr_count($token[1], "\n")); + } elseif (T_WHITESPACE === $token[0]) { + // reduce wide spaces + $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]); + // normalize newlines to \n + $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace); + // trim leading spaces + $whitespace = preg_replace('{\n +}', "\n", $whitespace); + $output .= $whitespace; } else { $output .= $token[1]; } From 7ab3a968745f5dad1453200d980af9a3f43d11d5 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Wed, 14 Mar 2012 15:37:45 +0100 Subject: [PATCH 12/36] Micro-optimization --- src/Composer/Factory.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 3f4812927..8c01066ad 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -83,6 +83,7 @@ class Factory foreach ($packageConfig['repositories'] as $repo) { if (isset($repo['packagist']) && $repo['packagist'] === false) { $loadPackagist = false; + break; } } } From ce08b2fc4f68de4e030f140274938d2becb92335 Mon Sep 17 00:00:00 2001 From: Beau Simensen Date: Wed, 14 Mar 2012 15:40:51 -0700 Subject: [PATCH 13/36] Fix HTTPS through Proxy errors. --- src/Composer/Util/RemoteFilesystem.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index 87d725037..57719cbf4 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -102,10 +102,9 @@ class RemoteFilesystem $this->io->write(" Downloading: connection...", false); } + $result = @file_get_contents($fileUrl, false, $ctx); if (null !== $fileName) { - $result = @copy($fileUrl, $fileName, $ctx); - } else { - $result = @file_get_contents($fileUrl, false, $ctx); + $result = @file_put_contents($fileName, $result) ? true : false; } // fix for 5.4.0 https://bugs.php.net/bug.php?id=61336 From 96b07ffb7b5f518fa557db17ce02089f4a5389f7 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 15 Mar 2012 00:56:04 +0100 Subject: [PATCH 14/36] Ensure missing packages are reinstalled if they are deleted from the filesystem, fixes #355, fixes #437 --- src/Composer/Factory.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 8c01066ad..df32d10ec 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -104,6 +104,13 @@ class Factory // initialize installation manager $im = $this->createInstallationManager($rm, $dm, $vendorDir, $binDir, $io); + // purge packages if they have been deleted on the filesystem + foreach ($rm->getLocalRepository()->getPackages() as $package) { + if (!$im->isPackageInstalled($package)) { + $rm->getLocalRepository()->removePackage($package); + } + } + // 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)); From 768bedc16409f27010b3d7de991c593ec31cef58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Chy=C5=82ek?= Date: Thu, 15 Mar 2012 00:57:58 +0100 Subject: [PATCH 15/36] Fix xdebug display errors in autoload --- bin/compile | 6 +++++- bin/composer | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/bin/compile b/bin/compile index bd8426693..e4c1c9eae 100755 --- a/bin/compile +++ b/bin/compile @@ -1,7 +1,11 @@ #!/usr/bin/env php Date: Thu, 15 Mar 2012 01:13:10 +0100 Subject: [PATCH 16/36] Update docs on repo order --- doc/04-schema.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/04-schema.md b/doc/04-schema.md index e3308630e..31188663f 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -297,9 +297,10 @@ Example: ] } -> **Note:** Order is significant here. Repositories added later will take -precedence. This also means that custom repositories can override packages -that exist on packagist. +> **Note:** Order is significant here. When looking for a package, Composer +will look from the first to the last repository, and pick the first match. +By default Packagist is added last which means that custom repositories can +override packages from it. ## config From b85564386545d05d45b179551462ec36c2be7c97 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 15 Mar 2012 01:13:25 +0100 Subject: [PATCH 17/36] Usability fix --- src/Composer/Package/Loader/RootPackageLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index 77b2599fb..734e28c1a 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -68,7 +68,7 @@ class RootPackageLoader extends ArrayLoader throw new \UnexpectedValueException('Repository '.$index.' should be an array, '.gettype($repo).' given'); } if (!isset($repo['type'])) { - throw new \UnexpectedValueException('Repository '.$index.' must have a type defined'); + throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a type defined'); } $repository = $this->manager->createRepository($repo['type'], $repo); $this->manager->addRepository($repository); From a02940cafbf9cdeef90b0781550ea2f4f45eb6c3 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 15 Mar 2012 01:28:10 +0100 Subject: [PATCH 18/36] Fix tests --- src/Composer/Downloader/FileDownloader.php | 7 +++--- .../Test/Downloader/FileDownloaderTest.php | 22 ++++++++++++++----- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index d3e668c93..1b440048f 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -27,15 +27,17 @@ use Composer\Util\RemoteFilesystem; class FileDownloader implements DownloaderInterface { protected $io; + protected $rfs; /** * Constructor. * * @param IOInterface $io The IO instance */ - public function __construct(IOInterface $io) + public function __construct(IOInterface $io, RemoteFilesystem $rfs = null) { $this->io = $io; + $this->rfs = $rfs ?: new RemoteFilesystem($io); } /** @@ -71,8 +73,7 @@ class FileDownloader implements DownloaderInterface $url = $this->processUrl($url); - $rfs = new RemoteFilesystem($this->io); - $rfs->copy($package->getSourceUrl(), $url, $fileName); + $this->rfs->copy($package->getSourceUrl(), $url, $fileName); $this->io->write(''); if (!file_exists($fileName)) { diff --git a/tests/Composer/Test/Downloader/FileDownloaderTest.php b/tests/Composer/Test/Downloader/FileDownloaderTest.php index cc0fb2f6a..a93deaac5 100644 --- a/tests/Composer/Test/Downloader/FileDownloaderTest.php +++ b/tests/Composer/Test/Downloader/FileDownloaderTest.php @@ -17,6 +17,13 @@ use Composer\Util\Filesystem; class FileDownloaderTest extends \PHPUnit_Framework_TestCase { + protected function getDownloader($io = null, $rfs = null) + { + $io = $io ?: $this->getMock('Composer\IO\IOInterface'); + $rfs = $rfs ?: $this->getMockBuilder('Composer\Util\RemoteFilesystem')->disableOriginalConstructor()->getMock(); + return new FileDownloader($io, $rfs); + } + /** * @expectedException \InvalidArgumentException */ @@ -28,7 +35,7 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue(null)) ; - $downloader = new FileDownloader($this->getMock('Composer\IO\IOInterface')); + $downloader = $this->getDownloader(); $downloader->download($packageMock, '/path'); } @@ -42,7 +49,7 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase $path = tempnam(sys_get_temp_dir(), 'c'); - $downloader = new FileDownloader($this->getMock('Composer\IO\IOInterface')); + $downloader = $this->getDownloader(); try { $downloader->download($packageMock, $path); $this->fail(); @@ -63,7 +70,7 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue('http://example.com/script.js')) ; - $downloader = new FileDownloader($this->getMock('Composer\IO\IOInterface')); + $downloader = $this->getDownloader(); $method = new \ReflectionMethod($downloader, 'getFileName'); $method->setAccessible(true); @@ -93,7 +100,7 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase })) ; - $downloader = new FileDownloader($ioMock); + $downloader = $this->getDownloader($ioMock); try { $downloader->download($packageMock, $path); $this->fail(); @@ -126,7 +133,12 @@ class FileDownloaderTest extends \PHPUnit_Framework_TestCase $path = sys_get_temp_dir().'/'.md5(time().rand()); } while (file_exists($path)); - $downloader = new FileDownloader($this->getMock('Composer\IO\IOInterface')); + $downloader = $this->getDownloader(); + + // make sure the file expected to be downloaded is on disk already + mkdir($path, 0777, true); + touch($path.'/script.js'); + try { $downloader->download($packageMock, $path); $this->fail(); From a5edc9e357aba73978d33b91fba1fabac9ffe778 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 15 Mar 2012 01:49:29 +0100 Subject: [PATCH 19/36] Extract package purging in a method and fix variable overriding --- src/Composer/Factory.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 30763e886..958844930 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -94,11 +94,7 @@ class Factory $im = $this->createInstallationManager($rm, $dm, $vendorDir, $binDir, $io); // purge packages if they have been deleted on the filesystem - foreach ($rm->getLocalRepository()->getPackages() as $package) { - if (!$im->isPackageInstalled($package)) { - $rm->getLocalRepository()->removePackage($package); - } - } + $this->purgePackages($rm, $im); // init locker $lockFile = substr($composerFile, -5) === '.json' ? substr($composerFile, 0, -4).'lock' : $composerFile . '.lock'; @@ -187,6 +183,15 @@ class Factory return $im; } + protected function purgePackages(Repository\RepositoryManager $rm, Installer\InstallationManager $im) + { + foreach ($rm->getLocalRepository()->getPackages() as $package) { + if (!$im->isPackageInstalled($package)) { + $rm->getLocalRepository()->removePackage($package); + } + } + } + static public function create(IOInterface $io, $composerFile = null) { $factory = new static(); From 7d2a2878639283de0c5cb68683a4ea6ab89c7c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Chy=C5=82ek?= Date: Thu, 15 Mar 2012 01:51:54 +0100 Subject: [PATCH 20/36] Add file_exists in bootstrap.php --- tests/bootstrap.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 02bd0e169..39c661936 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -10,7 +10,15 @@ * file that was distributed with this source code. */ -if ((!$loader = @include __DIR__.'/../../../.composer/autoload.php') && (!$loader = @include __DIR__.'/../vendor/.composer/autoload.php')) { +function autoload($file) { + if (file_exists($file)) { + return include $file; + } else { + return false; + } +} + +if ((!$loader = autoload(__DIR__.'/../../../.composer/autoload.php')) && (!$loader = autoload(__DIR__.'/../vendor/.composer/autoload.php'))) { die('You must set up the project dependencies, run the following commands:'.PHP_EOL. 'curl -s http://getcomposer.org/installer | php'.PHP_EOL. 'php composer.phar install'.PHP_EOL); From 82812ebc3704d2831aeb475cf0f4c22bbcf21a93 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 15 Mar 2012 02:29:53 +0100 Subject: [PATCH 21/36] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2a726272..4a93f6984 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * Added "file" downloader type to download plain files * Added support for authentication with svn repositories * Dependency on filter_var is now optional + * Many improvements to the `search` & `show` commands * Various robustness & error handling improvements * 1.0.0-alpha1 (2012-03-01) From 38680998ed18943276fedd830422c7736715d8b5 Mon Sep 17 00:00:00 2001 From: Beau Simensen Date: Wed, 14 Mar 2012 18:44:27 -0700 Subject: [PATCH 22/36] Remove the RemoteFilesystem factory and document GitHubDriver->GitDriver fallback. --- src/Composer/Downloader/ArchiveDownloader.php | 1 - src/Composer/Repository/Vcs/GitHubDriver.php | 13 +++++++++---- src/Composer/Repository/Vcs/VcsDriver.php | 13 +++++-------- .../Test/Repository/Vcs/GitHubDriverTest.php | 10 +++------- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/Composer/Downloader/ArchiveDownloader.php b/src/Composer/Downloader/ArchiveDownloader.php index 07d418bed..8e921a3e4 100644 --- a/src/Composer/Downloader/ArchiveDownloader.php +++ b/src/Composer/Downloader/ArchiveDownloader.php @@ -15,7 +15,6 @@ namespace Composer\Downloader; use Composer\IO\IOInterface; use Composer\Package\PackageInterface; use Composer\Util\Filesystem; -use Composer\Util\RemoteFilesystem; /** * Base downloader for archives diff --git a/src/Composer/Repository/Vcs/GitHubDriver.php b/src/Composer/Repository/Vcs/GitHubDriver.php index 6566d2b22..95701ddd6 100644 --- a/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/src/Composer/Repository/Vcs/GitHubDriver.php @@ -6,6 +6,7 @@ use Composer\Downloader\TransportException; use Composer\Json\JsonFile; use Composer\IO\IOInterface; use Composer\Util\ProcessExecutor; +use Composer\Util\RemoteFilesystem; /** * @author Jordi Boggiano @@ -33,15 +34,15 @@ class GitHubDriver extends VcsDriver * @param string $url * @param IOInterface $io * @param ProcessExecutor $process - * @param callable $remoteFilesystemFactory + * @param RemoteFilesystem $remoteFilesystem */ - public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystemFactory = null) + public function __construct($url, IOInterface $io, ProcessExecutor $process = null, RemoteFilesystem $remoteFilesystem = null) { preg_match('#^(?:https?|git)://github\.com/([^/]+)/(.+?)(?:\.git)?$#', $url, $match); $this->owner = $match[1]; $this->repository = $match[2]; - parent::__construct($url, $io, $process, $remoteFilesystemFactory); + parent::__construct($url, $io, $process, $remoteFilesystem); } /** @@ -212,11 +213,15 @@ class GitHubDriver extends VcsDriver case 404: $this->isPrivate = true; if (!$this->io->isInteractive()) { + // If this repository may be private (hard to say for sure, + // GitHub returns 404 for private repositories) and we + // cannot ask for authentication credentials (because we + // are not interactive) then we fallback to GitDriver. $this->gitDriver = new GitDriver( $this->generateSshUrl(), $this->io, $this->process, - $this->remoteFilesystemFactory + $this->remoteFilesystem ); $this->gitDriver->initialize(); return; diff --git a/src/Composer/Repository/Vcs/VcsDriver.php b/src/Composer/Repository/Vcs/VcsDriver.php index c2f65a7d8..99c705c50 100644 --- a/src/Composer/Repository/Vcs/VcsDriver.php +++ b/src/Composer/Repository/Vcs/VcsDriver.php @@ -27,7 +27,7 @@ abstract class VcsDriver implements VcsDriverInterface protected $url; protected $io; protected $process; - protected $remoteFilesystemFactory; + protected $remoteFilesystem; /** * Constructor. @@ -35,16 +35,14 @@ abstract class VcsDriver implements VcsDriverInterface * @param string $url The URL * @param IOInterface $io The IO instance * @param ProcessExecutor $process Process instance, injectable for mocking - * @param callable $remoteFilesystemFactory Remote Filesystem factory, injectable for mocking + * @param callable $remoteFilesystem Remote Filesystem, injectable for mocking */ - public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystemFactory = null) + public function __construct($url, IOInterface $io, ProcessExecutor $process = null, $remoteFilesystem = null) { $this->url = $url; $this->io = $io; $this->process = $process ?: new ProcessExecutor; - $this->remoteFilesystemFactory = $remoteFilesystemFactory ?: function() use ($io) { - return new RemoteFilesystem($io); - }; + $this->remoteFilesystem = $remoteFilesystem ?: new RemoteFilesystem($io); } /** @@ -85,8 +83,7 @@ abstract class VcsDriver implements VcsDriverInterface */ protected function getContents($url) { - $rfs = call_user_func($this->remoteFilesystemFactory); - return $rfs->getContents($this->url, $url, false); + return $this->remoteFilesystem->getContents($this->url, $url, false); } protected static function isLocalUrl($url) diff --git a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php index 96506185c..c410b5ab5 100644 --- a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php @@ -61,7 +61,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase ->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false)) ->will($this->returnValue('{"master_branch": "test_master"}')); - $gitHubDriver = new GitHubDriver($repoUrl, $io, null, function() use ($remoteFilesystem) { return $remoteFilesystem; }); + $gitHubDriver = new GitHubDriver($repoUrl, $io, null, $remoteFilesystem); $gitHubDriver->initialize(); $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha)); @@ -109,9 +109,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase ->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false)) ->will($this->returnValue('{"master_branch": "test_master"}')); - $gitHubDriver = new GitHubDriver($repoUrl, $io, null, function() use ($remoteFilesystem) { - return $remoteFilesystem; - }); + $gitHubDriver = new GitHubDriver($repoUrl, $io, null, $remoteFilesystem); $gitHubDriver->initialize(); $this->setAttribute($gitHubDriver, 'tags', array($identifier => $sha)); @@ -192,9 +190,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase ->method('splitLines') ->will($this->returnValue(array(' upstream/HEAD -> upstream/test_master'))); - $gitHubDriver = new GitHubDriver($repoUrl, $io, $process, function() use ($remoteFilesystem) { - return $remoteFilesystem; - }); + $gitHubDriver = new GitHubDriver($repoUrl, $io, $process, $remoteFilesystem); $gitHubDriver->initialize(); $this->assertEquals('test_master', $gitHubDriver->getRootIdentifier()); From 0e0b5ac222f375e06a95dcf7a4c5fbf023541087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Chy=C5=82ek?= Date: Thu, 15 Mar 2012 11:36:40 +0100 Subject: [PATCH 23/36] chache to return (file_exists() && include ); --- bin/compile | 2 +- bin/composer | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/compile b/bin/compile index e4c1c9eae..589db50d1 100755 --- a/bin/compile +++ b/bin/compile @@ -2,7 +2,7 @@ Date: Thu, 15 Mar 2012 13:14:02 +0100 Subject: [PATCH 24/36] Regroup bootstrapers --- bin/compile | 10 +--------- bin/composer | 10 +--------- src/bootstrap.php | 25 +++++++++++++++++++++++++ tests/bootstrap.php | 15 +-------------- 4 files changed, 28 insertions(+), 32 deletions(-) create mode 100644 src/bootstrap.php diff --git a/bin/compile b/bin/compile index 589db50d1..3bb0fb73d 100755 --- a/bin/compile +++ b/bin/compile @@ -1,15 +1,7 @@ #!/usr/bin/env php + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +function includeIfExists($file) { + if (file_exists($file)) { + return include $file; + } +} + +if ((!$loader = includeIfExists(__DIR__.'/../../../.composer/autoload.php')) && (!$loader = includeIfExists(__DIR__.'/../vendor/.composer/autoload.php'))) { + die('You must set up the project dependencies, run the following commands:'.PHP_EOL. + 'curl -s http://getcomposer.org/installer | php'.PHP_EOL. + 'php composer.phar install'.PHP_EOL); +} + +return $loader; \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 39c661936..a4f2e7cec 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -10,18 +10,5 @@ * file that was distributed with this source code. */ -function autoload($file) { - if (file_exists($file)) { - return include $file; - } else { - return false; - } -} - -if ((!$loader = autoload(__DIR__.'/../../../.composer/autoload.php')) && (!$loader = autoload(__DIR__.'/../vendor/.composer/autoload.php'))) { - die('You must set up the project dependencies, run the following commands:'.PHP_EOL. - 'curl -s http://getcomposer.org/installer | php'.PHP_EOL. - 'php composer.phar install'.PHP_EOL); -} - +$loader = require __DIR__.'/../src/bootstrap.php'; $loader->add('Composer\Test', __DIR__); From 30c880e5ffb5b9851295f17c9633c49a9c487128 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 15 Mar 2012 13:14:13 +0100 Subject: [PATCH 25/36] Update lock file --- composer.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.lock b/composer.lock index f6bdab64f..56479e5f5 100644 --- a/composer.lock +++ b/composer.lock @@ -1,5 +1,5 @@ { - "hash": "959be339ea6f0b140f09215c4ef451cc", + "hash": "df0b80bd7287f1783e3bf2a2c4b9db63", "packages": [ { "package": "justinrainbow/json-schema", @@ -9,7 +9,7 @@ { "package": "seld/jsonlint", "version": "dev-master", - "source-reference": "12f0b1e5334a52b7035e1d15f36974db7c06b78d" + "source-reference": "869e5d011fe1c82501ae0a3b427a686c21fd5baf" }, { "package": "symfony/console", From caf29268be519afead34600fe6c1d7549c6e1e36 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 15 Mar 2012 07:53:34 -0500 Subject: [PATCH 26/36] Tweaks per @igorw and @Seldaek. Biggest change is the capitalization of Composer (in these first 2 chapters so far) when we're talking about the actual library --- doc/00-intro.md | 16 ++++++++-------- doc/01-basic-usage.md | 30 +++++++++++++++--------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/doc/00-intro.md b/doc/00-intro.md index d218c59a7..289483336 100644 --- a/doc/00-intro.md +++ b/doc/00-intro.md @@ -15,7 +15,7 @@ This idea is not new and Composer is strongly inspired by node's [npm](http://np and ruby's [bundler](http://gembundler.com/). But there has not been such a tool for PHP. -The problem that composer solves is this: +The problem that Composer solves is this: a) You have a project that depends on a number of libraries. @@ -24,7 +24,7 @@ b) Some of those libraries depend on other libraries . c) You declare the things you depend on d) Composer finds out which versions of which packages need to be installed, and - install them (meaning it downloads them into your project). + installs them (meaning it downloads them into your project). ## Declaring dependencies @@ -47,16 +47,16 @@ any version beginning with `1.0`. ### 1) Downloading the Composer Executable To actually get Composer, we need to do two things. The first one is installing -composer (again, this mean downloading it into your project): +Composer (again, this mean downloading it into your project): $ curl -s http://getcomposer.org/installer | php This will just check a few PHP settings and then download `composer.phar` to -your working directory. This file is the composer binary. It is a PHAR (PHP +your working directory. This file is the Composer binary. It is a PHAR (PHP archive), which is an archive format for PHP which can be run on the command line, amongst other things. -You can install composer to a specific directory by using the `--install-dir` +You can install Composer to a specific directory by using the `--install-dir` option and providing a target directory (it can be an absolute or relative path): $ curl -s http://getcomposer.org/installer | php -- --install-dir=bin @@ -67,7 +67,7 @@ executable and invoke it without `php`. ### 2) Using Composer -Next, run the command the `install` command to calculate and download dependencies: +Next, run the command the `install` command to resolve and download dependencies: $ php composer.phar install @@ -75,14 +75,14 @@ This will download monolog into the `vendor/monolog/monolog` directory. ## Autoloading -Besides download the library, Composer also prepares an autoload file that's +Besides downloading the library, Composer also prepares an autoload file that's capable of autoloading all of the classes in any of the libraries that it downloads. To use it, just add the following line to your code's bootstrap process: require 'vendor/.composer/autoload.php'; -Woh! Now starting using monolog! To keep learning more about Composer, keep +Woh! Now start using monolog! To keep learning more about Composer, keep reading the "Basic Usage" chapter. [Basic Usage](01-basic-usage.md) → diff --git a/doc/01-basic-usage.md b/doc/01-basic-usage.md index 450da9cad..e8037b7cd 100644 --- a/doc/01-basic-usage.md +++ b/doc/01-basic-usage.md @@ -2,26 +2,26 @@ ## Installation -To install composer, you just need to download the `composer.phar` executable. +To install Composer, you just need to download the `composer.phar` executable. $ curl -s http://getcomposer.org/installer | php For the details, see the [Introduction](00-intro.md) chapter. -To check if composer is working, just run the PHAR through `php`: +To check if Composer is working, just run the PHAR through `php`: $ php composer.phar This should give you a list of available commands. -> **Note:** You can also perform the checks only without downloading composer +> **Note:** You can also perform the checks only without downloading Composer > by using the `--check` option. For more information, just use `--help`. > > $ curl -s http://getcomposer.org/installer | php -- --help ## `composer.json`: Project Setup -To start using composer in your project, all you need is a `composer.json` +To start using Composer in your project, all you need is a `composer.json` file. This file describes the dependencies of your project and may contain other metadata as well. @@ -31,7 +31,7 @@ define nested structures. ### The `require` Key The first (and often only) thing you specify in `composer.json` is the -`require` key. You're simply telling composer which packages your project +`require` key. You're simply telling Composer which packages your project depends on. { @@ -40,8 +40,8 @@ depends on. } } -As you can see, `require` takes an object that maps **package names(()) (e.g. `monolog/monolog`) -to ** package versions** (e.g. `1.0.*`). +As you can see, `require` takes an object that maps **package names** (e.g. `monolog/monolog`) +to **package versions** (e.g. `1.0.*`). ### Package Names @@ -94,7 +94,7 @@ file into your project root. ## `composer.lock` - The Lock File -After installing the dependencies, composer writes the list of the exact +After installing the dependencies, Composer writes the list of the exact versions it installed into a `composer.lock` file. This locks the project to those specific versions. @@ -108,7 +108,7 @@ same version of the dependencies. If no `composer.json` lock file exists, it will read the dependencies and versions from `composer.json` and create the lock file. -This means that if any of the dependencies gets a new version, you won't be updated +This means that if any of the dependencies get a new version, you won't get the updates. automatically. To update to the new version, use `update` command. This will fetch the latest matching versions (according to your `composer.json` file) and also update the lock file with the new version. @@ -117,7 +117,7 @@ the lock file with the new version. ## Packagist -[Packagist](http://packagist.org/) is the main composer repository. A composer +[Packagist](http://packagist.org/) is the main Composer repository. A Composer repository is basically a package source: a place where you can get packages from. Packagist aims to be the central repository that everybody uses. This means that you can automatically `require` any package that is available @@ -126,16 +126,16 @@ there. If you go to the [packagist website](http://packagist.org/) (packagist.org), you can browse and search for packages. -Any open source project using composer should publish their packages on -packagist. A library doesn't need to be on packagist to be used by composer, +Any open source project using Composer should publish their packages on +packagist. A library doesn't need to be on packagist to be used by Composer, but it makes life quite a bit simpler. ## Autoloading For libraries that follow the [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) -naming standard, composer generates a -`vendor/.composer/autoload.php` file for autoloading. You can simply include -this file and you will get autoloading for free. +naming standard, Composer generates a `vendor/.composer/autoload.php` file +for autoloading. You can simply include this file and you will get autoloading +for free. require 'vendor/.composer/autoload.php'; From d5891fe8d060b5dd4936b6196ad877b5dcff861c Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 15 Mar 2012 18:32:31 +0100 Subject: [PATCH 27/36] Fix test --- tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php index c410b5ab5..48dfff6a8 100644 --- a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php @@ -14,6 +14,7 @@ namespace Composer\Test\Repository\Vcs; use Composer\Downloader\TransportException; use Composer\Repository\Vcs\GitHubDriver; +use Composer\Util\Filesystem; /** * @author Beau Simensen @@ -162,9 +163,13 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase ->with($this->equalTo($repoUrl), $this->equalTo($repoApiUrl), $this->equalTo(false)) ->will($this->throwException(new TransportException('HTTP/1.1 404 Not Found', 404))); + // clean local clone if present + $fs = new Filesystem(); + $fs->removeDirectory(sys_get_temp_dir() . '/composer-' . preg_replace('{[^a-z0-9]}i', '-', $repoSshUrl) . '/'); + $process->expects($this->at(0)) ->method('execute') - ->with($this->stringContains('git fetch origin')); + ->with($this->stringContains($repoSshUrl)); $process->expects($this->at(1)) ->method('execute') From 59449feb3bc04117b4b107561bd68ad02d5c2fa3 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 15 Mar 2012 18:37:09 +0100 Subject: [PATCH 28/36] Update CHANGELOG --- CHANGELOG.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a93f6984..985127bbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,14 @@ * Added `create-project` command to install a project from scratch with composer * Added automated `classmap` autoloading support for non-PSR-0 compliant projects - * Git clones from GitHub automatically select between git/https/http protocols - * Enhanced `validate` command to give more feedback + * Improved clones from GitHub which now automatically select between git/https/http protocols + * Added support for private GitHub repositories (use --no-interaction for CI) + * Improved `validate` command to give more feedback * Added "file" downloader type to download plain files * Added support for authentication with svn repositories - * Dependency on filter_var is now optional - * Many improvements to the `search` & `show` commands - * Various robustness & error handling improvements + * Removed dependency on filter_var + * Improved the `search` & `show` commands output + * Various robustness & error handling improvements, docs fixes and more * 1.0.0-alpha1 (2012-03-01) From dd6608e4c2278f1dd82bd945cffd1c87002ba079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 15 Mar 2012 23:06:00 +0100 Subject: [PATCH 29/36] Allow unicode characters for author in "composer init" command. --- src/Composer/Command/InitCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Command/InitCommand.php b/src/Composer/Command/InitCommand.php index 6f8433c23..cdd5c4e34 100644 --- a/src/Composer/Command/InitCommand.php +++ b/src/Composer/Command/InitCommand.php @@ -33,7 +33,7 @@ class InitCommand extends Command public function parseAuthorString($author) { - if (preg_match('/^(?P[- \.,a-z0-9]+) <(?P.+?)>$/i', $author, $match)) { + if (preg_match('/^(?P[- \.,\w]+) <(?P.+?)>$/u', $author, $match)) { if (!function_exists('filter_var') || $match['email'] === filter_var($match['email'], FILTER_VALIDATE_EMAIL)) { return array( 'name' => trim($match['name']), From f65fe270979efe344c13d1fe87e3663824fccef2 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Fri, 16 Mar 2012 08:40:18 +0100 Subject: [PATCH 30/36] fixed create-project with json file the create-project command tried to instantiate a FilesystemRepository with the json file as string instead of an JsonFile instance --- src/Composer/Command/CreateProjectCommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index a859ac12a..4ad2e81d2 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -22,6 +22,7 @@ use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Composer\Json\JsonFile; /** * Install a package as new project into new directory. @@ -85,7 +86,7 @@ EOT if (null === $repositoryUrl) { $sourceRepo = new ComposerRepository(array('url' => 'http://packagist.org')); } elseif (".json" === substr($repositoryUrl, -5)) { - $sourceRepo = new FilesystemRepository($repositoryUrl); + $sourceRepo = new FilesystemRepository(new JsonFile($repositoryUrl)); } elseif (0 === strpos($repositoryUrl, 'http')) { $sourceRepo = new ComposerRepository(array('url' => $repositoryUrl)); } else { From 9ed05e09f34b8ad000289f8680491447a63185dc Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 16 Mar 2012 16:07:30 +0100 Subject: [PATCH 31/36] Fix version_compare for ubuntu that ships with versions like 5.3.3-1 (bigger than 5.3.3) --- src/Composer/DependencyResolver/Solver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/DependencyResolver/Solver.php b/src/Composer/DependencyResolver/Solver.php index fd39faed3..aa832b113 100644 --- a/src/Composer/DependencyResolver/Solver.php +++ b/src/Composer/DependencyResolver/Solver.php @@ -911,7 +911,7 @@ class Solver $this->installedMap[$package->getId()] = $package; } - if (version_compare(PHP_VERSION, '5.3.3', '>')) { + if (version_compare(PHP_VERSION, '5.3.4', '>=')) { $this->decisionMap = new \SplFixedArray($this->pool->getMaxId() + 1); } else { $this->decisionMap = array_fill(0, $this->pool->getMaxId() + 1, 0); From 7c43ecd81a13524e2ffef9235b19d172f6b4458b Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 17 Mar 2012 01:14:53 +0100 Subject: [PATCH 32/36] Reflow text --- doc/02-libraries.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/02-libraries.md b/doc/02-libraries.md index f5763b27a..da540e9a9 100644 --- a/doc/02-libraries.md +++ b/doc/02-libraries.md @@ -96,9 +96,9 @@ example we will publish the `acme/hello-world` library on GitHub under `github.com/composer/hello-world`. Now, To test installing the `acme/hello-world` package, we create a new -project locally. We will call it `acme/blog`. This blog will depend on `acme -/hello-world`, which in turn depends on `monolog/monolog`. We can accomplish -this by creating a new `blog` directory somewhere, containing a +project locally. We will call it `acme/blog`. This blog will depend on +`acme/hello-world`, which in turn depends on `monolog/monolog`. We can +accomplish this by creating a new `blog` directory somewhere, containing a `composer.json`: { From 099823c369ffae603572a05084b1376755ae06d2 Mon Sep 17 00:00:00 2001 From: Maks Date: Sat, 17 Mar 2012 08:49:04 +0100 Subject: [PATCH 33/36] Typo --- doc/04-schema.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/04-schema.md b/doc/04-schema.md index 31188663f..0cea8cf0a 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -399,7 +399,7 @@ Optional. A set of files that should be treated as binaries and symlinked into the `bin- dir` (from config). -See (Vendor Bins)[articles/vendor-bins.md] for more details. +See [Vendor Bins](articles/vendor-bins.md) for more details. Optional. From 98686e32e22e9bec7ec9346e54ab3b1aa380a7a4 Mon Sep 17 00:00:00 2001 From: Nils Adermann Date: Sat, 17 Mar 2012 15:02:39 +0100 Subject: [PATCH 34/36] fix typo "is is" => "it is" --- doc/03-cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/03-cli.md b/doc/03-cli.md index 8f917c8c3..0ee6a140e 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -157,7 +157,7 @@ will always take precedence over the values specified in `composer.json`. ### COMPOSER -By setting the `COMPOSER` env variable is is possible to set the filename of +By setting the `COMPOSER` env variable it is possible to set the filename of `composer.json` to something else. For example: From 502048bfd8633e47b15ef790bee60bc0c10aaf37 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 18 Mar 2012 11:49:06 +0100 Subject: [PATCH 35/36] Fix schema nesting --- doc/04-schema.md | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/doc/04-schema.md b/doc/04-schema.md index 0cea8cf0a..07626a1d9 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -13,7 +13,9 @@ can also be used to validate your `composer.json`. In fact, it is used by the The root of the package definition is a JSON object. -## name +## Properties + +### name The name of the package. It consists of vendor name and project name, separated by `/`. @@ -25,13 +27,13 @@ Examples: Required for published packages (libraries). -## description +### description A short description of the package. Usually this is just one line long. Optional but recommended. -## version +### version The version of the package. @@ -52,7 +54,7 @@ Optional if the package repository can infer the version from somewhere, such as the VCS tag name in the VCS repository. In that case it is also recommended to omit it. -## type +### type The type of the package. It defaults to `library`. @@ -74,7 +76,7 @@ order to be able to install the bundle. Only use a custom type if you need custom logic during installation. It is recommended to omit this field and have it just default to `library`. -## keywords +### keywords An array of keywords that the package is related to. These can be used for searching and filtering. @@ -89,13 +91,13 @@ Examples: Optional. -## homepage +### homepage An URL to the website of the project. Optional. -## time +### time Release date of the version. @@ -103,7 +105,7 @@ Must be in `YYYY-MM-DD` or `YYYY-MM-DD HH:MM:SS` format. Optional. -## license +### license The license of the package. This can be either a string or an array of strings. @@ -122,7 +124,7 @@ The recommended notation for the most common licenses is: Optional, but it is highly recommended to supply this. -## authors +### authors The authors of the package. This is an array of objects. @@ -151,7 +153,7 @@ An example: Optional, but highly recommended. -## Link types +### Link types Each of these takes an object which maps package names to version constraints. @@ -179,7 +181,7 @@ Example: Optional. -## autoload +### autoload Autoload mapping for a PHP autoloader. @@ -211,7 +213,7 @@ Example: } } -## target-dir +### target-dir Defines the installation target. @@ -236,7 +238,7 @@ To do that, `autoload` and `target-dir` are defined as follows: Optional. -## repositories +### repositories Custom package repositories to use. @@ -302,7 +304,7 @@ will look from the first to the last repository, and pick the first match. By default Packagist is added last which means that custom repositories can override packages from it. -## config +### config A set of configuration options. It is only used for projects. @@ -324,7 +326,7 @@ Example: } } -## scripts +### scripts Composer allows you to hook into various parts of the installation process through the use of scripts. @@ -383,7 +385,7 @@ which gives you access to the `Composer\Composer` instance through the } } -## extra +### extra Arbitrary extra data for consumption by `scripts`. @@ -394,7 +396,7 @@ handler, you can do: Optional. -## bin +### bin A set of files that should be treated as binaries and symlinked into the `bin- dir` (from config). From 2249dd0548a611260aad6c51d0555fd75fca941a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sun, 18 Mar 2012 13:05:20 +0100 Subject: [PATCH 36/36] Fix tests when openssl is disabled --- .../Test/Repository/Vcs/GitHubDriverTest.php | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php index 48dfff6a8..2d0217006 100644 --- a/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php +++ b/tests/Composer/Test/Repository/Vcs/GitHubDriverTest.php @@ -23,8 +23,10 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase { public function testPrivateRepository() { + $scheme = extension_loaded('openssl') ? 'https' : 'http'; + $repoUrl = 'http://github.com/composer/packagist'; - $repoApiUrl = 'https://api.github.com/repos/composer/packagist'; + $repoApiUrl = $scheme.'://api.github.com/repos/composer/packagist'; $repoSshUrl = 'git@github.com:composer/packagist.git'; $identifier = 'v0.0.0'; $sha = 'SOMESHA'; @@ -70,7 +72,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase $dist = $gitHubDriver->getDist($identifier); $this->assertEquals('zip', $dist['type']); - $this->assertEquals('https://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); + $this->assertEquals($scheme.'://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); $this->assertEquals('v0.0.0', $dist['reference']); $source = $gitHubDriver->getSource($identifier); @@ -80,7 +82,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase $dist = $gitHubDriver->getDist($sha); $this->assertEquals('zip', $dist['type']); - $this->assertEquals('https://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); + $this->assertEquals($scheme.'://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); $this->assertEquals('v0.0.0', $dist['reference']); $source = $gitHubDriver->getSource($sha); @@ -91,8 +93,10 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase public function testPublicRepository() { + $scheme = extension_loaded('openssl') ? 'https' : 'http'; + $repoUrl = 'http://github.com/composer/packagist'; - $repoApiUrl = 'https://api.github.com/repos/composer/packagist'; + $repoApiUrl = $scheme.'://api.github.com/repos/composer/packagist'; $identifier = 'v0.0.0'; $sha = 'SOMESHA'; @@ -118,7 +122,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase $dist = $gitHubDriver->getDist($identifier); $this->assertEquals('zip', $dist['type']); - $this->assertEquals('https://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); + $this->assertEquals($scheme.'://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); $this->assertEquals($identifier, $dist['reference']); $source = $gitHubDriver->getSource($identifier); @@ -128,7 +132,7 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase $dist = $gitHubDriver->getDist($sha); $this->assertEquals('zip', $dist['type']); - $this->assertEquals('https://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); + $this->assertEquals($scheme.'://github.com/composer/packagist/zipball/v0.0.0', $dist['url']); $this->assertEquals($identifier, $dist['reference']); $source = $gitHubDriver->getSource($sha); @@ -139,8 +143,10 @@ class GitHubDriverTest extends \PHPUnit_Framework_TestCase public function testPrivateRepositoryNoInteraction() { + $scheme = extension_loaded('openssl') ? 'https' : 'http'; + $repoUrl = 'http://github.com/composer/packagist'; - $repoApiUrl = 'https://api.github.com/repos/composer/packagist'; + $repoApiUrl = $scheme.'://api.github.com/repos/composer/packagist'; $repoSshUrl = 'git@github.com:composer/packagist.git'; $identifier = 'v0.0.0'; $sha = 'SOMESHA';