diff --git a/README.md b/README.md index 4da3c52..3e09a9c 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Detailed documentation can be found here : https://www.open-csp.org/DevOps:Doc/P #### Development +* 2.7.0 rebuild-files-clean. Same as rebuild-files, but will now also physically unused files from the server * 2.6.10 fix for maintenance script when installing a shared file. Changed pages were counted as unchanged * 2.6.9 fix for maintenance script rename and removed specific PHP 8.3 usage * 2.6.8 Added fail catcher for broken pages. Added continue-on-error argument for maintenance script diff --git a/extension.json b/extension.json index 43aceb2..e8b0051 100644 --- a/extension.json +++ b/extension.json @@ -1,6 +1,6 @@ { "name": "PageSync", - "version": "2.6.10", + "version": "2.7.0", "author": [ "Sen-Sai" ], diff --git a/i18n/en.json b/i18n/en.json index e6fec98..79789f5 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -211,6 +211,7 @@ "wsps-maintenance-analyze-server-wiki-error-slot-missing": "Slot $1 is missing on server.", "wsps-maintenance-analyze-server-wiki-error-slot-unsynced": "Slot $1 content in Wiki and on Server are not identical", "wsps-maintenance-analyze-server-wiki-slot": " Slot : ", + "wsps-maintenance-clean-header": "Delete files from server not in index", "apihelp-wsps-description": "PageSync API module", "apihelp-wsps-summary": "PageSync API module", "apihelp-wsps-param-what": "Action to take; valid values are 'add', 'remove', 'gettags' and 'updatetags'", diff --git a/maintenance/WspsMaintenance.php b/maintenance/WspsMaintenance.php index 90736a6..3b34977 100644 --- a/maintenance/WspsMaintenance.php +++ b/maintenance/WspsMaintenance.php @@ -52,6 +52,10 @@ public function __construct() { 'rebuild-files', 'Will take the index file and re-create all files from the database' ); + $this->addOption( + 'rebuild-files-clean', + 'Same as rebuild-files, but will also physically remove all files not in the PageSync from the server' + ); $this->addOption( 'rebuild-index', 'Will recreate the index file from existing file structure' @@ -67,7 +71,7 @@ public function __construct() { ); $this->addOption( 'force-rebuild-files', - 'Used with rebuild-files. This forces rebuild-files without prompting for user interaction' + 'Used with rebuild-files and rebuild-files-clean. This forces rebuild-files without prompting for user interaction' ); $this->addOption( @@ -259,6 +263,11 @@ public function execute() { $silent = true; } + if ( $this->hasOption( 'special' ) ) { + $special = true; + $silent = true; + } + $skipDifferentUser = false; if ( $this->hasOption( 'skip-if-page-is-changed-in-wiki' ) ) { $skipDifferentUser = true; @@ -315,15 +324,18 @@ public function execute() { } return; } - - if ( $this->hasOption( 'rebuild-files' ) ) { + if ( $this->hasOption( 'rebuild-files' ) || $this->hasOption( 'rebuild-files-clean' ) ) { // We need to rebuild the index file here. $continueOnError = $this->hasOption( 'continue-on-error' ); if ( $continueOnError ) { $errorList = []; } if ( $this->hasOption( 'force-rebuild-files' ) === false ) { - echo "\n[Rebuilding files from index]\n"; + if ( $this->hasOption( 'rebuild-files-clean' ) ) { + echo "\n[Rebuilding files from index and remove unused files from server. This cannot be undone!]\n"; + } else { + echo "\n[Rebuilding files from index]\n"; + } $answer = strtolower( readline( "Are you sure (y/n)" ) ); if ( $answer !== "y" ) { die( "no action\n\n" ); @@ -388,6 +400,10 @@ public function execute() { echo implode( "\n", $errorList ) . "\n"; } } + if ( $this->hasOption( 'rebuild-files-clean' ) ) { + $cleaner = new \PageSync\Core\PSClean(); + $cleaner->cleanServerFiles(); + } die(); } diff --git a/src/Core/PSClean.php b/src/Core/PSClean.php new file mode 100644 index 0000000..6000892 --- /dev/null +++ b/src/Core/PSClean.php @@ -0,0 +1,178 @@ +serverList[] = $fileName; + continue; + } + $explodedFileName = explode( '_', $fileName ); + $cnt = count( $explodedFileName ); + if ( $cnt > 2 ) { + unset( $explodedFileName[ $cnt - 1 ] ); + unset( $explodedFileName[ $cnt - 2 ] ); + $this->serverList[] = implode( '_', $explodedFileName ); + } + } + $this->exportPath = PSConfig::$config['exportPath']; + $indexList = PSCore::getFileIndex(); + if ( $indexList !== false ) { + $this->indexList = $indexList; + } + } + + /** + * @return void + */ + public function cleanServerFiles(): void { + echo Colors::cEcho( + wfMessage( "wsps-maintenance-clean-header" )->plain(), + "blue+bold", + true, + "", + wfMessage( "wsps-maintenance-analyze-start" )->plain() + ); + if ( empty( $this->serverList ) ) { + echo Colors::cEcho( + 'No files on server', + "yellow+bold", + true + ); + echo Colors::cEcho( + wfMessage( "wsps-maintenance-clean-header" )->plain(), + "blue+bold", + true, + "", + wfMessage( "wsps-maintenance-analyze-end" )->plain() + ); + + return; + } + $this->serverList = array_unique( $this->serverList ); + $cntNotDeleted = 0; + foreach ( $this->serverList as $infoFile ) { + if ( !array_key_exists( $infoFile, $this->indexList ) ) { + $this->deleteInfoFile( $infoFile ); + $this->deleteSlotFiles( $infoFile ); + $this->deleteDatFiles( $infoFile ); + } else { + $cntNotDeleted++; + } + } + + echo Colors::cEcho( + wfMessage( "wsps-maintenance-clean-header" )->plain(), + "blue+bold", + true, + "", + wfMessage( "wsps-maintenance-analyze-end" )->plain() + ); + } + + /** + * @param string $file + * @param string $function + * + * @return void + */ + private function echoDeleted( string $file, string $function ): void { + echo Colors::cEcho( + $file, + "yellow", + false, + $function, + "deleted" + ); + } + + /** + * @param string $file + * @param string $function + * + * @return void + */ + private function echoNotDeleted( string $file, string $function ): void { + echo Colors::cEcho( + $file, + "red", + false, + 'Could not be deleted', + $function + ); + } + + /** + * @param string $file + * + * @return void + */ + private function deleteInfoFile( string $file ): void { + $infoFile = $this->exportPath . $file . '.info'; + if ( file_exists( $infoFile ) ) { + if ( unlink( $infoFile ) ) { + $this->echoDeleted( $infoFile, __function__ ); + } else { + $this->echoNotDeleted( $infoFile, __function__ ); + } + } + } + + /** + * @param string $file + * + * @return void + */ + private function deleteSlotFiles( string $file ): void { + $slotFiles = $this->exportPath . $file . '_slot*.wiki'; + $filesList = glob( $slotFiles ); + foreach ( $filesList as $singleFile ) { + if ( unlink( $singleFile ) ) { + $this->echoDeleted( $singleFile, __function__ ); + } else { + $this->echoNotDeleted( $singleFile, __function__ ); + } + } + } + + /** + * @param string $file + * + * @return void + */ + private function deleteDatFiles( string $file ): void { + $dataFiles = $this->exportPath . $file . '.data'; + if ( file_exists( $dataFiles ) ) { + if ( unlink( $dataFiles ) ) { + $this->echoDeleted( $dataFiles, __function__ ); + } else { + $this->echoNotDeleted( $dataFiles, __function__ ); + + } + } + } +} diff --git a/src/Core/PSCore.php b/src/Core/PSCore.php index 0dc9dbc..beea243 100644 --- a/src/Core/PSCore.php +++ b/src/Core/PSCore.php @@ -67,13 +67,18 @@ public static function cleanFileName( string $fname ) : string { } /** + * @param bool $allFiles + * * @return array */ - public static function getFilesFromServer(): array { + public static function getFilesFromServer( bool $allFiles = false ): array { if ( empty( PSConfig::$config ) ) { self::setConfig(); } $path = PSConfig::$config['exportPath']; + if ( $allFiles ) { + return glob( $path . '*.*' ); + } return glob( $path . "*.info" ); }