Passed
Push — master ( 15924b...b89e6f )
by Roeland
17:24 queued 11s
created
apps/files/lib/Command/Scan.php 1 patch
Indentation   +273 added lines, -273 removed lines patch added patch discarded remove patch
@@ -53,277 +53,277 @@
 block discarded – undo
53 53
 
54 54
 class Scan extends Base {
55 55
 
56
-	/** @var IUserManager $userManager */
57
-	private $userManager;
58
-	/** @var float */
59
-	protected $execTime = 0;
60
-	/** @var int */
61
-	protected $foldersCounter = 0;
62
-	/** @var int */
63
-	protected $filesCounter = 0;
64
-
65
-	public function __construct(IUserManager $userManager) {
66
-		$this->userManager = $userManager;
67
-		parent::__construct();
68
-	}
69
-
70
-	protected function configure() {
71
-		parent::configure();
72
-
73
-		$this
74
-			->setName('files:scan')
75
-			->setDescription('rescan filesystem')
76
-			->addArgument(
77
-				'user_id',
78
-				InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
79
-				'will rescan all files of the given user(s)'
80
-			)
81
-			->addOption(
82
-				'path',
83
-				'p',
84
-				InputArgument::OPTIONAL,
85
-				'limit rescan to this path, eg. --path="/alice/files/Music", the user_id is determined by the path and the user_id parameter and --all are ignored'
86
-			)
87
-			->addOption(
88
-				'all',
89
-				null,
90
-				InputOption::VALUE_NONE,
91
-				'will rescan all files of all known users'
92
-			)->addOption(
93
-				'unscanned',
94
-				null,
95
-				InputOption::VALUE_NONE,
96
-				'only scan files which are marked as not fully scanned'
97
-			)->addOption(
98
-				'shallow',
99
-				null,
100
-				InputOption::VALUE_NONE,
101
-				'do not scan folders recursively'
102
-			)->addOption(
103
-				'home-only',
104
-				null,
105
-				InputOption::VALUE_NONE,
106
-				'only scan the home storage, ignoring any mounted external storage or share'
107
-			);
108
-	}
109
-
110
-	public function checkScanWarning($fullPath, OutputInterface $output) {
111
-		$normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
112
-		$path = basename($fullPath);
113
-
114
-		if ($normalizedPath !== $path) {
115
-			$output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
116
-		}
117
-	}
118
-
119
-	protected function scanFiles($user, $path, OutputInterface $output, $backgroundScan = false, $recursive = true, $homeOnly = false) {
120
-		$connection = $this->reconnectToDatabase($output);
121
-		$scanner = new \OC\Files\Utils\Scanner(
122
-			$user,
123
-			new ConnectionAdapter($connection),
124
-			\OC::$server->query(IEventDispatcher::class),
125
-			\OC::$server->getLogger()
126
-		);
127
-
128
-		# check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
129
-
130
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
131
-			$output->writeln("\tFile\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
132
-			++$this->filesCounter;
133
-			$this->abortIfInterrupted();
134
-		});
135
-
136
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
137
-			$output->writeln("\tFolder\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
138
-			++$this->foldersCounter;
139
-			$this->abortIfInterrupted();
140
-		});
141
-
142
-		$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
143
-			$output->writeln('Error while scanning, storage not available (' . $e->getMessage() . ')', OutputInterface::VERBOSITY_VERBOSE);
144
-		});
145
-
146
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
147
-			$this->checkScanWarning($path, $output);
148
-		});
149
-
150
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
151
-			$this->checkScanWarning($path, $output);
152
-		});
153
-
154
-		try {
155
-			if ($backgroundScan) {
156
-				$scanner->backgroundScan($path);
157
-			} else {
158
-				$scanner->scan($path, $recursive, $homeOnly ? [$this, 'filterHomeMount'] : null);
159
-			}
160
-		} catch (ForbiddenException $e) {
161
-			$output->writeln("<error>Home storage for user $user not writable</error>");
162
-			$output->writeln('Make sure you\'re running the scan command only as the user the web server runs as');
163
-		} catch (InterruptedException $e) {
164
-			# exit the function if ctrl-c has been pressed
165
-			$output->writeln('Interrupted by user');
166
-		} catch (NotFoundException $e) {
167
-			$output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
168
-		} catch (\Exception $e) {
169
-			$output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
170
-			$output->writeln('<error>' . $e->getTraceAsString() . '</error>');
171
-		}
172
-	}
173
-
174
-	public function filterHomeMount(IMountPoint $mountPoint) {
175
-		// any mountpoint inside '/$user/files/'
176
-		return substr_count($mountPoint->getMountPoint(), '/') <= 3;
177
-	}
178
-
179
-	protected function execute(InputInterface $input, OutputInterface $output): int {
180
-		$inputPath = $input->getOption('path');
181
-		if ($inputPath) {
182
-			$inputPath = '/' . trim($inputPath, '/');
183
-			list(, $user,) = explode('/', $inputPath, 3);
184
-			$users = [$user];
185
-		} elseif ($input->getOption('all')) {
186
-			$users = $this->userManager->search('');
187
-		} else {
188
-			$users = $input->getArgument('user_id');
189
-		}
190
-
191
-		# restrict the verbosity level to VERBOSITY_VERBOSE
192
-		if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
193
-			$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
194
-		}
195
-
196
-		# check quantity of users to be process and show it on the command line
197
-		$users_total = count($users);
198
-		if ($users_total === 0) {
199
-			$output->writeln('<error>Please specify the user id to scan, --all to scan for all users or --path=...</error>');
200
-			return 1;
201
-		}
202
-
203
-		$this->initTools();
204
-
205
-		$user_count = 0;
206
-		foreach ($users as $user) {
207
-			if (is_object($user)) {
208
-				$user = $user->getUID();
209
-			}
210
-			$path = $inputPath ? $inputPath : '/' . $user;
211
-			++$user_count;
212
-			if ($this->userManager->userExists($user)) {
213
-				$output->writeln("Starting scan for user $user_count out of $users_total ($user)");
214
-				$this->scanFiles($user, $path, $output, $input->getOption('unscanned'), !$input->getOption('shallow'), $input->getOption('home-only'));
215
-				$output->writeln('', OutputInterface::VERBOSITY_VERBOSE);
216
-			} else {
217
-				$output->writeln("<error>Unknown user $user_count $user</error>");
218
-				$output->writeln('', OutputInterface::VERBOSITY_VERBOSE);
219
-			}
220
-
221
-			try {
222
-				$this->abortIfInterrupted();
223
-			} catch (InterruptedException $e) {
224
-				break;
225
-			}
226
-		}
227
-
228
-		$this->presentStats($output);
229
-		return 0;
230
-	}
231
-
232
-	/**
233
-	 * Initialises some useful tools for the Command
234
-	 */
235
-	protected function initTools() {
236
-		// Start the timer
237
-		$this->execTime = -microtime(true);
238
-		// Convert PHP errors to exceptions
239
-		set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
240
-	}
241
-
242
-	/**
243
-	 * Processes PHP errors as exceptions in order to be able to keep track of problems
244
-	 *
245
-	 * @see https://www.php.net/manual/en/function.set-error-handler.php
246
-	 *
247
-	 * @param int $severity the level of the error raised
248
-	 * @param string $message
249
-	 * @param string $file the filename that the error was raised in
250
-	 * @param int $line the line number the error was raised
251
-	 *
252
-	 * @throws \ErrorException
253
-	 */
254
-	public function exceptionErrorHandler($severity, $message, $file, $line) {
255
-		if (!(error_reporting() & $severity)) {
256
-			// This error code is not included in error_reporting
257
-			return;
258
-		}
259
-		throw new \ErrorException($message, 0, $severity, $file, $line);
260
-	}
261
-
262
-	/**
263
-	 * @param OutputInterface $output
264
-	 */
265
-	protected function presentStats(OutputInterface $output) {
266
-		// Stop the timer
267
-		$this->execTime += microtime(true);
268
-
269
-		$headers = [
270
-			'Folders', 'Files', 'Elapsed time'
271
-		];
272
-
273
-		$this->showSummary($headers, null, $output);
274
-	}
275
-
276
-	/**
277
-	 * Shows a summary of operations
278
-	 *
279
-	 * @param string[] $headers
280
-	 * @param string[] $rows
281
-	 * @param OutputInterface $output
282
-	 */
283
-	protected function showSummary($headers, $rows, OutputInterface $output) {
284
-		$niceDate = $this->formatExecTime();
285
-		if (!$rows) {
286
-			$rows = [
287
-				$this->foldersCounter,
288
-				$this->filesCounter,
289
-				$niceDate,
290
-			];
291
-		}
292
-		$table = new Table($output);
293
-		$table
294
-			->setHeaders($headers)
295
-			->setRows([$rows]);
296
-		$table->render();
297
-	}
298
-
299
-
300
-	/**
301
-	 * Formats microtime into a human readable format
302
-	 *
303
-	 * @return string
304
-	 */
305
-	protected function formatExecTime() {
306
-		$secs = round($this->execTime);
307
-		# convert seconds into HH:MM:SS form
308
-		return sprintf('%02d:%02d:%02d', ($secs / 3600), ($secs / 60 % 60), $secs % 60);
309
-	}
310
-
311
-	protected function reconnectToDatabase(OutputInterface $output): Connection {
312
-		/** @var Connection $connection */
313
-		$connection = \OC::$server->get(Connection::class);
314
-		try {
315
-			$connection->close();
316
-		} catch (\Exception $ex) {
317
-			$output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
318
-		}
319
-		while (!$connection->isConnected()) {
320
-			try {
321
-				$connection->connect();
322
-			} catch (\Exception $ex) {
323
-				$output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
324
-				sleep(60);
325
-			}
326
-		}
327
-		return $connection;
328
-	}
56
+    /** @var IUserManager $userManager */
57
+    private $userManager;
58
+    /** @var float */
59
+    protected $execTime = 0;
60
+    /** @var int */
61
+    protected $foldersCounter = 0;
62
+    /** @var int */
63
+    protected $filesCounter = 0;
64
+
65
+    public function __construct(IUserManager $userManager) {
66
+        $this->userManager = $userManager;
67
+        parent::__construct();
68
+    }
69
+
70
+    protected function configure() {
71
+        parent::configure();
72
+
73
+        $this
74
+            ->setName('files:scan')
75
+            ->setDescription('rescan filesystem')
76
+            ->addArgument(
77
+                'user_id',
78
+                InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
79
+                'will rescan all files of the given user(s)'
80
+            )
81
+            ->addOption(
82
+                'path',
83
+                'p',
84
+                InputArgument::OPTIONAL,
85
+                'limit rescan to this path, eg. --path="/alice/files/Music", the user_id is determined by the path and the user_id parameter and --all are ignored'
86
+            )
87
+            ->addOption(
88
+                'all',
89
+                null,
90
+                InputOption::VALUE_NONE,
91
+                'will rescan all files of all known users'
92
+            )->addOption(
93
+                'unscanned',
94
+                null,
95
+                InputOption::VALUE_NONE,
96
+                'only scan files which are marked as not fully scanned'
97
+            )->addOption(
98
+                'shallow',
99
+                null,
100
+                InputOption::VALUE_NONE,
101
+                'do not scan folders recursively'
102
+            )->addOption(
103
+                'home-only',
104
+                null,
105
+                InputOption::VALUE_NONE,
106
+                'only scan the home storage, ignoring any mounted external storage or share'
107
+            );
108
+    }
109
+
110
+    public function checkScanWarning($fullPath, OutputInterface $output) {
111
+        $normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
112
+        $path = basename($fullPath);
113
+
114
+        if ($normalizedPath !== $path) {
115
+            $output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
116
+        }
117
+    }
118
+
119
+    protected function scanFiles($user, $path, OutputInterface $output, $backgroundScan = false, $recursive = true, $homeOnly = false) {
120
+        $connection = $this->reconnectToDatabase($output);
121
+        $scanner = new \OC\Files\Utils\Scanner(
122
+            $user,
123
+            new ConnectionAdapter($connection),
124
+            \OC::$server->query(IEventDispatcher::class),
125
+            \OC::$server->getLogger()
126
+        );
127
+
128
+        # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
129
+
130
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
131
+            $output->writeln("\tFile\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
132
+            ++$this->filesCounter;
133
+            $this->abortIfInterrupted();
134
+        });
135
+
136
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
137
+            $output->writeln("\tFolder\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
138
+            ++$this->foldersCounter;
139
+            $this->abortIfInterrupted();
140
+        });
141
+
142
+        $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
143
+            $output->writeln('Error while scanning, storage not available (' . $e->getMessage() . ')', OutputInterface::VERBOSITY_VERBOSE);
144
+        });
145
+
146
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
147
+            $this->checkScanWarning($path, $output);
148
+        });
149
+
150
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
151
+            $this->checkScanWarning($path, $output);
152
+        });
153
+
154
+        try {
155
+            if ($backgroundScan) {
156
+                $scanner->backgroundScan($path);
157
+            } else {
158
+                $scanner->scan($path, $recursive, $homeOnly ? [$this, 'filterHomeMount'] : null);
159
+            }
160
+        } catch (ForbiddenException $e) {
161
+            $output->writeln("<error>Home storage for user $user not writable</error>");
162
+            $output->writeln('Make sure you\'re running the scan command only as the user the web server runs as');
163
+        } catch (InterruptedException $e) {
164
+            # exit the function if ctrl-c has been pressed
165
+            $output->writeln('Interrupted by user');
166
+        } catch (NotFoundException $e) {
167
+            $output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
168
+        } catch (\Exception $e) {
169
+            $output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
170
+            $output->writeln('<error>' . $e->getTraceAsString() . '</error>');
171
+        }
172
+    }
173
+
174
+    public function filterHomeMount(IMountPoint $mountPoint) {
175
+        // any mountpoint inside '/$user/files/'
176
+        return substr_count($mountPoint->getMountPoint(), '/') <= 3;
177
+    }
178
+
179
+    protected function execute(InputInterface $input, OutputInterface $output): int {
180
+        $inputPath = $input->getOption('path');
181
+        if ($inputPath) {
182
+            $inputPath = '/' . trim($inputPath, '/');
183
+            list(, $user,) = explode('/', $inputPath, 3);
184
+            $users = [$user];
185
+        } elseif ($input->getOption('all')) {
186
+            $users = $this->userManager->search('');
187
+        } else {
188
+            $users = $input->getArgument('user_id');
189
+        }
190
+
191
+        # restrict the verbosity level to VERBOSITY_VERBOSE
192
+        if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
193
+            $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
194
+        }
195
+
196
+        # check quantity of users to be process and show it on the command line
197
+        $users_total = count($users);
198
+        if ($users_total === 0) {
199
+            $output->writeln('<error>Please specify the user id to scan, --all to scan for all users or --path=...</error>');
200
+            return 1;
201
+        }
202
+
203
+        $this->initTools();
204
+
205
+        $user_count = 0;
206
+        foreach ($users as $user) {
207
+            if (is_object($user)) {
208
+                $user = $user->getUID();
209
+            }
210
+            $path = $inputPath ? $inputPath : '/' . $user;
211
+            ++$user_count;
212
+            if ($this->userManager->userExists($user)) {
213
+                $output->writeln("Starting scan for user $user_count out of $users_total ($user)");
214
+                $this->scanFiles($user, $path, $output, $input->getOption('unscanned'), !$input->getOption('shallow'), $input->getOption('home-only'));
215
+                $output->writeln('', OutputInterface::VERBOSITY_VERBOSE);
216
+            } else {
217
+                $output->writeln("<error>Unknown user $user_count $user</error>");
218
+                $output->writeln('', OutputInterface::VERBOSITY_VERBOSE);
219
+            }
220
+
221
+            try {
222
+                $this->abortIfInterrupted();
223
+            } catch (InterruptedException $e) {
224
+                break;
225
+            }
226
+        }
227
+
228
+        $this->presentStats($output);
229
+        return 0;
230
+    }
231
+
232
+    /**
233
+     * Initialises some useful tools for the Command
234
+     */
235
+    protected function initTools() {
236
+        // Start the timer
237
+        $this->execTime = -microtime(true);
238
+        // Convert PHP errors to exceptions
239
+        set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
240
+    }
241
+
242
+    /**
243
+     * Processes PHP errors as exceptions in order to be able to keep track of problems
244
+     *
245
+     * @see https://www.php.net/manual/en/function.set-error-handler.php
246
+     *
247
+     * @param int $severity the level of the error raised
248
+     * @param string $message
249
+     * @param string $file the filename that the error was raised in
250
+     * @param int $line the line number the error was raised
251
+     *
252
+     * @throws \ErrorException
253
+     */
254
+    public function exceptionErrorHandler($severity, $message, $file, $line) {
255
+        if (!(error_reporting() & $severity)) {
256
+            // This error code is not included in error_reporting
257
+            return;
258
+        }
259
+        throw new \ErrorException($message, 0, $severity, $file, $line);
260
+    }
261
+
262
+    /**
263
+     * @param OutputInterface $output
264
+     */
265
+    protected function presentStats(OutputInterface $output) {
266
+        // Stop the timer
267
+        $this->execTime += microtime(true);
268
+
269
+        $headers = [
270
+            'Folders', 'Files', 'Elapsed time'
271
+        ];
272
+
273
+        $this->showSummary($headers, null, $output);
274
+    }
275
+
276
+    /**
277
+     * Shows a summary of operations
278
+     *
279
+     * @param string[] $headers
280
+     * @param string[] $rows
281
+     * @param OutputInterface $output
282
+     */
283
+    protected function showSummary($headers, $rows, OutputInterface $output) {
284
+        $niceDate = $this->formatExecTime();
285
+        if (!$rows) {
286
+            $rows = [
287
+                $this->foldersCounter,
288
+                $this->filesCounter,
289
+                $niceDate,
290
+            ];
291
+        }
292
+        $table = new Table($output);
293
+        $table
294
+            ->setHeaders($headers)
295
+            ->setRows([$rows]);
296
+        $table->render();
297
+    }
298
+
299
+
300
+    /**
301
+     * Formats microtime into a human readable format
302
+     *
303
+     * @return string
304
+     */
305
+    protected function formatExecTime() {
306
+        $secs = round($this->execTime);
307
+        # convert seconds into HH:MM:SS form
308
+        return sprintf('%02d:%02d:%02d', ($secs / 3600), ($secs / 60 % 60), $secs % 60);
309
+    }
310
+
311
+    protected function reconnectToDatabase(OutputInterface $output): Connection {
312
+        /** @var Connection $connection */
313
+        $connection = \OC::$server->get(Connection::class);
314
+        try {
315
+            $connection->close();
316
+        } catch (\Exception $ex) {
317
+            $output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
318
+        }
319
+        while (!$connection->isConnected()) {
320
+            try {
321
+                $connection->connect();
322
+            } catch (\Exception $ex) {
323
+                $output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
324
+                sleep(60);
325
+            }
326
+        }
327
+        return $connection;
328
+    }
329 329
 }
Please login to merge, or discard this patch.
apps/files/lib/Command/ScanAppData.php 2 patches
Indentation   +241 added lines, -241 removed lines patch added patch discarded remove patch
@@ -46,245 +46,245 @@
 block discarded – undo
46 46
 
47 47
 class ScanAppData extends Base {
48 48
 
49
-	/** @var IRootFolder */
50
-	protected $root;
51
-	/** @var IConfig */
52
-	protected $config;
53
-	/** @var float */
54
-	protected $execTime = 0;
55
-	/** @var int */
56
-	protected $foldersCounter = 0;
57
-	/** @var int */
58
-	protected $filesCounter = 0;
59
-
60
-	public function __construct(IRootFolder $rootFolder, IConfig $config) {
61
-		parent::__construct();
62
-
63
-		$this->root = $rootFolder;
64
-		$this->config = $config;
65
-	}
66
-
67
-	protected function configure() {
68
-		parent::configure();
69
-
70
-		$this
71
-			->setName('files:scan-app-data')
72
-			->setDescription('rescan the AppData folder');
73
-
74
-		$this->addArgument('folder', InputArgument::OPTIONAL, 'The appdata subfolder to scan', '');
75
-	}
76
-
77
-	public function checkScanWarning($fullPath, OutputInterface $output) {
78
-		$normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
79
-		$path = basename($fullPath);
80
-
81
-		if ($normalizedPath !== $path) {
82
-			$output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
83
-		}
84
-	}
85
-
86
-	protected function scanFiles(OutputInterface $output, string $folder): int {
87
-		try {
88
-			$appData = $this->getAppDataFolder();
89
-		} catch (NotFoundException $e) {
90
-			$output->writeln('<error>NoAppData folder found</error>');
91
-			return 1;
92
-		}
93
-
94
-		if ($folder !== '') {
95
-			try {
96
-				$appData = $appData->get($folder);
97
-			} catch (NotFoundException $e) {
98
-				$output->writeln('<error>Could not find folder: ' . $folder . '</error>');
99
-				return 1;
100
-			}
101
-		}
102
-
103
-		$connection = $this->reconnectToDatabase($output);
104
-		$scanner = new \OC\Files\Utils\Scanner(
105
-			null,
106
-			new ConnectionAdapter($connection),
107
-			\OC::$server->query(IEventDispatcher::class),
108
-			\OC::$server->getLogger()
109
-		);
110
-
111
-		# check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
112
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
113
-			$output->writeln("\tFile   <info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
114
-			++$this->filesCounter;
115
-			$this->abortIfInterrupted();
116
-		});
117
-
118
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
119
-			$output->writeln("\tFolder <info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
120
-			++$this->foldersCounter;
121
-			$this->abortIfInterrupted();
122
-		});
123
-
124
-		$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
125
-			$output->writeln('Error while scanning, storage not available (' . $e->getMessage() . ')', OutputInterface::VERBOSITY_VERBOSE);
126
-		});
127
-
128
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
129
-			$this->checkScanWarning($path, $output);
130
-		});
131
-
132
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
133
-			$this->checkScanWarning($path, $output);
134
-		});
135
-
136
-		try {
137
-			$scanner->scan($appData->getPath());
138
-		} catch (ForbiddenException $e) {
139
-			$output->writeln('<error>Storage not writable</error>');
140
-			$output->writeln('<info>Make sure you\'re running the scan command only as the user the web server runs as</info>');
141
-			return 1;
142
-		} catch (InterruptedException $e) {
143
-			# exit the function if ctrl-c has been pressed
144
-			$output->writeln('<info>Interrupted by user</info>');
145
-			return 1;
146
-		} catch (NotFoundException $e) {
147
-			$output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
148
-			return 1;
149
-		} catch (\Exception $e) {
150
-			$output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
151
-			$output->writeln('<error>' . $e->getTraceAsString() . '</error>');
152
-			return 1;
153
-		}
154
-
155
-		return 0;
156
-	}
157
-
158
-
159
-	protected function execute(InputInterface $input, OutputInterface $output): int {
160
-		# restrict the verbosity level to VERBOSITY_VERBOSE
161
-		if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
162
-			$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
163
-		}
164
-
165
-		$output->writeln('Scanning AppData for files');
166
-		$output->writeln('');
167
-
168
-		$folder = $input->getArgument('folder');
169
-
170
-		$this->initTools();
171
-
172
-		$exitCode = $this->scanFiles($output, $folder);
173
-		if ($exitCode === 0) {
174
-			$this->presentStats($output);
175
-		}
176
-		return $exitCode;
177
-	}
178
-
179
-	/**
180
-	 * Initialises some useful tools for the Command
181
-	 */
182
-	protected function initTools() {
183
-		// Start the timer
184
-		$this->execTime = -microtime(true);
185
-		// Convert PHP errors to exceptions
186
-		set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
187
-	}
188
-
189
-	/**
190
-	 * Processes PHP errors as exceptions in order to be able to keep track of problems
191
-	 *
192
-	 * @see https://www.php.net/manual/en/function.set-error-handler.php
193
-	 *
194
-	 * @param int $severity the level of the error raised
195
-	 * @param string $message
196
-	 * @param string $file the filename that the error was raised in
197
-	 * @param int $line the line number the error was raised
198
-	 *
199
-	 * @throws \ErrorException
200
-	 */
201
-	public function exceptionErrorHandler($severity, $message, $file, $line) {
202
-		if (!(error_reporting() & $severity)) {
203
-			// This error code is not included in error_reporting
204
-			return;
205
-		}
206
-		throw new \ErrorException($message, 0, $severity, $file, $line);
207
-	}
208
-
209
-	/**
210
-	 * @param OutputInterface $output
211
-	 */
212
-	protected function presentStats(OutputInterface $output) {
213
-		// Stop the timer
214
-		$this->execTime += microtime(true);
215
-
216
-		$headers = [
217
-			'Folders', 'Files', 'Elapsed time'
218
-		];
219
-
220
-		$this->showSummary($headers, null, $output);
221
-	}
222
-
223
-	/**
224
-	 * Shows a summary of operations
225
-	 *
226
-	 * @param string[] $headers
227
-	 * @param string[] $rows
228
-	 * @param OutputInterface $output
229
-	 */
230
-	protected function showSummary($headers, $rows, OutputInterface $output) {
231
-		$niceDate = $this->formatExecTime();
232
-		if (!$rows) {
233
-			$rows = [
234
-				$this->foldersCounter,
235
-				$this->filesCounter,
236
-				$niceDate,
237
-			];
238
-		}
239
-		$table = new Table($output);
240
-		$table
241
-			->setHeaders($headers)
242
-			->setRows([$rows]);
243
-		$table->render();
244
-	}
245
-
246
-
247
-	/**
248
-	 * Formats microtime into a human readable format
249
-	 *
250
-	 * @return string
251
-	 */
252
-	protected function formatExecTime() {
253
-		$secs = round($this->execTime);
254
-		# convert seconds into HH:MM:SS form
255
-		return sprintf('%02d:%02d:%02d', ($secs / 3600), ($secs / 60 % 60), $secs % 60);
256
-	}
257
-
258
-	protected function reconnectToDatabase(OutputInterface $output): Connection {
259
-		/** @var Connection $connection*/
260
-		$connection = \OC::$server->get(Connection::class);
261
-		try {
262
-			$connection->close();
263
-		} catch (\Exception $ex) {
264
-			$output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
265
-		}
266
-		while (!$connection->isConnected()) {
267
-			try {
268
-				$connection->connect();
269
-			} catch (\Exception $ex) {
270
-				$output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
271
-				sleep(60);
272
-			}
273
-		}
274
-		return $connection;
275
-	}
276
-
277
-	/**
278
-	 * @return \OCP\Files\Folder
279
-	 * @throws NotFoundException
280
-	 */
281
-	private function getAppDataFolder() {
282
-		$instanceId = $this->config->getSystemValue('instanceid', null);
283
-
284
-		if ($instanceId === null) {
285
-			throw new NotFoundException();
286
-		}
287
-
288
-		return $this->root->get('appdata_'.$instanceId);
289
-	}
49
+    /** @var IRootFolder */
50
+    protected $root;
51
+    /** @var IConfig */
52
+    protected $config;
53
+    /** @var float */
54
+    protected $execTime = 0;
55
+    /** @var int */
56
+    protected $foldersCounter = 0;
57
+    /** @var int */
58
+    protected $filesCounter = 0;
59
+
60
+    public function __construct(IRootFolder $rootFolder, IConfig $config) {
61
+        parent::__construct();
62
+
63
+        $this->root = $rootFolder;
64
+        $this->config = $config;
65
+    }
66
+
67
+    protected function configure() {
68
+        parent::configure();
69
+
70
+        $this
71
+            ->setName('files:scan-app-data')
72
+            ->setDescription('rescan the AppData folder');
73
+
74
+        $this->addArgument('folder', InputArgument::OPTIONAL, 'The appdata subfolder to scan', '');
75
+    }
76
+
77
+    public function checkScanWarning($fullPath, OutputInterface $output) {
78
+        $normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
79
+        $path = basename($fullPath);
80
+
81
+        if ($normalizedPath !== $path) {
82
+            $output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
83
+        }
84
+    }
85
+
86
+    protected function scanFiles(OutputInterface $output, string $folder): int {
87
+        try {
88
+            $appData = $this->getAppDataFolder();
89
+        } catch (NotFoundException $e) {
90
+            $output->writeln('<error>NoAppData folder found</error>');
91
+            return 1;
92
+        }
93
+
94
+        if ($folder !== '') {
95
+            try {
96
+                $appData = $appData->get($folder);
97
+            } catch (NotFoundException $e) {
98
+                $output->writeln('<error>Could not find folder: ' . $folder . '</error>');
99
+                return 1;
100
+            }
101
+        }
102
+
103
+        $connection = $this->reconnectToDatabase($output);
104
+        $scanner = new \OC\Files\Utils\Scanner(
105
+            null,
106
+            new ConnectionAdapter($connection),
107
+            \OC::$server->query(IEventDispatcher::class),
108
+            \OC::$server->getLogger()
109
+        );
110
+
111
+        # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
112
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
113
+            $output->writeln("\tFile   <info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
114
+            ++$this->filesCounter;
115
+            $this->abortIfInterrupted();
116
+        });
117
+
118
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
119
+            $output->writeln("\tFolder <info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
120
+            ++$this->foldersCounter;
121
+            $this->abortIfInterrupted();
122
+        });
123
+
124
+        $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
125
+            $output->writeln('Error while scanning, storage not available (' . $e->getMessage() . ')', OutputInterface::VERBOSITY_VERBOSE);
126
+        });
127
+
128
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
129
+            $this->checkScanWarning($path, $output);
130
+        });
131
+
132
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
133
+            $this->checkScanWarning($path, $output);
134
+        });
135
+
136
+        try {
137
+            $scanner->scan($appData->getPath());
138
+        } catch (ForbiddenException $e) {
139
+            $output->writeln('<error>Storage not writable</error>');
140
+            $output->writeln('<info>Make sure you\'re running the scan command only as the user the web server runs as</info>');
141
+            return 1;
142
+        } catch (InterruptedException $e) {
143
+            # exit the function if ctrl-c has been pressed
144
+            $output->writeln('<info>Interrupted by user</info>');
145
+            return 1;
146
+        } catch (NotFoundException $e) {
147
+            $output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
148
+            return 1;
149
+        } catch (\Exception $e) {
150
+            $output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
151
+            $output->writeln('<error>' . $e->getTraceAsString() . '</error>');
152
+            return 1;
153
+        }
154
+
155
+        return 0;
156
+    }
157
+
158
+
159
+    protected function execute(InputInterface $input, OutputInterface $output): int {
160
+        # restrict the verbosity level to VERBOSITY_VERBOSE
161
+        if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
162
+            $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
163
+        }
164
+
165
+        $output->writeln('Scanning AppData for files');
166
+        $output->writeln('');
167
+
168
+        $folder = $input->getArgument('folder');
169
+
170
+        $this->initTools();
171
+
172
+        $exitCode = $this->scanFiles($output, $folder);
173
+        if ($exitCode === 0) {
174
+            $this->presentStats($output);
175
+        }
176
+        return $exitCode;
177
+    }
178
+
179
+    /**
180
+     * Initialises some useful tools for the Command
181
+     */
182
+    protected function initTools() {
183
+        // Start the timer
184
+        $this->execTime = -microtime(true);
185
+        // Convert PHP errors to exceptions
186
+        set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
187
+    }
188
+
189
+    /**
190
+     * Processes PHP errors as exceptions in order to be able to keep track of problems
191
+     *
192
+     * @see https://www.php.net/manual/en/function.set-error-handler.php
193
+     *
194
+     * @param int $severity the level of the error raised
195
+     * @param string $message
196
+     * @param string $file the filename that the error was raised in
197
+     * @param int $line the line number the error was raised
198
+     *
199
+     * @throws \ErrorException
200
+     */
201
+    public function exceptionErrorHandler($severity, $message, $file, $line) {
202
+        if (!(error_reporting() & $severity)) {
203
+            // This error code is not included in error_reporting
204
+            return;
205
+        }
206
+        throw new \ErrorException($message, 0, $severity, $file, $line);
207
+    }
208
+
209
+    /**
210
+     * @param OutputInterface $output
211
+     */
212
+    protected function presentStats(OutputInterface $output) {
213
+        // Stop the timer
214
+        $this->execTime += microtime(true);
215
+
216
+        $headers = [
217
+            'Folders', 'Files', 'Elapsed time'
218
+        ];
219
+
220
+        $this->showSummary($headers, null, $output);
221
+    }
222
+
223
+    /**
224
+     * Shows a summary of operations
225
+     *
226
+     * @param string[] $headers
227
+     * @param string[] $rows
228
+     * @param OutputInterface $output
229
+     */
230
+    protected function showSummary($headers, $rows, OutputInterface $output) {
231
+        $niceDate = $this->formatExecTime();
232
+        if (!$rows) {
233
+            $rows = [
234
+                $this->foldersCounter,
235
+                $this->filesCounter,
236
+                $niceDate,
237
+            ];
238
+        }
239
+        $table = new Table($output);
240
+        $table
241
+            ->setHeaders($headers)
242
+            ->setRows([$rows]);
243
+        $table->render();
244
+    }
245
+
246
+
247
+    /**
248
+     * Formats microtime into a human readable format
249
+     *
250
+     * @return string
251
+     */
252
+    protected function formatExecTime() {
253
+        $secs = round($this->execTime);
254
+        # convert seconds into HH:MM:SS form
255
+        return sprintf('%02d:%02d:%02d', ($secs / 3600), ($secs / 60 % 60), $secs % 60);
256
+    }
257
+
258
+    protected function reconnectToDatabase(OutputInterface $output): Connection {
259
+        /** @var Connection $connection*/
260
+        $connection = \OC::$server->get(Connection::class);
261
+        try {
262
+            $connection->close();
263
+        } catch (\Exception $ex) {
264
+            $output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
265
+        }
266
+        while (!$connection->isConnected()) {
267
+            try {
268
+                $connection->connect();
269
+            } catch (\Exception $ex) {
270
+                $output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
271
+                sleep(60);
272
+            }
273
+        }
274
+        return $connection;
275
+    }
276
+
277
+    /**
278
+     * @return \OCP\Files\Folder
279
+     * @throws NotFoundException
280
+     */
281
+    private function getAppDataFolder() {
282
+        $instanceId = $this->config->getSystemValue('instanceid', null);
283
+
284
+        if ($instanceId === null) {
285
+            throw new NotFoundException();
286
+        }
287
+
288
+        return $this->root->get('appdata_'.$instanceId);
289
+    }
290 290
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -79,7 +79,7 @@  discard block
 block discarded – undo
79 79
 		$path = basename($fullPath);
80 80
 
81 81
 		if ($normalizedPath !== $path) {
82
-			$output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
82
+			$output->writeln("\t<error>Entry \"".$fullPath.'" will not be accessible due to incompatible encoding</error>');
83 83
 		}
84 84
 	}
85 85
 
@@ -95,7 +95,7 @@  discard block
 block discarded – undo
95 95
 			try {
96 96
 				$appData = $appData->get($folder);
97 97
 			} catch (NotFoundException $e) {
98
-				$output->writeln('<error>Could not find folder: ' . $folder . '</error>');
98
+				$output->writeln('<error>Could not find folder: '.$folder.'</error>');
99 99
 				return 1;
100 100
 			}
101 101
 		}
@@ -109,27 +109,27 @@  discard block
 block discarded – undo
109 109
 		);
110 110
 
111 111
 		# check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
112
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
112
+		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) {
113 113
 			$output->writeln("\tFile   <info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
114 114
 			++$this->filesCounter;
115 115
 			$this->abortIfInterrupted();
116 116
 		});
117 117
 
118
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
118
+		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) {
119 119
 			$output->writeln("\tFolder <info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
120 120
 			++$this->foldersCounter;
121 121
 			$this->abortIfInterrupted();
122 122
 		});
123 123
 
124
-		$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
125
-			$output->writeln('Error while scanning, storage not available (' . $e->getMessage() . ')', OutputInterface::VERBOSITY_VERBOSE);
124
+		$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function(StorageNotAvailableException $e) use ($output) {
125
+			$output->writeln('Error while scanning, storage not available ('.$e->getMessage().')', OutputInterface::VERBOSITY_VERBOSE);
126 126
 		});
127 127
 
128
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
128
+		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) {
129 129
 			$this->checkScanWarning($path, $output);
130 130
 		});
131 131
 
132
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
132
+		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) {
133 133
 			$this->checkScanWarning($path, $output);
134 134
 		});
135 135
 
@@ -144,11 +144,11 @@  discard block
 block discarded – undo
144 144
 			$output->writeln('<info>Interrupted by user</info>');
145 145
 			return 1;
146 146
 		} catch (NotFoundException $e) {
147
-			$output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
147
+			$output->writeln('<error>Path not found: '.$e->getMessage().'</error>');
148 148
 			return 1;
149 149
 		} catch (\Exception $e) {
150
-			$output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
151
-			$output->writeln('<error>' . $e->getTraceAsString() . '</error>');
150
+			$output->writeln('<error>Exception during scan: '.$e->getMessage().'</error>');
151
+			$output->writeln('<error>'.$e->getTraceAsString().'</error>');
152 152
 			return 1;
153 153
 		}
154 154
 
Please login to merge, or discard this patch.