Failed Conditions
Pull Request — master (#49)
by Helmut
19:53
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 14
CRAP Score 10

Importance

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

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