Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve #252: Integrate symfony/console and split out composer plugin implementation #262

Merged
merged 2 commits into from Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 6 additions & 2 deletions CHANGELOG.md
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions Makefile
@@ -1,4 +1,4 @@
PHP_VERSION=8.0
PHP_VERSION=7.4

up: ## Run all containers in all versions
docker compose up -d
Expand Down Expand Up @@ -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}'
Expand Down
16 changes: 4 additions & 12 deletions bin/composer-unused
Expand Up @@ -2,10 +2,9 @@

<?php

use Composer\Composer;
use Composer\Console\Application;
use Composer\IO\IOInterface;
use Icanhazstring\Composer\Unused\Console\Command\UnusedCommand;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;

(static function ($argv) {
Expand Down Expand Up @@ -36,19 +35,12 @@ use Symfony\Component\Console\Input\ArgvInput;

require UNUSED_COMPOSER_INSTALL;

/** @var ContainerInterface $container */
$container = require __DIR__ . '/../config/container.php';

$application = new Application();

$container->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);
16 changes: 7 additions & 9 deletions 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",
Expand All @@ -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",
Expand All @@ -39,9 +40,6 @@
"preferred-install": "dist",
"sort-packages": true
},
"extra": {
"class": "Icanhazstring\\Composer\\Unused\\UnusedPlugin"
},
"autoload": {
"psr-4": {
"Icanhazstring\\Composer\\Unused\\": "src"
Expand Down
2 changes: 2 additions & 0 deletions config/service_manager.php
Expand Up @@ -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;
Expand All @@ -24,5 +25,6 @@
ConsumedSymbolLoaderBuilder::class => InvokableFactory::class,
ProvidedSymbolLoaderBuilder::class => InvokableFactory::class,
PackageResolver::class => InvokableFactory::class,
ConfigFactory::class => InvokableFactory::class,
]
];
2 changes: 2 additions & 0 deletions docker-compose.yml
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions phpstan.neon
Expand Up @@ -9,6 +9,7 @@ parameters:
level: max
inferPrivatePropertyTypeFromConstructor: true
paths:
- bin/
- src/
- tests/
tmpDir: data
2 changes: 1 addition & 1 deletion src/Command/CollectConsumedSymbolsCommand.php
Expand Up @@ -4,7 +4,7 @@

namespace Icanhazstring\Composer\Unused\Command;

use Composer\Package\PackageInterface;
use ComposerUnused\Contracts\PackageInterface;

final class CollectConsumedSymbolsCommand
{
Expand Down
4 changes: 2 additions & 2 deletions src/Command/Handler/CollectConsumedSymbolsCommandHandler.php
Expand Up @@ -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'] ?? []),
Expand All @@ -38,7 +38,7 @@ public function collect(CollectConsumedSymbolsCommand $command): Generator

yield from $this->filterRootPackageSymbols(
$rootNamespaces,
$symbolLoader->load($package)
$symbolLoader->withBaseDir($command->getPackageRoot())->load($package)
);
}

Expand Down
Expand Up @@ -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
{
Expand All @@ -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;
}

Expand Down
13 changes: 10 additions & 3 deletions src/Command/Handler/CollectRequiredDependenciesCommandHandler.php
Expand Up @@ -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(
Expand All @@ -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)
)
)
);
Expand Down
10 changes: 5 additions & 5 deletions src/Command/LoadRequiredDependenciesCommand.php
Expand Up @@ -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<Link> */
/** @var array<LinkInterface> */
private $packageLinks;
/** @var RepositoryInterface */
private $packageRepository;

/**
* @param array<Link> $packageLinks
* @param array<LinkInterface> $packageLinks
*/
public function __construct(string $baseDir, array $packageLinks, RepositoryInterface $packageRepository)
{
Expand All @@ -32,7 +32,7 @@ public function getBaseDir(): string
}

/**
* @return array<Link>
* @return array<LinkInterface>
*/
public function getPackageLinks(): array
{
Expand Down
58 changes: 58 additions & 0 deletions src/Composer/Config.php
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace Icanhazstring\Composer\Unused\Composer;

final class Config
{
/** @var array<string, mixed> */
protected array $config = [];
protected string $name;
/** @var array<string, mixed> */
private array $require = [];
/** @var array<string, mixed> */
private array $autoload = [];
/** @var array<string, string> */
private array $suggests = [];

public function getName(): string
{
return $this->name;
}

/**
* @return array<string, mixed>
*/
public function getRequire(): array
{
return $this->require;
}

/**
* @return array<string, mixed>
*/
public function getAutoload(): array
{
return $this->autoload;
}

/**
* @return array<string, string>
*/
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;
}
}
29 changes: 29 additions & 0 deletions src/Composer/ConfigFactory.php
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Icanhazstring\Composer\Unused\Composer;

use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\SerializerInterface;

final class ConfigFactory
{
private SerializerInterface $serializer;

public function __construct()
{
$encoders = [new JsonEncoder()];
$normalizers = [new PropertyNormalizer(null, new CamelCaseToSnakeCaseNameConverter())];

$this->serializer = new Serializer($normalizers, $encoders);
}

public function fromComposerJson(string $jsonContent): Config
{
return $this->serializer->deserialize($jsonContent, Config::class, 'json');
}
}
22 changes: 22 additions & 0 deletions src/Composer/Link.php
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Icanhazstring\Composer\Unused\Composer;

use ComposerUnused\Contracts\LinkInterface;

final class Link implements LinkInterface
{
private string $target;

public function __construct(string $target)
{
$this->target = $target;
}

public function getTarget(): string
{
return $this->target;
}
}