Completed
Pull Request — master (#460)
by
unknown
06:08 queued 02:57
created

OccRunner::run()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 23
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 7.0986

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 11
cts 16
cp 0.6875
rs 8.5906
c 0
b 0
f 0
cc 6
eloc 18
nc 8
nop 3
crap 7.0986
1
<?php
2
/**
3
 * @author Victor Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2015, ownCloud, Inc.
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace Owncloud\Updater\Utils;
23
24
use GuzzleHttp\Client;
25
use Owncloud\Updater\Console\Application;
26
use Symfony\Component\Process\Process;
27
use Symfony\Component\Process\ProcessUtils;
28
use Symfony\Component\Process\Exception\ProcessFailedException;
29
30
/**
31
 * Class OccRunner
32
 *
33
 * @package Owncloud\Updater\Utils
34
 */
35
class OccRunner {
36
	/**
37
	 * @var Locator $locator
38
	 */
39
	protected $locator;
40
41
	/**
42
	 * @var bool
43
	 */
44
	protected $canUseProcess;
45
46
	/**
47
	 *
48
	 * @param Locator $locator
49
	 * @param bool $canUseProcess
50
	 */
51 2
	public function __construct(Locator $locator, $canUseProcess){
52 2
		$this->locator = $locator;
53 2
		$this->canUseProcess = $canUseProcess;
54 2
	}
55
56
	/**
57
	 * @param bool $canUseProcess
58
	 */
59
	public function setCanUseProcess($canUseProcess){
60
		$this->canUseProcess = $canUseProcess;
61
	}
62
63
	/**
64
	 * @param $command
65
	 * @param array $args
66
	 * @param bool $asJson
67
	 * @return string
68
	 */
69 2
	public function run($command, $args = [], $asJson = false){
70 2
		if ($this->canUseProcess){
71 1
			$extra = $asJson ? '--output=json' : '';
72 1
			$cmdLine = trim($command . ' ' . $extra);
73 1
			foreach ($args as $optionTitle => $optionValue){
74
				if (strpos($optionTitle, '--') === 0){
75
					$line = trim("$optionTitle=$optionValue");
76
				} else {
77
					$line = $optionValue;
78
				}
79
				$escapedLine = ProcessUtils::escapeArgument($line);
0 ignored issues
show
Bug introduced by
The method escapeArgument() does not seem to exist on object<Symfony\Component\Process\ProcessUtils>.

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...
80
				$cmdLine .= " $escapedLine";
81
			}
82 1
			return $this->runAsProcess($cmdLine);
83
		} else {
84 1
			if ($asJson){
85 1
				$args['--output'] = 'json';
86
			}
87 1
			$response = $this->runAsRequest($command, $args);
88 1
			$decodedResponse = json_decode($response, true);
89 1
			return $decodedResponse['response'];
90
		}
91
	}
92
93
	/**
94
	 * @param $command
95
	 * @param array $args
96
	 * @return mixed
97
	 */
98 5
	public function runJson($command, $args = []){
99 5
		$plain = $this->run($command, $args, true);
100
		// trim response to always be a valid json. Capture everything between the first and the last curly brace
101 5
		preg_match_all('!(\{.*\})!ms', $plain, $matches);
102 5
		$clean = isset($matches[1][0]) ? $matches[1][0] : '';
103 5
		$decoded = json_decode($clean, true);
104 5
		if (!is_array($decoded)){
105 1
			throw new \UnexpectedValueException('Could not parse a response for ' . $command . '. Please check if the current shell user can run occ command. Raw output: ' . PHP_EOL . $plain);
106
		}
107 4
		return $decoded;
108
	}
109
110
	/**
111
	 * @param $command
112
	 * @param $args
113
	 * @return string
114
	 */
115
	protected function runAsRequest($command, $args){
116
		$application = $this->getApplication();
117
		$client = new Client();
118
		$endpointBase = $application->getEndpoint();
119
		$params = [
120
			'timeout' => 0,
121
			'json' => [
122
				'token' => $application->getAuthToken(),
123
				'params'=> $args
124
			]
125
		];
126
		
127
		// Skip SSL validation for localhost only as localhost never has a valid cert
128
		if (preg_match('/^https:\/\/localhost\/.*/i', $endpointBase)){
129
			$params['verify'] = false;
130
		}
131
		
132
		$request = $client->createRequest(
133
			'POST',
134
			$endpointBase . $command,
135
			$params
136
		);
137
138
		$response = $client->send($request);
139
		$responseBody = $response->getBody()->getContents();
140
		return $responseBody;
141
	}
142
143
	/**
144
	 * @return mixed
145
	 */
146
	protected function getApplication(){
147
		$container = Application::$container;
148
		$application = $container['application'];
149
		return $application;
150
	}
151
152
	/**
153
	 * @param $cmdLine
154
	 * @return string
155
	 */
156
	protected function runAsProcess($cmdLine){
157
		$occPath = $this->locator->getPathToOccFile();
158
		$cmd = "php $occPath --no-warnings $cmdLine";
159
		$process = new Process($cmd);
160
		$process->setTimeout(null);
161
		$process->run();
162
163
		if (!$process->isSuccessful()){
164
			throw new ProcessFailedException($process);
165
		}
166
		return $process->getOutput();
167
	}
168
}
169