-
-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
12 changed files
with
719 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\YiiDevTool\Command; | ||
|
||
use Yiisoft\YiiDevTool\Component\CodeUsage\ComposerPackageUsageAnalyzer; | ||
use Yiisoft\YiiDevTool\Component\Composer\ComposerConfig; | ||
use Yiisoft\YiiDevTool\Component\Composer\ComposerConfigDependenciesModifier; | ||
use Yiisoft\YiiDevTool\Component\Composer\ComposerPackage; | ||
use Yiisoft\YiiDevTool\Component\CodeUsage\CodeUsageEnvironment; | ||
use Yiisoft\YiiDevTool\Component\CodeUsage\NamespaceUsageFinder; | ||
use Yiisoft\YiiDevTool\Component\Console\PackageCommand; | ||
use Yiisoft\YiiDevTool\Component\Package\Package; | ||
|
||
class FixDependenciesCommand extends PackageCommand | ||
{ | ||
protected function configure() | ||
{ | ||
$this | ||
->setName('fix-dependencies') | ||
->setDescription('Fix <fg=yellow;options=bold>require</> and <fg=yellow;options=bold>require-dev</> sections in <fg=blue;options=bold>composer.json</> according to the actual use of classes'); | ||
|
||
$this->addPackageArgument(); | ||
} | ||
|
||
protected function getMessageWhenNothingHasBeenOutput(): ?string | ||
{ | ||
return '<success>✔ Nothing to fix</success>'; | ||
} | ||
|
||
protected function processPackage(Package $package): void | ||
{ | ||
$io = $this->getIO(); | ||
$io->preparePackageHeader($package, "Fixing package {package} dependencies"); | ||
|
||
$package = new ComposerPackage($package->getName(), $package->getPath()); | ||
|
||
if (!$package->installed()) { | ||
$io->warning([ | ||
"Package <package>{$package->getName()}</package> is not installed.", | ||
"Dependencies fixing skipped.", | ||
]); | ||
|
||
return; | ||
} | ||
|
||
$dependencyPackages = $package->getDependencyPackages('yiisoft'); | ||
foreach ($dependencyPackages as $dependencyPackage) { | ||
if (!$dependencyPackage->installed()) { | ||
$io->warning([ | ||
"Dependency <package>{$dependencyPackage->getName()}</package> is not installed.", | ||
"Dependencies fixing skipped.", | ||
]); | ||
|
||
return; | ||
} | ||
} | ||
|
||
$namespaceUsages = | ||
(new NamespaceUsageFinder()) | ||
->addTargetPaths(CodeUsageEnvironment::PRODUCTION, [ | ||
'config/common.php', | ||
'config/web.php', | ||
'src', | ||
], $package->getPath()) | ||
->addTargetPaths(CodeUsageEnvironment::DEV, [ | ||
'config/tests.php', | ||
'tests', | ||
], $package->getPath()) | ||
->getUsages(); | ||
|
||
$analyzer = new ComposerPackageUsageAnalyzer($dependencyPackages, $namespaceUsages); | ||
$analyzer->analyze(); | ||
|
||
$composerConfig = $package->getComposerConfig(); | ||
|
||
(new ComposerConfigDependenciesModifier($composerConfig)) | ||
->removeDependencies($analyzer->getUnusedPackages()) | ||
->ensureDependenciesUsedOnlyInSection( | ||
$analyzer->getPackagesUsedInSpecifiedEnvironment(CodeUsageEnvironment::PRODUCTION), | ||
ComposerConfig::SECTION_REQUIRE, | ||
) | ||
->ensureDependenciesUsedOnlyInSection( | ||
$analyzer->getPackagesUsedOnlyInSpecifiedEnvironment(CodeUsageEnvironment::DEV), | ||
ComposerConfig::SECTION_REQUIRE_DEV, | ||
); | ||
|
||
$composerConfig->writeToFile($package->getComposerConfigPath()); | ||
|
||
$io->done(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\YiiDevTool\Component\CodeUsage; | ||
|
||
use InvalidArgumentException; | ||
|
||
class CodeUsage | ||
{ | ||
private string $identifier; | ||
|
||
/** | ||
* @var string[] | ||
*/ | ||
private array $environments = []; | ||
|
||
/** | ||
* @param string $identifier Unique identifier of code usage: namespace, package name, etc. | ||
* @param string[] $environments Environment in which the code is used. | ||
*/ | ||
public function __construct(string $identifier, array $environments) | ||
{ | ||
foreach ($environments as $environment) { | ||
if (!is_string($environment)) { | ||
throw new InvalidArgumentException('Each environment must be a string.'); | ||
} | ||
} | ||
|
||
$this->identifier = $identifier; | ||
$this->environments = $environments; | ||
} | ||
|
||
public function getIdentifier(): string | ||
{ | ||
return $this->identifier; | ||
} | ||
|
||
/** | ||
* @return string[] | ||
*/ | ||
public function getEnvironments(): array | ||
{ | ||
return $this->environments; | ||
} | ||
|
||
public function registerUsageInEnvironment(string $environment): void | ||
{ | ||
if (!in_array($environment, $this->environments, true)) { | ||
$this->environments[] = $environment; | ||
} | ||
} | ||
|
||
/** | ||
* @param string[] $environments | ||
*/ | ||
public function registerUsageInEnvironments(array $environments): void | ||
{ | ||
foreach ($environments as $environment) { | ||
if (!is_string($environment)) { | ||
throw new InvalidArgumentException('Each environment must be a string.'); | ||
} | ||
|
||
$this->registerUsageInEnvironment($environment); | ||
} | ||
} | ||
|
||
public function usedInEnvironment(string $environment): bool | ||
{ | ||
return in_array($environment, $this->environments, true); | ||
} | ||
|
||
public function usedOnlyInSpecifiedEnvironment(string $environment): bool | ||
{ | ||
if (count($this->environments) !== 1) { | ||
return false; | ||
} | ||
|
||
return in_array($environment, $this->environments, true); | ||
} | ||
|
||
public function used(): bool | ||
{ | ||
return count($this->environments) > 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\YiiDevTool\Component\CodeUsage; | ||
|
||
class CodeUsageEnvironment | ||
{ | ||
public const PRODUCTION = 'production'; | ||
public const DEV = 'dev'; | ||
} |
118 changes: 118 additions & 0 deletions
118
src/Component/CodeUsage/ComposerPackageUsageAnalyzer.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Yiisoft\YiiDevTool\Component\CodeUsage; | ||
|
||
use InvalidArgumentException; | ||
use Yiisoft\YiiDevTool\Component\Composer\ComposerPackage; | ||
|
||
class ComposerPackageUsageAnalyzer | ||
{ | ||
/** | ||
* @var ComposerPackage[] | ||
*/ | ||
private array $packages = []; | ||
|
||
/** | ||
* @var CodeUsage[] | ||
*/ | ||
private array $namespaceUsages = []; | ||
|
||
/** | ||
* @var CodeUsage[] | ||
*/ | ||
private array $packageUsages = []; | ||
|
||
/** | ||
* @param ComposerPackage[] $packages | ||
* @param CodeUsage[] $namespaceUsages | ||
*/ | ||
public function __construct(array $packages, array $namespaceUsages) | ||
{ | ||
foreach ($packages as $package) { | ||
if (!$package instanceof ComposerPackage) { | ||
throw new InvalidArgumentException('$packages must be an array of ComposerPackage objects.'); | ||
} | ||
} | ||
|
||
foreach ($namespaceUsages as $namespaceUsage) { | ||
if (!$namespaceUsage instanceof CodeUsage) { | ||
throw new InvalidArgumentException('$namespaceUsages must be an array of CodeUsage objects.'); | ||
} | ||
} | ||
|
||
foreach ($packages as $package) { | ||
$this->packages[$package->getName()] = $package; | ||
} | ||
|
||
foreach ($namespaceUsages as $namespaceUsage) { | ||
$this->namespaceUsages[$namespaceUsage->getIdentifier()] = $namespaceUsage; | ||
} | ||
} | ||
|
||
public function analyze(): void | ||
{ | ||
foreach ($this->packages as $package) { | ||
foreach ($package->getNamespaces() as $packageNamespace) { | ||
foreach ($this->namespaceUsages as $namespaceUsage) { | ||
if (strpos($namespaceUsage->getIdentifier(), "\\$packageNamespace") === 0) { | ||
$this->registerPackageUsage($package->getName(), $namespaceUsage->getEnvironments()); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
public function getPackagesUsedInSpecifiedEnvironment(string $environment): array | ||
{ | ||
$result = []; | ||
|
||
foreach ($this->packageUsages as $packageUsage) { | ||
if ($packageUsage->usedInEnvironment($environment)) { | ||
$result[] = $this->packages[$packageUsage->getIdentifier()]; | ||
} | ||
} | ||
|
||
return $result; | ||
} | ||
|
||
public function getPackagesUsedOnlyInSpecifiedEnvironment(string $environment): array | ||
{ | ||
$result = []; | ||
|
||
foreach ($this->packageUsages as $packageUsage) { | ||
if ($packageUsage->usedOnlyInSpecifiedEnvironment($environment)) { | ||
$result[] = $this->packages[$packageUsage->getIdentifier()]; | ||
} | ||
} | ||
|
||
return $result; | ||
} | ||
|
||
public function getUnusedPackages(): array | ||
{ | ||
$result = []; | ||
|
||
foreach ($this->packageUsages as $packageUsage) { | ||
if (!$packageUsage->used()) { | ||
$result[] = $this->packages[$packageUsage->getIdentifier()]; | ||
} | ||
} | ||
|
||
return $result; | ||
} | ||
|
||
/** | ||
* @param string $packageName | ||
* @param string[] $environments | ||
*/ | ||
private function registerPackageUsage(string $packageName, array $environments): void | ||
{ | ||
if (!array_key_exists($packageName, $this->packageUsages)) { | ||
$this->packageUsages[$packageName] = new CodeUsage($packageName, $environments); | ||
} else { | ||
$this->packageUsages[$packageName]->registerUsageInEnvironments($environments); | ||
} | ||
} | ||
} |
Oops, something went wrong.