summaryrefslogtreecommitdiffstatshomepage
path: root/composer/Plugin/RecipeUnpack/UnpackCommand.php
blob: 60bd86f08c170a0bd0d7b360b1fd2322ce60bbc9 (plain) (blame)
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
<?php

namespace Drupal\Composer\Plugin\RecipeUnpack;

use Composer\Command\BaseCommand;
use Composer\Package\PackageInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * The "drupal:recipe-unpack" command class.
 *
 * Manually run the unpack operation that normally happens after
 * 'composer require'.
 *
 * @internal
 */
final class UnpackCommand extends BaseCommand {

  /**
   * {@inheritdoc}
   */
  protected function configure(): void {
    $name = 'drupal:recipe-unpack';
    $this
      ->setName($name)
      ->setDescription('Unpack Drupal recipes.')
      ->addArgument('recipes', InputArgument::IS_ARRAY, "A list of recipe package names separated by a space, e.g. drupal/recipe_one drupal/recipe_two. If not provided, all recipes listed in the require section of the root composer are unpacked.")
      ->setHelp(
        <<<EOT
The <info>$name</info> command unpacks dependencies from the specified recipe
packages into the composer.json file.

<info>php composer.phar $name drupal/my-recipe [...]</info>

It is usually not necessary to call <info>$name</info> manually,
because by default it is called automatically as needed, after a
<info>require</info> command.
EOT
            );
  }

  /**
   * {@inheritdoc}
   */
  protected function execute(InputInterface $input, OutputInterface $output): int {
    $composer = $this->requireComposer();
    $io = $this->getIO();
    $local_repo = $composer->getRepositoryManager()->getLocalRepository();
    $package_names = $input->getArgument('recipes') ?? [];

    // If no recipes are provided unpack all recipes that are required by the
    // root package.
    if (empty($package_names)) {
      foreach ($composer->getPackage()->getRequires() as $link) {
        $package = $local_repo->findPackage($link->getTarget(), $link->getConstraint());
        if ($package->getType() === Plugin::RECIPE_PACKAGE_TYPE) {
          $package_names[] = $package->getName();
        }
      }
      if (empty($package_names)) {
        $io->write('<info>No recipes to unpack.</info>');
        return 0;
      }
    }

    $manager = new UnpackManager($composer, $io);
    $unpack_collection = new UnpackCollection();
    foreach ($package_names as $package_name) {
      if (!$manager->isRootDependency($package_name)) {
        $io->error(sprintf('<info>%s</info> not found in the root composer.json.', $package_name));
        return 1;
      }
      $packages = $local_repo->findPackages($package_name);
      $package = reset($packages);

      if (!$package instanceof PackageInterface) {
        $io->error(sprintf('<info>%s</info> does not resolve to a package.', $package_name));
        return 1;
      }

      if ($package->getType() !== Plugin::RECIPE_PACKAGE_TYPE) {
        $io->error(sprintf('<info>%s</info> is not a recipe.', $package->getPrettyName()));
        return 1;
      }

      if ($manager->unpackOptions->isIgnored($package)) {
        $io->error(sprintf('<info>%s</info> is in the extra.drupal-recipe-unpack.ignore list.', $package->getName()));
        return 1;
      }

      if (UnpackManager::isDevRequirement($package)) {
        $io->warning(sprintf('<info>%s</info> is present in the require-dev key. Unpacking will move the recipe\'s dependencies to the require key.', $package->getName()));
        if ($io->isInteractive() && !$io->askConfirmation('<info>Do you want to continue</info> [<comment>yes</comment>]?')) {
          return 0;
        }
      }
      $unpack_collection->add($package);
    }
    $manager->unpack($unpack_collection);
    return 0;
  }

}