Completed
Pull Request — master (#355)
by Victor
02:51
created

Application::getEndpoint()   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 0
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
57
	/** @var array */
58
	protected $allowFailure = [
59
		'upgrade:executeCoreUpgradeScripts',
60
		'upgrade:checkpoint',
61
		'upgrade:maintenanceMode',
62
		'help',
63
		'list'
64
	];
65
66
	/**
67
	 * Pass Pimple container into application
68
	 * @param Container $container
69
	 */
70
	public function setContainer(Container $container){
71
		$this->diContainer = $container;
72
		self::$container = $container;
73
	}
74
75
	/**
76
	 * Get Pimple container
77
	 * @return Container
78
	 */
79
	public function getContainer(){
80
		return $this->diContainer;
81
	}
82
83
	/**
84
	 * @param string $endpoint
85
	 */
86
	public function setEndpoint($endpoint){
87
		$this->endpoint = $endpoint;
88
	}
89
90
	/**
91
	 * @return string
92
	 */
93
	public function getEndpoint(){
94
		return $this->endpoint;
95
	}
96
97
	/**
98
	 * Get logger instance
99
	 * @return \Psr\Log\LoggerInterface
100
	 */
101
	public function getLogger(){
102
		if (isset($this->diContainer['logger'])) {
103
			return $this->diContainer['logger'];
104
		}
105
106
		// Logger is not available yet, fallback to stdout
107
		if (is_null($this->fallbackLogger)){
108
			$output = new ConsoleOutput();
109
			$this->fallbackLogger = new ConsoleLogger($output);
110
		}
111
112
		return $this->fallbackLogger;
113
	}
114
115
	/**
116
	 * Log exception with trace
117
	 * @param \Exception $e
118
	 */
119
	public function logException($e){
120
		$buffer = new BufferedOutput(OutputInterface::VERBOSITY_VERBOSE);
121
		$this->renderException($e, $buffer);
122
		$this->getLogger()->error($buffer->fetch());
123
	}
124
125
	/**
126
	 * Runs the current application.
127
	 *
128
	 * @param InputInterface $input An Input instance
129
	 * @param OutputInterface $output An Output instance
130
	 * @return int 0 if everything went fine, or an error code
131
	 * @throws \Exception
132
	 */
133
	public function doRun(InputInterface $input, OutputInterface $output){
134
		try{
135
			$configReader = $this->diContainer['utils.configReader'];
136
			$commandName = $this->getCommandName($input);
137
			try{
138
				$configReader->init();
139
				$this->diContainer['utils.docLink'] = function($c){
140
					$locator = $c['utils.locator'];
141
					$installedVersion = implode('.', $locator->getInstalledVersion());
142
					return new DocLink($installedVersion);
143
				};
144
			} catch (ProcessFailedException $e){
145
				if (!in_array($commandName, $this->allowFailure)){
146
					$this->logException($e);
147
					$output->writeln("<error>Initialization failed with message:</error>");
148
					$output->writeln($e->getProcess()->getOutput());
149
					$output->writeln('<info>Use upgrade:checkpoint --list to view a list of checkpoints</info>');
150
					$output->writeln('<info>upgrade:checkpoint --restore [checkpointid] to revert to the last checkpoint</info>');
151
					$output->writeln('Please attach your update.log to the issues you reporting.');
152
					return 1;
153
				}
154
			}
155
			// TODO: check if the current command needs a valid OC instance
156
			$this->assertOwnCloudFound();
157
			
158
			return parent::doRun($input, $output);
159
		} catch (\Exception $e){
160
			$this->logException($e);
161
			throw $e;
162
		}
163
	}
164
165
	/**
166
	 * @param Command $command
167
	 * @param InputInterface $input
168
	 * @param OutputInterface $output
169
	 * @return int
170
	 * @throws \Exception
171
	 */
172
	protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output){
173
		if ($command instanceof \Owncloud\Updater\Command\Command){
174
			$command->setContainer($this->getContainer());
175
			$commandName = $this->getCommandName($input);
176
			$this->getLogger()->info('Execution of ' . $commandName . ' command started');
177
			if (!empty($command->getMessage())){
178
				$message = sprintf('<info>%s</info>', $command->getMessage());
179
				$output->writeln($message);
180
			}
181
			$exitCode = parent::doRunCommand($command, $input, $output);
182
			$this->getLogger()->info(
183
					'Execution of ' . $commandName . ' command stopped. Exit code is ' . $exitCode
184
			);
185
		} else {
186
			$exitCode = parent::doRunCommand($command, $input, $output);
187
		}
188
		return $exitCode;
189
	}
190
191
	/**
192
	 * @param string $baseDir
193
	 */
194
	protected function initLogger($baseDir){
195
		$container = $this->getContainer();
196
		$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...
197
			$stream = @fopen($baseDir . '/update.log', 'a+');
198
			if ($stream === false){
199
				$stream = @fopen('php://stderr', 'a');
200
			}
201
			return new StreamOutput($stream, StreamOutput::VERBOSITY_DEBUG, false);
202
		};
203
		$container['logger'] = function($c){
204
			return new ConsoleLogger($c['logger.output']);
205
		};
206
	}
207
208
	/**
209
	 * Check for ownCloud instance
210
	 * @throws \RuntimeException
211
	 */
212
	protected function assertOwnCloudFound(){
213
		$container = $this->getContainer();
214
		/** @var Locator $locator */
215
		$locator = $container['utils.locator'];
216
		$fsHelper = $container['utils.filesystemhelper'];
217
218
		// assert minimum version
219
		$installedVersion = implode('.', $locator->getInstalledVersion());
220
		if (version_compare($installedVersion, '9.0.0', '<')){
221
			throw new \RuntimeException("Minimum ownCloud version 9.0.0 is required for the updater - $installedVersion was found in " . $locator->getOwnCloudRootPath());
222
		}
223
224
		// has to be installed
225
		$file = $locator->getPathToConfigFile();
226 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...
227
			throw new \RuntimeException('ownCloud in ' . dirname(dirname($file)) . ' is not installed.');
228
		}
229
230
		// version.php should exist
231
		$file = $locator->getPathToVersionFile();
232 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...
233
			throw new \RuntimeException('ownCloud is not found in ' . dirname($file));
234
		}
235
236
		// datadir should exist
237
		$dataDir = $locator->getDataDir();
238
		if (!$fsHelper->fileExists($dataDir)){
239
			throw new \RuntimeException('Datadirectory ' . $dataDir . ' does not exist.');
240
		}
241
242
		// datadir should be writable
243
		if (!$fsHelper->isWritable($dataDir)){
244
			throw new \RuntimeException('Datadirectory ' . $dataDir . ' is not writable.');
245
		}
246
247
		if (!isset($this->diContainer['logger'])) {
248
			$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...
249
		}
250
251
		if (!$fsHelper->fileExists($locator->getUpdaterBaseDir())){
252
			$fsHelper->mkdir($locator->getUpdaterBaseDir());
253
		}
254
255
		if (!$fsHelper->fileExists($locator->getDownloadBaseDir())){
256
			$fsHelper->mkdir($locator->getDownloadBaseDir());
257
		}
258
		if (!$fsHelper->fileExists($locator->getCheckpointDir())){
259
			$fsHelper->mkdir($locator->getCheckpointDir());
260
		}
261
	}
262
}
263