]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - maintenance/rebuildImages.php
MediaWiki 1.17.0
[autoinstalls/mediawiki.git] / maintenance / rebuildImages.php
1 <?php
2 /**
3  * Script to update image metadata records
4  *
5  * Usage: php rebuildImages.php [--missing] [--dry-run]
6  * Options:
7  *   --missing  Crawl the uploads dir for images without records, and
8  *              add them only.
9  *
10  * Copyright © 2005 Brion Vibber <brion@pobox.com>
11  * http://www.mediawiki.org/
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  * http://www.gnu.org/copyleft/gpl.html
27  *
28  * @file
29  * @author Brion Vibber <brion at pobox.com>
30  * @ingroup maintenance
31  */
32
33 require_once( dirname( __FILE__ ) . '/Maintenance.php' );
34
35 class ImageBuilder extends Maintenance {
36         function __construct() {
37                 parent::__construct();
38
39                 $this->mDescription = 'Script to update image metadata records';
40
41                 $this->addOption( 'missing', 'Check for files without associated database record' );
42                 $this->addOption( 'dry-run', 'Only report, don\'t update the database' );
43         }
44
45         public function execute() {
46                 $this->dbw = wfGetDB( DB_MASTER );
47                 $this->maxLag = 10; # if slaves are lagged more than 10 secs, wait
48                 $this->dryrun = $this->hasOption( 'dry-run' );
49                 if ( $this->dryrun ) {
50                         $GLOBALS['wgReadOnly'] = 'Dry run mode, image upgrades are suppressed';
51                 }
52
53                 if ( $this->hasOption( 'missing' ) ) {
54                         $this->crawlMissing();
55                 } else {
56                         $this->build();
57                 }
58         }
59
60         function getRepo() {
61                 if ( !isset( $this->repo ) ) {
62                         $this->repo = RepoGroup::singleton()->getLocalRepo();
63                 }
64                 return $this->repo;
65         }
66
67         function build() {
68                 $this->buildImage();
69                 $this->buildOldImage();
70         }
71
72         function init( $count, $table ) {
73                 $this->processed = 0;
74                 $this->updated = 0;
75                 $this->count = $count;
76                 $this->startTime = wfTime();
77                 $this->table = $table;
78         }
79
80         function progress( $updated ) {
81                 $this->updated += $updated;
82                 $this->processed++;
83                 if ( $this->processed % 100 != 0 ) {
84                         return;
85                 }
86                 $portion = $this->processed / $this->count;
87                 $updateRate = $this->updated / $this->processed;
88
89                 $now = wfTime();
90                 $delta = $now - $this->startTime;
91                 $estimatedTotalTime = $delta / $portion;
92                 $eta = $this->startTime + $estimatedTotalTime;
93                 $rate = $this->processed / $delta;
94
95                 $this->output( sprintf( "%s: %6.2f%% done on %s; ETA %s [%d/%d] %.2f/sec <%.2f%% updated>\n",
96                         wfTimestamp( TS_DB, intval( $now ) ),
97                         $portion * 100.0,
98                         $this->table,
99                         wfTimestamp( TS_DB, intval( $eta ) ),
100                         $this->processed,
101                         $this->count,
102                         $rate,
103                         $updateRate * 100.0 ) );
104                 flush();
105         }
106
107         function buildTable( $table, $key, $callback ) {
108                 $count = $this->dbw->selectField( $table, 'count(*)', '', __METHOD__ );
109                 $this->init( $count, $table );
110                 $this->output( "Processing $table...\n" );
111
112                 $result = wfGetDB( DB_SLAVE )->select( $table, '*', array(), __METHOD__ );
113
114                 foreach ( $result as $row ) {
115                         $update = call_user_func( $callback, $row, null );
116                         if ( $update ) {
117                                 $this->progress( 1 );
118                         } else {
119                                 $this->progress( 0 );
120                         }
121                 }
122                 $this->output( "Finished $table... $this->updated of $this->processed rows updated\n" );
123         }
124
125         function buildImage() {
126                 $callback = array( $this, 'imageCallback' );
127                 $this->buildTable( 'image', 'img_name', $callback );
128         }
129
130         function imageCallback( $row, $copy ) {
131                 // Create a File object from the row
132                 // This will also upgrade it
133                 $file = $this->getRepo()->newFileFromRow( $row );
134                 return $file->getUpgraded();
135         }
136
137         function buildOldImage() {
138                 $this->buildTable( 'oldimage', 'oi_archive_name',
139                         array( $this, 'oldimageCallback' ) );
140         }
141
142         function oldimageCallback( $row, $copy ) {
143                 // Create a File object from the row
144                 // This will also upgrade it
145                 if ( $row->oi_archive_name == '' ) {
146                         $this->output( "Empty oi_archive_name for oi_name={$row->oi_name}\n" );
147                         return false;
148                 }
149                 $file = $this->getRepo()->newFileFromRow( $row );
150                 return $file->getUpgraded();
151         }
152
153         function crawlMissing() {
154                 $repo = RepoGroup::singleton()->getLocalRepo();
155                 $repo->enumFilesInFS( array( $this, 'checkMissingImage' ) );
156         }
157
158         function checkMissingImage( $fullpath ) {
159                 $filename = wfBaseName( $fullpath );
160                 if ( is_dir( $fullpath ) ) {
161                         return;
162                 }
163                 if ( is_link( $fullpath ) ) {
164                         $this->output( "skipping symlink at $fullpath\n" );
165                         return;
166                 }
167                 $row = $this->dbw->selectRow( 'image',
168                         array( 'img_name' ),
169                         array( 'img_name' => $filename ),
170                         __METHOD__ );
171
172                 if ( $row ) {
173                         // already known, move on
174                         return;
175                 } else {
176                         $this->addMissingImage( $filename, $fullpath );
177                 }
178         }
179
180         function addMissingImage( $filename, $fullpath ) {
181                 $timestamp = $this->dbw->timestamp( filemtime( $fullpath ) );
182
183                 global $wgContLang;
184                 $altname = $wgContLang->checkTitleEncoding( $filename );
185                 if ( $altname != $filename ) {
186                         if ( $this->dryrun ) {
187                                 $filename = $altname;
188                                 $this->output( "Estimating transcoding... $altname\n" );
189                         } else {
190                                 $filename = $this->renameFile( $filename );
191                         }
192                 }
193
194                 if ( $filename == '' ) {
195                         $this->output( "Empty filename for $fullpath\n" );
196                         return;
197                 }
198                 if ( !$this->dryrun ) {
199                         $file = wfLocalFile( $filename );
200                         if ( !$file->recordUpload( '', '(recovered file, missing upload log entry)', '', '', '',
201                                 false, $timestamp ) )
202                         {
203                                 $this->output( "Error uploading file $fullpath\n" );
204                                 return;
205                         }
206                 }
207                 $this->output( $fullpath . "\n" );
208         }
209 }
210
211 $maintClass = 'ImageBuilder';
212 require( RUN_MAINTENANCE_IF_MAIN );