commit
894b53c115
|
@ -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'] : ''));
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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')
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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')
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue