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

Live::liveCycle()   A

Complexity

Conditions 4
Paths 7

Size

Total Lines 34

Duplication

Lines 15
Ratio 44.12 %

Importance

Changes 0
Metric Value
dl 15
loc 34
rs 9.376
c 0
b 0
f 0
cc 4
nc 7
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\Runner;
41
use OCA\FullTextSearch\Service\CliService;
42
use OCA\FullTextSearch\Service\ConfigService;
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\IUserManager;
49
use OutOfBoundsException;
50
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
51
use Symfony\Component\Console\Input\InputInterface;
52
use Symfony\Component\Console\Input\InputOption;
53
use Symfony\Component\Console\Output\OutputInterface;
54
use Symfony\Component\Console\Terminal;
55
use Throwable;
56
57
58
/**
59
 * Class Live
60
 *
61
 * @package OCA\FullTextSearch\Command
62
 */
63
class Live extends ACommandBase {
64
65
66
	use TArrayTools;
67
68
69
	const INDEX_OPTION_NO_READLINE = '_no-readline';
70
71
	const CYCLE_DELAY = 300000;
72
73
	const PANEL_RUN = 'run';
74
	const PANEL_RUN_LINE_MEMORY = 'Memory: %_memory%';
75
76
	const PANEL_INDEX = 'indexing';
77
	const PANEL_INDEX_LINE_HEADER = '┌─ Indexing %_paused% ────';
78
	const PANEL_INDEX_LINE_ACCOUNT = '│ Provider: <info>%providerName:-20s%</info> Account: <info>%userId%</info>';
79
	const PANEL_INDEX_LINE_ACTION = '│ Action: <info>%action%</info>';
80
	const PANEL_INDEX_LINE_DOCUMENT = '│ Document: <info>%documentId%</info>';
81
	const PANEL_INDEX_LINE_INFO = '│ Info: <info>%info%</info>';
82
	const PANEL_INDEX_LINE_TITLE = '│ Title: <info>%title%</info>';
83
	const PANEL_INDEX_LINE_CONTENT = '│ Content size: <info>%content%</info>';
84
	const PANEL_INDEX_LINE_FOOTER = '└──';
85
86
	const PANEL_RESULT = 'result';
87
	const PANEL_RESULT_LINE_HEADER = '┌─ Results ────';
88
	const PANEL_RESULT_LINE_RESULT = '│ Result: <info>%resultCurrent:6s%</info>/<info>%resultTotal%</info>';
89
	const PANEL_RESULT_LINE_INDEX = '│ Index: <info>%resultIndex%</info>';
90
	const PANEL_RESULT_LINE_STATUS = '│ Status: %resultStatusColored%';
91
	const PANEL_RESULT_LINE_MESSAGE1 = '│ Message: <info>%resultMessageA%</info>';
92
	const PANEL_RESULT_LINE_MESSAGE2 = '│ <info>%resultMessageB%</info>';
93
	const PANEL_RESULT_LINE_MESSAGE3 = '│ <info>%resultMessageC%</info>';
94
	const PANEL_RESULT_LINE_FOOTER = '└──';
95
96
	const PANEL_ERRORS = 'errors';
97
	const PANEL_ERRORS_LINE_HEADER = '┌─ Errors ────';
98
	const PANEL_ERRORS_LINE_ERRORS = '│ Error: <comment>%errorCurrent:6s%</comment>/<comment>%errorTotal%</comment>';
99
	const PANEL_ERRORS_LINE_ERROR_INDEX = '│ Index: <comment>%errorIndex%</comment>';
100
	const PANEL_ERRORS_LINE_ERROR_EXCEPTION = '│ Exception: <comment>%errorException%</comment>';
101
	const PANEL_ERRORS_LINE_ERROR_MESSAGE1 = '│ Message: <comment>%errorMessageA%</comment>';
102
	const PANEL_ERRORS_LINE_ERROR_MESSAGE2 = '│ <comment>%errorMessageB%</comment>';
103
	const PANEL_ERRORS_LINE_ERROR_MESSAGE3 = '│ <comment>%errorMessageC%</comment>';
104
	const PANEL_ERRORS_LINE_FOOTER = '└──';
105
106
	const PANEL_COMMANDS_ROOT = 'root';
107
	const PANEL_COMMANDS_ROOT_LINE = '## <char>q</char>:quit ## <char>p</char>:pause ';
108
	const PANEL_COMMANDS_PAUSED = 'paused';
109
	const PANEL_COMMANDS_PAUSED_LINE = '## <char>q</char>:quit ## <char>u</char>:unpause ## <char>n</char>:next step';
110
	const PANEL_COMMANDS_DONE = 'done';
111
	const PANEL_COMMANDS_DONE_LINE = '## <char>q</char>:quit';
112
	const PANEL_COMMANDS_NAVIGATION = 'navigation';
113
	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';
114
	const PANEL_COMMANDS_RESULTS_LINE = '## <char>x</char>:first result ## <char>c</char>/<char>v</char>:prec/next result ## <char>b</char>:last result';
115
116
117
	/** @var IUserManager */
118
	private $userManager;
119
120
	/** @var ConfigService */
121
	private $configService;
122
123
	/** @var CliService */
124
	private $cliService;
125
126
	/** @var RunningService */
127
	private $runningService;
128
129
	/** @var IndexService */
130
	private $indexService;
131
132
	/** @var PlatformService */
133
	private $platformService;
134
135
	/** @var ProviderService */
136
	private $providerService;
137
138
	/** @var MiscService */
139
	private $miscService;
140
141
142
	/** @var Runner */
143
	private $runner;
144
145
	/** @var Terminal */
146
	private $terminal;
147
148
	/** @var array */
149
	private $errors = [];
150
151
	/** @var bool */
152
	private $navigateLastError = true;
153
154
	/** @var array */
155
	private $results = [];
156
157
	/** @var bool */
158
	private $navigateLastResult = true;
159
160
	/**
161
	 * Live constructor.
162
	 *
163
	 * @param IUserManager $userManager
164
	 * @param RunningService $runningService
165
	 * @param ConfigService $configService
166
	 * @param CliService $cliService
167
	 * @param IndexService $indexService
168
	 * @param PlatformService $platformService
169
	 * @param ProviderService $providerService
170
	 * @param MiscService $miscService
171
	 */
172
	public function __construct(
173
		IUserManager $userManager, RunningService $runningService, ConfigService $configService,
174
		CliService $cliService, IndexService $indexService, PlatformService $platformService,
175
		ProviderService $providerService, MiscService $miscService
176
	) {
177
		parent::__construct();
178
		$this->userManager = $userManager;
179
180
		$this->runner = new Runner($runningService, 'commandLive');
181
		$this->configService = $configService;
182
		$this->cliService = $cliService;
183
		$this->runningService = $runningService;
184
		$this->indexService = $indexService;
185
		$this->platformService = $platformService;
186
		$this->providerService = $providerService;
187
		$this->miscService = $miscService;
188
	}
189
190
191
	/**
192
	 *
193
	 */
194
	protected function configure() {
195
		parent::configure();
196
		$this->setName('fulltextsearch:live')
197
			 ->setDescription('Index files')
198
			 ->addOption(
199
				 'no-readline', 'r', InputOption::VALUE_NONE,
200
				 'disable readline - non interactive mode'
201
			 );
202
	}
203
204
205
	/**
206
	 * @param InputInterface $input
207
	 * @param OutputInterface $output
208
	 *
209
	 * @return int|null|void
210
	 * @throws Exception
211
	 */
212
	protected function execute(InputInterface $input, OutputInterface $output) {
213
214
		if ($this->configService->getCloudVersion() < 14) {
215
			throw new Exception('This feature is only available on Nextcloud 14 or newer');
216
		}
217
218
		if (!$input->getOption('no-readline')) {
219
			try {
220
				/** do not get stuck while waiting interactive input */
221
				readline_callback_handler_install(
222
					'', function() {
223
				}
224
				);
225
			} 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...
226
				throw new Exception('Please install php-readline, or use --no-readline');
227
			}
228
		}
229
		stream_set_blocking(STDIN, false);
230
231
		$this->terminal = new Terminal();
232
233
		$outputStyle = new OutputFormatterStyle('white', 'black', ['bold']);
234
		$output->getFormatter()
235
			   ->setStyle('char', $outputStyle);
236
237
		$this->runner = new Runner($this->runningService, 'commandIndex', ['nextStep' => 'n']);
238
		$this->runner->onKeyPress([$this, 'onKeyPressed']);
239
		$this->runner->onNewIndexError([$this, 'onNewIndexError']);
240
		$this->runner->onNewIndexResult([$this, 'onNewIndexResult']);
241
242
243
		$this->indexService->setRunner($this->runner);
244
		$this->cliService->setRunner($this->runner);
245
246
		$this->generatePanels(!$input->getOption('no-readline'));
247
248
249
		try {
250
			$this->runner->sourceIsCommandLine($this, $output);
251
			$this->runner->start();
252
253
			$this->cliService->runDisplay($output);
254
			$this->generateIndexErrors();
255
			$this->displayError();
256
			$this->displayResult();
257
258
			$this->liveCycle();
259
260
		} catch (Exception $e) {
261
			$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...
262
			throw $e;
263
		}
264
265
		$this->runner->stop();
266
	}
267
268
269
	/**
270
	 * @throws Exception
271
	 * @throws TickDoesNotExistException
272
	 */
273
	private function liveCycle() {
274
275
		$wrapper = $this->platformService->getPlatform();
276
		$platform = $wrapper->getPlatform();
277
		$platform->setRunner($this->runner);
278
279
		while (true) {
280
281
			$indexes = $this->indexService->getQueuedIndexes();
282
283 View Code Duplication
			foreach ($indexes as $index) {
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...
284
				$this->runner->updateAction('indexing');
285
286
				try {
287
					$providerWrapper = $this->providerService->getProvider($index->getProviderId());
288
					$provider = $providerWrapper->getProvider();
289
290
					$provider->setRunner($this->runner);
291
					$this->indexService->updateDocument($platform, $provider, $index);
292
				} catch (Exception $e) {
293
					$this->runner->exception($e->getMessage(), false);
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...
294
					// TODO - upgrade error number - after too many errors, delete index
295
					// TODO - do not count error if elasticsearch is down.
296
				}
297
			}
298
299
			$this->runner->updateAction('waiting', true);
300
301
			usleep(self::CYCLE_DELAY);
302
		}
303
304
		$this->runner->stop();
305
306
	}
307
308
309
	/**
310
	 * @param string $key
311
	 */
312 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...
313
		$key = strtolower($key);
314
		if ($key === 'q') {
315
			try {
316
				$this->runner->stop();
317
			} catch (TickDoesNotExistException $e) {
318
				/** we do nohtin' */
319
			}
320
			exit();
321
		}
322
323
		$current = $this->cliService->currentPanel('commands');
324
		if ($current === self::PANEL_COMMANDS_ROOT && $key === 'p') {
325
			$this->cliService->switchPanel('commands', self::PANEL_COMMANDS_PAUSED);
326
			$this->runner->pause(true);
327
		}
328
		if ($current === self::PANEL_COMMANDS_PAUSED && $key === 'u') {
329
			$this->cliService->switchPanel('commands', self::PANEL_COMMANDS_ROOT);
330
			$this->runner->pause(false);
331
		}
332
333
		if ($key === 'x') {
334
			$this->displayResult(-99);
335
		}
336
		if ($key === 'c') {
337
			$this->displayResult(-1);
338
		}
339
		if ($key === 'v') {
340
			$this->displayResult(1);
341
		}
342
		if ($key === 'b') {
343
			$this->displayResult(99);
344
		}
345
346
		if ($key === 'f') {
347
			$this->displayError(-99);
348
		}
349
		if ($key === 'h') {
350
			$this->displayError(-1);
351
		}
352
		if ($key === 'j') {
353
			$this->displayError(1);
354
		}
355
		if ($key === 'l') {
356
			$this->displayError(99);
357
		}
358
		if ($key === 'd') {
359
			$this->deleteError();
360
		}
361
	}
362
363
364
	/**
365
	 * @param array $error
366
	 */
367
	public function onNewIndexError(array $error) {
368
		$this->errors[] = $error;
369
		$this->displayError();
370
	}
371
372
	/**
373
	 * @param array $result
374
	 */
375
	public function onNewIndexResult(array $result) {
376
		$this->results[] = $result;
377
		$this->displayResult();
378
	}
379
380
381
	/**
382
	 * @param bool $commands
383
	 */
384
	private function generatePanels(bool $commands) {
385
386
		$this->cliService->createPanel(
387
			self::PANEL_RUN,
388
			[
389
				self::PANEL_RUN_LINE_MEMORY
390
			]
391
		);
392
393
		$this->cliService->createPanel(
394
			self::PANEL_INDEX, [
395
								 self::PANEL_INDEX_LINE_HEADER,
396
								 self::PANEL_INDEX_LINE_ACTION,
397
								 self::PANEL_INDEX_LINE_ACCOUNT,
398
								 self::PANEL_INDEX_LINE_DOCUMENT,
399
								 self::PANEL_INDEX_LINE_INFO,
400
								 self::PANEL_INDEX_LINE_TITLE,
401
								 self::PANEL_INDEX_LINE_CONTENT,
402
								 self::PANEL_INDEX_LINE_FOOTER,
403
							 ]
404
		);
405
406
		$this->cliService->createPanel(
407
			self::PANEL_RESULT, [
408
								  self::PANEL_RESULT_LINE_HEADER,
409
								  self::PANEL_RESULT_LINE_RESULT,
410
								  self::PANEL_RESULT_LINE_INDEX,
411
								  self::PANEL_RESULT_LINE_STATUS,
412
								  self::PANEL_RESULT_LINE_MESSAGE1,
413
								  self::PANEL_RESULT_LINE_MESSAGE2,
414
								  self::PANEL_RESULT_LINE_MESSAGE3,
415
								  self::PANEL_RESULT_LINE_FOOTER,
416
							  ]
417
		);
418
419
		$this->cliService->createPanel(
420
			self::PANEL_ERRORS, [
421
								  self::PANEL_ERRORS_LINE_HEADER,
422
								  self::PANEL_ERRORS_LINE_ERRORS,
423
								  self::PANEL_ERRORS_LINE_ERROR_INDEX,
424
								  self::PANEL_ERRORS_LINE_ERROR_EXCEPTION,
425
								  self::PANEL_ERRORS_LINE_ERROR_MESSAGE1,
426
								  self::PANEL_ERRORS_LINE_ERROR_MESSAGE2,
427
								  self::PANEL_ERRORS_LINE_ERROR_MESSAGE3,
428
								  self::PANEL_ERRORS_LINE_FOOTER,
429
							  ]
430
		);
431
432
		$this->cliService->createPanel(
433
			self::PANEL_COMMANDS_ROOT, [
434
										 self::PANEL_COMMANDS_ROOT_LINE
435
									 ]
436
		);
437
438
		$this->cliService->createPanel(
439
			self::PANEL_COMMANDS_PAUSED, [
440
										   self::PANEL_COMMANDS_PAUSED_LINE
441
									   ]
442
		);
443
444
		$this->cliService->createPanel(
445
			self::PANEL_COMMANDS_NAVIGATION, [
446
											   self::PANEL_COMMANDS_RESULTS_LINE,
447
											   self::PANEL_COMMANDS_ERRORS_LINE
448
										   ]
449
		);
450
451
		$this->cliService->initDisplay();
452
		$this->cliService->displayPanel('run', self::PANEL_RUN);
453
		$this->cliService->displayPanel('indexPanel', self::PANEL_INDEX);
454
		$this->cliService->displayPanel('resultsPanel', self::PANEL_RESULT);
455
		$this->cliService->displayPanel('errorsPanel', self::PANEL_ERRORS);
456
457 View Code Duplication
		if ($commands) {
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...
458
			$this->cliService->displayPanel('navigation', self::PANEL_COMMANDS_NAVIGATION);
459
			if ($this->runner->isPaused()) {
460
				$this->cliService->displayPanel('commands', self::PANEL_COMMANDS_PAUSED);
461
			} else {
462
				$this->cliService->displayPanel('commands', self::PANEL_COMMANDS_ROOT);
463
			}
464
		}
465
466
		$this->runner->setInfoArray(
467
			[
468
				'userId'              => '',
469
				'providerName'        => '',
470
				'_memory'             => '',
471
				'documentId'          => '',
472
				'action'              => '',
473
				'info'                => '',
474
				'title'               => '',
475
				'_paused'             => '',
476
				'resultIndex'         => '',
477
				'resultCurrent'       => '',
478
				'resultTotal'         => '',
479
				'resultMessageA'      => '',
480
				'resultMessageB'      => '',
481
				'resultMessageC'      => '',
482
				'resultStatus'        => '',
483
				'resultStatusColored' => '',
484
				'content'             => '',
485
				'statusColored'       => '',
486
				'progressStatus'      => '',
487
				'errorCurrent'        => '0',
488
				'errorTotal'          => '0',
489
				'errorMessageA'       => '',
490
				'errorMessageB'       => '',
491
				'errorMessageC'       => '',
492
				'errorException'      => '',
493
				'errorIndex'          => ''
494
			]
495
		);
496
	}
497
498
499
	/**
500
	 *
501
	 */
502 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...
503
		$indexes = $this->indexService->getErrorIndexes();
504
505
		foreach ($indexes as $index) {
506
			foreach ($index->getErrors() as $error) {
507
				$this->errors[] = [
508
					'index'     => $index,
509
					'message'   => $error['message'],
510
					'exception' => $error['exception'],
511
					'severity'  => $error['severity']
512
				];
513
			}
514
515
		}
516
517
	}
518
519
520
	/**
521
	 * @param int $pos
522
	 */
523 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...
524
		$total = sizeof($this->results);
525
526
		if ($total === 0) {
527
			$this->runner->setInfoArray(
528
				[
529
					'resultCurrent' => 0,
530
					'resultTotal'   => 0,
531
				]
532
			);
533
534
			return;
535
		}
536
537
		try {
538
			$current = key($this->results) + 1;
539
			$result = $this->getNavigationResult($pos, ($current === 1), ($current === $total));
540
			$current = key($this->results) + 1;
541
		} catch (OutOfBoundsException $e) {
542
			return;
543
		}
544
545
		/** @var ModelIndex $index */
546
		$index = $result['index'];
547
		$resultIndex = '';
548
		if ($index !== null) {
549
			$resultIndex = $index->getProviderId() . ':' . $index->getDocumentId();
550
		}
551
552
553
		$width = $this->terminal->getWidth() - 13;
554
		$message = $this->get('message', $result, '');
555
		$msg1 = (string)substr($message, 0, $width);
556
		$msg2 = (string)substr($message, $width, $width + 10);
557
		$msg3 = (string)substr($message, $width + $width + 10, $width + 10);
558
559
560
		$status = $this->get('status', $result, '');
561
		$type = $this->getInt('type', $result, 0);
562
563
564
		$this->runner->setInfoArray(
565
			[
566
				'resultCurrent'  => $current,
567
				'resultTotal'    => $total,
568
				'resultMessageA' => trim($msg1),
569
				'resultMessageB' => trim($msg2),
570
				'resultMessageC' => trim($msg3),
571
				'resultStatus'   => $status,
572
				'resultIndex'    => $resultIndex
573
			]
574
		);
575
		$this->runner->setInfoColored('resultStatus', $type);
576
	}
577
578
	/**
579
	 * @param int $pos
580
	 */
581 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...
582
		$total = sizeof($this->errors);
583
584
		if ($total === 0) {
585
			$this->runner->setInfoArray(
586
				[
587
					'errorCurrent' => 0,
588
					'errorTotal'   => 0,
589
				]
590
			);
591
592
			return;
593
		}
594
595
		try {
596
			$current = key($this->errors) + 1;
597
			$error = $this->getNavigationError($pos, ($current === 1), ($current === $total));
598
			$current = key($this->errors) + 1;
599
		} catch (OutOfBoundsException $e) {
600
			return;
601
		}
602
603
		/** @var ModelIndex $index */
604
		$index = $error['index'];
605
		$errorIndex = '';
606
		if ($index !== null) {
607
			$errorIndex = $index->getProviderId() . ':' . $index->getDocumentId();
608
		}
609
610
		$width = $this->terminal->getWidth() - 13;
611
		$message = $this->get('message', $error, '');
612
		$err1 = (string)substr($message, 0, $width);
613
		$err2 = (string)substr($message, $width, $width + 10);
614
		$err3 = (string)substr($message, $width + $width + 10, $width + 10);
615
616
		$this->runner->setInfoArray(
617
			[
618
				'errorCurrent'   => $current,
619
				'errorTotal'     => $total,
620
				'errorMessageA'  => trim($err1),
621
				'errorMessageB'  => trim($err2),
622
				'errorMessageC'  => trim($err3),
623
				'errorException' => $this->get('exception', $error, ''),
624
				'errorIndex'     => $errorIndex
625
			]
626
		);
627
	}
628
629
630
	/**
631
	 * @param int $pos
632
	 * @param bool $isFirst
633
	 * @param bool $isLast
634
	 *
635
	 * @return array
636
	 * @throws OutOfBoundsException
637
	 */
638 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...
639
640
		if ($pos === 0) {
641
			if ($this->navigateLastResult === true) {
642
				return end($this->results);
643
			} else {
644
				return current($this->results);
645
			}
646
		}
647
648
		$this->navigateLastResult = false;
649
		if ($pos === -99) {
650
			return reset($this->results);
651
		}
652
653
		if ($pos === -1 && !$isFirst) {
654
			return prev($this->results);
655
		}
656
657
		if ($pos === 1 && !$isLast) {
658
			return next($this->results);
659
		}
660
661
		if ($pos === 99) {
662
			$this->navigateLastResult = true;
663
664
			return end($this->results);
665
		}
666
667
		throw new OutOfBoundsException();
668
	}
669
670
671
	/**
672
	 * @param int $pos
673
	 * @param bool $isFirst
674
	 * @param bool $isLast
675
	 *
676
	 * @return array
677
	 */
678 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...
679
680
		if ($pos === 0) {
681
			if ($this->navigateLastError === true) {
682
				return end($this->errors);
683
			} else {
684
				return current($this->errors);
685
			}
686
		}
687
688
		$this->navigateLastError = false;
689
		if ($pos === -99) {
690
			return reset($this->errors);
691
		}
692
693
		if ($pos === -1 && !$isFirst) {
694
			return prev($this->errors);
695
		}
696
697
		if ($pos === 1 && !$isLast) {
698
			return next($this->errors);
699
		}
700
701
		if ($pos === 99) {
702
			$this->navigateLastError = true;
703
704
			return end($this->errors);
705
		}
706
707
		throw new OutOfBoundsException();
708
	}
709
710
711
	/**
712
	 *
713
	 */
714 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...
715
		$current = current($this->errors);
716
		if ($current === false) {
717
			return;
718
		}
719
720
		$this->runner->setInfoArray(
721
			[
722
				'errorMessageA'  => '',
723
				'errorMessageB'  => '',
724
				'errorMessageC'  => '',
725
				'errorException' => '',
726
				'errorIndex'     => ''
727
			]
728
		);
729
730
		$pos = key($this->errors);
731
732
		/** @var ModelIndex $index */
733
		$index = $current['index'];
734
		$this->indexService->resetErrorFromIndex($index);
735
736
		$errors = [];
737
		foreach ($this->errors as $error) {
738
			/** @var ModelIndex $errorIndex */
739
			$errorIndex = $error['index'];
740
			if ($index->getProviderId() === $errorIndex->getProviderId()
741
				&& $index->getDocumentId() === $errorIndex->getDocumentId()) {
742
				continue;
743
			}
744
745
			$errors[] = $error;
746
		}
747
748
		$this->errors = $errors;
749
		while (key($this->errors) < $pos) {
750
			if (next($this->errors) === false) {
751
				end($this->errors);
752
				break;
753
			}
754
		}
755
756
		$this->displayError();
757
	}
758
759
760
	/**
761
	 * @throws TickDoesNotExistException
762
	 */
763
	public function abort() {
764
		try {
765
			$this->abortIfInterrupted();
766
		} 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...
767
			$this->runner->stop();
768
			exit();
769
		}
770
	}
771
772
773
}
774
775