From 31313178a56d6c173a45e7e89546da1f5d43052a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Fri, 26 Jan 2018 17:46:42 +0100 Subject: [PATCH 1/4] Add repair step to clear frontend related caches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/private/Repair.php | 4 ++ lib/private/Repair/ClearFrontendCaches.php | 78 ++++++++++++++++++++++ lib/private/Server.php | 12 ++++ lib/private/Template/JSCombiner.php | 21 +++++- lib/private/Template/SCSSCacher.php | 9 ++- 5 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 lib/private/Repair/ClearFrontendCaches.php diff --git a/lib/private/Repair.php b/lib/private/Repair.php index 8562465aad3e5..3ddcf0accec87 100644 --- a/lib/private/Repair.php +++ b/lib/private/Repair.php @@ -33,6 +33,7 @@ use OC\App\AppStore\Bundles\BundleFetcher; use OC\Files\AppData\Factory; use OC\Repair\CleanTags; +use OC\Repair\ClearFrontendCaches; use OC\Repair\Collation; use OC\Repair\MoveUpdaterStepFile; use OC\Repair\NC11\CleanPreviews; @@ -50,6 +51,8 @@ use OC\Repair\SqliteAutoincrement; use OC\Repair\RepairMimeTypes; use OC\Repair\RepairInvalidShares; +use OC\Template\JSCombiner; +use OC\Template\SCSSCacher; use OCP\AppFramework\QueryException; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; @@ -152,6 +155,7 @@ public static function getRepairSteps() { new RepairInvalidPaths(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig()), new RepairIdentityProofKeyFolders(\OC::$server->getConfig(), \OC::$server->query(Factory::class), \OC::$server->getRootFolder()), new AddLogRotateJob(\OC::$server->getJobList()), + new ClearFrontendCaches(\OC::$server->getMemCacheFactory(), \OC::$server->query(SCSSCacher::class), \OC::$server->query(JSCombiner::class)) ]; } diff --git a/lib/private/Repair/ClearFrontendCaches.php b/lib/private/Repair/ClearFrontendCaches.php new file mode 100644 index 0000000000000..8d109462f6ae8 --- /dev/null +++ b/lib/private/Repair/ClearFrontendCaches.php @@ -0,0 +1,78 @@ + + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see . + * + */ + +namespace OC\Repair; + +use OC\Core\Command\Maintenance\ClearCacheJSCSS; +use OC\Template\JSCombiner; +use OC\Template\SCSSCacher; +use OCP\AppFramework\QueryException; +use OCP\ICacheFactory; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\BufferedOutput; + +class ClearFrontendCaches implements IRepairStep { + + /** @var ICacheFactory */ + protected $cacheFactory; + + /** @var SCSSCacher */ + protected $scssCacher; + + /** @var JSCombiner */ + protected $jsCombiner; + + public function __construct(ICacheFactory $cacheFactory, + SCSSCacher $SCSSCacher, + JSCombiner $JSCombiner) { + $this->cacheFactory = $cacheFactory; + $this->scssCacher = $SCSSCacher; + $this->jsCombiner = $JSCombiner; + } + + public function getName() { + return 'Clear frontend caches'; + } + + public function run(IOutput $output) { + try { + $c = $this->cacheFactory->createDistributed('imagePath'); + $c->clear(''); + $output->info('Image cache cleared'); + + $this->scssCacher->resetCache(); + $c = $this->cacheFactory->createDistributed('SCSS'); + $c->clear(''); + $output->info('SCSS cache cleared'); + + $this->jsCombiner->resetCache(); + $c = $this->cacheFactory->createDistributed('JS'); + $c->clear(''); + $output->info('JS cache cleared'); + } catch (\Exception $e) { + $output->warning('Unable to clear the frontend cache'); + } + } +} diff --git a/lib/private/Server.php b/lib/private/Server.php index 4a851d672266a..fa22e52eee360 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -109,6 +109,7 @@ use OC\Session\CryptoWrapper; use OC\Share20\ShareHelper; use OC\Tagging\TagMapper; +use OC\Template\JSCombiner; use OC\Template\SCSSCacher; use OCA\Theming\ThemingDefaults; @@ -956,6 +957,17 @@ public function __construct($webRoot, \OC\Config $config) { $cacheFactory->createDistributed('SCSS') ); }); + $this->registerService(JSCombiner::class, function (Server $c) { + /** @var Factory $cacheFactory */ + $cacheFactory = $c->query(Factory::class); + return new JSCombiner( + $c->getAppDataDir('js'), + $c->getURLGenerator(), + $cacheFactory->createDistributed('JS'), + $c->getSystemConfig(), + $c->getLogger() + ); + }); $this->registerService(EventDispatcher::class, function () { return new EventDispatcher(); }); diff --git a/lib/private/Template/JSCombiner.php b/lib/private/Template/JSCombiner.php index 6a67dd0dede53..b95a59834a605 100644 --- a/lib/private/Template/JSCombiner.php +++ b/lib/private/Template/JSCombiner.php @@ -184,9 +184,10 @@ protected function cache($path, $fileName, ISimpleFolder $folder) { $depFile->putContent($deps); $this->depsCache->set($folder->getName() . '-' . $depFileName, $deps); $gzipFile->putContent(gzencode($res, 9)); - + $this->logger->debug('JSCombiner: successfully cached: ' . $fileName); return true; } catch (NotPermittedException $e) { + $this->logger->error('JSCombiner: unable to cache: ' . $fileName); return false; } } @@ -227,4 +228,22 @@ public function getContent($root, $file) { return $result; } + + + /** + * Clear cache with combined javascript files + * + * @throws NotFoundException + */ + public function resetCache() { + $appDirectory = $this->appData->getDirectoryListing(); + if(empty($appDirectory)){ + return; + } + foreach ($appDirectory as $folder) { + foreach ($folder->getDirectoryListing() as $file) { + $file->delete(); + } + } + } } diff --git a/lib/private/Template/SCSSCacher.php b/lib/private/Template/SCSSCacher.php index c6473ead09de6..32462455439d2 100644 --- a/lib/private/Template/SCSSCacher.php +++ b/lib/private/Template/SCSSCacher.php @@ -242,9 +242,10 @@ private function cache($path, $fileNameCSS, $fileNameSCSS, ISimpleFolder $folder $depFile->putContent($deps); $this->depsCache->set($folder->getName() . '-' . $depFileName, $deps); $gzipFile->putContent(gzencode($data, 9)); - $this->logger->debug($webDir.'/'.$fileNameSCSS.' compiled and successfully cached', ['app' => 'core']); + $this->logger->debug('SCSSCacher: '.$webDir.'/'.$fileNameSCSS.' compiled and successfully cached', ['app' => 'core']); return true; } catch(NotPermittedException $e) { + $this->logger->error('SCSSCacher: unable to cache: ' . $fileNameSCSS); return false; } } @@ -253,7 +254,7 @@ private function cache($path, $fileNameCSS, $fileNameSCSS, ISimpleFolder $folder * Reset scss cache by deleting all generated css files * We need to regenerate all files when variables change */ - private function resetCache() { + public function resetCache() { $this->injectedVariables = null; $appDirectory = $this->appData->getDirectoryListing(); if(empty($appDirectory)){ @@ -261,9 +262,7 @@ private function resetCache() { } foreach ($appDirectory as $folder) { foreach ($folder->getDirectoryListing() as $file) { - if (substr($file->getName(), -3) === "css" || substr($file->getName(), -4) === "deps") { - $file->delete(); - } + $file->delete(); } } } From bf24b4db2430ecd6796bfe323859656234691bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Thu, 1 Feb 2018 16:02:09 +0100 Subject: [PATCH 2/4] Add tests and class mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + tests/lib/Repair/ClearFrontendCachesTest.php | 94 ++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 tests/lib/Repair/ClearFrontendCachesTest.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 7b82da1dc2000..e9de3538b7763 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -804,6 +804,7 @@ 'OC\\Repair' => $baseDir . '/lib/private/Repair.php', 'OC\\RepairException' => $baseDir . '/lib/private/RepairException.php', 'OC\\Repair\\CleanTags' => $baseDir . '/lib/private/Repair/CleanTags.php', + 'OC\\Repair\\ClearFrontendCaches' => $baseDir . '/lib/private/Repair/ClearFrontendCaches.php', 'OC\\Repair\\Collation' => $baseDir . '/lib/private/Repair/Collation.php', 'OC\\Repair\\MoveUpdaterStepFile' => $baseDir . '/lib/private/Repair/MoveUpdaterStepFile.php', 'OC\\Repair\\NC11\\CleanPreviews' => $baseDir . '/lib/private/Repair/NC11/CleanPreviews.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 67ae9f84d3c85..9988e2118f4a4 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -828,6 +828,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Repair' => __DIR__ . '/../../..' . '/lib/private/Repair.php', 'OC\\RepairException' => __DIR__ . '/../../..' . '/lib/private/RepairException.php', 'OC\\Repair\\CleanTags' => __DIR__ . '/../../..' . '/lib/private/Repair/CleanTags.php', + 'OC\\Repair\\ClearFrontendCaches' => __DIR__ . '/../../..' . '/lib/private/Repair/ClearFrontendCaches.php', 'OC\\Repair\\Collation' => __DIR__ . '/../../..' . '/lib/private/Repair/Collation.php', 'OC\\Repair\\MoveUpdaterStepFile' => __DIR__ . '/../../..' . '/lib/private/Repair/MoveUpdaterStepFile.php', 'OC\\Repair\\NC11\\CleanPreviews' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/CleanPreviews.php', diff --git a/tests/lib/Repair/ClearFrontendCachesTest.php b/tests/lib/Repair/ClearFrontendCachesTest.php new file mode 100644 index 0000000000000..393e1de4f541a --- /dev/null +++ b/tests/lib/Repair/ClearFrontendCachesTest.php @@ -0,0 +1,94 @@ + + * + * @author Julius Härtl + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see . + * + */ + +namespace Test\Repair; +use OC\Template\JSCombiner; +use OC\Template\SCSSCacher; +use OCP\ICache; +use OCP\ICacheFactory; +use OCP\Migration\IOutput; + +class ClearFrontendCachesTest extends \Test\TestCase { + + /** @var ICacheFactory */ + private $cacheFactory; + + /** @var SCSSCacher */ + private $scssCacher; + + /** @var JSCombiner */ + private $jsCombiner; + + /** @var \OC\Repair\ClearFrontendCaches */ + protected $repair; + + /** @var IOutput */ + private $outputMock; + + protected function setUp() { + parent::setUp(); + + $this->outputMock = $this->createMock(IOutput::class); + + $this->cacheFactory = $this->createMock(ICacheFactory::class); + $this->scssCacher = $this->createMock(SCSSCacher::class); + $this->jsCombiner = $this->createMock(JSCombiner::class); + + $this->repair = new \OC\Repair\ClearFrontendCaches($this->cacheFactory, $this->scssCacher, $this->jsCombiner); + } + + + public function testRun() { + $imagePathCache = $this->createMock(ICache::class); + $imagePathCache->expects($this->once()) + ->method('clear') + ->with(''); + $jsCache = $this->createMock(ICache::class); + $jsCache->expects($this->once()) + ->method('clear') + ->with(''); + $cssCache = $this->createMock(ICache::class); + $cssCache->expects($this->once()) + ->method('clear') + ->with(''); + $this->jsCombiner->expects($this->once()) + ->method('resetCache'); + $this->scssCacher->expects($this->once()) + ->method('resetCache'); + $this->cacheFactory->expects($this->at(0)) + ->method('createDistributed') + ->with('imagePath') + ->willReturn($imagePathCache); + $this->cacheFactory->expects($this->at(1)) + ->method('createDistributed') + ->with('SCSS') + ->willReturn($cssCache); + $this->cacheFactory->expects($this->at(2)) + ->method('createDistributed') + ->with('JS') + ->willReturn($jsCache); + + $this->repair->run($this->outputMock); + $this->assertTrue(true); + } +} From 69b22c2d616bb7867c3a5f0cc723328fff2501fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Sat, 3 Feb 2018 12:41:21 +0100 Subject: [PATCH 3/4] Move depsCache clearing to SCSSCacher/JSCombiner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/private/Repair/ClearFrontendCaches.php | 10 +--------- lib/private/Template/JSCombiner.php | 4 +--- lib/private/Template/SCSSCacher.php | 4 +--- tests/lib/Repair/ClearFrontendCachesTest.php | 16 --------------- tests/lib/Template/JSCombinerTest.php | 21 ++++++++++++++++++++ tests/lib/Template/SCSSCacherTest.php | 21 ++++++++++++++++++++ 6 files changed, 45 insertions(+), 31 deletions(-) diff --git a/lib/private/Repair/ClearFrontendCaches.php b/lib/private/Repair/ClearFrontendCaches.php index 8d109462f6ae8..0a92aa8d201bd 100644 --- a/lib/private/Repair/ClearFrontendCaches.php +++ b/lib/private/Repair/ClearFrontendCaches.php @@ -23,15 +23,11 @@ namespace OC\Repair; -use OC\Core\Command\Maintenance\ClearCacheJSCSS; use OC\Template\JSCombiner; use OC\Template\SCSSCacher; -use OCP\AppFramework\QueryException; use OCP\ICacheFactory; use OCP\Migration\IOutput; use OCP\Migration\IRepairStep; -use Symfony\Component\Console\Input\StringInput; -use Symfony\Component\Console\Output\BufferedOutput; class ClearFrontendCaches implements IRepairStep { @@ -59,17 +55,13 @@ public function getName() { public function run(IOutput $output) { try { $c = $this->cacheFactory->createDistributed('imagePath'); - $c->clear(''); + $c->clear(); $output->info('Image cache cleared'); $this->scssCacher->resetCache(); - $c = $this->cacheFactory->createDistributed('SCSS'); - $c->clear(''); $output->info('SCSS cache cleared'); $this->jsCombiner->resetCache(); - $c = $this->cacheFactory->createDistributed('JS'); - $c->clear(''); $output->info('JS cache cleared'); } catch (\Exception $e) { $output->warning('Unable to clear the frontend cache'); diff --git a/lib/private/Template/JSCombiner.php b/lib/private/Template/JSCombiner.php index b95a59834a605..c5adcee68542e 100644 --- a/lib/private/Template/JSCombiner.php +++ b/lib/private/Template/JSCombiner.php @@ -236,10 +236,8 @@ public function getContent($root, $file) { * @throws NotFoundException */ public function resetCache() { + $this->depsCache->clear(); $appDirectory = $this->appData->getDirectoryListing(); - if(empty($appDirectory)){ - return; - } foreach ($appDirectory as $folder) { foreach ($folder->getDirectoryListing() as $file) { $file->delete(); diff --git a/lib/private/Template/SCSSCacher.php b/lib/private/Template/SCSSCacher.php index 32462455439d2..66569cba02524 100644 --- a/lib/private/Template/SCSSCacher.php +++ b/lib/private/Template/SCSSCacher.php @@ -256,10 +256,8 @@ private function cache($path, $fileNameCSS, $fileNameSCSS, ISimpleFolder $folder */ public function resetCache() { $this->injectedVariables = null; + $this->depsCache->clear(); $appDirectory = $this->appData->getDirectoryListing(); - if(empty($appDirectory)){ - return; - } foreach ($appDirectory as $folder) { foreach ($folder->getDirectoryListing() as $file) { $file->delete(); diff --git a/tests/lib/Repair/ClearFrontendCachesTest.php b/tests/lib/Repair/ClearFrontendCachesTest.php index 393e1de4f541a..7c3a54cf1db6f 100644 --- a/tests/lib/Repair/ClearFrontendCachesTest.php +++ b/tests/lib/Repair/ClearFrontendCachesTest.php @@ -63,14 +63,6 @@ public function testRun() { $imagePathCache->expects($this->once()) ->method('clear') ->with(''); - $jsCache = $this->createMock(ICache::class); - $jsCache->expects($this->once()) - ->method('clear') - ->with(''); - $cssCache = $this->createMock(ICache::class); - $cssCache->expects($this->once()) - ->method('clear') - ->with(''); $this->jsCombiner->expects($this->once()) ->method('resetCache'); $this->scssCacher->expects($this->once()) @@ -79,14 +71,6 @@ public function testRun() { ->method('createDistributed') ->with('imagePath') ->willReturn($imagePathCache); - $this->cacheFactory->expects($this->at(1)) - ->method('createDistributed') - ->with('SCSS') - ->willReturn($cssCache); - $this->cacheFactory->expects($this->at(2)) - ->method('createDistributed') - ->with('JS') - ->willReturn($jsCache); $this->repair->run($this->outputMock); $this->assertTrue(true); diff --git a/tests/lib/Template/JSCombinerTest.php b/tests/lib/Template/JSCombinerTest.php index d6583d4a45071..d5f7000e0a5f6 100644 --- a/tests/lib/Template/JSCombinerTest.php +++ b/tests/lib/Template/JSCombinerTest.php @@ -511,4 +511,25 @@ public function testGetContentInvalidJson() { $expected = []; $this->assertEquals($expected, $this->jsCombiner->getContent($pathInfo['dirname'], $pathInfo['basename'])); } + + public function testResetCache() { + $file = $this->createMock(ISimpleFile::class); + $file->expects($this->once()) + ->method('delete'); + + $folder = $this->createMock(ISimpleFolder::class); + $folder->expects($this->once()) + ->method('getDirectoryListing') + ->willReturn([$file]); + + $this->depsCache->expects($this->once()) + ->method('clear') + ->with(''); + $this->appData->expects($this->once()) + ->method('getDirectoryListing') + ->willReturn([$folder]); + + $this->jsCombiner->resetCache(); + } + } diff --git a/tests/lib/Template/SCSSCacherTest.php b/tests/lib/Template/SCSSCacherTest.php index 7b5300b99a915..94d3d5a610e32 100644 --- a/tests/lib/Template/SCSSCacherTest.php +++ b/tests/lib/Template/SCSSCacherTest.php @@ -445,4 +445,25 @@ public function testgetWebDir($path, $appName, $webRoot, $serverRoot, $correctWe $this->rrmdir($tmpDir.$path); } + public function testResetCache() { + $file = $this->createMock(ISimpleFile::class); + $file->expects($this->once()) + ->method('delete'); + + $folder = $this->createMock(ISimpleFolder::class); + $folder->expects($this->once()) + ->method('getDirectoryListing') + ->willReturn([$file]); + + $this->depsCache->expects($this->once()) + ->method('clear') + ->with(''); + $this->appData->expects($this->once()) + ->method('getDirectoryListing') + ->willReturn([$folder]); + + $this->scssCacher->resetCache(); + } + + } From b837d3f33277880923a169a984c460ea970e031b Mon Sep 17 00:00:00 2001 From: Roeland Jago Douma Date: Sat, 3 Feb 2018 22:16:09 +0100 Subject: [PATCH 4/4] Fix tests Signed-off-by: Roeland Jago Douma --- tests/lib/Template/SCSSCacherTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/lib/Template/SCSSCacherTest.php b/tests/lib/Template/SCSSCacherTest.php index 94d3d5a610e32..dfaeb80357844 100644 --- a/tests/lib/Template/SCSSCacherTest.php +++ b/tests/lib/Template/SCSSCacherTest.php @@ -85,6 +85,7 @@ public function testProcessUncachedFileNoAppDataFolder() { $this->appData->expects($this->once())->method('getFolder')->with('core')->willThrowException(new NotFoundException()); $this->appData->expects($this->once())->method('newFolder')->with('core')->willReturn($folder); + $this->appData->method('getDirectoryListing')->willReturn([]); $fileDeps = $this->createMock(ISimpleFile::class); $gzfile = $this->createMock(ISimpleFile::class); @@ -118,6 +119,7 @@ public function testProcessUncachedFileNoAppDataFolder() { public function testProcessUncachedFile() { $folder = $this->createMock(ISimpleFolder::class); $this->appData->expects($this->once())->method('getFolder')->with('core')->willReturn($folder); + $this->appData->method('getDirectoryListing')->willReturn([]); $file = $this->createMock(ISimpleFile::class); $file->expects($this->any())->method('getSize')->willReturn(1); $fileDeps = $this->createMock(ISimpleFile::class); @@ -148,6 +150,7 @@ public function testProcessUncachedFile() { public function testProcessCachedFile() { $folder = $this->createMock(ISimpleFolder::class); $this->appData->expects($this->once())->method('getFolder')->with('core')->willReturn($folder); + $this->appData->method('getDirectoryListing')->willReturn([]); $file = $this->createMock(ISimpleFile::class); $fileDeps = $this->createMock(ISimpleFile::class); $fileDeps->expects($this->any())->method('getSize')->willReturn(1); @@ -178,6 +181,7 @@ public function testProcessCachedFileMemcache() { ->willReturn($folder); $folder->method('getName') ->willReturn('core'); + $this->appData->method('getDirectoryListing')->willReturn([]); $file = $this->createMock(ISimpleFile::class);