Pull merge.
[yaffs-website] / vendor / drupal / console / src / Command / ComposerizeCommand.php
1 <?php
2
3 namespace Drupal\Console\Command;
4
5 use Drupal\Console\Extension\Manager;
6 use Drupal\Console\Core\Utils\DrupalFinder;
7 use Symfony\Component\Console\Input\InputInterface;
8 use Symfony\Component\Console\Input\InputOption;
9 use Symfony\Component\Console\Output\OutputInterface;
10 use Drupal\Console\Core\Command\ContainerAwareCommand;
11 use Drupal\Component\Serialization\Json;
12
13 /**
14  * Class ComposerizeCommand
15  *
16  * @package Drupal\Console\Command
17  */
18 class ComposerizeCommand extends ContainerAwareCommand
19 {
20
21     /**
22      * @var array
23      */
24     protected $corePackages = [];
25
26     /**
27      * @var array
28      */
29     protected $packages = [];
30
31     /**
32      * @var array
33      */
34     protected $dependencies = [];
35
36     /**
37      * @var DrupalFinder
38      */
39     protected $drupalFinder = null;
40
41     /**
42      * @var Manager $extensionManager
43      */
44     protected $extensionManager = null;
45
46     /**
47      * {@inheritdoc}
48      */
49     protected function configure()
50     {
51         $this
52             ->setName('composerize')
53             ->setDescription(
54                 $this->trans('commands.composerize.description')
55             )
56             ->addOption(
57                 'show-packages',
58                 null,
59                 InputOption::VALUE_NONE,
60                 $this->trans('commands.composerize.options.show-packages')
61             )
62             ->addOption(
63                 'include-version',
64                 null,
65                 InputOption::VALUE_NONE,
66                 $this->trans('commands.composerize.options.include-version')
67             )
68             ->setHelp($this->trans('commands.composerize.description'));
69     }
70
71     /**
72      * {@inheritdoc}
73      */
74     protected function execute(InputInterface $input, OutputInterface $output)
75     {
76         $includeVersion = $input->getOption('include-version');
77         $showPackages = $input->getOption('show-packages')?:false;
78
79         $this->drupalFinder = $this->get('console.drupal_finder');
80
81         $this->extensionManager = $this->get('console.extension_manager');
82         $this->extractCorePackages();
83
84         $this->processProfiles();
85         $this->processModules();
86         $this->processThemes();
87
88         $types = [
89             'profile',
90             'module',
91             'theme'
92         ];
93
94         $composerCommand = 'composer require ';
95         foreach ($types as $type) {
96             $packages = $this->packages[$type];
97             if (!$packages) {
98                 continue;
99             }
100
101             if ($showPackages) {
102                 $this->getIo()->comment($this->trans('commands.composerize.messages.'.$type));
103                 $tableHeader = [
104                     $this->trans('commands.composerize.messages.name'),
105                     $this->trans('commands.composerize.messages.version'),
106                     $this->trans('commands.composerize.messages.dependencies')
107                 ];
108                 $this->getIo()->table($tableHeader, $packages);
109             }
110             foreach ($packages as $package) {
111                 $module = str_replace('drupal/', '', $package['name']);
112                 if (array_key_exists($module, $this->dependencies)) {
113                     continue;
114                 }
115                 $composerCommand .= $package['name'];
116                 if ($includeVersion) {
117                     $composerCommand .= ':' . $package['version'];
118                 }
119                 $composerCommand .= ' ';
120             }
121         }
122         $this->getIo()->comment($this->trans('commands.composerize.messages.from'));
123         $this->getIo()->simple($this->drupalFinder->getComposerRoot());
124         $this->getIo()->newLine();
125         $this->getIo()->comment($this->trans('commands.composerize.messages.execute'));
126         $this->getIo()->simple($composerCommand);
127         $this->getIo()->newLine();
128         $this->getIo()->comment($this->trans('commands.composerize.messages.ignore'));
129
130         $webRoot = str_replace(
131             $this->drupalFinder->getComposerRoot() . '/',
132             '',
133             $this->drupalFinder->getDrupalRoot() . '/'
134         );
135
136         $this->getIo()->writeln(
137             [
138                 ' vendor/',
139                 ' '.$webRoot.'modules/contrib',
140                 ' '.$webRoot.'themes/contrib',
141                 ' '.$webRoot.'profiles/contrib'
142             ]
143         );
144     }
145
146     private function extractCorePackages()
147     {
148         $this->corePackages['module'] = $this->extensionManager->discoverModules()
149             ->showInstalled()
150             ->showUninstalled()
151             ->showCore()
152             ->getList(true);
153
154         $this->corePackages['theme'] = $this->extensionManager->discoverThemes()
155             ->showInstalled()
156             ->showUninstalled()
157             ->showCore()
158             ->getList(true);
159
160         $this->corePackages['profile'] = $this->extensionManager->discoverProfiles()
161             ->showInstalled()
162             ->showUninstalled()
163             ->showCore()
164             ->getList(true);
165     }
166
167     private function processProfiles()
168     {
169         $type = 'profile';
170         $profiles = $this->extensionManager->discoverProfiles()
171             ->showNoCore()
172             ->showInstalled()
173             ->getList();
174
175         /**
176          * @var \Drupal\Core\Extension\Extension[] $module
177          */
178         foreach ($profiles as $profile) {
179             if (!$this->isValidModule($profile)) {
180                 continue;
181             }
182
183             $dependencies = $this->extractDependencies(
184                 $profile,
185                 []
186             );
187
188             $this->packages[$type][] = [
189                 'name' => sprintf('drupal/%s', $profile->getName()),
190                 'version' => $this->calculateVersion($profile->info['version']),
191                 'dependencies' => implode(PHP_EOL, array_values($dependencies))
192             ];
193
194             $this->dependencies = array_merge(
195                 $this->dependencies,
196                 $dependencies?$dependencies:[]
197             );
198         }
199     }
200
201     private function processModules()
202     {
203         $type = 'module';
204         $modules = $this->extensionManager->discoverModules()
205             ->showInstalled()
206             ->showNoCore()
207             ->getList();
208
209         /**
210          * @var \Drupal\Core\Extension\Extension[] $module
211          */
212         foreach ($modules as $module) {
213             if (!$this->isValidModule($module)) {
214                 continue;
215             }
216
217             $dependencies = $this->extractDependencies(
218                 $module,
219                 array_keys($modules)
220             );
221             $this->packages[$type][] = [
222                 'name' => sprintf('drupal/%s', $module->getName()),
223                 'version' => $this->calculateVersion($module->info['version']),
224                 'dependencies' => implode(PHP_EOL, array_values($dependencies))
225             ];
226
227             $this->dependencies = array_merge(
228                 $this->dependencies,
229                 $dependencies?$dependencies:[]
230             );
231         }
232     }
233
234     private function processThemes()
235     {
236         $type = 'theme';
237         $themes = $this->extensionManager->discoverThemes()
238             ->showInstalled()
239             ->showNoCore()
240             ->getList();
241         /**
242          * @var \Drupal\Core\Extension\Extension[] $module
243          */
244         foreach ($themes as $theme) {
245             if (!$this->isValidTheme($theme)) {
246                 continue;
247             }
248             $this->packages[$type][] = [
249                 'name' => sprintf('drupal/%s', $theme->getName()),
250                 'version' => $this->calculateVersion($theme->info['version']),
251                 'dependencies' => ''
252             ];
253         }
254     }
255
256     /**
257      * @param $module
258      * @return bool
259      */
260     private function isValidModule($module)
261     {
262         if (strpos($module->getPath(), 'modules/custom') === 0) {
263             return false;
264         }
265
266         if (!array_key_exists('project', $module->info)) {
267             return true;
268         }
269
270         if (!array_key_exists('project', $module->info)) {
271             return true;
272         }
273
274         return $module->info['project'] === $module->getName();
275     }
276
277     /**
278      * @param $module
279      * @return bool
280      */
281     private function isValidTheme($module)
282     {
283         if (strpos($module->getPath(), 'themes/custom') === 0) {
284             return false;
285         }
286
287         return true;
288     }
289
290     private function isValidDependency($moduleDependency, $extension, $extensions)
291     {
292         if (in_array($moduleDependency, $this->corePackages['module'])) {
293             return false;
294         }
295
296         if ($extensions && !in_array($moduleDependency, $extensions)) {
297             return false;
298         }
299
300         if ($moduleDependency !== $extension->getName()) {
301             return true;
302         }
303     }
304
305     /**
306      * @param $extension
307      * @param $extensions
308      * @return array
309      */
310     private function extractDependencies($extension, $extensions)
311     {
312         if (!array_key_exists('dependencies', $extension->info)) {
313             return [];
314         }
315
316         $dependencies = [];
317
318         // Dependencies defined at info.yml
319         foreach ($extension->info['dependencies'] as $dependency) {
320             $dependencyExploded = explode(':', $dependency);
321             $moduleDependency = count($dependencyExploded)>1?$dependencyExploded[1]:$dependencyExploded[0];
322
323             if ($space = strpos($moduleDependency, ' ')) {
324                 $moduleDependency = substr($moduleDependency, 0, $space);
325             }
326
327             if ($this->isValidDependency($moduleDependency, $extension, $extensions)) {
328                 $dependencies[$moduleDependency] = 'drupal/'.$moduleDependency;
329             }
330         }
331
332         // Dependencies defined at composer.json
333         $composer = $this->readComposerFile($extension->getPath() . '/composer.json');
334         if (array_key_exists('require', $composer)) {
335             foreach (array_keys($composer['require']) as $package) {
336                 if (strpos($package, 'drupal/') !== 0) {
337                     continue;
338                 }
339                 $moduleDependency = str_replace('drupal/', '', $package);
340                 if ($this->isValidDependency($moduleDependency, $extension, $extensions)) {
341                     $dependencies[$moduleDependency] = $package;
342                 }
343             }
344         }
345
346         return $dependencies;
347     }
348
349     protected function readComposerFile($file)
350     {
351         if (!file_exists($file)) {
352             return [];
353         }
354
355         return Json::decode(file_get_contents($file));
356     }
357
358     /**
359      * @param $version
360      * @return mixed
361      */
362     private function calculateVersion($version)
363     {
364         $replaceKeys = [
365             '8.x-' => '',
366             '8.' => ''
367         ];
368         return str_replace(
369             array_keys($replaceKeys),
370             array_values($replaceKeys),
371             $version
372         );
373     }
374 }