Completed
Pull Request — master (#355)
by Victor
03:09
created

Application::setAuthToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 3
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
/**
4
 * @author Victor Dubiniuk <[email protected]>
5
 *
6
 * @copyright Copyright (c) 2015, ownCloud, Inc.
7
 * @license AGPL-3.0
8
 *
9
 * This code is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License, version 3,
11
 * as published by the Free Software Foundation.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License, version 3,
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
20
 *
21
 */
22
23
namespace Owncloud\Updater\Console;
24
25
use Owncloud\Updater\Utils\DocLink;
26
use Owncloud\Updater\Utils\Locator;
27
use Pimple\Container;
28
use Symfony\Component\Console\Logger\ConsoleLogger;
29
use Symfony\Component\Console\Output\ConsoleOutput;
30
use Symfony\Component\Console\Output\StreamOutput;
31
use Symfony\Component\Console\Input\InputInterface;
32
use Symfony\Component\Console\Output\BufferedOutput;
33
use Symfony\Component\Console\Output\OutputInterface;
34
use Symfony\Component\Console\Command\Command;
35
use \Symfony\Component\Process\Exception\ProcessFailedException;
36
37
/**
38
 * Class Application
39
 *
40
 * @package Owncloud\Updater\Console
41
 */
42
class Application extends \Symfony\Component\Console\Application {
43
44
	/** @var Container */
45
	public static $container;
46
47
	/** @var Container */
48
	protected $diContainer;
49
50
	/** @var ConsoleLogger */
51
	protected $fallbackLogger;
52
53
	/** @var  string */
54
	protected $endpoint;
55
56
	/** @var  string */
57
	protected $authToken;
58
59
	/** @var array */
60
	protected $allowFailure = [
61
		'upgrade:executeCoreUpgradeScripts',
62
		'upgrade:checkpoint',
63
		'upgrade:maintenanceMode',
64
		'help',
65
		'list'
66
	];
67
68
	/**
69
	 * Pass Pimple container into application
70
	 * @param Container $container
71
	 */
72
	public function setContainer(Container $container){
73
		$this->diContainer = $container;
74
		self::$container = $container;
75
	}
76
77
	/**
78
	 * Get Pimple container
79
	 * @return Container
80
	 */
81
	public function getContainer(){
82
		return $this->diContainer;
83
	}
84
85
	/**
86
	 * @param string $endpoint
87
	 */
88
	public function setEndpoint($endpoint){
89
		$this->endpoint = $endpoint;
90
	}
91
92
	/**
93
	 * @return string
94
	 */
95
	public function getEndpoint(){
96
		return $this->endpoint;
97
	}
98
99
	/**
100
	 * @param $token
101
	 */
102
	public function setAuthToken($token){
103
		$this->authToken = $token;
104
	}
105
106
	/**
107
	 * @return string
108
	 */
109
	public function getAuthToken(){
110
		return $this->authToken;
111
	}
112
113
	/**
114
	 * Get logger instance
115
	 * @return \Psr\Log\LoggerInterface
116
	 */
117
	public function getLogger(){
118
		if (isset($this->diContainer['logger'])) {
119
			return $this->diContainer['logger'];
120
		}
121
122
		// Logger is not available yet, fallback to stdout
123
		if (is_null($this->fallbackLogger)){
124
			$output = new ConsoleOutput();
125
			$this->fallbackLogger = new ConsoleLogger($output);
126
		}
127
128
		return $this->fallbackLogger;
129
	}
130
131
	/**
132
	 * Log exception with trace
133
	 * @param \Exception $e
134
	 */
135
	public function logException($e){
136
		$buffer = new BufferedOutput(OutputInterface::VERBOSITY_VERBOSE);
137
		$this->renderException($e, $buffer);
138
		$this->getLogger()->error($buffer->fetch());
139
	}
140
141
	/**
142
	 * Runs the current application.
143
	 *
144
	 * @param InputInterface $input An Input instance
145
	 * @param OutputInterface $output An Output instance
146
	 * @return int 0 if everything went fine, or an error code
147
	 * @throws \Exception
148
	 */
149
	public function doRun(InputInterface $input, OutputInterface $output){
150
		try{
151
			$configReader = $this->diContainer['utils.configReader'];
152
			$commandName = $this->getCommandName($input);
153
			try{
154
				$configReader->init();
155
				$this->diContainer['utils.docLink'] = function($c){
156
					$locator = $c['utils.locator'];
157
					$installedVersion = implode('.', $locator->getInstalledVersion());
158
					return new DocLink($installedVersion);
159
				};
160
			} catch (ProcessFailedException $e){
161
				if (!in_array($commandName, $this->allowFailure)){
162
					$this->logException($e);
163
					$output->writeln("<error>Initialization failed with message:</error>");
164
					$output->writeln($e->getProcess()->getOutput());
165
					$output->writeln('<info>Use upgrade:checkpoint --list to view a list of checkpoints</info>');
166
					$output->writeln('<info>upgrade:checkpoint --restore [checkpointid] to revert to the last checkpoint</info>');
167
					$output->writeln('Please attach your update.log to the issues you reporting.');
168
					return 1;
169
				}
170
			}
171
			// TODO: check if the current command needs a valid OC instance
172
			$this->assertOwnCloudFound();
173
			
174
			return parent::doRun($input, $output);
175
		} catch (\Exception $e){
176
			$this->logException($e);
177
			throw $e;
178
		}
179
	}
180
181
	/**
182
	 * @param Command $command
183
	 * @param InputInterface $input
184
	 * @param OutputInterface $output
185
	 * @return int
186
	 * @throws \Exception
187
	 */
188
	protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output){
189
		if ($command instanceof \Owncloud\Updater\Command\Command){
190
			$command->setContainer($this->getContainer());
191
			$commandName = $this->getCommandName($input);
192
			$this->getLogger()->info('Execution of ' . $commandName . ' command started');
193
			if (!empty($command->getMessage())){
194
				$message = sprintf('<info>%s</info>', $command->getMessage());
195
				$output->writeln($message);
196
			}
197
			$exitCode = parent::doRunCommand($command, $input, $output);
198
			$this->getLogger()->info(
199
					'Execution of ' . $commandName . ' command stopped. Exit code is ' . $exitCode
200
			);
201
		} else {
202
			$exitCode = parent::doRunCommand($command, $input, $output);
203
		}
204
		return $exitCode;
205
	}
206
207
	/**
208
	 * @param string $baseDir
209
	 */
210
	protected function initLogger($baseDir){
211
		$container = $this->getContainer();
212
		$container['logger.output'] = function($c) use ($baseDir) {
0 ignored issues
show
Unused Code introduced by
The parameter $c is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
213
			$stream = @fopen($baseDir . '/update.log', 'a+');
214
			if ($stream === false){
215
				$stream = @fopen('php://stderr', 'a');
216
			}
217
			return new StreamOutput($stream, StreamOutput::VERBOSITY_DEBUG, false);
218
		};
219
		$container['logger'] = function($c){
220
			return new ConsoleLogger($c['logger.output']);
221
		};
222
	}
223
224
	/**
225
	 * Check for ownCloud instance
226
	 * @throws \RuntimeException
227
	 */
228
	protected function assertOwnCloudFound(){
229
		$container = $this->getContainer();
230
		/** @var Locator $locator */
231
		$locator = $container['utils.locator'];
232
		$fsHelper = $container['utils.filesystemhelper'];
233
234
		// assert minimum version
235
		$installedVersion = implode('.', $locator->getInstalledVersion());
236
		if (version_compare($installedVersion, '9.0.0', '<')){
237
			throw new \RuntimeException("Minimum ownCloud version 9.0.0 is required for the updater - $installedVersion was found in " . $locator->getOwnCloudRootPath());
238
		}
239
240
		// has to be installed
241
		$file = $locator->getPathToConfigFile();
242 View Code Duplication
		if (!file_exists($file) || !is_file($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...
243
			throw new \RuntimeException('ownCloud in ' . dirname(dirname($file)) . ' is not installed.');
244
		}
245
246
		// version.php should exist
247
		$file = $locator->getPathToVersionFile();
248 View Code Duplication
		if (!file_exists($file) || !is_file($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...
249
			throw new \RuntimeException('ownCloud is not found in ' . dirname($file));
250
		}
251
252
		// datadir should exist
253
		$dataDir = $locator->getDataDir();
254
		if (!$fsHelper->fileExists($dataDir)){
255
			throw new \RuntimeException('Datadirectory ' . $dataDir . ' does not exist.');
256
		}
257
258
		// datadir should be writable
259
		if (!$fsHelper->isWritable($dataDir)){
260
			throw new \RuntimeException('Datadirectory ' . $dataDir . ' is not writable.');
261
		}
262
263
		if (!isset($this->diContainer['logger'])) {
264
			$this->initLogger($dataDir);
0 ignored issues
show
Unused Code introduced by
The call to the method Owncloud\Updater\Console\Application::initLogger() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
265
		}
266
267
		if (!$fsHelper->fileExists($locator->getUpdaterBaseDir())){
268
			$fsHelper->mkdir($locator->getUpdaterBaseDir());
269
		}
270
271
		if (!$fsHelper->fileExists($locator->getDownloadBaseDir())){
272
			$fsHelper->mkdir($locator->getDownloadBaseDir());
273
		}
274
		if (!$fsHelper->fileExists($locator->getCheckpointDir())){
275
			$fsHelper->mkdir($locator->getCheckpointDir());
276
		}
277
	}
278
}
279