1
0
Fork 0

Merge pull request #5454 from pierredup/type-search

Added type option to search
pull/5463/head
Jordi Boggiano 2016-06-21 17:03:13 +02:00 committed by GitHub
commit 894b53c115
7 changed files with 110 additions and 11 deletions

View File

@ -41,6 +41,7 @@ class SearchCommand extends BaseCommand
->setDescription('Search for packages') ->setDescription('Search for packages')
->setDefinition(array( ->setDefinition(array(
new InputOption('only-name', 'N', InputOption::VALUE_NONE, 'Search only in name'), 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'), new InputArgument('tokens', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'tokens to search for'),
)) ))
->setHelp(<<<EOT ->setHelp(<<<EOT
@ -68,9 +69,10 @@ EOT
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
$onlyName = $input->getOption('only-name'); $onlyName = $input->getOption('only-name');
$type = $input->getOption('type') ?: null;
$flags = $onlyName ? RepositoryInterface::SEARCH_NAME : RepositoryInterface::SEARCH_FULLTEXT; $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) { foreach ($results as $result) {
$io->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : '')); $io->write($result['name'] . (isset($result['description']) ? ' '. $result['description'] : ''));

View File

@ -89,7 +89,7 @@ class ArrayRepository extends BaseRepository
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function search($query, $mode = 0) public function search($query, $mode = 0, $type = null)
{ {
$regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i'; $regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i';
@ -102,9 +102,13 @@ class ArrayRepository extends BaseRepository
if (preg_match($regex, $name) if (preg_match($regex, $name)
|| ($mode === self::SEARCH_FULLTEXT && $package instanceof CompletePackageInterface && preg_match($regex, implode(' ', (array) $package->getKeywords()) . ' ' . $package->getDescription())) || ($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( $matches[$name] = array(
'name' => $package->getPrettyName(), 'name' => $package->getPrettyName(),
'description' => $package->getDescription(), 'description' => $package instanceof CompletePackageInterface ? $package->getDescription() : null,
); );
} }
} }

View File

@ -190,12 +190,12 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function search($query, $mode = 0) public function search($query, $mode = 0, $type = null)
{ {
$this->loadRootServerFile(); $this->loadRootServerFile();
if ($this->searchUrl && $mode === self::SEARCH_FULLTEXT) { 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; $hostname = parse_url($url, PHP_URL_HOST) ?: $url;
$json = $this->rfs->getContents($hostname, $url, false); $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; $hostname = parse_url($filename, PHP_URL_HOST) ?: $filename;
$rfs = $preFileDownloadEvent->getRemoteFilesystem(); $rfs = $preFileDownloadEvent->getRemoteFilesystem();
$json = $rfs->getContents($hostname, $filename, false); $json = $rfs->getContents($hostname, $filename, false);
if ($sha256 && $sha256 !== hash('sha256', $json)) { if ($sha256 && $sha256 !== hash('sha256', $json)) {
if ($retries) { if ($retries) {

View File

@ -97,12 +97,12 @@ class CompositeRepository extends BaseRepository
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function search($query, $mode = 0) public function search($query, $mode = 0, $type = null)
{ {
$matches = array(); $matches = array();
foreach ($this->repositories as $repository) { foreach ($this->repositories as $repository) {
/* @var $repository RepositoryInterface */ /* @var $repository RepositoryInterface */
$matches[] = $repository->search($query, $mode); $matches[] = $repository->search($query, $mode, $type);
} }
return $matches ? call_user_func_array('array_merge', $matches) : array(); return $matches ? call_user_func_array('array_merge', $matches) : array();

View File

@ -67,7 +67,9 @@ interface RepositoryInterface extends \Countable
* *
* @param string $query search query * @param string $query search query
* @param int $mode a set of SEARCH_* constants to search on, implementations should do a best effort only * @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 $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);
} }

View File

@ -13,6 +13,7 @@
namespace Composer\Test\Repository; namespace Composer\Test\Repository;
use Composer\Repository\ArrayRepository; use Composer\Repository\ArrayRepository;
use Composer\Repository\RepositoryInterface;
use Composer\TestCase; use Composer\TestCase;
class ArrayRepositoryTest extends 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', '1')));
$this->assertTrue($repo->hasPackage($this->getPackage('foo', '2'))); $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')
);
}
} }

View File

@ -13,6 +13,8 @@
namespace Composer\Test\Repository; namespace Composer\Test\Repository;
use Composer\IO\NullIO; use Composer\IO\NullIO;
use Composer\Repository\ComposerRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Test\Mock\FactoryMock; use Composer\Test\Mock\FactoryMock;
use Composer\TestCase; use Composer\TestCase;
use Composer\Package\Loader\ArrayLoader; 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-root']->getAliasOf());
$this->assertSame($packages['2'], $packages['2-alias']->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')
);
}
} }