Failed Conditions
Push — master ( 4ce244...5643f1 )
by Bernhard
11s
created

PuliPluginImpl::preAutoloadDump()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 45
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 6.1666

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 45
ccs 20
cts 24
cp 0.8333
rs 8.439
cc 6
eloc 25
nc 12
nop 0
crap 6.1666
1
<?php
2
3
/*
4
 * This file is part of the puli/composer-plugin package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Puli\ComposerPlugin;
13
14
use Composer\Composer;
15
use Composer\Config;
16
use Composer\IO\IOInterface;
17
use Composer\Package\AliasPackage;
18
use Composer\Package\PackageInterface;
19
use Composer\Script\Event;
20
use Exception;
21
use RuntimeException;
22
use Symfony\Component\Filesystem\Filesystem;
23
use Webmozart\PathUtil\Path;
24
25
/**
26
 * Implementation of the Puli plugin.
27
 *
28
 * This class is separate from the main {@link PuliPlugin} class so that it can
29
 * be loaded lazily after updating the sources of this package in the project
30
 * that requires the package.
31
 *
32
 * @author Bernhard Schussek <[email protected]>
33
 */
34
class PuliPluginImpl
35
{
36
    /**
37
     * The version of the Puli plugin.
38
     */
39
    const VERSION = '@package_version@';
40
41
    /**
42
     * The minimum version of the Puli CLI.
43
     */
44
    const MIN_CLI_VERSION = '1.0.0-beta10';
45
46
    /**
47
     * The maximum version of the Puli CLI.
48
     */
49
    const MAX_CLI_VERSION = '1.999.99999';
50
51
    /**
52
     * The name of the installer.
53
     */
54
    const INSTALLER_NAME = 'composer';
55
56
    /**
57
     * @var Composer
58
     */
59
    private $composer;
60
61
    /**
62
     * @var IOInterface
63
     */
64
    private $io;
65
66
    /**
67
     * @var Config
68
     */
69
    private $config;
70
71
    /**
72
     * @var bool
73
     */
74
    private $isDev;
75
76
    /**
77
     * @var PuliRunner
78
     */
79
    private $puliRunner;
80
81
    /**
82
     * @var string
83
     */
84
    private $rootDir;
85
86
    /**
87
     * @var bool
88
     */
89
    private $runPreAutoloadDump = true;
90
91
    /**
92
     * @var bool
93
     */
94
    private $runPostAutoloadDump = true;
95
96
    /**
97
     * @var bool
98
     */
99
    private $runPostInstall = true;
100
101
    /**
102
     * @var bool
103
     */
104
    private $initialized = false;
105
106
    /**
107
     * @var string
108
     */
109
    private $autoloadFile;
110
111 42
    public function __construct(Event $event, PuliRunner $puliRunner = null)
112
    {
113 42
        $this->composer = $event->getComposer();
114 42
        $this->io = $event->getIO();
115 42
        $this->config = $this->composer->getConfig();
116 42
        $this->isDev = $event->isDevMode();
117 42
        $this->puliRunner = $puliRunner;
118 42
        $this->rootDir = Path::normalize(getcwd());
119
120 42
        $vendorDir = $this->config->get('vendor-dir');
121
122
        // On TravisCI, $vendorDir is a relative path. Probably an old Composer
123
        // build or something. Usually, $vendorDir should be absolute already.
124 42
        $vendorDir = Path::makeAbsolute($vendorDir, $this->rootDir);
125
126 42
        $this->autoloadFile = $vendorDir.'/autoload.php';
127 42
    }
128
129 3
    public function preAutoloadDump()
130
    {
131 3
        if (!$this->initialized) {
132 3
            $this->initialize();
133
        }
134
135
        // This method is called twice. Run it only once.
136 3
        if (!$this->runPreAutoloadDump) {
137
            return;
138
        }
139
140 3
        $this->runPreAutoloadDump = false;
141
142
        try {
143 3
            $factoryClass = $this->getConfigKey('factory.in.class');
144 3
            $factoryFile = $this->getConfigKey('factory.in.file');
145
        } catch (PuliRunnerException $e) {
146
            $this->printWarning('Could not load Puli configuration', $e);
147
148
            return;
149
        }
150
151 3
        $factoryFile = Path::makeAbsolute($factoryFile, $this->rootDir);
0 ignored issues
show
Bug introduced by
It seems like $factoryFile can also be of type boolean or null; however, Webmozart\PathUtil\Path::makeAbsolute() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
152
153 3
        $autoload = $this->composer->getPackage()->getAutoload();
154 3
        $autoload['classmap'][] = $factoryFile;
155
156 3
        $this->composer->getPackage()->setAutoload($autoload);
157
158 3
        if (!file_exists($factoryFile)) {
159 2
            $filesystem = new Filesystem();
160
            // Let Composer find the factory class with a temporary stub
161
162 2
            $namespace = explode('\\', ltrim($factoryClass, '\\'));
163 2
            $className = array_pop($namespace);
164
165 2
            if (count($namespace)) {
166 1
                $stub = '<?php namespace '.implode('\\', $namespace).'; class '.$className.' {}';
167
            } else {
168 1
                $stub = '<?php class '.$className.' {}';
169
            }
170
171 2
            $filesystem->dumpFile($factoryFile, $stub);
172
        }
173 3
    }
174
175 5
    public function postAutoloadDump()
176
    {
177 5
        if (!$this->initialized) {
178 5
            $this->initialize();
179
        }
180
181
        // This method is called twice. Run it only once.
182 5
        if (!$this->runPostAutoloadDump) {
183 1
            return;
184
        }
185
186 5
        $this->runPostAutoloadDump = false;
187
188
        try {
189 5
            $factoryClass = $this->getConfigKey('factory.in.class');
190 1
        } catch (PuliRunnerException $e) {
191 1
            $this->printWarning('Could not load Puli configuration', $e);
192
193 1
            return;
194
        }
195
196 4
        $this->insertFactoryClassConstant($this->autoloadFile, $factoryClass);
197 4
        $this->setBootstrapFile($this->autoloadFile);
198 4
    }
199
200
    /**
201
     * Updates the Puli repository after Composer installations/updates.
202
     */
203 34
    public function postInstall()
204
    {
205 34
        if (!$this->initialized) {
206 34
            $this->initialize();
207
        }
208
209
        // This method is called twice. Run it only once.
210 34
        if (!$this->runPostInstall) {
211 3
            return;
212
        }
213
214 32
        $this->runPostInstall = false;
215
216 32
        $this->io->write('<info>Synchronizing Puli with Composer</info>');
217
218 32
        $rootPackage = $this->composer->getPackage();
219 32
        $composerPackages = $this->loadComposerPackages();
220 32
        $prodPackageNames = $this->filterProdPackageNames($composerPackages, $rootPackage);
221 32
        $env = $this->isDev ? PuliPackage::ENV_DEV : PuliPackage::ENV_PROD;
222
223
        try {
224 32
            $puliPackages = $this->loadPuliPackages();
225 1
        } catch (PuliRunnerException $e) {
226 1
            $this->printWarning('Could not load Puli packages', $e);
227
228 1
            return;
229
        }
230
231
        // Don't remove non-existing packages in production environment
232
        // Removed packages could be dev dependencies (i.e. "require-dev"
233
        // of the root package or "require" of another dev dependency), and
234
        // we can't find out whether they are since Composer doesn't load them
235 31
        if (PuliPackage::ENV_PROD !== $env) {
236 3
            $this->removeRemovedPackages($composerPackages, $puliPackages);
237
        }
238
239 31
        $this->installNewPackages($composerPackages, $prodPackageNames, $puliPackages);
240
241
        // Don't print warnings for non-existing packages in production
242 31
        if (PuliPackage::ENV_PROD !== $env) {
243 3
            $this->checkForNotFoundErrors($puliPackages);
244
        }
245
246 31
        $this->checkForNotLoadableErrors($puliPackages);
247 31
        $this->adoptComposerName($puliPackages);
248 31
        $this->removePuliDir();
249 31
        $this->buildPuli();
250 31
    }
251
252 42
    private function initialize()
253
    {
254 42
        if (!file_exists($this->autoloadFile)) {
255
            $filesystem = new Filesystem();
256
            // Avoid problems if using the runner before autoload.php has been
257
            // generated
258
            $filesystem->dumpFile($this->autoloadFile, '');
259
        }
260
261 42
        $this->initialized = true;
262
263
        // Keep the manually set runner
264 42
        if (null === $this->puliRunner) {
265
            try {
266
                // Add Composer's bin directory in case the "puli" executable is
267
                // installed with Composer
268
                $this->puliRunner = new PuliRunner($this->config->get('bin-dir'));
269
            } catch (RuntimeException $e) {
270
                $this->printWarning('Plugin initialization failed', $e);
271
                $this->runPreAutoloadDump = false;
272
                $this->runPostAutoloadDump = false;
273
                $this->runPostInstall = false;
274
            }
275
        }
276
277
        // Use the runner to verify if Puli has the right version
278
        try {
279 42
            $this->verifyPuliVersion();
280 2
        } catch (RuntimeException $e) {
281 2
            $this->printWarning('Version check failed', $e);
282 2
            $this->runPreAutoloadDump = false;
283 2
            $this->runPostAutoloadDump = false;
284 2
            $this->runPostInstall = false;
285
        }
286 42
    }
287
288
    /**
289
     * @param PackageInterface[] $composerPackages
290
     * @param bool[]             $prodPackageNames
291
     * @param PuliPackage[]      $puliPackages
292
     */
293 31
    private function installNewPackages(array $composerPackages, array $prodPackageNames, array &$puliPackages)
294
    {
295 31
        $installationManager = $this->composer->getInstallationManager();
296
297 31
        foreach ($composerPackages as $packageName => $package) {
298 21
            if ($package instanceof AliasPackage) {
299 2
                $package = $package->getAliasOf();
300
            }
301
302
            // We need to normalize the system-dependent paths returned by Composer
303 21
            $installPath = Path::normalize($installationManager->getInstallPath($package));
304 21
            $env = isset($prodPackageNames[$packageName]) ? PuliPackage::ENV_PROD : PuliPackage::ENV_DEV;
305
306
            // Skip meta packages
307 21
            if ('' === $installPath) {
308 1
                continue;
309
            }
310
311 20
            if (isset($puliPackages[$packageName])) {
312 15
                $puliPackage = $puliPackages[$packageName];
313
314
                // Only proceed if the install path or environment has changed
315 15
                if ($installPath === $puliPackage->getInstallPath() && $env === $puliPackage->getEnvironment()) {
316 14
                    continue;
317
                }
318
319
                // Only remove packages installed by Composer
320 6
                if (self::INSTALLER_NAME === $puliPackage->getInstallerName()) {
321 5
                    $this->io->write(sprintf(
322 5
                        'Reinstalling <info>%s</info> (<comment>%s</comment>) in <comment>%s</comment>',
323
                        $packageName,
324 5
                        Path::makeRelative($installPath, $this->rootDir),
325
                        $env
326
                    ));
327
328
                    try {
329 5
                        $this->removePackage($packageName);
330 1
                    } catch (PuliRunnerException $e) {
331 1
                        $this->printPackageWarning('Could not remove package "%s" (at "%s")', $packageName, $installPath, $e);
332
333 6
                        continue;
334
                    }
335
                }
336
            } else {
337 6
                $this->io->write(sprintf(
338 6
                    'Installing <info>%s</info> (<comment>%s</comment>) in <comment>%s</comment>',
339
                    $packageName,
340 6
                    Path::makeRelative($installPath, $this->rootDir),
341
                    $env
342
                ));
343
            }
344
345
            try {
346 11
                $this->installPackage($installPath, $packageName, $env);
347 3
            } catch (PuliRunnerException $e) {
348 3
                $this->printPackageWarning('Could not install package "%s" (at "%s")', $packageName, $installPath, $e);
349
350 3
                continue;
351
            }
352
353 8
            $puliPackages[$packageName] = new PuliPackage(
354
                $packageName,
355 8
                self::INSTALLER_NAME,
356
                $installPath,
357 8
                PuliPackage::STATE_ENABLED,
358
                $env
359
            );
360
        }
361 31
    }
362
363
    /**
364
     * @param PackageInterface[] $composerPackages
365
     * @param PuliPackage[]      $puliPackages
366
     */
367 3
    private function removeRemovedPackages(array $composerPackages, array &$puliPackages)
368
    {
369
        /** @var PuliPackage[] $notFoundPackages */
370
        $notFoundPackages = array_filter($puliPackages, function (PuliPackage $package) {
371 3
            return PuliPackage::STATE_NOT_FOUND === $package->getState()
372 3
                && PuliPluginImpl::INSTALLER_NAME === $package->getInstallerName();
373 3
        });
374
375 3
        foreach ($notFoundPackages as $packageName => $package) {
376
            // Check whether package was only moved
377 3
            if (isset($composerPackages[$packageName])) {
378 1
                continue;
379
            }
380
381 2
            $this->io->write(sprintf(
382 2
                'Removing <info>%s</info> (<comment>%s</comment>)',
383
                $packageName,
384 2
                Path::makeRelative($package->getInstallPath(), $this->rootDir)
385
            ));
386
387
            try {
388 2
                $this->removePackage($packageName);
389 1
            } catch (PuliRunnerException $e) {
390 1
                $this->printPackageWarning('Could not remove package "%s" (at "%s")', $packageName, $package->getInstallPath(), $e);
391
392 1
                continue;
393
            }
394
395 1
            unset($puliPackages[$packageName]);
396
        }
397 3
    }
398
399 3 View Code Duplication
    private function checkForNotFoundErrors(array $puliPackages)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
400
    {
401
        /** @var PuliPackage[] $notFoundPackages */
402 3
        $notFoundPackages = array_filter($puliPackages,
403
            function (PuliPackage $package) {
404 3
                return PuliPackage::STATE_NOT_FOUND === $package->getState()
405 3
                && PuliPluginImpl::INSTALLER_NAME === $package->getInstallerName();
406 3
            });
407
408 3
        foreach ($notFoundPackages as $package) {
409 2
            $this->printPackageWarning(
410 2
                'The package "%s" (at "%s") could not be found',
411 2
                $package->getName(),
412 2
                $package->getInstallPath()
413
            );
414
        }
415 3
    }
416
417 31 View Code Duplication
    private function checkForNotLoadableErrors(array $puliPackages)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
418
    {
419
        /** @var PuliPackage[] $notLoadablePackages */
420
        $notLoadablePackages = array_filter($puliPackages, function (PuliPackage $package) {
421 31
            return PuliPackage::STATE_NOT_LOADABLE === $package->getState()
422 31
                && PuliPluginImpl::INSTALLER_NAME === $package->getInstallerName();
423 31
        });
424
425 31
        foreach ($notLoadablePackages as $package) {
426 1
            $this->printPackageWarning(
427 1
                'The package "%s" (at "%s") could not be loaded',
428 1
                $package->getName(),
429 1
                $package->getInstallPath()
430
            );
431
        }
432 31
    }
433
434 31
    private function adoptComposerName(array $puliPackages)
435
    {
436 31
        $rootDir = $this->rootDir;
437
438
        /** @var PuliPackage[] $rootPackages */
439 31
        $rootPackages = array_filter($puliPackages, function (PuliPackage $package) use ($rootDir) {
440 31
            return !$package->getInstallerName() && $rootDir === $package->getInstallPath();
441 31
        });
442
443 31
        if (0 === count($rootPackages)) {
444
            // This should never happen
445
            $this->printWarning('No root package could be found');
446
447
            return;
448
        }
449
450 31
        if (count($rootPackages) > 1) {
451
            // This should never happen
452
            $this->printWarning('More than one root package was found');
453
454
            return;
455
        }
456
457
        /** @var PuliPackage $rootPackage */
458 31
        $rootPackage = reset($rootPackages);
459 31
        $name = $rootPackage->getName();
460 31
        $newName = $this->composer->getPackage()->getName();
461
462
        // Rename the root package after changing the name in composer.json
463 31
        if ($name !== $newName) {
464
            try {
465 2
                $this->renamePackage($name, $newName);
466 1
            } catch (PuliRunnerException $e) {
467 1
                $this->printWarning(sprintf(
468 1
                    'Could not rename root package to "%s"',
469
                    $newName
470
                ), $e);
471
            }
472
        }
473 31
    }
474
475 4
    private function insertFactoryClassConstant($autoloadFile, $factoryClass)
476
    {
477 4
        if (!file_exists($autoloadFile)) {
478
            throw new PuliPluginException(sprintf(
479
                'Could not adjust autoloader: The file %s was not found.',
480
                $autoloadFile
481
            ));
482
        }
483
484 4
        $this->io->write('<info>Generating the "PULI_FACTORY_CLASS" constant</info>');
485
486 4
        $contents = file_get_contents($autoloadFile);
487 4
        $escFactoryClass = var_export($factoryClass, true);
488 4
        $constant = "if (!defined('PULI_FACTORY_CLASS')) {\n";
489 4
        $constant .= sprintf("    define('PULI_FACTORY_CLASS', %s);\n", $escFactoryClass);
490 4
        $constant .= "}\n\n";
491
492
        // Regex modifiers:
493
        // "m": \s matches newlines
494
        // "D": $ matches at EOF only
495
        // Translation: insert before the last "return" in the file
496 4
        $contents = preg_replace('/\n(?=return [^;]+;\s*$)/mD', "\n".$constant,
497
            $contents);
498
499 4
        file_put_contents($autoloadFile, $contents);
500 4
    }
501
502 4
    private function setBootstrapFile($autoloadFile)
503
    {
504 4
        $bootstrapFile = $this->getConfigKey('bootstrap-file');
505
506
        // Don't change user-defined bootstrap files
507 4
        if (!empty($bootstrapFile)) {
508 1
            return;
509
        }
510
511 3
        $relAutoloadFile = Path::makeRelative($autoloadFile, $this->rootDir);
512
513 3
        $this->io->write(sprintf('<info>Setting "bootstrap-file" to "%s"</info>', $relAutoloadFile));
514
515 3
        $this->setConfigKey('bootstrap-file', $relAutoloadFile);
516 3
    }
517
518
    /**
519
     * Loads Composer's currently installed packages.
520
     *
521
     * @return PackageInterface[] The installed packages indexed by their names.
522
     */
523 32
    private function loadComposerPackages()
524
    {
525 32
        $repository = $this->composer->getRepositoryManager()->getLocalRepository();
526 32
        $packages = array();
527
528 32
        foreach ($repository->getPackages() as $package) {
529
            /* @var PackageInterface $package */
530 21
            $packages[$package->getName()] = $package;
531
        }
532
533 32
        return $packages;
534
    }
535
536 39
    private function getConfigKey($key)
537
    {
538 39
        $value = trim($this->puliRunner->run('config %key% --parsed', array(
539 39
            'key' => $key,
540
        )));
541
542
        switch ($value) {
543 38
            case 'null':
544 1
                return null;
545 38
            case 'true':
546
                return true;
547 38
            case 'false':
548
                return false;
549
            default:
550 38
                return $value;
551
        }
552
    }
553
554 3
    private function setConfigKey($key, $value)
555
    {
556 3
        $this->puliRunner->run('config %key% %value%', array(
557 3
            'key' => $key,
558 3
            'value' => $value,
559
        ));
560 3
    }
561
562
    /**
563
     * @return PuliPackage[]
564
     */
565 32
    private function loadPuliPackages()
566
    {
567 32
        $packages = array();
568
569 32
        $output = $this->puliRunner->run('package --list --format %format%', array(
570 32
            'format' => '%name%;%installer%;%install_path%;%state%;%env%',
571
        ));
572
573
        // PuliRunner replaces \r\n by \n for those Windows boxes
574 31
        foreach (explode("\n", $output) as $packageLine) {
575 31
            if (!$packageLine) {
576 31
                continue;
577
            }
578
579 31
            $packageParts = explode(';', $packageLine);
580
581 31
            $packages[$packageParts[0]] = new PuliPackage(
582 31
                $packageParts[0],
583 31
                $packageParts[1],
584 31
                $packageParts[2],
585 31
                $packageParts[3],
586 31
                $packageParts[4]
587
            );
588
        }
589
590 31
        return $packages;
591
    }
592
593 11
    private function installPackage($installPath, $packageName, $env)
594
    {
595 11
        $env = PuliPackage::ENV_DEV === $env ? ' --dev' : '';
596
597 11
        $this->puliRunner->run('package --install %path% %package_name% --installer %installer%'.$env, array(
598 11
            'path' => $installPath,
599 11
            'package_name' => $packageName,
600 11
            'installer' => self::INSTALLER_NAME,
601
        ));
602 8
    }
603
604 7
    private function removePackage($packageName)
605
    {
606 7
        $this->puliRunner->run('package --delete %package_name%', array(
607 7
            'package_name' => $packageName,
608
        ));
609 5
    }
610
611 31
    private function removePuliDir()
612
    {
613 31
        $relativePuliDir = rtrim($this->getConfigKey('puli-dir'), '/');
614
615 31
        $puliDir = Path::makeAbsolute($relativePuliDir, $this->rootDir);
616
617
        // Only remove existing sub-directories of the root directory
618 31
        if (!file_exists($puliDir) || 0 !== strpos($puliDir, $this->rootDir.'/')) {
619 30
            return;
620
        }
621
622 1
        $this->io->write(sprintf('<info>Deleting the "%s" directory</info>', $relativePuliDir));
623
624
        // Remove the .puli directory to prevent upgrade problems
625 1
        $filesystem = new Filesystem();
626 1
        $filesystem->remove($puliDir);
627 1
    }
628
629 31
    private function buildPuli()
630
    {
631 31
        $this->io->write('<info>Running "puli build"</info>');
632
633 31
        $this->puliRunner->run('build');
634 31
    }
635
636 2
    private function renamePackage($name, $newName)
637
    {
638 2
        $this->puliRunner->run('package --rename %old_name% %new_name%', array(
639 2
            'old_name' => $name,
640 2
            'new_name' => $newName,
641
        ));
642 1
    }
643
644
    /**
645
     * @param                $message
646
     * @param Exception|null $exception
647
     */
648 12
    private function printWarning($message, Exception $exception = null)
649
    {
650 12
        if (!$exception) {
651 3
            $reasonPhrase = '';
652 10
        } elseif ($this->io->isVerbose()) {
653
            $reasonPhrase = $exception instanceof PuliRunnerException
654
                ? $exception->getFullError()
655
                : $exception->getMessage()."\n\n".$exception->getTraceAsString();
656
        } else {
657 10
            $reasonPhrase = $exception instanceof PuliRunnerException
658 8
                ? $exception->getShortError()
659 10
                : $exception->getMessage();
660
        }
661
662 12
        $this->io->writeError(sprintf(
663 12
            '<warning>Warning: %s%s</warning>',
664
            $message,
665 12
            $reasonPhrase ? ': '.$reasonPhrase : '.'
666
        ));
667 12
    }
668
669 7
    private function printPackageWarning($message, $packageName, $installPath, PuliRunnerException $exception = null)
670
    {
671 7
        $this->printWarning(sprintf(
672
            $message,
673
            $packageName,
674 7
            Path::makeRelative($installPath, $this->rootDir)
675
        ), $exception);
676 7
    }
677
678 32
    private function filterProdPackageNames(array $composerPackages, PackageInterface $package, array &$result = array())
679
    {
680
        // Resolve aliases
681 32
        if ($package instanceof AliasPackage) {
682 2
            $package = $package->getAliasOf();
683
        }
684
685
        // Package was processed already
686 32
        if (isset($result[$package->getName()])) {
687
            return $result;
688
        }
689
690 32
        $result[$package->getName()] = true;
691
692
        // Recursively filter package names
693 32
        foreach ($package->getRequires() as $packageName => $link) {
694 21
            if (isset($composerPackages[$packageName])) {
695 21
                $this->filterProdPackageNames($composerPackages, $composerPackages[$packageName], $result);
696
            }
697
        }
698
699 32
        return $result;
700
    }
701
702 42
    private function verifyPuliVersion()
703
    {
704 42
        $versionString = $this->puliRunner->run('-V');
705
706 42
        if (!preg_match('~^Puli version (\S+)$~', $versionString, $matches)) {
707
            throw new RuntimeException(sprintf(
708
                'Could not determine Puli version. "puli -V" returned: %s',
709
                $versionString
710
            ));
711
        }
712
713
        // the development build of the plugin is always considered compatible
714
        // with the development build of the CLI
715
        // Split strings to prevent replacement during release
716 42
        if ('@package_'.'version@' === self::VERSION && '@package_'.'version@' === $matches[1]) {
717 1
            return;
718
        }
719
720 41 View Code Duplication
        if (version_compare($matches[1], self::MIN_CLI_VERSION, '<')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
721 1
            throw new RuntimeException(sprintf(
722
                'Found an unsupported version of the Puli CLI: %s. Please '.
723
                'upgrade to version %s or higher. You can also install the '.
724 1
                'puli/cli dependency at version %s in your project.',
725 1
                $matches[1],
726 1
                self::MIN_CLI_VERSION,
727 1
                self::MIN_CLI_VERSION
728
            ));
729
        }
730
731 40 View Code Duplication
        if (version_compare($matches[1], self::MAX_CLI_VERSION, '>')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
732 1
            throw new RuntimeException(sprintf(
733
                'Found an unsupported version of the Puli CLI: %s. Please '.
734
                'downgrade to a lower version than %s. You can also install '.
735 1
                'the puli/cli dependency in your project.',
736 1
                $matches[1],
737 1
                self::MAX_CLI_VERSION
738
            ));
739
        }
740 39
    }
741
}
742