drush_plugin__composer_check/ComposerCheckCommands.php

194 lines
5.3 KiB
PHP

<?php
declare(strict_types=1);
namespace Drush\Commands\composer_check;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Drush\Commands\DrushCommands;
use Symfony\Component\Yaml\Yaml;
/**
* MagpjmCommands provides Drush 9 commands for the MAGPJ run time module.
*/
class ComposerCheckCommands extends DrushCommands {
/**
* The serialization.yaml service.
*
* @var \Symfony\Component\Yaml
*/
private $yaml;
public function __construct() {
$this->yaml = new Yaml();
}
/**
* Command callback for composer-check.
*
* @param null|string $lockPath
* Optional. The path to a composer.lock file.
*/
/**
* Lists the packages requested in composer.json and the matching locked
* version.
*
* @param ?string $lockPath
*
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
* The list of package versions, unless YAML encoding is used.
*
* @field-labels
* name: Name
* kind: Kind
* req: Requirement
* ver: Version
*
* @command composer:check
* @aliases cch
*
* @option all List all locked packages, even those not requested
* @option yaml Produce YAML output instead of a table
*
* @throws \Exception
*/
public function composerCheck(string $lockPath = NULL) {
$lockPath = $this->validateLockPath($lockPath);
$jsonPath = $this->validateJsonPath($lockPath);
['run' => $jrPack, 'dev' => $jdPack] = $this->decodeJsonPackages($jsonPath);
['run' => $lrPack, 'dev' => $ldPack] = $this->decodeLockPackages($lockPath);
$all = !!$this->input()->getOption('all');
$yaml = !!$this->input()->getOption('yaml');
$packages = ['run' => [], 'dev' => []];
foreach ($jrPack as $package => $requirement) {
if ($all || !empty($requirement)) {
$package = mb_strtolower($package);
$packages['run'][$package]['requirement'] = $requirement;
}
}
foreach ($jdPack as $package => $requirement) {
if ($all || !empty($requirement)) {
$package = mb_strtolower($package);
$packages['dev'][$package]['requirement'] = $requirement;
}
}
foreach ($lrPack as $packageInfo) {
$package = mb_strtolower($packageInfo['name']);
if ($all || !empty($packages['run'][$package])) {
$version = $packageInfo['version'];
$packages['run'][$package]['version'] = $version;
}
}
foreach ($ldPack as $packageInfo) {
$package = mb_strtolower($packageInfo['name']);
if ($all || !empty($packages['dev'][$package])) {
$version = $packageInfo['version'];
$packages['dev'][$package]['version'] = $version;
}
}
ksort($packages['dev']);
ksort($packages['run']);
if ($yaml) {
$this->output()->writeln($this->yaml->dump($packages, 3, 2));
return NULL;
}
return $this->humanOutput($packages);
}
/**
* Display a package comparison as a text table.
*
* @param array $packages
* A package comparison array.
*
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
*
*/
protected function humanOutput($packages): RowsOfFields {
//$header = ['Name', 'Kind', 'Requirement', 'Version'];
$rows = [];
foreach ($packages as $kind => $kindPackages) {
foreach ($kindPackages as $package => $info) {
$rows["$package/$kind"] = [
'name' => $package,
'kind' => $kind,
'req' => $info['requirement'] ?? '',
'ver' => $info['version'] ?? '',
];
}
}
ksort($rows);
return new RowsOfFields($rows);
}
/**
* @param string $jsonPath
*
* @return array
*/
protected function decodeJsonPackages(string $jsonPath): array {
$json = json_decode(file_get_contents($jsonPath), TRUE);
$jsonPackages = $json['require'] ?? [];
$jsonDevPackages = $json['require-dev'] ?? [];
return ['run' => $jsonPackages, 'dev' => $jsonDevPackages];
}
protected function decodeLockPackages(string $lockPath): array {
$file = json_decode(file_get_contents($lockPath), TRUE);
$run = $file['packages'];
$dev = $file['packages-dev'];
$platform = $file['platform'];
array_walk($platform, function (&$requirement, $component) {
$requirement = [
'name' => $component,
'version' => $requirement,
];
});
$run = array_merge($run, $platform);
$dev = array_merge($dev, $platform);
return ['run' => $run, 'dev' => $dev];
}
/**
* @param string $lockPath The lockPath command argument.
*
* @return string
*
* @throws \Exception
*/
protected function validateJsonPath(string $lockPath): string {
$jsonPath = dirname($lockPath) . '/composer.json';
if (!is_file($jsonPath) && is_readable($jsonPath)) {
throw new \Exception("Cannot read composer.json file");
}
return $jsonPath;
}
/**
* @param string|null $lockPath The lockPath optional command argument.
*
* @return string|null The defaulted lock path.
*
* @throws \Exception If the defaulted lock path cannot be read.
*/
protected function validateLockPath(?string $lockPath): ?string {
if (empty($lockPath)) {
$lockPath = dirname(DRUPAL_ROOT) . '/composer.lock';
}
if (!is_file($lockPath) && is_readable($lockPath)) {
throw new \Exception("Cannot read composer.lock file");
}
return $lockPath;
}
}