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; } }