Completed
Push — master ( 59bc3e...2295a6 )
by
unknown
31s queued 12s
created

PatchCommand::configure()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 80
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 1
eloc 57
c 2
b 0
f 1
nc 1
nop 0
dl 0
loc 80
rs 8.9381

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Copyright © Vaimo Group. All rights reserved.
4
 * See LICENSE_VAIMO.txt for license details.
5
 */
6
namespace Vaimo\ComposerPatches\Composer\Commands;
7
8
use Symfony\Component\Console\Input\InputInterface;
9
use Symfony\Component\Console\Output\OutputInterface;
10
use Symfony\Component\Console\Input\InputOption;
11
use Symfony\Component\Console\Input\InputArgument;
12
13
use Composer\Script\ScriptEvents;
14
15
use Vaimo\ComposerPatches\Patch\Definition as Patch;
16
use Vaimo\ComposerPatches\Repository\PatchesApplier\ListResolvers;
17
use Vaimo\ComposerPatches\Config;
18
use Vaimo\ComposerPatches\Interfaces\ListResolverInterface;
19
use Vaimo\ComposerPatches\Composer\Plugin\Behaviour;
20
use Vaimo\ComposerPatches\Environment;
21
22
/**
23
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
24
 */
25
class PatchCommand extends \Composer\Command\BaseCommand
26
{
27
    protected function configure()
28
    {
29
        $this->setName('patch');
30
        $this->setDescription('Apply registered patches to current project');
31
32
        $this->addArgument(
33
            'targets',
34
            InputArgument::IS_ARRAY,
35
            'Packages for the patcher to target',
36
            array()
37
        );
38
39
        $this->addOption(
40
            '--redo',
41
            null,
42
            InputOption::VALUE_NONE,
43
            'Re-patch all packages or a specific package when targets defined'
44
        );
45
46
        $this->addOption(
47
            '--undo',
48
            null,
49
            InputOption::VALUE_NONE,
50
            'Remove all patches or a specific patch when targets defined'
51
        );
52
53
        $this->addOption(
54
            '--no-dev',
55
            null,
56
            InputOption::VALUE_NONE,
57
            'Disables installation of require-dev packages'
58
        );
59
60
        $this->addOption(
61
            '--filter',
62
            null,
63
            InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
64
            'Apply only those patch files/sources that match with provided filter'
65
        );
66
        
67
        $this->addOption(
68
            '--explicit',
69
            null,
70
            InputOption::VALUE_NONE,
71
            'Show information for every patch that gets re-applied (due to package reset)'
72
        );
73
74
        $this->addOption(
75
            '--show-reapplies',
76
            null,
77
            InputOption::VALUE_NONE,
78
            'Alias for \'explicit\' argument'
79
        );
80
        
81
        $this->addOption(
82
            '--from-source',
83
            null,
84
            InputOption::VALUE_NONE,
85
            'Apply patches based on information directly from packages in vendor folder'
86
        );
87
88
        $this->addOption(
89
            '--graceful',
90
            null,
91
            InputOption::VALUE_NONE,
92
            'Continue even when some patch fails to apply'
93
        );
94
95
        $this->addOption(
96
            '--force',
97
            null,
98
            InputOption::VALUE_NONE,
99
            'Force package reset even when it has local change'
100
        );
101
102
        $this->addOption(
103
            '--no-scripts',
104
            null,
105
            InputOption::VALUE_NONE,
106
            'Skips the execution of all scripts defined in composer.json file.'
107
        );
108
    }
109
    
110
    /**
111
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
112
     *
113
     * @param InputInterface $input
114
     * @param OutputInterface $output
115
     * @return int|void|null
116
     * @throws \Exception
117
     */
118
    protected function execute(InputInterface $input, OutputInterface $output)
119
    {
120
        $composer = $this->getComposer();
121
122
        $appIO = $this->getIO();
123
        
124
        $isDevMode = !$input->getOption('no-dev');
125
126
        $behaviourFlags = $this->getBehaviourFlags($input);
127
128
        $shouldUndo = !$behaviourFlags[Behaviour::REDO] && $behaviourFlags[Behaviour::UNDO];
129
130
        $contextFactory = new \Vaimo\ComposerPatches\Factories\ComposerContextFactory($composer);
131
        $composerContext = $contextFactory->create();
132
133
        $configFactory = new \Vaimo\ComposerPatches\Factories\ConfigFactory($composerContext, array(
134
            Config::PATCHER_FORCE_REAPPLY => $behaviourFlags[Behaviour::REDO],
135
            Config::PATCHER_FROM_SOURCE => (bool)$input->getOption('from-source'),
136
            Config::PATCHER_GRACEFUL => (bool)$input->getOption('graceful')
137
                || $behaviourFlags[Behaviour::REDO]
138
                || $behaviourFlags[Behaviour::UNDO],
139
            Config::PATCHER_SOURCES => $this->createSourcesEnablerConfig()
140
        ));
141
        
142
        $filters = $this->resolveActiveFilters($input, $behaviourFlags);
143
        
144
        $listResolver = $this->createListResolver($behaviourFlags, $filters);
145
        
146
        $this->configureEnvironmentForBehaviour($behaviourFlags);
147
148
        $outputTriggers = $this->resolveOutputTriggers($filters, $behaviourFlags);
149
        
150
        $bootstrapFactory = new \Vaimo\ComposerPatches\Factories\BootstrapFactory($composerContext, $appIO);
151
        
152
        $outputStrategy = new \Vaimo\ComposerPatches\Strategies\OutputStrategy($outputTriggers);
153
        $bootstrap = $bootstrapFactory->create($configFactory, $listResolver, $outputStrategy);
154
155
        $runtimeUtils = new \Vaimo\ComposerPatches\Utils\RuntimeUtils();
156
        $lockSanitizer = new \Vaimo\ComposerPatches\Repository\Lock\Sanitizer($appIO);
157
        $repository = $composer->getRepositoryManager()->getLocalRepository();
158
        
159
        $result = $runtimeUtils->executeWithPostAction(
160
            function () use ($shouldUndo, $filters, $bootstrap, $isDevMode) {
161
                if ($shouldUndo && !array_filter($filters)) {
162
                    $bootstrap->stripPatches($isDevMode);
163
                    
164
                    return true;
165
                }
166
167
                return $bootstrap->applyPatches($isDevMode);
168
            },
169
            function () use ($repository, $lockSanitizer) {
170
                $repository->write();
171
                $lockSanitizer->sanitize();
172
            }
173
        );
174
175
        if (!$input->getOption('no-scripts')) {
176
            $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_INSTALL_CMD, $isDevMode);
177
        }
178
179
        return (int)!$result;
180
    }
181
    
182
    private function createSourcesEnablerConfig()
183
    {
184
        $configDefaults = new \Vaimo\ComposerPatches\Config\Defaults();
185
186
        $defaultValues = $configDefaults->getPatcherConfig();
187
        
188
        if (isset($defaultValues[Config::PATCHER_SOURCES]) && is_array($defaultValues[Config::PATCHER_SOURCES])) {
189
            $sourceTypes = array_keys((array)$defaultValues[Config::PATCHER_SOURCES]);
190
191
            return array_fill_keys($sourceTypes, true);
192
        }
193
194
        return array();
195
    }
196
197
    protected function getBehaviourFlags(InputInterface $input)
198
    {
199
        return array(
200
            Behaviour::REDO => $this->getOptionGraceful($input, 'redo'),
201
            Behaviour::UNDO => $this->getOptionGraceful($input, 'undo'),
202
            Behaviour::FORCE => $this->getOptionGraceful($input, 'force'),
203
            Behaviour::EXPLICIT => $this->getOptionGraceful($input, 'explicit')
204
                || $this->getOptionGraceful($input, 'show-reapplies')
205
        );
206
    }
207
    
208
    private function getOptionGraceful(InputInterface $input, $name)
209
    {
210
        return $input->hasOption($name) && $input->getOption($name);
211
    }
212
    
213
    private function resolveActiveFilters(InputInterface $input, array $behaviourFlags)
214
    {
215
        $filters = array(
216
            Patch::SOURCE => $input->getOption('filter'),
217
            Patch::TARGETS => $input->getArgument('targets')
218
        );
219
220
        $hasFilers = (bool)array_filter($filters);
221
222
        if (!$hasFilers && $behaviourFlags[Behaviour::REDO]) {
223
            $filters[Patch::SOURCE] = array('*');
224
        }
225
226
        return $filters;
227
    }
228
    
229
    private function configureEnvironmentForBehaviour(array $behaviourFlags)
230
    {
231
        $runtimeUtils = new \Vaimo\ComposerPatches\Utils\RuntimeUtils();
232
233
        $runtimeUtils->setEnvironmentValues(array(
234
            Environment::FORCE_RESET => (int)$behaviourFlags[Behaviour::FORCE]
235
        ));
236
    }
237
    
238
    private function resolveOutputTriggers(array $filters, array $behaviourFlags)
239
    {
240
        $hasFilers = (bool)array_filter($filters);
241
242
        $isExplicit = $behaviourFlags[Behaviour::EXPLICIT];
243
        
244
        if (!$hasFilers && $behaviourFlags[Behaviour::REDO]) {
245
            $isExplicit = true;
246
        }
247
        
248
        $outputTriggerFlags = array(
249
            Patch::STATUS_NEW => !$hasFilers,
250
            Patch::STATUS_CHANGED => !$hasFilers,
251
            Patch::STATUS_MATCH => true,
252
            Patch::SOURCE => $isExplicit,
253
            Patch::URL => $isExplicit
254
        );
255
256
        return array_keys(
257
            array_filter($outputTriggerFlags)
258
        );
259
    }
260
    
261
    private function createListResolver(array $behaviourFlags, array $filters)
262
    {
263
        $listResolver = new ListResolvers\FilteredListResolver($filters);
264
265
        $isDefaultBehaviour = !$behaviourFlags[Behaviour::REDO] && !$behaviourFlags[Behaviour::UNDO];
266
267
        $listResolver = $this->attachBehaviourToListResolver($listResolver, $behaviourFlags);
268
        
269
        if ($isDefaultBehaviour) {
270
            $listResolver = new ListResolvers\ChangesListResolver($listResolver);
271
        }
272
        
273
        return $listResolver;
274
    }
275
    
276
    private function attachBehaviourToListResolver(ListResolverInterface $listResolver, array $behaviourFlags)
277
    {
278
        $shouldUndo = !$behaviourFlags[Behaviour::REDO] && $behaviourFlags[Behaviour::UNDO];
279
280
        if ($shouldUndo) {
281
            return new ListResolvers\InvertedListResolver($listResolver);
282
        }
283
284
        return new ListResolvers\InclusiveListResolver($listResolver);
285
    }
286
}
287