diff --git a/CHANGELOG.md b/CHANGELOG.md
index 756e4524..67570f4e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,10 +2,14 @@
## [Unreleased] - TBA
### Added
-
+- Added CLI argument `composer-json` which can be used to parse external projects.
+ This will default to the current working directory.
### Changed
-
+- Change `bin/composer-unused` to be used as standalone binary
+- Package type is now `library` instead of `composer-plugin`
### Removed
+- Removed ability to work as `composer-plugin` (will be supported using `composer-unused/composer-unused-plugin`)
+- Dropped support for php `7.3`
## [0.7.7] - 2021-07-26
### Added
diff --git a/Makefile b/Makefile
index 7317ad50..63591f8b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-PHP_VERSION=8.0
+PHP_VERSION=7.4
up: ## Run all containers in all versions
docker compose up -d
@@ -39,7 +39,7 @@ box: ## Compile /build/composer-unused.phar
docker compose run php$(PHP_VERSION) php box.phar compile
ssh: ## SSH into container
- docker compose run $(PHP_VERSION) /bin/sh
+ docker compose run php$(PHP_VERSION) /bin/sh
help: ## Displays this list of targets with descriptions
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}'
diff --git a/bin/composer-unused b/bin/composer-unused
index 581f043e..3ad7071a 100755
--- a/bin/composer-unused
+++ b/bin/composer-unused
@@ -2,10 +2,9 @@
register(IOInterface::class, $application->getIO());
- $container->register(Composer::class, $application->getComposer());
-
$application->add($container->get(UnusedCommand::class));
-
- // Add 'unused' command if necessary
- if (!isset($argv[1]) || $argv[1] !== 'unused') {
- $argv = array_merge([$argv[0], 'unused'], array_slice($argv, 1));
- }
+ $application->setDefaultCommand('unused', true);
$application->run(new ArgvInput($argv));
})($argv);
diff --git a/composer.json b/composer.json
index ae99529e..129b554e 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"name": "icanhazstring/composer-unused",
- "type": "composer-plugin",
+ "type": "library",
"description": "Show unused packages by scanning your code",
"keywords": [
"composer",
@@ -17,17 +17,18 @@
}
],
"require": {
- "php": "^7.3 || ^8.0",
- "composer-plugin-api": "^2.0",
- "composer-unused/symbol-parser": "^0.1.3",
+ "php": "^7.4 || ^8.0",
+ "composer-unused/contracts": "dev-main",
+ "composer-unused/symbol-parser": "dev-main",
"nikic/php-parser": "^4.13",
"psr/container": "^1.0 || ^2.0",
- "psr/log": "^1.1 || ^2 || ^3"
+ "psr/log": "^1.1 || ^2 || ^3",
+ "symfony/console": "^4.4 || ^5.4 || ^6.0",
+ "symfony/serializer": "^4.4 || ^5.4 || ^6.0"
},
"require-dev": {
"ext-ds": "*",
"ext-zend-opcache": "*",
- "composer/composer": "^2.2.3",
"jangregor/phpstan-prophecy": "^0.8.1",
"phpspec/prophecy-phpunit": "^2.0.1",
"phpstan/phpstan": "^0.12.99",
@@ -39,9 +40,6 @@
"preferred-install": "dist",
"sort-packages": true
},
- "extra": {
- "class": "Icanhazstring\\Composer\\Unused\\UnusedPlugin"
- },
"autoload": {
"psr-4": {
"Icanhazstring\\Composer\\Unused\\": "src"
diff --git a/config/service_manager.php b/config/service_manager.php
index 5886b570..b01d3e65 100644
--- a/config/service_manager.php
+++ b/config/service_manager.php
@@ -8,6 +8,7 @@
use Icanhazstring\Composer\Unused\Command\Handler\Factory\CollectConsumedSymbolsCommandHandlerFactory;
use Icanhazstring\Composer\Unused\Command\Handler\Factory\CollectFilteredDependenciesCommandHandlerFactory;
use Icanhazstring\Composer\Unused\Command\Handler\Factory\CollectRequiredDependenciesCommandHandlerFactory;
+use Icanhazstring\Composer\Unused\Composer\ConfigFactory;
use Icanhazstring\Composer\Unused\Console\Command\UnusedCommand;
use Icanhazstring\Composer\Unused\Console\Command\UnusedCommandFactory;
use Icanhazstring\Composer\Unused\Di\InvokableFactory;
@@ -24,5 +25,6 @@
ConsumedSymbolLoaderBuilder::class => InvokableFactory::class,
ProvidedSymbolLoaderBuilder::class => InvokableFactory::class,
PackageResolver::class => InvokableFactory::class,
+ ConfigFactory::class => InvokableFactory::class,
]
];
diff --git a/docker-compose.yml b/docker-compose.yml
index 1ac34105..2ef84c5c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,6 +6,8 @@ services:
container_name: composer-unused-7.4
volumes:
- .:/docker/composer-unused:rw
+ - ../contracts:/docker/contracts:rw
+ - ../symbol-parser:/docker/symbol-parser:rw
tty: true
php8.0:
diff --git a/phpstan.neon b/phpstan.neon
index bce0f27d..ac12398b 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -9,6 +9,7 @@ parameters:
level: max
inferPrivatePropertyTypeFromConstructor: true
paths:
+ - bin/
- src/
- tests/
tmpDir: data
diff --git a/src/Command/CollectConsumedSymbolsCommand.php b/src/Command/CollectConsumedSymbolsCommand.php
index c68f1e98..dc06da84 100644
--- a/src/Command/CollectConsumedSymbolsCommand.php
+++ b/src/Command/CollectConsumedSymbolsCommand.php
@@ -4,7 +4,7 @@
namespace Icanhazstring\Composer\Unused\Command;
-use Composer\Package\PackageInterface;
+use ComposerUnused\Contracts\PackageInterface;
final class CollectConsumedSymbolsCommand
{
diff --git a/src/Command/Handler/CollectConsumedSymbolsCommandHandler.php b/src/Command/Handler/CollectConsumedSymbolsCommandHandler.php
index d2bc0543..7229b717 100644
--- a/src/Command/Handler/CollectConsumedSymbolsCommandHandler.php
+++ b/src/Command/Handler/CollectConsumedSymbolsCommandHandler.php
@@ -29,7 +29,7 @@ public function __construct(ConsumedSymbolLoaderBuilder $consumedSymbolLoaderBui
public function collect(CollectConsumedSymbolsCommand $command): Generator
{
$package = $command->getPackage();
- $symbolLoader = $this->consumedSymbolLoaderBuilder->build($command->getPackageRoot());
+ $symbolLoader = $this->consumedSymbolLoaderBuilder->build();
$rootNamespaces = array_merge(
array_keys($package->getAutoload()['psr-0'] ?? []),
@@ -38,7 +38,7 @@ public function collect(CollectConsumedSymbolsCommand $command): Generator
yield from $this->filterRootPackageSymbols(
$rootNamespaces,
- $symbolLoader->load($package)
+ $symbolLoader->withBaseDir($command->getPackageRoot())->load($package)
);
}
diff --git a/src/Command/Handler/CollectFilteredDependenciesCommandHandler.php b/src/Command/Handler/CollectFilteredDependenciesCommandHandler.php
index 147c79b4..b5b3ac91 100644
--- a/src/Command/Handler/CollectFilteredDependenciesCommandHandler.php
+++ b/src/Command/Handler/CollectFilteredDependenciesCommandHandler.php
@@ -6,6 +6,7 @@
use Icanhazstring\Composer\Unused\Command\FilterDependencyCollectionCommand;
use Icanhazstring\Composer\Unused\Dependency\DependencyCollection;
+use Icanhazstring\Composer\Unused\Dependency\DependencyInterface;
final class CollectFilteredDependenciesCommandHandler
{
@@ -14,11 +15,11 @@ public function collect(FilterDependencyCollectionCommand $command): DependencyC
$namedExclusion = $command->getNamedExclusion();
$patternExclusion = $command->getPatternExclusion();
- return $command->getRequiredDependencyCollection()->filter(static function ($dependency) use (
+ return $command->getRequiredDependencyCollection()->filter(static function (DependencyInterface $dependency) use (
$namedExclusion,
$patternExclusion
) {
- if (in_array($dependency->getName(), $namedExclusion)) {
+ if (in_array($dependency->getName(), $namedExclusion, true)) {
return false;
}
diff --git a/src/Command/Handler/CollectRequiredDependenciesCommandHandler.php b/src/Command/Handler/CollectRequiredDependenciesCommandHandler.php
index bbc3e8e8..083686c7 100644
--- a/src/Command/Handler/CollectRequiredDependenciesCommandHandler.php
+++ b/src/Command/Handler/CollectRequiredDependenciesCommandHandler.php
@@ -30,7 +30,7 @@ public function __construct(
public function collect(LoadRequiredDependenciesCommand $command): DependencyCollection
{
$dependencyCollection = new DependencyCollection();
- $providedSymbolLoader = $this->providedSymbolLoaderBuilder->build($command->getBaseDir());
+ $providedSymbolLoader = $this->providedSymbolLoaderBuilder->build();
foreach ($command->getPackageLinks() as $require) {
$composerPackage = $this->packageResolver->resolve(
@@ -39,15 +39,22 @@ public function collect(LoadRequiredDependenciesCommand $command): DependencyCol
);
if ($composerPackage === null) {
- $dependencyCollection->add(new InvalidDependency($require, 'Unable to locate package'));
+ $dependencyCollection->add(
+ new InvalidDependency(
+ $require,
+ 'Dependency can\'t be located. Maybe not installed?'
+ )
+ );
continue;
}
+ $packageBaseDir = $command->getBaseDir() . DIRECTORY_SEPARATOR . $composerPackage->getName();
+
$dependencyCollection->add(
new RequiredDependency(
$composerPackage,
(new SymbolList())->addAll(
- $providedSymbolLoader->load($composerPackage)
+ $providedSymbolLoader->withBaseDir($packageBaseDir)->load($composerPackage)
)
)
);
diff --git a/src/Command/LoadRequiredDependenciesCommand.php b/src/Command/LoadRequiredDependenciesCommand.php
index 06859cd1..9cb53b37 100644
--- a/src/Command/LoadRequiredDependenciesCommand.php
+++ b/src/Command/LoadRequiredDependenciesCommand.php
@@ -4,20 +4,20 @@
namespace Icanhazstring\Composer\Unused\Command;
-use Composer\Package\Link;
-use Composer\Repository\RepositoryInterface;
+use ComposerUnused\Contracts\LinkInterface;
+use ComposerUnused\Contracts\RepositoryInterface;
final class LoadRequiredDependenciesCommand
{
/** @var string */
private $baseDir;
- /** @var array */
+ /** @var array */
private $packageLinks;
/** @var RepositoryInterface */
private $packageRepository;
/**
- * @param array $packageLinks
+ * @param array $packageLinks
*/
public function __construct(string $baseDir, array $packageLinks, RepositoryInterface $packageRepository)
{
@@ -32,7 +32,7 @@ public function getBaseDir(): string
}
/**
- * @return array
+ * @return array
*/
public function getPackageLinks(): array
{
diff --git a/src/Composer/Config.php b/src/Composer/Config.php
new file mode 100644
index 00000000..e345a3f1
--- /dev/null
+++ b/src/Composer/Config.php
@@ -0,0 +1,58 @@
+ */
+ protected array $config = [];
+ protected string $name;
+ /** @var array */
+ private array $require = [];
+ /** @var array */
+ private array $autoload = [];
+ /** @var array */
+ private array $suggests = [];
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ /**
+ * @return array
+ */
+ public function getRequire(): array
+ {
+ return $this->require;
+ }
+
+ /**
+ * @return array
+ */
+ public function getAutoload(): array
+ {
+ return $this->autoload;
+ }
+
+ /**
+ * @return array
+ */
+ public function getSuggests(): array
+ {
+ return $this->suggests;
+ }
+
+ public function get(string $property): string
+ {
+ $value = $this->config[$property] ?? null;
+
+ if ($property === 'vendor-dir') {
+ $value = $value ?? 'vendor';
+ }
+
+ return $value;
+ }
+}
diff --git a/src/Composer/ConfigFactory.php b/src/Composer/ConfigFactory.php
new file mode 100644
index 00000000..73dbcda6
--- /dev/null
+++ b/src/Composer/ConfigFactory.php
@@ -0,0 +1,29 @@
+serializer = new Serializer($normalizers, $encoders);
+ }
+
+ public function fromComposerJson(string $jsonContent): Config
+ {
+ return $this->serializer->deserialize($jsonContent, Config::class, 'json');
+ }
+}
diff --git a/src/Composer/Link.php b/src/Composer/Link.php
new file mode 100644
index 00000000..873305c4
--- /dev/null
+++ b/src/Composer/Link.php
@@ -0,0 +1,22 @@
+target = $target;
+ }
+
+ public function getTarget(): string
+ {
+ return $this->target;
+ }
+}
diff --git a/src/Composer/LocalRepository.php b/src/Composer/LocalRepository.php
new file mode 100644
index 00000000..0f540f26
--- /dev/null
+++ b/src/Composer/LocalRepository.php
@@ -0,0 +1,46 @@
+vendorDir = $vendorDir;
+ $encoders = [new JsonEncoder()];
+ $normalizers = [new PropertyNormalizer(null, new CamelCaseToSnakeCaseNameConverter())];
+
+ $this->serializer = new Serializer($normalizers, $encoders);
+ }
+
+ public function findPackage(string $name): ?PackageInterface
+ {
+ $packageDir = $this->vendorDir . DIRECTORY_SEPARATOR . $name;
+ $packageComposerJson = $packageDir . DIRECTORY_SEPARATOR . 'composer.json';
+
+ if (!is_dir($packageDir) && !file_exists($packageComposerJson)) {
+ return null;
+ }
+
+ $jsonContent = file_get_contents($packageComposerJson);
+
+ if ($jsonContent === false) {
+ return null;
+ }
+
+ $config = $this->serializer->deserialize($jsonContent, Config::class, 'json');
+ return Package::fromConfig($config);
+ }
+}
diff --git a/src/Composer/Package.php b/src/Composer/Package.php
new file mode 100644
index 00000000..f085de48
--- /dev/null
+++ b/src/Composer/Package.php
@@ -0,0 +1,72 @@
+ */
+ private array $requires = [];
+ /** @var array */
+ private array $suggests = [];
+ /** @phpstan-var array{psr-0?: array, psr-4?: array, classmap?: list, files?: list} */
+ private array $autoload = [];
+
+ public static function fromConfig(Config $config): self
+ {
+ $package = new self($config->getName());
+ $package->autoload = $config->getAutoload();
+ $package->requires = array_map(static function (string $name) {
+ return new Link($name);
+ }, array_keys($config->getRequire()));
+ $package->suggests = array_keys($config->getSuggests());
+
+ return $package;
+ }
+
+ public function __construct(string $name)
+ {
+ $this->name = $name;
+ }
+
+ public function getAutoload(): array
+ {
+ return $this->autoload;
+ }
+
+ public function getName(): string
+ {
+ return $this->name;
+ }
+
+ public function getRequires(): array
+ {
+ return $this->requires;
+ }
+
+ public function getSuggests(): array
+ {
+ return $this->suggests;
+ }
+
+ /**
+ * @param array $requires
+ */
+ public function setRequires(array $requires): void
+ {
+ $this->requires = $requires;
+ }
+
+ /**
+ * @param array $suggests
+ */
+ public function setSuggests(array $suggests): void
+ {
+ $this->suggests = $suggests;
+ }
+}
diff --git a/src/Console/Command/UnusedCommand.php b/src/Console/Command/UnusedCommand.php
index 510876c2..9b662081 100644
--- a/src/Console/Command/UnusedCommand.php
+++ b/src/Console/Command/UnusedCommand.php
@@ -4,17 +4,21 @@
namespace Icanhazstring\Composer\Unused\Console\Command;
-use Composer\Command\BaseCommand;
use Icanhazstring\Composer\Unused\Command\CollectConsumedSymbolsCommand;
use Icanhazstring\Composer\Unused\Command\FilterDependencyCollectionCommand;
use Icanhazstring\Composer\Unused\Command\Handler\CollectConsumedSymbolsCommandHandler;
use Icanhazstring\Composer\Unused\Command\Handler\CollectFilteredDependenciesCommandHandler;
use Icanhazstring\Composer\Unused\Command\Handler\CollectRequiredDependenciesCommandHandler;
use Icanhazstring\Composer\Unused\Command\LoadRequiredDependenciesCommand;
+use Icanhazstring\Composer\Unused\Composer\ConfigFactory;
+use Icanhazstring\Composer\Unused\Composer\LocalRepository;
+use Icanhazstring\Composer\Unused\Composer\Package;
use Icanhazstring\Composer\Unused\Dependency\DependencyCollection;
use Icanhazstring\Composer\Unused\Dependency\DependencyInterface;
use Icanhazstring\Composer\Unused\Dependency\InvalidDependency;
use Icanhazstring\Composer\Unused\Dependency\RequiredDependency;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -24,7 +28,7 @@
use const DIRECTORY_SEPARATOR;
-final class UnusedCommand extends BaseCommand
+final class UnusedCommand extends Command
{
/** @var CollectConsumedSymbolsCommandHandler */
private $collectConsumedSymbolsCommandHandler;
@@ -32,13 +36,16 @@ final class UnusedCommand extends BaseCommand
private $collectRequiredDependenciesCommandHandler;
/** @var CollectFilteredDependenciesCommandHandler */
private $collectFilteredDependenciesCommandHandler;
+ private ConfigFactory $configFactory;
public function __construct(
+ ConfigFactory $configFactory,
CollectConsumedSymbolsCommandHandler $collectConsumedSymbolsCommandHandler,
CollectRequiredDependenciesCommandHandler $collectRequiredDependenciesCommandHandler,
CollectFilteredDependenciesCommandHandler $collectFilteredDependenciesCommandHandler
) {
parent::__construct('unused');
+ $this->configFactory = $configFactory;
$this->collectConsumedSymbolsCommandHandler = $collectConsumedSymbolsCommandHandler;
$this->collectRequiredDependenciesCommandHandler = $collectRequiredDependenciesCommandHandler;
$this->collectFilteredDependenciesCommandHandler = $collectFilteredDependenciesCommandHandler;
@@ -50,6 +57,13 @@ protected function configure(): void
'Show unused packages by scanning and comparing package namespaces against your source.'
);
+ $this->addArgument(
+ 'composer-json',
+ InputArgument::OPTIONAL,
+ 'Provide a composer.json to be scanned',
+ getcwd() . DIRECTORY_SEPARATOR . 'composer.json'
+ );
+
$this->addOption(
'excludeDir',
null,
@@ -83,15 +97,23 @@ protected function configure(): void
protected function execute(InputInterface $input, OutputInterface $output): int
{
- $composer = $this->getComposer();
+ $composerJsonPath = $input->getArgument('composer-json');
- if ($composer === null) {
- // TODO IO Error
+ if (!file_exists($composerJsonPath) && !is_readable($composerJsonPath)) {
return 1;
}
- $baseDir = dirname($composer->getConfig()->getConfigSource()->getName());
- $rootPackage = $composer->getPackage();
+ $composerJson = file_get_contents($composerJsonPath);
+
+ if ($composerJson === false) {
+ return 1;
+ }
+
+ $config = $this->configFactory->fromComposerJson($composerJson);
+ $baseDir = dirname($composerJsonPath);
+
+ $rootPackage = Package::fromConfig($config);
+ $localRepository = new LocalRepository($baseDir . DIRECTORY_SEPARATOR . $config->get('vendor-dir'));
$consumedSymbols = $this->collectConsumedSymbolsCommandHandler->collect(
new CollectConsumedSymbolsCommand(
@@ -102,9 +124,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$unfilteredRequiredDependencyCollection = $this->collectRequiredDependenciesCommandHandler->collect(
new LoadRequiredDependenciesCommand(
- $baseDir . DIRECTORY_SEPARATOR . $composer->getConfig()->get('vendor-dir'),
+ $baseDir . DIRECTORY_SEPARATOR . $config->get('vendor-dir'),
$rootPackage->getRequires(),
- $composer->getRepositoryManager()->getLocalRepository()
+ $localRepository
)
);
diff --git a/src/Console/Command/UnusedCommandFactory.php b/src/Console/Command/UnusedCommandFactory.php
index 8bb56122..be341e09 100644
--- a/src/Console/Command/UnusedCommandFactory.php
+++ b/src/Console/Command/UnusedCommandFactory.php
@@ -7,6 +7,7 @@
use Icanhazstring\Composer\Unused\Command\Handler\CollectConsumedSymbolsCommandHandler;
use Icanhazstring\Composer\Unused\Command\Handler\CollectFilteredDependenciesCommandHandler;
use Icanhazstring\Composer\Unused\Command\Handler\CollectRequiredDependenciesCommandHandler;
+use Icanhazstring\Composer\Unused\Composer\ConfigFactory;
use Psr\Container\ContainerInterface;
final class UnusedCommandFactory
@@ -14,6 +15,7 @@ final class UnusedCommandFactory
public function __invoke(ContainerInterface $container): UnusedCommand
{
return new UnusedCommand(
+ $container->get(ConfigFactory::class),
$container->get(CollectConsumedSymbolsCommandHandler::class),
$container->get(CollectRequiredDependenciesCommandHandler::class),
$container->get(CollectFilteredDependenciesCommandHandler::class),
diff --git a/src/Dependency/InvalidDependency.php b/src/Dependency/InvalidDependency.php
index 0e97ea45..e648fb6d 100644
--- a/src/Dependency/InvalidDependency.php
+++ b/src/Dependency/InvalidDependency.php
@@ -4,17 +4,17 @@
namespace Icanhazstring\Composer\Unused\Dependency;
-use Composer\Package\Link;
+use ComposerUnused\Contracts\LinkInterface;
use ComposerUnused\SymbolParser\Symbol\SymbolInterface;
final class InvalidDependency implements DependencyInterface
{
- /** @var Link */
+ /** @var LinkInterface */
private $linkedPackage;
/** @var string */
private $reason;
- public function __construct(Link $linkedPackage, string $reason)
+ public function __construct(LinkInterface $linkedPackage, string $reason)
{
$this->linkedPackage = $linkedPackage;
$this->reason = $reason;
diff --git a/src/Dependency/RequiredDependency.php b/src/Dependency/RequiredDependency.php
index 88ad8e56..5e1a1f4c 100644
--- a/src/Dependency/RequiredDependency.php
+++ b/src/Dependency/RequiredDependency.php
@@ -4,7 +4,7 @@
namespace Icanhazstring\Composer\Unused\Dependency;
-use Composer\Package\PackageInterface;
+use ComposerUnused\Contracts\PackageInterface;
use ComposerUnused\SymbolParser\Symbol\SymbolInterface;
use ComposerUnused\SymbolParser\Symbol\SymbolListInterface;
@@ -62,7 +62,7 @@ public function requires(DependencyInterface $dependency): bool
public function suggests(DependencyInterface $dependency): bool
{
- return array_key_exists($dependency->getName(), $this->package->getSuggests());
+ return in_array($dependency->getName(), $this->package->getSuggests(), true);
}
public function requiredBy(DependencyInterface $dependency): void
diff --git a/src/PackageResolver.php b/src/PackageResolver.php
index fc48c28f..c4f16c34 100644
--- a/src/PackageResolver.php
+++ b/src/PackageResolver.php
@@ -4,28 +4,24 @@
namespace Icanhazstring\Composer\Unused;
-use Composer\Package\Link;
-use Composer\Package\Package;
-use Composer\Package\PackageInterface;
-use Composer\Repository\RepositoryInterface;
+use ComposerUnused\Contracts\LinkInterface;
+use ComposerUnused\Contracts\PackageInterface;
+use ComposerUnused\Contracts\RepositoryInterface;
+use Icanhazstring\Composer\Unused\Composer\Package;
final class PackageResolver
{
public function resolve(
- Link $package,
+ LinkInterface $packageLink,
RepositoryInterface $repository
): ?PackageInterface {
- $isPhp = strpos($package->getTarget(), 'php') === 0;
- $isExtension = strpos($package->getTarget(), 'ext-') === 0;
+ $isPhp = strpos($packageLink->getTarget(), 'php') === 0;
+ $isExtension = strpos($packageLink->getTarget(), 'ext-') === 0;
if ($isPhp || $isExtension) {
- return new Package(
- strtolower($package->getTarget()),
- '*',
- '*'
- );
+ return new Package(strtolower($packageLink->getTarget()));
}
- return $repository->findPackage($package->getTarget(), $package->getConstraint());
+ return $repository->findPackage($packageLink->getTarget());
}
}
diff --git a/src/Symbol/ConsumedSymbolLoaderBuilder.php b/src/Symbol/ConsumedSymbolLoaderBuilder.php
index 09d96e55..3acccb9b 100644
--- a/src/Symbol/ConsumedSymbolLoaderBuilder.php
+++ b/src/Symbol/ConsumedSymbolLoaderBuilder.php
@@ -5,6 +5,7 @@
namespace Icanhazstring\Composer\Unused\Symbol;
use ComposerUnused\SymbolParser\File\FileContentProvider;
+use ComposerUnused\SymbolParser\Parser\PHP\AutoloadType;
use ComposerUnused\SymbolParser\Parser\PHP\ConsumedSymbolCollector;
use ComposerUnused\SymbolParser\Parser\PHP\Strategy\ClassConstStrategy;
use ComposerUnused\SymbolParser\Parser\PHP\Strategy\NewStrategy;
@@ -22,7 +23,7 @@
final class ConsumedSymbolLoaderBuilder
{
- public function build(string $packageRoot): SymbolLoaderInterface
+ public function build(): SymbolLoaderInterface
{
$usedSymbolCollector = new ConsumedSymbolCollector(
[
@@ -49,9 +50,8 @@ public function build(string $packageRoot): SymbolLoaderInterface
);
return new FileSymbolLoader(
- $packageRoot,
$fileSymbolProvider,
- ['classmap', 'files', 'psr-0', 'psr-4']
+ AutoloadType::all()
);
}
}
diff --git a/src/Symbol/ProvidedSymbolLoaderBuilder.php b/src/Symbol/ProvidedSymbolLoaderBuilder.php
index 4e647864..b3efa6ef 100644
--- a/src/Symbol/ProvidedSymbolLoaderBuilder.php
+++ b/src/Symbol/ProvidedSymbolLoaderBuilder.php
@@ -5,6 +5,7 @@
namespace Icanhazstring\Composer\Unused\Symbol;
use ComposerUnused\SymbolParser\File\FileContentProvider;
+use ComposerUnused\SymbolParser\Parser\PHP\AutoloadType;
use ComposerUnused\SymbolParser\Parser\PHP\DefinedSymbolCollector;
use ComposerUnused\SymbolParser\Parser\PHP\SymbolNameParser;
use ComposerUnused\SymbolParser\Symbol\Loader\CompositeSymbolLoader;
@@ -17,7 +18,7 @@
final class ProvidedSymbolLoaderBuilder
{
- public function build(string $packageRoot): SymbolLoaderInterface
+ public function build(): SymbolLoaderInterface
{
$symbolNameParser = new SymbolNameParser(
(new ParserFactory())->create(ParserFactory::ONLY_PHP7),
@@ -33,7 +34,7 @@ public function build(string $packageRoot): SymbolLoaderInterface
[
new ExtensionSymbolLoader(),
new PsrSymbolLoader(),
- new FileSymbolLoader($packageRoot, $fileSymbolProvider, ['classmap', 'files'])
+ new FileSymbolLoader($fileSymbolProvider, [AutoloadType::CLASSMAP, AutoloadType::FILES])
]
);
}
diff --git a/src/UnusedPlugin.php b/src/UnusedPlugin.php
deleted file mode 100644
index 41d65487..00000000
--- a/src/UnusedPlugin.php
+++ /dev/null
@@ -1,68 +0,0 @@
-container = $plugin->container;
- }
- }
-
- public function activate(Composer $composer, IOInterface $io): void
- {
- $this->container = require __DIR__ . '/../config/container.php';
-
- $this->container->register(IOInterface::class, $io);
- $this->container->register(Composer::class, $composer);
- }
-
- public function deactivate(Composer $composer, IOInterface $io): void
- {
- }
-
- public function uninstall(Composer $composer, IOInterface $io): void
- {
- }
-
- public function getCapabilities(): array
- {
- return [
- Plugin\Capability\CommandProvider::class => self::class
- ];
- }
-
- /**
- * @return array|BaseCommand[]
- * @throws Exception
- */
- public function getCommands(): array
- {
- return [
- $this->container->get(UnusedCommand::class)
- ];
- }
-}
diff --git a/tests/Integration/Di/ServiceContainerTest.php b/tests/Integration/Di/ServiceContainerTest.php
index 644b425e..d6d8a768 100644
--- a/tests/Integration/Di/ServiceContainerTest.php
+++ b/tests/Integration/Di/ServiceContainerTest.php
@@ -4,10 +4,6 @@
namespace Icanhazstring\Composer\Test\Unused\Integration\Di;
-use Composer\Composer;
-use Composer\IO\IOInterface;
-use Composer\Repository\RepositoryManager;
-use Composer\Repository\WritableRepositoryInterface;
use Icanhazstring\Composer\Unused\Di\ServiceContainer;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
@@ -25,13 +21,6 @@ public function itShouldLoadServiceContainer(): void
{
/** @var ServiceContainer $container */
$container = require __DIR__ . '/../../../config/container.php';
- $container->register(IOInterface::class, $this->prophesize(IOInterface::class)->reveal());
- $repositoryManager = $this->prophesize(RepositoryManager::class);
- $repositoryManager->getLocalRepository()->willReturn($this->prophesize(WritableRepositoryInterface::class)->reveal());
- $composer = $this->prophesize(Composer::class);
- $composer->getRepositoryManager()->willReturn($repositoryManager->reveal());
- $container->register(Composer::class, $composer->reveal());
-
$services = require __DIR__ . '/../../../config/service_manager.php';
foreach ($services['factories'] as $type => $factory) {
diff --git a/tests/Integration/UnusedCommandTest.php b/tests/Integration/UnusedCommandTest.php
index d987b28b..7a7047bc 100644
--- a/tests/Integration/UnusedCommandTest.php
+++ b/tests/Integration/UnusedCommandTest.php
@@ -4,15 +4,10 @@
namespace Icanhazstring\Composer\Test\Unused\Integration;
-use Composer\Composer;
-use Composer\Console\Application;
-use Composer\IO\IOInterface;
use Icanhazstring\Composer\Unused\Console\Command\UnusedCommand;
use Icanhazstring\Composer\Unused\Di\ServiceContainer;
use PHPUnit\Framework\TestCase;
-use Symfony\Component\Console\Input\ArrayInput;
-use Symfony\Component\Console\Output\BufferedOutput;
-use Symfony\Component\Console\Output\NullOutput;
+use Symfony\Component\Console\Tester\CommandTester;
class UnusedCommandTest extends TestCase
{
@@ -24,36 +19,17 @@ protected function setUp(): void
$this->container = require __DIR__ . '/../../config/container.php';
}
- private function getApplication(): Application
- {
- $application = new Application();
- $application->setAutoExit(false);
-
- $io = $application->getIO();
- /** @var Composer $composer */
- $composer = $application->getComposer();
-
- $this->container->register(IOInterface::class, $io);
- $this->container->register(Composer::class, $composer);
- $application->add($this->container->get(UnusedCommand::class));
-
- return $application;
- }
-
/**
* @test
*/
public function itShouldHaveZeroExitCodeOnEmptyRequirements(): void
{
chdir(__DIR__ . '/../assets/TestProjects/EmptyRequire');
+ $commandTester = new CommandTester($this->container->get(UnusedCommand::class));
+
+ $exitCode = $commandTester->execute([]);
- self::assertEquals(
- 0,
- $this->getApplication()->run(
- new ArrayInput(['unused']),
- new NullOutput()
- )
- );
+ self::assertSame(0, $exitCode);
}
/**
@@ -62,14 +38,11 @@ public function itShouldHaveZeroExitCodeOnEmptyRequirements(): void
public function itShouldNotReportPHPAsUnused(): void
{
chdir(__DIR__ . '/../assets/TestProjects/OnlyLanguageRequirement');
+ $commandTester = new CommandTester($this->container->get(UnusedCommand::class));
- self::assertEquals(
- 0,
- $this->getApplication()->run(
- new ArrayInput(['unused']),
- new NullOutput()
- )
- );
+ $exitCode = $commandTester->execute([]);
+
+ self::assertSame(0, $exitCode);
}
/**
@@ -78,14 +51,11 @@ public function itShouldNotReportPHPAsUnused(): void
public function itShouldNotReportExtDsAsUnused(): void
{
chdir(__DIR__ . '/../assets/TestProjects/ExtDsRequirement');
+ $commandTester = new CommandTester($this->container->get(UnusedCommand::class));
+ $exitCode = $commandTester->execute([]);
- self::assertEquals(
- 0,
- $this->getApplication()->run(
- new ArrayInput(['unused']),
- new NullOutput()
- )
- );
+ self::assertSame(0, $exitCode);
+ self::assertStringContainsString('Found 2 used, 0 unused and 0 ignored packages', $commandTester->getDisplay());
}
/**
@@ -94,14 +64,11 @@ public function itShouldNotReportExtDsAsUnused(): void
public function itShouldNoReportUnusedWithAutoloadFilesWithRequire(): void
{
chdir(__DIR__ . '/../assets/TestProjects/AutoloadFilesWithRequire');
+ $commandTester = new CommandTester($this->container->get(UnusedCommand::class));
+ $exitCode = $commandTester->execute([]);
- self::assertEquals(
- 0,
- $this->getApplication()->run(
- new ArrayInput(['unused']),
- new NullOutput()
- )
- );
+ self::assertSame(0, $exitCode);
+ self::assertStringContainsString('Found 2 used, 0 unused and 0 ignored packages', $commandTester->getDisplay());
}
/**
@@ -110,15 +77,12 @@ public function itShouldNoReportUnusedWithAutoloadFilesWithRequire(): void
public function itShouldNotReportSpecialPackages(): void
{
chdir(__DIR__ . '/../assets/TestProjects/IgnoreSpecialPackages');
+ $commandTester = new CommandTester($this->container->get(UnusedCommand::class));
+ $exitCode = $commandTester->execute([]);
- $output = new BufferedOutput();
-
- $this->getApplication()->run(
- new ArrayInput(['unused']),
- $output
- );
-
- self::assertStringNotContainsString('composer-plugin-api', $output->fetch());
+ self::assertSame(0, $exitCode);
+ self::assertStringNotContainsString('composer-plugin-api', $commandTester->getDisplay());
+ self::assertStringContainsString('Found 0 used, 0 unused and 0 ignored packages', $commandTester->getDisplay());
}
/**
@@ -127,15 +91,12 @@ public function itShouldNotReportSpecialPackages(): void
public function itShouldNotReportExcludedPackages(): void
{
chdir(__DIR__ . '/../assets/TestProjects/IgnoreExcludedPackages');
+ $commandTester = new CommandTester($this->container->get(UnusedCommand::class));
+ $exitCode = $commandTester->execute(['--excludePackage' => ['dummy/test-package']]);
- $output = new BufferedOutput();
-
- $this->getApplication()->run(
- new ArrayInput(['unused', '--excludePackage' => ['dummy/test-package']]),
- $output
- );
-
- self::assertStringNotContainsString('dummy/test-package', $output->fetch());
+ self::assertSame(0, $exitCode);
+ self::assertStringNotContainsString('dummy/test-package', $commandTester->getDisplay());
+ self::assertStringContainsString('Found 0 used, 0 unused and 0 ignored packages', $commandTester->getDisplay());
}
/**
@@ -144,14 +105,12 @@ public function itShouldNotReportExcludedPackages(): void
public function itShouldNotReportPatternExcludedPackages(): void
{
chdir(__DIR__ . '/../assets/TestProjects/IgnorePatternPackages');
+ $commandTester = new CommandTester($this->container->get(UnusedCommand::class));
+ $exitCode = $commandTester->execute([]);
- $output = new BufferedOutput();
-
- $this->getApplication()->run(
- new ArrayInput(['unused']),
- $output
- );
-
- self::assertStringNotContainsString('-implementation', $output->fetch());
+ self::assertSame(1, $exitCode);
+ self::assertStringNotContainsString('-implementation', $commandTester->getDisplay());
+ self::assertStringContainsString('dummy/test-package', $commandTester->getDisplay());
+ self::assertStringContainsString('Found 0 used, 1 unused and 0 ignored packages', $commandTester->getDisplay());
}
}
diff --git a/tests/Unit/Collection/DependencyCollectionTest.php b/tests/Unit/Collection/DependencyCollectionTest.php
index 1c15a54a..536a157d 100644
--- a/tests/Unit/Collection/DependencyCollectionTest.php
+++ b/tests/Unit/Collection/DependencyCollectionTest.php
@@ -4,7 +4,7 @@
namespace Icanhazstring\Composer\Test\Unused\Unit\Collection;
-use Composer\Package\PackageInterface;
+use ComposerUnused\Contracts\PackageInterface;
use Icanhazstring\Composer\Unused\Dependency\DependencyCollection;
use Icanhazstring\Composer\Unused\Dependency\RequiredDependency;
use ComposerUnused\SymbolParser\Symbol\SymbolListInterface;
diff --git a/tests/Unit/Dependency/RequiredDependencyTest.php b/tests/Unit/Dependency/RequiredDependencyTest.php
index 5762bc45..caf3ae65 100644
--- a/tests/Unit/Dependency/RequiredDependencyTest.php
+++ b/tests/Unit/Dependency/RequiredDependencyTest.php
@@ -4,10 +4,9 @@
namespace Icanhazstring\Composer\Test\Unused\Unit\Dependency;
-use Composer\Package\Link;
-use Composer\Package\Package;
-use Composer\Package\PackageInterface;
-use Composer\Semver\Constraint\ConstraintInterface;
+use ComposerUnused\Contracts\PackageInterface;
+use Icanhazstring\Composer\Unused\Composer\Link;
+use Icanhazstring\Composer\Unused\Composer\Package;
use Icanhazstring\Composer\Unused\Dependency\RequiredDependency;
use ComposerUnused\SymbolParser\Symbol\Symbol;
use ComposerUnused\SymbolParser\Symbol\SymbolList;
@@ -48,13 +47,13 @@ public function itShouldProvideSymbol(): void
public function itShouldRequireDependency(): void
{
$rootRequirement = new RequiredDependency(
- new Package('root/requirement', '1.0.0', '1.0.0'),
+ new Package('root/requirement'),
new SymbolList()
);
- $requiredPackage = new Package('required/pacakge', '1.0.0', '1.0.0');
+ $requiredPackage = new Package('required/pacakge');
$requiredPackage->setRequires([
- 'root/requirement' => new Link('', 'root/requirement', $this->createStub(ConstraintInterface::class))
+ 'root/requirement' => new Link('root/requirement')
]);
$requiredDependency = new RequiredDependency($requiredPackage, new SymbolList());
@@ -68,12 +67,12 @@ public function itShouldRequireDependency(): void
public function itShouldSuggestDependency(): void
{
$rootRequirement = new RequiredDependency(
- new Package('root/requirement', '1.0.0', '1.0.0'),
+ new Package('root/requirement'),
new SymbolList()
);
- $requiredPackage = new Package('required/pacakge', '1.0.0', '1.0.0');
- $requiredPackage->setSuggests(['root/requirement' => '*']);
+ $requiredPackage = new Package('required/pacakge');
+ $requiredPackage->setSuggests(['root/requirement']);
$requiredDependency = new RequiredDependency($requiredPackage, new SymbolList());
diff --git a/tests/assets/TestProjects/IgnoreExcludedPackages/vendor/dummy/test-package/composer.json b/tests/assets/TestProjects/IgnoreExcludedPackages/vendor/dummy/test-package/composer.json
new file mode 100644
index 00000000..b2922546
--- /dev/null
+++ b/tests/assets/TestProjects/IgnoreExcludedPackages/vendor/dummy/test-package/composer.json
@@ -0,0 +1,5 @@
+{
+ "name": "dummy/test-package",
+ "require": {
+ }
+}
diff --git a/tests/assets/TestProjects/IgnorePatternPackages/vendor/dummy/test-package/composer.json b/tests/assets/TestProjects/IgnorePatternPackages/vendor/dummy/test-package/composer.json
new file mode 100644
index 00000000..b2922546
--- /dev/null
+++ b/tests/assets/TestProjects/IgnorePatternPackages/vendor/dummy/test-package/composer.json
@@ -0,0 +1,5 @@
+{
+ "name": "dummy/test-package",
+ "require": {
+ }
+}