Completed
Push — master ( 347a51...ad246f )
by Maxence
02:23
created

Index::abort()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
c 0
b 0
f 0
rs 10
nc 2
cc 2
nop 0
1
<?php
2
declare(strict_types=1);
3
4
5
/**
6
 * FullTextSearch - Full text search framework for Nextcloud
7
 *
8
 * This file is licensed under the Affero General Public License version 3 or
9
 * later. See the COPYING file.
10
 *
11
 * @author Maxence Lange <[email protected]>
12
 * @copyright 2018
13
 * @license GNU AGPL version 3 or any later version
14
 *
15
 * This program is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License as
17
 * published by the Free Software Foundation, either version 3 of the
18
 * License, or (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27
 *
28
 */
29
30
31
namespace OCA\FullTextSearch\Command;
32
33
34
use daita\MySmallPhpTools\Traits\TArrayTools;
35
use Exception;
36
use OC\Core\Command\InterruptedException;
37
use OCA\FullTextSearch\ACommandBase;
38
use OCA\FullTextSearch\Exceptions\TickDoesNotExistException;
39
use OCA\FullTextSearch\Model\Index as ModelIndex;
40
use OCA\FullTextSearch\Model\IndexOptions;
41
use OCA\FullTextSearch\Model\Runner;
42
use OCA\FullTextSearch\Service\CliService;
43
use OCA\FullTextSearch\Service\IndexService;
44
use OCA\FullTextSearch\Service\MiscService;
45
use OCA\FullTextSearch\Service\PlatformService;
46
use OCA\FullTextSearch\Service\ProviderService;
47
use OCA\FullTextSearch\Service\RunningService;
48
use OCP\FullTextSearch\IFullTextSearchProvider;
49
use OCP\IUserManager;
50
use OutOfBoundsException;
51
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
52
use Symfony\Component\Console\Input\InputArgument;
53
use Symfony\Component\Console\Input\InputInterface;
54
use Symfony\Component\Console\Input\InputOption;
55
use Symfony\Component\Console\Output\OutputInterface;
56
use Symfony\Component\Console\Terminal;
57
use Throwable;
58
59
60
/**
61
 * Class Index
62
 *
63
 * @package OCA\FullTextSearch\Command
64
 */
65
class Index extends ACommandBase {
66
67
68
	use TArrayTools;
69
70
71
	const INDEX_OPTION_NO_READLINE = '_no-readline';
72
73
//			'%job:1s%%message:-40s%%current:6s%/%max:6s% [%bar%] %percent:3s%% \n %duration% %infos:-12s% %jvm:-30s%      '
74
	const PANEL_RUN = 'run';
75
	const PANEL_RUN_LINE_OPTIONS = 'Options: %options%';
76
	const PANEL_RUN_LINE_MEMORY = 'Memory: %_memory%';
77
78
	const PANEL_INDEX = 'indexing';
79
	const PANEL_INDEX_LINE_HEADER = '┌─ Indexing %_paused% ────';
80
	const PANEL_INDEX_LINE_ACCOUNT = '│ Provider: <info>%providerName:-20s%</info> Account: <info>%userId%</info>';
81
	const PANEL_INDEX_LINE_ACTION = '│ Action: <info>%action%</info>';
82
	const PANEL_INDEX_LINE_DOCUMENT = '│ Document: <info>%documentId%</info>';
83
	const PANEL_INDEX_LINE_INFO = '│ Info: <info>%info%</info>';
84
	const PANEL_INDEX_LINE_TITLE = '│ Title: <info>%title%</info>';
85
	const PANEL_INDEX_LINE_CONTENT = '│ Content size: <info>%content%</info>';
86
	const PANEL_INDEX_LINE_PROGRESS = '│ Progress: %documentCurrent:6s%/%documentTotal%';
87
	const PANEL_INDEX_LINE_FOOTER = '└──';
88
89
	const PANEL_RESULT = 'result';
90
	const PANEL_RESULT_LINE_HEADER = '┌─ Results ────';
91
	const PANEL_RESULT_LINE_RESULT = '│ Result: <info>%resultCurrent:6s%</info>/<info>%resultTotal%</info>';
92
	const PANEL_RESULT_LINE_INDEX = '│ Index: <info>%resultIndex%</info>';
93
	const PANEL_RESULT_LINE_STATUS = '│ Status: %resultStatusColored%';
94
	const PANEL_RESULT_LINE_MESSAGE1 = '│ Message: <info>%resultMessageA%</info>';
95
	const PANEL_RESULT_LINE_MESSAGE2 = '│ <info>%resultMessageB%</info>';
96
	const PANEL_RESULT_LINE_MESSAGE3 = '│ <info>%resultMessageC%</info>';
97
	const PANEL_RESULT_LINE_FOOTER = '└──';
98
99
	const PANEL_ERRORS = 'errors';
100
	const PANEL_ERRORS_LINE_HEADER = '┌─ Errors ────';
101
	const PANEL_ERRORS_LINE_ERRORS = '│ Error: <comment>%errorCurrent:6s%</comment>/<comment>%errorTotal%</comment>';
102
	const PANEL_ERRORS_LINE_ERROR_INDEX = '│ Index: <comment>%errorIndex%</comment>';
103
	const PANEL_ERRORS_LINE_ERROR_EXCEPTION = '│ Exception: <comment>%errorException%</comment>';
104
	const PANEL_ERRORS_LINE_ERROR_MESSAGE1 = '│ Message: <comment>%errorMessageA%</comment>';
105
	const PANEL_ERRORS_LINE_ERROR_MESSAGE2 = '│ <comment>%errorMessageB%</comment>';
106
	const PANEL_ERRORS_LINE_ERROR_MESSAGE3 = '│ <comment>%errorMessageC%</comment>';
107
	const PANEL_ERRORS_LINE_FOOTER = '└──';
108
109
	const PANEL_COMMANDS_ROOT = 'root';
110
	const PANEL_COMMANDS_ROOT_LINE = '## <char>q</char>:quit ## <char>p</char>:pause ';
111
	const PANEL_COMMANDS_PAUSED = 'paused';
112
	const PANEL_COMMANDS_PAUSED_LINE = '## <char>q</char>:quit ## <char>u</char>:unpause ## <char>n</char>:next step';
113
	const PANEL_COMMANDS_DONE = 'done';
114
	const PANEL_COMMANDS_DONE_LINE = '## <char>q</char>:quit';
115
	const PANEL_COMMANDS_NAVIGATION = 'navigation';
116
	const PANEL_COMMANDS_ERRORS_LINE = '## <char>f</char>:first error ## <char>h</char>/<char>j</char>:prec/next error ## <char>d</char>:delete error ## <char>l</char>:last error';
117
	const PANEL_COMMANDS_RESULTS_LINE = '## <char>x</char>:first result ## <char>c</char>/<char>v</char>:prec/next result ## <char>b</char>:last result';
118
119
	/** @var IUserManager */
120
	private $userManager;
121
122
	/** @var RunningService */
123
	private $runningService;
124
125
	/** @var CliService */
126
	private $cliService;
127
128
	/** @var IndexService */
129
	private $indexService;
130
131
	/** @var PlatformService */
132
	private $platformService;
133
134
	/** @var ProviderService */
135
	private $providerService;
136
137
	/** @var MiscService */
138
	private $miscService;
139
140
141
	/** @var Runner */
142
	private $runner;
143
144
	/** @var Terminal */
145
	private $terminal;
146
147
	/** @var array */
148
	private $results = [];
149
150
	/** @var bool */
151
	private $navigateLastResult = true;
152
153
	/** @var array */
154
	private $errors = [];
155
156
	/** @var bool */
157
	private $navigateLastError = true;
158
159
160
	/**
161
	 * Index constructor.
162
	 *
163
	 * @param IUserManager $userManager
164
	 * @param RunningService $runningService
165
	 * @param CliService $cliService
166
	 * @param IndexService $indexService
167
	 * @param PlatformService $platformService
168
	 * @param ProviderService $providerService
169
	 * @param MiscService $miscService
170
	 */
171 View Code Duplication
	public function __construct(
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
172
		IUserManager $userManager, RunningService $runningService, CliService $cliService,
173
		IndexService $indexService, PlatformService $platformService,
174
		ProviderService $providerService, MiscService $miscService
175
	) {
176
		parent::__construct();
177
		$this->userManager = $userManager;
178
179
		$this->runningService = $runningService;
180
		$this->cliService = $cliService;
181
		$this->indexService = $indexService;
182
183
		$this->platformService = $platformService;
184
		$this->providerService = $providerService;
185
		$this->miscService = $miscService;
186
	}
187
188
189
	/**
190
	 *
191
	 */
192
	protected function configure() {
193
		parent::configure();
194
		$this->setName('fulltextsearch:index')
195
			 ->setDescription('Index files')
196
			 ->addArgument('options', InputArgument::OPTIONAL, 'options')
197
			 ->addOption(
198
				 'no-readline', 'r', InputOption::VALUE_NONE,
199
				 'disable readline - non interactive mode'
200
			 );
201
	}
202
203
204
	/**
205
	 * @param InputInterface $input
206
	 * @param OutputInterface $output
207
	 *
208
	 * @return int|null|void
209
	 * @throws Exception
210
	 */
211
	protected function execute(InputInterface $input, OutputInterface $output) {
212
213
		$options = $this->generateIndexOptions($input);
214
215
		if ($options->getOptionBool(self::INDEX_OPTION_NO_READLINE, false) === false) {
216
			/** do not get stuck while waiting interactive input */
217
			try {
218
				readline_callback_handler_install(
219
					'', function() {
220
				}
221
				);
222
			} catch (Throwable $t) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
223
				throw new Exception('Please install php-readline, or use --no-readline');
224
			}
225
		}
226
227
		stream_set_blocking(STDIN, false);
228
229
		$this->terminal = new Terminal();
230
231
		$outputStyle = new OutputFormatterStyle('white', 'black', ['bold']);
232
		$output->getFormatter()
233
			   ->setStyle('char', $outputStyle);
234
235
		$this->runner = new Runner($this->runningService, 'commandIndex', ['nextStep' => 'n']);
236
		$this->runner->onKeyPress([$this, 'onKeyPressed']);
237
		$this->runner->onNewIndexError([$this, 'onNewIndexError']);
238
		$this->runner->onNewIndexResult([$this, 'onNewIndexResult']);
239
		$this->runner->pause($options->getOptionBool('paused', false));
240
241
		$this->indexService->setRunner($this->runner);
242
		$this->cliService->setRunner($this->runner);
243
244
		$this->generatePanels($options);
245
		$this->runner->setInfo('options', json_encode($options));
246
247
		try {
248
			$this->runner->sourceIsCommandLine($this, $output);
249
			$this->runner->start();
250
251
			if ($options->getOption('errors') === 'reset') {
252
				$this->indexService->resetErrorsAll();
253
			}
254
255
			$this->testPlatform();
256
			$this->cliService->runDisplay($output);
257
			$this->generateIndexErrors();
258
			$this->displayError();
259
			$this->displayResult();
260
261
			$providers = $this->providerService->getProviders();
262
			foreach ($providers as $providerWrapper) {
263
				$provider = $providerWrapper->getProvider();
264
265
				if (!$this->isIncludedProvider($options, $provider->getId())) {
266
					continue;
267
				}
268
269
				$provider->setRunner($this->runner);
270
				$provider->setIndexOptions($options);
271
				$this->indexProvider($provider, $options);
272
			}
273
274
		} catch (Exception $e) {
275
			$this->runner->exception($e->getMessage(), true);
0 ignored issues
show
Deprecated Code introduced by
The method OCA\FullTextSearch\Model\Runner::exception() has been deprecated with message: - verifier l'interet !?

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
276
			throw $e;
277
		}
278
279
		$this->runner->setInfo('documentCurrent', 'all');
280
		$this->runner->stop();
281
282
//		while (true) {
283
//			$this->runner->updateAction('_indexOver', true);
284
//			$pressed = strtolower($this->updateAction(''));
285
//			if ($pressed === $this->keys['nextStep']) {
286
//				$this->pauseRunning(false);
287
//				break;
288
//			}
289
//			usleep(300000);
290
//		}
291
292
293
//		$output->writeLn('');
294
295
	}
296
297
298
	/**
299
	 * @param string $key
300
	 */
301 View Code Duplication
	public function onKeyPressed(string $key) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
302
		$key = strtolower($key);
303
		if ($key === 'q') {
304
			try {
305
				$this->runner->stop();
306
			} catch (TickDoesNotExistException $e) {
307
				/** we do nohtin' */
308
			}
309
			exit();
310
		}
311
312
		$current = $this->cliService->currentPanel('commands');
313
		if ($current === self::PANEL_COMMANDS_ROOT && $key === 'p') {
314
			$this->cliService->switchPanel('commands', self::PANEL_COMMANDS_PAUSED);
315
			$this->runner->pause(true);
316
		}
317
		if ($current === self::PANEL_COMMANDS_PAUSED && $key === 'u') {
318
			$this->cliService->switchPanel('commands', self::PANEL_COMMANDS_ROOT);
319
			$this->runner->pause(false);
320
		}
321
322
		if ($key === 'x') {
323
			$this->displayResult(-99);
324
		}
325
		if ($key === 'c') {
326
			$this->displayResult(-1);
327
		}
328
		if ($key === 'v') {
329
			$this->displayResult(1);
330
		}
331
		if ($key === 'b') {
332
			$this->displayResult(99);
333
		}
334
335
		if ($key === 'f') {
336
			$this->displayError(-99);
337
		}
338
		if ($key === 'h') {
339
			$this->displayError(-1);
340
		}
341
		if ($key === 'j') {
342
			$this->displayError(1);
343
		}
344
		if ($key === 'l') {
345
			$this->displayError(99);
346
		}
347
		if ($key === 'd') {
348
			$this->deleteError();
349
		}
350
	}
351
352
353
	/**
354
	 * @param array $error
355
	 */
356
	public function onNewIndexError(array $error) {
357
		$this->errors[] = $error;
358
		$this->displayError();
359
	}
360
361
362
	/**
363
	 * @param array $result
364
	 */
365
	public function onNewIndexResult(array $result) {
366
		$this->results[] = $result;
367
		$this->displayResult();
368
	}
369
370
371
	/**
372
	 * @throws Exception
373
	 */
374
	private function testPlatform() {
375
		$wrapper = $this->platformService->getPlatform();
376
		$platform = $wrapper->getPlatform();
377
378
		if (!$platform->testPlatform()) {
379
			throw new Exception('failed platform test.');
380
		}
381
	}
382
383
384
	/**
385
	 * @param IFullTextSearchProvider $provider
386
	 * @param IndexOptions $options
387
	 *
388
	 * @throws Exception
389
	 */
390
	private function indexProvider(IFullTextSearchProvider $provider, IndexOptions $options) {
391
		$wrapper = $this->platformService->getPlatform();
392
		$platform = $wrapper->getPlatform();
393
394
		$platform->initializeIndex();
395
		$provider->onInitializingIndex($platform);
396
397
		$platform->setRunner($this->runner);
398
399
		$users = $this->generateUserList($options);
400
		foreach ($users as $user) {
401
			if ($user === null) {
402
				continue;
403
			}
404
405
			try {
406
				$this->indexService->indexProviderContentFromUser(
407
					$platform, $provider, $user->getUID(), $options
408
				);
409
			} catch (Exception $e) {
410
				continue;
411
			}
412
		}
413
414
		$this->providerService->setProviderAsIndexed($provider, true);
415
	}
416
417
418
	/**
419
	 * @param InputInterface $input
420
	 *
421
	 * @return IndexOptions
422
	 */
423
	private function generateIndexOptions(InputInterface $input): IndexOptions {
424
		$jsonOptions = $input->getArgument('options');
425
426
		if (!is_string($jsonOptions)) {
427
			return new IndexOptions([]);
428
		}
429
430
		$options = json_decode($jsonOptions, true);
431
432
		if (!is_array($options)) {
433
			$options = [];
434
		}
435
436
		if ($input->getOption('no-readline')) {
437
			$options['_no-readline'] = true;
438
		}
439
440
		return new IndexOptions($options);
441
	}
442
443
444
	/**
445
	 * @param IndexOptions $options
446
	 * @param string $providerId
447
	 *
448
	 * @return bool
449
	 */
450
	private function isIncludedProvider(IndexOptions $options, string $providerId): bool {
451
		if ($options->getOption('provider', '') !== ''
452
			&& $options->getOption('provider') !== $providerId) {
453
			return false;
454
		}
455
456
		if ($options->getOptionArray('providers', []) !== []) {
457
			return (in_array($providerId, $options->getOptionArray('providers', [])));
458
		}
459
460
		return true;
461
	}
462
463
464
	/**
465
	 * @param IndexOptions $options
466
	 *
467
	 * @return array
468
	 */
469
	private function generateUserList(IndexOptions $options): array {
470
		if ($options->getOption('user', '') !== '') {
471
			return [$this->userManager->get($options->getOption('user'))];
472
		}
473
474
		if ($options->getOptionArray('users', []) !== []) {
475
			return array_map([$this->userManager, 'get'], $options->getOptionArray('users'));
476
		}
477
478
		return $this->userManager->search('');
479
	}
480
481
482
	/**
483
	 * @param IndexOptions $options
484
	 */
485
	private function generatePanels(IndexOptions $options) {
486
487
		$this->cliService->createPanel(
488
			self::PANEL_RUN,
489
			[
490
				self::PANEL_RUN_LINE_OPTIONS,
491
				self::PANEL_RUN_LINE_MEMORY
492
			]
493
		);
494
495
		$this->cliService->createPanel(
496
			self::PANEL_INDEX, [
497
								 self::PANEL_INDEX_LINE_HEADER,
498
								 self::PANEL_INDEX_LINE_ACTION,
499
								 self::PANEL_INDEX_LINE_ACCOUNT,
500
								 self::PANEL_INDEX_LINE_DOCUMENT,
501
								 self::PANEL_INDEX_LINE_INFO,
502
								 self::PANEL_INDEX_LINE_TITLE,
503
								 self::PANEL_INDEX_LINE_CONTENT,
504
								 self::PANEL_INDEX_LINE_PROGRESS,
505
								 self::PANEL_INDEX_LINE_FOOTER,
506
							 ]
507
		);
508
509
		$this->cliService->createPanel(
510
			self::PANEL_RESULT, [
511
								  self::PANEL_RESULT_LINE_HEADER,
512
								  self::PANEL_RESULT_LINE_RESULT,
513
								  self::PANEL_RESULT_LINE_INDEX,
514
								  self::PANEL_RESULT_LINE_STATUS,
515
								  self::PANEL_RESULT_LINE_MESSAGE1,
516
								  self::PANEL_RESULT_LINE_MESSAGE2,
517
								  self::PANEL_RESULT_LINE_MESSAGE3,
518
								  self::PANEL_RESULT_LINE_FOOTER,
519
							  ]
520
		);
521
522
		$this->cliService->createPanel(
523
			self::PANEL_ERRORS, [
524
								  self::PANEL_ERRORS_LINE_HEADER,
525
								  self::PANEL_ERRORS_LINE_ERRORS,
526
								  self::PANEL_ERRORS_LINE_ERROR_INDEX,
527
								  self::PANEL_ERRORS_LINE_ERROR_EXCEPTION,
528
								  self::PANEL_ERRORS_LINE_ERROR_MESSAGE1,
529
								  self::PANEL_ERRORS_LINE_ERROR_MESSAGE2,
530
								  self::PANEL_ERRORS_LINE_ERROR_MESSAGE3,
531
								  self::PANEL_ERRORS_LINE_FOOTER,
532
							  ]
533
		);
534
535
		$this->cliService->createPanel(
536
			self::PANEL_COMMANDS_PAUSED, [
537
										   self::PANEL_COMMANDS_PAUSED_LINE
538
									   ]
539
		);
540
541
		$this->cliService->createPanel(
542
			self::PANEL_COMMANDS_ROOT, [
543
										 self::PANEL_COMMANDS_ROOT_LINE
544
									 ]
545
		);
546
547
		$this->cliService->createPanel(
548
			self::PANEL_COMMANDS_NAVIGATION, [
549
											   self::PANEL_COMMANDS_RESULTS_LINE,
550
											   self::PANEL_COMMANDS_ERRORS_LINE
551
										   ]
552
		);
553
554
		$this->cliService->initDisplay();
555
		$this->cliService->displayPanel('run', self::PANEL_RUN);
556
		$this->cliService->displayPanel('indexPanel', self::PANEL_INDEX);
557
		$this->cliService->displayPanel('resultsPanel', self::PANEL_RESULT);
558
		$this->cliService->displayPanel('errorsPanel', self::PANEL_ERRORS);
559
560
		if ($options->getOptionBool(self::INDEX_OPTION_NO_READLINE, false) === false) {
561
			$this->cliService->displayPanel('navigation', self::PANEL_COMMANDS_NAVIGATION);
562 View Code Duplication
			if ($this->runner->isPaused()) {
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...
563
				$this->cliService->displayPanel('commands', self::PANEL_COMMANDS_PAUSED);
564
			} else {
565
				$this->cliService->displayPanel('commands', self::PANEL_COMMANDS_ROOT);
566
			}
567
		}
568
569
		// full list of info that can be edited
570
		$this->runner->setInfoArray(
571
			[
572
				'userId'       => '',
573
				'providerName' => '',
574
				'_memory'      => '',
575
				'documentId'   => '',
576
				'action'       => '',
577
				'info'         => '',
578
				'title'        => '',
579
				'_paused'      => '',
580
581
				'resultIndex'         => '',
582
				'resultCurrent'       => '',
583
				'resultTotal'         => '',
584
				'resultMessageA'      => '',
585
				'resultMessageB'      => '',
586
				'resultMessageC'      => '',
587
				'resultStatus'        => '',
588
				'resultStatusColored' => '',
589
				'content'             => '',
590
				'statusColored'       => '',
591
				'documentCurrent'     => '',
592
				'documentTotal'       => '',
593
				'progressStatus'      => '',
594
				'errorCurrent'        => '0',
595
				'errorTotal'          => '0',
596
				'errorMessageA'       => '',
597
				'errorMessageB'       => '',
598
				'errorMessageC'       => '',
599
				'errorException'      => '',
600
				'errorIndex'          => ''
601
			]
602
		);
603
	}
604
605
606
	/**
607
	 * @param int $pos
608
	 */
609 View Code Duplication
	private function displayError(int $pos = 0) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
610
		$total = sizeof($this->errors);
611
612
		if ($total === 0) {
613
			$this->runner->setInfoArray(
614
				[
615
					'errorCurrent' => 0,
616
					'errorTotal'   => 0,
617
				]
618
			);
619
620
			return;
621
		}
622
623
		try {
624
			$current = key($this->errors) + 1;
625
			$error = $this->getNavigationError($pos, ($current === 1), ($current === $total));
626
			$current = key($this->errors) + 1;
627
		} catch (OutOfBoundsException $e) {
628
			return;
629
		}
630
631
		/** @var ModelIndex $index */
632
		$index = $error['index'];
633
		$errorIndex = '';
634
		if ($index !== null) {
635
			$errorIndex = $index->getProviderId() . ':' . $index->getDocumentId();
636
		}
637
638
		$width = $this->terminal->getWidth() - 13;
639
		$message = $this->get('message', $error, '');
640
		$err1 = (string)substr($message, 0, $width);
641
		$err2 = (string)substr($message, $width, $width + 10);
642
		$err3 = (string)substr($message, $width + $width + 10, $width + 10);
643
644
		$this->runner->setInfoArray(
645
			[
646
				'errorCurrent'   => $current,
647
				'errorTotal'     => $total,
648
				'errorMessageA'  => trim($err1),
649
				'errorMessageB'  => trim($err2),
650
				'errorMessageC'  => trim($err3),
651
				'errorException' => $this->get('exception', $error, ''),
652
				'errorIndex'     => $errorIndex
653
			]
654
		);
655
	}
656
657
658
	/**
659
	 * @param int $pos
660
	 */
661 View Code Duplication
	private function displayResult(int $pos = 0) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
662
		$total = sizeof($this->results);
663
664
		if ($total === 0) {
665
			$this->runner->setInfoArray(
666
				[
667
					'resultCurrent' => 0,
668
					'resultTotal'   => 0,
669
				]
670
			);
671
672
			return;
673
		}
674
675
		try {
676
			$current = key($this->results) + 1;
677
			$result = $this->getNavigationResult($pos, ($current === 1), ($current === $total));
678
			$current = key($this->results) + 1;
679
		} catch (OutOfBoundsException $e) {
680
			return;
681
		}
682
683
		/** @var ModelIndex $index */
684
		$index = $result['index'];
685
		$resultIndex = '';
686
		if ($index !== null) {
687
			$resultIndex = $index->getProviderId() . ':' . $index->getDocumentId();
688
		}
689
690
691
		$width = $this->terminal->getWidth() - 13;
692
		$message = $this->get('message', $result, '');
693
		$msg1 = (string)substr($message, 0, $width);
694
		$msg2 = (string)substr($message, $width, $width + 10);
695
		$msg3 = (string)substr($message, $width + $width + 10, $width + 10);
696
697
		$status = $this->get('status', $result, '');
698
		$type = $this->getInt('type', $result, 0);
699
700
		$this->runner->setInfoArray(
701
			[
702
				'resultCurrent'  => $current,
703
				'resultTotal'    => $total,
704
				'resultMessageA' => trim($msg1),
705
				'resultMessageB' => trim($msg2),
706
				'resultMessageC' => trim($msg3),
707
				'resultStatus'   => $status,
708
				'resultIndex'    => $resultIndex
709
			]
710
		);
711
		$this->runner->setInfoColored('resultStatus', $type);
712
	}
713
714
715
	/**
716
	 * @param int $pos
717
	 * @param bool $isFirst
718
	 * @param bool $isLast
719
	 *
720
	 * @throw OutOfBoundsException
721
	 * @return array
722
	 */
723 View Code Duplication
	private function getNavigationError(int $pos, bool $isFirst, bool $isLast): array {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
724
725
		if ($pos === 0) {
726
			if ($this->navigateLastError === true) {
727
				return end($this->errors);
728
			} else {
729
				return current($this->errors);
730
			}
731
		}
732
733
		$this->navigateLastError = false;
734
		if ($pos === -99) {
735
			return reset($this->errors);
736
		}
737
738
		if ($pos === -1 && !$isFirst) {
739
			return prev($this->errors);
740
		}
741
742
		if ($pos === 1 && !$isLast) {
743
			return next($this->errors);
744
		}
745
746
		if ($pos === 99) {
747
			$this->navigateLastError = true;
748
749
			return end($this->errors);
750
		}
751
752
		throw new OutOfBoundsException();
753
	}
754
755
756
	/**
757
	 * @param int $pos
758
	 * @param bool $isFirst
759
	 * @param bool $isLast
760
	 *
761
	 * @throw OutOfBoundsException
762
	 * @return array
763
	 */
764 View Code Duplication
	private function getNavigationResult(int $pos, bool $isFirst, bool $isLast): array {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
765
766
		if ($pos === 0) {
767
			if ($this->navigateLastResult === true) {
768
				return end($this->results);
769
			} else {
770
				return current($this->results);
771
			}
772
		}
773
774
		$this->navigateLastResult = false;
775
		if ($pos === -99) {
776
			return reset($this->results);
777
		}
778
779
		if ($pos === -1 && !$isFirst) {
780
			return prev($this->results);
781
		}
782
783
		if ($pos === 1 && !$isLast) {
784
			return next($this->results);
785
		}
786
787
		if ($pos === 99) {
788
			$this->navigateLastResult = true;
789
790
			return end($this->results);
791
		}
792
793
		throw new OutOfBoundsException();
794
	}
795
796
797
	/**
798
	 *
799
	 */
800 View Code Duplication
	private function generateIndexErrors() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
801
		$indexes = $this->indexService->getErrorIndexes();
802
803
		foreach ($indexes as $index) {
804
			foreach ($index->getErrors() as $error) {
805
				$this->errors[] = [
806
					'index'     => $index,
807
					'message'   => $error['message'],
808
					'exception' => $error['exception'],
809
					'severity'  => $error['severity']
810
				];
811
			}
812
813
		}
814
	}
815
816
817
	/**
818
	 *
819
	 */
820 View Code Duplication
	private function deleteError() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
821
		$current = current($this->errors);
822
		if ($current === false) {
823
			return;
824
		}
825
826
		$this->runner->setInfoArray(
827
			[
828
				'errorMessageA'  => '',
829
				'errorMessageB'  => '',
830
				'errorMessageC'  => '',
831
				'errorException' => '',
832
				'errorIndex'     => ''
833
			]
834
		);
835
836
		$pos = key($this->errors);
837
838
		/** @var ModelIndex $index */
839
		$index = $current['index'];
840
		$this->indexService->resetErrorFromIndex($index);
841
842
		$errors = [];
843
		foreach ($this->errors as $error) {
844
			/** @var ModelIndex $errorIndex */
845
			$errorIndex = $error['index'];
846
			if ($index->getProviderId() === $errorIndex->getProviderId()
847
				&& $index->getDocumentId() === $errorIndex->getDocumentId()) {
848
				continue;
849
			}
850
851
			$errors[] = $error;
852
		}
853
854
		$this->errors = $errors;
855
		while (key($this->errors) < $pos) {
856
			if (next($this->errors) === false) {
857
				end($this->errors);
858
				break;
859
			}
860
		}
861
862
		$this->displayError();
863
	}
864
865
866
	/**
867
	 * @throws TickDoesNotExistException
868
	 */
869
	public function abort() {
870
		try {
871
			$this->abortIfInterrupted();
872
		} catch (InterruptedException $e) {
0 ignored issues
show
Bug introduced by
The class OC\Core\Command\InterruptedException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
873
			$this->runner->stop();
874
			exit();
875
		}
876
	}
877
878
879
}
880
881