Passed
Pull Request — master (#46)
by Théo
02:11
created

SelfUpdateCommand::printAvailableUpdates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14
15
namespace KevinGH\Box\Console\Command;
16
17
use Humbug\SelfUpdate\Updater;
18
use KevinGH\Box\Console\Logger\UpdateConsoleLogger;
19
use PHAR;
20
use Symfony\Component\Console\Command\Command;
21
use Symfony\Component\Console\Input\InputInterface;
22
use Symfony\Component\Console\Input\InputOption;
23
use Symfony\Component\Console\Output\OutputInterface;
24
use Symfony\Component\Console\Style\SymfonyStyle;
25
use Throwable;
26
27
final class SelfUpdateCommand extends Command
28
{
29
    private const REMOTE_FILENAME = 'box.phar';
30
    private const STABILITY_STABLE = 'stable';
31
    private const PACKAGIST_PACKAGE_NAME = 'humbug/box';
32
    private const ROLLBACK_OPT = 'rollback';
33
    private const CHECK_OPT = 'check';
34
    private $updater;
35
36
    /**
37
     * @var string
38
     */
39
    private $version;
40
41
    /**
42
     * @var UpdateConsoleLogger
43
     */
44
    private $logger;
45
46
    /**
47
     * {@inheritdoc}
48
     */
49
    public function __construct(Updater $updater)
50
    {
51
        parent::__construct();
52
53
        $this->updater = $updater;
54
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59
    protected function configure(): void
60
    {
61
        $this
62
            ->setName('self-update')
63
            ->setDescription(sprintf(
64
                'Update %s to most recent stable build.',
65
                $this->getLocalPharName()
66
            ))
67
            ->addOption(
68
                self::ROLLBACK_OPT,
69
                'r',
70
                InputOption::VALUE_NONE,
71
                'Rollback to previous version of PHP-Scoper if available on filesystem.'
72
            )
73
            ->addOption(
74
                self::CHECK_OPT,
75
                'c',
76
                InputOption::VALUE_NONE,
77
                'Checks whether an update is available.'
78
            )
79
        ;
80
    }
81
82
    /**
83
     * {@inheritdoc}
84
     */
85
    protected function execute(InputInterface $input, OutputInterface $output): int
86
    {
87
        $this->logger = new UpdateConsoleLogger(
88
            new SymfonyStyle($input, $output)
89
        );
90
91
        $this->version = $this->getApplication()->getVersion();
92
93
        $this->configureUpdater();
94
95
        if ($input->getOption('rollback')) {
96
            $this->rollback();
97
98
            return 0;
99
        }
100
101
        if ($input->getOption('check')) {
102
            $this->printAvailableUpdates();
103
104
            return 0;
105
        }
106
107
        $this->update();
108
109
        return 0;
110
    }
111
112
    private function configureUpdater(): void
113
    {
114
        $this->updater->setStrategy(Updater::STRATEGY_GITHUB);
115
        $this->updater->getStrategy()->setPackageName(self::PACKAGIST_PACKAGE_NAME);
0 ignored issues
show
Bug introduced by
The method setPackageName() does not exist on Humbug\SelfUpdate\Strategy\ShaStrategy. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

115
        $this->updater->getStrategy()->/** @scrutinizer ignore-call */ setPackageName(self::PACKAGIST_PACKAGE_NAME);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
116
        $this->updater->getStrategy()->setPharName(self::REMOTE_FILENAME);
0 ignored issues
show
Bug introduced by
The method setPharName() does not exist on Humbug\SelfUpdate\Strategy\ShaStrategy. Did you maybe mean setPharUrl()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

116
        $this->updater->getStrategy()->/** @scrutinizer ignore-call */ setPharName(self::REMOTE_FILENAME);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
117
        $this->updater->getStrategy()->setCurrentLocalVersion($this->version);
0 ignored issues
show
Bug introduced by
The method setCurrentLocalVersion() does not exist on Humbug\SelfUpdate\Strategy\ShaStrategy. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

117
        $this->updater->getStrategy()->/** @scrutinizer ignore-call */ setCurrentLocalVersion($this->version);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
118
    }
119
120
    private function update(): void
121
    {
122
        $this->logger->startUpdating();
123
124
        try {
125
            $result = $this->updater->update();
126
127
            $newVersion = $this->updater->getNewVersion();
128
            $oldVersion = $this->updater->getOldVersion();
129
130
            if ($result) {
131
                $this->logger->updateSuccess($newVersion, $oldVersion);
132
            } else {
133
                $this->logger->updateNotNeeded($oldVersion);
134
            }
135
        } catch (Throwable $throwable) {
136
            $this->logger->error($throwable);
137
138
            throw $throwable;
139
        }
140
    }
141
142
    private function rollback(): void
143
    {
144
        try {
145
            $result = $this->updater->rollback();
146
147
            if ($result) {
148
                $this->logger->rollbackSuccess();
149
            } else {
150
                $this->logger->rollbackFail();
151
            }
152
        } catch (Throwable $throwable) {
153
            $this->logger->error($throwable);
154
155
            throw $throwable;
156
        }
157
    }
158
159
    private function printAvailableUpdates(): void
160
    {
161
        $this->logger->printLocalVersion($this->version);
162
163
        $this->printCurrentStableVersion();
164
    }
165
166
    private function printCurrentStableVersion(): void
167
    {
168
        $stability = self::STABILITY_STABLE;
169
170
        try {
171
            if ($this->updater->hasUpdate()) {
172
                $this->logger->printRemoteVersion(
173
                    $stability,
174
                    $this->updater->getNewVersion()
0 ignored issues
show
Bug introduced by
It seems like $this->updater->getNewVersion() can also be of type boolean; however, parameter $version of KevinGH\Box\Console\Logg...r::printRemoteVersion() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

174
                    /** @scrutinizer ignore-type */ $this->updater->getNewVersion()
Loading history...
175
                );
176
            } elseif (false == $this->updater->getNewVersion()) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $this->updater->getNewVersion() of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
177
                $this->logger->noNewRemoteVersions($stability);
178
            } else {
179
                $this->logger->currentVersionInstalled($stability);
180
            }
181
        } catch (Throwable $throwable) {
182
            $this->logger->error($throwable);
183
184
            throw $throwable;
185
        }
186
    }
187
188
    private function getLocalPharName(): string
189
    {
190
        return basename(PHAR::running());
191
    }
192
}
193