From 1a36bb628ede6121d8a7aae49e915e39b5f9c279 Mon Sep 17 00:00:00 2001 From: Will Rossiter Date: Sat, 11 May 2013 15:07:12 +1200 Subject: [PATCH] API: Add sync_blacklisted_patterns for configuring files to skip in sync tasks Fixes http://open.silverstripe.org/ticket/6210. Replaces the hardcoded file patterns from Folder::syncChildren() with a new static Filesystem::$sync_blacklisted_patterns to describe files and folder names to skip when running Folder::sync(). Added unit test for Folder::sync() Extended Folder::sync() to report on the number of file / folders skipped. --- filesystem/Filesystem.php | 19 ++++++++++++++ filesystem/Folder.php | 34 +++++++++++++++++++++---- tests/filesystem/FolderTest.php | 44 +++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/filesystem/Filesystem.php b/filesystem/Filesystem.php index 87f08116305..9930f0a38e0 100644 --- a/filesystem/Filesystem.php +++ b/filesystem/Filesystem.php @@ -19,8 +19,27 @@ class Filesystem extends Object { */ private static $folder_create_mask = 02775; + /** + * @var int + */ protected static $cache_folderModTime; + /** + * @config + * + * Array of file / folder regex expressions to exclude from the + * {@link Filesystem::sync()} + * + * @var array + */ + private static $sync_blacklisted_patterns = array( + "/^\./", + "/^_combinedfiles$/i", + "/^_resampled$/i", + "/^web.config/i", + "/^Thumbs(.)/" + ); + /** * Create a folder on the filesystem, recursively. * Uses {@link Filesystem::$folder_create_mask} to set filesystem permissions. diff --git a/filesystem/Folder.php b/filesystem/Folder.php index 95c6ee53897..28ff5a54107 100644 --- a/filesystem/Folder.php +++ b/filesystem/Folder.php @@ -80,12 +80,14 @@ public static function find_or_make($folderPath) { } /** - * Syncronise the file database with the actual content of the assets folder + * Synchronize the file database with the actual content of the assets + * folder. */ public function syncChildren() { $parentID = (int)$this->ID; // parentID = 0 on the singleton, used as the 'root node'; $added = 0; $deleted = 0; + $skipped = 0; // First, merge any children that are duplicates $duplicateChildrenNames = DB::query("SELECT \"Name\" FROM \"File\"" @@ -113,6 +115,7 @@ public function syncChildren() { // We don't use DataObject so that things like subsites doesn't muck with this. $dbChildren = DB::query("SELECT * FROM \"File\" WHERE \"ParentID\" = $parentID"); $hasDbChild = array(); + if($dbChildren) { foreach($dbChildren as $dbChild) { $className = $dbChild['ClassName']; @@ -120,6 +123,7 @@ public function syncChildren() { $hasDbChild[$dbChild['Name']] = new $className($dbChild); } } + $unwantedDbChildren = $hasDbChild; // if we're syncing a folder with no ID, we assume we're syncing the root assets folder @@ -135,13 +139,28 @@ public function syncChildren() { if(file_exists($baseDir)) { $actualChildren = scandir($baseDir); + $ignoreRules = Config::inst()->get('Filesystem', 'sync_blacklisted_patterns'); + foreach($actualChildren as $actualChild) { - if($actualChild[0] == '.' || $actualChild[0] == '_' || substr($actualChild,0,6) == 'Thumbs' - || $actualChild == 'web.config') { + if($ignoreRules) { + $skip = false; + + foreach($ignoreRules as $rule) { + if(preg_match($rule, $actualChild)) { + $skip = true; + + break; + } + } + + if($skip) { + $skipped++; - continue; + continue; + } } + // A record with a bad class type doesn't deserve to exist. It must be purged! if(isset($hasDbChild[$actualChild])) { $child = $hasDbChild[$actualChild]; @@ -166,6 +185,7 @@ public function syncChildren() { $childResult = $child->syncChildren(); $added += $childResult['added']; $deleted += $childResult['deleted']; + $skipped += $childResult['skipped']; } // Clean up the child record from memory after use. Important! @@ -182,7 +202,11 @@ public function syncChildren() { DB::query("DELETE FROM \"File\" WHERE \"ID\" = $this->ID"); } - return array('added' => $added, 'deleted' => $deleted); + return array( + 'added' => $added, + 'deleted' => $deleted, + 'skipped' => $skipped + ); } /** diff --git a/tests/filesystem/FolderTest.php b/tests/filesystem/FolderTest.php index 0f9b9ceef97..229f8a04874 100644 --- a/tests/filesystem/FolderTest.php +++ b/tests/filesystem/FolderTest.php @@ -293,5 +293,49 @@ public function tearDown() { parent::tearDown(); } + + public function testSyncedChildren() { + mkdir(ASSETS_PATH ."/FolderTest"); + mkdir(ASSETS_PATH ."/FolderTest/sync"); + + $files = array( + '.htaccess', + '.git', + 'web.config', + '.DS_Store', + '_my_synced_file.txt' + ); + + $folders = array( + '_combinedfiles', + '_resampled', + '_testsync' + ); + + foreach($files as $file) { + $fh = fopen(ASSETS_PATH."/FolderTest/sync/$file", "w"); + fwrite($fh, 'test'); + fclose($fh); + } + + foreach($folders as $folder) { + mkdir(ASSETS_PATH ."/FolderTest/sync/". $folder); + } + + $folder = Folder::find_or_make('/FolderTest/sync'); + $result = $folder->syncChildren(); + + $this->assertEquals(10, $result['skipped']); + $this->assertEquals(2, $result['added']); + + // folder with a path of _test should exist + $this->assertEquals(1, Folder::get()->filter(array( + 'Name' => '_testsync' + ))->count()); + + $this->assertEquals(1, File::get()->filter(array( + 'Name' => '_my_synced_file.txt' + ))->count()); + } }