Failed Conditions
Pull Request — master (#49)
by Helmut
04:20
created

src/PuliPluginImpl.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Json\JsonFile;
18
use Composer\Package\AliasPackage;
19
use Composer\Package\PackageInterface;
20
use Composer\Script\Event;
21
use Composer\Util\RemoteFilesystem;
22
use Exception;
23
use RuntimeException;
24
use Symfony\Component\Filesystem\Filesystem;
25
use Webmozart\PathUtil\Path;
26
27
/**
28
 * Implementation of the Puli plugin.
29
 *
30
 * This class is separate from the main {@link PuliPlugin} class so that it can
31
 * be loaded lazily after updating the sources of this package in the project
32
 * that requires the package.
33
 *
34
 * @author Bernhard Schussek <[email protected]>
35
 */
36
class PuliPluginImpl
37
{
38
    /**
39
     * The version of the Puli plugin.
40
     */
41
    const VERSION = '@package_version@';
42
43
    /**
44
     * The minimum version of the Puli CLI.
45
     */
46
    const MIN_CLI_VERSION = '1.0.0-beta10';
47
48
    /**
49
     * The maximum version of the Puli CLI.
50
     */
51
    const MAX_CLI_VERSION = '1.999.99999';
52
53
    /**
54
     * The name of the installer.
55
     */
56
    const INSTALLER_NAME = 'composer';
57
58
    /**
59
     * @var Composer
60
     */
61
    private $composer;
62
63
    /**
64
     * @var IOInterface
65
     */
66
    private $io;
67
68
    /**
69
     * @var Config
70
     */
71
    private $config;
72
73
    /**
74
     * @var bool
75
     */
76
    private $isDev;
77
78
    /**
79
     * @var PuliRunner
80
     */
81
    private $puliRunner;
82
83
    /**
84
     * @var string
85
     */
86
    private $rootDir;
87
88
    /**
89
     * @var bool
90
     */
91
    private $runPreAutoloadDump = true;
92
93
    /**
94
     * @var bool
95
     */
96
    private $runPostAutoloadDump = true;
97
98
    /**
99
     * @var bool
100
     */
101
    private $runPostInstall = true;
102
103
    /**
104
     * @var bool
105
     */
106
    private $initialized = false;
107
108 42
    public function __construct(Event $event, PuliRunner $puliRunner = null)
109
    {
110 42
        $this->composer = $event->getComposer();
111 42
        $this->io = $event->getIO();
112 42
        $this->config = $this->composer->getConfig();
113 42
        $this->isDev = $event->isDevMode();
114 42
        $this->puliRunner = $puliRunner;
115 42
        $this->rootDir = Path::normalize(getcwd());
116 42
    }
117
118 3
    public function preAutoloadDump()
119
    {
120
        // This method is called multiple times. Run it only once.
121 3
        if (!$this->runPreAutoloadDump) {
122
            return;
123
        }
124
125 3
        $this->runPreAutoloadDump = false;
126
127 3
        $factoryClass = $this->getConfigKeyFromJsonFile('factory.in.class');
128 3
        $factoryFile = $this->getConfigKeyFromJsonFile('factory.in.file');
129 3
        $factoryFile = Path::makeAbsolute($factoryFile, $this->rootDir);
130
131 3
        $autoload = $this->composer->getPackage()->getAutoload();
132 3
        $autoload['classmap'][] = $factoryFile;
133
134 3
        $this->composer->getPackage()->setAutoload($autoload);
135
136 3
        if (!file_exists($factoryFile)) {
137 3
            $filesystem = new Filesystem();
138
            // Let Composer find the factory class with a temporary stub
139
140 3
            $namespace = explode('\\', ltrim($factoryClass, '\\'));
141 3
            $className = array_pop($namespace);
142
143 3
            if (count($namespace)) {
144 3
                $stub = '<?php namespace '.implode('\\', $namespace).'; class '.$className.' {}';
145
            } else {
146
                $stub = '<?php class '.$className.' {}';
147
            }
148
149 3
            $filesystem->dumpFile($factoryFile, $stub);
150
        }
151 3
    }
152
153 5
    public function postAutoloadDump()
154
    {
155 5
        if (!$this->initialized) {
156 5
            $this->initialize();
157
        }
158
159
        // This method is called multiple times. Run it only once.
160 5
        if (!$this->runPostAutoloadDump) {
161 1
            return;
162
        }
163
164 5
        $this->runPostAutoloadDump = false;
165
166
        try {
167 5
            $factoryClass = $this->getConfigKey('factory.in.class');
168 1
        } catch (PuliRunnerException $e) {
169 1
            $this->printWarning('Could not load Puli configuration', $e);
170
171 1
            return;
172
        }
173
174 4
        $vendorDir = $this->config->get('vendor-dir');
175
176
        // On TravisCI, $vendorDir is a relative path. Probably an old Composer
177
        // build or something. Usually, $vendorDir should be absolute already.
178 4
        $vendorDir = Path::makeAbsolute($vendorDir, $this->rootDir);
179
180 4
        $autoloadFile = $vendorDir.'/autoload.php';
181 4
        $this->insertFactoryClassConstant($autoloadFile, $factoryClass);
182 4
        $this->setBootstrapFile($autoloadFile);
183 4
    }
184
185
    /**
186
     * Updates the Puli repository after Composer installations/updates.
187
     */
188 34
    public function postInstall()
189
    {
190 34
        if (!$this->initialized) {
191 34
            $this->initialize();
192
        }
193
194
        // This method is called multiple times. Run it only once.
195 34
        if (!$this->runPostInstall) {
196 3
            return;
197
        }
198
199 32
        $this->runPostInstall = false;
200
201 32
        $this->io->write('<info>Synchronizing Puli with Composer</info>');
202
203 32
        $rootPackage = $this->composer->getPackage();
204 32
        $composerPackages = $this->loadComposerPackages();
205 32
        $prodPackageNames = $this->filterProdPackageNames($composerPackages, $rootPackage);
206 32
        $env = $this->isDev ? PuliPackage::ENV_DEV : PuliPackage::ENV_PROD;
207
208
        try {
209 32
            $puliPackages = $this->loadPuliPackages();
210 1
        } catch (PuliRunnerException $e) {
211 1
            $this->printWarning('Could not load Puli packages', $e);
212
213 1
            return;
214
        }
215
216
        // Don't remove non-existing packages in production environment
217
        // Removed packages could be dev dependencies (i.e. "require-dev"
218
        // of the root package or "require" of another dev dependency), and
219
        // we can't find out whether they are since Composer doesn't load them
220 31
        if (PuliPackage::ENV_PROD !== $env) {
221 3
            $this->removeRemovedPackages($composerPackages, $puliPackages);
222
        }
223
224 31
        $this->installNewPackages($composerPackages, $prodPackageNames, $puliPackages);
225
226
        // Don't print warnings for non-existing packages in production
227 31
        if (PuliPackage::ENV_PROD !== $env) {
228 3
            $this->checkForNotFoundErrors($puliPackages);
229
        }
230
231 31
        $this->checkForNotLoadableErrors($puliPackages);
232 31
        $this->adoptComposerName($puliPackages);
233 31
        $this->removePuliDir();
234 31
        $this->buildPuli();
235 31
    }
236
237 39
    private function initialize()
238
    {
239 39
        $this->initialized = true;
240
241
        // Keep the manually set runner
242 39
        if (null === $this->puliRunner) {
243
            try {
244
                // Add Composer's bin directory in case the "puli" executable is
245
                // installed with Composer
246
                $this->puliRunner = new PuliRunner($this->config->get('bin-dir'));
247
            } catch (RuntimeException $e) {
248
                $this->printWarning('Plugin initialization failed', $e);
249
                $this->runPreAutoloadDump = false;
250
                $this->runPostAutoloadDump = false;
251
                $this->runPostInstall = false;
252
            }
253
        }
254
255
        // Use the runner to verify if Puli has the right version
256
        try {
257 39
            $this->verifyPuliVersion();
258 2
        } catch (RuntimeException $e) {
259 2
            $this->printWarning('Version check failed', $e);
260 2
            $this->runPreAutoloadDump = false;
261 2
            $this->runPostAutoloadDump = false;
262 2
            $this->runPostInstall = false;
263
        }
264 39
    }
265
266
    /**
267
     * @param PackageInterface[] $composerPackages
268
     * @param bool[]             $prodPackageNames
269
     * @param PuliPackage[]      $puliPackages
270
     */
271 31
    private function installNewPackages(array $composerPackages, array $prodPackageNames, array &$puliPackages)
272
    {
273 31
        $installationManager = $this->composer->getInstallationManager();
274
275 31
        foreach ($composerPackages as $packageName => $package) {
276 21
            if ($package instanceof AliasPackage) {
277 2
                $package = $package->getAliasOf();
278
            }
279
280
            // We need to normalize the system-dependent paths returned by Composer
281 21
            $installPath = Path::normalize($installationManager->getInstallPath($package));
282 21
            $env = isset($prodPackageNames[$packageName]) ? PuliPackage::ENV_PROD : PuliPackage::ENV_DEV;
283
284
            // Skip meta packages
285 21
            if ('' === $installPath) {
286 1
                continue;
287
            }
288
289 20
            if (isset($puliPackages[$packageName])) {
290 15
                $puliPackage = $puliPackages[$packageName];
291
292
                // Only proceed if the install path or environment has changed
293 15
                if ($installPath === $puliPackage->getInstallPath() && $env === $puliPackage->getEnvironment()) {
294 14
                    continue;
295
                }
296
297
                // Only remove packages installed by Composer
298 6
                if (self::INSTALLER_NAME === $puliPackage->getInstallerName()) {
299 5
                    $this->io->write(sprintf(
300 5
                        'Reinstalling <info>%s</info> (<comment>%s</comment>) in <comment>%s</comment>',
301
                        $packageName,
302 5
                        Path::makeRelative($installPath, $this->rootDir),
303
                        $env
304
                    ));
305
306
                    try {
307 5
                        $this->removePackage($packageName);
308 1
                    } catch (PuliRunnerException $e) {
309 1
                        $this->printPackageWarning('Could not remove package "%s" (at "%s")', $packageName, $installPath, $e);
310
311 6
                        continue;
312
                    }
313
                }
314
            } else {
315 6
                $this->io->write(sprintf(
316 6
                    'Installing <info>%s</info> (<comment>%s</comment>) in <comment>%s</comment>',
317
                    $packageName,
318 6
                    Path::makeRelative($installPath, $this->rootDir),
319
                    $env
320
                ));
321
            }
322
323
            try {
324 11
                $this->installPackage($installPath, $packageName, $env);
325 3
            } catch (PuliRunnerException $e) {
326 3
                $this->printPackageWarning('Could not install package "%s" (at "%s")', $packageName, $installPath, $e);
327
328 3
                continue;
329
            }
330
331 8
            $puliPackages[$packageName] = new PuliPackage(
332
                $packageName,
333 8
                self::INSTALLER_NAME,
334
                $installPath,
335 8
                PuliPackage::STATE_ENABLED,
336
                $env
337
            );
338
        }
339 31
    }
340
341
    /**
342
     * @param PackageInterface[] $composerPackages
343
     * @param PuliPackage[]      $puliPackages
344
     */
345 3
    private function removeRemovedPackages(array $composerPackages, array &$puliPackages)
346
    {
347
        /** @var PuliPackage[] $notFoundPackages */
348
        $notFoundPackages = array_filter($puliPackages, function (PuliPackage $package) {
349 3
            return PuliPackage::STATE_NOT_FOUND === $package->getState()
350 3
                && PuliPluginImpl::INSTALLER_NAME === $package->getInstallerName();
351 3
        });
352
353 3
        foreach ($notFoundPackages as $packageName => $package) {
354
            // Check whether package was only moved
355 3
            if (isset($composerPackages[$packageName])) {
356 1
                continue;
357
            }
358
359 2
            $this->io->write(sprintf(
360 2
                'Removing <info>%s</info> (<comment>%s</comment>)',
361
                $packageName,
362 2
                Path::makeRelative($package->getInstallPath(), $this->rootDir)
363
            ));
364
365
            try {
366 2
                $this->removePackage($packageName);
367 1
            } catch (PuliRunnerException $e) {
368 1
                $this->printPackageWarning('Could not remove package "%s" (at "%s")', $packageName, $package->getInstallPath(), $e);
369
370 1
                continue;
371
            }
372
373 1
            unset($puliPackages[$packageName]);
374
        }
375 3
    }
376
377 3 View Code Duplication
    private function checkForNotFoundErrors(array $puliPackages)
378
    {
379
        /** @var PuliPackage[] $notFoundPackages */
380 3
        $notFoundPackages = array_filter($puliPackages,
381
            function (PuliPackage $package) {
382 3
                return PuliPackage::STATE_NOT_FOUND === $package->getState()
383 3
                && PuliPluginImpl::INSTALLER_NAME === $package->getInstallerName();
384 3
            });
385
386 3
        foreach ($notFoundPackages as $package) {
387 2
            $this->printPackageWarning(
388 2
                'The package "%s" (at "%s") could not be found',
389 2
                $package->getName(),
390 2
                $package->getInstallPath()
391
            );
392
        }
393 3
    }
394
395 31 View Code Duplication
    private function checkForNotLoadableErrors(array $puliPackages)
396
    {
397
        /** @var PuliPackage[] $notLoadablePackages */
398
        $notLoadablePackages = array_filter($puliPackages, function (PuliPackage $package) {
399 31
            return PuliPackage::STATE_NOT_LOADABLE === $package->getState()
400 31
                && PuliPluginImpl::INSTALLER_NAME === $package->getInstallerName();
401 31
        });
402
403 31
        foreach ($notLoadablePackages as $package) {
404 1
            $this->printPackageWarning(
405 1
                'The package "%s" (at "%s") could not be loaded',
406 1
                $package->getName(),
407 1
                $package->getInstallPath()
408
            );
409
        }
410 31
    }
411
412 31
    private function adoptComposerName(array $puliPackages)
413
    {
414 31
        $rootDir = $this->rootDir;
415
416
        /** @var PuliPackage[] $rootPackages */
417 31
        $rootPackages = array_filter($puliPackages, function (PuliPackage $package) use ($rootDir) {
418 31
            return !$package->getInstallerName() && $rootDir === $package->getInstallPath();
419 31
        });
420
421 31
        if (0 === count($rootPackages)) {
422
            // This should never happen
423
            $this->printWarning('No root package could be found');
424
425
            return;
426
        }
427
428 31
        if (count($rootPackages) > 1) {
429
            // This should never happen
430
            $this->printWarning('More than one root package was found');
431
432
            return;
433
        }
434
435
        /** @var PuliPackage $rootPackage */
436 31
        $rootPackage = reset($rootPackages);
437 31
        $name = $rootPackage->getName();
438 31
        $newName = $this->composer->getPackage()->getName();
439
440
        // Rename the root package after changing the name in composer.json
441 31
        if ($name !== $newName) {
442
            try {
443 2
                $this->renamePackage($name, $newName);
444 1
            } catch (PuliRunnerException $e) {
445 1
                $this->printWarning(sprintf(
446 1
                    'Could not rename root package to "%s"',
447
                    $newName
448
                ), $e);
449
            }
450
        }
451 31
    }
452
453 4
    private function insertFactoryClassConstant($autoloadFile, $factoryClass)
454
    {
455 4
        if (!file_exists($autoloadFile)) {
456
            throw new PuliPluginException(sprintf(
457
                'Could not adjust autoloader: The file %s was not found.',
458
                $autoloadFile
459
            ));
460
        }
461
462 4
        $this->io->write('<info>Generating the "PULI_FACTORY_CLASS" constant</info>');
463
464 4
        $contents = file_get_contents($autoloadFile);
465 4
        $escFactoryClass = var_export($factoryClass, true);
466 4
        $constant = "if (!defined('PULI_FACTORY_CLASS')) {\n";
467 4
        $constant .= sprintf("    define('PULI_FACTORY_CLASS', %s);\n", $escFactoryClass);
468 4
        $constant .= "}\n\n";
469
470
        // Regex modifiers:
471
        // "m": \s matches newlines
472
        // "D": $ matches at EOF only
473
        // Translation: insert before the last "return" in the file
474 4
        $contents = preg_replace('/\n(?=return [^;]+;\s*$)/mD', "\n".$constant,
475
            $contents);
476
477 4
        file_put_contents($autoloadFile, $contents);
478 4
    }
479
480 4
    private function setBootstrapFile($autoloadFile)
481
    {
482 4
        $bootstrapFile = $this->getConfigKey('bootstrap-file');
483
484
        // Don't change user-defined bootstrap files
485 4
        if (!empty($bootstrapFile)) {
486 1
            return;
487
        }
488
489 3
        $relAutoloadFile = Path::makeRelative($autoloadFile, $this->rootDir);
490
491 3
        $this->io->write(sprintf('<info>Setting "bootstrap-file" to "%s"</info>', $relAutoloadFile));
492
493 3
        $this->setConfigKey('bootstrap-file', $relAutoloadFile);
494 3
    }
495
496
    /**
497
     * Loads Composer's currently installed packages.
498
     *
499
     * @return PackageInterface[] The installed packages indexed by their names
500
     */
501 32
    private function loadComposerPackages()
502
    {
503 32
        $repository = $this->composer->getRepositoryManager()->getLocalRepository();
504 32
        $packages = array();
505
506 32
        foreach ($repository->getPackages() as $package) {
507
            /* @var PackageInterface $package */
508 21
            $packages[$package->getName()] = $package;
509
        }
510
511 32
        return $packages;
512
    }
513
514 3
    private function getConfigKeyFromJsonFile($key)
515
    {
516 3
        $value = null;
0 ignored issues
show
$value is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
517 3
        $jsonPath = realpath(substr($this->config->get('vendor-dir'), 0, -strlen($this->config->get('vendor-dir', Config::RELATIVE_PATHS)))).DIRECTORY_SEPARATOR.'puli.json';
518 3
        if (file_exists($jsonPath)) {
519
            $jsonFile = new JsonFile($jsonPath, new RemoteFilesystem($this->io));
520
            $config = $jsonFile->read();
521
            if (empty($config['version']) || '1.0' !== $config['version']) {
522
                throw new \RuntimeException('Invalid configuration version schema of puli.json file!');
523
            }
524
        }
525
        switch ($key) {
526 3 View Code Duplication
            case 'factory.in.file':
527 3
                if (empty($config) || empty($config['config']['factory']['in']['file'])) {
528 3
                    $value = '.puli/GeneratedPuliFactory';
529
                } else {
530
                    $value = $config['config']['factory']['in']['file'];
531
                }
532 3
                break;
533 3 View Code Duplication
            case 'factory.in.class':
534 3
                if (empty($config) || empty($config['config']['factory']['in']['class'])) {
535 3
                    $value = 'Puli\\GeneratedPuliFactory';
536
                } else {
537
                    $value = $config['config']['factory']['in']['class'];
538
                }
539 3
                break;
540
            default:
541
                throw new \RuntimeException(sprintf('Cannot extract key "%s" from config!', $key));
542
        }
543
544 3
        return $value;
545
    }
546
547 36
    private function getConfigKey($key)
548
    {
549 36
        $value = trim($this->puliRunner->run('config %key% --parsed', array(
550 36
            'key' => $key,
551
        )));
552
553
        switch ($value) {
554 35
            case 'null':
555 1
                return null;
556 35
            case 'true':
557
                return true;
558 35
            case 'false':
559
                return false;
560
            default:
561 35
                return $value;
562
        }
563
    }
564
565 3
    private function setConfigKey($key, $value)
566
    {
567 3
        $this->puliRunner->run('config %key% %value%', array(
568 3
            'key' => $key,
569 3
            'value' => $value,
570
        ));
571 3
    }
572
573
    /**
574
     * @return PuliPackage[]
575
     */
576 32
    private function loadPuliPackages()
577
    {
578 32
        $packages = array();
579
580 32
        $output = $this->puliRunner->run('package --list --format %format%', array(
581 32
            'format' => '%name%;%installer%;%install_path%;%state%;%env%',
582
        ));
583
584
        // PuliRunner replaces \r\n by \n for those Windows boxes
585 31
        foreach (explode("\n", $output) as $packageLine) {
586 31
            if (!$packageLine) {
587 31
                continue;
588
            }
589
590 31
            $packageParts = explode(';', $packageLine);
591
592 31
            $packages[$packageParts[0]] = new PuliPackage(
593 31
                $packageParts[0],
594 31
                $packageParts[1],
595 31
                $packageParts[2],
596 31
                $packageParts[3],
597 31
                $packageParts[4]
598
            );
599
        }
600
601 31
        return $packages;
602
    }
603
604 11
    private function installPackage($installPath, $packageName, $env)
605
    {
606 11
        $env = PuliPackage::ENV_DEV === $env ? ' --dev' : '';
607
608 11
        $this->puliRunner->run('package --install %path% %package_name% --installer %installer%'.$env, array(
609 11
            'path' => $installPath,
610 11
            'package_name' => $packageName,
611 11
            'installer' => self::INSTALLER_NAME,
612
        ));
613 8
    }
614
615 7
    private function removePackage($packageName)
616
    {
617 7
        $this->puliRunner->run('package --delete %package_name%', array(
618 7
            'package_name' => $packageName,
619
        ));
620 5
    }
621
622 31
    private function removePuliDir()
623
    {
624 31
        $relativePuliDir = rtrim($this->getConfigKey('puli-dir'), '/');
625
626 31
        $puliDir = Path::makeAbsolute($relativePuliDir, $this->rootDir);
627
628
        // Only remove existing sub-directories of the root directory
629 31
        if (!file_exists($puliDir) || 0 !== strpos($puliDir, $this->rootDir.'/')) {
630 30
            return;
631
        }
632
633 1
        $this->io->write(sprintf('<info>Deleting the "%s" directory</info>', $relativePuliDir));
634
635
        // Remove the .puli directory to prevent upgrade problems
636 1
        $filesystem = new Filesystem();
637 1
        $filesystem->remove($puliDir);
638 1
    }
639
640 31
    private function buildPuli()
641
    {
642 31
        $this->io->write('<info>Running "puli build"</info>');
643
644 31
        $this->puliRunner->run('build');
645 31
    }
646
647 2
    private function renamePackage($name, $newName)
648
    {
649 2
        $this->puliRunner->run('package --rename %old_name% %new_name%', array(
650 2
            'old_name' => $name,
651 2
            'new_name' => $newName,
652
        ));
653 1
    }
654
655
    /**
656
     * @param                $message
657
     * @param Exception|null $exception
658
     */
659 12
    private function printWarning($message, Exception $exception = null)
660
    {
661 12
        if (!$exception) {
662 3
            $reasonPhrase = '';
663 10
        } elseif ($this->io->isVerbose()) {
664
            $reasonPhrase = $exception instanceof PuliRunnerException
665
                ? $exception->getFullError()
666
                : $exception->getMessage()."\n\n".$exception->getTraceAsString();
667
        } else {
668 10
            $reasonPhrase = $exception instanceof PuliRunnerException
669 8
                ? $exception->getShortError()
670 10
                : $exception->getMessage();
671
        }
672
673 12
        $this->io->writeError(sprintf(
674 12
            '<warning>Warning: %s%s</warning>',
675
            $message,
676 12
            $reasonPhrase ? ': '.$reasonPhrase : '.'
677
        ));
678 12
    }
679
680 7
    private function printPackageWarning($message, $packageName, $installPath, PuliRunnerException $exception = null)
681
    {
682 7
        $this->printWarning(sprintf(
683
            $message,
684
            $packageName,
685 7
            Path::makeRelative($installPath, $this->rootDir)
686
        ), $exception);
687 7
    }
688
689 32
    private function filterProdPackageNames(array $composerPackages, PackageInterface $package, array &$result = array())
690
    {
691
        // Resolve aliases
692 32
        if ($package instanceof AliasPackage) {
693 2
            $package = $package->getAliasOf();
694
        }
695
696
        // Package was processed already
697 32
        if (isset($result[$package->getName()])) {
698
            return $result;
699
        }
700
701 32
        $result[$package->getName()] = true;
702
703
        // Recursively filter package names
704 32
        foreach ($package->getRequires() as $packageName => $link) {
705 21
            if (isset($composerPackages[$packageName])) {
706 21
                $this->filterProdPackageNames($composerPackages, $composerPackages[$packageName], $result);
707
            }
708
        }
709
710 32
        return $result;
711
    }
712
713 39
    private function verifyPuliVersion()
714
    {
715 39
        $versionString = $this->puliRunner->run('-V');
716
717 39
        if (!preg_match('~^Puli version (\S+)$~', $versionString, $matches)) {
718
            throw new RuntimeException(sprintf(
719
                'Could not determine Puli version. "puli -V" returned: %s',
720
                $versionString
721
            ));
722
        }
723
724
        // the development build of the plugin is always considered compatible
725
        // with the development build of the CLI
726
        // Split strings to prevent replacement during release
727 39
        if ('@package_'.'version@' === self::VERSION && '@package_'.'version@' === $matches[1]) {
728 1
            return;
729
        }
730
731 38 View Code Duplication
        if (version_compare($matches[1], self::MIN_CLI_VERSION, '<')) {
732 1
            throw new RuntimeException(sprintf(
733
                'Found an unsupported version of the Puli CLI: %s. Please '.
734
                'upgrade to version %s or higher. You can also install the '.
735 1
                'puli/cli dependency at version %s in your project.',
736 1
                $matches[1],
737 1
                self::MIN_CLI_VERSION,
738 1
                self::MIN_CLI_VERSION
739
            ));
740
        }
741
742 37 View Code Duplication
        if (version_compare($matches[1], self::MAX_CLI_VERSION, '>')) {
743 1
            throw new RuntimeException(sprintf(
744
                'Found an unsupported version of the Puli CLI: %s. Please '.
745
                'downgrade to a lower version than %s. You can also install '.
746 1
                'the puli/cli dependency in your project.',
747 1
                $matches[1],
748 1
                self::MAX_CLI_VERSION
749
            ));
750
        }
751 36
    }
752
}
753