1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
<?php
namespace Piwik\Plugins\TestRunner\Commands;
use Piwik\Exception\Exception;
use Piwik\Plugin\ConsoleCommand;
class CheckDirectDependencyUse extends ConsoleCommand
{
public $usesFoundList = [];
protected function configure()
{
parent::configure();
$this->setName('tests:check-direct-dependency-use');
$this->addRequiredValueOption('plugin', null, 'Run test only for a specific plugin');
$this->addNoValueOption('grep-vendor', null, 'Do not skip vendor folders and scan them too');
$this->setDescription('checks for direct dependency use in plugins');
}
protected function doExecute(): int
{
$output = $this->getOutput();
$output->writeln("<error>Unavailable on Debian systems, the dependencies are installed by packages.</error>");
return self::FAILURE;
[$psr4NamespacePrefixes, $psr0Prefixes] = $this->getCoreDependencyNamespacePrefixes();
$input = $this->getInput();
$plugin = $input->getOption('plugin');
$isGrepVendorFolder = $input->getOption('grep-vendor');
if (!empty($plugin)) {
$this->usesFoundList[$plugin] = [];
}
$this->grepUses($psr4NamespacePrefixes, 'psr4', $plugin, $isGrepVendorFolder);
$this->grepUses($psr0Prefixes, 'psr0', $plugin, $isGrepVendorFolder);
return self::SUCCESS;
}
private function getCoreDependencyNamespacePrefixes()
{
$psr4NamespacePrefixes = [];
$psr0Prefixes = [];
$coreComposerLock = PIWIK_INCLUDE_PATH . '/composer.lock';
$coreComposerLockContents = file_get_contents($coreComposerLock);
$coreComposerLockContents = json_decode($coreComposerLockContents, true);
foreach ($coreComposerLockContents['packages'] as $package) {
$psr4NamespacePrefixes = array_merge(
$psr4NamespacePrefixes,
array_keys($package['autoload']['psr-4'] ?? [])
);
$psr0Prefixes = array_merge(
$psr0Prefixes,
array_keys($package['autoload']['psr-0'] ?? [])
);
}
$psr4NamespacePrefixes = array_filter($psr4NamespacePrefixes);
$psr4NamespacePrefixes = array_unique($psr4NamespacePrefixes);
$psr0Prefixes = array_filter($psr0Prefixes);
$psr0Prefixes = array_unique($psr0Prefixes);
return [$psr4NamespacePrefixes, $psr0Prefixes];
}
private function grepUses($prefixes, $psrType, $plugin, $isGrepVendorFolder)
{
foreach ($prefixes as $prefix) {
$directUses = $this->grepForUses($prefix, $psrType, $plugin, $isGrepVendorFolder);
if (!empty($directUses)) {
$this->reportDirectUses($prefix, $directUses, $psrType);
}
}
}
private function grepForUses($prefix, $psrType, $plugin, $isGrepVendorFolder)
{
$uses = [];
$rgOutput = [];
$regex = '';
if ($plugin) {
$plugin = '/plugins/' . $plugin;
}
$vendorScan = '--glob=\\!vendor';
if ($isGrepVendorFolder) {
$vendorScan = '';
}
if ($psrType === 'psr4') {
$prefix = rtrim($prefix, '\\');
$regex = ' \\\\?' . preg_quote($prefix) . '\\b';
} elseif ($psrType === 'psr0') {
$regex = '\\b' . preg_quote($prefix) . '_';
}
$command = 'rg \'' . $regex . '\' --glob=*.php ' . $vendorScan . ' --json --sort path ' . PIWIK_INCLUDE_PATH . $plugin;
exec($command, $rgOutput, $returnCode);
if ($returnCode == 127) {
throw new Exception('Please install ripgrep package, Check https://github.com/BurntSushi/ripgrep?tab=readme-ov-file#installation for installation');
}
foreach ($rgOutput as $line) {
$line = json_decode($line, true);
if ($line['type'] !== 'match') {
continue;
}
$path = $line['data']['path']['text'];
$path = str_replace(PIWIK_INCLUDE_PATH, '', $path);
$path = ltrim($path, '/');
$parts = explode('/', $path);
array_shift($parts);
$pluginName = array_shift($parts);
if ($pluginName) {
$remainingPath = implode('/', $parts);
$uses[$pluginName][] = $remainingPath;
}
}
foreach ($uses as $pluginName => $entries) {
$uses[$pluginName] = array_unique($entries);
}
return $uses;
}
private function reportDirectUses($prefix, $directUses, $type)
{
$output = $this->getOutput();
$output->writeln("<info>Found '$prefix' ($type) usage in:</info>");
foreach ($directUses as $plugin => $files) {
foreach ($files as $file) {
$this->usesFoundList[rtrim($plugin, '\\')][rtrim($prefix, '\\')][] = $plugin . '/' . $file;
}
$output->writeln(" - $plugin, " . count($files) . " files");
}
}
}
|