Failed Conditions
Push — master ( 7014aa...7fc00d )
by Alexander
04:08
created

SelfUpdateCommand::changeUpdateChannel()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
ccs 0
cts 8
cp 0
rs 9.2
cc 4
eloc 7
nc 8
nop 0
crap 20
1
<?php
2
/**
3
 * This file is part of the SVN-Buddy library.
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 *
7
 * @copyright Alexander Obuhovich <[email protected]>
8
 * @link      https://github.com/console-helpers/svn-buddy
9
 */
10
11
namespace ConsoleHelpers\SVNBuddy\Command;
12
13
14
use ConsoleHelpers\ConsoleKit\Config\ConfigEditor;
15
use ConsoleHelpers\ConsoleKit\Exception\CommandException;
16
use ConsoleHelpers\SVNBuddy\Process\ProcessFactory;
17
use ConsoleHelpers\SVNBuddy\Updater\Stability;
18
use ConsoleHelpers\SVNBuddy\Updater\UpdateManager;
19
use ConsoleHelpers\SVNBuddy\Updater\Updater;
20
use ConsoleHelpers\SVNBuddy\Updater\VersionUpdateStrategy;
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\Process\PhpExecutableFinder;
25
use Symfony\Component\Process\ProcessBuilder;
26
27
class SelfUpdateCommand extends AbstractCommand
28
{
29
30
	/**
31
	 * Update manager.
32
	 *
33
	 * @var UpdateManager
34
	 */
35
	private $_updateManager;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
36
37
	/**
38
	 * Process factory.
39
	 *
40
	 * @var ProcessFactory
41
	 */
42
	private $_processFactory;
43
44
	/**
45
	 * {@inheritdoc}
46
	 */
47
	protected function configure()
48
	{
49
		$this
50
			->setName('self-update')
51
			->setDescription(
52
				'Update application to most recent version'
53
			)
54
			->addOption(
55
				'rollback',
56
				'r',
57
				InputOption::VALUE_NONE,
58
				'Revert to an older version of the application'
59
			)
60
			->addOption(
61
				'stable',
62
				null,
63
				InputOption::VALUE_NONE,
64
				'Force an update to the stable channel'
65
			)
66
			->addOption(
67
				'snapshot',
68
				null,
69
				InputOption::VALUE_NONE,
70
				'Force an update to the snapshot channel'
71
			)
72
			->addOption(
73
				'preview',
74
				null,
75
				InputOption::VALUE_NONE,
76
				'Force an update to the preview channel'
77
			)
78
			->addOption(
79
				'check',
80
				null,
81
				InputOption::VALUE_NONE,
82
				'Checks for update availability'
83
			);
84
85
		parent::configure();
86
	}
87
88
	/**
89
	 * Prepare dependencies.
90
	 *
91
	 * @return void
92
	 */
93
	protected function prepareDependencies()
94
	{
95
		parent::prepareDependencies();
96
97
		$container = $this->getContainer();
98
99
		$this->_updateManager = $container['update_manager'];
100
		$this->_processFactory = $container['process_factory'];
101
	}
102
103
	/**
104
	 * Allow showing update banner.
105
	 *
106
	 * @param InputInterface $input Input.
107
	 *
108
	 * @return boolean
109
	 */
110
	protected function checkForAppUpdates(InputInterface $input)
111
	{
112
		return false;
113
	}
114
115
	/**
116
	 * {@inheritdoc}
117
	 */
118
	protected function execute(InputInterface $input, OutputInterface $output)
119
	{
120
		$this->changeUpdateChannel();
121
122
		if ( $this->io->getOption('rollback') ) {
123
			$this->processRollback();
124
		}
125
		elseif ( $this->io->getOption('check') ) {
126
			$this->processCheck();
127
		}
128
		else {
129
			$this->processUpdate();
130
		}
131
	}
132
133
	/**
134
	 * Changes update channel.
135
	 *
136
	 * @return void
137
	 */
138
	protected function changeUpdateChannel()
139
	{
140
		if ( $this->io->getOption('stable') ) {
141
			$this->_updateManager->setUpdateChannel(Stability::STABLE);
142
		}
143
144
		if ( $this->io->getOption('snapshot') ) {
145
			$this->_updateManager->setUpdateChannel(Stability::SNAPSHOT);
146
		}
147
148
		if ( $this->io->getOption('preview') ) {
149
			$this->_updateManager->setUpdateChannel(Stability::PREVIEW);
150
		}
151
	}
152
153
	/**
154
	 * Processes rollback.
155
	 *
156
	 * @return void
157
	 * @throws CommandException When rollback failed.
158
	 */
159
	protected function processRollback()
160
	{
161
		$updater = new Updater(null, false);
162
163
		// To get all needed classes autoloaded before phar gets overwritten.
164
		$this->getFreshVersion();
165
166
		if ( !$updater->rollback() ) {
167
			throw new CommandException('Failed to restore previous version.');
168
		}
169
170
		$this->io->writeln(
171
			'Rolling back to version <info>' . $this->getFreshVersion() . '</info>.'
172
		);
173
	}
174
175
	/**
176
	 * Returns fresh application version.
177
	 *
178
	 * @return string
179
	 */
180
	protected function getFreshVersion()
181
	{
182
		$output = $this->_processFactory
183
			->createCommandProcess('list', array('--format=xml'))
184
			->mustRun()
185
			->getOutput();
186
187
		$xml = new \SimpleXMLElement($output);
188
189
		return (string)$xml['version'];
190
	}
191
192
	/**
193
	 * Processes update.
194
	 *
195
	 * @return void
196
	 */
197
	protected function processUpdate()
1 ignored issue
show
Coding Style introduced by
processUpdate uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
198
	{
199
		$updater = $this->_updateManager->getUpdater();
200
201
		$this->io->write('Checking for updates ... ');
202
		$has_update = $updater->hasUpdate();
203
		$this->io->writeln('done');
204
205
		$update_channel = $this->_updateManager->getUpdateChannel();
206
207
		if ( !$has_update ) {
208
			$this->io->writeln(sprintf(
209
				'<info>You are already using version %s (%s channel).</info>',
210
				$updater->getNewVersion(),
211
				$update_channel
212
			));
213
214
			return;
215
		}
216
217
		$this->io->write(
218
			'Updating to version <info>' . $updater->getNewVersion() . '</info> (' . $update_channel . ' channel) ... '
219
		);
220
221
		$updater->update();
222
223
		$this->io->writeln('done.');
224
225
		$this->io->writeln(sprintf(
226
			'Run <info>%s self-update --rollback</info> to return to version %s',
227
			$_SERVER['argv'][0],
228
			$updater->getOldVersion()
229
		));
230
	}
231
232
	/**
233
	 * Processes check.
234
	 *
235
	 * @return void
236
	 */
237
	protected function processCheck()
238
	{
239
		$updater = $this->_updateManager->getUpdater();
240
241
		$this->io->write('Checking for updates ... ');
242
		$has_update = $updater->hasUpdate();
243
		$this->io->writeln('done');
244
245
		$this->_updateManager->setNewVersion($has_update ? $updater->getNewVersion() : '');
246
	}
247
248
}
249