From: Aaron Date: Thu, 26 Apr 2012 18:40:47 +0000 (-0700) Subject: [FileBackend] Added 'recursive' flag to directory clean() function. X-Git-Tag: 1.31.0-rc.0~23809^2 X-Git-Url: https://git.cyclocoop.org/%28%28?a=commitdiff_plain;h=104e8bb0d72dcf58676e3c3f34784ebd85b774fc;p=lhc%2Fweb%2Fwiklou.git [FileBackend] Added 'recursive' flag to directory clean() function. Change-Id: I8fadd25c05840e2324bf8433dc0a4846daf8e2c3 --- diff --git a/includes/filerepo/backend/FSFileBackend.php b/includes/filerepo/backend/FSFileBackend.php index df822fdca7..9839fa1b9b 100644 --- a/includes/filerepo/backend/FSFileBackend.php +++ b/includes/filerepo/backend/FSFileBackend.php @@ -534,6 +534,14 @@ class FSFileBackend extends FileBackendStore { return $tmpFile; } + /** + * @see FileBackendStore::directoriesAreVirtual() + * @return bool + */ + protected function directoriesAreVirtual() { + return false; + } + /** * Chmod a file, suppressing the warnings * diff --git a/includes/filerepo/backend/FileBackend.php b/includes/filerepo/backend/FileBackend.php index f3b879a4dd..52baf1e1e4 100644 --- a/includes/filerepo/backend/FileBackend.php +++ b/includes/filerepo/backend/FileBackend.php @@ -383,7 +383,8 @@ abstract class FileBackend { * is that of an empty container, in which case it should be deleted. * * $params include: - * dir : storage directory + * dir : storage directory + * recursive : recursively delete empty subdirectories first (@since 1.20) * * @param $params Array * @return Status diff --git a/includes/filerepo/backend/FileBackendStore.php b/includes/filerepo/backend/FileBackendStore.php index f7e4529fae..d81cd081ee 100644 --- a/includes/filerepo/backend/FileBackendStore.php +++ b/includes/filerepo/backend/FileBackendStore.php @@ -371,6 +371,17 @@ abstract class FileBackendStore extends FileBackend { wfProfileIn( __METHOD__ . '-' . $this->name ); $status = Status::newGood(); + // Recursive: first delete all empty subdirs recursively + if ( !empty( $params['recursive'] ) && !$this->directoriesAreVirtual() ) { + $subDirsRel = $this->getTopDirectoryList( array( 'dir' => $params['dir'] ) ); + if ( $subDirsRel !== null ) { // no errors + foreach ( $subDirsRel as $subDirRel ) { + $subDir = $params['dir'] . "/{$subDirRel}"; // full path + $status->merge( $this->doClean( array( 'dir' => $subDir ) + $params ) ); + } + } + } + list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( $params['dir'] ); if ( $dir === null ) { $status->fatal( 'backend-fail-invalidpath', $params['dir'] ); @@ -891,6 +902,15 @@ abstract class FileBackendStore extends FileBackend { */ protected function doClearCache( array $paths = null ) {} + /** + * Is this a key/value store where directories are just virtual? + * Virtual directories exists in so much as files exists that are + * prefixed with the directory path followed by a forward slash. + * + * @return bool + */ + abstract protected function directoriesAreVirtual(); + /** * Move a cache entry to the top (such as when accessed) * diff --git a/includes/filerepo/backend/SwiftFileBackend.php b/includes/filerepo/backend/SwiftFileBackend.php index af5d693dd8..c8cb62f064 100644 --- a/includes/filerepo/backend/SwiftFileBackend.php +++ b/includes/filerepo/backend/SwiftFileBackend.php @@ -770,6 +770,14 @@ class SwiftFileBackend extends FileBackendStore { return $tmpFile; } + /** + * @see FileBackendStore::directoriesAreVirtual() + * @return bool + */ + protected function directoriesAreVirtual() { + return true; + } + /** * Get headers to send to Swift when reading a file based * on a FileBackend params array, e.g. that of getLocalCopy(). diff --git a/tests/phpunit/includes/filerepo/FileBackendTest.php b/tests/phpunit/includes/filerepo/FileBackendTest.php index 612c368327..af88bc8ced 100644 --- a/tests/phpunit/includes/filerepo/FileBackendTest.php +++ b/tests/phpunit/includes/filerepo/FileBackendTest.php @@ -1022,6 +1022,58 @@ class FileBackendTest extends MediaWikiTestCase { } } + public function testRecursiveClean() { + $this->backend = $this->singleBackend; + $this->doTestRecursiveClean(); + $this->tearDownFiles(); + + $this->backend = $this->multiBackend; + $this->doTestRecursiveClean(); + $this->tearDownFiles(); + } + + function doTestRecursiveClean() { + $backendName = $this->backendClass(); + + $base = $this->baseStorePath(); + $dirs = array( + "$base/unittest-cont1/a", + "$base/unittest-cont1/a/b", + "$base/unittest-cont1/a/b/c", + "$base/unittest-cont1/a/b/c/d0", + "$base/unittest-cont1/a/b/c/d1", + "$base/unittest-cont1/a/b/c/d2", + "$base/unittest-cont1/a/b/c/d0/1", + "$base/unittest-cont1/a/b/c/d0/2", + "$base/unittest-cont1/a/b/c/d1/3", + "$base/unittest-cont1/a/b/c/d1/4", + "$base/unittest-cont1/a/b/c/d2/5", + "$base/unittest-cont1/a/b/c/d2/6" + ); + foreach ( $dirs as $dir ) { + $status = $this->prepare( array( 'dir' => $dir ) ); + $this->assertEquals( array(), $status->errors, + "Preparing dir $dir succeeded without warnings ($backendName)." ); + } + + if ( $this->backend instanceof FSFileBackend ) { + foreach ( $dirs as $dir ) { + $this->assertEquals( true, $this->backend->directoryExists( array( 'dir' => $dir ) ), + "Dir $dir exists ($backendName)." ); + } + } + + $status = $this->backend->clean( + array( 'dir' => "$base/unittest-cont1", 'recursive' => 1 ) ); + $this->assertEquals( array(), $status->errors, + "Recursive cleaning of dir $dir succeeded without warnings ($backendName)." ); + + foreach ( $dirs as $dir ) { + $this->assertEquals( false, $this->backend->directoryExists( array( 'dir' => $dir ) ), + "Dir $dir no longer exists ($backendName)." ); + } + } + // @TODO: testSecure public function testDoOperations() {