Merge "Add option to expose original sha1 in thumb url"
[lhc/web/wiklou.git] / maintenance / deleteArchivedFiles.php
index e83edff..bd8ca10 100644 (file)
@@ -1,8 +1,9 @@
 <?php
-
 /**
  * Delete archived (non-current) files from the database
  *
+ * Based on deleteOldRevisions.php by Rob Church.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
+ * @file
  * @ingroup Maintenance
  * @author Aaron Schulz
- * Based on deleteOldRevisions.php by Rob Church
  */
 
-require_once( dirname(__FILE__) . '/Maintenance.php' );
+require_once __DIR__ . '/Maintenance.php';
 
+/**
+ * Maintenance script to delete archived (non-current) files from the database.
+ *
+ * @ingroup Maintenance
+ */
 class DeleteArchivedFiles extends Maintenance {
        public function __construct() {
                parent::__construct();
                $this->mDescription = "Deletes all archived images.";
                $this->addOption( 'delete', 'Perform the deletion' );
+               $this->addOption( 'force', 'Force deletion of rows from filearchive' );
        }
 
-       /**
-        * @todo @fixme FSTransaction/FileStore crap needs removing. Does
-        * not work on trunk
-        */
        public function execute() {
-               if( !$this->hasOption('delete') ) {
+               if ( !$this->hasOption( 'delete' ) ) {
                        $this->output( "Use --delete to actually confirm this script\n" );
                        return;
                }
+
                # Data should come off the master, wrapped in a transaction
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->begin();
-               $tbl_arch = $dbw->tableName( 'filearchive' );
+               $dbw = $this->getDB( DB_MASTER );
+               $dbw->begin( __METHOD__ );
                $repo = RepoGroup::singleton()->getLocalRepo();
+
                # Get "active" revisions from the filearchive table
                $this->output( "Searching for and deleting archived files...\n" );
-               $res = $dbw->query( "SELECT fa_id,fa_storage_group,fa_storage_key FROM $tbl_arch" );
+               $res = $dbw->select(
+                       'filearchive',
+                       array( 'fa_id', 'fa_storage_group', 'fa_storage_key', 'fa_sha1' ),
+                       '',
+                       __METHOD__
+               );
+
                $count = 0;
-               foreach( $res as $row ) {
+               foreach ( $res as $row ) {
                        $key = $row->fa_storage_key;
+                       if ( !strlen( $key ) ) {
+                               $this->output( "Entry with ID {$row->fa_id} has empty key, skipping\n" );
+                               continue;
+                       }
+
                        $group = $row->fa_storage_group;
                        $id = $row->fa_id;
-                       $path = $repo->getZonePath( 'deleted' ).'/'.$repo->getDeletedHashPath($key).$key;
-                       $sha1 = substr( $key, 0, strcspn( $key, '.' ) );
+                       $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
+                       if ( isset( $row->fa_sha1 ) ) {
+                               $sha1 = $row->fa_sha1;
+                       } else {
+                               // old row, populate from key
+                               $sha1 = LocalRepo::getHashFromKey( $key );
+                       }
+
                        // Check if the file is used anywhere...
-                       $inuse = $dbw->selectField( 'oldimage', '1',
-                               array( 'oi_sha1' => $sha1,
-                               'oi_deleted & '.File::DELETED_FILE => File::DELETED_FILE ),
+                       $inuse = $dbw->selectField(
+                               'oldimage',
+                               '1',
+                               array(
+                                       'oi_sha1' => $sha1,
+                                       $dbw->bitAnd( 'oi_deleted', File::DELETED_FILE ) => File::DELETED_FILE
+                               ),
                                __METHOD__,
                                array( 'FOR UPDATE' )
                        );
-                       if ( $path && file_exists($path) && !$inuse ) {
-                               unlink($path); // delete
-                               $count++;
-                               $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" );
-                       } else {
+
+                       $needForce = true;
+                       if ( !$repo->fileExists( $path ) ) {
                                $this->output( "Notice - file '$key' not found in group '$group'\n" );
+                       } elseif ( $inuse ) {
+                               $this->output( "Notice - file '$key' is still in use\n" );
+                       } elseif ( !$repo->quickPurge( $path ) ) {
+                               $this->output( "Unable to remove file $path, skipping\n" );
+                               continue; // don't delete even with --force
+                       } else {
+                               $needForce = false;
+                       }
+
+                       if ( $needForce ) {
+                               if ( $this->hasOption( 'force' ) ) {
+                                       $this->output( "Got --force, deleting DB entry\n" );
+                               } else {
+                                       continue;
+                               }
                        }
+
+                       $count++;
+                       $dbw->delete( 'filearchive', array( 'fa_id' => $id ), __METHOD__ );
                }
-               $dbw->commit();
+
+               $dbw->commit( __METHOD__ );
                $this->output( "Done! [$count file(s)]\n" );
        }
 }
 
 $maintClass = "DeleteArchivedFiles";
-require_once( DO_MAINTENANCE );
+require_once RUN_MAINTENANCE_IF_MAIN;