diff options
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | apps/files/l10n/es.js | 1 | ||||
-rw-r--r-- | apps/files/l10n/es.json | 1 | ||||
-rw-r--r-- | apps/files_external/3rdparty/composer.json | 2 | ||||
-rw-r--r-- | apps/files_external/3rdparty/composer.lock | 14 | ||||
-rw-r--r-- | apps/files_external/3rdparty/composer/LICENSE | 2 | ||||
-rw-r--r-- | apps/files_external/3rdparty/composer/installed.json | 12 | ||||
-rw-r--r-- | apps/files_external/3rdparty/icewind/smb/src/Connection.php | 52 | ||||
-rw-r--r-- | apps/files_external/3rdparty/icewind/smb/src/IShare.php | 18 | ||||
-rw-r--r-- | apps/files_external/3rdparty/icewind/smb/src/NativeShare.php | 12 | ||||
-rw-r--r-- | apps/files_external/3rdparty/icewind/smb/src/Share.php | 51 | ||||
-rw-r--r-- | apps/files_sharing/l10n/de.js | 17 | ||||
-rw-r--r-- | apps/files_sharing/l10n/de.json | 17 | ||||
-rw-r--r-- | apps/files_sharing/l10n/de_DE.js | 17 | ||||
-rw-r--r-- | apps/files_sharing/l10n/de_DE.json | 17 | ||||
-rw-r--r-- | apps/files_sharing/l10n/fi_FI.js | 7 | ||||
-rw-r--r-- | apps/files_sharing/l10n/fi_FI.json | 7 | ||||
-rw-r--r-- | apps/files_sharing/l10n/fr.js | 10 | ||||
-rw-r--r-- | apps/files_sharing/l10n/fr.json | 10 | ||||
-rw-r--r-- | apps/files_sharing/l10n/it.js | 1 | ||||
-rw-r--r-- | apps/files_sharing/l10n/it.json | 1 | ||||
-rw-r--r-- | apps/systemtags/l10n/es.js | 1 | ||||
-rw-r--r-- | apps/systemtags/l10n/es.json | 1 | ||||
-rw-r--r-- | apps/user_ldap/l10n/es.js | 1 | ||||
-rw-r--r-- | apps/user_ldap/l10n/es.json | 1 | ||||
-rw-r--r-- | core/Command/Maintenance/Repair.php | 69 | ||||
-rw-r--r-- | core/Command/Upgrade.php | 66 | ||||
-rw-r--r-- | core/ajax/update.php | 64 | ||||
-rw-r--r-- | core/register_command.php | 4 | ||||
-rw-r--r-- | lib/private/ActivityManager.php (renamed from lib/private/activitymanager.php) | 0 | ||||
-rw-r--r-- | lib/private/AllConfig.php (renamed from lib/private/allconfig.php) | 0 | ||||
-rw-r--r-- | lib/private/App/DependencyAnalyzer.php | 6 | ||||
-rw-r--r-- | lib/private/App/InfoParser.php | 6 | ||||
-rw-r--r-- | lib/private/App/Platform.php | 7 | ||||
-rw-r--r-- | lib/private/AppConfig.php (renamed from lib/private/appconfig.php) | 0 | ||||
-rw-r--r-- | lib/private/AppFramework/Http/Request.php | 3 | ||||
-rw-r--r-- | lib/private/AppHelper.php (renamed from lib/private/apphelper.php) | 0 | ||||
-rw-r--r-- | lib/private/Avatar.php (renamed from lib/private/avatar.php) | 0 | ||||
-rw-r--r-- | lib/private/AvatarManager.php (renamed from lib/private/avatarmanager.php) | 0 | ||||
-rw-r--r-- | lib/private/CapabilitiesManager.php (renamed from lib/private/capabilitiesmanager.php) | 0 | ||||
-rw-r--r-- | lib/private/Config.php (renamed from lib/private/config.php) | 0 | ||||
-rw-r--r-- | lib/private/ContactsManager.php (renamed from lib/private/contactsmanager.php) | 0 | ||||
-rw-r--r-- | lib/private/DatabaseException.php (renamed from lib/private/databaseexception.php) | 0 | ||||
-rw-r--r-- | lib/private/DatabaseSetupException.php (renamed from lib/private/databasesetupexception.php) | 0 | ||||
-rw-r--r-- | lib/private/DateTimeFormatter.php (renamed from lib/private/datetimeformatter.php) | 0 | ||||
-rw-r--r-- | lib/private/DateTimeZone.php (renamed from lib/private/datetimezone.php) | 0 | ||||
-rw-r--r-- | lib/private/Files/Filesystem.php | 7 | ||||
-rw-r--r-- | lib/private/Files/Storage/Wrapper/Availability.php | 4 | ||||
-rw-r--r-- | lib/private/ForbiddenException.php (renamed from lib/private/forbiddenexception.php) | 0 | ||||
-rw-r--r-- | lib/private/HTTPHelper.php (renamed from lib/private/httphelper.php) | 0 | ||||
-rw-r--r-- | lib/private/HintException.php (renamed from lib/private/hintexception.php) | 0 | ||||
-rw-r--r-- | lib/private/Http/Client/Client.php (renamed from lib/private/http/client/client.php) | 0 | ||||
-rw-r--r-- | lib/private/Http/Client/ClientService.php (renamed from lib/private/http/client/clientservice.php) | 0 | ||||
-rw-r--r-- | lib/private/Http/Client/Response.php (renamed from lib/private/http/client/response.php) | 0 | ||||
-rw-r--r-- | lib/private/LargeFileHelper.php (renamed from lib/private/largefilehelper.php) | 0 | ||||
-rw-r--r-- | lib/private/Lock/AbstractLockingProvider.php | 4 | ||||
-rw-r--r-- | lib/private/Lock/MemcacheLockingProvider.php | 9 | ||||
-rw-r--r-- | lib/private/Log.php (renamed from lib/private/log.php) | 0 | ||||
-rw-r--r-- | lib/private/Migration/BackgroundRepair.php | 116 | ||||
-rw-r--r-- | lib/private/NaturalSort.php (renamed from lib/private/naturalsort.php) | 0 | ||||
-rw-r--r-- | lib/private/NavigationManager.php (renamed from lib/private/navigationmanager.php) | 0 | ||||
-rw-r--r-- | lib/private/NeedsUpdateException.php (renamed from lib/private/needsupdateexception.php) | 0 | ||||
-rw-r--r-- | lib/private/NotSquareException.php (renamed from lib/private/notsquareexception.php) | 0 | ||||
-rw-r--r-- | lib/private/OCSClient.php (renamed from lib/private/ocsclient.php) | 0 | ||||
-rw-r--r-- | lib/private/Preview.php (renamed from lib/private/preview.php) | 0 | ||||
-rw-r--r-- | lib/private/PreviewManager.php (renamed from lib/private/previewmanager.php) | 0 | ||||
-rw-r--r-- | lib/private/Repair.php (renamed from lib/private/repair.php) | 20 | ||||
-rw-r--r-- | lib/private/Repair/DropOldTables.php | 5 | ||||
-rw-r--r-- | lib/private/RepairException.php (renamed from lib/private/repairexception.php) | 0 | ||||
-rw-r--r-- | lib/private/Search.php (renamed from lib/private/search.php) | 0 | ||||
-rw-r--r-- | lib/private/ServerContainer.php (renamed from lib/private/servercontainer.php) | 0 | ||||
-rw-r--r-- | lib/private/ServerNotAvailableException.php (renamed from lib/private/servernotavailableexception.php) | 0 | ||||
-rw-r--r-- | lib/private/ServiceUnavailableException.php (renamed from lib/private/serviceunavailableexception.php) | 0 | ||||
-rw-r--r-- | lib/private/Setup.php (renamed from lib/private/setup.php) | 0 | ||||
-rw-r--r-- | lib/private/Streamer.php (renamed from lib/private/streamer.php) | 0 | ||||
-rw-r--r-- | lib/private/SubAdmin.php (renamed from lib/private/subadmin.php) | 0 | ||||
-rw-r--r-- | lib/private/SystemConfig.php (renamed from lib/private/systemconfig.php) | 0 | ||||
-rw-r--r-- | lib/private/TagManager.php (renamed from lib/private/tagmanager.php) | 0 | ||||
-rw-r--r-- | lib/private/Tags.php (renamed from lib/private/tags.php) | 0 | ||||
-rw-r--r-- | lib/private/TempManager.php (renamed from lib/private/tempmanager.php) | 0 | ||||
-rw-r--r-- | lib/private/TemplateLayout.php (renamed from lib/private/templatelayout.php) | 0 | ||||
-rw-r--r-- | lib/private/URLGenerator.php (renamed from lib/private/urlgenerator.php) | 0 | ||||
-rw-r--r-- | lib/private/Updater.php (renamed from lib/private/updater.php) | 29 | ||||
-rw-r--r-- | lib/private/app.php | 14 | ||||
-rw-r--r-- | lib/public/migration/ioutput.php | 3 | ||||
-rw-r--r-- | tests/data/app/expected-info.json | 3 | ||||
-rw-r--r-- | tests/lib/RepairTest.php | 134 | ||||
-rw-r--r-- | tests/lib/app/dependencyanalyzer.php | 24 | ||||
-rw-r--r-- | tests/lib/files/storage/wrapper/availability.php | 7 | ||||
-rw-r--r-- | tests/lib/migration/BackgroundRepairTest.php | 120 | ||||
-rw-r--r-- | tests/lib/preview/movie.php | 7 | ||||
-rw-r--r-- | tests/lib/preview/office.php | 7 | ||||
-rw-r--r-- | tests/lib/repair.php | 159 |
93 files changed, 886 insertions, 288 deletions
diff --git a/README.md b/README.md index 63ba04031b0..6d23a365993 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ A personal cloud which runs on your own server.** * ... ## Installation instructions -https://doc.owncloud.org/server/9.0/developer_manual/app/index.html +https://doc.owncloud.org/server/9.1/developer_manual/app/index.html ## Contribution Guidelines https://owncloud.org/contribute/ @@ -47,4 +47,4 @@ https://www.transifex.com/projects/p/owncloud/ [![Transifex](https://www.transifex.com/projects/p/owncloud/resource/core/chart/image_png)](https://www.transifex.com/projects/p/owncloud/) For more detailed information about translations: -http://doc.owncloud.org/server/9.0/developer_manual/core/translation.html +http://doc.owncloud.org/server/9.1/developer_manual/core/translation.html diff --git a/apps/files/l10n/es.js b/apps/files/l10n/es.js index 51114b98999..87f531a02e6 100644 --- a/apps/files/l10n/es.js +++ b/apps/files/l10n/es.js @@ -105,6 +105,7 @@ OC.L10N.register( "With PHP-FPM it might take 5 minutes for changes to be applied." : "Con PHP-FPM podría tomar 5 minutos para que los cambios se apliquen.", "Missing permissions to edit from here." : "Faltan permisos para poder editar desde aquí.", "Settings" : "Ajustes", + "Show hidden files" : "Mostrar archivos ocultos", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">access your Files via WebDAV</a>" : "Introduce esta dirección <a href=\"%s\" target=\"_blank\" rel=\"noreferrer\"> en el cliente de ownCloud para acceder a tus archivos a través de él</a>", "Cancel upload" : "Cancelar la subida", diff --git a/apps/files/l10n/es.json b/apps/files/l10n/es.json index eee5fcfced9..73366ba821b 100644 --- a/apps/files/l10n/es.json +++ b/apps/files/l10n/es.json @@ -103,6 +103,7 @@ "With PHP-FPM it might take 5 minutes for changes to be applied." : "Con PHP-FPM podría tomar 5 minutos para que los cambios se apliquen.", "Missing permissions to edit from here." : "Faltan permisos para poder editar desde aquí.", "Settings" : "Ajustes", + "Show hidden files" : "Mostrar archivos ocultos", "WebDAV" : "WebDAV", "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">access your Files via WebDAV</a>" : "Introduce esta dirección <a href=\"%s\" target=\"_blank\" rel=\"noreferrer\"> en el cliente de ownCloud para acceder a tus archivos a través de él</a>", "Cancel upload" : "Cancelar la subida", diff --git a/apps/files_external/3rdparty/composer.json b/apps/files_external/3rdparty/composer.json index b0267ba3438..72335c8d891 100644 --- a/apps/files_external/3rdparty/composer.json +++ b/apps/files_external/3rdparty/composer.json @@ -8,7 +8,7 @@ "classmap-authoritative": true }, "require": { - "icewind/smb": "1.0.8", + "icewind/smb": "1.1.0", "icewind/streams": "0.4" } } diff --git a/apps/files_external/3rdparty/composer.lock b/apps/files_external/3rdparty/composer.lock index 13931ad757d..7161ae19a2c 100644 --- a/apps/files_external/3rdparty/composer.lock +++ b/apps/files_external/3rdparty/composer.lock @@ -4,21 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "1671a5ec7bef407432d42775f898dc34", - "content-hash": "9d995f0d55bee8a3b344a3c685e7b4a4", + "hash": "8de0823d3d0a167ee24450a111cb67b9", + "content-hash": "6733058865c1765823b31cfbb24552e1", "packages": [ { "name": "icewind/smb", - "version": "v1.0.8", + "version": "v1.1.0", "source": { "type": "git", "url": "https://github.com/icewind1991/SMB.git", - "reference": "764f3fc793a904eb937d619ad097fb076ff199cd" + "reference": "822f924967c68228555cea84ea44765f8e85c601" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/icewind1991/SMB/zipball/764f3fc793a904eb937d619ad097fb076ff199cd", - "reference": "764f3fc793a904eb937d619ad097fb076ff199cd", + "url": "https://api.github.com/repos/icewind1991/SMB/zipball/822f924967c68228555cea84ea44765f8e85c601", + "reference": "822f924967c68228555cea84ea44765f8e85c601", "shasum": "" }, "require": { @@ -47,7 +47,7 @@ } ], "description": "php wrapper for smbclient and libsmbclient-php", - "time": "2016-03-17 13:29:58" + "time": "2016-04-26 13:26:39" }, { "name": "icewind/streams", diff --git a/apps/files_external/3rdparty/composer/LICENSE b/apps/files_external/3rdparty/composer/LICENSE index c8d57af8b27..1a28124886d 100644 --- a/apps/files_external/3rdparty/composer/LICENSE +++ b/apps/files_external/3rdparty/composer/LICENSE @@ -1,5 +1,5 @@ -Copyright (c) 2015 Nils Adermann, Jordi Boggiano +Copyright (c) 2016 Nils Adermann, Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/apps/files_external/3rdparty/composer/installed.json b/apps/files_external/3rdparty/composer/installed.json index 48f8c555c34..31c602de3ca 100644 --- a/apps/files_external/3rdparty/composer/installed.json +++ b/apps/files_external/3rdparty/composer/installed.json @@ -44,17 +44,17 @@ }, { "name": "icewind/smb", - "version": "v1.0.8", - "version_normalized": "1.0.8.0", + "version": "v1.1.0", + "version_normalized": "1.1.0.0", "source": { "type": "git", "url": "https://github.com/icewind1991/SMB.git", - "reference": "764f3fc793a904eb937d619ad097fb076ff199cd" + "reference": "822f924967c68228555cea84ea44765f8e85c601" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/icewind1991/SMB/zipball/764f3fc793a904eb937d619ad097fb076ff199cd", - "reference": "764f3fc793a904eb937d619ad097fb076ff199cd", + "url": "https://api.github.com/repos/icewind1991/SMB/zipball/822f924967c68228555cea84ea44765f8e85c601", + "reference": "822f924967c68228555cea84ea44765f8e85c601", "shasum": "" }, "require": { @@ -65,7 +65,7 @@ "phpunit/phpunit": "^4.8", "satooshi/php-coveralls": "v1.0.0" }, - "time": "2016-03-17 13:29:58", + "time": "2016-04-26 13:26:39", "type": "library", "installation-source": "source", "autoload": { diff --git a/apps/files_external/3rdparty/icewind/smb/src/Connection.php b/apps/files_external/3rdparty/icewind/smb/src/Connection.php index f48dcb766e4..d24cdc1f6d0 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Connection.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Connection.php @@ -15,6 +15,7 @@ use Icewind\SMB\Exception\NoLoginServerException; class Connection extends RawConnection { const DELIMITER = 'smb:'; + const DELIMITER_LENGTH = 4; /** * send input to smbclient @@ -28,6 +29,7 @@ class Connection extends RawConnection { /** * get all unprocessed output from smbclient until the next prompt * + * @param callable $callback (optional) callback to call for every line read * @return string * @throws AuthenticationException * @throws ConnectException @@ -35,7 +37,7 @@ class Connection extends RawConnection { * @throws InvalidHostException * @throws NoLoginServerException */ - public function read() { + public function read(callable $callback = null) { if (!$this->isValid()) { throw new ConnectionException('Connection not valid'); } @@ -45,26 +47,50 @@ class Connection extends RawConnection { $output = array(); $line = $this->readLine(); if ($line === false) { - if ($promptLine) { //maybe we have some error we missed on the previous line - throw new ConnectException('Unknown error (' . $promptLine . ')'); - } else { - $error = $this->readError(); // maybe something on stderr - if ($error) { - throw new ConnectException('Unknown error (' . $error . ')'); - } else { - throw new ConnectException('Unknown error'); + $this->unknownError($promptLine); + } + while (!$this->isPrompt($line)) { //next prompt functions as delimiter + if (is_callable($callback)) { + $result = $callback($line); + if ($result === false) { // allow the callback to close the connection for infinite running commands + $this->close(true); } + } else { + $output[] .= $line; } - } - $length = mb_strlen(self::DELIMITER); - while (mb_substr($line, 0, $length) !== self::DELIMITER) { //next prompt functions as delimiter - $output[] .= $line; $line = $this->readLine(); } return $output; } /** + * Check + * + * @param $line + * @return bool + */ + private function isPrompt($line) { + return mb_substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER || $line === false; + } + + /** + * @param string $promptLine (optional) prompt line that might contain some info about the error + * @throws ConnectException + */ + private function unknownError($promptLine = '') { + if ($promptLine) { //maybe we have some error we missed on the previous line + throw new ConnectException('Unknown error (' . $promptLine . ')'); + } else { + $error = $this->readError(); // maybe something on stderr + if ($error) { + throw new ConnectException('Unknown error (' . $error . ')'); + } else { + throw new ConnectException('Unknown error'); + } + } + } + + /** * check if the first line holds a connection failure * * @param $line diff --git a/apps/files_external/3rdparty/icewind/smb/src/IShare.php b/apps/files_external/3rdparty/icewind/smb/src/IShare.php index 4851e9de053..40423151332 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/IShare.php +++ b/apps/files_external/3rdparty/icewind/smb/src/IShare.php @@ -8,6 +8,17 @@ namespace Icewind\SMB; interface IShare { + // https://msdn.microsoft.com/en-us/library/dn392331.aspx + const NOTIFY_ADDED = 1; + const NOTIFY_REMOVED = 2; + const NOTIFY_MODIFIED = 3; + const NOTIFY_RENAMED_OLD = 4; + const NOTIFY_RENAMED_NEW = 5; + const NOTIFY_ADDED_STREAM = 6; + const NOTIFY_REMOVED_STREAM = 7; + const NOTIFY_MODIFIED_STREAM = 8; + const NOTIFY_REMOVED_BY_DELETE = 9; + /** * Get the name of the share * @@ -131,4 +142,11 @@ interface IShare { * @return mixed */ public function setMode($path, $mode); + + /** + * @param string $path + * @param callable $callback callable which will be called for each received change + * @return mixed + */ + public function notify($path, callable $callback); } diff --git a/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php b/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php index 27d975514a3..51e16d1841f 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php +++ b/apps/files_external/3rdparty/icewind/smb/src/NativeShare.php @@ -301,6 +301,18 @@ class NativeShare extends AbstractShare { return $this->setAttribute($path, 'system.dos_attr.mode', $mode); } + /** + * @param string $path + * @param callable $callback callable which will be called for each received change + * @return mixed + */ + public function notify($path, callable $callback) { + // php-smbclient does support notify (https://github.com/eduardok/libsmbclient-php/issues/29) + // so we use the smbclient based backend for this + $share = new Share($this->server, $this->getName()); + $share->notify($path, $callback); + } + public function __destruct() { unset($this->state); } diff --git a/apps/files_external/3rdparty/icewind/smb/src/Share.php b/apps/files_external/3rdparty/icewind/smb/src/Share.php index 694bd30bd0d..21f8fe5b139 100644 --- a/apps/files_external/3rdparty/icewind/smb/src/Share.php +++ b/apps/files_external/3rdparty/icewind/smb/src/Share.php @@ -51,6 +51,22 @@ class Share extends AbstractShare { $this->parser = new Parser(new TimeZoneProvider($this->server->getHost(), $this->system)); } + protected function getConnection() { + $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : ''; + $command = sprintf('stdbuf -o0 %s %s --authentication-file=%s %s', + $this->system->getSmbclientPath(), + $workgroupArgument, + System::getFD(3), + escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) + ); + $connection = new Connection($command); + $connection->writeAuthentication($this->server->getUser(), $this->server->getPassword()); + if (!$connection->isValid()) { + throw new ConnectionException(); + } + return $connection; + } + /** * @throws \Icewind\SMB\Exception\ConnectionException * @throws \Icewind\SMB\Exception\AuthenticationException @@ -60,18 +76,7 @@ class Share extends AbstractShare { if ($this->connection and $this->connection->isValid()) { return; } - $workgroupArgument = ($this->server->getWorkgroup()) ? ' -W ' . escapeshellarg($this->server->getWorkgroup()) : ''; - $command = sprintf('%s %s --authentication-file=%s %s', - $this->system->getSmbclientPath(), - $workgroupArgument, - System::getFD(3), - escapeshellarg('//' . $this->server->getHost() . '/' . $this->name) - ); - $this->connection = new Connection($command); - $this->connection->writeAuthentication($this->server->getUser(), $this->server->getPassword()); - if (!$this->connection->isValid()) { - throw new ConnectionException(); - } + $this->connection = $this->getConnection(); } protected function reconnect() { @@ -345,6 +350,26 @@ class Share extends AbstractShare { } /** + * @param string $path + * @param callable $callback callable which will be called for each received change + * @return mixed + */ + public function notify($path, callable $callback) { + $connection = $this->getConnection(); // use a fresh connection since the notify command blocks the process + $command = 'notify ' . $this->escapePath($path); + $connection->write($command . PHP_EOL); + $connection->read(function ($line) use ($callback, $path) { + $code = (int)substr($line, 0, 4); + $subPath = substr($line, 5); + if ($path === '') { + return $callback($code, $subPath); + } else { + return $callback($code, $path . '/' . $subPath); + } + }); + } + + /** * @param string $command * @return array */ @@ -370,7 +395,7 @@ class Share extends AbstractShare { * @return bool */ protected function parseOutput($lines, $path = '') { - $this->parser->checkForError($lines, $path); + return $this->parser->checkForError($lines, $path); } /** diff --git a/apps/files_sharing/l10n/de.js b/apps/files_sharing/l10n/de.js index 33d6259527d..a300dd15118 100644 --- a/apps/files_sharing/l10n/de.js +++ b/apps/files_sharing/l10n/de.js @@ -9,6 +9,23 @@ OC.L10N.register( "Storage not valid" : "Speicher ungültig", "Couldn't add remote share" : "Remotefreigabe kann nicht hinzu gefügt werden", "Share API is disabled" : "Teilen-API ist deaktivert", + "Wrong share ID, share doesn't exist" : "Fehlerhafte Freigabe-ID, Freigabe existiert nicht", + "Could not delete share" : "Freigabe konnte nicht gelöscht werden", + "Please specify a file or folder path" : "Bitte eine Datei oder Verzeichnis definieren", + "Wrong path, file/folder doesn't exist" : "Falscher Pfad, Datei/Verzeichnis existiert nicht", + "Please specify a valid user" : "Bitte gib einen gültigen Nutzer an", + "Group sharing is disabled by the administrator" : "Die Gruppenfreigabe ist durch den Administrator deaktiviert", + "Please specify a valid group" : "Bitte gib eine gültige Gruppe an", + "Public link sharing is disabled by the administrator" : "Die öffentliche Freigabe von Links ist durch den Administrator deaktiviert", + "Public upload disabled by the administrator" : "Das öffentliche Hochladen ist durch den Administrator deaktiviert", + "Public upload is only possible for publicly shared folders" : "Das öffentliche Hochladen ist nur für öffentlich freigegebene Ordner erlaubt", + "Invalid date, date format must be YYYY-MM-DD" : "Ungültiges Datum, das Datumsformat muss JJJJ-MM-TT sein", + "Sharing %s failed because the back end does not allow shares from type %s" : "Freigabe von %s fehlgeschlagen, da das Backend die Freigabe vom Typ %s nicht erlaubt.", + "Unknown share type" : "Unbekannter Freigabetyp", + "Not a directory" : "Kein Verzeichnis", + "Can't change permissions for public share links" : "Berechtigungen für öffentlich freigegebene Links konnten nicht geändert werden", + "Wrong or no update parameter given" : "Falscher oder kein Updateparameter wurde übergeben", + "Cannot increase permissions" : "Berechtigungen können nicht erhöht werden", "Shared with you" : "Mit Dir geteilt", "Shared with others" : "Von Dir geteilt", "Shared by link" : "Geteilt über einen Link", diff --git a/apps/files_sharing/l10n/de.json b/apps/files_sharing/l10n/de.json index f1cd55bd9f0..bb68ef07639 100644 --- a/apps/files_sharing/l10n/de.json +++ b/apps/files_sharing/l10n/de.json @@ -7,6 +7,23 @@ "Storage not valid" : "Speicher ungültig", "Couldn't add remote share" : "Remotefreigabe kann nicht hinzu gefügt werden", "Share API is disabled" : "Teilen-API ist deaktivert", + "Wrong share ID, share doesn't exist" : "Fehlerhafte Freigabe-ID, Freigabe existiert nicht", + "Could not delete share" : "Freigabe konnte nicht gelöscht werden", + "Please specify a file or folder path" : "Bitte eine Datei oder Verzeichnis definieren", + "Wrong path, file/folder doesn't exist" : "Falscher Pfad, Datei/Verzeichnis existiert nicht", + "Please specify a valid user" : "Bitte gib einen gültigen Nutzer an", + "Group sharing is disabled by the administrator" : "Die Gruppenfreigabe ist durch den Administrator deaktiviert", + "Please specify a valid group" : "Bitte gib eine gültige Gruppe an", + "Public link sharing is disabled by the administrator" : "Die öffentliche Freigabe von Links ist durch den Administrator deaktiviert", + "Public upload disabled by the administrator" : "Das öffentliche Hochladen ist durch den Administrator deaktiviert", + "Public upload is only possible for publicly shared folders" : "Das öffentliche Hochladen ist nur für öffentlich freigegebene Ordner erlaubt", + "Invalid date, date format must be YYYY-MM-DD" : "Ungültiges Datum, das Datumsformat muss JJJJ-MM-TT sein", + "Sharing %s failed because the back end does not allow shares from type %s" : "Freigabe von %s fehlgeschlagen, da das Backend die Freigabe vom Typ %s nicht erlaubt.", + "Unknown share type" : "Unbekannter Freigabetyp", + "Not a directory" : "Kein Verzeichnis", + "Can't change permissions for public share links" : "Berechtigungen für öffentlich freigegebene Links konnten nicht geändert werden", + "Wrong or no update parameter given" : "Falscher oder kein Updateparameter wurde übergeben", + "Cannot increase permissions" : "Berechtigungen können nicht erhöht werden", "Shared with you" : "Mit Dir geteilt", "Shared with others" : "Von Dir geteilt", "Shared by link" : "Geteilt über einen Link", diff --git a/apps/files_sharing/l10n/de_DE.js b/apps/files_sharing/l10n/de_DE.js index 1046645adbe..c1a4f9189d4 100644 --- a/apps/files_sharing/l10n/de_DE.js +++ b/apps/files_sharing/l10n/de_DE.js @@ -9,6 +9,23 @@ OC.L10N.register( "Storage not valid" : "Speicher ungültig", "Couldn't add remote share" : "Entfernte Freigabe kann nicht hinzugefügt werden", "Share API is disabled" : "Teilen-API ist deaktivert", + "Wrong share ID, share doesn't exist" : "Fehlerhafte Freigabe-ID, Freigabe existiert nicht", + "Could not delete share" : "Freigabe konnte nicht gelöscht werden", + "Please specify a file or folder path" : "Bitte eine Datei oder Verzeichnis definieren", + "Wrong path, file/folder doesn't exist" : "Falscher Pfad, Datei/Verzeichnis existiert nicht", + "Please specify a valid user" : "Bitte geben Sie einen gültigen Nutzer an", + "Group sharing is disabled by the administrator" : "Die Gruppenfreigabe ist durch den Administrator deaktiviert", + "Please specify a valid group" : "Bitte geben Sie eine gültige Gruppe an", + "Public link sharing is disabled by the administrator" : "Die öffentliche Freigabe von Links ist durch den Administrator deaktiviert", + "Public upload disabled by the administrator" : "Das öffentliche Hochladen ist durch den Administrator deaktiviert", + "Public upload is only possible for publicly shared folders" : "Das öffentliche Hochladen ist nur für öffentlich freigegebene Ordner erlaubt", + "Invalid date, date format must be YYYY-MM-DD" : "Ungültiges Datum, das Datumsformat muss JJJJ-MM-TT sein", + "Sharing %s failed because the back end does not allow shares from type %s" : "Freigabe von %s fehlgeschlagen, da das Backend die Freigabe vom Typ %s nicht erlaubt.", + "Unknown share type" : "Unbekannter Freigabetyp", + "Not a directory" : "Kein Verzeichnis", + "Can't change permissions for public share links" : "Berechtigungen für öffentlich freigegebene Links konnten nicht geändert werden", + "Wrong or no update parameter given" : "Falscher oder kein Updateparameter wurde übergeben", + "Cannot increase permissions" : "Berechtigungen können nicht erhöht werden", "Shared with you" : "Mit Ihnen geteilt", "Shared with others" : "Von Ihnen geteilt", "Shared by link" : "Geteilt über einen Link", diff --git a/apps/files_sharing/l10n/de_DE.json b/apps/files_sharing/l10n/de_DE.json index 72353313ea9..b5ae9602ab0 100644 --- a/apps/files_sharing/l10n/de_DE.json +++ b/apps/files_sharing/l10n/de_DE.json @@ -7,6 +7,23 @@ "Storage not valid" : "Speicher ungültig", "Couldn't add remote share" : "Entfernte Freigabe kann nicht hinzugefügt werden", "Share API is disabled" : "Teilen-API ist deaktivert", + "Wrong share ID, share doesn't exist" : "Fehlerhafte Freigabe-ID, Freigabe existiert nicht", + "Could not delete share" : "Freigabe konnte nicht gelöscht werden", + "Please specify a file or folder path" : "Bitte eine Datei oder Verzeichnis definieren", + "Wrong path, file/folder doesn't exist" : "Falscher Pfad, Datei/Verzeichnis existiert nicht", + "Please specify a valid user" : "Bitte geben Sie einen gültigen Nutzer an", + "Group sharing is disabled by the administrator" : "Die Gruppenfreigabe ist durch den Administrator deaktiviert", + "Please specify a valid group" : "Bitte geben Sie eine gültige Gruppe an", + "Public link sharing is disabled by the administrator" : "Die öffentliche Freigabe von Links ist durch den Administrator deaktiviert", + "Public upload disabled by the administrator" : "Das öffentliche Hochladen ist durch den Administrator deaktiviert", + "Public upload is only possible for publicly shared folders" : "Das öffentliche Hochladen ist nur für öffentlich freigegebene Ordner erlaubt", + "Invalid date, date format must be YYYY-MM-DD" : "Ungültiges Datum, das Datumsformat muss JJJJ-MM-TT sein", + "Sharing %s failed because the back end does not allow shares from type %s" : "Freigabe von %s fehlgeschlagen, da das Backend die Freigabe vom Typ %s nicht erlaubt.", + "Unknown share type" : "Unbekannter Freigabetyp", + "Not a directory" : "Kein Verzeichnis", + "Can't change permissions for public share links" : "Berechtigungen für öffentlich freigegebene Links konnten nicht geändert werden", + "Wrong or no update parameter given" : "Falscher oder kein Updateparameter wurde übergeben", + "Cannot increase permissions" : "Berechtigungen können nicht erhöht werden", "Shared with you" : "Mit Ihnen geteilt", "Shared with others" : "Von Ihnen geteilt", "Shared by link" : "Geteilt über einen Link", diff --git a/apps/files_sharing/l10n/fi_FI.js b/apps/files_sharing/l10n/fi_FI.js index 04d8a74e974..0a5a4d59110 100644 --- a/apps/files_sharing/l10n/fi_FI.js +++ b/apps/files_sharing/l10n/fi_FI.js @@ -8,6 +8,13 @@ OC.L10N.register( "Could not authenticate to remote share, password might be wrong" : "Tunnistautuminen etäjakoa kohtaan epäonnistui. Salasana saattaa olla väärä", "Storage not valid" : "Tallennustila ei ole kelvollinen", "Couldn't add remote share" : "Etäjaon liittäminen epäonnistui", + "Share API is disabled" : "Jakamisrajapinta on poistettu käytöstä", + "Could not delete share" : "Jaon poistaminen ei onnistunut", + "Wrong path, file/folder doesn't exist" : "Väärä polku, tiedostoa tai kansiota ei ole olemassa", + "Please specify a valid user" : "Määritä kelvollinen käyttäjä", + "Group sharing is disabled by the administrator" : "Ylläpitäjä on estänyt ryhmäjakamisen", + "Please specify a valid group" : "Määritä kelvollinen ryhmä", + "Public link sharing is disabled by the administrator" : "Ylläpitäjä on estänyt julkisen linkin jakamisen", "Shared with you" : "Jaettu kanssasi", "Shared with others" : "Jaettu muiden kanssa", "Shared by link" : "Jaettu linkin kautta", diff --git a/apps/files_sharing/l10n/fi_FI.json b/apps/files_sharing/l10n/fi_FI.json index c2ded25771b..bed64329317 100644 --- a/apps/files_sharing/l10n/fi_FI.json +++ b/apps/files_sharing/l10n/fi_FI.json @@ -6,6 +6,13 @@ "Could not authenticate to remote share, password might be wrong" : "Tunnistautuminen etäjakoa kohtaan epäonnistui. Salasana saattaa olla väärä", "Storage not valid" : "Tallennustila ei ole kelvollinen", "Couldn't add remote share" : "Etäjaon liittäminen epäonnistui", + "Share API is disabled" : "Jakamisrajapinta on poistettu käytöstä", + "Could not delete share" : "Jaon poistaminen ei onnistunut", + "Wrong path, file/folder doesn't exist" : "Väärä polku, tiedostoa tai kansiota ei ole olemassa", + "Please specify a valid user" : "Määritä kelvollinen käyttäjä", + "Group sharing is disabled by the administrator" : "Ylläpitäjä on estänyt ryhmäjakamisen", + "Please specify a valid group" : "Määritä kelvollinen ryhmä", + "Public link sharing is disabled by the administrator" : "Ylläpitäjä on estänyt julkisen linkin jakamisen", "Shared with you" : "Jaettu kanssasi", "Shared with others" : "Jaettu muiden kanssa", "Shared by link" : "Jaettu linkin kautta", diff --git a/apps/files_sharing/l10n/fr.js b/apps/files_sharing/l10n/fr.js index 72275072598..ccd1b4517d3 100644 --- a/apps/files_sharing/l10n/fr.js +++ b/apps/files_sharing/l10n/fr.js @@ -8,6 +8,16 @@ OC.L10N.register( "Could not authenticate to remote share, password might be wrong" : "Impossible de s'authentifier au partage distant : le mot de passe en probablement incorrect", "Storage not valid" : "Support de stockage non valide", "Couldn't add remote share" : "Impossible d'ajouter le partage distant", + "Share API is disabled" : "l'API de partage est désactivée", + "Wrong share ID, share doesn't exist" : "Mauvais ID de partage, le partage n'existe pas", + "Could not delete share" : "Impossible de supprimer le partage", + "Please specify a file or folder path" : "Veuillez spécifier un fichier ou dossier", + "Wrong path, file/folder doesn't exist" : "Mauvais chemin, Le fichier/dossier n'existe pas", + "Please specify a valid user" : "Veuillez entrer un utilisateur valide", + "Group sharing is disabled by the administrator" : "Le partage de groupe a été désactivé par l'administrateur", + "Please specify a valid group" : "Veuillez entrer un groupe valide", + "Public link sharing is disabled by the administrator" : "Le partage de lien public a été désactivé par l'administrateur", + "Invalid date, date format must be YYYY-MM-DD" : "Date invalide, le format doit être YYYY-MM-DD", "Shared with you" : "Partagés avec vous", "Shared with others" : "Partagés avec d'autres", "Shared by link" : "Partagés par lien", diff --git a/apps/files_sharing/l10n/fr.json b/apps/files_sharing/l10n/fr.json index 03c39ca719f..33c05fba70a 100644 --- a/apps/files_sharing/l10n/fr.json +++ b/apps/files_sharing/l10n/fr.json @@ -6,6 +6,16 @@ "Could not authenticate to remote share, password might be wrong" : "Impossible de s'authentifier au partage distant : le mot de passe en probablement incorrect", "Storage not valid" : "Support de stockage non valide", "Couldn't add remote share" : "Impossible d'ajouter le partage distant", + "Share API is disabled" : "l'API de partage est désactivée", + "Wrong share ID, share doesn't exist" : "Mauvais ID de partage, le partage n'existe pas", + "Could not delete share" : "Impossible de supprimer le partage", + "Please specify a file or folder path" : "Veuillez spécifier un fichier ou dossier", + "Wrong path, file/folder doesn't exist" : "Mauvais chemin, Le fichier/dossier n'existe pas", + "Please specify a valid user" : "Veuillez entrer un utilisateur valide", + "Group sharing is disabled by the administrator" : "Le partage de groupe a été désactivé par l'administrateur", + "Please specify a valid group" : "Veuillez entrer un groupe valide", + "Public link sharing is disabled by the administrator" : "Le partage de lien public a été désactivé par l'administrateur", + "Invalid date, date format must be YYYY-MM-DD" : "Date invalide, le format doit être YYYY-MM-DD", "Shared with you" : "Partagés avec vous", "Shared with others" : "Partagés avec d'autres", "Shared by link" : "Partagés par lien", diff --git a/apps/files_sharing/l10n/it.js b/apps/files_sharing/l10n/it.js index b1f398d5ab5..a946482b164 100644 --- a/apps/files_sharing/l10n/it.js +++ b/apps/files_sharing/l10n/it.js @@ -24,6 +24,7 @@ OC.L10N.register( "Unknown share type" : "Tipo di condivisione sconosciuto", "Not a directory" : "Non è una cartella", "Can't change permissions for public share links" : "Impossibile cambiare i permessi per i collegamenti di condivisione pubblici", + "Wrong or no update parameter given" : "Parametro fornito non valido o non di aggiornamento", "Cannot increase permissions" : "Impossibile aumentare i permessi", "Shared with you" : "Condivisi con te", "Shared with others" : "Condivisi con altri", diff --git a/apps/files_sharing/l10n/it.json b/apps/files_sharing/l10n/it.json index e6802c74504..048414b8346 100644 --- a/apps/files_sharing/l10n/it.json +++ b/apps/files_sharing/l10n/it.json @@ -22,6 +22,7 @@ "Unknown share type" : "Tipo di condivisione sconosciuto", "Not a directory" : "Non è una cartella", "Can't change permissions for public share links" : "Impossibile cambiare i permessi per i collegamenti di condivisione pubblici", + "Wrong or no update parameter given" : "Parametro fornito non valido o non di aggiornamento", "Cannot increase permissions" : "Impossibile aumentare i permessi", "Shared with you" : "Condivisi con te", "Shared with others" : "Condivisi con altri", diff --git a/apps/systemtags/l10n/es.js b/apps/systemtags/l10n/es.js index 56941f3f5da..e0e6b73b596 100644 --- a/apps/systemtags/l10n/es.js +++ b/apps/systemtags/l10n/es.js @@ -2,6 +2,7 @@ OC.L10N.register( "systemtags", { "<strong>System tags</strong> for a file have been modified" : "Se han modificado las <strong>etiquetas de sistema</strong> de un archivo", + "You assigned system tag %3$s" : "Se asignó la etiqueta de sistema %3$s", "%1$s assigned system tag %3$s" : "%1$s asignó la etiqueta de sistema %3$s", "%1$s unassigned system tag %3$s" : "%1$s eliminó la asignación de etiqueta de sistema %3$s", "%1$s created system tag %2$s" : "%1$s creó la etiqueta de sistema %2$s", diff --git a/apps/systemtags/l10n/es.json b/apps/systemtags/l10n/es.json index e5ad1d78fef..2e475e3e626 100644 --- a/apps/systemtags/l10n/es.json +++ b/apps/systemtags/l10n/es.json @@ -1,5 +1,6 @@ { "translations": { "<strong>System tags</strong> for a file have been modified" : "Se han modificado las <strong>etiquetas de sistema</strong> de un archivo", + "You assigned system tag %3$s" : "Se asignó la etiqueta de sistema %3$s", "%1$s assigned system tag %3$s" : "%1$s asignó la etiqueta de sistema %3$s", "%1$s unassigned system tag %3$s" : "%1$s eliminó la asignación de etiqueta de sistema %3$s", "%1$s created system tag %2$s" : "%1$s creó la etiqueta de sistema %2$s", diff --git a/apps/user_ldap/l10n/es.js b/apps/user_ldap/l10n/es.js index 8ba9fbefee5..9503830a911 100644 --- a/apps/user_ldap/l10n/es.js +++ b/apps/user_ldap/l10n/es.js @@ -13,6 +13,7 @@ OC.L10N.register( " Could not set configuration %s" : "No se pudo establecer la configuración %s", "Action does not exist" : "La acción no existe.", "The Base DN appears to be wrong" : "La Base DN parece estar mal", + "Testing configuration…" : "Probando configuración", "Configuration incorrect" : "Configuración Incorrecta", "Configuration incomplete" : "Configuración incompleta", "Configuration OK" : "Configuración correcta", diff --git a/apps/user_ldap/l10n/es.json b/apps/user_ldap/l10n/es.json index 8cf67f71bb0..528afb920da 100644 --- a/apps/user_ldap/l10n/es.json +++ b/apps/user_ldap/l10n/es.json @@ -11,6 +11,7 @@ " Could not set configuration %s" : "No se pudo establecer la configuración %s", "Action does not exist" : "La acción no existe.", "The Base DN appears to be wrong" : "La Base DN parece estar mal", + "Testing configuration…" : "Probando configuración", "Configuration incorrect" : "Configuración Incorrecta", "Configuration incomplete" : "Configuración incompleta", "Configuration OK" : "Configuración correcta", diff --git a/core/Command/Maintenance/Repair.php b/core/Command/Maintenance/Repair.php index 2da76143390..286df5fd7bb 100644 --- a/core/Command/Maintenance/Repair.php +++ b/core/Command/Maintenance/Repair.php @@ -25,24 +25,36 @@ namespace OC\Core\Command\Maintenance; use Exception; +use OCP\IConfig; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\GenericEvent; class Repair extends Command { /** @var \OC\Repair $repair */ protected $repair; - /** @var \OCP\IConfig */ + /** @var IConfig */ protected $config; + /** @var EventDispatcherInterface */ + private $dispatcher; + /** @var ProgressBar */ + private $progress; + /** @var OutputInterface */ + private $output; /** * @param \OC\Repair $repair - * @param \OCP\IConfig $config + * @param IConfig $config */ - public function __construct(\OC\Repair $repair, \OCP\IConfig $config) { + public function __construct(\OC\Repair $repair, IConfig $config, EventDispatcherInterface $dispatcher) { $this->repair = $repair; $this->config = $config; + $this->dispatcher = $dispatcher; parent::__construct(); } @@ -87,21 +99,48 @@ class Repair extends Command { $maintenanceMode = $this->config->getSystemValue('maintenance', false); $this->config->setSystemValue('maintenance', true); - $this->repair->listen('\OC\Repair', 'step', function ($description) use ($output) { - $output->writeln(' - ' . $description); - }); - $this->repair->listen('\OC\Repair', 'info', function ($description) use ($output) { - $output->writeln(' - ' . $description); - }); - $this->repair->listen('\OC\Repair', 'warning', function ($description) use ($output) { - $output->writeln(' - WARNING: ' . $description); - }); - $this->repair->listen('\OC\Repair', 'error', function ($description) use ($output) { - $output->writeln(' - ERROR: ' . $description); - }); + $this->progress = new ProgressBar($output); + $this->output = $output; + $this->dispatcher->addListener('\OC\Repair::startProgress', [$this, 'handleRepairFeedBack']); + $this->dispatcher->addListener('\OC\Repair::advance', [$this, 'handleRepairFeedBack']); + $this->dispatcher->addListener('\OC\Repair::finishProgress', [$this, 'handleRepairFeedBack']); + $this->dispatcher->addListener('\OC\Repair::step', [$this, 'handleRepairFeedBack']); + $this->dispatcher->addListener('\OC\Repair::info', [$this, 'handleRepairFeedBack']); + $this->dispatcher->addListener('\OC\Repair::warning', [$this, 'handleRepairFeedBack']); + $this->dispatcher->addListener('\OC\Repair::error', [$this, 'handleRepairFeedBack']); $this->repair->run(); $this->config->setSystemValue('maintenance', $maintenanceMode); } + + public function handleRepairFeedBack($event) { + if (!$event instanceof GenericEvent) { + return; + } + switch ($event->getSubject()) { + case '\OC\Repair::startProgress': + $this->progress->start($event->getArgument(0)); + break; + case '\OC\Repair::advance': + $this->progress->advance($event->getArgument(0)); + break; + case '\OC\Repair::finishProgress': + $this->progress->finish(); + $this->output->writeln(''); + break; + case '\OC\Repair::step': + $this->output->writeln(' - ' . $event->getArgument(0)); + break; + case '\OC\Repair::info': + $this->output->writeln(' - ' . $event->getArgument(0)); + break; + case '\OC\Repair::warning': + $this->output->writeln(' - WARNING: ' . $event->getArgument(0)); + break; + case '\OC\Repair::error': + $this->output->writeln(' - ERROR: ' . $event->getArgument(0)); + break; + } + } } diff --git a/core/Command/Upgrade.php b/core/Command/Upgrade.php index 1001962c6af..d61acf0451a 100644 --- a/core/Command/Upgrade.php +++ b/core/Command/Upgrade.php @@ -162,8 +162,59 @@ class Upgrade extends Command { } } }; + $repairListener = function($event) use ($progress, $output) { + if (!$event instanceof GenericEvent) { + return; + } + switch ($event->getSubject()) { + case '\OC\Repair::startProgress': + $progress->setMessage('Starting ...'); + $output->writeln($event->getArgument(1)); + $output->writeln(''); + $progress->start($event->getArgument(0)); + break; + case '\OC\Repair::advance': + $desc = $event->getArgument(1); + if (!empty($desc)) { + $progress->setMessage($desc); + } + $progress->advance($event->getArgument(0)); + + break; + case '\OC\Repair::finishProgress': + $progress->setMessage('Done'); + $progress->finish(); + $output->writeln(''); + break; + case '\OC\Repair::step': + if(OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) { + $output->writeln('<info>Repair step: ' . $event->getArgument(0) . '</info>'); + } + break; + case '\OC\Repair::info': + if(OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) { + $output->writeln('<info>Repair info: ' . $event->getArgument(0) . '</info>'); + } + break; + case '\OC\Repair::warning': + $output->writeln('<error>Repair warning: ' . $event->getArgument(0) . '</error>'); + break; + case '\OC\Repair::error': + $output->writeln('<error>Repair error: ' . $event->getArgument(0) . '</error>'); + break; + } + }; + $dispatcher->addListener('\OC\DB\Migrator::executeSql', $listener); $dispatcher->addListener('\OC\DB\Migrator::checkTable', $listener); + $dispatcher->addListener('\OC\Repair::startProgress', $repairListener); + $dispatcher->addListener('\OC\Repair::advance', $repairListener); + $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener); + $dispatcher->addListener('\OC\Repair::step', $repairListener); + $dispatcher->addListener('\OC\Repair::info', $repairListener); + $dispatcher->addListener('\OC\Repair::warning', $repairListener); + $dispatcher->addListener('\OC\Repair::error', $repairListener); + $updater->listen('\OC\Updater', 'maintenanceEnabled', function () use($output) { $output->writeln('<info>Turned on maintenance mode</info>'); @@ -205,12 +256,6 @@ class Upgrade extends Command { $updater->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($output) { $output->writeln('<info>Update 3rd-party app: ' . $app . '</info>'); }); - $updater->listen('\OC\Updater', 'repairWarning', function ($app) use($output) { - $output->writeln('<error>Repair warning: ' . $app . '</error>'); - }); - $updater->listen('\OC\Updater', 'repairError', function ($app) use($output) { - $output->writeln('<error>Repair error: ' . $app . '</error>'); - }); $updater->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($output) { $output->writeln('<info>Checking updates of apps</info>'); }); @@ -242,15 +287,6 @@ class Upgrade extends Command { $output->writeln("<info>Finished code integrity check</info>"); }); - if(OutputInterface::VERBOSITY_NORMAL < $output->getVerbosity()) { - $updater->listen('\OC\Updater', 'repairInfo', function ($message) use($output) { - $output->writeln('<info>Repair info: ' . $message . '</info>'); - }); - $updater->listen('\OC\Updater', 'repairStep', function ($message) use($output) { - $output->writeln('<info>Repair step: ' . $message . '</info>'); - }); - } - $success = $updater->upgrade(); $this->postUpgradeCheck($input, $output); diff --git a/core/ajax/update.php b/core/ajax/update.php index 0e6c1176ac1..f673467f64a 100644 --- a/core/ajax/update.php +++ b/core/ajax/update.php @@ -39,6 +39,56 @@ $eventSource = \OC::$server->createEventSource(); // message $eventSource->send('success', (string)$l->t('Preparing update')); +class FeedBackHandler { + /** @var integer */ + private $progressStateMax = 100; + /** @var integer */ + private $progressStateStep = 0; + /** @var string */ + private $currentStep; + + public function __construct(\OCP\IEventSource $eventSource, \OCP\IL10N $l10n) { + $this->eventSource = $eventSource; + $this->l10n = $l10n; + } + + public function handleRepairFeedback($event) { + if (!$event instanceof GenericEvent) { + return; + } + + switch ($event->getSubject()) { + case '\OC\Repair::startProgress': + $this->progressStateMax = $event->getArgument(0); + $this->progressStateStep = 0; + $this->currentStep = $event->getArgument(1); + break; + case '\OC\Repair::advance': + $this->progressStateStep += $event->getArgument(0); + $desc = $event->getArgument(1); + if (empty($desc)) { + $desc = $this->currentStep; + } + $this->eventSource->send('success', (string)$this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $desc])); + break; + case '\OC\Repair::finishProgress': + $this->progressStateMax = $this->progressStateStep; + $this->eventSource->send('success', (string)$this->l10n->t('[%d / %d]: %s', [$this->progressStateStep, $this->progressStateMax, $this->currentStep])); + break; + case '\OC\Repair::step': + break; + case '\OC\Repair::info': + break; + case '\OC\Repair::warning': + $this->eventSource->send('notice', (string)$this->l10n->t('Repair warning: ') . $event->getArgument(0)); + break; + case '\OC\Repair::error': + $this->eventSource->send('notice', (string)$this->l10n->t('Repair error: ') . $event->getArgument(0)); + break; + } + } +} + if (OC::checkUpgrade(false)) { $config = \OC::$server->getSystemConfig(); @@ -73,6 +123,14 @@ if (OC::checkUpgrade(false)) { $eventSource->send('success', (string)$l->t('[%d / %d]: Checking table %s', [$event[0], $event[1], $event->getSubject()])); } }); + $feedBack = new FeedBackHandler($eventSource, $l); + $dispatcher->addListener('\OC\Repair::startProgress', [$feedBack, 'handleRepairFeedback']); + $dispatcher->addListener('\OC\Repair::advance', [$feedBack, 'handleRepairFeedback']); + $dispatcher->addListener('\OC\Repair::finishProgress', [$feedBack, 'handleRepairFeedback']); + $dispatcher->addListener('\OC\Repair::step', [$feedBack, 'handleRepairFeedback']); + $dispatcher->addListener('\OC\Repair::info', [$feedBack, 'handleRepairFeedback']); + $dispatcher->addListener('\OC\Repair::warning', [$feedBack, 'handleRepairFeedback']); + $dispatcher->addListener('\OC\Repair::error', [$feedBack, 'handleRepairFeedback']); $updater->listen('\OC\Updater', 'maintenanceEnabled', function () use ($eventSource, $l) { $eventSource->send('success', (string)$l->t('Turned on maintenance mode')); @@ -107,12 +165,6 @@ if (OC::checkUpgrade(false)) { $updater->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($eventSource, $l) { $eventSource->send('success', (string)$l->t('Updated "%s" to %s', array($app, $version))); }); - $updater->listen('\OC\Updater', 'repairWarning', function ($description) use ($eventSource, $l) { - $eventSource->send('notice', (string)$l->t('Repair warning: ') . $description); - }); - $updater->listen('\OC\Updater', 'repairError', function ($description) use ($eventSource, $l) { - $eventSource->send('notice', (string)$l->t('Repair error: ') . $description); - }); $updater->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use (&$incompatibleApps) { $incompatibleApps[]= $app; }); diff --git a/core/register_command.php b/core/register_command.php index 0b1a019f993..798497d97d2 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -112,7 +112,9 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) { $application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateDB(\OC::$server->getMimeTypeDetector(), \OC::$server->getMimeTypeLoader())); $application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateJS(\OC::$server->getMimeTypeDetector())); $application->add(new OC\Core\Command\Maintenance\Mode(\OC::$server->getConfig())); - $application->add(new OC\Core\Command\Maintenance\Repair(new \OC\Repair(\OC\Repair::getRepairSteps()), \OC::$server->getConfig())); + $application->add(new OC\Core\Command\Maintenance\Repair( + new \OC\Repair(\OC\Repair::getRepairSteps(), \OC::$server->getEventDispatcher()), \OC::$server->getConfig(), + \OC::$server->getEventDispatcher())); $application->add(new OC\Core\Command\Maintenance\SingleUser(\OC::$server->getConfig())); $application->add(new OC\Core\Command\Upgrade(\OC::$server->getConfig(), \OC::$server->getLogger())); diff --git a/lib/private/activitymanager.php b/lib/private/ActivityManager.php index e522dca9e3b..e522dca9e3b 100644 --- a/lib/private/activitymanager.php +++ b/lib/private/ActivityManager.php diff --git a/lib/private/allconfig.php b/lib/private/AllConfig.php index b4888fde022..b4888fde022 100644 --- a/lib/private/allconfig.php +++ b/lib/private/AllConfig.php diff --git a/lib/private/App/DependencyAnalyzer.php b/lib/private/App/DependencyAnalyzer.php index 6519e15bd8b..1e3a81c6351 100644 --- a/lib/private/App/DependencyAnalyzer.php +++ b/lib/private/App/DependencyAnalyzer.php @@ -145,6 +145,12 @@ class DependencyAnalyzer { $missing[] = (string)$this->l->t('PHP with a version lower than %s is required.', $maxVersion); } } + if (isset($dependencies['php']['@attributes']['min-int-size'])) { + $intSize = $dependencies['php']['@attributes']['min-int-size']; + if ($intSize > $this->platform->getIntSize()*8) { + $missing[] = (string)$this->l->t('%sbit or higher PHP required.', $intSize); + } + } return $missing; } diff --git a/lib/private/App/InfoParser.php b/lib/private/App/InfoParser.php index e763364e148..b7540c04248 100644 --- a/lib/private/App/InfoParser.php +++ b/lib/private/App/InfoParser.php @@ -80,6 +80,9 @@ class InfoParser { if (!array_key_exists('post-migration', $array['repair-steps'])) { $array['repair-steps']['post-migration'] = []; } + if (!array_key_exists('live-migration', $array['repair-steps'])) { + $array['repair-steps']['live-migration'] = []; + } if (array_key_exists('documentation', $array) && is_array($array['documentation'])) { foreach ($array['documentation'] as $key => $url) { @@ -110,6 +113,9 @@ class InfoParser { if (isset($array['repair-steps']['post-migration']['step']) && is_array($array['repair-steps']['post-migration']['step'])) { $array['repair-steps']['post-migration'] = $array['repair-steps']['post-migration']['step']; } + if (isset($array['repair-steps']['live-migration']['step']) && is_array($array['repair-steps']['live-migration']['step'])) { + $array['repair-steps']['live-migration'] = $array['repair-steps']['live-migration']['step']; + } return $array; } diff --git a/lib/private/App/Platform.php b/lib/private/App/Platform.php index 1d4c3767121..b1cb7c5aeb0 100644 --- a/lib/private/App/Platform.php +++ b/lib/private/App/Platform.php @@ -49,6 +49,13 @@ class Platform { } /** + * @return int + */ + public function getIntSize() { + return PHP_INT_SIZE; + } + + /** * @return string */ public function getOcVersion() { diff --git a/lib/private/appconfig.php b/lib/private/AppConfig.php index 14c48299a8a..14c48299a8a 100644 --- a/lib/private/appconfig.php +++ b/lib/private/AppConfig.php diff --git a/lib/private/AppFramework/Http/Request.php b/lib/private/AppFramework/Http/Request.php index 7cd8cedcfdd..fb6f1415fe9 100644 --- a/lib/private/AppFramework/Http/Request.php +++ b/lib/private/AppFramework/Http/Request.php @@ -271,6 +271,9 @@ class Request implements \ArrayAccess, \Countable, IRequest { * @return bool */ public function __isset($name) { + if (in_array($name, $this->allowedKeys, true)) { + return true; + } return isset($this->items['parameters'][$name]); } diff --git a/lib/private/apphelper.php b/lib/private/AppHelper.php index c19ed2f5b67..c19ed2f5b67 100644 --- a/lib/private/apphelper.php +++ b/lib/private/AppHelper.php diff --git a/lib/private/avatar.php b/lib/private/Avatar.php index 3f8038360a4..3f8038360a4 100644 --- a/lib/private/avatar.php +++ b/lib/private/Avatar.php diff --git a/lib/private/avatarmanager.php b/lib/private/AvatarManager.php index 62f4faf436c..62f4faf436c 100644 --- a/lib/private/avatarmanager.php +++ b/lib/private/AvatarManager.php diff --git a/lib/private/capabilitiesmanager.php b/lib/private/CapabilitiesManager.php index 8b89692faa9..8b89692faa9 100644 --- a/lib/private/capabilitiesmanager.php +++ b/lib/private/CapabilitiesManager.php diff --git a/lib/private/config.php b/lib/private/Config.php index 9bb5c299463..9bb5c299463 100644 --- a/lib/private/config.php +++ b/lib/private/Config.php diff --git a/lib/private/contactsmanager.php b/lib/private/ContactsManager.php index a2640d36945..a2640d36945 100644 --- a/lib/private/contactsmanager.php +++ b/lib/private/ContactsManager.php diff --git a/lib/private/databaseexception.php b/lib/private/DatabaseException.php index 4d50fe82b0f..4d50fe82b0f 100644 --- a/lib/private/databaseexception.php +++ b/lib/private/DatabaseException.php diff --git a/lib/private/databasesetupexception.php b/lib/private/DatabaseSetupException.php index 30bd00de2d6..30bd00de2d6 100644 --- a/lib/private/databasesetupexception.php +++ b/lib/private/DatabaseSetupException.php diff --git a/lib/private/datetimeformatter.php b/lib/private/DateTimeFormatter.php index 5639ab1cace..5639ab1cace 100644 --- a/lib/private/datetimeformatter.php +++ b/lib/private/DateTimeFormatter.php diff --git a/lib/private/datetimezone.php b/lib/private/DateTimeZone.php index 5359cd6b391..5359cd6b391 100644 --- a/lib/private/datetimezone.php +++ b/lib/private/DateTimeZone.php diff --git a/lib/private/Files/Filesystem.php b/lib/private/Files/Filesystem.php index d33f9476f22..61319a8cbaa 100644 --- a/lib/private/Files/Filesystem.php +++ b/lib/private/Files/Filesystem.php @@ -58,6 +58,7 @@ namespace OC\Files; +use OC\Cache\CappedMemoryCache; use OC\Files\Config\MountProviderCollection; use OC\Files\Mount\MountPoint; use OC\Files\Storage\StorageFactory; @@ -81,7 +82,7 @@ class Filesystem { static private $usersSetup = array(); - static private $normalizedPathCache = array(); + static private $normalizedPathCache = null; static private $listeningForProviders = false; @@ -812,6 +813,10 @@ class Filesystem { * @return string */ public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false) { + if (is_null(self::$normalizedPathCache)) { + self::$normalizedPathCache = new CappedMemoryCache(); + } + /** * FIXME: This is a workaround for existing classes and files which call * this function with another type than a valid string. This diff --git a/lib/private/Files/Storage/Wrapper/Availability.php b/lib/private/Files/Storage/Wrapper/Availability.php index 0ed31ba854a..8d6fc4b3369 100644 --- a/lib/private/Files/Storage/Wrapper/Availability.php +++ b/lib/private/Files/Storage/Wrapper/Availability.php @@ -40,9 +40,13 @@ class Availability extends Wrapper { } /** + * Only called if availability === false + * * @return bool */ private function updateAvailability() { + // reset availability to false so that multiple requests don't recheck concurrently + $this->setAvailability(false); try { $result = $this->test(); } catch (\Exception $e) { diff --git a/lib/private/forbiddenexception.php b/lib/private/ForbiddenException.php index 48be35ba316..48be35ba316 100644 --- a/lib/private/forbiddenexception.php +++ b/lib/private/ForbiddenException.php diff --git a/lib/private/httphelper.php b/lib/private/HTTPHelper.php index f33d4a51745..f33d4a51745 100644 --- a/lib/private/httphelper.php +++ b/lib/private/HTTPHelper.php diff --git a/lib/private/hintexception.php b/lib/private/HintException.php index aeddea481cc..aeddea481cc 100644 --- a/lib/private/hintexception.php +++ b/lib/private/HintException.php diff --git a/lib/private/http/client/client.php b/lib/private/Http/Client/Client.php index bd9e82ddae7..bd9e82ddae7 100644 --- a/lib/private/http/client/client.php +++ b/lib/private/Http/Client/Client.php diff --git a/lib/private/http/client/clientservice.php b/lib/private/Http/Client/ClientService.php index 7e280dbf3ca..7e280dbf3ca 100644 --- a/lib/private/http/client/clientservice.php +++ b/lib/private/Http/Client/ClientService.php diff --git a/lib/private/http/client/response.php b/lib/private/Http/Client/Response.php index 7a879eab111..7a879eab111 100644 --- a/lib/private/http/client/response.php +++ b/lib/private/Http/Client/Response.php diff --git a/lib/private/largefilehelper.php b/lib/private/LargeFileHelper.php index f5252ee01e7..f5252ee01e7 100644 --- a/lib/private/largefilehelper.php +++ b/lib/private/LargeFileHelper.php diff --git a/lib/private/Lock/AbstractLockingProvider.php b/lib/private/Lock/AbstractLockingProvider.php index f96358778c1..1886fbea082 100644 --- a/lib/private/Lock/AbstractLockingProvider.php +++ b/lib/private/Lock/AbstractLockingProvider.php @@ -116,4 +116,8 @@ abstract class AbstractLockingProvider implements ILockingProvider { $this->releaseLock($path, self::LOCK_EXCLUSIVE); } } + + protected function getOwnSharedLockCount($path) { + return isset($this->acquiredLocks['shared'][$path]) ? $this->acquiredLocks['shared'][$path] : 0; + } } diff --git a/lib/private/Lock/MemcacheLockingProvider.php b/lib/private/Lock/MemcacheLockingProvider.php index 536b29e2c28..56e581b2192 100644 --- a/lib/private/Lock/MemcacheLockingProvider.php +++ b/lib/private/Lock/MemcacheLockingProvider.php @@ -88,9 +88,14 @@ class MemcacheLockingProvider extends AbstractLockingProvider { */ public function releaseLock($path, $type) { if ($type === self::LOCK_SHARED) { - if (isset($this->acquiredLocks['shared'][$path]) and $this->acquiredLocks['shared'][$path] > 0) { + if ($this->getOwnSharedLockCount($path) === 1) { + $removed = $this->memcache->cad($path, 1); // if we're the only one having a shared lock we can remove it in one go + if (!$removed) { //someone else also has a shared lock, decrease only + $this->memcache->dec($path); + } + } else { + // if we own more than one lock ourselves just decrease $this->memcache->dec($path); - $this->memcache->cad($path, 0); } } else if ($type === self::LOCK_EXCLUSIVE) { $this->memcache->cad($path, 'exclusive'); diff --git a/lib/private/log.php b/lib/private/Log.php index bbdad9cf166..bbdad9cf166 100644 --- a/lib/private/log.php +++ b/lib/private/Log.php diff --git a/lib/private/Migration/BackgroundRepair.php b/lib/private/Migration/BackgroundRepair.php new file mode 100644 index 00000000000..d85c8550d5d --- /dev/null +++ b/lib/private/Migration/BackgroundRepair.php @@ -0,0 +1,116 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ +namespace OC\Migration; + +use OC\BackgroundJob\JobList; +use OC\BackgroundJob\TimedJob; +use OC\NeedsUpdateException; +use OC\Repair; +use OC_App; +use OCP\BackgroundJob\IJobList; +use OCP\ILogger; +use Symfony\Component\EventDispatcher\EventDispatcher; + +/** + * Class BackgroundRepair + * + * @package OC\Migration + */ +class BackgroundRepair extends TimedJob { + + /** @var IJobList */ + private $jobList; + + /** @var ILogger */ + private $logger; + + /** @var EventDispatcher */ + private $dispatcher; + + public function setDispatcher(EventDispatcher $dispatcher) { + $this->dispatcher = $dispatcher; + } + /** + * run the job, then remove it from the job list + * + * @param JobList $jobList + * @param ILogger $logger + */ + public function execute($jobList, ILogger $logger = null) { + // add an interval of 15 mins + $this->setInterval(15*60); + + $this->jobList = $jobList; + $this->logger = $logger; + parent::execute($jobList, $logger); + } + + /** + * @param array $argument + * @throws \Exception + * @throws \OC\NeedsUpdateException + */ + protected function run($argument) { + if (!isset($argument['app']) || !isset($argument['step'])) { + // remove the job - we can never execute it + $this->jobList->remove($this, $this->argument); + return; + } + $app = $argument['app']; + + try { + $this->loadApp($app); + } catch (NeedsUpdateException $ex) { + // as long as the app is not yet done with it's offline migration + // we better not start with the live migration + return; + } + + $step = $argument['step']; + $repair = new Repair([], $this->dispatcher); + try { + $repair->addStep($step); + } catch (\Exception $ex) { + $this->logger->logException($ex,[ + 'app' => 'migration' + ]); + + // remove the job - we can never execute it + $this->jobList->remove($this, $this->argument); + return; + } + + // execute the repair step + $repair->run(); + + // remove the job once executed successfully + $this->jobList->remove($this, $this->argument); + } + + /** + * @codeCoverageIgnore + * @param $app + * @throws NeedsUpdateException + */ + protected function loadApp($app) { + OC_App::loadApp($app); + } +} diff --git a/lib/private/naturalsort.php b/lib/private/NaturalSort.php index f44e8032d36..f44e8032d36 100644 --- a/lib/private/naturalsort.php +++ b/lib/private/NaturalSort.php diff --git a/lib/private/navigationmanager.php b/lib/private/NavigationManager.php index 6dbb9c925e0..6dbb9c925e0 100644 --- a/lib/private/navigationmanager.php +++ b/lib/private/NavigationManager.php diff --git a/lib/private/needsupdateexception.php b/lib/private/NeedsUpdateException.php index 90c642780d8..90c642780d8 100644 --- a/lib/private/needsupdateexception.php +++ b/lib/private/NeedsUpdateException.php diff --git a/lib/private/notsquareexception.php b/lib/private/NotSquareException.php index e3494463850..e3494463850 100644 --- a/lib/private/notsquareexception.php +++ b/lib/private/NotSquareException.php diff --git a/lib/private/ocsclient.php b/lib/private/OCSClient.php index a783a1f8425..a783a1f8425 100644 --- a/lib/private/ocsclient.php +++ b/lib/private/OCSClient.php diff --git a/lib/private/preview.php b/lib/private/Preview.php index 4fca56dd984..4fca56dd984 100644 --- a/lib/private/preview.php +++ b/lib/private/Preview.php diff --git a/lib/private/previewmanager.php b/lib/private/PreviewManager.php index f3c7a4de0d0..f3c7a4de0d0 100644 --- a/lib/private/previewmanager.php +++ b/lib/private/PreviewManager.php diff --git a/lib/private/repair.php b/lib/private/Repair.php index 586e4e42b13..590b0bee721 100644 --- a/lib/private/repair.php +++ b/lib/private/Repair.php @@ -28,7 +28,6 @@ namespace OC; -use OC\Hooks\BasicEmitter; use OC\Hooks\Emitter; use OC\Repair\AssetCache; use OC\Repair\CleanTags; @@ -51,11 +50,13 @@ use OCP\Migration\IRepairStep; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\GenericEvent; -class Repair extends BasicEmitter implements IOutput{ +class Repair implements IOutput{ /* @var IRepairStep[] */ private $repairSteps; /** @var EventDispatcher */ private $dispatcher; + /** @var string */ + private $currentStep; /** * Creates a new repair step runner @@ -79,7 +80,8 @@ class Repair extends BasicEmitter implements IOutput{ } // run each repair step foreach ($this->repairSteps as $step) { - $this->emit('\OC\Repair', 'step', array($step->getName())); + $this->currentStep = $step->getName(); + $this->emit('\OC\Repair', 'step', [$this->currentStep]); if ($step instanceof Emitter) { $step->listen('\OC\Repair', 'warning', function ($description) use ($self) { @@ -178,10 +180,11 @@ class Repair extends BasicEmitter implements IOutput{ } /** - * {@inheritDoc} + * @param string $scope + * @param string $method + * @param array $arguments */ public function emit($scope, $method, array $arguments = []) { - parent::emit($scope, $method, $arguments); if (!is_null($this->dispatcher)) { $this->dispatcher->dispatch("$scope::$method", new GenericEvent("$scope::$method", $arguments)); @@ -206,15 +209,16 @@ class Repair extends BasicEmitter implements IOutput{ */ public function startProgress($max = 0) { // for now just emit as we did in the past - $this->emit('\OC\Repair', 'startProgress', [$max]); + $this->emit('\OC\Repair', 'startProgress', [$max, $this->currentStep]); } /** * @param int $step + * @param string $description */ - public function advance($step = 1) { + public function advance($step = 1, $description = '') { // for now just emit as we did in the past - $this->emit('\OC\Repair', 'advance', [$step]); + $this->emit('\OC\Repair', 'advance', [$step, $description]); } /** diff --git a/lib/private/Repair/DropOldTables.php b/lib/private/Repair/DropOldTables.php index 15d5b9a3577..b9963b50775 100644 --- a/lib/private/Repair/DropOldTables.php +++ b/lib/private/Repair/DropOldTables.php @@ -55,12 +55,15 @@ class DropOldTables implements IRepairStep { * @throws \Exception in case of failure */ public function run(IOutput $output) { + $tables = $this->oldDatabaseTables(); + $output->startProgress(count($tables)); foreach ($this->oldDatabaseTables() as $tableName) { if ($this->connection->tableExists($tableName)){ - $output->info(sprintf('Table %s has been deleted', $tableName)); $this->connection->dropTable($tableName); } + $output->advance(1, "Drop old database table: $tableName"); } + $output->finishProgress(); } /** diff --git a/lib/private/repairexception.php b/lib/private/RepairException.php index e244f2bb820..e244f2bb820 100644 --- a/lib/private/repairexception.php +++ b/lib/private/RepairException.php diff --git a/lib/private/search.php b/lib/private/Search.php index 7d1e2734195..7d1e2734195 100644 --- a/lib/private/search.php +++ b/lib/private/Search.php diff --git a/lib/private/servercontainer.php b/lib/private/ServerContainer.php index d297c9fd39c..d297c9fd39c 100644 --- a/lib/private/servercontainer.php +++ b/lib/private/ServerContainer.php diff --git a/lib/private/servernotavailableexception.php b/lib/private/ServerNotAvailableException.php index f4b5f4f8cf3..f4b5f4f8cf3 100644 --- a/lib/private/servernotavailableexception.php +++ b/lib/private/ServerNotAvailableException.php diff --git a/lib/private/serviceunavailableexception.php b/lib/private/ServiceUnavailableException.php index fb4920b3607..fb4920b3607 100644 --- a/lib/private/serviceunavailableexception.php +++ b/lib/private/ServiceUnavailableException.php diff --git a/lib/private/setup.php b/lib/private/Setup.php index 196ae8a8bce..196ae8a8bce 100644 --- a/lib/private/setup.php +++ b/lib/private/Setup.php diff --git a/lib/private/streamer.php b/lib/private/Streamer.php index 23c191b68da..23c191b68da 100644 --- a/lib/private/streamer.php +++ b/lib/private/Streamer.php diff --git a/lib/private/subadmin.php b/lib/private/SubAdmin.php index 34dd40c22ff..34dd40c22ff 100644 --- a/lib/private/subadmin.php +++ b/lib/private/SubAdmin.php diff --git a/lib/private/systemconfig.php b/lib/private/SystemConfig.php index 449a2dc50b2..449a2dc50b2 100644 --- a/lib/private/systemconfig.php +++ b/lib/private/SystemConfig.php diff --git a/lib/private/tagmanager.php b/lib/private/TagManager.php index a9e1cdfe076..a9e1cdfe076 100644 --- a/lib/private/tagmanager.php +++ b/lib/private/TagManager.php diff --git a/lib/private/tags.php b/lib/private/Tags.php index cf39a9a9759..cf39a9a9759 100644 --- a/lib/private/tags.php +++ b/lib/private/Tags.php diff --git a/lib/private/tempmanager.php b/lib/private/TempManager.php index dd97a36cd7f..dd97a36cd7f 100644 --- a/lib/private/tempmanager.php +++ b/lib/private/TempManager.php diff --git a/lib/private/templatelayout.php b/lib/private/TemplateLayout.php index 88077b418a7..88077b418a7 100644 --- a/lib/private/templatelayout.php +++ b/lib/private/TemplateLayout.php diff --git a/lib/private/urlgenerator.php b/lib/private/URLGenerator.php index 327c0c32dfe..327c0c32dfe 100644 --- a/lib/private/urlgenerator.php +++ b/lib/private/URLGenerator.php diff --git a/lib/private/updater.php b/lib/private/Updater.php index 66f410b779f..093ebebbbe4 100644 --- a/lib/private/updater.php +++ b/lib/private/Updater.php @@ -132,6 +132,8 @@ class Updater extends BasicEmitter { * @return bool true if the operation succeeded, false otherwise */ public function upgrade() { + $this->emitRepairEvents(); + $logLevel = $this->config->getSystemValue('loglevel', \OCP\Util::WARN); $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); $this->config->setSystemValue('loglevel', \OCP\Util::DEBUG); @@ -196,26 +198,6 @@ class Updater extends BasicEmitter { } /** - * Forward messages emitted by the repair routine - * - * @param Repair $repair repair routine - */ - private function emitRepairMessages(Repair $repair) { - $repair->listen('\OC\Repair', 'warning', function ($description) { - $this->emit('\OC\Updater', 'repairWarning', array($description)); - }); - $repair->listen('\OC\Repair', 'error', function ($description) { - $this->emit('\OC\Updater', 'repairError', array($description)); - }); - $repair->listen('\OC\Repair', 'info', function ($description) { - $this->emit('\OC\Updater', 'repairInfo', array($description)); - }); - $repair->listen('\OC\Repair', 'step', function ($description) { - $this->emit('\OC\Updater', 'repairStep', array($description)); - }); - } - - /** * runs the update actions in maintenance mode, does not upgrade the source files * except the main .htaccess file * @@ -245,8 +227,7 @@ class Updater extends BasicEmitter { file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); // pre-upgrade repairs - $repair = new Repair(Repair::getBeforeUpgradeRepairSteps()); - $this->emitRepairMessages($repair); + $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher()); $repair->run(); // simulate DB upgrade @@ -278,8 +259,7 @@ class Updater extends BasicEmitter { } // post-upgrade repairs - $repair = new Repair(Repair::getRepairSteps()); - $this->emitRepairMessages($repair); + $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher()); $repair->run(); //Invalidate update feed @@ -362,7 +342,6 @@ class Updater extends BasicEmitter { * @throws NeedsUpdateException */ protected function doAppUpgrade() { - $this->emitRepairEvents(); $apps = \OC_App::getEnabledApps(); $priorityTypes = array('authentication', 'filesystem', 'logging'); $pseudoOtherType = 'other'; diff --git a/lib/private/app.php b/lib/private/app.php index 7bcbef32531..246bf97ee91 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -1153,6 +1153,7 @@ class OC_App { OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml'); } self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']); + self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']); unset(self::$appVersion[$appId]); // run upgrade code if (file_exists($appPath . '/appinfo/update.php')) { @@ -1211,6 +1212,19 @@ class OC_App { /** * @param string $appId + * @param string[] $steps + */ + private static function setupLiveMigrations($appId, array $steps) { + $queue = \OC::$server->getJobList(); + foreach ($steps as $step) { + $queue->add('OC\Migration\BackgroundRepair', [ + 'app' => $appId, + 'step' => $step]); + } + } + + /** + * @param string $appId * @return \OC\Files\View|false */ public static function getStorage($appId) { diff --git a/lib/public/migration/ioutput.php b/lib/public/migration/ioutput.php index c52f13b31dc..d3b43028495 100644 --- a/lib/public/migration/ioutput.php +++ b/lib/public/migration/ioutput.php @@ -48,9 +48,10 @@ interface IOutput { /** * @param int $step + * @param string $description * @since 9.1.0 */ - public function advance($step = 1); + public function advance($step = 1, $description = ''); /** * @param int $max diff --git a/tests/data/app/expected-info.json b/tests/data/app/expected-info.json index e05d02f7641..51d0c00ccef 100644 --- a/tests/data/app/expected-info.json +++ b/tests/data/app/expected-info.json @@ -70,6 +70,7 @@ }, "repair-steps": { "pre-migration": [], - "post-migration": [] + "post-migration": [], + "live-migration": [] } } diff --git a/tests/lib/RepairTest.php b/tests/lib/RepairTest.php new file mode 100644 index 00000000000..9ae1318eb32 --- /dev/null +++ b/tests/lib/RepairTest.php @@ -0,0 +1,134 @@ +<?php +/** + * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test; + +use OCP\Migration\IRepairStep; +use Symfony\Component\EventDispatcher\EventDispatcher; + +class TestRepairStep implements IRepairStep { + private $warning; + + public function __construct($warning = false) { + $this->warning = $warning; + } + + public function getName() { + return 'Test Name'; + } + + public function run(\OCP\Migration\IOutput $out) { + if ($this->warning) { + $out->warning('Simulated warning'); + } + else { + $out->info('Simulated info'); + } + } +} + +class RepairTest extends TestCase { + /** @var \OC\Repair */ + private $repair; + + /** @var string[] */ + private $outputArray; + + public function setUp() { + parent::setUp(); + $dispatcher = new EventDispatcher(); + $this->repair = new \OC\Repair([], $dispatcher); + + $dispatcher->addListener('\OC\Repair::warning', function ($event) { + /** @var \Symfony\Component\EventDispatcher\GenericEvent $event */ + $this->outputArray[] = 'warning: ' . $event->getArgument(0); + }); + $dispatcher->addListener('\OC\Repair::info', function ($event) { + /** @var \Symfony\Component\EventDispatcher\GenericEvent $event */ + $this->outputArray[] = 'info: ' . $event->getArgument(0); + }); + $dispatcher->addListener('\OC\Repair::step', function ($event) { + /** @var \Symfony\Component\EventDispatcher\GenericEvent $event */ + $this->outputArray[] = 'step: ' . $event->getArgument(0); + }); + } + + public function testRunRepairStep() { + + $this->repair->addStep(new TestRepairStep(false)); + $this->repair->run(); + + $this->assertEquals( + array( + 'step: Test Name', + 'info: Simulated info', + ), + $this->outputArray + ); + } + + public function testRunRepairStepThatFail() { + + $this->repair->addStep(new TestRepairStep(true)); + $this->repair->run(); + + $this->assertEquals( + array( + 'step: Test Name', + 'warning: Simulated warning', + ), + $this->outputArray + ); + } + + public function testRunRepairStepsWithException() { + $mock = $this->getMock('\Test\TestRepairStep'); + $mock->expects($this->any()) + ->method('run') + ->will($this->throwException(new \Exception())); + $mock->expects($this->any()) + ->method('getName') + ->will($this->returnValue('Exception Test')); + + $this->repair->addStep($mock); + $this->repair->addStep(new TestRepairStep(false)); + + $thrown = false; + try { + $this->repair->run(); + } + catch (\Exception $e) { + $thrown = true; + } + + $this->assertTrue($thrown); + // jump out after exception + $this->assertEquals( + array( + 'step: Exception Test', + ), + $this->outputArray + ); + } + + public function testRunRepairStepsContinueAfterWarning() { + $this->repair->addStep(new TestRepairStep(true)); + $this->repair->addStep(new TestRepairStep(false)); + $this->repair->run(); + + $this->assertEquals( + array( + 'step: Test Name', + 'warning: Simulated warning', + 'step: Test Name', + 'info: Simulated info', + ), + $this->outputArray + ); + } +} diff --git a/tests/lib/app/dependencyanalyzer.php b/tests/lib/app/dependencyanalyzer.php index fecba518856..eee0bc29083 100644 --- a/tests/lib/app/dependencyanalyzer.php +++ b/tests/lib/app/dependencyanalyzer.php @@ -33,6 +33,9 @@ class DependencyAnalyzer extends TestCase { ->method('getPhpVersion') ->will( $this->returnValue('5.4.3')); $this->platformMock->expects($this->any()) + ->method('getIntSize') + ->will( $this->returnValue('4')); + $this->platformMock->expects($this->any()) ->method('getDatabase') ->will( $this->returnValue('mysql')); $this->platformMock->expects($this->any()) @@ -73,8 +76,9 @@ class DependencyAnalyzer extends TestCase { * @param string $expectedMissing * @param string $minVersion * @param string $maxVersion + * @param string $intSize */ - public function testPhpVersion($expectedMissing, $minVersion, $maxVersion) { + public function testPhpVersion($expectedMissing, $minVersion, $maxVersion, $intSize) { $app = array( 'dependencies' => array( 'php' => array() @@ -86,6 +90,9 @@ class DependencyAnalyzer extends TestCase { if (!is_null($maxVersion)) { $app['dependencies']['php']['@attributes']['max-version'] = $maxVersion; } + if (!is_null($intSize)) { + $app['dependencies']['php']['@attributes']['min-int-size'] = $intSize; + } $missing = $this->analyser->analyze($app); $this->assertTrue(is_array($missing)); @@ -278,13 +285,14 @@ class DependencyAnalyzer extends TestCase { */ function providesPhpVersion() { return array( - array(array(), null, null), - array(array(), '5.4', null), - array(array(), null, '5.5'), - array(array(), '5.4', '5.5'), - array(array('PHP 5.4.4 or higher is required.'), '5.4.4', null), - array(array('PHP with a version lower than 5.4.2 is required.'), null, '5.4.2'), - array(array(), '5.4', '5.4'), + array(array(), null, null, null), + array(array(), '5.4', null, null), + array(array(), null, '5.5', null), + array(array(), '5.4', '5.5', null), + array(array('PHP 5.4.4 or higher is required.'), '5.4.4', null, null), + array(array('PHP with a version lower than 5.4.2 is required.'), null, '5.4.2', null), + array(array('64bit or higher PHP required.'), null, null, 64), + array(array(), '5.4', '5.4', null), ); } } diff --git a/tests/lib/files/storage/wrapper/availability.php b/tests/lib/files/storage/wrapper/availability.php index 9b394df8ca3..99d6f7dbe5c 100644 --- a/tests/lib/files/storage/wrapper/availability.php +++ b/tests/lib/files/storage/wrapper/availability.php @@ -74,9 +74,12 @@ class Availability extends \Test\TestCase { $storage->expects($this->once()) ->method('test') ->willReturn(true); - $storage->expects($this->once()) + $storage->expects($this->exactly(2)) ->method('setAvailability') - ->with($this->equalTo(true)); + ->withConsecutive( + [$this->equalTo(false)], // prevents concurrent rechecks + [$this->equalTo(true)] // sets correct availability + ); $storage->expects($this->once()) ->method('mkdir'); diff --git a/tests/lib/migration/BackgroundRepairTest.php b/tests/lib/migration/BackgroundRepairTest.php new file mode 100644 index 00000000000..e092f6c2e8b --- /dev/null +++ b/tests/lib/migration/BackgroundRepairTest.php @@ -0,0 +1,120 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace Test\Migration; + + +use OC\Migration\BackgroundRepair; +use OC\NeedsUpdateException; +use OCP\ILogger; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\GenericEvent; +use Test\TestCase; + +class TestRepairStep implements IRepairStep { + + /** + * Returns the step's name + * + * @return string + * @since 9.1.0 + */ + public function getName() { + return 'A test repair step'; + } + + /** + * Run repair step. + * Must throw exception on error. + * + * @since 9.1.0 + * @throws \Exception in case of failure + */ + public function run(IOutput $output) { + // TODO: Implement run() method. + } +} + +class BackgroundRepairTest extends TestCase { + + /** @var \OC\BackgroundJob\JobList | \PHPUnit_Framework_MockObject_MockObject */ + private $jobList; + + /** @var BackgroundRepair | \PHPUnit_Framework_MockObject_MockObject */ + private $job; + + /** @var ILogger | \PHPUnit_Framework_MockObject_MockObject */ + private $logger; + + public function setUp() { + parent::setUp(); + + $this->jobList = $this->getMockBuilder('OC\BackgroundJob\JobList') + ->disableOriginalConstructor() + ->getMock(); + $this->logger = $this->getMockBuilder('OCP\ILogger') + ->disableOriginalConstructor() + ->getMock(); + $this->job = $this->getMock('OC\Migration\BackgroundRepair', ['loadApp']); + } + + public function testNoArguments() { + $this->jobList->expects($this->once())->method('remove'); + $this->job->execute($this->jobList); + } + + public function testAppUpgrading() { + $this->jobList->expects($this->never())->method('remove'); + $this->job->expects($this->once())->method('loadApp')->with('test')->willThrowException(new NeedsUpdateException()); + $this->job->setArgument([ + 'app' => 'test', + 'step' => 'j' + ]); + $this->job->execute($this->jobList); + } + + public function testUnknownStep() { + $this->jobList->expects($this->once())->method('remove'); + $this->logger->expects($this->once())->method('logException'); + $this->job->setArgument([ + 'app' => 'test', + 'step' => 'j' + ]); + $this->job->execute($this->jobList, $this->logger); + } + + public function testWorkingStep() { + /** @var EventDispatcher | \PHPUnit_Framework_MockObject_MockObject $dispatcher */ + $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcher', []); + $dispatcher->expects($this->once())->method('dispatch') + ->with('\OC\Repair::step', new GenericEvent('\OC\Repair::step', ['A test repair step'])); + + $this->jobList->expects($this->once())->method('remove'); + $this->job->setDispatcher($dispatcher); + $this->job->setArgument([ + 'app' => 'test', + 'step' => '\Test\Migration\TestRepairStep' + ]); + $this->job->execute($this->jobList, $this->logger); + } +} diff --git a/tests/lib/preview/movie.php b/tests/lib/preview/movie.php index c6b0c0f7322..0ad8c13fc63 100644 --- a/tests/lib/preview/movie.php +++ b/tests/lib/preview/movie.php @@ -21,6 +21,13 @@ namespace Test\Preview; +/** + * Class Movie + * + * @group DB + * + * @package Test\Preview + */ class Movie extends Provider { public function setUp() { diff --git a/tests/lib/preview/office.php b/tests/lib/preview/office.php index 22eeb0aed33..83eb5e2cecb 100644 --- a/tests/lib/preview/office.php +++ b/tests/lib/preview/office.php @@ -21,6 +21,13 @@ namespace Test\Preview; +/** + * Class Office + * + * @group DB + * + * @package Test\Preview + */ class Office extends Provider { public function setUp() { diff --git a/tests/lib/repair.php b/tests/lib/repair.php deleted file mode 100644 index a598d3c1a29..00000000000 --- a/tests/lib/repair.php +++ /dev/null @@ -1,159 +0,0 @@ -<?php -/** - * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -use OCP\Migration\IRepairStep; - -class TestRepairStep implements IRepairStep { - private $warning; - - public function __construct($warning = false) { - $this->warning = $warning; - } - - public function getName() { - return 'Test Name'; - } - - public function run(\OCP\Migration\IOutput $out) { - if ($this->warning) { - $out->warning('Simulated warning'); - } - else { - $out->info('Simulated info'); - } - } -} - -class Test_Repair extends \Test\TestCase { - public function testRunRepairStep() { - $output = array(); - - $repair = new \OC\Repair(); - $repair->addStep(new TestRepairStep(false)); - - $repair->listen('\OC\Repair', 'warning', function ($description) use (&$output) { - $output[] = 'warning: ' . $description; - }); - $repair->listen('\OC\Repair', 'info', function ($description) use (&$output) { - $output[] = 'info: ' . $description; - }); - $repair->listen('\OC\Repair', 'step', function ($description) use (&$output) { - $output[] = 'step: ' . $description; - }); - - $repair->run(); - - $this->assertEquals( - array( - 'step: Test Name', - 'info: Simulated info', - ), - $output - ); - } - - public function testRunRepairStepThatFail() { - $output = array(); - - $repair = new \OC\Repair(); - $repair->addStep(new TestRepairStep(true)); - - $repair->listen('\OC\Repair', 'warning', function ($description) use (&$output) { - $output[] = 'warning: ' . $description; - }); - $repair->listen('\OC\Repair', 'info', function ($description) use (&$output) { - $output[] = 'info: ' . $description; - }); - $repair->listen('\OC\Repair', 'step', function ($description) use (&$output) { - $output[] = 'step: ' . $description; - }); - - $repair->run(); - - $this->assertEquals( - array( - 'step: Test Name', - 'warning: Simulated warning', - ), - $output - ); - } - - public function testRunRepairStepsWithException() { - $output = array(); - - $mock = $this->getMock('TestRepairStep'); - $mock->expects($this->any()) - ->method('run') - ->will($this->throwException(new Exception)); - $mock->expects($this->any()) - ->method('getName') - ->will($this->returnValue('Exception Test')); - - $repair = new \OC\Repair(); - $repair->addStep($mock); - $repair->addStep(new TestRepairStep(false)); - - $repair->listen('\OC\Repair', 'warning', function ($description) use (&$output) { - $output[] = 'warning: ' . $description; - }); - $repair->listen('\OC\Repair', 'info', function ($description) use (&$output) { - $output[] = 'info: ' . $description; - }); - $repair->listen('\OC\Repair', 'step', function ($description) use (&$output) { - $output[] = 'step: ' . $description; - }); - - $thrown = false; - try { - $repair->run(); - } - catch (Exception $e) { - $thrown = true; - } - - $this->assertTrue($thrown); - // jump out after exception - $this->assertEquals( - array( - 'step: Exception Test', - ), - $output - ); - } - - public function testRunRepairStepsContinueAfterWarning() { - $output = array(); - - $repair = new \OC\Repair(); - $repair->addStep(new TestRepairStep(true)); - $repair->addStep(new TestRepairStep(false)); - - $repair->listen('\OC\Repair', 'warning', function ($description) use (&$output) { - $output[] = 'warning: ' . $description; - }); - $repair->listen('\OC\Repair', 'info', function ($description) use (&$output) { - $output[] = 'info: ' . $description; - }); - $repair->listen('\OC\Repair', 'step', function ($description) use (&$output) { - $output[] = 'step: ' . $description; - }); - - $repair->run(); - - $this->assertEquals( - array( - 'step: Test Name', - 'warning: Simulated warning', - 'step: Test Name', - 'info: Simulated info', - ), - $output - ); - } -} |