Skip to content

Commit

Permalink
Improve iterators
Browse files Browse the repository at this point in the history
Signed-off-by: Benjamin Gaussorgues <[email protected]>
  • Loading branch information
Altahrim committed Nov 9, 2023
1 parent 347765d commit 782b428
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 122 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ updater.phar: updater.php lib/*.php buildVersionFile.php
clean:
rm updater.phar index.php

index.php: lib/UpdateException.php lib/LogException.php lib/RecursiveDirectoryIteratorWithoutData.php lib/Updater.php index.web.php
index.php: lib/UpdateException.php lib/LogException.php lib/RecursiveDirectoryIteratorFilter.php lib/Updater.php index.web.php
# First put openining php tag and license
awk '/^<\?php$$/,/\*\//' index.web.php > index.php
# Then concat all files while filtering php tag and license
cat lib/UpdateException.php lib/LogException.php lib/RecursiveDirectoryIteratorWithoutData.php lib/Updater.php index.web.php| grep -v "^namespace" | awk '/^<\?php$$/,/\*\//{next} 1' >> index.php
cat lib/UpdateException.php lib/LogException.php lib/RecursiveDirectoryIteratorFilter.php lib/Updater.php index.web.php| grep -v "^namespace" | awk '/^<\?php$$/,/\*\//{next} 1' >> index.php

test/vendor:
cd tests && composer install
Expand Down
98 changes: 51 additions & 47 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,25 @@ class LogException extends \Exception {
}


class RecursiveDirectoryIteratorWithoutData extends \RecursiveFilterIterator {
public function accept(): bool {
$excludes = [
'.rnd',
'.well-known',
'data',
'..',
];
class RecursiveDirectoryIteratorFilter extends \RecursiveFilterIterator {
private array $excludedPaths;

/** @var \SplFileInfo|false */
$current = $this->current();
if (!$current) {
return false;
}
public function __construct(
\RecursiveDirectoryIterator $iterator,
array $excludedPaths = ['data'],
) {
parent::__construct($iterator);
$this->excludedPaths = array_flip($excludedPaths);
}

return !(in_array($current->getFilename(), $excludes, true) || $current->isDir());
public function accept(): bool {
return !isset($this->excludedPaths[$this->current()->getFilename()]);
}
}


class Updater {
private string $baseDir;
private string $nextcloudDir;
private array $configValues = [];
private string $currentVersion = 'unknown';
private string $buildTime;
Expand All @@ -75,13 +72,15 @@ class Updater {
* @param string $baseDir the absolute path to the /updater/ directory in the Nextcloud root
* @throws \Exception
*/
public function __construct(string $baseDir) {
$this->baseDir = $baseDir;
public function __construct(
private string $baseDir
) {
$this->nextcloudDir = realpath(dirname($baseDir));

if ($dir = getenv('NEXTCLOUD_CONFIG_DIR')) {
$configFileName = rtrim($dir, '/') . '/config.php';
$configFileName = realpath($dir . '/config.php');
} else {
$configFileName = $this->baseDir . '/../config/config.php';
$configFileName = $this->nextcloudDir . '/config/config.php';
}
if (!file_exists($configFileName)) {
throw new \Exception('Could not find config.php. Is this file in the "updater" subfolder of Nextcloud?');
Expand All @@ -102,7 +101,7 @@ public function __construct(string $baseDir) {
throw new \Exception('Could not read data directory from config.php.');
}

$versionFileName = $this->baseDir . '/../version.php';
$versionFileName = $this->nextcloudDir . '/version.php';
if (!file_exists($versionFileName)) {
// fallback to version in config.php
$version = $this->getConfigOptionString('version');
Expand Down Expand Up @@ -133,27 +132,23 @@ public function __construct(string $baseDir) {

/**
* Returns whether the web updater is disabled
*
* @return bool
*/
public function isDisabled() {
public function isDisabled(): bool {
return $this->disabled;
}

/**
* Returns current version or "unknown" if this could not be determined.
*
* @return string
*/
public function getCurrentVersion() {
public function getCurrentVersion(): string {
return $this->currentVersion;
}

/**
* Returns currently used release channel
*/
private function getCurrentReleaseChannel(): string {
return ($this->getConfigOptionString('updater.release.channel') ?? 'stable');
return $this->getConfigOptionString('updater.release.channel') ?? 'stable';
}

/**
Expand Down Expand Up @@ -325,14 +320,17 @@ private function getAppDirectories(): array {
*
* @return \RecursiveIteratorIterator<\RecursiveDirectoryIterator>
*/
private function getRecursiveDirectoryIterator(?string $folder = null): \RecursiveIteratorIterator {
private function getRecursiveDirectoryIterator(?string $folder = null, array $excludedPaths = []): \RecursiveIteratorIterator {
if ($folder === null) {
$folder = $this->baseDir . '/../';
}
return new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($folder, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);

$iterator = new \RecursiveDirectoryIterator($folder, \RecursiveDirectoryIterator::SKIP_DOTS);
if (!empty($excludedPaths)) {
$iterator = new RecursiveDirectoryIteratorFilter($iterator, $excludedPaths);
}

return new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST);
}

/**
Expand All @@ -343,7 +341,7 @@ public function checkForExpectedFilesAndFolders(): void {

$expectedElements = $this->getExpectedElementsList();
$unexpectedElements = [];
foreach (new \DirectoryIterator($this->baseDir . '/../') as $fileInfo) {
foreach (new \DirectoryIterator($this->nextcloudDir) as $fileInfo) {
if (array_search($fileInfo->getFilename(), $expectedElements) === false) {
$unexpectedElements[] = $fileInfo->getFilename();
}
Expand All @@ -361,15 +359,21 @@ public function checkForExpectedFilesAndFolders(): void {
public function checkWritePermissions(): void {
$this->silentLog('[info] checkWritePermissions()');

$notWritablePaths = array();
$dir = new \RecursiveDirectoryIterator($this->baseDir . '/../');
$filter = new RecursiveDirectoryIteratorWithoutData($dir);
/** @var iterable<string, \SplFileInfo> */
$it = new \RecursiveIteratorIterator($filter);
$excludedPaths = [
'.rnd',
'.well-known',
'data',
];

$it = new \DirectoryIterator($this->nextcloudDir);

foreach ($it as $path => $dir) {
if (!is_writable($path)) {
$notWritablePaths[] = $path;
$notWritablePaths = [];
foreach ($it as $path => $fileInfo) {
if ($fileInfo->isDot() || isset($excludedPaths[$fileInfo->getFilename()])) {
continue;
}
if (!$fileInfo->isWritable()) {
$notWritablePaths[] = $fileInfo->getFilename();
}
}
if (count($notWritablePaths) > 0) {
Expand Down Expand Up @@ -442,7 +446,7 @@ public function createBackup(): void {
* @var string $path
* @var \SplFileInfo $fileInfo
*/
foreach ($this->getRecursiveDirectoryIterator($currentDir) as $path => $fileInfo) {
foreach ($this->getRecursiveDirectoryIterator($currentDir, $excludedElements) as $path => $fileInfo) {
$fileName = explode($currentDir, $path)[1];
$folderStructure = explode('/', $fileName, -1);

Expand All @@ -459,6 +463,7 @@ public function createBackup(): void {

// Create folder if it doesn't exist
if (!file_exists($backupFolderLocation . '/' . dirname($fileName))) {
echo 'Create directory ', $backupFolderLocation . '/' . dirname($fileName), PHP_EOL;
$state = mkdir($backupFolderLocation . '/' . dirname($fileName), 0750, true);
if ($state === false) {
throw new \Exception('Could not create folder: ' . $backupFolderLocation . '/' . dirname($fileName));
Expand All @@ -467,6 +472,8 @@ public function createBackup(): void {

// If it is a file copy it
if ($fileInfo->isFile()) {
echo 'Copy file ',$fileInfo->getRealPath(), 'to ', $backupFolderLocation, PHP_EOL;
$state = true;
$state = copy($fileInfo->getRealPath(), $backupFolderLocation . $fileName);
if ($state === false) {
$message = sprintf(
Expand Down Expand Up @@ -971,8 +978,9 @@ public function deleteOldFiles(): void {
}

/**
* Moves the specified filed except the excluded elements to the correct position
* Moves the specified files except the excluded elements to the correct position
*
* @param string[] $excludedElements
* @throws \Exception
*/
private function moveWithExclusions(string $dataLocation, array $excludedElements): void {
Expand Down Expand Up @@ -1294,7 +1302,6 @@ public function isAuthenticated(): bool {
if (isset($_POST['step'])) {
// mark step as failed
http_response_code(500);
header('Content-Type: application/json');
echo(json_encode(['proceed' => false, 'response' => $e->getMessage()]));
die();
}
Expand Down Expand Up @@ -1381,7 +1388,6 @@ public function isAuthenticated(): bool {
break;
}
$updater->endStep($step);
header('Content-Type: application/json');
echo(json_encode(['proceed' => true]));
} catch (UpdateException $e) {
$data = $e->getData();
Expand All @@ -1397,7 +1403,6 @@ public function isAuthenticated(): bool {
$updater->rollbackChanges($step);
}
http_response_code(500);
header('Content-Type: application/json');
echo(json_encode(['proceed' => false, 'response' => $data]));
} catch (\Exception $e) {
$message = $e->getMessage();
Expand All @@ -1413,7 +1418,6 @@ public function isAuthenticated(): bool {
$updater->rollbackChanges($step);
}
http_response_code(500);
header('Content-Type: application/json');
echo(json_encode(['proceed' => false, 'response' => $message]));
}

Expand Down
42 changes: 0 additions & 42 deletions lib/RecursiveDirectoryIteratorWithoutData.php

This file was deleted.

Loading

0 comments on commit 782b428

Please sign in to comment.