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

PuliPluginImpl::getConfigKeyFromJsonFile()   D

Complexity

Conditions 10
Paths 11

Size

Total Lines 32
Code Lines 24

Duplication

Lines 14
Ratio 43.75 %

Code Coverage

Tests 13
CRAP Score 14.2875

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 14
loc 32
ccs 13
cts 20
cp 0.65
rs 4.8196
cc 10
eloc 24
nc 11
nop 1
crap 14.2875

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/*
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)
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...
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)
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...
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)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
515
    {
516 3
        $value = null;
0 ignored issues
show
Unused Code introduced by
$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':
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...
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':
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...
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, '<')) {
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
                '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, '>')) {
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...
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