Completed
Pull Request — master (#46)
by Chris
05:33
created

PuliPluginImpl::preAutoloadDump()   B

Complexity

Conditions 5
Paths 10

Size

Total Lines 33
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 33
rs 8.439
ccs 0
cts 19
cp 0
cc 5
eloc 19
nc 10
nop 0
crap 30
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 43
    public function __construct(Event $event, PuliRunner $puliRunner = null)
112
    {
113 43
        $this->composer = $event->getComposer();
114 43
        $this->io = $event->getIO();
115 43
        $this->config = $this->composer->getConfig();
116 43
        $this->isDev = $event->isDevMode();
117 43
        $this->puliRunner = $puliRunner;
118 43
        $this->rootDir = Path::normalize(getcwd());
119
120 43
        $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 43
        $vendorDir = Path::makeAbsolute($vendorDir, $this->rootDir);
125
126 43
        $this->autoloadFile = $vendorDir.'/autoload.php';
127 43
    }
128
129
    public function preAutoloadDump()
130
    {
131
        if (!$this->initialized) {
132
            $this->initialize();
133
        }
134
135
        // This method is called twice. Run it only once.
136
        if (!$this->runPreAutoloadDump) {
137
            return;
138
        }
139
140
        $this->runPreAutoloadDump = false;
141
142
        try {
143
            $factoryClass = $this->getConfigKey('factory.in.class');
144
            $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
        $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
        $autoload = $this->composer->getPackage()->getAutoload();
154
        $autoload['classmap'][] = $factoryFile;
155
        $this->composer->getPackage()->setAutoload($autoload);
156
157
        if (!file_exists($factoryFile)) {
158
            $filesystem = new Filesystem();
159
            $filesystem->dumpFile($factoryFile, '<?php class '.$factoryClass.' {}');
160
        }
161
    }
162
163 9
    public function postAutoloadDump()
164
    {
165 9
        if (!$this->initialized) {
166 9
            $this->initialize();
167
        }
168
169
        // This method is called twice. Run it only once.
170 9
        if (!$this->runPostAutoloadDump) {
171 1
            return;
172
        }
173
174 9
        $this->runPostAutoloadDump = false;
175
176
        try {
177 9
            $factoryClass = $this->getConfigKey('factory.in.class');
178 1
        } catch (PuliRunnerException $e) {
179 1
            $this->printWarning('Could not load Puli configuration', $e);
180
181 1
            return;
182
        }
183
184 8
        $this->insertFactoryClassConstant($this->autoloadFile, $factoryClass);
185 7
        $this->setBootstrapFile($this->autoloadFile);
186 2
    }
187
188
    /**
189
     * Updates the Puli repository after Composer installations/updates.
190
     */
191 34
    public function postInstall()
192
    {
193 34
        if (!$this->initialized) {
194 34
            $this->initialize();
195
        }
196
197
        // This method is called twice. Run it only once.
198 34
        if (!$this->runPostInstall) {
199 3
            return;
200
        }
201
202 32
        $this->runPostInstall = false;
203
204 32
        $this->io->write('<info>Synchronizing Puli with Composer</info>');
205
206 32
        $rootPackage = $this->composer->getPackage();
207 32
        $composerPackages = $this->loadComposerPackages();
208 32
        $prodPackageNames = $this->filterProdPackageNames($composerPackages, $rootPackage);
209 32
        $env = $this->isDev ? PuliPackage::ENV_DEV : PuliPackage::ENV_PROD;
210
211
        try {
212 32
            $puliPackages = $this->loadPuliPackages();
213 1
        } catch (PuliRunnerException $e) {
214 1
            $this->printWarning('Could not load Puli packages', $e);
215
216 1
            return;
217
        }
218
219
        // Don't remove non-existing packages in production environment
220
        // Removed packages could be dev dependencies (i.e. "require-dev"
221
        // of the root package or "require" of another dev dependency), and
222
        // we can't find out whether they are since Composer doesn't load them
223 31
        if (PuliPackage::ENV_PROD !== $env) {
224 3
            $this->removeRemovedPackages($composerPackages, $puliPackages);
225
        }
226
227 31
        $this->installNewPackages($composerPackages, $prodPackageNames, $puliPackages);
228
229
        // Don't print warnings for non-existing packages in production
230 31
        if (PuliPackage::ENV_PROD !== $env) {
231 3
            $this->checkForNotFoundErrors($puliPackages);
232
        }
233
234 31
        $this->checkForNotLoadableErrors($puliPackages);
235 31
        $this->adoptComposerName($puliPackages);
236 31
        $this->removePuliDir();
237 31
        $this->buildPuli();
238 31
    }
239
240 43
    private function initialize()
241
    {
242 43
        if (!file_exists($this->autoloadFile)) {
243 1
            $filesystem = new Filesystem();
244
            // Avoid problems if using the runner before autoload.php has been
245
            // generated
246 1
            $filesystem->dumpFile($this->autoloadFile, '');
247
        }
248
249 43
        $this->initialized = true;
250
251
        // Keep the manually set runner
252 43
        if (null === $this->puliRunner) {
253
            try {
254
                // Add Composer's bin directory in case the "puli" executable is
255
                // installed with Composer
256
                $this->puliRunner = new PuliRunner($this->config->get('bin-dir'));
257
            } catch (RuntimeException $e) {
258
                $this->printWarning('Plugin initialization failed', $e);
259
                $this->runPreAutoloadDump = false;
260
                $this->runPostAutoloadDump = false;
261
                $this->runPostInstall = false;
262
            }
263
        }
264
265
        // Use the runner to verify if Puli has the right version
266
        try {
267 43
            $this->verifyPuliVersion();
268 2
        } catch (RuntimeException $e) {
269 2
            $this->printWarning('Version check failed', $e);
270 2
            $this->runPreAutoloadDump = false;
271 2
            $this->runPostAutoloadDump = false;
272 2
            $this->runPostInstall = false;
273
        }
274 43
    }
275
276
    /**
277
     * @param PackageInterface[] $composerPackages
278
     * @param bool[]             $prodPackageNames
279
     * @param PuliPackage[]      $puliPackages
280
     */
281 31
    private function installNewPackages(array $composerPackages, array $prodPackageNames, array &$puliPackages)
282
    {
283 31
        $installationManager = $this->composer->getInstallationManager();
284
285 31
        foreach ($composerPackages as $packageName => $package) {
286 21
            if ($package instanceof AliasPackage) {
287 2
                $package = $package->getAliasOf();
288
            }
289
290
            // We need to normalize the system-dependent paths returned by Composer
291 21
            $installPath = Path::normalize($installationManager->getInstallPath($package));
292 21
            $env = isset($prodPackageNames[$packageName]) ? PuliPackage::ENV_PROD : PuliPackage::ENV_DEV;
293
294
            // Skip meta packages
295 21
            if ('' === $installPath) {
296 1
                continue;
297
            }
298
299 20
            if (isset($puliPackages[$packageName])) {
300 15
                $puliPackage = $puliPackages[$packageName];
301
302
                // Only proceed if the install path or environment has changed
303 15
                if ($installPath === $puliPackage->getInstallPath() && $env === $puliPackage->getEnvironment()) {
304 14
                    continue;
305
                }
306
307
                // Only remove packages installed by Composer
308 6
                if (self::INSTALLER_NAME === $puliPackage->getInstallerName()) {
309 5
                    $this->io->write(sprintf(
310 5
                        'Reinstalling <info>%s</info> (<comment>%s</comment>) in <comment>%s</comment>',
311
                        $packageName,
312 5
                        Path::makeRelative($installPath, $this->rootDir),
313
                        $env
314
                    ));
315
316
                    try {
317 5
                        $this->removePackage($packageName);
318 1
                    } catch (PuliRunnerException $e) {
319 1
                        $this->printPackageWarning('Could not remove package "%s" (at "%s")', $packageName, $installPath, $e);
320
321 6
                        continue;
322
                    }
323
                }
324
            } else {
325 6
                $this->io->write(sprintf(
326 6
                    'Installing <info>%s</info> (<comment>%s</comment>) in <comment>%s</comment>',
327
                    $packageName,
328 6
                    Path::makeRelative($installPath, $this->rootDir),
329
                    $env
330
                ));
331
            }
332
333
            try {
334 11
                $this->installPackage($installPath, $packageName, $env);
335 3
            } catch (PuliRunnerException $e) {
336 3
                $this->printPackageWarning('Could not install package "%s" (at "%s")', $packageName, $installPath, $e);
337
338 3
                continue;
339
            }
340
341 8
            $puliPackages[$packageName] = new PuliPackage(
342
                $packageName,
343 8
                self::INSTALLER_NAME,
344
                $installPath,
345 8
                PuliPackage::STATE_ENABLED,
346
                $env
347
            );
348
        }
349 31
    }
350
351
    /**
352
     * @param PackageInterface[] $composerPackages
353
     * @param PuliPackage[]      $puliPackages
354
     */
355 3
    private function removeRemovedPackages(array $composerPackages, array &$puliPackages)
356
    {
357
        /** @var PuliPackage[] $notFoundPackages */
358
        $notFoundPackages = array_filter($puliPackages, function (PuliPackage $package) {
359 3
            return PuliPackage::STATE_NOT_FOUND === $package->getState()
360 3
                && PuliPluginImpl::INSTALLER_NAME === $package->getInstallerName();
361 3
        });
362
363 3
        foreach ($notFoundPackages as $packageName => $package) {
364
            // Check whether package was only moved
365 3
            if (isset($composerPackages[$packageName])) {
366 1
                continue;
367
            }
368
369 2
            $this->io->write(sprintf(
370 2
                'Removing <info>%s</info> (<comment>%s</comment>)',
371
                $packageName,
372 2
                Path::makeRelative($package->getInstallPath(), $this->rootDir)
373
            ));
374
375
            try {
376 2
                $this->removePackage($packageName);
377 1
            } catch (PuliRunnerException $e) {
378 1
                $this->printPackageWarning('Could not remove package "%s" (at "%s")', $packageName, $package->getInstallPath(), $e);
379
380 1
                continue;
381
            }
382
383 1
            unset($puliPackages[$packageName]);
384
        }
385 3
    }
386
387 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...
388
    {
389
        /** @var PuliPackage[] $notFoundPackages */
390 3
        $notFoundPackages = array_filter($puliPackages,
391
            function (PuliPackage $package) {
392 3
                return PuliPackage::STATE_NOT_FOUND === $package->getState()
393 3
                && PuliPluginImpl::INSTALLER_NAME === $package->getInstallerName();
394 3
            });
395
396 3
        foreach ($notFoundPackages as $package) {
397 2
            $this->printPackageWarning(
398 2
                'The package "%s" (at "%s") could not be found',
399 2
                $package->getName(),
400 2
                $package->getInstallPath()
401
            );
402
        }
403 3
    }
404
405 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...
406
    {
407
        /** @var PuliPackage[] $notLoadablePackages */
408
        $notLoadablePackages = array_filter($puliPackages, function (PuliPackage $package) {
409 31
            return PuliPackage::STATE_NOT_LOADABLE === $package->getState()
410 31
                && PuliPluginImpl::INSTALLER_NAME === $package->getInstallerName();
411 31
        });
412
413 31
        foreach ($notLoadablePackages as $package) {
414 1
            $this->printPackageWarning(
415 1
                'The package "%s" (at "%s") could not be loaded',
416 1
                $package->getName(),
417 1
                $package->getInstallPath()
418
            );
419
        }
420 31
    }
421
422 31
    private function adoptComposerName(array $puliPackages)
423
    {
424 31
        $rootDir = $this->rootDir;
425
426
        /** @var PuliPackage[] $rootPackages */
427 31
        $rootPackages = array_filter($puliPackages, function (PuliPackage $package) use ($rootDir) {
428 31
            return !$package->getInstallerName() && $rootDir === $package->getInstallPath();
429 31
        });
430
431 31
        if (0 === count($rootPackages)) {
432
            // This should never happen
433
            $this->printWarning('No root package could be found');
434
435
            return;
436
        }
437
438 31
        if (count($rootPackages) > 1) {
439
            // This should never happen
440
            $this->printWarning('More than one root package was found');
441
442
            return;
443
        }
444
445
        /** @var PuliPackage $rootPackage */
446 31
        $rootPackage = reset($rootPackages);
447 31
        $name = $rootPackage->getName();
448 31
        $newName = $this->composer->getPackage()->getName();
449
450
        // Rename the root package after changing the name in composer.json
451 31
        if ($name !== $newName) {
452
            try {
453 2
                $this->renamePackage($name, $newName);
454 1
            } catch (PuliRunnerException $e) {
455 1
                $this->printWarning(sprintf(
456 1
                    'Could not rename root package to "%s"',
457
                    $newName
458
                ), $e);
459
            }
460
        }
461 31
    }
462
463 8
    private function insertFactoryClassConstant($autoloadFile, $factoryClass)
464
    {
465 8
        if (!file_exists($autoloadFile)) {
466
            throw new PuliPluginException(sprintf(
467
                'Could not adjust autoloader: The file %s was not found.',
468
                $autoloadFile
469
            ));
470
        }
471
472 8
        $this->io->write('<info>Generating the "PULI_FACTORY_CLASS" constant</info>');
473
474 7
        $contents = file_get_contents($autoloadFile);
475 7
        $escFactoryClass = var_export($factoryClass, true);
476 7
        $constant = "if (!defined('PULI_FACTORY_CLASS')) {\n";
477 7
        $constant .= sprintf("    define('PULI_FACTORY_CLASS', %s);\n", $escFactoryClass);
478 7
        $constant .= "}\n\n";
479
480
        // Regex modifiers:
481
        // "m": \s matches newlines
482
        // "D": $ matches at EOF only
483
        // Translation: insert before the last "return" in the file
484 7
        $contents = preg_replace('/\n(?=return [^;]+;\s*$)/mD', "\n".$constant,
485
            $contents);
486
487 7
        file_put_contents($autoloadFile, $contents);
488 7
    }
489
490 7
    private function setBootstrapFile($autoloadFile)
491
    {
492 7
        $bootstrapFile = $this->getConfigKey('bootstrap-file');
493
494
        // Don't change user-defined bootstrap files
495 4
        if (!empty($bootstrapFile)) {
496
            return;
497
        }
498
499 4
        $relAutoloadFile = Path::makeRelative($autoloadFile, $this->rootDir);
500
501 4
        $this->io->write(sprintf('<info>Setting "bootstrap-file" to "%s"</info>', $relAutoloadFile));
502
503 4
        $this->setConfigKey('bootstrap-file', $relAutoloadFile);
504 2
    }
505
506
    /**
507
     * Loads Composer's currently installed packages.
508
     *
509
     * @return PackageInterface[] The installed packages indexed by their names.
510
     */
511 32
    private function loadComposerPackages()
512
    {
513 32
        $repository = $this->composer->getRepositoryManager()->getLocalRepository();
514 32
        $packages = array();
515
516 32
        foreach ($repository->getPackages() as $package) {
517
            /* @var PackageInterface $package */
518 21
            $packages[$package->getName()] = $package;
519
        }
520
521 32
        return $packages;
522
    }
523
524 40
    private function getConfigKey($key)
525
    {
526 40
        $value = trim($this->puliRunner->run('config %key% --parsed', array(
527 40
            'key' => $key,
528
        )));
529
530
        switch ($value) {
531 39
            case 'null':
532
                return null;
533 39
            case 'true':
534
                return true;
535 39
            case 'false':
536
                return false;
537
            default:
538 39
                return $value;
539
        }
540
    }
541
542 4
    private function setConfigKey($key, $value)
543
    {
544 4
        $this->puliRunner->run('config %key% %value%', array(
545 4
            'key' => $key,
546 4
            'value' => $value,
547
        ));
548 2
    }
549
550
    /**
551
     * @return PuliPackage[]
552
     */
553 32
    private function loadPuliPackages()
554
    {
555 32
        $packages = array();
556
557 32
        $output = $this->puliRunner->run('package --list --format %format%', array(
558 32
            'format' => '%name%;%installer%;%install_path%;%state%;%env%',
559
        ));
560
561
        // PuliRunner replaces \r\n by \n for those Windows boxes
562 31
        foreach (explode("\n", $output) as $packageLine) {
563 31
            if (!$packageLine) {
564 31
                continue;
565
            }
566
567 31
            $packageParts = explode(';', $packageLine);
568
569 31
            $packages[$packageParts[0]] = new PuliPackage(
570 31
                $packageParts[0],
571 31
                $packageParts[1],
572 31
                $packageParts[2],
573 31
                $packageParts[3],
574 31
                $packageParts[4]
575
            );
576
        }
577
578 31
        return $packages;
579
    }
580
581 11
    private function installPackage($installPath, $packageName, $env)
582
    {
583 11
        $env = PuliPackage::ENV_DEV === $env ? ' --dev' : '';
584
585 11
        $this->puliRunner->run('package --install %path% %package_name% --installer %installer%'.$env, array(
586 11
            'path' => $installPath,
587 11
            'package_name' => $packageName,
588 11
            'installer' => self::INSTALLER_NAME,
589
        ));
590 8
    }
591
592 7
    private function removePackage($packageName)
593
    {
594 7
        $this->puliRunner->run('package --delete %package_name%', array(
595 7
            'package_name' => $packageName,
596
        ));
597 5
    }
598
599 31
    private function removePuliDir()
600
    {
601 31
        $relativePuliDir = rtrim($this->getConfigKey('puli-dir'), '/');
602
603 31
        $puliDir = Path::makeAbsolute($relativePuliDir, $this->rootDir);
604
605
        // Only remove existing sub-directories of the root directory
606 31
        if (!file_exists($puliDir) || 0 !== strpos($puliDir, $this->rootDir.'/')) {
607 30
            return;
608
        }
609
610 1
        $this->io->write(sprintf('<info>Deleting the "%s" directory</info>', $relativePuliDir));
611
612
        // Remove the .puli directory to prevent upgrade problems
613 1
        $filesystem = new Filesystem();
614 1
        $filesystem->remove($puliDir);
615 1
    }
616
617 31
    private function buildPuli()
618
    {
619 31
        $this->io->write('<info>Running "puli build"</info>');
620
621 31
        $this->puliRunner->run('build');
622 31
    }
623
624 2
    private function renamePackage($name, $newName)
625
    {
626 2
        $this->puliRunner->run('package --rename %old_name% %new_name%', array(
627 2
            'old_name' => $name,
628 2
            'new_name' => $newName,
629
        ));
630 1
    }
631
632
    /**
633
     * @param                $message
634
     * @param Exception|null $exception
635
     */
636 12
    private function printWarning($message, Exception $exception = null)
637
    {
638 12
        if (!$exception) {
639 3
            $reasonPhrase = '';
640 10
        } elseif ($this->io->isVerbose()) {
641
            $reasonPhrase = $exception instanceof PuliRunnerException
642
                ? $exception->getFullError()
643
                : $exception->getMessage()."\n\n".$exception->getTraceAsString();
644
        } else {
645 10
            $reasonPhrase = $exception instanceof PuliRunnerException
646 8
                ? $exception->getShortError()
647 10
                : $exception->getMessage();
648
        }
649
650 12
        $this->io->writeError(sprintf(
651 12
            '<warning>Warning: %s%s</warning>',
652
            $message,
653 12
            $reasonPhrase ? ': '.$reasonPhrase : '.'
654
        ));
655 12
    }
656
657 7
    private function printPackageWarning($message, $packageName, $installPath, PuliRunnerException $exception = null)
658
    {
659 7
        $this->printWarning(sprintf(
660
            $message,
661
            $packageName,
662 7
            Path::makeRelative($installPath, $this->rootDir)
663
        ), $exception);
664 7
    }
665
666 32
    private function filterProdPackageNames(array $composerPackages, PackageInterface $package, array &$result = array())
667
    {
668
        // Resolve aliases
669 32
        if ($package instanceof AliasPackage) {
670 2
            $package = $package->getAliasOf();
671
        }
672
673
        // Package was processed already
674 32
        if (isset($result[$package->getName()])) {
675
            return $result;
676
        }
677
678 32
        $result[$package->getName()] = true;
679
680
        // Recursively filter package names
681 32
        foreach ($package->getRequires() as $packageName => $link) {
682 21
            if (isset($composerPackages[$packageName])) {
683 21
                $this->filterProdPackageNames($composerPackages, $composerPackages[$packageName], $result);
684
            }
685
        }
686
687 32
        return $result;
688
    }
689
690 43
    private function verifyPuliVersion()
691
    {
692 43
        $versionString = $this->puliRunner->run('-V');
693
694 43
        if (!preg_match('~^Puli version (\S+)$~', $versionString, $matches)) {
695
            throw new RuntimeException(sprintf(
696
                'Could not determine Puli version. "puli -V" returned: %s',
697
                $versionString
698
            ));
699
        }
700
701
        // the development build of the plugin is always considered compatible
702
        // with the development build of the CLI
703
        // Split strings to prevent replacement during release
704 43
        if ('@package_'.'version@' === self::VERSION && '@package_'.'version@' === $matches[1]) {
705 1
            return;
706
        }
707
708 42 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...
709 1
            throw new RuntimeException(sprintf(
710
                'Found an unsupported version of the Puli CLI: %s. Please '.
711
                'upgrade to version %s or higher. You can also install the '.
712 1
                'puli/cli dependency at version %s in your project.',
713 1
                $matches[1],
714 1
                self::MIN_CLI_VERSION,
715 1
                self::MIN_CLI_VERSION
716
            ));
717
        }
718
719 41 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...
720 1
            throw new RuntimeException(sprintf(
721
                'Found an unsupported version of the Puli CLI: %s. Please '.
722
                'downgrade to a lower version than %s. You can also install '.
723 1
                'the puli/cli dependency in your project.',
724 1
                $matches[1],
725 1
                self::MAX_CLI_VERSION
726
            ));
727
        }
728 40
    }
729
}
730