|
@@ -0,0 +1,194 @@
|
|
|
+<?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 {
|
|
|
+
|
|
|
+ $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;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|