From 6a557e45b8295007db61e786736f04018fe5fe90 Mon Sep 17 00:00:00 2001 From: Pierre du Plessis Date: Tue, 21 Jun 2016 16:38:52 +0200 Subject: [PATCH] Added --type option to search --- src/Composer/Command/SearchCommand.php | 4 +- src/Composer/Repository/ArrayRepository.php | 8 +++- .../Repository/ComposerRepository.php | 5 +- .../Repository/CompositeRepository.php | 4 +- .../Repository/RepositoryInterface.php | 10 ++-- .../Test/Repository/ArrayRepositoryTest.php | 47 +++++++++++++++++++ .../Repository/ComposerRepositoryTest.php | 43 +++++++++++++++++ 7 files changed, 110 insertions(+), 11 deletions(-) diff --git a/src/Composer/Command/SearchCommand.php b/src/Composer/Command/SearchCommand.php index 1b88af331..854574274 100644 --- a/src/Composer/Command/SearchCommand.php +++ b/src/Composer/Command/SearchCommand.php @@ -41,6 +41,7 @@ class SearchCommand extends BaseCommand ->setDescription('Search for packages') ->setDefinition(array( new InputOption('only-name', 'N', InputOption::VALUE_NONE, 'Search only in name'), + new InputOption('type', 't', InputOption::VALUE_REQUIRED, 'Search for a specific package type'), new InputArgument('tokens', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'tokens to search for'), )) ->setHelp(<<getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); $onlyName = $input->getOption('only-name'); + $type = $input->getOption('type') ?: null; $flags = $onlyName ? RepositoryInterface::SEARCH_NAME : RepositoryInterface::SEARCH_FULLTEXT; - $results = $repos->search(implode(' ', $input->getArgument('tokens')), $flags); + $results = $repos->search(implode(' ', $input->getArgument('tokens')), $flags, $type); foreach ($results as $result) { $io->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : '')); diff --git a/src/Composer/Repository/ArrayRepository.php b/src/Composer/Repository/ArrayRepository.php index 36eaabadc..4f0409a60 100644 --- a/src/Composer/Repository/ArrayRepository.php +++ b/src/Composer/Repository/ArrayRepository.php @@ -89,7 +89,7 @@ class ArrayRepository extends BaseRepository /** * {@inheritDoc} */ - public function search($query, $mode = 0) + public function search($query, $mode = 0, $type = null) { $regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i'; @@ -102,9 +102,13 @@ class ArrayRepository extends BaseRepository if (preg_match($regex, $name) || ($mode === self::SEARCH_FULLTEXT && $package instanceof CompletePackageInterface && preg_match($regex, implode(' ', (array) $package->getKeywords()) . ' ' . $package->getDescription())) ) { + if (null !== $type && $package->getType() !== $type) { + continue; + } + $matches[$name] = array( 'name' => $package->getPrettyName(), - 'description' => $package->getDescription(), + 'description' => $package instanceof CompletePackageInterface ? $package->getDescription() : null, ); } } diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index f2d10d943..ce2caa968 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -190,12 +190,12 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito /** * {@inheritDoc} */ - public function search($query, $mode = 0) + public function search($query, $mode = 0, $type = null) { $this->loadRootServerFile(); if ($this->searchUrl && $mode === self::SEARCH_FULLTEXT) { - $url = str_replace('%query%', $query, $this->searchUrl); + $url = str_replace(array('%query%', '%type%'), array($query, $type), $this->searchUrl); $hostname = parse_url($url, PHP_URL_HOST) ?: $url; $json = $this->rfs->getContents($hostname, $url, false); @@ -642,6 +642,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $hostname = parse_url($filename, PHP_URL_HOST) ?: $filename; $rfs = $preFileDownloadEvent->getRemoteFilesystem(); + $json = $rfs->getContents($hostname, $filename, false); if ($sha256 && $sha256 !== hash('sha256', $json)) { if ($retries) { diff --git a/src/Composer/Repository/CompositeRepository.php b/src/Composer/Repository/CompositeRepository.php index a9342a5d1..ce57504f0 100644 --- a/src/Composer/Repository/CompositeRepository.php +++ b/src/Composer/Repository/CompositeRepository.php @@ -97,12 +97,12 @@ class CompositeRepository extends BaseRepository /** * {@inheritdoc} */ - public function search($query, $mode = 0) + public function search($query, $mode = 0, $type = null) { $matches = array(); foreach ($this->repositories as $repository) { /* @var $repository RepositoryInterface */ - $matches[] = $repository->search($query, $mode); + $matches[] = $repository->search($query, $mode, $type); } return $matches ? call_user_func_array('array_merge', $matches) : array(); diff --git a/src/Composer/Repository/RepositoryInterface.php b/src/Composer/Repository/RepositoryInterface.php index 94e52af5f..f04b579f8 100644 --- a/src/Composer/Repository/RepositoryInterface.php +++ b/src/Composer/Repository/RepositoryInterface.php @@ -65,9 +65,11 @@ interface RepositoryInterface extends \Countable /** * Searches the repository for packages containing the query * - * @param string $query search query - * @param int $mode a set of SEARCH_* constants to search on, implementations should do a best effort only - * @return array[] an array of array('name' => '...', 'description' => '...') + * @param string $query search query + * @param int $mode a set of SEARCH_* constants to search on, implementations should do a best effort only + * @param string $type The type of package to search for. Defaults to all types of packages + * + * @return \array[] an array of array('name' => '...', 'description' => '...') */ - public function search($query, $mode = 0); + public function search($query, $mode = 0, $type = null); } diff --git a/tests/Composer/Test/Repository/ArrayRepositoryTest.php b/tests/Composer/Test/Repository/ArrayRepositoryTest.php index 434b3da99..c4c771d05 100644 --- a/tests/Composer/Test/Repository/ArrayRepositoryTest.php +++ b/tests/Composer/Test/Repository/ArrayRepositoryTest.php @@ -13,6 +13,7 @@ namespace Composer\Test\Repository; use Composer\Repository\ArrayRepository; +use Composer\Repository\RepositoryInterface; use Composer\TestCase; class ArrayRepositoryTest extends TestCase @@ -80,4 +81,50 @@ class ArrayRepositoryTest extends TestCase $this->assertTrue($repo->hasPackage($this->getPackage('foo', '1'))); $this->assertTrue($repo->hasPackage($this->getPackage('foo', '2'))); } + + public function testSearch() + { + $repo = new ArrayRepository(); + + $repo->addPackage($this->getPackage('foo', '1')); + $repo->addPackage($this->getPackage('bar', '1')); + + $this->assertSame( + array(array('name' => 'foo', 'description' => null)), + $repo->search('foo', RepositoryInterface::SEARCH_FULLTEXT) + ); + + $this->assertSame( + array(array('name' => 'bar', 'description' => null)), + $repo->search('bar') + ); + + $this->assertEmpty( + $repo->search('foobar') + ); + } + + public function testSearchWithPackageType() + { + $repo = new ArrayRepository(); + + $repo->addPackage($this->getPackage('foo', '1', 'Composer\Package\CompletePackage')); + $repo->addPackage($this->getPackage('bar', '1', 'Composer\Package\CompletePackage')); + + $package = $this->getPackage('foobar', '1', 'Composer\Package\CompletePackage'); + $package->setType('composer-plugin'); + $repo->addPackage($package); + + $this->assertSame( + array(array('name' => 'foo', 'description' => null)), + $repo->search('foo', RepositoryInterface::SEARCH_FULLTEXT, 'library') + ); + + $this->assertEmpty($repo->search('bar', RepositoryInterface::SEARCH_FULLTEXT, 'package')); + + $this->assertSame( + array(array('name' => 'foobar', 'description' => null)), + $repo->search('foo', 0, 'composer-plugin') + ); + } } diff --git a/tests/Composer/Test/Repository/ComposerRepositoryTest.php b/tests/Composer/Test/Repository/ComposerRepositoryTest.php index 115069441..11adf3d6e 100644 --- a/tests/Composer/Test/Repository/ComposerRepositoryTest.php +++ b/tests/Composer/Test/Repository/ComposerRepositoryTest.php @@ -13,6 +13,8 @@ namespace Composer\Test\Repository; use Composer\IO\NullIO; +use Composer\Repository\ComposerRepository; +use Composer\Repository\RepositoryInterface; use Composer\Test\Mock\FactoryMock; use Composer\TestCase; use Composer\Package\Loader\ArrayLoader; @@ -165,4 +167,45 @@ class ComposerRepositoryTest extends TestCase $this->assertSame($packages['2'], $packages['2-root']->getAliasOf()); $this->assertSame($packages['2'], $packages['2-alias']->getAliasOf()); } + + public function testSearchWithType() + { + $repoConfig = array( + 'url' => 'http://example.org', + ); + + $result = array( + 'results' => array( + array( + 'name' => 'foo', + 'description' => null + ) + ) + ); + + $rfs = $this->getMockBuilder('Composer\Util\RemoteFilesystem') + ->disableOriginalConstructor() + ->getMock(); + + $rfs->expects($this->at(0)) + ->method('getContents') + ->with('example.org', 'http://example.org/packages.json', false) + ->willReturn(json_encode(array('search' => '/search.json?q=%query%&type=%type%'))); + + $rfs->expects($this->at(1)) + ->method('getContents') + ->with('example.org', 'http://example.org/search.json?q=foo&type=composer-plugin', false) + ->willReturn(json_encode($result)); + + $repository = new ComposerRepository($repoConfig, new NullIO, FactoryMock::createConfig(), null, $rfs); + + $this->assertSame( + array(array('name' => 'foo', 'description' => null)), + $repository->search('foo', RepositoryInterface::SEARCH_FULLTEXT, 'composer-plugin') + ); + + $this->assertEmpty( + $repository->search('foo', RepositoryInterface::SEARCH_FULLTEXT, 'library') + ); + } }