Completed
Push — master ( cc98f3...674943 )
by Alexander
03:06
created

SelfUpdateCommand::getFreshVersion()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 16
ccs 0
cts 9
cp 0
rs 9.4285
cc 2
eloc 9
nc 2
nop 0
crap 6
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\Updater\Stability;
17
use ConsoleHelpers\SVNBuddy\Updater\Updater;
18
use ConsoleHelpers\SVNBuddy\Updater\VersionUpdateStrategy;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22
use Symfony\Component\Process\PhpExecutableFinder;
23
use Symfony\Component\Process\Process;
24
use Symfony\Component\Process\ProcessBuilder;
25
26
class SelfUpdateCommand extends AbstractCommand
27
{
28
29
	/**
30
	 * Config editor.
31
	 *
32
	 * @var ConfigEditor
33
	 */
34
	private $_configEditor;
35
36
	/**
37
	 * {@inheritdoc}
38
	 */
39
	protected function configure()
40
	{
41
		$this
42
			->setName('self-update')
43
			->setDescription(
44
				'Update application to most recent version'
45
			)
46
			->addOption(
47
				'rollback',
48
				'r',
49
				InputOption::VALUE_NONE,
50
				'Revert to an older version of the application'
51
			)
52
			->addOption(
53
				'stable',
54
				null,
55
				InputOption::VALUE_NONE,
56
				'Force an update to the stable channel'
57
			)
58
			->addOption(
59
				'snapshot',
60
				null,
61
				InputOption::VALUE_NONE,
62
				'Force an update to the snapshot channel'
63
			)
64
			->addOption(
65
				'preview',
66
				null,
67
				InputOption::VALUE_NONE,
68
				'Force an update to the preview channel'
69
			);
70
71
		parent::configure();
72
	}
73
74
	/**
75
	 * Prepare dependencies.
76
	 *
77
	 * @return void
78
	 */
79
	protected function prepareDependencies()
80
	{
81
		parent::prepareDependencies();
82
83
		$container = $this->getContainer();
84
85
		$this->_configEditor = $container['config_editor'];
86
	}
87
88
	/**
89
	 * {@inheritdoc}
90
	 */
91
	protected function execute(InputInterface $input, OutputInterface $output)
92
	{
93
		if ( $this->io->getOption('rollback') ) {
94
			$this->processRollback();
95
		}
96
		else {
97
			$this->processUpdate();
98
		}
99
	}
100
101
	/**
102
	 * Returns update channel.
103
	 *
104
	 * @return string
105
	 */
106
	protected function getUpdateChannel()
107
	{
108
		if ( $this->io->getOption('stable') ) {
109
			$this->_configEditor->set('update-channel', Stability::STABLE);
110
		}
111
112
		if ( $this->io->getOption('snapshot') ) {
113
			$this->_configEditor->set('update-channel', Stability::SNAPSHOT);
114
		}
115
116
		if ( $this->io->getOption('preview') ) {
117
			$this->_configEditor->set('update-channel', Stability::PREVIEW);
118
		}
119
120
		return $this->_configEditor->get('update-channel');
121
	}
122
123
	/**
124
	 * Processes rollback.
125
	 *
126
	 * @return void
127
	 * @throws CommandException When rollback failed.
128
	 */
129
	protected function processRollback()
130
	{
131
		$updater = new Updater(null, false);
132
133
		// To get all needed classes autoloaded before phar gets overwritten.
134
		$this->getFreshVersion();
135
136
		if ( !$updater->rollback() ) {
137
			throw new CommandException('Failed to restore previous version.');
138
		}
139
140
		$this->io->writeln(
141
			'Rolling back to version <info>' . $this->getFreshVersion() . '</info>.'
142
		);
143
	}
144
145
	/**
146
	 * Returns fresh application version.
147
	 *
148
	 * @return string
149
	 * @throws \RuntimeException When PHP executable can't be found.
150
	 */
151
	protected function getFreshVersion()
152
	{
153
		$php_executable_finder = new PhpExecutableFinder();
154
		$php_executable = $php_executable_finder->find();
155
156
		if ( !$php_executable ) {
157
			throw new \RuntimeException('The PHP executable cannot be found.');
158
		}
159
160
		$arguments = array($php_executable, $_SERVER['argv'][0], 'list', '--format=xml');
161
		$output = ProcessBuilder::create($arguments)->getProcess()->mustRun()->getOutput();
162
163
		$xml = new \SimpleXMLElement($output);
164
165
		return (string)$xml['version'];
166
	}
167
168
	/**
169
	 * Processes update.
170
	 *
171
	 * @return void
172
	 */
173
	protected function processUpdate()
174
	{
175
		$update_strategy = new VersionUpdateStrategy();
176
		$update_channel = $this->getUpdateChannel();
177
		$update_strategy->setStability($update_channel);
178
		$update_strategy->setCurrentLocalVersion($this->getApplication()->getVersion());
179
180
		$updater = new Updater(null, false);
181
		$updater->setStrategyObject($update_strategy);
182
183
		if ( !$updater->hasUpdate() ) {
184
			$this->io->writeln(sprintf(
185
				'<info>You are already using version %s (%s channel).</info>',
186
				$updater->getNewVersion(),
187
				$update_channel
188
			));
189
190
			return;
191
		}
192
193
		$this->io->write(
194
			'Updating to version <info>' . $updater->getNewVersion() . '</info> (' . $update_channel . ' channel) ... '
195
		);
196
197
		$updater->update();
198
199
		$this->io->writeln('done.');
200
201
		$this->io->writeln(sprintf(
202
			'Use <info>%s self-update --rollback</info> to return to version %s',
203
			$_SERVER['argv'][0],
204
			$updater->getOldVersion()
205
		));
206
	}
207
208
}
209