17require_once __DIR__ .
'/Maintenance.php';
43 parent::__construct();
45 $this->
addDescription(
'Script to update image metadata records' );
50 'Reload metadata from file even if the metadata looks ok',
57 'Only fix really broken records, leave old but still compatible records alone.'
61 'Fix records with an out of date serialization format.'
65 'Enable splitting out large metadata items to the text table. Implies --convert-to-json.'
69 'Output extra information about each upgraded/non-upgraded file.',
74 $this->
addOption(
'start',
'Name of file to start with',
false,
true );
75 $this->
addOption(
'end',
'Name of file to end with',
false,
true );
79 'Only refresh files with this media type, e.g. BITMAP, UNKNOWN etc.',
85 "Only refresh files with this MIME type. Can accept wild-card 'image/*'. "
86 .
"Potentially inefficient unless 'mediatype' is also specified",
92 '(Inefficient!) Only refresh files where the img_metadata field '
93 .
'contains this string. Can be used if its known a specific '
94 .
'property was being extracted incorrectly.',
100 'Time to sleep between each batch (in seconds). Default: 0',
104 $this->
addOption(
'oldimage',
'Run and refresh on oldimage table.' );
109 $brokenOnly = $this->
hasOption(
'broken-only' );
110 $verbose = $this->
hasOption(
'verbose' );
111 $start = $this->
getOption(
'start',
false );
113 $sleep = (int)$this->
getOption(
'sleep', 0 );
114 $reserialize = $this->
hasOption(
'convert-to-json' );
115 $oldimage = $this->
hasOption(
'oldimage' );
119 $fieldPrefix =
'oi_';
120 $queryBuilderTemplate = FileSelectQueryBuilder::newForOldFile( $dbw );
122 $fieldPrefix =
'img_';
123 $queryBuilderTemplate = FileSelectQueryBuilder::newForFile( $dbw );
129 if ( $batchSize <= 0 ) {
130 $this->
fatalError(
"Batch size is too low...", 12 );
132 $repo = $this->newLocalRepo( $force, $brokenOnly, $reserialize, $split );
133 $this->setConditions( $dbw, $queryBuilderTemplate, $fieldPrefix );
134 $queryBuilderTemplate
135 ->orderBy( $fieldPrefix .
'name', SelectQueryBuilder::SORT_ASC )
136 ->limit( $batchSize );
138 $batchCondition = [];
140 if ( $start !==
false ) {
141 $batchCondition[] = $dbw->
expr( $fieldPrefix .
'name',
'>=', $start );
144 $queryBuilder = clone $queryBuilderTemplate;
145 $res = $queryBuilder->
andWhere( $batchCondition )
146 ->caller( __METHOD__ )->fetchResultSet();
147 $nameField = $fieldPrefix .
'name';
148 if ( $res->numRows() > 0 ) {
149 $row1 = $res->current();
150 $this->
output(
"Processing next {$res->numRows()} row(s) starting with {$row1->$nameField}.\n" );
154 foreach ( $res as $row ) {
157 $file = $repo->newFileFromRow( $row );
158 $file->maybeUpgradeRow();
159 if ( $file->getUpgraded() ) {
162 $this->
output(
"Refreshed File:{$row->$nameField}.\n" );
168 $this->
output(
"Forcibly refreshed File:{$row->$nameField}.\n" );
172 $this->
output(
"Skipping File:{$row->$nameField}.\n" );
176 }
catch ( Exception $e ) {
177 $this->
output(
"{$row->$nameField} failed. {$e->getMessage()}\n" );
180 if ( $res->numRows() > 0 ) {
182 $batchCondition = [ $dbw->
expr( $fieldPrefix .
'name',
'>', $row->$nameField ) ];
188 }
while ( $res->numRows() === $batchSize );
190 $total = $upgraded + $leftAlone;
192 $this->
output(
"\nFinished refreshing file metadata for $total files. "
193 .
"$upgraded needed to be refreshed, $leftAlone did not need to "
194 .
"be but were refreshed anyways.\n" );
196 $this->
output(
"\nFinished refreshing file metadata for $total files. "
197 .
"$upgraded were refreshed, $leftAlone were already up to date.\n" );
208 $end = $this->getOption(
'end',
false );
209 $mime = $this->getOption(
'mime',
false );
210 $mediatype = $this->getOption(
'mediatype',
false );
211 $like = $this->getOption(
'metadata-contains',
false );
213 if ( $end !==
false ) {
214 $queryBuilder->
andWhere( $dbw->
expr( $fieldPrefix .
'name',
'<=', $end ) );
216 if ( $mime !==
false ) {
217 [ $major, $minor ] = File::splitMime( $mime );
218 $queryBuilder->
andWhere( [ $fieldPrefix .
'major_mime' => $major ] );
219 if ( $minor !==
'*' ) {
220 $queryBuilder->
andWhere( [ $fieldPrefix .
'minor_mime' => $minor ] );
223 if ( $mediatype !==
false ) {
224 $queryBuilder->
andWhere( [ $fieldPrefix .
'media_type' => $mediatype ] );
228 $dbw->
expr( $fieldPrefix .
'metadata', IExpression::LIKE,
242 private function newLocalRepo( $force, $brokenOnly, $reserialize, $split ):
LocalRepo {
243 if ( $brokenOnly && $force ) {
244 $this->
fatalError(
'Cannot use --broken-only and --force together. ', 2 );
246 $reserialize = $reserialize || $split;
247 if ( $brokenOnly && $reserialize ) {
248 $this->
fatalError(
'Cannot use --broken-only with --convert-to-json or --split. ',
253 'updateCompatibleMetadata' => !$brokenOnly,
255 if ( $reserialize ) {
256 $overrides[
'reserializeMetadata'] =
true;
257 $overrides[
'useJsonMetadata'] =
true;
260 $overrides[
'useSplitMetadata'] =
true;
264 ->newCustomLocalRepo( $overrides );
270require_once RUN_MAINTENANCE_IF_MAIN;
if(!defined('MW_SETUP_CALLBACK'))
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
getBatchSize()
Returns batch size.
output( $out, $channel=null)
Throw some output to the user.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
waitForReplication()
Wait for replica DB servers to catch up.
hasOption( $name)
Checks to see if a particular option was set.
getOption( $name, $default=null)
Get an option, or return the default.
getServiceContainer()
Returns the main service container.
getPrimaryDB(string|false $virtualDomain=false)
addDescription( $text)
Set the description text.
Advanced database interface for IDatabase handles that include maintenance methods.