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(); |
||
0 ignored issues
–
show
|
|||
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 | $this->configureEnvironmentForBehaviour($behaviourFlags); |
||
146 | |||
147 | $outputTriggers = $this->resolveOutputTriggers($filters, $behaviourFlags); |
||
148 | $bootstrapFactory = new \Vaimo\ComposerPatches\Factories\BootstrapFactory($composerContext, $appIO); |
||
149 | |||
150 | $outputStrategy = new \Vaimo\ComposerPatches\Strategies\OutputStrategy($outputTriggers); |
||
151 | $bootstrap = $bootstrapFactory->create($configFactory, $listResolver, $outputStrategy); |
||
152 | $compatExecutor = new \Vaimo\ComposerPatches\Compatibility\Executor(); |
||
153 | |||
154 | $runtimeUtils = new \Vaimo\ComposerPatches\Utils\RuntimeUtils(); |
||
155 | $lockSanitizer = new \Vaimo\ComposerPatches\Repository\Lock\Sanitizer($appIO); |
||
156 | $repository = $composer->getRepositoryManager()->getLocalRepository(); |
||
157 | $installationManager = $composer->getInstallationManager(); |
||
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 ($installationManager, $repository, $lockSanitizer, $isDevMode, $compatExecutor) { |
||
170 | $compatExecutor->repositoryWrite($repository, $installationManager, $isDevMode); |
||
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 |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.