Passed
Push — install-models-command ( d7dd36...24a3b7 )
by Matias
04:31
created

SetupCommand   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 172
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 87
dl 0
loc 172
ccs 0
cts 96
cp 0
rs 10
c 1
b 0
f 0
wmc 20

7 Methods

Rating   Name   Duplication   Size   Complexity  
B bunzip2() 0 22 10
A getModelFile() 0 3 1
A configure() 0 4 1
A downloadModel() 0 51 5
A __construct() 0 6 1
A execute() 0 21 1
A getDownloadedFile() 0 3 1
1
<?php
2
/**
3
 * @copyright Copyright (c) 2019, Matias De lellis <[email protected]>
4
 *
5
 * @author Matias De lellis <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
namespace OCA\FaceRecognition\Command;
24
25
use OCP\ITempManager;
26
use OCP\App\IAppManager;
27
28
use Symfony\Component\Console\Command\Command;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Command\Command was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
use Symfony\Component\Console\Input\InputOption;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Input\InputOption was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use Symfony\Component\Console\Input\InputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Input\InputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
use Symfony\Component\Console\Output\OutputInterface;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Console\Output\OutputInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
32
33
class SetupCommand extends Command {
34
35
	/** @var \OCP\App\IAppManager **/
36
	protected $appManager;
37
38
	/** @var ITempManager */
39
	protected $tempManager;
40
41
	/** @var string */
42
	protected $tempFolder;
43
44
	/** @var string */
45
	protected $modelsFolder;
46
47
	/* @var  OutputInterface */
48
	protected $logger;
49
50
	/*
51
	 * Model 1
52
	 */
53
	private $detectorModelUrl = 'https://github.com/davisking/dlib-models/raw/94cdb1e40b1c29c0bfcaf7355614bfe6da19460e/mmod_human_face_detector.dat.bz2';
54
	private $detectorModel = 'mmod_human_face_detector.dat';
55
56
	private $resnetModelUrl = 'https://github.com/davisking/dlib-models/raw/2a61575dd45d818271c085ff8cd747613a48f20d/dlib_face_recognition_resnet_model_v1.dat.bz2';
57
	private $resnetModel = 'dlib_face_recognition_resnet_model_v1.dat';
58
59
	private $predictorModelUrl = 'https://github.com/davisking/dlib-models/raw/4af9b776281dd7d6e2e30d4a2d40458b1e254e40/shape_predictor_5_face_landmarks.dat.bz2';
60
	private $predictorModel = 'shape_predictor_5_face_landmarks.dat';
61
62
	/**
63
	 * @param FaceManagementService $faceManagementService
0 ignored issues
show
Bug introduced by
The type OCA\FaceRecognition\Command\FaceManagementService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
64
	 * @param IUserManager $userManager
0 ignored issues
show
Bug introduced by
The type OCA\FaceRecognition\Command\IUserManager was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
65
	 */
66
	public function __construct(IAppManager  $appManager,
67
	                            ITempManager $tempManager) {
68
		parent::__construct();
69
70
		$this->appManager = $appManager;
71
		$this->tempManager = $tempManager;
72
	}
73
74
	protected function configure() {
75
		$this
76
			->setName('face:setup')
77
			->setDescription('Download and Setup the model 1 used for the analysis');
78
	}
79
80
	/**
81
	 * @param InputInterface $input
82
	 * @param OutputInterface $output
83
	 * @return int
84
	 */
85
	protected function execute(InputInterface $input, OutputInterface $output) {
86
		$this->logger = $output;
87
88
		$this->tempFolder = $this->tempManager->getTemporaryFolder('/facerecognition/');
89
		$this->modelsFolder = $this->appManager->getAppPath('facerecognition') . '/vendor/models/1/';
90
91
		$this->downloadModel ($this->detectorModelUrl);
92
		$this->bunzip2 ($this->getDownloadedFile($this->detectorModelUrl), $this->getModelFile($this->detectorModel));
93
94
		$this->downloadModel ($this->resnetModelUrl);
95
		$this->bunzip2 ($this->getDownloadedFile($this->resnetModelUrl), $this->getModelFile($this->resnetModel));
96
97
		$this->downloadModel ($this->predictorModelUrl);
98
		$this->bunzip2 ($this->getDownloadedFile($this->predictorModelUrl), $this->getModelFile($this->predictorModel));
99
100
		$this->logger->writeln('Install models successfully done');
101
		die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
102
103
		$this->tempManager->clean();
0 ignored issues
show
Unused Code introduced by
$this->tempManager->clean() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
104
105
		return 0;
106
	}
107
108
	/**
109
	 * Downloads the facereconition model to $/updater-$instanceid/downloads/$filename
110
	 *
111
	 * @throws \Exception
112
	 */
113
	private function downloadModel(string $url) {
114
		$this->logger->writeln('Downloading: ' . $url . ' on ' . $this->getDownloadedFile($url));
115
116
		$fp = fopen($this->getDownloadedFile($url), 'w+');
117
		$ch = curl_init($url);
118
		curl_setopt_array($ch, [
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_setopt_array() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

118
		curl_setopt_array(/** @scrutinizer ignore-type */ $ch, [
Loading history...
119
			CURLOPT_FILE => $fp,
120
			CURLOPT_FOLLOWLOCATION => true,
121
			CURLOPT_SSL_VERIFYPEER => false,
122
			CURLOPT_SSL_VERIFYHOST => 0,
123
			CURLOPT_USERAGENT => 'Nextcloud Facerecognition Installer',
124
		]);
125
126
		if(curl_exec($ch) === false) {
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_exec() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

126
		if(curl_exec(/** @scrutinizer ignore-type */ $ch) === false) {
Loading history...
127
			throw new \Exception('Curl error: ' . curl_error($ch));
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_error() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

127
			throw new \Exception('Curl error: ' . curl_error(/** @scrutinizer ignore-type */ $ch));
Loading history...
128
		}
129
130
		$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_getinfo() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

130
		$httpCode = curl_getinfo(/** @scrutinizer ignore-type */ $ch, CURLINFO_HTTP_CODE);
Loading history...
131
		if ($httpCode !== 200) {
132
			$statusCodes = [
133
				400 => 'Bad request',
134
				401 => 'Unauthorized',
135
				403 => 'Forbidden',
136
				404 => 'Not Found',
137
				500 => 'Internal Server Error',
138
				502 => 'Bad Gateway',
139
				503 => 'Service Unavailable',
140
				504 => 'Gateway Timeout',
141
			];
142
143
			$message = 'Download failed';
144
			if(isset($statusCodes[$httpCode])) {
145
				$message .= ' - ' . $statusCodes[$httpCode] . ' (HTTP ' . $httpCode . ')';
146
			} else {
147
				$message .= ' - HTTP status code: ' . $httpCode;
148
			}
149
150
			$curlErrorMessage = curl_error($ch);
151
			if(!empty($curlErrorMessage)) {
152
				$message .= ' - curl error message: ' . $curlErrorMessage;
153
			}
154
			$message .= ' - URL: ' . htmlentities($url);
155
156
			throw new \Exception($message);
157
		}
158
159
		$info = curl_getinfo($ch);
160
		$this->logger->writeln("Download ".$info['size_download']." bytes");
161
162
		curl_close($ch);
0 ignored issues
show
Bug introduced by
It seems like $ch can also be of type false; however, parameter $ch of curl_close() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

162
		curl_close(/** @scrutinizer ignore-type */ $ch);
Loading history...
163
		fclose($fp);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

163
		fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
164
	}
165
166
	/**
167
	 * @param string $in
168
	 * @param string $out
169
	 * @desc uncompressing the file with the bzip2-extension
170
	 *
171
	 * @throws \Exception
172
	 */
173
	private function bunzip2 ($in, $out) {
174
		$this->logger->writeln('Decompresing: '.$in. ' on '.$out);
175
		$this->logger->writeln('');
176
177
		if (!file_exists ($in) || !is_readable ($in))
178
			throw new \Exception('The file '.$in.' not exists or is not readable');
179
		if ((!file_exists ($out) && !is_writeable (dirname ($out)) || (file_exists($out) && !is_writable($out)) ))
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (! file_exists($out) && ... && ! is_writable($out), Probably Intended Meaning: ! file_exists($out) && (...&& ! is_writable($out))
Loading history...
180
			throw new \Exception('The file '.$out.' exists or is not writable');
181
182
		$in_file = bzopen ($in, "r");
183
		$out_file = fopen ($out, "w");
184
185
		while ($buffer = bzread ($in_file, 4096)) {
186
			if($buffer === FALSE)
187
				throw new \Exception('Read problem:  ' . bzerrstr($in_file));
188
			if(bzerrno($in_file) !== 0)
189
				throw new \Exception('Compression problem: '. bzerrstr($in_file));
190
			fwrite ($out_file, $buffer, 4096);
0 ignored issues
show
Bug introduced by
It seems like $out_file can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

190
			fwrite (/** @scrutinizer ignore-type */ $out_file, $buffer, 4096);
Loading history...
191
		}
192
193
		bzclose ($in_file);
194
		fclose ($out_file);
0 ignored issues
show
Bug introduced by
It seems like $out_file can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

194
		fclose (/** @scrutinizer ignore-type */ $out_file);
Loading history...
195
	}
196
197
	private function getDownloadedFile (string $url): string {
198
		$file = $this->tempFolder . basename($url);
199
		return $file;
200
	}
201
202
	private function getModelFile (string $name): string {
203
		$file = $this->modelsFolder . $name;
204
		return $file;
205
	}
206
207
}
208