diff options
Diffstat (limited to 'maintenance')
217 files changed, 4180 insertions, 1792 deletions
diff --git a/maintenance/Doxyfile b/maintenance/Doxyfile index b7c1e5e8..b60a1962 100644 --- a/maintenance/Doxyfile +++ b/maintenance/Doxyfile @@ -182,7 +182,7 @@ EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = -INPUT_FILTER = +INPUT_FILTER = "{{INPUT_FILTER}}" FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = @@ -345,8 +345,8 @@ UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES -CALL_GRAPH = YES -CALLER_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png diff --git a/maintenance/Maintenance.php b/maintenance/Maintenance.php index 082cf8be..69d11313 100644 --- a/maintenance/Maintenance.php +++ b/maintenance/Maintenance.php @@ -20,23 +20,24 @@ * @defgroup Maintenance Maintenance */ +// Make sure we're on PHP5.3.2 or better +if ( !function_exists( 'version_compare' ) || version_compare( PHP_VERSION, '5.3.2' ) < 0 ) { + // We need to use dirname( __FILE__ ) here cause __DIR__ is PHP5.3+ + require_once( dirname( __FILE__ ) . '/../includes/PHPVersionError.php' ); + wfPHPVersionError( 'cli' ); +} + /** * @defgroup MaintenanceArchive Maintenance archives * @ingroup Maintenance */ // Define this so scripts can easily find doMaintenance.php -define( 'RUN_MAINTENANCE_IF_MAIN', dirname( __FILE__ ) . '/doMaintenance.php' ); +define( 'RUN_MAINTENANCE_IF_MAIN', __DIR__ . '/doMaintenance.php' ); define( 'DO_MAINTENANCE', RUN_MAINTENANCE_IF_MAIN ); // original name, harmless $maintClass = false; -// Make sure we're on PHP5 or better -if ( !function_exists( 'version_compare' ) || version_compare( PHP_VERSION, '5.2.3' ) < 0 ) { - require_once( dirname( __FILE__ ) . '/../includes/PHPVersionError.php' ); - wfPHPVersionError( 'cli' ); -} - /** * Abstract maintenance class for quickly writing and churning out * maintenance scripts with minimal effort. All that _must_ be defined @@ -101,7 +102,10 @@ abstract class Maintenance { // Generic options which might or not be supported by the script private $mDependantParameters = array(); - // Used by getDD() / setDB() + /** + * Used by getDD() / setDB() + * @var DatabaseBase + */ private $mDb = null; /** @@ -120,7 +124,7 @@ abstract class Maintenance { global $IP; $IP = strval( getenv( 'MW_INSTALL_PATH' ) ) !== '' ? getenv( 'MW_INSTALL_PATH' ) - : realpath( dirname( __FILE__ ) . '/..' ); + : realpath( __DIR__ . '/..' ); $this->addDefaultParams(); register_shutdown_function( array( $this, 'outputChanneled' ), false ); @@ -297,6 +301,9 @@ abstract class Maintenance { return rtrim( $input ); } + /** + * @return bool + */ public function isQuiet() { return $this->mQuiet; } @@ -314,11 +321,7 @@ abstract class Maintenance { } if ( $channel === null ) { $this->cleanupChanneled(); - if( php_sapi_name() == 'cli' ) { - fwrite( STDOUT, $out ); - } else { - print( $out ); - } + print( $out ); } else { $out = preg_replace( '/\n\z/', '', $out ); $this->outputChanneled( $out, $channel ); @@ -352,11 +355,7 @@ abstract class Maintenance { */ public function cleanupChanneled() { if ( !$this->atLineStart ) { - if( php_sapi_name() == 'cli' ) { - fwrite( STDOUT, "\n" ); - } else { - print "\n"; - } + print "\n"; $this->atLineStart = true; } } @@ -366,7 +365,7 @@ abstract class Maintenance { * same channel are concatenated, but any intervening messages in another * channel start a new line. * @param $msg String: the message without trailing newline - * @param $channel Channel identifier or null for no + * @param $channel string Channel identifier or null for no * channel. Channel comparison uses ===. */ public function outputChanneled( $msg, $channel = null ) { @@ -375,31 +374,17 @@ abstract class Maintenance { return; } - $cli = php_sapi_name() == 'cli'; - // End the current line if necessary if ( !$this->atLineStart && $channel !== $this->lastChannel ) { - if( $cli ) { - fwrite( STDOUT, "\n" ); - } else { - print "\n"; - } + print "\n"; } - if( $cli ) { - fwrite( STDOUT, $msg ); - } else { - print $msg; - } + print $msg; $this->atLineStart = false; if ( $channel === null ) { // For unchanneled messages, output trailing newline immediately - if( $cli ) { - fwrite( STDOUT, "\n" ); - } else { - print "\n"; - } + print "\n"; $this->atLineStart = true; } $this->lastChannel = $channel; @@ -951,7 +936,7 @@ abstract class Maintenance { public function purgeRedundantText( $delete = true ) { # Data should come off the master, wrapped in a transaction $dbw = $this->getDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $tbl_arc = $dbw->tableName( 'archive' ); $tbl_rev = $dbw->tableName( 'revision' ); @@ -996,7 +981,7 @@ abstract class Maintenance { } # Done - $dbw->commit(); + $dbw->commit( __METHOD__ ); } /** @@ -1004,7 +989,7 @@ abstract class Maintenance { * @return string */ protected function getDir() { - return dirname( __FILE__ ); + return __DIR__; } /** @@ -1025,10 +1010,9 @@ abstract class Maintenance { protected static function getCoreScripts() { if ( !self::$mCoreScripts ) { $paths = array( - dirname( __FILE__ ), - dirname( __FILE__ ) . '/gearman', - dirname( __FILE__ ) . '/language', - dirname( __FILE__ ) . '/storage', + __DIR__, + __DIR__ . '/language', + __DIR__ . '/storage', ); self::$mCoreScripts = array(); foreach ( $paths as $p ) { @@ -1080,7 +1064,7 @@ abstract class Maintenance { /** * Lock the search index - * @param &$db Database object + * @param &$db DatabaseBase object */ private function lockSearchindex( &$db ) { $write = array( 'searchindex' ); @@ -1090,7 +1074,7 @@ abstract class Maintenance { /** * Unlock the tables - * @param &$db Database object + * @param &$db DatabaseBase object */ private function unlockSearchindex( &$db ) { $db->unlockTables( __CLASS__ . '::' . __METHOD__ ); @@ -1099,7 +1083,7 @@ abstract class Maintenance { /** * Unlock and lock again * Since the lock is low-priority, queued reads will be able to complete - * @param &$db Database object + * @param &$db DatabaseBase object */ private function relockSearchindex( &$db ) { $this->unlockSearchindex( $db ); @@ -1147,7 +1131,7 @@ abstract class Maintenance { /** * Update the searchindex table for a given pageid - * @param $dbw Database: a database write handle + * @param $dbw DatabaseBase a database write handle * @param $pageId Integer: the page ID to update. * @return null|string */ diff --git a/maintenance/archives/patch-cat_hidden.sql b/maintenance/archives/patch-cat_hidden.sql new file mode 100644 index 00000000..933188ce --- /dev/null +++ b/maintenance/archives/patch-cat_hidden.sql @@ -0,0 +1,3 @@ +-- cat_hidden is no longer used, delete it + +ALTER TABLE /*$wgDBprefix*/category DROP COLUMN cat_hidden; diff --git a/maintenance/archives/patch-filejournal.sql b/maintenance/archives/patch-filejournal.sql new file mode 100644 index 00000000..4356d70d --- /dev/null +++ b/maintenance/archives/patch-filejournal.sql @@ -0,0 +1,20 @@ +-- File backend operation journal +CREATE TABLE /*_*/filejournal ( + -- Unique ID for each file operation + fj_id bigint unsigned NOT NULL PRIMARY KEY auto_increment, + -- UUID of the batch this operation belongs to + fj_batch_uuid varbinary(32) NOT NULL, + -- The registered file backend name + fj_backend varchar(255) NOT NULL, + -- The storage path that was affected (may be internal paths) + fj_path blob NOT NULL, + -- Primitive operation description (create/update/delete) + fj_op varchar(16) NOT NULL default '', + -- SHA-1 file content hash in base-36 + fj_new_sha1 varbinary(32) NOT NULL default '', + -- Timestamp of the batch operation + fj_timestamp varbinary(14) NOT NULL default '' +) /*$wgDBTableOptions*/; + +CREATE INDEX /*i*/fj_batch_id ON /*_*/filejournal (fj_batch_uuid); +CREATE INDEX /*i*/fj_timestamp ON /*_*/filejournal (fj_timestamp); diff --git a/maintenance/archives/patch-ipb-parent-block-id-index.sql b/maintenance/archives/patch-ipb-parent-block-id-index.sql new file mode 100644 index 00000000..1f413f37 --- /dev/null +++ b/maintenance/archives/patch-ipb-parent-block-id-index.sql @@ -0,0 +1,2 @@ +-- index for ipblocks.ipb_parent_block_id +CREATE INDEX /*i*/ipb_parent_block_id ON /*_*/ipblocks (ipb_parent_block_id); diff --git a/maintenance/archives/patch-ipb-parent-block-id.sql b/maintenance/archives/patch-ipb-parent-block-id.sql new file mode 100644 index 00000000..8ebcf786 --- /dev/null +++ b/maintenance/archives/patch-ipb-parent-block-id.sql @@ -0,0 +1,3 @@ +-- Adding ipb_parent_block_id to track the block that caused an autoblock +ALTER TABLE /*$wgDBprefix*/ipblocks + ADD ipb_parent_block_id int DEFAULT NULL; diff --git a/maintenance/archives/patch-revision-user-page-index.sql b/maintenance/archives/patch-revision-user-page-index.sql new file mode 100644 index 00000000..a4554c8f --- /dev/null +++ b/maintenance/archives/patch-revision-user-page-index.sql @@ -0,0 +1,4 @@ +-- New index on revision table to allow searches for all edits by a given user +-- to a given page. Added 2007-08-28 + +CREATE INDEX /*i*/page_user_timestamp ON /*_*/revision (rev_page,rev_user,rev_timestamp); diff --git a/maintenance/archives/upgradeLogging.php b/maintenance/archives/upgradeLogging.php index 1765bd9f..2c28011b 100644 --- a/maintenance/archives/upgradeLogging.php +++ b/maintenance/archives/upgradeLogging.php @@ -1,6 +1,6 @@ <?php /** - * Replication-safe online upgrade script for log_id/log_deleted + * Replication-safe online upgrade for log_id/log_deleted fields. * * 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 @@ -21,8 +21,14 @@ * @ingroup MaintenanceArchive */ -require( dirname( __FILE__ ) . '/../commandLine.inc' ); +require( __DIR__ . '/../commandLine.inc' ); +/** + * Maintenance script that upgrade for log_id/log_deleted fields in a + * replication-safe way. + * + * @ingroup Maintenance + */ class UpdateLogging { /** @@ -63,21 +69,21 @@ CREATE TABLE $logging_1_10 ( -- action field, but only the type controls categorization. log_type varbinary(10) NOT NULL default '', log_action varbinary(10) NOT NULL default '', - + -- Timestamp. Duh. log_timestamp binary(14) NOT NULL default '19700101000000', - + -- The user who performed this action; key to user_id log_user int unsigned NOT NULL default 0, - + -- Key to the page affected. Where a user is the target, -- this will point to the user page. log_namespace int NOT NULL default 0, log_title varchar(255) binary NOT NULL default '', - + -- Freeform text. Interpreted as edit history comments. log_comment varchar(255) NOT NULL default '', - + -- LF separated list of miscellaneous parameters log_params blob NOT NULL, @@ -124,7 +130,7 @@ EOT; $minTs = $this->dbw->selectField( $srcTable, 'MIN(log_timestamp)', false, __METHOD__ ); $minTsUnix = wfTimestamp( TS_UNIX, $minTs ); $numRowsCopied = 0; - + while ( true ) { $maxTs = $this->dbw->selectField( $srcTable, 'MAX(log_timestamp)', false, __METHOD__ ); $copyPos = $this->dbw->selectField( $dstTable, 'MAX(log_timestamp)', false, __METHOD__ ); @@ -137,7 +143,7 @@ EOT; $percent = ( $copyPosUnix - $minTsUnix ) / ( $maxTsUnix - $minTsUnix ) * 100; } printf( "%s %.2f%%\n", $copyPos, $percent ); - + # Handle all entries with timestamp equal to $copyPos if ( $copyPos !== null ) { $numRowsCopied += $this->copyExactMatch( $srcTable, $dstTable, $copyPos ); diff --git a/maintenance/attachLatest.php b/maintenance/attachLatest.php index 6e09671a..475cafc9 100644 --- a/maintenance/attachLatest.php +++ b/maintenance/attachLatest.php @@ -1,7 +1,6 @@ <?php /** - * quick hackjob to fix damages imports on wikisource - * page records have page_latest wrong + * Corrects wrong values in the `page_latest` field in the database. * * Copyright © 2005 Brion Vibber <brion@pobox.com> * http://www.mediawiki.org/ @@ -25,8 +24,14 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to correct wrong values in the `page_latest` field + * in the database. + * + * @ingroup Maintenance + */ class AttachLatest extends Maintenance { public function __construct() { diff --git a/maintenance/backup.inc b/maintenance/backup.inc index 9f67a1ac..e3dc488b 100644 --- a/maintenance/backup.inc +++ b/maintenance/backup.inc @@ -28,7 +28,7 @@ * @ingroup Dump Maintenance */ class DumpDBZip2Output extends DumpPipeOutput { - function DumpDBZip2Output( $file ) { + function __construct( $file ) { parent::__construct( "dbzip2", $file ); } } @@ -61,6 +61,15 @@ class BackupDumper { var $outputTypes = array(), $filterTypes = array(); /** + * The dependency-injected database to use. + * + * @var DatabaseBase|null + * + * @see self::setDb + */ + protected $forcedDb = null; + + /** * @var LoadBalancer */ protected $lb; @@ -245,9 +254,12 @@ class BackupDumper { $table = ( $history == WikiExporter::CURRENT ) ? 'page' : 'revision'; $field = ( $history == WikiExporter::CURRENT ) ? 'page_id' : 'rev_id'; - $dbr = wfGetDB( DB_SLAVE ); + $dbr = $this->forcedDb; + if ( $this->forcedDb === null ) { + $dbr = wfGetDB( DB_SLAVE ); + } $this->maxCount = $dbr->selectField( $table, "MAX($field)", '', __METHOD__ ); - $this->startTime = wfTime(); + $this->startTime = microtime( true ); $this->lastTime = $this->startTime; $this->ID = getmypid(); } @@ -259,16 +271,32 @@ class BackupDumper { * @return DatabaseBase */ function backupDb() { + if ( $this->forcedDb !== null ) { + return $this->forcedDb; + } + $this->lb = wfGetLBFactory()->newMainLB(); $db = $this->lb->getConnection( DB_SLAVE, 'backup' ); // Discourage the server from disconnecting us if it takes a long time // to read out the big ol' batch query. - $db->setTimeout( 3600 * 24 ); + $db->setSessionOptions( array( 'connTimeout' => 3600 * 24 ) ); return $db; } + /** + * Force the dump to use the provided database connection for database + * operations, wherever possible. + * + * @param $db DatabaseBase|null: (Optional) the database connection to + * use. If null, resort to use the globally provided ways to + * get database connections. + */ + function setDb( DatabaseBase $db = null ) { + $this->forcedDb = $db; + } + function __destruct() { if ( isset( $this->lb ) ) { $this->lb->closeAll(); @@ -300,9 +328,9 @@ class BackupDumper { function showReport() { if ( $this->reporting ) { $now = wfTimestamp( TS_DB ); - $nowts = wfTime(); - $deltaAll = wfTime() - $this->startTime; - $deltaPart = wfTime() - $this->lastTime; + $nowts = microtime( true ); + $deltaAll = $nowts - $this->startTime; + $deltaPart = $nowts - $this->lastTime; $this->pageCountPart = $this->pageCount - $this->pageCountLast; $this->revCountPart = $this->revCount - $this->revCountLast; diff --git a/maintenance/backupTextPass.inc b/maintenance/backupTextPass.inc new file mode 100644 index 00000000..f1f09546 --- /dev/null +++ b/maintenance/backupTextPass.inc @@ -0,0 +1,794 @@ +<?php +/** + * BackupDumper that postprocesses XML dumps from dumpBackup.php to add page text + * + * Copyright (C) 2005 Brion Vibber <brion@pobox.com> + * http://www.mediawiki.org/ + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Maintenance + */ + +require_once( __DIR__ . '/backup.inc' ); + +/** + * @ingroup Maintenance + */ +class TextPassDumper extends BackupDumper { + var $prefetch = null; + var $input = "php://stdin"; + var $history = WikiExporter::FULL; + var $fetchCount = 0; + var $prefetchCount = 0; + var $prefetchCountLast = 0; + var $fetchCountLast = 0; + + var $maxFailures = 5; + var $maxConsecutiveFailedTextRetrievals = 200; + var $failureTimeout = 5; // Seconds to sleep after db failure + + var $php = "php"; + var $spawn = false; + + /** + * @var bool|resource + */ + var $spawnProc = false; + + /** + * @var bool|resource + */ + var $spawnWrite = false; + + /** + * @var bool|resource + */ + var $spawnRead = false; + + /** + * @var bool|resource + */ + var $spawnErr = false; + + var $xmlwriterobj = false; + + // when we spend more than maxTimeAllowed seconds on this run, we continue + // processing until we write out the next complete page, then save output file(s), + // rename it/them and open new one(s) + var $maxTimeAllowed = 0; // 0 = no limit + var $timeExceeded = false; + var $firstPageWritten = false; + var $lastPageWritten = false; + var $checkpointJustWritten = false; + var $checkpointFiles = array(); + + /** + * @var DatabaseBase + */ + protected $db; + + + /** + * Drop the database connection $this->db and try to get a new one. + * + * This function tries to get a /different/ connection if this is + * possible. Hence, (if this is possible) it switches to a different + * failover upon each call. + * + * This function resets $this->lb and closes all connections on it. + * + * @throws MWException + */ + function rotateDb() { + // Cleaning up old connections + if ( isset( $this->lb ) ) { + $this->lb->closeAll(); + unset( $this->lb ); + } + + if ( $this->forcedDb !== null ) { + $this->db = $this->forcedDb; + return; + } + + if ( isset( $this->db ) && $this->db->isOpen() ) { + throw new MWException( 'DB is set and has not been closed by the Load Balancer' ); + } + + unset( $this->db ); + + // Trying to set up new connection. + // We do /not/ retry upon failure, but delegate to encapsulating logic, to avoid + // individually retrying at different layers of code. + + // 1. The LoadBalancer. + try { + $this->lb = wfGetLBFactory()->newMainLB(); + } catch ( Exception $e ) { + throw new MWException( __METHOD__ . " rotating DB failed to obtain new load balancer (" . $e->getMessage() . ")" ); + } + + + // 2. The Connection, through the load balancer. + try { + $this->db = $this->lb->getConnection( DB_SLAVE, 'backup' ); + } catch ( Exception $e ) { + throw new MWException( __METHOD__ . " rotating DB failed to obtain new database (" . $e->getMessage() . ")" ); + } + } + + + function initProgress( $history = WikiExporter::FULL ) { + parent::initProgress(); + $this->timeOfCheckpoint = $this->startTime; + } + + function dump( $history, $text = WikiExporter::TEXT ) { + // Notice messages will foul up your XML output even if they're + // relatively harmless. + if ( ini_get( 'display_errors' ) ) + ini_set( 'display_errors', 'stderr' ); + + $this->initProgress( $this->history ); + + // We are trying to get an initial database connection to avoid that the + // first try of this request's first call to getText fails. However, if + // obtaining a good DB connection fails it's not a serious issue, as + // getText does retry upon failure and can start without having a working + // DB connection. + try { + $this->rotateDb(); + } catch ( Exception $e ) { + // We do not even count this as failure. Just let eventual + // watchdogs know. + $this->progress( "Getting initial DB connection failed (" . + $e->getMessage() . ")" ); + } + + $this->egress = new ExportProgressFilter( $this->sink, $this ); + + // it would be nice to do it in the constructor, oh well. need egress set + $this->finalOptionCheck(); + + // we only want this so we know how to close a stream :-P + $this->xmlwriterobj = new XmlDumpWriter(); + + $input = fopen( $this->input, "rt" ); + $result = $this->readDump( $input ); + + if ( $this->spawnProc ) { + $this->closeSpawn(); + } + + $this->report( true ); + } + + function processOption( $opt, $val, $param ) { + global $IP; + $url = $this->processFileOpt( $val, $param ); + + switch( $opt ) { + case 'prefetch': + require_once "$IP/maintenance/backupPrefetch.inc"; + $this->prefetch = new BaseDump( $url ); + break; + case 'stub': + $this->input = $url; + break; + case 'maxtime': + $this->maxTimeAllowed = intval( $val ) * 60; + break; + case 'checkpointfile': + $this->checkpointFiles[] = $val; + break; + case 'current': + $this->history = WikiExporter::CURRENT; + break; + case 'full': + $this->history = WikiExporter::FULL; + break; + case 'spawn': + $this->spawn = true; + if ( $val ) { + $this->php = $val; + } + break; + } + } + + function processFileOpt( $val, $param ) { + $fileURIs = explode( ';', $param ); + foreach ( $fileURIs as $URI ) { + switch( $val ) { + case "file": + $newURI = $URI; + break; + case "gzip": + $newURI = "compress.zlib://$URI"; + break; + case "bzip2": + $newURI = "compress.bzip2://$URI"; + break; + case "7zip": + $newURI = "mediawiki.compress.7z://$URI"; + break; + default: + $newURI = $URI; + } + $newFileURIs[] = $newURI; + } + $val = implode( ';', $newFileURIs ); + return $val; + } + + /** + * Overridden to include prefetch ratio if enabled. + */ + function showReport() { + if ( !$this->prefetch ) { + parent::showReport(); + return; + } + + if ( $this->reporting ) { + $now = wfTimestamp( TS_DB ); + $nowts = microtime( true ); + $deltaAll = $nowts - $this->startTime; + $deltaPart = $nowts - $this->lastTime; + $this->pageCountPart = $this->pageCount - $this->pageCountLast; + $this->revCountPart = $this->revCount - $this->revCountLast; + + if ( $deltaAll ) { + $portion = $this->revCount / $this->maxCount; + $eta = $this->startTime + $deltaAll / $portion; + $etats = wfTimestamp( TS_DB, intval( $eta ) ); + if ( $this->fetchCount ) { + $fetchRate = 100.0 * $this->prefetchCount / $this->fetchCount; + } else { + $fetchRate = '-'; + } + $pageRate = $this->pageCount / $deltaAll; + $revRate = $this->revCount / $deltaAll; + } else { + $pageRate = '-'; + $revRate = '-'; + $etats = '-'; + $fetchRate = '-'; + } + if ( $deltaPart ) { + if ( $this->fetchCountLast ) { + $fetchRatePart = 100.0 * $this->prefetchCountLast / $this->fetchCountLast; + } else { + $fetchRatePart = '-'; + } + $pageRatePart = $this->pageCountPart / $deltaPart; + $revRatePart = $this->revCountPart / $deltaPart; + + } else { + $fetchRatePart = '-'; + $pageRatePart = '-'; + $revRatePart = '-'; + } + $this->progress( sprintf( "%s: %s (ID %d) %d pages (%0.1f|%0.1f/sec all|curr), %d revs (%0.1f|%0.1f/sec all|curr), %0.1f%%|%0.1f%% prefetched (all|curr), ETA %s [max %d]", + $now, wfWikiID(), $this->ID, $this->pageCount, $pageRate, $pageRatePart, $this->revCount, $revRate, $revRatePart, $fetchRate, $fetchRatePart, $etats, $this->maxCount ) ); + $this->lastTime = $nowts; + $this->revCountLast = $this->revCount; + $this->prefetchCountLast = $this->prefetchCount; + $this->fetchCountLast = $this->fetchCount; + } + } + + function setTimeExceeded() { + $this->timeExceeded = True; + } + + function checkIfTimeExceeded() { + if ( $this->maxTimeAllowed && ( $this->lastTime - $this->timeOfCheckpoint > $this->maxTimeAllowed ) ) { + return true; + } + return false; + } + + function finalOptionCheck() { + if ( ( $this->checkpointFiles && ! $this->maxTimeAllowed ) || + ( $this->maxTimeAllowed && !$this->checkpointFiles ) ) { + throw new MWException( "Options checkpointfile and maxtime must be specified together.\n" ); + } + foreach ( $this->checkpointFiles as $checkpointFile ) { + $count = substr_count ( $checkpointFile, "%s" ); + if ( $count != 2 ) { + throw new MWException( "Option checkpointfile must contain two '%s' for substitution of first and last pageids, count is $count instead, file is $checkpointFile.\n" ); + } + } + + if ( $this->checkpointFiles ) { + $filenameList = (array)$this->egress->getFilenames(); + if ( count( $filenameList ) != count( $this->checkpointFiles ) ) { + throw new MWException( "One checkpointfile must be specified for each output option, if maxtime is used.\n" ); + } + } + } + + /** + * @throws MWException Failure to parse XML input + * @return true + */ + function readDump( $input ) { + $this->buffer = ""; + $this->openElement = false; + $this->atStart = true; + $this->state = ""; + $this->lastName = ""; + $this->thisPage = 0; + $this->thisRev = 0; + + $parser = xml_parser_create( "UTF-8" ); + xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false ); + + xml_set_element_handler( $parser, array( &$this, 'startElement' ), array( &$this, 'endElement' ) ); + xml_set_character_data_handler( $parser, array( &$this, 'characterData' ) ); + + $offset = 0; // for context extraction on error reporting + $bufferSize = 512 * 1024; + do { + if ( $this->checkIfTimeExceeded() ) { + $this->setTimeExceeded(); + } + $chunk = fread( $input, $bufferSize ); + if ( !xml_parse( $parser, $chunk, feof( $input ) ) ) { + wfDebug( "TextDumpPass::readDump encountered XML parsing error\n" ); + + $byte = xml_get_current_byte_index( $parser ); + $msg = wfMessage( 'xml-error-string', + 'XML import parse failure', + xml_get_current_line_number( $parser ), + xml_get_current_column_number( $parser ), + $byte . ( is_null( $chunk ) ? null : ( '; "' . substr( $chunk, $byte -$offset, 16 ) . '"' ) ), + xml_error_string( xml_get_error_code( $parser ) ) )->escaped(); + + xml_parser_free( $parser ); + + throw new MWException( $msg ); + } + $offset += strlen( $chunk ); + } while ( $chunk !== false && !feof( $input ) ); + if ( $this->maxTimeAllowed ) { + $filenameList = (array)$this->egress->getFilenames(); + // we wrote some stuff after last checkpoint that needs renamed + if ( file_exists( $filenameList[0] ) ) { + $newFilenames = array(); + # we might have just written the header and footer and had no + # pages or revisions written... perhaps they were all deleted + # there's no pageID 0 so we use that. the caller is responsible + # for deciding what to do with a file containing only the + # siteinfo information and the mw tags. + if ( ! $this->firstPageWritten ) { + $firstPageID = str_pad( 0, 9, "0", STR_PAD_LEFT ); + $lastPageID = str_pad( 0, 9, "0", STR_PAD_LEFT ); + } + else { + $firstPageID = str_pad( $this->firstPageWritten, 9, "0", STR_PAD_LEFT ); + $lastPageID = str_pad( $this->lastPageWritten, 9, "0", STR_PAD_LEFT ); + } + for ( $i = 0; $i < count( $filenameList ); $i++ ) { + $checkpointNameFilledIn = sprintf( $this->checkpointFiles[$i], $firstPageID, $lastPageID ); + $fileinfo = pathinfo( $filenameList[$i] ); + $newFilenames[] = $fileinfo['dirname'] . '/' . $checkpointNameFilledIn; + } + $this->egress->closeAndRename( $newFilenames ); + } + } + xml_parser_free( $parser ); + + return true; + } + + /** + * Tries to get the revision text for a revision id. + * + * Upon errors, retries (Up to $this->maxFailures tries each call). + * If still no good revision get could be found even after this retrying, "" is returned. + * If no good revision text could be returned for + * $this->maxConsecutiveFailedTextRetrievals consecutive calls to getText, MWException + * is thrown. + * + * @param $id string The revision id to get the text for + * + * @return string The revision text for $id, or "" + * @throws MWException + */ + function getText( $id ) { + $prefetchNotTried = true; // Whether or not we already tried to get the text via prefetch. + $text = false; // The candidate for a good text. false if no proper value. + $failures = 0; // The number of times, this invocation of getText already failed. + + static $consecutiveFailedTextRetrievals = 0; // The number of times getText failed without + // yielding a good text in between. + + $this->fetchCount++; + + // To allow to simply return on success and do not have to worry about book keeping, + // we assume, this fetch works (possible after some retries). Nevertheless, we koop + // the old value, so we can restore it, if problems occur (See after the while loop). + $oldConsecutiveFailedTextRetrievals = $consecutiveFailedTextRetrievals; + $consecutiveFailedTextRetrievals = 0; + + while ( $failures < $this->maxFailures ) { + + // As soon as we found a good text for the $id, we will return immediately. + // Hence, if we make it past the try catch block, we know that we did not + // find a good text. + + try { + // Step 1: Get some text (or reuse from previous iteratuon if checking + // for plausibility failed) + + // Trying to get prefetch, if it has not been tried before + if ( $text === false && isset( $this->prefetch ) && $prefetchNotTried ) { + $prefetchNotTried = false; + $tryIsPrefetch = true; + $text = $this->prefetch->prefetch( intval( $this->thisPage ), + intval( $this->thisRev ) ); + if ( $text === null ) { + $text = false; + } + } + + if ( $text === false ) { + // Fallback to asking the database + $tryIsPrefetch = false; + if ( $this->spawn ) { + $text = $this->getTextSpawned( $id ); + } else { + $text = $this->getTextDb( $id ); + } + + // No more checks for texts from DB for now. + // If we received something that is not false, + // We treat it as good text, regardless of whether it actually is or is not + if ( $text !== false ) { + return $text; + } + } + + if ( $text === false ) { + throw new MWException( "Generic error while obtaining text for id " . $id ); + } + + // We received a good candidate for the text of $id via some method + + // Step 2: Checking for plausibility and return the text if it is + // plausible + $revID = intval( $this->thisRev ); + if ( ! isset( $this->db ) ) { + throw new MWException( "No database available" ); + } + $revLength = $this->db->selectField( 'revision', 'rev_len', array( 'rev_id' => $revID ) ); + if ( strlen( $text ) == $revLength ) { + if ( $tryIsPrefetch ) { + $this->prefetchCount++; + } + return $text; + } + + $text = false; + throw new MWException( "Received text is unplausible for id " . $id ); + + } catch ( Exception $e ) { + $msg = "getting/checking text " . $id . " failed (" . $e->getMessage() . ")"; + if ( $failures + 1 < $this->maxFailures ) { + $msg .= " (Will retry " . ( $this->maxFailures - $failures - 1 ) . " more times)"; + } + $this->progress( $msg ); + } + + // Something went wrong; we did not a text that was plausible :( + $failures++; + + // A failure in a prefetch hit does not warrant resetting db connection etc. + if ( ! $tryIsPrefetch ) { + // After backing off for some time, we try to reboot the whole process as + // much as possible to not carry over failures from one part to the other + // parts + sleep( $this->failureTimeout ); + try { + $this->rotateDb(); + if ( $this->spawn ) { + $this->closeSpawn(); + $this->openSpawn(); + } + } catch ( Exception $e ) { + $this->progress( "Rebooting getText infrastructure failed (" . $e->getMessage() . ")" . + " Trying to continue anyways" ); + } + } + } + + // Retirieving a good text for $id failed (at least) maxFailures times. + // We abort for this $id. + + // Restoring the consecutive failures, and maybe aborting, if the dump + // is too broken. + $consecutiveFailedTextRetrievals = $oldConsecutiveFailedTextRetrievals + 1; + if ( $consecutiveFailedTextRetrievals > $this->maxConsecutiveFailedTextRetrievals ) { + throw new MWException( "Graceful storage failure" ); + } + + return ""; + } + + + /** + * May throw a database error if, say, the server dies during query. + * @param $id + * @return bool|string + * @throws MWException + */ + private function getTextDb( $id ) { + global $wgContLang; + if ( ! isset( $this->db ) ) { + throw new MWException( __METHOD__ . "No database available" ); + } + $row = $this->db->selectRow( 'text', + array( 'old_text', 'old_flags' ), + array( 'old_id' => $id ), + __METHOD__ ); + $text = Revision::getRevisionText( $row ); + if ( $text === false ) { + return false; + } + $stripped = str_replace( "\r", "", $text ); + $normalized = $wgContLang->normalize( $stripped ); + return $normalized; + } + + private function getTextSpawned( $id ) { + wfSuppressWarnings(); + if ( !$this->spawnProc ) { + // First time? + $this->openSpawn(); + } + $text = $this->getTextSpawnedOnce( $id ); + wfRestoreWarnings(); + return $text; + } + + function openSpawn() { + global $IP; + + if ( file_exists( "$IP/../multiversion/MWScript.php" ) ) { + $cmd = implode( " ", + array_map( 'wfEscapeShellArg', + array( + $this->php, + "$IP/../multiversion/MWScript.php", + "fetchText.php", + '--wiki', wfWikiID() ) ) ); + } + else { + $cmd = implode( " ", + array_map( 'wfEscapeShellArg', + array( + $this->php, + "$IP/maintenance/fetchText.php", + '--wiki', wfWikiID() ) ) ); + } + $spec = array( + 0 => array( "pipe", "r" ), + 1 => array( "pipe", "w" ), + 2 => array( "file", "/dev/null", "a" ) ); + $pipes = array(); + + $this->progress( "Spawning database subprocess: $cmd" ); + $this->spawnProc = proc_open( $cmd, $spec, $pipes ); + if ( !$this->spawnProc ) { + // shit + $this->progress( "Subprocess spawn failed." ); + return false; + } + list( + $this->spawnWrite, // -> stdin + $this->spawnRead, // <- stdout + ) = $pipes; + + return true; + } + + private function closeSpawn() { + wfSuppressWarnings(); + if ( $this->spawnRead ) + fclose( $this->spawnRead ); + $this->spawnRead = false; + if ( $this->spawnWrite ) + fclose( $this->spawnWrite ); + $this->spawnWrite = false; + if ( $this->spawnErr ) + fclose( $this->spawnErr ); + $this->spawnErr = false; + if ( $this->spawnProc ) + pclose( $this->spawnProc ); + $this->spawnProc = false; + wfRestoreWarnings(); + } + + private function getTextSpawnedOnce( $id ) { + global $wgContLang; + + $ok = fwrite( $this->spawnWrite, "$id\n" ); + // $this->progress( ">> $id" ); + if ( !$ok ) return false; + + $ok = fflush( $this->spawnWrite ); + // $this->progress( ">> [flush]" ); + if ( !$ok ) return false; + + // check that the text id they are sending is the one we asked for + // this avoids out of sync revision text errors we have encountered in the past + $newId = fgets( $this->spawnRead ); + if ( $newId === false ) { + return false; + } + if ( $id != intval( $newId ) ) { + return false; + } + + $len = fgets( $this->spawnRead ); + // $this->progress( "<< " . trim( $len ) ); + if ( $len === false ) return false; + + $nbytes = intval( $len ); + // actual error, not zero-length text + if ( $nbytes < 0 ) return false; + + $text = ""; + + // Subprocess may not send everything at once, we have to loop. + while ( $nbytes > strlen( $text ) ) { + $buffer = fread( $this->spawnRead, $nbytes - strlen( $text ) ); + if ( $buffer === false ) break; + $text .= $buffer; + } + + $gotbytes = strlen( $text ); + if ( $gotbytes != $nbytes ) { + $this->progress( "Expected $nbytes bytes from database subprocess, got $gotbytes " ); + return false; + } + + // Do normalization in the dump thread... + $stripped = str_replace( "\r", "", $text ); + $normalized = $wgContLang->normalize( $stripped ); + return $normalized; + } + + function startElement( $parser, $name, $attribs ) { + $this->checkpointJustWritten = false; + + $this->clearOpenElement( null ); + $this->lastName = $name; + + if ( $name == 'revision' ) { + $this->state = $name; + $this->egress->writeOpenPage( null, $this->buffer ); + $this->buffer = ""; + } elseif ( $name == 'page' ) { + $this->state = $name; + if ( $this->atStart ) { + $this->egress->writeOpenStream( $this->buffer ); + $this->buffer = ""; + $this->atStart = false; + } + } + + if ( $name == "text" && isset( $attribs['id'] ) ) { + $text = $this->getText( $attribs['id'] ); + $this->openElement = array( $name, array( 'xml:space' => 'preserve' ) ); + if ( strlen( $text ) > 0 ) { + $this->characterData( $parser, $text ); + } + } else { + $this->openElement = array( $name, $attribs ); + } + } + + function endElement( $parser, $name ) { + $this->checkpointJustWritten = false; + + if ( $this->openElement ) { + $this->clearOpenElement( "" ); + } else { + $this->buffer .= "</$name>"; + } + + if ( $name == 'revision' ) { + $this->egress->writeRevision( null, $this->buffer ); + $this->buffer = ""; + $this->thisRev = ""; + } elseif ( $name == 'page' ) { + if ( ! $this->firstPageWritten ) { + $this->firstPageWritten = trim( $this->thisPage ); + } + $this->lastPageWritten = trim( $this->thisPage ); + if ( $this->timeExceeded ) { + $this->egress->writeClosePage( $this->buffer ); + // nasty hack, we can't just write the chardata after the + // page tag, it will include leading blanks from the next line + $this->egress->sink->write( "\n" ); + + $this->buffer = $this->xmlwriterobj->closeStream(); + $this->egress->writeCloseStream( $this->buffer ); + + $this->buffer = ""; + $this->thisPage = ""; + // this could be more than one file if we had more than one output arg + + $filenameList = (array)$this->egress->getFilenames(); + $newFilenames = array(); + $firstPageID = str_pad( $this->firstPageWritten, 9, "0", STR_PAD_LEFT ); + $lastPageID = str_pad( $this->lastPageWritten, 9, "0", STR_PAD_LEFT ); + for ( $i = 0; $i < count( $filenameList ); $i++ ) { + $checkpointNameFilledIn = sprintf( $this->checkpointFiles[$i], $firstPageID, $lastPageID ); + $fileinfo = pathinfo( $filenameList[$i] ); + $newFilenames[] = $fileinfo['dirname'] . '/' . $checkpointNameFilledIn; + } + $this->egress->closeRenameAndReopen( $newFilenames ); + $this->buffer = $this->xmlwriterobj->openStream(); + $this->timeExceeded = false; + $this->timeOfCheckpoint = $this->lastTime; + $this->firstPageWritten = false; + $this->checkpointJustWritten = true; + } + else { + $this->egress->writeClosePage( $this->buffer ); + $this->buffer = ""; + $this->thisPage = ""; + } + + } elseif ( $name == 'mediawiki' ) { + $this->egress->writeCloseStream( $this->buffer ); + $this->buffer = ""; + } + } + + function characterData( $parser, $data ) { + $this->clearOpenElement( null ); + if ( $this->lastName == "id" ) { + if ( $this->state == "revision" ) { + $this->thisRev .= $data; + } elseif ( $this->state == "page" ) { + $this->thisPage .= $data; + } + } + // have to skip the newline left over from closepagetag line of + // end of checkpoint files. nasty hack!! + if ( $this->checkpointJustWritten ) { + if ( $data[0] == "\n" ) { + $data = substr( $data, 1 ); + } + $this->checkpointJustWritten = false; + } + $this->buffer .= htmlspecialchars( $data ); + } + + function clearOpenElement( $style ) { + if ( $this->openElement ) { + $this->buffer .= Xml::element( $this->openElement[0], $this->openElement[1], $style ); + $this->openElement = false; + } + } +} diff --git a/maintenance/benchmarks/Benchmarker.php b/maintenance/benchmarks/Benchmarker.php index 0056c3c7..c198e0ff 100644 --- a/maintenance/benchmarks/Benchmarker.php +++ b/maintenance/benchmarks/Benchmarker.php @@ -5,7 +5,7 @@ */ /** - * Create a doxygen subgroup of Maintenance for benchmarks + * Base code for benchmark scripts. * * 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 @@ -27,7 +27,13 @@ * @ingroup Benchmark */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); + +/** + * Base class for benchmark scripts. + * + * @ingroup Benchmark + */ abstract class Benchmarker extends Maintenance { private $results; @@ -47,11 +53,11 @@ abstract class Benchmarker extends Maintenance { } $bench_number++; - $start = wfTime(); + $start = microtime( true ); for( $i=0; $i<$count; $i++ ) { call_user_func_array( $bench['function'], $bench['args'] ); } - $delta = wfTime() - $start; + $delta = microtime( true ) - $start; // function passed as a callback if( is_array( $bench['function'] ) ) { @@ -61,7 +67,7 @@ abstract class Benchmarker extends Maintenance { $this->results[$bench_number] = array( 'function' => $bench['function'], - 'arguments' => $bench['args'], + 'arguments' => $bench['args'], 'count' => $count, 'delta' => $delta, 'average' => $delta / $count, diff --git a/maintenance/benchmarks/bench_HTTP_HTTPS.php b/maintenance/benchmarks/bench_HTTP_HTTPS.php index cf62aadb..fa76ae22 100644 --- a/maintenance/benchmarks/bench_HTTP_HTTPS.php +++ b/maintenance/benchmarks/bench_HTTP_HTTPS.php @@ -1,6 +1,8 @@ <?php /** - * This come from r75429 message + * Benchmark HTTP request vs HTTPS request. + * + * This come from r75429 message. * * 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 @@ -22,7 +24,13 @@ * @author Platonides */ -require_once( dirname( __FILE__ ) . '/Benchmarker.php' ); +require_once( __DIR__ . '/Benchmarker.php' ); + +/** + * Maintenance script that benchmarks HTTP request vs HTTPS request. + * + * @ingroup Benchmark + */ class bench_HTTP_HTTPS extends Benchmarker { public function __construct() { diff --git a/maintenance/benchmarks/bench_delete_truncate.php b/maintenance/benchmarks/bench_delete_truncate.php index 71385520..d9741496 100644 --- a/maintenance/benchmarks/bench_delete_truncate.php +++ b/maintenance/benchmarks/bench_delete_truncate.php @@ -1,11 +1,33 @@ <?php /** + * Benchmark SQL DELETE vs SQL TRUNCATE. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup Benchmark */ -require_once( dirname( __FILE__ ) . '/Benchmarker.php' ); +require_once( __DIR__ . '/Benchmarker.php' ); +/** + * Maintenance script that benchmarks SQL DELETE vs SQL TRUNCATE. + * + * @ingroup Benchmark + */ class BenchmarkDeleteTruncate extends Benchmarker { public function __construct() { @@ -24,24 +46,24 @@ class BenchmarkDeleteTruncate extends Benchmarker { $this->insertData( $dbw ); - $start = wfTime(); + $start = microtime( true ); $this->delete( $dbw ); - $end = wfTime(); + $end = microtime( true ); - echo "Delete: " . $end - $start; + echo "Delete: " . sprintf( "%6.3fms", ( $end - $start ) * 1000 ); echo "\r\n"; $this->insertData( $dbw ); - $start = wfTime(); + $start = microtime( true ); $this->truncate( $dbw ); - $end = wfTime(); + $end = microtime( true ); - echo "Truncate: " . $end - $start; + echo "Truncate: " . sprintf( "%6.3fms", ( $end - $start ) * 1000 ); echo "\r\n"; $dbw->dropTable( 'test' ); diff --git a/maintenance/benchmarks/bench_if_switch.php b/maintenance/benchmarks/bench_if_switch.php index dafce050..1f590d4d 100644 --- a/maintenance/benchmarks/bench_if_switch.php +++ b/maintenance/benchmarks/bench_if_switch.php @@ -1,5 +1,7 @@ <?php /** + * Benchmark if elseif... versus switch case. + * * This come from r75429 message * * This program is free software; you can redistribute it and/or modify @@ -22,7 +24,13 @@ * @author Platonides */ -require_once( dirname( __FILE__ ) . '/Benchmarker.php' ); +require_once( __DIR__ . '/Benchmarker.php' ); + +/** + * Maintenance script that benchmark if elseif... versus switch case. + * + * @ingroup Maintenance + */ class bench_if_switch extends Benchmarker { public function __construct() { diff --git a/maintenance/benchmarks/bench_strtr_str_replace.php b/maintenance/benchmarks/bench_strtr_str_replace.php index 73ace2bd..9fa7c8e3 100644 --- a/maintenance/benchmarks/bench_strtr_str_replace.php +++ b/maintenance/benchmarks/bench_strtr_str_replace.php @@ -1,10 +1,29 @@ <?php /** + * Benchmark for strtr() vs str_replace(). + * + * This come from r75429 message. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup Benchmark */ -require_once( dirname( __FILE__ ) . '/Benchmarker.php' ); +require_once( __DIR__ . '/Benchmarker.php' ); function bfNormalizeTitleStrTr( $str ) { return strtr( $str, '_', ' ' ); @@ -14,6 +33,11 @@ function bfNormalizeTitleStrReplace( $str ) { return str_replace( '_', ' ', $str ); } +/** + * Maintenance script that benchmarks for strtr() vs str_replace(). + * + * @ingroup Benchmark + */ class bench_strtr_str_replace extends Benchmarker { public function __construct() { diff --git a/maintenance/benchmarks/bench_utf8_title_check.php b/maintenance/benchmarks/bench_utf8_title_check.php new file mode 100644 index 00000000..f5987800 --- /dev/null +++ b/maintenance/benchmarks/bench_utf8_title_check.php @@ -0,0 +1,126 @@ +<?php +/** + * Benchmark for using a regexp vs. mb_check_encoding to check for UTF-8 encoding. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Benchmark + */ + +require_once( __DIR__ . '/Benchmarker.php' ); + +/** + * This little benchmark executes the regexp used in Language->checkTitleEncoding() + * and compares its execution time against that of mb_check_encoding, if available. + * + * @ingroup Benchmark + */ +class bench_utf8_title_check extends Benchmarker { + + private $canRun; + + private $data; + + public function __construct() { + parent::__construct(); + + $this->data = array ( + "", + "United States of America", // 7bit ASCII + "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e", + "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn", + // This comes from bug 36839 + "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C" + . "Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C" + . "Internet%20Movie%20Database%7CJim%20Brass%7CLady%20Heather%7C" + . "Les%20Experts%20(s%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e)%7CLes%20Experts%20:%20Manhattan%7C" + . "Les%20Experts%20:%20Miami%7CListe%20des%20personnages%20des%20Experts%7C" + . "Liste%20des%20%C3%A9pisodes%20des%20Experts%7CMod%C3%A8le%20discussion:Palette%20Les%20Experts%7C" + . "Nick%20Stokes%7CPersonnage%20de%20fiction%7CPersonnage%20fictif%7CPersonnage%20de%20fiction%7C" + . "Personnages%20r%C3%A9currents%20dans%20Les%20Experts%7CRaymond%20Langston%7CRiley%20Adams%7C" + . "Saison%201%20des%20Experts%7CSaison%2010%20des%20Experts%7CSaison%2011%20des%20Experts%7C" + . "Saison%2012%20des%20Experts%7CSaison%202%20des%20Experts%7CSaison%203%20des%20Experts%7C" + . "Saison%204%20des%20Experts%7CSaison%205%20des%20Experts%7CSaison%206%20des%20Experts%7C" + . "Saison%207%20des%20Experts%7CSaison%208%20des%20Experts%7CSaison%209%20des%20Experts%7C" + . "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C" + . "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis" + ); + + $this->canRun = function_exists ( 'mb_check_encoding' ); + + if ( $this->canRun ) { + $this->mDescription = "Benchmark for using a regexp vs. mb_check_encoding to check for UTF-8 encoding."; + mb_internal_encoding( 'UTF-8' ); + } else { + $this->mDescription = "CANNOT RUN benchmark using mb_check_encoding: function not available."; + } + } + + public function execute() { + if ( !$this->canRun ) { + return; + } + $benchmarks = array(); + foreach ($this->data as $val) { + $benchmarks[] = array( + 'function' => array( $this, 'use_regexp' ), + 'args' => array( rawurldecode ( $val ) ) + ); + $benchmarks[] = array( + 'function' => array( $this, 'use_regexp_non_capturing' ), + 'args' => array( rawurldecode ( $val ) ) + ); + $benchmarks[] = array( + 'function' => array( $this, 'use_regexp_once_only' ), + 'args' => array( rawurldecode ( $val ) ) + ); + $benchmarks[] = array( + 'function' => array( $this, 'use_mb_check_encoding' ), + 'args' => array( rawurldecode ( $val ) ) + ); + } + $this->bench( $benchmarks ); + print $this->getFormattedResults(); + } + + private $isutf8; + + function use_regexp( $s ) { + $this->isutf8 = preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' . + '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s ); + } + + function use_regexp_non_capturing( $s ) { + // Same as above with a non-capturing subgroup. + $this->isutf8 = preg_match( '/^(?:[\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' . + '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s ); + } + + function use_regexp_once_only( $s ) { + // Same as above with a once-only subgroup. + $this->isutf8 = preg_match( '/^(?>[\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' . + '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s ); + } + + function use_mb_check_encoding( $s ) { + $this->isutf8 = mb_check_encoding( $s, 'UTF-8' ); + } + +} + +$maintClass = 'bench_utf8_title_check'; +require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/benchmarks/bench_wfIsWindows.php b/maintenance/benchmarks/bench_wfIsWindows.php index 4caebc5e..85439827 100644 --- a/maintenance/benchmarks/bench_wfIsWindows.php +++ b/maintenance/benchmarks/bench_wfIsWindows.php @@ -1,6 +1,8 @@ <?php /** - * This come from r75429 message + * Benchmark for wfIsWindows(). + * + * This come from r75429 message. * * 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 @@ -22,7 +24,13 @@ * @author Platonides */ -require_once( dirname( __FILE__ ) . '/Benchmarker.php' ); +require_once( __DIR__ . '/Benchmarker.php' ); + +/** + * Maintenance script that benchmarks wfIsWindows(). + * + * @ingroup Benchmark + */ class bench_wfIsWindows extends Benchmarker { public function __construct() { diff --git a/maintenance/benchmarks/benchmarkHooks.php b/maintenance/benchmarks/benchmarkHooks.php index 4ec26168..fdb016f4 100644 --- a/maintenance/benchmarks/benchmarkHooks.php +++ b/maintenance/benchmarks/benchmarkHooks.php @@ -1,5 +1,7 @@ <?php /** + * Benchmark %MediaWiki hooks. + * * 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 @@ -19,8 +21,13 @@ * @ingroup Benchmark */ -require_once( dirname( __FILE__ ) . '/Benchmarker.php' ); +require_once( __DIR__ . '/Benchmarker.php' ); +/** + * Maintenance script that benchmarks %MediaWiki hooks. + * + * @ingroup Benchmark + */ class BenchmarkHooks extends Benchmarker { public function __construct() { @@ -58,14 +65,14 @@ class BenchmarkHooks extends Benchmarker { * @return string */ private function benchHooks( $trials = 10 ) { - $start = wfTime(); + $start = microtime( true ); for ( $i = 0; $i < $trials; $i++ ) { wfRunHooks( 'Test' ); } - $delta = wfTime() - $start; + $delta = microtime( true ) - $start; $pertrial = $delta / $trials; - return sprintf( "Took %6.2fs", - $pertrial ); + return sprintf( "Took %6.3fms", + $pertrial * 1000 ); } /** diff --git a/maintenance/benchmarks/benchmarkPurge.php b/maintenance/benchmarks/benchmarkPurge.php index e9d2ec7a..ec686b2a 100644 --- a/maintenance/benchmarks/benchmarkPurge.php +++ b/maintenance/benchmarks/benchmarkPurge.php @@ -1,6 +1,6 @@ <?php /** - * Squid purge benchmark script + * Benchmark for Squid purge. * * 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 @@ -21,8 +21,13 @@ * @ingroup Benchmark */ -require_once( dirname( __FILE__ ) . '/Benchmarker.php' ); +require_once( __DIR__ . '/Benchmarker.php' ); +/** + * Maintenance script that benchmarks Squid purge. + * + * @ingroup Benchmark + */ class BenchmarkPurge extends Benchmarker { public function __construct() { @@ -57,11 +62,11 @@ class BenchmarkPurge extends Benchmarker { * @return string */ private function benchSquid( $urls, $trials = 1 ) { - $start = wfTime(); + $start = microtime( true ); for ( $i = 0; $i < $trials; $i++ ) { SquidUpdate::purge( $urls ); } - $delta = wfTime() - $start; + $delta = microtime( true ) - $start; $pertrial = $delta / $trials; $pertitle = $pertrial / count( $urls ); return sprintf( "%4d titles in %6.2fms (%6.2fms each)", diff --git a/maintenance/cdb.php b/maintenance/cdb.php index 270f7a60..c06c2cd0 100644 --- a/maintenance/cdb.php +++ b/maintenance/cdb.php @@ -23,7 +23,7 @@ */ /** */ -require_once( dirname( __FILE__ ) . '/commandLine.inc' ); +require_once( __DIR__ . '/commandLine.inc' ); function cdbShowHelp( $command ) { $commandList = array( diff --git a/maintenance/changePassword.php b/maintenance/changePassword.php index cfcac406..f276fc16 100644 --- a/maintenance/changePassword.php +++ b/maintenance/changePassword.php @@ -24,8 +24,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to change the password of a given user. + * + * @ingroup Maintenance + */ class ChangePassword extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/checkAutoLoader.php b/maintenance/checkAutoLoader.php index d199b6fe..8d0e442b 100644 --- a/maintenance/checkAutoLoader.php +++ b/maintenance/checkAutoLoader.php @@ -21,8 +21,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to check classes definitions in the autoloader. + * + * @ingroup Maintenance + */ class CheckAutoLoader extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/checkBadRedirects.php b/maintenance/checkBadRedirects.php index bac2ff69..670b93de 100644 --- a/maintenance/checkBadRedirects.php +++ b/maintenance/checkBadRedirects.php @@ -1,7 +1,6 @@ <?php /** - * CheckBadRedirects - See if pages marked as being redirects - * really are. + * Check that pages marked as being redirects really are. * * 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 @@ -22,8 +21,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to check that pages marked as being redirects really are. + * + * @ingroup Maintenance + */ class CheckBadRedirects extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/checkImages.php b/maintenance/checkImages.php index 484217d9..c05d9151 100644 --- a/maintenance/checkImages.php +++ b/maintenance/checkImages.php @@ -1,6 +1,6 @@ <?php /** - * Check images to see if they exist, are readable, etc etc + * Check images to see if they exist, are readable, etc. * * 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 @@ -20,8 +20,13 @@ * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to check images to see if they exist, are readable, etc. + * + * @ingroup Maintenance + */ class CheckImages extends Maintenance { public function __construct() { diff --git a/maintenance/checkSyntax.php b/maintenance/checkSyntax.php index cc4e5af5..0a22f58c 100644 --- a/maintenance/checkSyntax.php +++ b/maintenance/checkSyntax.php @@ -21,8 +21,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to check syntax of all PHP files in MediaWiki. + * + * @ingroup Maintenance + */ class CheckSyntax extends Maintenance { // List of files we're going to check @@ -36,7 +41,7 @@ class CheckSyntax extends Maintenance { $this->addOption( 'path', 'Specific path (file or directory) to check, either with absolute path or relative to the root of this MediaWiki installation', false, true ); $this->addOption( 'list-file', 'Text file containing list of files or directories to check', false, true ); - $this->addOption( 'modified', 'Check only files that were modified (requires SVN command-line client)' ); + $this->addOption( 'modified', 'Check only files that were modified (requires Git command-line client)' ); $this->addOption( 'syntax-only', 'Check for syntax validity only, skip code style warnings' ); } @@ -114,18 +119,10 @@ class CheckSyntax extends Maintenance { fclose( $f ); return; } elseif ( $this->hasOption( 'modified' ) ) { - $this->output( "Retrieving list from Subversion... " ); - $parentDir = wfEscapeShellArg( dirname( __FILE__ ) . '/..' ); - $retval = null; - $output = wfShellExec( "svn status --ignore-externals $parentDir", $retval ); - if ( $retval ) { - $this->error( "Error retrieving list from Subversion!\n", true ); - } else { - $this->output( "done\n" ); - } - - preg_match_all( '/^\s*[AM].{7}(.*?)\r?$/m', $output, $matches ); - foreach ( $matches[1] as $file ) { + $this->output( "Retrieving list from Git... " ); + $files = $this->getGitModifiedFiles( $IP ); + $this->output( "done\n" ); + foreach ( $files as $file ) { if ( $this->isSuitableFile( $file ) && !is_dir( $file ) ) { $this->mFiles[] = $file; } @@ -164,6 +161,59 @@ class CheckSyntax extends Maintenance { } /** + * Returns a list of tracked files in a Git work tree differing from the master branch. + * @param $path string: Path to the repository + * @return array: Resulting list of changed files + */ + private function getGitModifiedFiles( $path ) { + + global $wgMaxShellMemory; + + if ( !is_dir( "$path/.git" ) ) { + $this->error( "Error: Not a Git repository!\n", true ); + } + + // git diff eats memory. + $oldMaxShellMemory = $wgMaxShellMemory; + if ( $wgMaxShellMemory < 1024000 ) { + $wgMaxShellMemory = 1024000; + } + + $ePath = wfEscapeShellArg( $path ); + + // Find an ancestor in common with master (rather than just using its HEAD) + // to prevent files only modified there from showing up in the list. + $cmd = "cd $ePath && git merge-base master HEAD"; + $retval = 0; + $output = wfShellExec( $cmd, $retval ); + if ( $retval !== 0 ) { + $this->error( "Error retrieving base SHA1 from Git!\n", true ); + } + + // Find files in the working tree that changed since then. + $eBase = wfEscapeShellArg( rtrim( $output, "\n" ) ); + $cmd = "cd $ePath && git diff --name-only --diff-filter AM $eBase"; + $retval = 0; + $output = wfShellExec( $cmd, $retval ); + if ( $retval !== 0 ) { + $this->error( "Error retrieving list from Git!\n", true ); + } + + $wgMaxShellMemory = $oldMaxShellMemory; + + $arr = array(); + $filename = strtok( $output, "\n" ); + while ( $filename !== false ) { + if ( $filename !== '' ) { + $arr[] = "$path/$filename"; + } + $filename = strtok( "\n" ); + } + + return $arr; + } + + /** * Returns true if $file is of a type we can check * @param $file string * @return bool diff --git a/maintenance/checkUsernames.php b/maintenance/checkUsernames.php index 9b98721d..dd5e0022 100644 --- a/maintenance/checkUsernames.php +++ b/maintenance/checkUsernames.php @@ -1,8 +1,6 @@ <?php /** - * This script verifies that database usernames are actually valid. - * An existing usernames can become invalid if User::isValidUserName() - * is altered or if we change the $wgMaxNameChars + * Check that database usernames are actually valid. * * 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 @@ -24,8 +22,16 @@ */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to check that database usernames are actually valid. + * + * An existing usernames can become invalid if User::isValidUserName() + * is altered or if we change the $wgMaxNameChars + * + * @ingroup Maintenance + */ class CheckUsernames extends Maintenance { public function __construct() { diff --git a/maintenance/cleanupAncientTables.php b/maintenance/cleanupAncientTables.php new file mode 100644 index 00000000..dbc2e0d3 --- /dev/null +++ b/maintenance/cleanupAncientTables.php @@ -0,0 +1,113 @@ +<?php +/** + * Cleans up old database tables, dropping old indexes and fields. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Maintenance + */ + +require_once( __DIR__ . '/Maintenance.php' ); + +/** + * Maintenance script to cleans up old database tables, dropping old indexes + * and fields. + * + * @ingroup Maintenance + */ +class CleanupAncientTables extends Maintenance { + + public function __construct() { + parent::__construct(); + $this->mDescription = "Cleanup ancient tables and indexes"; + $this->addOption( 'force', 'Actually run this script' ); + } + + public function execute() { + if( !$this->hasOption( 'force' ) ) { + $this->error( "This maintenance script will remove old columns and indexes.\n" + . "It is recommended to backup your database first, and ensure all your data has been migrated to newer tables\n" + . "If you want to continue, run this script again with the --force \n" + ); + } + + $db = wfGetDB( DB_MASTER ); + $ancientTables = array( + 'blobs', // 1.4 + 'brokenlinks', // 1.4 + 'cur', // 1.4 + 'ip_blocks_old', // Temporary in 1.6 + 'links', // 1.4 + 'linkscc', // 1.4 + // 'math', // 1.18, but don't want to drop if math extension is enabled... + 'old', // 1.4 + 'oldwatchlist', // pre 1.1? + 'trackback', // 1.19 + 'user_rights', // 1.5 + 'validate', // 1.6 + ); + + foreach( $ancientTables as $table ) { + if ( $db->tableExists( $table, __METHOD__ ) ) { + $this->output( "Dropping table $table..." ); + $db->dropTable( $table, __METHOD__ ); + $this->output( "done.\n" ); + } + } + + $this->output( "Cleaning up text table\n" ); + + $oldIndexes = array( + 'old_namespace', + 'old_timestamp', + 'name_title_timestamp', + 'user_timestamp', + 'usertext_timestamp', + ); + foreach( $oldIndexes as $index ) { + if ( $db->indexExists( 'text', $index, __METHOD__ ) ) { + $this->output( "Dropping index $index from the text table..." ); + $db->query( "DROP INDEX " . $db->addIdentifierQuotes( $index ) + . " ON " . $db->tableName( 'text' ) ); + $this->output( "done.\n" ); + } + } + + $oldFields = array( + 'old_namespace', + 'old_title', + 'old_comment', + 'old_user', + 'old_user_text', + 'old_timestamp', + 'old_minor_edit', + 'inverse_timestamp', + ); + foreach( $oldFields as $field ) { + if ( $db->fieldExists( 'text', $field, __METHOD__ ) ) { + $this->output( "Dropping the $field field from the text table..." ); + $db->query( "ALTER TABLE " . $db->tableName( 'text' ) + . " DROP COLUMN " . $db->addIdentifierQuotes( $field ) ); + $this->output( "done.\n" ); + } + } + $this->output( "Done!\n" ); + } +} + +$maintClass = "CleanupAncientTables"; +require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/cleanupCaps.php b/maintenance/cleanupCaps.php index 6f8e180c..ec2aa957 100644 --- a/maintenance/cleanupCaps.php +++ b/maintenance/cleanupCaps.php @@ -1,6 +1,6 @@ <?php /** - * Script to clean up broken page links when somebody turns on $wgCapitalLinks. + * Clean up broken page links when somebody turns on $wgCapitalLinks. * * Usage: php cleanupCaps.php [--dry-run] * Options: @@ -29,8 +29,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/cleanupTable.inc' ); +require_once( __DIR__ . '/cleanupTable.inc' ); +/** + * Maintenance script to clean up broken page links when somebody turns on $wgCapitalLinks. + * + * @ingroup Maintenance + */ class CapsCleanup extends TableCleanup { public function __construct() { parent::__construct(); diff --git a/maintenance/cleanupImages.php b/maintenance/cleanupImages.php index 81d1c85b..4e7b937d 100644 --- a/maintenance/cleanupImages.php +++ b/maintenance/cleanupImages.php @@ -1,12 +1,12 @@ <?php /** - * Script to clean up broken, unparseable upload filenames. + * Clean up broken, unparseable upload filenames. * * Usage: php cleanupImages.php [--fix] * Options: * --fix Actually clean up titles; otherwise just checks for them * - * Copyright (C) 2005-2006 Brion Vibber <brion@pobox.com> + * Copyright © 2005-2006 Brion Vibber <brion@pobox.com> * http://www.mediawiki.org/ * * This program is free software; you can redistribute it and/or modify @@ -29,8 +29,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/cleanupTable.inc' ); +require_once( __DIR__ . '/cleanupTable.inc' ); +/** + * Maintenance script to clean up broken, unparseable upload filenames. + * + * @ingroup Maintenance + */ class ImageCleanup extends TableCleanup { protected $defaultParams = array( 'table' => 'image', @@ -156,7 +161,7 @@ class ImageCleanup extends TableCleanup { } else { $this->output( "renaming $path to $finalPath\n" ); // @todo FIXME: Should this use File::move()? - $db->begin(); + $db->begin( __METHOD__ ); $db->update( 'image', array( 'img_name' => $final ), array( 'img_name' => $orig ), @@ -173,15 +178,15 @@ class ImageCleanup extends TableCleanup { if ( !file_exists( $dir ) ) { if ( !wfMkdirParents( $dir, null, __METHOD__ ) ) { $this->output( "RENAME FAILED, COULD NOT CREATE $dir" ); - $db->rollback(); + $db->rollback( __METHOD__ ); return; } } if ( rename( $path, $finalPath ) ) { - $db->commit(); + $db->commit( __METHOD__ ); } else { $this->error( "RENAME FAILED" ); - $db->rollback(); + $db->rollback( __METHOD__ ); } } } @@ -192,9 +197,8 @@ class ImageCleanup extends TableCleanup { } private function buildSafeTitle( $name ) { - global $wgLegalTitleChars; $x = preg_replace_callback( - "/([^$wgLegalTitleChars]|~)/", + '/([^' . Title::legalChars() . ']|~)/', array( $this, 'hexChar' ), $name ); diff --git a/maintenance/refreshImageCount.php b/maintenance/cleanupPreferences.php index f9bdeea7..f37af775 100644 --- a/maintenance/refreshImageCount.php +++ b/maintenance/cleanupPreferences.php @@ -1,54 +1,52 @@ -<?php -/** - * Quickie hack; patch-ss_images.sql uses variables which don't - * replicate properly. - * - * 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 - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * http://www.gnu.org/copyleft/gpl.html - * - * @ingroup Maintenance - */ - -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); - -class RefreshImageCount extends Maintenance { - public function __construct() { - parent::__construct(); - $this->mDescription = "Resets ss_image count, forcing slaves to pick it up."; - } - - public function execute() { - $dbw = wfGetDB( DB_MASTER ); - - // Load the current value from the master - $count = $dbw->selectField( 'site_stats', 'ss_images' ); - - $this->output( wfWikiID() . ": forcing ss_images to $count\n" ); - - // First set to NULL so that it changes on the master - $dbw->update( 'site_stats', - array( 'ss_images' => null ), - array( 'ss_row_id' => 1 ) ); - - // Now this update will be forced to go out - $dbw->update( 'site_stats', - array( 'ss_images' => $count ), - array( 'ss_row_id' => 1 ) ); - } -} - -$maintClass = "RefreshImageCount"; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +<?php
+/**
+ * Remove hidden preferences from the database.
+ *
+ * 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
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author TyA <tya.wiki@gmail.com>
+ * @see [[bugzilla:30976]]
+ * @ingroup Maintenance
+ */
+
+require_once( __DIR__ . '/Maintenance.php' );
+
+/**
+ * Maintenance script that removes hidden preferences from the database.
+ *
+ * @ingroup Maintenance
+ */
+class CleanupPreferences extends Maintenance {
+ public function execute() {
+ global $wgHiddenPrefs;
+
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->begin();
+ foreach( $wgHiddenPrefs as $item ) {
+ $dbw->delete(
+ 'user_properties',
+ array( 'up_property' => $item ),
+ __METHOD__
+ );
+ };
+ $dbw->commit();
+ $this->output( "Finished!\n" );
+ }
+}
+
+$maintClass = 'CleanupPreferences'; // Tells it to run the class
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/maintenance/cleanupRemovedModules.php b/maintenance/cleanupRemovedModules.php index fb8afd2d..2085da94 100644 --- a/maintenance/cleanupRemovedModules.php +++ b/maintenance/cleanupRemovedModules.php @@ -1,7 +1,6 @@ <?php /** - * Maintenance script to remove cache entries for removed ResourceLoader modules - * from the database + * Remove cache entries for removed ResourceLoader modules from the database. * * 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 @@ -23,8 +22,14 @@ * @author Roan Kattouw */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to remove cache entries for removed ResourceLoader modules + * from the database. + * + * @ingroup Maintenance + */ class CleanupRemovedModules extends Maintenance { public function __construct() { diff --git a/maintenance/cleanupSpam.php b/maintenance/cleanupSpam.php index ca1e302b..e20bcd87 100644 --- a/maintenance/cleanupSpam.php +++ b/maintenance/cleanupSpam.php @@ -1,6 +1,6 @@ <?php /** - * Cleanup all spam from a given hostname + * Cleanup all spam from a given hostname. * * 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 @@ -21,20 +21,27 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to cleanup all spam from a given hostname. + * + * @ingroup Maintenance + */ class CleanupSpam extends Maintenance { + public function __construct() { parent::__construct(); $this->mDescription = "Cleanup all spam from a given hostname"; $this->addOption( 'all', 'Check all wikis in $wgLocalDatabases' ); - $this->addArg( 'hostname', 'Hostname that was spamming' ); + $this->addOption( 'delete', 'Delete pages containing only spam instead of blanking them' ); + $this->addArg( 'hostname', 'Hostname that was spamming, single * wildcard in the beginning allowed' ); } public function execute() { global $wgLocalDatabases, $wgUser; - $username = wfMsg( 'spambot_username' ); + $username = wfMessage( 'spambot_username' )->text(); $wgUser = User::newFromName( $username ); if ( !$wgUser ) { $this->error( "Invalid username", true ); @@ -106,19 +113,23 @@ class CleanupSpam extends Maintenance { $this->output( "False match\n" ); } else { $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $page = WikiPage::factory( $title ); - if ( !$rev ) { - // Didn't find a non-spammy revision, blank the page - $this->output( "blanking\n" ); - $page->doEdit( '', wfMsgForContent( 'spam_blanking', $domain ) ); - } else { + if ( $rev ) { // Revert to this revision $this->output( "reverting\n" ); - $page->doEdit( $rev->getText(), wfMsgForContent( 'spam_reverting', $domain ), + $page->doEdit( $rev->getText(), wfMessage( 'spam_reverting', $domain )->inContentLanguage()->text(), EDIT_UPDATE, $rev->getId() ); + } elseif ( $this->hasOption( 'delete' ) ) { + // Didn't find a non-spammy revision, blank the page + $this->output( "deleting\n" ); + $page->doDeleteArticle( wfMessage( 'spam_deleting', $domain )->inContentLanguage()->text() ); + } else { + // Didn't find a non-spammy revision, blank the page + $this->output( "blanking\n" ); + $page->doEdit( '', wfMessage( 'spam_blanking', $domain )->inContentLanguage()->text() ); } - $dbw->commit(); + $dbw->commit( __METHOD__ ); } } } diff --git a/maintenance/cleanupTable.inc b/maintenance/cleanupTable.inc index 1c279762..57acfd82 100644 --- a/maintenance/cleanupTable.inc +++ b/maintenance/cleanupTable.inc @@ -1,6 +1,6 @@ <?php /** - * Generic table cleanup class. Already subclasses maintenance + * Generic class to cleanup a database table. * * 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 @@ -21,8 +21,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Generic class to cleanup a database table. Already subclasses Maintenance. + * + * @ingroup Maintenance + */ class TableCleanup extends Maintenance { protected $defaultParams = array( 'table' => 'page', @@ -57,7 +62,7 @@ class TableCleanup extends Maintenance { $this->processed = 0; $this->updated = 0; $this->count = $count; - $this->startTime = wfTime(); + $this->startTime = microtime( true ); $this->table = $table; } @@ -70,7 +75,7 @@ class TableCleanup extends Maintenance { $portion = $this->processed / $this->count; $updateRate = $this->updated / $this->processed; - $now = wfTime(); + $now = microtime( true ); $delta = $now - $this->startTime; $estimatedTotalTime = $delta / $portion; $eta = $this->startTime + $estimatedTotalTime; diff --git a/maintenance/cleanupTitles.php b/maintenance/cleanupTitles.php index 4fc6415e..ad2577aa 100644 --- a/maintenance/cleanupTitles.php +++ b/maintenance/cleanupTitles.php @@ -1,6 +1,6 @@ <?php /** - * Script to clean up broken, unparseable titles. + * Clean up broken, unparseable titles. * * Usage: php cleanupTitles.php [--fix] * Options: @@ -29,8 +29,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/cleanupTable.inc' ); +require_once( __DIR__ . '/cleanupTable.inc' ); +/** + * Maintenance script to clean up broken, unparseable titles. + * + * @ingroup Maintenance + */ class TitleCleanup extends TableCleanup { public function __construct() { parent::__construct(); diff --git a/maintenance/cleanupUploadStash.php b/maintenance/cleanupUploadStash.php index 5f57ffdf..cc329461 100644 --- a/maintenance/cleanupUploadStash.php +++ b/maintenance/cleanupUploadStash.php @@ -25,8 +25,14 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to remove old or broken uploads from temporary uploaded + * file storage and clean up associated database records. + * + * @ingroup Maintenance + */ class UploadStashCleanup extends Maintenance { public function __construct() { @@ -68,15 +74,21 @@ class UploadStashCleanup extends Maintenance { // out-of-date someday $stash = new UploadStash( $repo ); + $i = 0; foreach( $keys as $key ) { + $i++; try { $stash->getFile( $key, true ); $stash->removeFileNoAuth( $key ); } catch ( UploadStashBadPathException $ex ) { $this->output( "Failed removing stashed upload with key: $key\n" ); } + if ( $i % 100 == 0 ) { + $this->output( "$i\n" ); + } } - } + $this->output( "$i done\n" ); + } } $maintClass = "UploadStashCleanup"; diff --git a/maintenance/cleanupWatchlist.php b/maintenance/cleanupWatchlist.php index a9b20fea..fbab6a3c 100644 --- a/maintenance/cleanupWatchlist.php +++ b/maintenance/cleanupWatchlist.php @@ -1,12 +1,12 @@ <?php /** - * Script to remove broken, unparseable titles in the Watchlist. + * Remove broken, unparseable titles in the watchlist table. * * Usage: php cleanupWatchlist.php [--fix] * Options: * --fix Actually remove entries; without will only report. * - * Copyright (C) 2005,2006 Brion Vibber <brion@pobox.com> + * Copyright © 2005,2006 Brion Vibber <brion@pobox.com> * http://www.mediawiki.org/ * * This program is free software; you can redistribute it and/or modify @@ -29,8 +29,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/cleanupTable.inc' ); +require_once( __DIR__ . '/cleanupTable.inc' ); +/** + * Maintenance script to remove broken, unparseable titles in the watchlist table. + * + * @ingroup Maintenance + */ class WatchlistCleanup extends TableCleanup { protected $defaultParams = array( 'table' => 'watchlist', diff --git a/maintenance/clear_interwiki_cache.php b/maintenance/clear_interwiki_cache.php index 953bd4ce..88769df2 100644 --- a/maintenance/clear_interwiki_cache.php +++ b/maintenance/clear_interwiki_cache.php @@ -1,7 +1,6 @@ <?php /** - * This script is used to clear the interwiki links for ALL languages in - * the cache. + * Clear the cache of interwiki prefixes for all local wikis. * * 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 @@ -22,8 +21,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to clear the cache of interwiki prefixes for all local wikis. + * + * @ingroup Maintenance + */ class ClearInterwikiCache extends Maintenance { public function __construct() { diff --git a/maintenance/clear_stats.php b/maintenance/clear_stats.php index 61314e67..4581d532 100644 --- a/maintenance/clear_stats.php +++ b/maintenance/clear_stats.php @@ -1,6 +1,6 @@ <?php /** - * This script remove all statistics tracking from the cache + * Removes all statistics tracking from the cache. * * 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 @@ -21,8 +21,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to remove all statistics tracking from the cache. + * + * @ingroup Maintenance + */ class clear_stats extends Maintenance { public function __construct() { diff --git a/maintenance/commandLine.inc b/maintenance/commandLine.inc index c7adbfbc..86a558d0 100644 --- a/maintenance/commandLine.inc +++ b/maintenance/commandLine.inc @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); global $optionsWithArgs; if ( !isset( $optionsWithArgs ) ) { diff --git a/maintenance/compareParsers.php b/maintenance/compareParsers.php index 4fe4e4d0..a3337173 100644 --- a/maintenance/compareParsers.php +++ b/maintenance/compareParsers.php @@ -6,8 +6,9 @@ * * Templates etc are pulled from the local wiki database, not from the dump. * - * Copyright (C) 2011 Platonides - http://www.mediawiki.org/ - * + * Copyright © 2011 Platonides + * http://www.mediawiki.org/ + * * 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 @@ -26,9 +27,15 @@ * @file * @ingroup Maintenance */ - -require_once( dirname( __FILE__ ) . '/dumpIterator.php' ); +require_once( __DIR__ . '/dumpIterator.php' ); + +/** + * Maintenance script to take page text out of an XML dump file and render + * basic HTML out to files. + * + * @ingroup Maintenance + */ class CompareParsers extends DumpIterator { private $count = 0; @@ -51,10 +58,10 @@ class CompareParsers extends DumpIterator { if ( $this->hasOption('save-failed') ) { $this->saveFailed = $this->getOption('save-failed'); } - + $this->stripParametersEnabled = $this->hasOption( 'strip-parameters' ); $this->showParsedOutput = $this->hasOption( 'show-parsed-output' ); - + $this->showDiff = $this->hasOption( 'show-diff' ); if ( $this->showDiff ) { $bin = $this->getOption( 'diff-bin', getenv( 'DIFF' ) ); @@ -63,10 +70,10 @@ class CompareParsers extends DumpIterator { $wgDiff = $bin; } } - - $user = new User(); + + $user = new User(); $this->options = ParserOptions::newFromUser( $user ); - + if ( $this->hasOption( 'tidy' ) ) { global $wgUseTidy; if ( !$wgUseTidy ) { @@ -74,46 +81,46 @@ class CompareParsers extends DumpIterator { } $this->options->setTidy( true ); } - + $this->failed = 0; } - - public function conclusions() { + + public function conclusions() { $this->error( "{$this->failed} failed revisions out of {$this->count}" ); if ($this->count > 0) $this->output( " (" . ( $this->failed / $this->count ) . "%)\n" ); } - + function stripParameters( $text ) { if ( !$this->stripParametersEnabled ) { return $text; } return preg_replace( '/(<a) [^>]+>/', '$1>', $text ); } - + /** * Callback function for each revision, parse with both parsers and compare * @param $rev Revision */ public function processRevision( $rev ) { $title = $rev->getTitle(); - + $parser1Name = $this->getOption( 'parser1' ); $parser2Name = $this->getOption( 'parser2' ); - + self::checkParserLocally( $parser1Name ); self::checkParserLocally( $parser2Name ); - + $parser1 = new $parser1Name(); $parser2 = new $parser2Name(); - + $output1 = $parser1->parse( $rev->getText(), $title, $this->options ); $output2 = $parser2->parse( $rev->getText(), $title, $this->options ); if ( $output1->getText() != $output2->getText() ) { $this->failed++; $this->error( "Parsing for {$title->getPrefixedText()} differs\n" ); - + if ( $this->saveFailed ) { file_put_contents( $this->saveFailed . '/' . rawurlencode( $title->getPrefixedText() ) . ".txt", $rev->getText()); } @@ -127,7 +134,7 @@ class CompareParsers extends DumpIterator { } } } - + private static function checkParserLocally( $parserName ) { /* Look for the parser in a file appropiately named in the current folder */ if ( !class_exists( $parserName ) && file_exists( "$parserName.php" ) ) { diff --git a/maintenance/convertLinks.php b/maintenance/convertLinks.php index 85ef5c8c..5f7b02e4 100644 --- a/maintenance/convertLinks.php +++ b/maintenance/convertLinks.php @@ -1,7 +1,6 @@ <?php /** - * Convert from the old links schema (string->ID) to the new schema (ID->ID) - * The wiki should be put into read-only mode while this script executes + * Convert from the old links schema (string->ID) to the new schema (ID->ID). * * 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 @@ -22,14 +21,22 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to convert from the old links schema (string->ID) + * to the new schema (ID->ID). + * + * The wiki should be put into read-only mode while this script executes. + * + * @ingroup Maintenance + */ class ConvertLinks extends Maintenance { private $logPerformance; public function __construct() { parent::__construct(); - $this->mDescription = "Convert from the old links schema (string->ID) to the new schema (ID->ID) + $this->mDescription = "Convert from the old links schema (string->ID) to the new schema (ID->ID). The wiki should be put into read-only mode while this script executes"; $this->addArg( 'logperformance', "Log performance to perfLogFilename.", false ); diff --git a/maintenance/convertUserOptions.php b/maintenance/convertUserOptions.php index da6ff9b6..7c9ca269 100644 --- a/maintenance/convertUserOptions.php +++ b/maintenance/convertUserOptions.php @@ -1,6 +1,6 @@ <?php /** - * Do each user sequentially, since accounts can't be deleted + * Convert user options to the new `user_properties` table. * * 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 @@ -21,8 +21,15 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to convert user options to the new `user_properties` table. + * + * Do each user sequentially, since accounts can't be deleted + * + * @ingroup Maintenance + */ class ConvertUserOptions extends Maintenance { private $mConversionCount = 0; diff --git a/maintenance/copyFileBackend.php b/maintenance/copyFileBackend.php new file mode 100644 index 00000000..aebdee17 --- /dev/null +++ b/maintenance/copyFileBackend.php @@ -0,0 +1,201 @@ +<?php +/** + * Copy all files in some containers of one backend to another. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Maintenance + */ + +require_once( __DIR__ . '/Maintenance.php' ); + +/** + * Copy all files in one container of one backend to another. + * + * This can also be used to re-shard the files for one backend using the + * config of second backend. The second backend should have the same config + * as the first, except for it having a different name and different sharding + * configuration. The backend should be made read-only while this runs. + * After this script finishes, the old files in the containers can be deleted. + * + * @ingroup Maintenance + */ +class CopyFileBackend extends Maintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = "Copy files in one backend to another."; + $this->addOption( 'src', 'Backend containing the source files', true, true ); + $this->addOption( 'dst', 'Backend where files should be copied to', true, true ); + $this->addOption( 'containers', 'Pipe separated list of containers', true, true ); + $this->addOption( 'subdir', 'Only do items in this child directory', false, true ); + $this->addOption( 'ratefile', 'File to check periodically for batch size', false, true ); + $this->addOption( 'skiphash', 'Skip SHA-1 sync checks for files' ); + $this->addOption( 'missingonly', 'Only copy files missing from destination listing' ); + $this->addOption( 'utf8only', 'Skip source files that do not have valid UTF-8 names' ); + $this->setBatchSize( 50 ); + } + + public function execute() { + $src = FileBackendGroup::singleton()->get( $this->getOption( 'src' ) ); + $dst = FileBackendGroup::singleton()->get( $this->getOption( 'dst' ) ); + $containers = explode( '|', $this->getOption( 'containers' ) ); + $subDir = $this->getOption( rtrim( 'subdir', '/' ), '' ); + + $rateFile = $this->getOption( 'ratefile' ); + + if ( $this->hasOption( 'utf8only' ) && !extension_loaded( 'mbstring' ) ) { + $this->error( "Cannot check for UTF-8, mbstring extension missing.", 1 ); // die + } + + $count = 0; + foreach ( $containers as $container ) { + if ( $subDir != '' ) { + $backendRel = "$container/$subDir"; + $this->output( "Doing container '$container', directory '$subDir'...\n" ); + } else { + $backendRel = $container; + $this->output( "Doing container '$container'...\n" ); + } + + $srcPathsRel = $src->getFileList( array( + 'dir' => $src->getRootStoragePath() . "/$backendRel" ) ); + if ( $srcPathsRel === null ) { + $this->error( "Could not list files in $container.", 1 ); // die + } + + // Do a listing comparison if specified + if ( $this->hasOption( 'missingonly' ) ) { + $relFilesSrc = array(); + $relFilesDst = array(); + foreach ( $srcPathsRel as $srcPathRel ) { + $relFilesSrc[] = $srcPathRel; + } + $dstPathsRel = $dst->getFileList( array( + 'dir' => $dst->getRootStoragePath() . "/$backendRel" ) ); + if ( $dstPathsRel === null ) { + $this->error( "Could not list files in $container.", 1 ); // die + } + foreach ( $dstPathsRel as $dstPathRel ) { + $relFilesDst[] = $dstPathRel; + } + // Only copy the missing files over in the next loop + $srcPathsRel = array_diff( $relFilesSrc, $relFilesDst ); + $this->output( count( $srcPathsRel ) . " file(s) need to be copied.\n" ); + unset( $relFilesSrc ); + unset( $relFilesDst ); + } + + $batchPaths = array(); + foreach ( $srcPathsRel as $srcPathRel ) { + // Check up on the rate file periodically to adjust the concurrency + if ( $rateFile && ( !$count || ( $count % 500 ) == 0 ) ) { + $this->mBatchSize = max( 1, (int)file_get_contents( $rateFile ) ); + $this->output( "Batch size is now {$this->mBatchSize}.\n" ); + } + $batchPaths[$srcPathRel] = 1; // remove duplicates + if ( count( $batchPaths ) >= $this->mBatchSize ) { + $this->copyFileBatch( array_keys( $batchPaths ), $backendRel, $src, $dst ); + $batchPaths = array(); // done + } + ++$count; + } + if ( count( $batchPaths ) ) { // left-overs + $this->copyFileBatch( array_keys( $batchPaths ), $backendRel, $src, $dst ); + $batchPaths = array(); // done + } + + if ( $subDir != '' ) { + $this->output( "Finished container '$container', directory '$subDir'.\n" ); + } else { + $this->output( "Finished container '$container'.\n" ); + } + } + + $this->output( "Done [$count file(s)].\n" ); + } + + protected function copyFileBatch( + array $srcPathsRel, $backendRel, FileBackend $src, FileBackend $dst + ) { + $ops = array(); + $fsFiles = array(); + $copiedRel = array(); // for output message + foreach ( $srcPathsRel as $srcPathRel ) { + $srcPath = $src->getRootStoragePath() . "/$backendRel/$srcPathRel"; + $dstPath = $dst->getRootStoragePath() . "/$backendRel/$srcPathRel"; + if ( $this->hasOption( 'utf8only' ) && !mb_check_encoding( $srcPath, 'UTF-8' ) ) { + $this->error( "Detected illegal (non-UTF8) path for $srcPath." ); + continue; + } elseif ( $this->filesAreSame( $src, $dst, $srcPath, $dstPath ) ) { + $this->output( "Already have $srcPathRel.\n" ); + continue; // assume already copied... + } + // Note: getLocalReference() is fast for FS backends + $fsFile = $src->getLocalReference( array( 'src' => $srcPath, 'latest' => 1 ) ); + if ( !$fsFile ) { + $this->error( "Could not get local copy of $srcPath.", 1 ); // die + } elseif ( !$fsFile->exists() ) { + // FSFileBackends just return the path for getLocalReference() and paths with + // illegal slashes may get normalized to a different path. This can cause the + // local reference to not exist...skip these broken files. + $this->error( "Detected possible illegal path for $srcPath." ); + continue; + } + $fsFiles[] = $fsFile; // keep TempFSFile objects alive as needed + // Note: prepare() is usually fast for key/value backends + $status = $dst->prepare( array( 'dir' => dirname( $dstPath ), 'bypassReadOnly' => 1 ) ); + if ( !$status->isOK() ) { + $this->error( print_r( $status->getErrorsArray(), true ) ); + $this->error( "Could not copy $srcPath to $dstPath.", 1 ); // die + } + $ops[] = array( 'op' => 'store', + 'src' => $fsFile->getPath(), 'dst' => $dstPath, 'overwrite' => 1 ); + $copiedRel[] = $srcPathRel; + } + + $t_start = microtime( true ); + $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); + if ( !$status->isOK() ) { + sleep( 10 ); // wait and retry copy again + $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); + } + $ellapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); + if ( !$status->isOK() ) { + $this->error( print_r( $status->getErrorsArray(), true ) ); + $this->error( "Could not copy file batch.", 1 ); // die + } elseif ( count( $copiedRel ) ) { + $this->output( "\nCopied these file(s) [{$ellapsed_ms}ms]:\n" . + implode( "\n", $copiedRel ) . "\n\n" ); + } + } + + protected function filesAreSame( FileBackend $src, FileBackend $dst, $sPath, $dPath ) { + $skipHash = $this->hasOption( 'skiphash' ); + return ( + ( $src->fileExists( array( 'src' => $sPath, 'latest' => 1 ) ) + === $dst->fileExists( array( 'src' => $dPath, 'latest' => 1 ) ) // short-circuit + ) && ( $src->getFileSize( array( 'src' => $sPath, 'latest' => 1 ) ) + === $dst->getFileSize( array( 'src' => $dPath, 'latest' => 1 ) ) // short-circuit + ) && ( $skipHash || ( $src->getFileSha1Base36( array( 'src' => $sPath, 'latest' => 1 ) ) + === $dst->getFileSha1Base36( array( 'src' => $dPath, 'latest' => 1 ) ) + ) ) + ); + } +} + +$maintClass = 'CopyFileBackend'; +require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/createAndPromote.php b/maintenance/createAndPromote.php index 0d7de9a9..ad5333fc 100644 --- a/maintenance/createAndPromote.php +++ b/maintenance/createAndPromote.php @@ -1,6 +1,6 @@ <?php /** - * Maintenance script to create an account and grant it administrator rights + * Creates an account and grant it administrator rights. * * 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 @@ -22,8 +22,13 @@ * @author Rob Church <robchur@gmail.com> */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to create an account and grant it administrator rights. + * + * @ingroup Maintenance + */ class CreateAndPromote extends Maintenance { public function __construct() { @@ -76,4 +81,4 @@ class CreateAndPromote extends Maintenance { } $maintClass = "CreateAndPromote"; -require_once( RUN_MAINTENANCE_IF_MAIN );
\ No newline at end of file +require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/deleteArchivedFiles.inc b/maintenance/deleteArchivedFiles.inc index 68394b4a..e638b17c 100644 --- a/maintenance/deleteArchivedFiles.inc +++ b/maintenance/deleteArchivedFiles.inc @@ -17,14 +17,20 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ +/** + * Core functions for deleteArchivedFiles.php + * + * @ingroup Maintenance + */ class DeleteArchivedFilesImplementation { static public function doDelete( $output, $force ) { # Data should come off the master, wrapped in a transaction $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $tbl_arch = $dbw->tableName( 'filearchive' ); $repo = RepoGroup::singleton()->getLocalRepo(); # Get "active" revisions from the filearchive table @@ -44,8 +50,8 @@ class DeleteArchivedFilesImplementation { __METHOD__, array( 'FOR UPDATE' ) ); - if ( $path && file_exists( $path ) && !$inuse ) { - if( unlink( $path ) ) { // delete + if ( $path && $repo->fileExists( $path ) && !$inuse ) { + if ( $repo->quickPurge( $path ) ) { $count++; $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" ); } else { @@ -59,7 +65,7 @@ class DeleteArchivedFilesImplementation { } } } - $dbw->commit(); + $dbw->commit( __METHOD__ ); $output->handleOutput( "Done! [$count file(s)]\n" ); } -}
\ No newline at end of file +} diff --git a/maintenance/deleteArchivedFiles.php b/maintenance/deleteArchivedFiles.php index 6067c807..85ffc23b 100644 --- a/maintenance/deleteArchivedFiles.php +++ b/maintenance/deleteArchivedFiles.php @@ -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 @@ -18,14 +19,19 @@ * 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( dirname( __FILE__ ) . '/deleteArchivedFiles.inc' ); +require_once( __DIR__ . '/Maintenance.php' ); +require_once( __DIR__ . '/deleteArchivedFiles.inc' ); +/** + * Maintenance script to delete archived (non-current) files from the database. + * + * @ingroup Maintenance + */ class DeleteArchivedFiles extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/deleteArchivedRevisions.inc b/maintenance/deleteArchivedRevisions.inc index 7628985c..414d41ad 100644 --- a/maintenance/deleteArchivedRevisions.inc +++ b/maintenance/deleteArchivedRevisions.inc @@ -1,7 +1,6 @@ <?php - /** - * Delete archived (deleted from public) revisions from the database + * Helper methods for the deleteArchivedRevisions.php maintenance script. * * 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 @@ -18,9 +17,15 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ +/** + * Helper methods for the deleteArchivedRevisions.php maintenance script. + * + * @ingroup Maintenance + */ class DeleteArchivedRevisionsImplementation { /** @@ -34,7 +39,7 @@ class DeleteArchivedRevisionsImplementation { static public function doDelete( $maint ) { $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $tbl_arch = $dbw->tableName( 'archive' ); @@ -49,7 +54,7 @@ class DeleteArchivedRevisionsImplementation { # This bit's done # Purge redundant text records - $dbw->commit(); + $dbw->commit( __METHOD__ ); if ( $deletedRows ) { $maint->purgeRedundantText( true ); } diff --git a/maintenance/deleteArchivedRevisions.php b/maintenance/deleteArchivedRevisions.php index 0faa0abb..4b658bbb 100644 --- a/maintenance/deleteArchivedRevisions.php +++ b/maintenance/deleteArchivedRevisions.php @@ -1,8 +1,9 @@ <?php - /** * Delete archived (deleted from public) revisions from the database * + * Shamelessly stolen from 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 @@ -18,14 +19,20 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Aaron Schulz - * Shamelessly stolen from deleteOldRevisions.php by Rob Church :) */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); -require_once( dirname( __FILE__ ) . '/deleteArchivedRevisions.inc' ); +require_once( __DIR__ . '/Maintenance.php' ); +require_once( __DIR__ . '/deleteArchivedRevisions.inc' ); +/** + * Maintenance script to delete archived (deleted from public) revisions + * from the database. + * + * @ingroup Maintenance + */ class DeleteArchivedRevisions extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/deleteBatch.php b/maintenance/deleteBatch.php index 56fe13a4..936a52b8 100644 --- a/maintenance/deleteBatch.php +++ b/maintenance/deleteBatch.php @@ -1,6 +1,6 @@ <?php /** - * Deletes a batch of pages + * Deletes a batch of pages. * Usage: php deleteBatch.php [-u <user>] [-r <reason>] [-i <interval>] [listfile] * where * [listfile] is a file where each line contains the title of a page to be @@ -24,11 +24,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to delete a batch of pages. + * + * @ingroup Maintenance + */ class DeleteBatch extends Maintenance { public function __construct() { @@ -89,7 +95,7 @@ class DeleteBatch extends Maintenance { } $this->output( $title->getPrefixedText() ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); if ( $title->getNamespace() == NS_FILE ) { $img = wfFindFile( $title ); if ( $img && $img->isLocal() && !$img->delete( $reason ) ) { @@ -99,7 +105,7 @@ class DeleteBatch extends Maintenance { $page = WikiPage::factory( $title ); $error = ''; $success = $page->doDeleteArticle( $reason, false, 0, false, $error, $user ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); if ( $success ) { $this->output( " Deleted!\n" ); } else { diff --git a/maintenance/deleteDefaultMessages.php b/maintenance/deleteDefaultMessages.php index 21d7755f..4ab6d1d9 100644 --- a/maintenance/deleteDefaultMessages.php +++ b/maintenance/deleteDefaultMessages.php @@ -18,11 +18,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that deletes all pages in the MediaWiki namespace + * which were last edited by "MediaWiki default". + * + * @ingroup Maintenance + */ class DeleteDefaultMessages extends Maintenance { public function __construct() { parent::__construct(); @@ -68,13 +75,13 @@ class DeleteDefaultMessages extends Maintenance { $dbw->ping(); $title = Title::makeTitle( $row->page_namespace, $row->page_title ); $page = WikiPage::factory( $title ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $error = ''; // Passed by ref $page->doDeleteArticle( 'No longer required', false, 0, false, $error, $user ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); } - $this->output( 'done!', 'msg' ); + $this->output( "done!\n", 'msg' ); } } diff --git a/maintenance/deleteImageMemcached.php b/maintenance/deleteImageMemcached.php index 007f0d17..3c8c5fdd 100644 --- a/maintenance/deleteImageMemcached.php +++ b/maintenance/deleteImageMemcached.php @@ -1,6 +1,6 @@ <?php /** - * This script delete image information from the cache. + * Delete image information from the object cache. * * Usage example: * php deleteImageMemcached.php --until "2005-09-05 00:00:00" --sleep 0 @@ -20,11 +20,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that deletes image information from the object cache. + * + * @ingroup Maintenance + */ class DeleteImageCache extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/deleteOldRevisions.php b/maintenance/deleteOldRevisions.php index 2cb347fc..6a3e211b 100644 --- a/maintenance/deleteOldRevisions.php +++ b/maintenance/deleteOldRevisions.php @@ -1,5 +1,4 @@ <?php - /** * Delete old (non-current) revisions from the database * @@ -18,12 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that deletes old (non-current) revisions from the database. + * + * @ingroup Maintenance + */ class DeleteOldRevisions extends Maintenance { public function __construct() { parent::__construct(); @@ -41,7 +46,7 @@ class DeleteOldRevisions extends Maintenance { # Data should come off the master, wrapped in a transaction $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $tbl_pag = $dbw->tableName( 'page' ); $tbl_rev = $dbw->tableName( 'revision' ); @@ -90,7 +95,7 @@ class DeleteOldRevisions extends Maintenance { # This bit's done # Purge redundant text records - $dbw->commit(); + $dbw->commit( __METHOD__ ); if ( $delete ) { $this->purgeRedundantText( true ); } diff --git a/maintenance/deleteOrphanedRevisions.php b/maintenance/deleteOrphanedRevisions.php index c322320b..5dc7567f 100644 --- a/maintenance/deleteOrphanedRevisions.php +++ b/maintenance/deleteOrphanedRevisions.php @@ -1,8 +1,7 @@ <?php - /** - * Maintenance script to delete revisions which refer to a nonexisting page - * Sometimes manual deletion done in a rush leaves crap in the database + * Delete revisions which refer to a nonexisting page. + * Sometimes manual deletion done in a rush leaves crap in the database. * * 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 @@ -19,13 +18,19 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> * @todo More efficient cleanup of text records */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that deletes revisions which refer to a nonexisting page. + * + * @ingroup Maintenance + */ class DeleteOrphanedRevisions extends Maintenance { public function __construct() { parent::__construct(); @@ -39,7 +44,7 @@ class DeleteOrphanedRevisions extends Maintenance { $report = $this->hasOption( 'report' ); $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); list( $page, $revision ) = $dbw->tableNamesN( 'page', 'revision' ); # Find all the orphaned revisions @@ -66,7 +71,7 @@ class DeleteOrphanedRevisions extends Maintenance { $this->output( "done.\n" ); # Close the transaction and call the script to purge unused text records - $dbw->commit(); + $dbw->commit( __METHOD__ ); $this->purgeRedundantText( true ); } diff --git a/maintenance/deleteRevision.php b/maintenance/deleteRevision.php index 5e8ecaac..ad6470d9 100644 --- a/maintenance/deleteRevision.php +++ b/maintenance/deleteRevision.php @@ -17,11 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that deletes one or more revisions by moving them + * to the archive table. + * + * @ingroup Maintenance + */ class DeleteRevision extends Maintenance { public function __construct() { diff --git a/maintenance/deleteSelfExternals.php b/maintenance/deleteSelfExternals.php index 4e9f54f2..da220d64 100644 --- a/maintenance/deleteSelfExternals.php +++ b/maintenance/deleteSelfExternals.php @@ -1,10 +1,6 @@ <?php /** - * We want to make this whole thing as seamless as possible to the - * end-user. Unfortunately, we can't do _all_ of the work in the class - * because A) included files are not in global scope, but in the scope - * of their caller, and B) MediaWiki has way too many globals. So instead - * we'll kinda fake it, and do the requires() inline. <3 PHP + * Delete self-references to $wgServer from the externallinks table. * * 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 @@ -21,12 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); - +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that deletes self-references to $wgServer + * from the externallinks table. + * + * @ingroup Maintenance + */ class DeleteSelfExternals extends Maintenance { public function __construct() { parent::__construct(); @@ -40,7 +42,7 @@ class DeleteSelfExternals extends Maintenance { $db = wfGetDB( DB_MASTER ); while ( 1 ) { wfWaitForSlaves(); - $db->commit(); + $db->commit( __METHOD__ ); $q = $db->limitResult( "DELETE /* deleteSelfExternals */ FROM externallinks WHERE el_to" . $db->buildLike( $wgServer . '/', $db->anyString() ), $this->mBatchSize ); $this->output( "Deleting a batch\n" ); diff --git a/maintenance/dev/includes/php.sh b/maintenance/dev/includes/php.sh index 3021b93b..7ce87944 100644 --- a/maintenance/dev/includes/php.sh +++ b/maintenance/dev/includes/php.sh @@ -1,12 +1,14 @@ # Include-able script to determine the location of our php if any +# We search for a environment var called PHP, native php, +# a local copy, home directory location used by installphp.sh +# and previous home directory location +# The binary path is returned in $PHP if any -if [ -d "$DEV/php" -a -x "$DEV/php/bin/php" ]; then - # Quick local copy - PHP="$DEV/php/bin/php" -elif [ -d "$HOME/.mediawiki/php" -a -x "$HOME/.mediawiki/php/bin/php" ]; then - # Previous home directory location to install php in - PHP="$HOME/.mediawiki/php/bin/php" -elif [ -d "$HOME/.mwphp" -a -x "$HOME/.mwphp/bin/php" ]; then - # Previous home directory location to install php in - PHP="$HOME/.mwphp/bin/php" -fi +for binary in $PHP `which php || true` "$DEV/php/bin/php" "$HOME/.mediawiki/php/bin/php" "$HOME/.mwphp/bin/php" ]; do + if [ -x "$binary" ]; then + if "$binary" -r 'exit((int)!version_compare(PHP_VERSION, "5.4", ">="));'; then + PHP="$binary" + break + fi + fi +done diff --git a/maintenance/dev/includes/router.php b/maintenance/dev/includes/router.php index f6a062b6..ac96f459 100644 --- a/maintenance/dev/includes/router.php +++ b/maintenance/dev/includes/router.php @@ -1,7 +1,25 @@ <?php - -# Router for the php cli-server built-in webserver -# http://ca2.php.net/manual/en/features.commandline.webserver.php +/** + * Router for the php cli-server built-in webserver. + * http://www.php.net/manual/en/features.commandline.webserver.php + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ if ( php_sapi_name() != 'cli-server' ) { die( "This script can only be run by php's cli-server sapi." ); @@ -66,7 +84,7 @@ if ( $mime ) { # PHP webserver doesn't understand. # ;) Nicely enough we just happen to bundle a mime.types file $f = fopen($file, 'rb'); - if ( preg_match( '^text/', $mime ) ) { + if ( preg_match( '#^text/#', $mime ) ) { # Text should have a charset=UTF-8 (php's webserver does this too) header("Content-Type: $mime; charset=UTF-8"); } else { diff --git a/maintenance/doMaintenance.php b/maintenance/doMaintenance.php index 6b29c5fd..2bb2a0f4 100644 --- a/maintenance/doMaintenance.php +++ b/maintenance/doMaintenance.php @@ -93,6 +93,11 @@ if ( $maintenance->getDbType() === Maintenance::DB_ADMIN && { require( MWInit::interpretedPath( 'AdminSettings.php' ) ); } + +if ( $maintenance->getDbType() === Maintenance::DB_NONE ) { + if ( $wgLocalisationCacheConf['storeClass'] === false && ( $wgLocalisationCacheConf['store'] == 'db' || ( $wgLocalisationCacheConf['store'] == 'detect' && !$wgCacheDirectory ) ) ) + $wgLocalisationCacheConf['storeClass'] = 'LCStore_Null'; +} $maintenance->finalSetup(); // Some last includes require_once( MWInit::compiledPath( 'includes/Setup.php' ) ); diff --git a/maintenance/dumpBackup.php b/maintenance/dumpBackup.php index c49a2963..c9546c60 100644 --- a/maintenance/dumpBackup.php +++ b/maintenance/dumpBackup.php @@ -29,8 +29,8 @@ $originalDir = getcwd(); $optionsWithArgs = array( 'pagelist', 'start', 'end', 'revstart', 'revend'); -require_once( dirname( __FILE__ ) . '/commandLine.inc' ); -require_once( 'backup.inc' ); +require_once( __DIR__ . '/commandLine.inc' ); +require_once( __DIR__ . '/backup.inc' ); $dumper = new BackupDumper( $argv ); @@ -88,6 +88,10 @@ XML interchange wrapper format for export or backup. XML output is sent to stdout; progress reports are sent to stderr. +WARNING: this is not a full database dump! It is merely for public export + of your wiki. For full backup, see our online help at: + https://www.mediawiki.org/wiki/Backup + Usage: php dumpBackup.php <action> [<options>] Actions: --full Dump all revisions of every page. diff --git a/maintenance/dumpIterator.php b/maintenance/dumpIterator.php index 470bc56e..3657f960 100644 --- a/maintenance/dumpIterator.php +++ b/maintenance/dumpIterator.php @@ -4,7 +4,8 @@ * Used as a base class for CompareParsers and PreprocessDump. * We implement below the simple task of searching inside a dump. * - * Copyright (C) 2011 Platonides - http://www.mediawiki.org/ + * Copyright © 2011 Platonides + * http://www.mediawiki.org/ * * 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 @@ -25,8 +26,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Base class for interating over a dump. + * + * @ingroup Maintenance + */ abstract class DumpIterator extends Maintenance { private $count = 0; @@ -56,7 +62,7 @@ abstract class DumpIterator extends Maintenance { return; } - $this->startTime = wfTime(); + $this->startTime = microtime( true ); if ( $this->getOption('dump') == '-' ) { $source = new ImportStreamSource( $this->getStdin() ); @@ -74,7 +80,7 @@ abstract class DumpIterator extends Maintenance { $this->conclusions(); - $delta = wfTime() - $this->startTime; + $delta = microtime( true ) - $this->startTime; $this->error( "Done {$this->count} revisions in " . round($delta, 2) . " seconds " ); if ($delta > 0) $this->error( round($this->count / $delta, 2) . " pages/sec" ); @@ -141,6 +147,11 @@ abstract class DumpIterator extends Maintenance { abstract public function processRevision( $rev ); } +/** + * Maintenance script that runs a regex in the revisions from a dump. + * + * @ingroup Maintenance + */ class SearchDump extends DumpIterator { public function __construct() { diff --git a/maintenance/dumpLinks.php b/maintenance/dumpLinks.php index 0101dc8d..153fdd79 100644 --- a/maintenance/dumpLinks.php +++ b/maintenance/dumpLinks.php @@ -1,8 +1,5 @@ <?php /** - * Copyright (C) 2005 Brion Vibber <brion@pobox.com> - * http://www.mediawiki.org/ - * * Quick demo hack to generate a plaintext link dump, * per the proposed wiki link database standard: * http://www.usemod.com/cgi-bin/mb.pl?LinkDatabase @@ -11,6 +8,9 @@ * Does not include interwiki or URL links. * Dumps ASCII text to stdout; command-line. * + * Copyright © 2005 Brion Vibber <brion@pobox.com> + * http://www.mediawiki.org/ + * * 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 @@ -26,11 +26,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that generates a plaintext link dump. + * + * @ingroup Maintenance + */ class DumpLinks extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/dumpSisterSites.php b/maintenance/dumpSisterSites.php index f5abcd1b..e05e154e 100644 --- a/maintenance/dumpSisterSites.php +++ b/maintenance/dumpSisterSites.php @@ -3,7 +3,7 @@ * Quickie page name dump script for SisterSites usage. * http://www.eekim.com/cgi-bin/wiki.pl?SisterSites * - * Copyright (C) 2006 Brion Vibber <brion@pobox.com> + * Copyright © 2006 Brion Vibber <brion@pobox.com> * http://www.mediawiki.org/ * * This program is free software; you can redistribute it and/or modify @@ -21,11 +21,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that generates a page name dump for SisterSites usage. + * + * @ingroup Maintenance + */ class DumpSisterSites extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/dumpTextPass.php b/maintenance/dumpTextPass.php index 0fed29fc..72d7d97c 100644 --- a/maintenance/dumpTextPass.php +++ b/maintenance/dumpTextPass.php @@ -26,634 +26,8 @@ $originalDir = getcwd(); -require_once( dirname( __FILE__ ) . '/commandLine.inc' ); -require_once( 'backup.inc' ); - -/** - * @ingroup Maintenance - */ -class TextPassDumper extends BackupDumper { - var $prefetch = null; - var $input = "php://stdin"; - var $history = WikiExporter::FULL; - var $fetchCount = 0; - var $prefetchCount = 0; - var $prefetchCountLast = 0; - var $fetchCountLast = 0; - - var $failures = 0; - var $maxFailures = 5; - var $failedTextRetrievals = 0; - var $maxConsecutiveFailedTextRetrievals = 200; - var $failureTimeout = 5; // Seconds to sleep after db failure - - var $php = "php"; - var $spawn = false; - var $spawnProc = false; - var $spawnWrite = false; - var $spawnRead = false; - var $spawnErr = false; - - var $xmlwriterobj = false; - - // when we spend more than maxTimeAllowed seconds on this run, we continue - // processing until we write out the next complete page, then save output file(s), - // rename it/them and open new one(s) - var $maxTimeAllowed = 0; // 0 = no limit - var $timeExceeded = false; - var $firstPageWritten = false; - var $lastPageWritten = false; - var $checkpointJustWritten = false; - var $checkpointFiles = array(); - - /** - * @var DatabaseBase - */ - protected $db; - - function initProgress( $history ) { - parent::initProgress(); - $this->timeOfCheckpoint = $this->startTime; - } - - function dump( $history, $text = WikiExporter::TEXT ) { - // This shouldn't happen if on console... ;) - header( 'Content-type: text/html; charset=UTF-8' ); - - // Notice messages will foul up your XML output even if they're - // relatively harmless. - if ( ini_get( 'display_errors' ) ) - ini_set( 'display_errors', 'stderr' ); - - $this->initProgress( $this->history ); - - $this->db = $this->backupDb(); - - $this->egress = new ExportProgressFilter( $this->sink, $this ); - - // it would be nice to do it in the constructor, oh well. need egress set - $this->finalOptionCheck(); - - // we only want this so we know how to close a stream :-P - $this->xmlwriterobj = new XmlDumpWriter(); - - $input = fopen( $this->input, "rt" ); - $result = $this->readDump( $input ); - - if ( WikiError::isError( $result ) ) { - throw new MWException( $result->getMessage() ); - } - - if ( $this->spawnProc ) { - $this->closeSpawn(); - } - - $this->report( true ); - } - - function processOption( $opt, $val, $param ) { - global $IP; - $url = $this->processFileOpt( $val, $param ); - - switch( $opt ) { - case 'prefetch': - require_once "$IP/maintenance/backupPrefetch.inc"; - $this->prefetch = new BaseDump( $url ); - break; - case 'stub': - $this->input = $url; - break; - case 'maxtime': - $this->maxTimeAllowed = intval($val)*60; - break; - case 'checkpointfile': - $this->checkpointFiles[] = $val; - break; - case 'current': - $this->history = WikiExporter::CURRENT; - break; - case 'full': - $this->history = WikiExporter::FULL; - break; - case 'spawn': - $this->spawn = true; - if ( $val ) { - $this->php = $val; - } - break; - } - } - - function processFileOpt( $val, $param ) { - $fileURIs = explode(';',$param); - foreach ( $fileURIs as $URI ) { - switch( $val ) { - case "file": - $newURI = $URI; - break; - case "gzip": - $newURI = "compress.zlib://$URI"; - break; - case "bzip2": - $newURI = "compress.bzip2://$URI"; - break; - case "7zip": - $newURI = "mediawiki.compress.7z://$URI"; - break; - default: - $newURI = $URI; - } - $newFileURIs[] = $newURI; - } - $val = implode( ';', $newFileURIs ); - return $val; - } - - /** - * Overridden to include prefetch ratio if enabled. - */ - function showReport() { - if ( !$this->prefetch ) { - parent::showReport(); - return; - } - - if ( $this->reporting ) { - $now = wfTimestamp( TS_DB ); - $nowts = wfTime(); - $deltaAll = wfTime() - $this->startTime; - $deltaPart = wfTime() - $this->lastTime; - $this->pageCountPart = $this->pageCount - $this->pageCountLast; - $this->revCountPart = $this->revCount - $this->revCountLast; - - if ( $deltaAll ) { - $portion = $this->revCount / $this->maxCount; - $eta = $this->startTime + $deltaAll / $portion; - $etats = wfTimestamp( TS_DB, intval( $eta ) ); - if ( $this->fetchCount ) { - $fetchRate = 100.0 * $this->prefetchCount / $this->fetchCount; - } else { - $fetchRate = '-'; - } - $pageRate = $this->pageCount / $deltaAll; - $revRate = $this->revCount / $deltaAll; - } else { - $pageRate = '-'; - $revRate = '-'; - $etats = '-'; - $fetchRate = '-'; - } - if ( $deltaPart ) { - if ( $this->fetchCountLast ) { - $fetchRatePart = 100.0 * $this->prefetchCountLast / $this->fetchCountLast; - } else { - $fetchRatePart = '-'; - } - $pageRatePart = $this->pageCountPart / $deltaPart; - $revRatePart = $this->revCountPart / $deltaPart; - - } else { - $fetchRatePart = '-'; - $pageRatePart = '-'; - $revRatePart = '-'; - } - $this->progress( sprintf( "%s: %s (ID %d) %d pages (%0.1f|%0.1f/sec all|curr), %d revs (%0.1f|%0.1f/sec all|curr), %0.1f%%|%0.1f%% prefetched (all|curr), ETA %s [max %d]", - $now, wfWikiID(), $this->ID, $this->pageCount, $pageRate, $pageRatePart, $this->revCount, $revRate, $revRatePart, $fetchRate, $fetchRatePart, $etats, $this->maxCount ) ); - $this->lastTime = $nowts; - $this->revCountLast = $this->revCount; - $this->prefetchCountLast = $this->prefetchCount; - $this->fetchCountLast = $this->fetchCount; - } - } - - function setTimeExceeded() { - $this->timeExceeded = True; - } - - function checkIfTimeExceeded() { - if ( $this->maxTimeAllowed && ( $this->lastTime - $this->timeOfCheckpoint > $this->maxTimeAllowed ) ) { - return true; - } - return false; - } - - function finalOptionCheck() { - if ( ( $this->checkpointFiles && ! $this->maxTimeAllowed ) || - ( $this->maxTimeAllowed && !$this->checkpointFiles ) ) { - throw new MWException("Options checkpointfile and maxtime must be specified together.\n"); - } - foreach ($this->checkpointFiles as $checkpointFile) { - $count = substr_count ( $checkpointFile,"%s" ); - if ( $count != 2 ) { - throw new MWException("Option checkpointfile must contain two '%s' for substitution of first and last pageids, count is $count instead, file is $checkpointFile.\n"); - } - } - - if ( $this->checkpointFiles ) { - $filenameList = (array)$this->egress->getFilenames(); - if ( count( $filenameList ) != count( $this->checkpointFiles ) ) { - throw new MWException("One checkpointfile must be specified for each output option, if maxtime is used.\n"); - } - } - } - - function readDump( $input ) { - $this->buffer = ""; - $this->openElement = false; - $this->atStart = true; - $this->state = ""; - $this->lastName = ""; - $this->thisPage = 0; - $this->thisRev = 0; - - $parser = xml_parser_create( "UTF-8" ); - xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false ); - - xml_set_element_handler( $parser, array( &$this, 'startElement' ), array( &$this, 'endElement' ) ); - xml_set_character_data_handler( $parser, array( &$this, 'characterData' ) ); - - $offset = 0; // for context extraction on error reporting - $bufferSize = 512 * 1024; - do { - if ($this->checkIfTimeExceeded()) { - $this->setTimeExceeded(); - } - $chunk = fread( $input, $bufferSize ); - if ( !xml_parse( $parser, $chunk, feof( $input ) ) ) { - wfDebug( "TextDumpPass::readDump encountered XML parsing error\n" ); - return new WikiXmlError( $parser, 'XML import parse failure', $chunk, $offset ); - } - $offset += strlen( $chunk ); - } while ( $chunk !== false && !feof( $input ) ); - if ($this->maxTimeAllowed) { - $filenameList = (array)$this->egress->getFilenames(); - // we wrote some stuff after last checkpoint that needs renamed - if (file_exists($filenameList[0])) { - $newFilenames = array(); - # we might have just written the header and footer and had no - # pages or revisions written... perhaps they were all deleted - # there's no pageID 0 so we use that. the caller is responsible - # for deciding what to do with a file containing only the - # siteinfo information and the mw tags. - if (! $this->firstPageWritten) { - $firstPageID = str_pad(0,9,"0",STR_PAD_LEFT); - $lastPageID = str_pad(0,9,"0",STR_PAD_LEFT); - } - else { - $firstPageID = str_pad($this->firstPageWritten,9,"0",STR_PAD_LEFT); - $lastPageID = str_pad($this->lastPageWritten,9,"0",STR_PAD_LEFT); - } - for ( $i = 0; $i < count( $filenameList ); $i++ ) { - $checkpointNameFilledIn = sprintf( $this->checkpointFiles[$i], $firstPageID, $lastPageID ); - $fileinfo = pathinfo($filenameList[$i]); - $newFilenames[] = $fileinfo['dirname'] . '/' . $checkpointNameFilledIn; - } - $this->egress->closeAndRename( $newFilenames ); - } - } - xml_parser_free( $parser ); - - return true; - } - - function getText( $id ) { - $this->fetchCount++; - if ( isset( $this->prefetch ) ) { - $text = $this->prefetch->prefetch( $this->thisPage, $this->thisRev ); - if ( $text !== null ) { // Entry missing from prefetch dump - $dbr = wfGetDB( DB_SLAVE ); - $revID = intval( $this->thisRev ); - $revLength = $dbr->selectField( 'revision', 'rev_len', array( 'rev_id' => $revID ) ); - // if length of rev text in file doesn't match length in db, we reload - // this avoids carrying forward broken data from previous xml dumps - if( strlen( $text ) == $revLength ) { - $this->prefetchCount++; - return $text; - } - } - } - return $this->doGetText( $id ); - } - - private function doGetText( $id ) { - $id = intval( $id ); - $this->failures = 0; - $ex = new MWException( "Graceful storage failure" ); - while (true) { - if ( $this->spawn ) { - if ($this->failures) { - // we don't know why it failed, could be the child process - // borked, could be db entry busted, could be db server out to lunch, - // so cover all bases - $this->closeSpawn(); - $this->openSpawn(); - } - $text = $this->getTextSpawned( $id ); - } else { - $text = $this->getTextDbSafe( $id ); - } - if ( $text === false ) { - $this->failures++; - if ( $this->failures > $this->maxFailures) { - $this->progress( "Failed to retrieve revision text for text id ". - "$id after $this->maxFailures tries, giving up" ); - // were there so many bad retrievals in a row we want to bail? - // at some point we have to declare the dump irretrievably broken - $this->failedTextRetrievals++; - if ($this->failedTextRetrievals > $this->maxConsecutiveFailedTextRetrievals) { - throw $ex; - } else { - // would be nice to return something better to the caller someday, - // log what we know about the failure and about the revision - return ""; - } - } else { - $this->progress( "Error $this->failures " . - "of allowed $this->maxFailures retrieving revision text for text id $id! " . - "Pausing $this->failureTimeout seconds before retry..." ); - sleep( $this->failureTimeout ); - } - } else { - $this->failedTextRetrievals= 0; - return $text; - } - } - return ''; - } - - /** - * Fetch a text revision from the database, retrying in case of failure. - * This may survive some transitory errors by reconnecting, but - * may not survive a long-term server outage. - * - * FIXME: WTF? Why is it using a loop and then returning unconditionally? - */ - private function getTextDbSafe( $id ) { - while ( true ) { - try { - $text = $this->getTextDb( $id ); - } catch ( DBQueryError $ex ) { - $text = false; - } - return $text; - } - } - - /** - * May throw a database error if, say, the server dies during query. - * @param $id - * @return bool|string - */ - private function getTextDb( $id ) { - global $wgContLang; - $row = $this->db->selectRow( 'text', - array( 'old_text', 'old_flags' ), - array( 'old_id' => $id ), - __METHOD__ ); - $text = Revision::getRevisionText( $row ); - if ( $text === false ) { - return false; - } - $stripped = str_replace( "\r", "", $text ); - $normalized = $wgContLang->normalize( $stripped ); - return $normalized; - } - - private function getTextSpawned( $id ) { - wfSuppressWarnings(); - if ( !$this->spawnProc ) { - // First time? - $this->openSpawn(); - } - $text = $this->getTextSpawnedOnce( $id ); - wfRestoreWarnings(); - return $text; - } - - function openSpawn() { - global $IP; - - if ( file_exists( "$IP/../multiversion/MWScript.php" ) ) { - $cmd = implode( " ", - array_map( 'wfEscapeShellArg', - array( - $this->php, - "$IP/../multiversion/MWScript.php", - "fetchText.php", - '--wiki', wfWikiID() ) ) ); - } - else { - $cmd = implode( " ", - array_map( 'wfEscapeShellArg', - array( - $this->php, - "$IP/maintenance/fetchText.php", - '--wiki', wfWikiID() ) ) ); - } - $spec = array( - 0 => array( "pipe", "r" ), - 1 => array( "pipe", "w" ), - 2 => array( "file", "/dev/null", "a" ) ); - $pipes = array(); - - $this->progress( "Spawning database subprocess: $cmd" ); - $this->spawnProc = proc_open( $cmd, $spec, $pipes ); - if ( !$this->spawnProc ) { - // shit - $this->progress( "Subprocess spawn failed." ); - return false; - } - list( - $this->spawnWrite, // -> stdin - $this->spawnRead, // <- stdout - ) = $pipes; - - return true; - } - - private function closeSpawn() { - wfSuppressWarnings(); - if ( $this->spawnRead ) - fclose( $this->spawnRead ); - $this->spawnRead = false; - if ( $this->spawnWrite ) - fclose( $this->spawnWrite ); - $this->spawnWrite = false; - if ( $this->spawnErr ) - fclose( $this->spawnErr ); - $this->spawnErr = false; - if ( $this->spawnProc ) - pclose( $this->spawnProc ); - $this->spawnProc = false; - wfRestoreWarnings(); - } - - private function getTextSpawnedOnce( $id ) { - global $wgContLang; - - $ok = fwrite( $this->spawnWrite, "$id\n" ); - // $this->progress( ">> $id" ); - if ( !$ok ) return false; - - $ok = fflush( $this->spawnWrite ); - // $this->progress( ">> [flush]" ); - if ( !$ok ) return false; - - // check that the text id they are sending is the one we asked for - // this avoids out of sync revision text errors we have encountered in the past - $newId = fgets( $this->spawnRead ); - if ( $newId === false ) { - return false; - } - if ( $id != intval( $newId ) ) { - return false; - } - - $len = fgets( $this->spawnRead ); - // $this->progress( "<< " . trim( $len ) ); - if ( $len === false ) return false; - - $nbytes = intval( $len ); - // actual error, not zero-length text - if ($nbytes < 0 ) return false; - - $text = ""; - - // Subprocess may not send everything at once, we have to loop. - while ( $nbytes > strlen( $text ) ) { - $buffer = fread( $this->spawnRead, $nbytes - strlen( $text ) ); - if ( $buffer === false ) break; - $text .= $buffer; - } - - $gotbytes = strlen( $text ); - if ( $gotbytes != $nbytes ) { - $this->progress( "Expected $nbytes bytes from database subprocess, got $gotbytes " ); - return false; - } - - // Do normalization in the dump thread... - $stripped = str_replace( "\r", "", $text ); - $normalized = $wgContLang->normalize( $stripped ); - return $normalized; - } - - function startElement( $parser, $name, $attribs ) { - $this->checkpointJustWritten = false; - - $this->clearOpenElement( null ); - $this->lastName = $name; - - if ( $name == 'revision' ) { - $this->state = $name; - $this->egress->writeOpenPage( null, $this->buffer ); - $this->buffer = ""; - } elseif ( $name == 'page' ) { - $this->state = $name; - if ( $this->atStart ) { - $this->egress->writeOpenStream( $this->buffer ); - $this->buffer = ""; - $this->atStart = false; - } - } - - if ( $name == "text" && isset( $attribs['id'] ) ) { - $text = $this->getText( $attribs['id'] ); - $this->openElement = array( $name, array( 'xml:space' => 'preserve' ) ); - if ( strlen( $text ) > 0 ) { - $this->characterData( $parser, $text ); - } - } else { - $this->openElement = array( $name, $attribs ); - } - } - - function endElement( $parser, $name ) { - $this->checkpointJustWritten = false; - - if ( $this->openElement ) { - $this->clearOpenElement( "" ); - } else { - $this->buffer .= "</$name>"; - } - - if ( $name == 'revision' ) { - $this->egress->writeRevision( null, $this->buffer ); - $this->buffer = ""; - $this->thisRev = ""; - } elseif ( $name == 'page' ) { - if (! $this->firstPageWritten) { - $this->firstPageWritten = trim($this->thisPage); - } - $this->lastPageWritten = trim($this->thisPage); - if ($this->timeExceeded) { - $this->egress->writeClosePage( $this->buffer ); - // nasty hack, we can't just write the chardata after the - // page tag, it will include leading blanks from the next line - $this->egress->sink->write("\n"); - - $this->buffer = $this->xmlwriterobj->closeStream(); - $this->egress->writeCloseStream( $this->buffer ); - - $this->buffer = ""; - $this->thisPage = ""; - // this could be more than one file if we had more than one output arg - - $filenameList = (array)$this->egress->getFilenames(); - $newFilenames = array(); - $firstPageID = str_pad($this->firstPageWritten,9,"0",STR_PAD_LEFT); - $lastPageID = str_pad($this->lastPageWritten,9,"0",STR_PAD_LEFT); - for ( $i = 0; $i < count( $filenameList ); $i++ ) { - $checkpointNameFilledIn = sprintf( $this->checkpointFiles[$i], $firstPageID, $lastPageID ); - $fileinfo = pathinfo($filenameList[$i]); - $newFilenames[] = $fileinfo['dirname'] . '/' . $checkpointNameFilledIn; - } - $this->egress->closeRenameAndReopen( $newFilenames ); - $this->buffer = $this->xmlwriterobj->openStream(); - $this->timeExceeded = false; - $this->timeOfCheckpoint = $this->lastTime; - $this->firstPageWritten = false; - $this->checkpointJustWritten = true; - } - else { - $this->egress->writeClosePage( $this->buffer ); - $this->buffer = ""; - $this->thisPage = ""; - } - - } elseif ( $name == 'mediawiki' ) { - $this->egress->writeCloseStream( $this->buffer ); - $this->buffer = ""; - } - } - - function characterData( $parser, $data ) { - $this->clearOpenElement( null ); - if ( $this->lastName == "id" ) { - if ( $this->state == "revision" ) { - $this->thisRev .= $data; - } elseif ( $this->state == "page" ) { - $this->thisPage .= $data; - } - } - // have to skip the newline left over from closepagetag line of - // end of checkpoint files. nasty hack!! - if ($this->checkpointJustWritten) { - if ($data[0] == "\n") { - $data = substr($data,1); - } - $this->checkpointJustWritten = false; - } - $this->buffer .= htmlspecialchars( $data ); - } - - function clearOpenElement( $style ) { - if ( $this->openElement ) { - $this->buffer .= Xml::element( $this->openElement[0], $this->openElement[1], $style ); - $this->openElement = false; - } - } -} +require_once( __DIR__ . '/commandLine.inc' ); +require_once( __DIR__ . '/backupTextPass.inc' ); $dumper = new TextPassDumper( $argv ); diff --git a/maintenance/dumpUploads.php b/maintenance/dumpUploads.php index 919bb4df..0d0dfcf3 100644 --- a/maintenance/dumpUploads.php +++ b/maintenance/dumpUploads.php @@ -1,6 +1,6 @@ <?php /** - * Dump a the list of files uploaded, for feeding to tar or similar + * Dump a the list of files uploaded, for feeding to tar or similar. * * 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 @@ -17,11 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to dump a the list of files uploaded, + * for feeding to tar or similar. + * + * @ingroup Maintenance + */ class UploadDumper extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/edit.php b/maintenance/edit.php index 88573714..59df5e88 100644 --- a/maintenance/edit.php +++ b/maintenance/edit.php @@ -1,6 +1,6 @@ <?php /** - * Make an edit + * Make a page edit. * * 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 @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to make a page edit. + * + * @ingroup Maintenance + */ class EditCLI extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/eval.php b/maintenance/eval.php index 3bd164fd..5aefe1c9 100644 --- a/maintenance/eval.php +++ b/maintenance/eval.php @@ -34,7 +34,7 @@ $optionsWithArgs = array( 'd' ); /** */ -require_once( dirname( __FILE__ ) . "/commandLine.inc" ); +require_once( __DIR__ . "/commandLine.inc" ); if ( isset( $options['d'] ) ) { $d = $options['d']; diff --git a/maintenance/fetchText.php b/maintenance/fetchText.php index 3b43bcd5..a705bcca 100644 --- a/maintenance/fetchText.php +++ b/maintenance/fetchText.php @@ -1,6 +1,6 @@ <?php /** - * Communications protocol... + * Communications protocol. * This is used by dumpTextPass.php when the --spawn option is present. * * This program is free software; you can redistribute it and/or modify @@ -18,11 +18,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script used to fetch page text in a subprocess. + * + * @ingroup Maintenance + */ class FetchText extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/fileOpPerfTest.php b/maintenance/fileOpPerfTest.php new file mode 100644 index 00000000..501bcfc3 --- /dev/null +++ b/maintenance/fileOpPerfTest.php @@ -0,0 +1,146 @@ +<?php +/** + * Test for fileop performance. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Maintenance + */ + +$initialTime = microtime( true ); +$wgProfiler = array( 'class' => 'ProfilerSimpleText' ); +error_reporting( E_ALL ); + +require_once( __DIR__ . '/Maintenance.php' ); + +/** + * Maintenance script to test fileop performance. + * + * @ingroup Maintenance + */ +class TestFileOpPerformance extends Maintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = "Test fileop performance"; + $this->addOption( 'b1', 'Backend 1', true, true ); + $this->addOption( 'b2', 'Backend 2', false, true ); + $this->addOption( 'srcdir', 'File source directory', true, true ); + $this->addOption( 'maxfiles', 'Max files', false, true ); + $this->addOption( 'quick', 'Avoid operation pre-checks' ); + } + + public function execute() { + $backend = FileBackendGroup::singleton()->get( $this->getOption( 'b1' ) ); + $this->doPerfTest( $backend ); + + if ( $this->getOption( 'b2' ) ) { + $backend = FileBackendGroup::singleton()->get( $this->getOption( 'b2' ) ); + $this->doPerfTest( $backend ); + } + + $profiler = Profiler::instance(); + $profiler->setTemplated( true ); + $profiler->logData(); // prints + } + + protected function doPerfTest( FileBackend $backend ) { + $ops1 = array(); + $ops2 = array(); + $ops3 = array(); + $ops4 = array(); + $ops5 = array(); + + $baseDir = 'mwstore://' . $backend->getName() . '/testing-cont1'; + $backend->prepare( array( 'dir' => $baseDir ) ); + + $dirname = $this->getOption( 'srcdir' ); + $dir = opendir( $dirname ); + if ( !$dir ) { + return; + } + + while ( $dir && ( $file = readdir( $dir ) ) !== false ) { + if ( $file[0] != '.' ) { + $this->output( "Using '$dirname/$file' in operations.\n" ); + $dst = $baseDir . '/' . wfBaseName( $file ); + $ops1[] = array( 'op' => 'store', + 'src' => "$dirname/$file", 'dst' => $dst, 'overwrite' => 1); + $ops2[] = array( 'op' => 'copy', + 'src' => "$dst", 'dst' => "$dst-1", 'overwrite' => 1 ); + $ops3[] = array( 'op' => 'move', + 'src' => $dst, 'dst' => "$dst-2", 'overwrite' => 1 ); + $ops4[] = array( 'op' => 'delete', 'src' => "$dst-1" ); + $ops5[] = array( 'op' => 'delete', 'src' => "$dst-2" ); + } + if ( count( $ops1 ) >= $this->getOption( 'maxfiles', 20 ) ) { + break; // enough + } + } + closedir( $dir ); + $this->output( "\n" ); + + $method = $this->hasOption( 'quick' ) ? 'doQuickOperations' : 'doOperations'; + + $start = microtime( true ); + $status = $backend->$method( $ops1, array( 'force' => 1 ) ); + $e = ( microtime( true ) - $start ) * 1000; + if ( $status->getErrorsArray() ) { + print_r( $status->getErrorsArray() ); + exit(0); + } + $this->output( $backend->getName() . ": Stored " . count( $ops1 ) . " files in $e ms.\n" ); + + $start = microtime( true ); + $backend->$method( $ops2, array( 'force' => 1 ) ); + $e = ( microtime( true ) - $start ) * 1000; + if ( $status->getErrorsArray() ) { + print_r( $status->getErrorsArray() ); + exit(0); + } + $this->output( $backend->getName() . ": Copied " . count( $ops2 ) . " files in $e ms.\n" ); + + $start = microtime( true ); + $backend->$method( $ops3, array( 'force' => 1 ) ); + $e = ( microtime( true ) - $start ) * 1000; + if ( $status->getErrorsArray() ) { + print_r( $status->getErrorsArray() ); + exit(0); + } + $this->output( $backend->getName() . ": Moved " . count( $ops3 ) . " files in $e ms.\n" ); + + $start = microtime( true ); + $backend->$method( $ops4, array( 'force' => 1 ) ); + $e = ( microtime( true ) - $start ) * 1000; + if ( $status->getErrorsArray() ) { + print_r( $status->getErrorsArray() ); + exit(0); + } + $this->output( $backend->getName() . ": Deleted " . count( $ops4 ) . " files in $e ms.\n" ); + + $start = microtime( true ); + $backend->$method( $ops5, array( 'force' => 1 ) ); + $e = ( microtime( true ) - $start ) * 1000; + if ( $status->getErrorsArray() ) { + print_r( $status->getErrorsArray() ); + exit(0); + } + $this->output( $backend->getName() . ": Deleted " . count( $ops5 ) . " files in $e ms.\n" ); + } +} + +$maintClass = "TestFileOpPerformance"; +require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/findHooks.php b/maintenance/findHooks.php index cb582857..e273c545 100644 --- a/maintenance/findHooks.php +++ b/maintenance/findHooks.php @@ -34,8 +34,13 @@ * @author Antoine Musso <hashar at free dot fr> */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that compares documented and actually present mismatches. + * + * @ingroup Maintenance + */ class FindHooks extends Maintenance { public function __construct() { parent::__construct(); @@ -63,8 +68,10 @@ class FindHooks extends Maintenance { $IP . '/includes/db/', $IP . '/includes/diff/', $IP . '/includes/filerepo/', + $IP . '/includes/filerepo/file/', $IP . '/includes/installer/', $IP . '/includes/interwiki/', + $IP . '/includes/logging/', $IP . '/includes/media/', $IP . '/includes/parser/', $IP . '/includes/resourceloader/', @@ -157,7 +164,7 @@ class FindHooks extends Maintenance { /** * Get hooks from a PHP file - * @param $file Full filename to the PHP file. + * @param $file string Full filename to the PHP file. * @return array of hooks found. */ private function getHooksFromFile( $file ) { @@ -188,7 +195,7 @@ class FindHooks extends Maintenance { /** * Get bad hooks (where the hook name could not be determined) from a PHP file - * @param $file Full filename to the PHP file. + * @param $file string Full filename to the PHP file. * @return array of bad wfRunHooks() lines */ private function getBadHooksFromFile( $file ) { diff --git a/maintenance/fixDoubleRedirects.php b/maintenance/fixDoubleRedirects.php index c1d14dd8..6f017eca 100644 --- a/maintenance/fixDoubleRedirects.php +++ b/maintenance/fixDoubleRedirects.php @@ -1,8 +1,8 @@ <?php /** - * Script to fix double redirects. + * Fix double redirects. * - * Copyright (C) 2011 Ilmari Karonen <nospam@vyznev.net> + * Copyright © 2011 Ilmari Karonen <nospam@vyznev.net> * http://www.mediawiki.org/ * * This program is free software; you can redistribute it and/or modify @@ -25,15 +25,20 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that fixes double redirects. + * + * @ingroup Maintenance + */ class FixDoubleRedirects extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Script to fix double redirects"; $this->addOption( 'async', 'Don\'t fix anything directly, just queue the jobs' ); $this->addOption( 'title', 'Fix only redirects pointing to this page', false, true ); - $this->addOption( 'dry-run', 'Perform a dry run, fix nothing' ); + $this->addOption( 'dry-run', 'Perform a dry run, fix nothing' ); } public function execute() { diff --git a/maintenance/fixExtLinksProtocolRelative.php b/maintenance/fixExtLinksProtocolRelative.php index 0cabe816..2403ec68 100644 --- a/maintenance/fixExtLinksProtocolRelative.php +++ b/maintenance/fixExtLinksProtocolRelative.php @@ -19,11 +19,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that fixes any entriy for protocol-relative URLs + * in the externallinks table. + * + * @ingroup Maintenance + */ class FixExtLinksProtocolRelative extends LoggedUpdateMaintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/fixSlaveDesync.php b/maintenance/fixSlaveDesync.php index 3c6888ae..8bf556f0 100644 --- a/maintenance/fixSlaveDesync.php +++ b/maintenance/fixSlaveDesync.php @@ -1,5 +1,7 @@ <?php /** + * Fix erroneous page_latest values due to slave desynchronisation. + * * 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 @@ -15,11 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that fixes erroneous page_latest values + * due to slave desynchronisation. + * + * @ingroup Maintenance + */ class FixSlaveDesync extends Maintenance { public function __construct() { parent::__construct(); @@ -88,7 +97,7 @@ class FixSlaveDesync extends Maintenance { private function desyncFixPage( $pageID ) { # Check for a corrupted page_latest $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $realLatest = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), __METHOD__, 'FOR UPDATE' ); # list( $masterFile, $masterPos ) = $dbw->getMasterPos(); @@ -98,7 +107,7 @@ class FixSlaveDesync extends Maintenance { /* if ( !$db->masterPosWait( $masterFile, $masterPos, 10 ) ) { $this->output( "Slave is too lagged, aborting\n" ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); sleep(10); return; }*/ @@ -112,7 +121,7 @@ class FixSlaveDesync extends Maintenance { } if ( !$found ) { $this->output( "page_id $pageID seems fine\n" ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); return; } @@ -199,7 +208,7 @@ class FixSlaveDesync extends Maintenance { } $this->output( "done\n" ); } - $dbw->commit(); + $dbw->commit( __METHOD__ ); } } diff --git a/maintenance/fixTimestamps.php b/maintenance/fixTimestamps.php index 3e3bd0a5..84d08d39 100644 --- a/maintenance/fixTimestamps.php +++ b/maintenance/fixTimestamps.php @@ -1,10 +1,10 @@ <?php /** - * This script fixes timestamp corruption caused by one or more webservers - * temporarily being set to the wrong time. The time offset must be known and - * consistent. Start and end times (in 14-character format) restrict the search, - * and must bracket the damage. There must be a majority of good timestamps in the - * search period. + * Fixes timestamp corruption caused by one or more webservers temporarily + * being set to the wrong time. + * The time offset must be known and consistent. Start and end times + * (in 14-character format) restrict the search, and must bracket the damage. + * There must be a majority of good timestamps in the search period. * * 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 @@ -21,11 +21,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that fixes timestamp corruption caused by one or + * more webservers temporarily being set to the wrong time. + * + * @ingroup Maintenance + */ class FixTimestamps extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/fixUserRegistration.php b/maintenance/fixUserRegistration.php index d4ff7c23..91d42a5d 100644 --- a/maintenance/fixUserRegistration.php +++ b/maintenance/fixUserRegistration.php @@ -18,11 +18,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that fixes the user_registration field. + * + * @ingroup Maintenance + */ class FixUserRegistration extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/formatInstallDoc.php b/maintenance/formatInstallDoc.php index b3bb50ca..600ca976 100644 --- a/maintenance/formatInstallDoc.php +++ b/maintenance/formatInstallDoc.php @@ -1,10 +1,33 @@ <?php /** + * Format RELEASE-NOTE file to wiki text or HTML markup. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) .'/Maintenance.php' ); +require_once( __DIR__ .'/Maintenance.php' ); +/** + * Maintenance script that formats RELEASE-NOTE file to wiki text or HTML markup. + * + * @ingroup Maintenance + */ class MaintenanceFormatInstallDoc extends Maintenance { function __construct() { parent::__construct(); diff --git a/maintenance/fuzz-tester.php b/maintenance/fuzz-tester.php index d87d6281..1c96a571 100644 --- a/maintenance/fuzz-tester.php +++ b/maintenance/fuzz-tester.php @@ -181,7 +181,7 @@ TODO: // ///////////////////////// COMMAND LINE HELP //////////////////////////////////// // This is a command line script, load MediaWiki env (gives command line options); -require_once( dirname( __FILE__ ) . '/commandLine.inc' ); +require_once( __DIR__ . '/commandLine.inc' ); // if the user asked for an explanation of command line options. if ( isset( $options["help"] ) ) { @@ -381,7 +381,6 @@ class wikiFuzz { "br" => array( "CLASS", "ID", "STYLE", "title", "clear" ), "cite" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), "var" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), - "dl" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), "ruby" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), "rt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), "rp" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ), @@ -817,7 +816,7 @@ class wikiFuzz { * Returns the matched character slash-escaped as in a C string * Helper for makeTitleSafe callback * @param $matches - * @return atring + * @return string */ static private function stringEscape( $matches ) { return sprintf( "\\x%02x", ord( $matches[1] ) ); @@ -1360,6 +1359,7 @@ class viewPageTest extends pageTest { "rdfrom" => wikiFuzz::makeFuzz( 2 ), // things from Article.php from here on: "token" => wikiFuzz::makeFuzz( 2 ), "tbid" => wikiFuzz::makeFuzz( 2 ), + // @todo FIXME: Duplicate array key. "action" => wikiFuzz::chooseInput( array( "purge", wikiFuzz::makeFuzz( 2 ) ) ), "wpReason" => wikiFuzz::makeFuzz( 2 ), "wpEditToken" => wikiFuzz::makeFuzz( 2 ), diff --git a/maintenance/generateSitemap.php b/maintenance/generateSitemap.php index 80d31f97..f3a5d875 100644 --- a/maintenance/generateSitemap.php +++ b/maintenance/generateSitemap.php @@ -1,6 +1,6 @@ <?php /** - * Creates a sitemap for the site + * Creates a sitemap for the site. * * Copyright © 2005, Ævar Arnfjörð Bjarmason, Jens Frank <jeluf@gmx.de> and * Brion Vibber <brion@pobox.com> @@ -26,8 +26,13 @@ * @see http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that generates a sitemap for the site. + * + * @ingroup Maintenance + */ class GenerateSitemap extends Maintenance { const GS_MAIN = -2; const GS_TALK = -1; @@ -72,6 +77,13 @@ class GenerateSitemap extends Maintenance { var $compress; /** + * Whether or not to include redirection pages + * + * @var bool + */ + var $skipRedirects; + + /** * The number of entries to save in each sitemap file * * @var array @@ -137,6 +149,7 @@ class GenerateSitemap extends Maintenance { $this->addOption( 'fspath', 'The file system path to save to, e.g. /tmp/sitemap; defaults to current directory', false, true ); $this->addOption( 'urlpath', 'The URL path corresponding to --fspath, prepended to filenames in the index; defaults to an empty string', false, true ); $this->addOption( 'compress', 'Compress the sitemap files, can take value yes|no, default yes', false, true ); + $this->addOption( 'skip-redirects', 'Do not include redirecting articles in the sitemap' ); $this->addOption( 'identifier', 'What site identifier to use for the wiki, defaults to $wgDBname', false, true ); } @@ -154,6 +167,7 @@ class GenerateSitemap extends Maintenance { } $this->identifier = $this->getOption( 'identifier', wfWikiID() ); $this->compress = $this->getOption( 'compress', 'yes' ) !== 'no'; + $this->skipRedirects = $this->getOption( 'skip-redirects', false ) !== false ; $this->dbr = wfGetDB( DB_SLAVE ); $this->generateNamespaces(); $this->timestamp = wfTimestamp( TS_ISO_8601, wfTimestampNow() ); @@ -264,7 +278,7 @@ class GenerateSitemap extends Maintenance { * @return String */ function guessPriority( $namespace ) { - return MWNamespace::isMain( $namespace ) ? $this->priorities[self::GS_MAIN] : $this->priorities[self::GS_TALK]; + return MWNamespace::isSubject( $namespace ) ? $this->priorities[self::GS_MAIN] : $this->priorities[self::GS_TALK]; } /** @@ -279,6 +293,7 @@ class GenerateSitemap extends Maintenance { 'page_namespace', 'page_title', 'page_touched', + 'page_is_redirect' ), array( 'page_namespace' => $namespace ), __METHOD__ @@ -302,7 +317,13 @@ class GenerateSitemap extends Maintenance { $fns = $wgContLang->getFormattedNsText( $namespace ); $this->output( "$namespace ($fns)\n" ); + $skippedRedirects = 0; // Number of redirects skipped for that namespace foreach ( $res as $row ) { + if ($this->skipRedirects && $row->page_is_redirect ) { + $skippedRedirects++; + continue; + } + if ( $i++ === 0 || $i === $this->url_limit + 1 || $length + $this->limit[1] + $this->limit[2] > $this->size_limit ) { if ( $this->file !== false ) { $this->write( $this->file, $this->closeFile() ); @@ -332,6 +353,11 @@ class GenerateSitemap extends Maintenance { } } } + + if ($this->skipRedirects && $skippedRedirects > 0) { + $this->output( " skipped $skippedRedirects redirect(s)\n" ); + } + if ( $this->file ) { $this->write( $this->file, $this->closeFile() ); $this->close( $this->file ); diff --git a/maintenance/getLagTimes.php b/maintenance/getLagTimes.php index 0322fa2d..72b1d48a 100644 --- a/maintenance/getLagTimes.php +++ b/maintenance/getLagTimes.php @@ -1,5 +1,7 @@ <?php /** + * Display replication lag times. + * * 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 @@ -15,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that displays replication lag times. + * + * @ingroup Maintenance + */ class GetLagTimes extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/getSlaveServer.php b/maintenance/getSlaveServer.php index 3d13bc4e..ec9ed20a 100644 --- a/maintenance/getSlaveServer.php +++ b/maintenance/getSlaveServer.php @@ -1,6 +1,6 @@ <?php /** - * This script reports the hostname of a slave server. + * Reports the hostname of a slave server. * * 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 @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that reports the hostname of a slave server. + * + * @ingroup Maintenance + */ class GetSlaveServer extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/getText.php b/maintenance/getText.php index eb044117..3e2f8540 100644 --- a/maintenance/getText.php +++ b/maintenance/getText.php @@ -1,6 +1,7 @@ <?php /** - * Outputs page text to stdout, useful for command-line editing automation. + * Outputs page text to stdout. + * Useful for command-line editing automation. * Example: php getText.php "page title" | sed -e '...' | php edit.php "page title" * * This program is free software; you can redistribute it and/or modify @@ -18,11 +19,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that outputs page text to stdout. + * + * @ingroup Maintenance + */ class GetTextMaint extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/hiphop/make b/maintenance/hiphop/make index 2bb9951f..2fa70dcb 100644 --- a/maintenance/hiphop/make +++ b/maintenance/hiphop/make @@ -2,7 +2,7 @@ <?php define( 'MW_CONFIG_CALLBACK', 'MakeHipHop::noConfigNeeded' ); -require( dirname( __FILE__ ) . '/../Maintenance.php' ); +require( __DIR__ . '/../Maintenance.php' ); class MakeHipHop extends Maintenance { function noConfigNeeded() {} @@ -12,7 +12,7 @@ class MakeHipHop extends Maintenance { $startTime = time(); - $thisDir = realpath( dirname( __FILE__ ) ); + $thisDir = realpath( __DIR__ ); $IP = realpath( "$thisDir/../.." ); if ( strval( $wgHipHopBuildDirectory ) !== '' ) { $buildDir = $wgHipHopBuildDirectory; @@ -278,7 +278,7 @@ class MakeHipHop extends Maintenance { } } - $extraCoreFiles = array_map( 'trim', file( dirname( __FILE__ ) . '/extra-files' ) ); + $extraCoreFiles = array_map( 'trim', file( __DIR__ . '/extra-files' ) ); foreach ( $extraCoreFiles as $file ) { if ( $file === '' ) { continue; diff --git a/maintenance/hiphop/run-server b/maintenance/hiphop/run-server index 0ad43134..1c4b51f4 100644 --- a/maintenance/hiphop/run-server +++ b/maintenance/hiphop/run-server @@ -1,7 +1,7 @@ #!/usr/bin/hphpi -f <?php -require( dirname( __FILE__ ) . '/../Maintenance.php' ); +require( __DIR__ . '/../Maintenance.php' ); class RunHipHopServer extends Maintenance { function __construct() { @@ -19,7 +19,7 @@ class RunHipHopServer extends Maintenance { function runCompiled() { global $wgHipHopBuildDirectory; - $thisDir = realpath( dirname( __FILE__ ) ); + $thisDir = realpath( __DIR__ ); $IP = realpath( "$thisDir/../.." ); if ( strval( $wgHipHopBuildDirectory ) !== '' ) { $buildDir = $wgHipHopBuildDirectory; @@ -51,7 +51,7 @@ class RunHipHopServer extends Maintenance { } function runInterpreted() { - $thisDir = realpath( dirname( __FILE__ ) ); + $thisDir = realpath( __DIR__ ); $IP = realpath( "$thisDir/../.." ); $sourceBase = realpath( "$IP/.." ); diff --git a/maintenance/ibm_db2/tables.sql b/maintenance/ibm_db2/tables.sql index 66fc6564..caad9251 100644 --- a/maintenance/ibm_db2/tables.sql +++ b/maintenance/ibm_db2/tables.sql @@ -371,7 +371,9 @@ CREATE TABLE ipblocks ( ipb_range_end VARCHAR(1024), ipb_deleted SMALLINT NOT NULL DEFAULT 0, ipb_block_email SMALLINT NOT NULL DEFAULT 0, - ipb_allow_usertalk SMALLINT NOT NULL DEFAULT 0 + ipb_allow_usertalk SMALLINT NOT NULL DEFAULT 0, + ipb_parent_block_id INTEGER DEFAULT NULL + -- REFERENCES ipblocks(ipb_id) ON DELETE SET NULL ); CREATE INDEX ipb_address @@ -926,13 +928,3 @@ CREATE TABLE user_former_groups ( ); CREATE UNIQUE INDEX ufg_user_group ON user_former_groups (ufg_user, ufg_group); - - - --- Table for holding configuration changes -CREATE TABLE config ( - cf_name VARCHAR(255) NOT NULL - PRIMARY KEY, - cf_value CLOB(64K) INLINE LENGTH 4096 NOT NULL -); - diff --git a/maintenance/importDump.php b/maintenance/importDump.php index 2ad0872f..f51d7ad7 100644 --- a/maintenance/importDump.php +++ b/maintenance/importDump.php @@ -1,6 +1,8 @@ <?php /** - * Copyright (C) 2005 Brion Vibber <brion@pobox.com> + * Import XML dump files into the current wiki. + * + * Copyright © 2005 Brion Vibber <brion@pobox.com> * http://www.mediawiki.org/ * * This program is free software; you can redistribute it and/or modify @@ -22,9 +24,11 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); /** + * Maintenance script that imports XML dump files into the current wiki. + * * @ingroup Maintenance */ class BackupReader extends Maintenance { @@ -204,7 +208,7 @@ TEXT; function showReport() { if ( !$this->mQuiet ) { - $delta = wfTime() - $this->startTime; + $delta = microtime( true ) - $this->startTime; if ( $delta ) { $rate = sprintf( "%.2f", $this->pageCount / $delta ); $revrate = sprintf( "%.2f", $this->revCount / $delta ); @@ -250,7 +254,7 @@ TEXT; } function importFromHandle( $handle ) { - $this->startTime = wfTime(); + $this->startTime = microtime( true ); $source = new ImportStreamSource( $handle ); $importer = new WikiImporter( $source ); diff --git a/maintenance/importImages.inc b/maintenance/importImages.inc index 5d35e2c0..ac5d1443 100644 --- a/maintenance/importImages.inc +++ b/maintenance/importImages.inc @@ -1,6 +1,6 @@ <?php /** - * Support functions for the importImages script + * Support functions for the importImages.php script * * 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 @@ -26,7 +26,7 @@ /** * Search a directory for files with one of a set of extensions * - * @param $dir Path to directory to search + * @param $dir string Path to directory to search * @param $exts Array of extensions to search for * @return mixed Array of filenames on success, or false on failure */ @@ -74,9 +74,9 @@ function splitFilename( $filename ) { * files for acme.foo.bar and the extension ".txt". With $maxStrip = 2, * acme.txt would also be acceptable. * - * @param $file base path - * @param $auxExtension the extension to be appended to the base path - * @param $maxStrip the maximum number of extensions to strip from the base path (default: 1) + * @param $file string base path + * @param $auxExtension string the extension to be appended to the base path + * @param $maxStrip int the maximum number of extensions to strip from the base path (default: 1) * @return string or false */ function findAuxFile( $file, $auxExtension, $maxStrip = 1 ) { diff --git a/maintenance/importImages.php b/maintenance/importImages.php index bd077ff9..8d92383d 100644 --- a/maintenance/importImages.php +++ b/maintenance/importImages.php @@ -1,8 +1,7 @@ <?php - /** - * Maintenance script to import one or more images from the local file system into - * the wiki without using the web-based interface. + * Import one or more images from the local file system into the wiki without + * using the web-based interface. * * "Smart import" additions: * - aim: preserve the essential metadata (user, description) when importing medias from an existing wiki @@ -33,8 +32,8 @@ */ $optionsWithArgs = array( 'extensions', 'comment', 'comment-file', 'comment-ext', 'user', 'license', 'sleep', 'limit', 'from', 'source-wiki-url' ); -require_once( dirname( __FILE__ ) . '/commandLine.inc' ); -require_once( dirname( __FILE__ ) . '/importImages.inc' ); +require_once( __DIR__ . '/commandLine.inc' ); +require_once( __DIR__ . '/importImages.inc' ); $processed = $added = $ignored = $skipped = $overwritten = $failed = 0; echo( "Import Images\n\n" ); diff --git a/maintenance/importSiteScripts.php b/maintenance/importSiteScripts.php index 0dc200ec..e369cb15 100644 --- a/maintenance/importSiteScripts.php +++ b/maintenance/importSiteScripts.php @@ -1,13 +1,34 @@ <?php /** - * Maintenance script to import all scripts in the MediaWiki namespace from a - * local site. + * Import all scripts in the MediaWiki namespace from a local site. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to import all scripts in the MediaWiki namespace from a + * local site. + * + * @ingroup Maintenance + */ class ImportSiteScripts extends Maintenance { public function __construct() { parent::__construct(); @@ -16,17 +37,17 @@ class ImportSiteScripts extends Maintenance { $this->addArg( 'index', 'index.php base url' ); $this->addOption( 'username', 'User name of the script importer' ); } - + public function execute() { global $wgUser; $user = User::newFromName( $this->getOption( 'username', 'ScriptImporter' ) ); $wgUser = $user; - + $baseUrl = $this->getArg( 1 ); $pageList = $this->fetchScriptList(); $this->output( 'Importing ' . count( $pageList ) . " pages\n" ); - + foreach ( $pageList as $page ) { $title = Title::makeTitleSafe( NS_MEDIAWIKI, $page ); if ( !$title ) { @@ -35,34 +56,34 @@ class ImportSiteScripts extends Maintenance { } $this->output( "Importing $page\n" ); - $url = wfAppendQuery( $baseUrl, array( - 'action' => 'raw', + $url = wfAppendQuery( $baseUrl, array( + 'action' => 'raw', 'title' => "MediaWiki:{$page}" ) ); $text = Http::get( $url ); $wikiPage = WikiPage::factory( $title ); $wikiPage->doEdit( $text, "Importing from $url", 0, false, $user ); } - + } - + protected function fetchScriptList() { - $data = array( + $data = array( 'action' => 'query', 'format' => 'php',//'json', 'list' => 'allpages', 'apnamespace' => '8', - 'aplimit' => '500', + 'aplimit' => '500', ); $baseUrl = $this->getArg( 0 ); $pages = array(); - + do { $url = wfAppendQuery( $baseUrl, $data ); $strResult = Http::get( $url ); //$result = FormatJson::decode( $strResult ); // Still broken $result = unserialize( $strResult ); - + if ( !empty( $result['query']['allpages'] ) ) { foreach ( $result['query']['allpages'] as $page ) { if ( substr( $page['title'], -3 ) === '.js' ) { @@ -76,9 +97,9 @@ class ImportSiteScripts extends Maintenance { $this->output( "Fetching new batch from {$data['apfrom']}\n" ); } } while ( isset( $result['query-continue'] ) ); - + return $pages; - + } } diff --git a/maintenance/importTextFile.php b/maintenance/importTextFile.php index ec9ff001..adb50635 100644 --- a/maintenance/importTextFile.php +++ b/maintenance/importTextFile.php @@ -1,8 +1,6 @@ <?php - /** - * Maintenance script allows creating or editing pages using - * the contents of a text file + * Create or edit pages using the contents of a text file. * * 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 @@ -26,7 +24,7 @@ $options = array( 'help', 'nooverwrite', 'norc' ); $optionsWithArgs = array( 'title', 'user', 'comment' ); -require_once( dirname( __FILE__ ) . '/commandLine.inc' ); +require_once( __DIR__ . '/commandLine.inc' ); echo( "Import Text File\n\n" ); if ( count( $args ) < 1 || isset( $options['help'] ) ) { diff --git a/maintenance/initEditCount.php b/maintenance/initEditCount.php index 0f136450..3135b4c7 100644 --- a/maintenance/initEditCount.php +++ b/maintenance/initEditCount.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); class InitEditCount extends Maintenance { public function __construct() { diff --git a/maintenance/initStats.php b/maintenance/initStats.php index eab9c8df..5d8b8866 100644 --- a/maintenance/initStats.php +++ b/maintenance/initStats.php @@ -1,6 +1,6 @@ <?php /** - * Maintenance script to re-initialise or update the site statistics table + * Re-initialise or update the site statistics table. * * 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 @@ -23,8 +23,13 @@ * @author Rob Church <robchur@gmail.com> */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to re-initialise or update the site statistics table + * + * @ingroup Maintenance + */ class InitStats extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/install.php b/maintenance/install.php index 9a408aa6..762bb94f 100644 --- a/maintenance/install.php +++ b/maintenance/install.php @@ -1,6 +1,7 @@ <?php - /** + * CLI-based MediaWiki installation and configuration. + * * 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 @@ -16,12 +17,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance - * @see wfWaitForSlaves() */ -if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.2.3' ) < 0 ) ) { - echo "You are using PHP version " . phpversion() . " but MediaWiki needs PHP 5.2.3 or higher. ABORTING.\n" . +if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.3.2' ) < 0 ) ) { + echo "You are using PHP version " . phpversion() . " but MediaWiki needs PHP 5.3.2 or higher. ABORTING.\n" . "Check if you have a newer php executable with a different name, such as php5.\n"; die( 1 ); } @@ -29,8 +30,13 @@ if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), ' define( 'MW_CONFIG_CALLBACK', 'Installer::overrideConfig' ); define( 'MEDIAWIKI_INSTALL', true ); -require_once( dirname( dirname( __FILE__ ) )."/maintenance/Maintenance.php" ); +require_once( dirname( __DIR__ )."/maintenance/Maintenance.php" ); +/** + * Maintenance script to install and configure MediaWiki + * + * @ingroup Maintenance + */ class CommandLineInstaller extends Maintenance { function __construct() { parent::__construct(); @@ -39,7 +45,7 @@ class CommandLineInstaller extends Maintenance { $this->addArg( 'name', 'The name of the wiki', true); $this->addArg( 'admin', 'The username of the wiki administrator (WikiSysop)', true ); - $this->addOption( 'pass', 'The password for the wiki administrator. You will be prompted for this if it isn\'t provided', false, true ); + $this->addOption( 'pass', 'The password for the wiki administrator.', true, true ); /* $this->addOption( 'email', 'The email for the wiki administrator', false, true ); */ $this->addOption( 'scriptpath', 'The relative path of the wiki in the web server (/wiki)', false, true ); @@ -81,7 +87,7 @@ class CommandLineInstaller extends Maintenance { } $installer = - new CliInstaller( $siteName, $adminName, $this->mOptions ); + InstallerOverrides::getCliInstaller( $siteName, $adminName, $this->mOptions ); $status = $installer->doEnvironmentChecks(); if( $status->isGood() ) { diff --git a/maintenance/interwiki.list b/maintenance/interwiki.list index d6abd1a7..179fa5c6 100644 --- a/maintenance/interwiki.list +++ b/maintenance/interwiki.list @@ -14,8 +14,8 @@ docbook|http://wiki.docbook.org/topic/$1|0 doi|http://dx.doi.org/$1|0 drumcorpswiki|http://www.drumcorpswiki.com/index.php/$1|0 dwjwiki|http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1|0 -emacswiki|http://www.emacswiki.org/cgi-bin/wiki.pl?$1|0 elibre|http://enciclopedia.us.es/index.php/$1|0 +emacswiki|http://www.emacswiki.org/cgi-bin/wiki.pl?$1|0 foldoc|http://foldoc.org/?$1|0 foxwiki|http://fox.wikis.com/wc.dll?Wiki~$1|0 freebsdman|http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1|0 @@ -37,11 +37,11 @@ lqwiki|http://wiki.linuxquestions.org/wiki/$1|0 lugkr|http://lug-kr.sourceforge.net/cgi-bin/lugwiki.pl?$1|0 mathsongswiki|http://SeedWiki.com/page.cfm?wikiid=237&doc=$1|0 meatball|http://www.usemod.com/cgi-bin/mb.pl?$1|0 -mediazilla|https://bugzilla.wikimedia.org/$1|1 mediawikiwiki|http://www.mediawiki.org/wiki/$1|0 +mediazilla|https://bugzilla.wikimedia.org/$1|1 memoryalpha|http://www.memory-alpha.org/en/index.php/$1|0 metawiki|http://sunir.org/apps/meta.pl?$1|0 -metawikipedia|http://meta.wikimedia.org/wiki/$1|0 +metawikimedia|http://meta.wikimedia.org/wiki/$1|0 moinmoin|http://purl.net/wiki/moin/$1|0 mozillawiki|http://wiki.mozilla.org/index.php/$1|0 mw|http://www.mediawiki.org/wiki/$1|0 @@ -82,10 +82,11 @@ wikicities|http://www.wikia.com/wiki/$1|0 wikif1|http://www.wikif1.org/$1|0 wikihow|http://www.wikihow.com/$1|0 wikinfo|http://www.wikinfo.org/index.php/$1|0 +# The following wik[it]* interwikis but wikitravel belong to the Wikimedia Family: wikimedia|http://wikimediafoundation.org/wiki/$1|0 wikinews|http://en.wikinews.org/wiki/$1|1 -wikiquote|http://en.wikiquote.org/wiki/$1|1 wikipedia|http://en.wikipedia.org/wiki/$1|1 +wikiquote|http://en.wikiquote.org/wiki/$1|1 wikisource|http://wikisource.org/wiki/$1|1 wikispecies|http://species.wikimedia.org/wiki/$1|1 wikitravel|http://wikitravel.org/en/$1|0 diff --git a/maintenance/interwiki.sql b/maintenance/interwiki.sql index 6efc1e0e..370460af 100644 --- a/maintenance/interwiki.sql +++ b/maintenance/interwiki.sql @@ -16,8 +16,8 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('doi','http://dx.doi.org/$1',0), ('drumcorpswiki','http://www.drumcorpswiki.com/index.php/$1',0), ('dwjwiki','http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1',0), -('emacswiki','http://www.emacswiki.org/cgi-bin/wiki.pl?$1',0), ('elibre','http://enciclopedia.us.es/index.php/$1',0), +('emacswiki','http://www.emacswiki.org/cgi-bin/wiki.pl?$1',0), ('foldoc','http://foldoc.org/?$1',0), ('foxwiki','http://fox.wikis.com/wc.dll?Wiki~$1',0), ('freebsdman','http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1',0), @@ -39,11 +39,11 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('lugkr','http://lug-kr.sourceforge.net/cgi-bin/lugwiki.pl?$1',0), ('mathsongswiki','http://SeedWiki.com/page.cfm?wikiid=237&doc=$1',0), ('meatball','http://www.usemod.com/cgi-bin/mb.pl?$1',0), -('mediazilla','https://bugzilla.wikimedia.org/$1',1), ('mediawikiwiki','http://www.mediawiki.org/wiki/$1',0), +('mediazilla','https://bugzilla.wikimedia.org/$1',1), ('memoryalpha','http://www.memory-alpha.org/en/index.php/$1',0), ('metawiki','http://sunir.org/apps/meta.pl?$1',0), -('metawikipedia','http://meta.wikimedia.org/wiki/$1',0), +('metawikimedia','http://meta.wikimedia.org/wiki/$1',0), ('moinmoin','http://purl.net/wiki/moin/$1',0), ('mozillawiki','http://wiki.mozilla.org/index.php/$1',0), ('mw','http://www.mediawiki.org/wiki/$1',0), @@ -84,10 +84,11 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('wikif1','http://www.wikif1.org/$1',0), ('wikihow','http://www.wikihow.com/$1',0), ('wikinfo','http://www.wikinfo.org/index.php/$1',0), +# The following wik[it]* interwikis but wikitravel belong to the Wikimedia Family: ('wikimedia','http://wikimediafoundation.org/wiki/$1',0), ('wikinews','http://en.wikinews.org/wiki/$1',1), -('wikiquote','http://en.wikiquote.org/wiki/$1',1), ('wikipedia','http://en.wikipedia.org/wiki/$1',1), +('wikiquote','http://en.wikiquote.org/wiki/$1',1), ('wikisource','http://wikisource.org/wiki/$1',1), ('wikispecies','http://species.wikimedia.org/wiki/$1',1), ('wikitravel','http://wikitravel.org/en/$1',0), diff --git a/maintenance/jsparse.php b/maintenance/jsparse.php index da6798e1..ceafc390 100644 --- a/maintenance/jsparse.php +++ b/maintenance/jsparse.php @@ -1,6 +1,6 @@ <?php /** - * Maintenance script to do test JavaScript validity parses using jsmin+'s parser + * Test JavaScript validity parses using jsmin+'s parser * * 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 @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to do test JavaScript validity parses using jsmin+'s parser + * + * @ingroup Maintenance + */ class JSParseHelper extends Maintenance { var $errs = 0; @@ -35,7 +41,7 @@ class JSParseHelper extends Maintenance { if ( $this->hasArg() ) { $files = $this->mArgs; } else { - $this->maybeHelp( true ); // @fixme this is a lame API :) + $this->maybeHelp( true ); // @todo fixme this is a lame API :) exit( 1 ); // it should exit from the above first... } diff --git a/maintenance/lag.php b/maintenance/lag.php index dc8bff5f..3ad0864f 100644 --- a/maintenance/lag.php +++ b/maintenance/lag.php @@ -21,8 +21,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to show database lag. + * + * @ingroup Maintenance + */ class DatabaseLag extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/language/StatOutputs.php b/maintenance/language/StatOutputs.php index befd0d72..d77029e7 100644 --- a/maintenance/language/StatOutputs.php +++ b/maintenance/language/StatOutputs.php @@ -46,7 +46,7 @@ class statsOutput { /** Outputs WikiText */ class wikiStatsOutput extends statsOutput { function heading() { - global $wgDummyLanguageCodes, $wgContLang; + global $wgDummyLanguageCodes; $version = SpecialVersion::getVersion( 'nodb' ); echo "'''Statistics are based on:''' <code>" . $version . "</code>\n\n"; echo "'''Note:''' These statistics can be generated by running <code>php maintenance/language/transstat.php</code>.\n\n"; @@ -55,7 +55,7 @@ class wikiStatsOutput extends statsOutput { if( is_array( $wgDummyLanguageCodes ) ) { $dummyCodes = array(); foreach( $wgDummyLanguageCodes as $dummyCode => $correctCode ) { - $dummyCodes[] = $wgContLang->getLanguageName( $dummyCode ) . ' (' . $dummyCode . ')'; + $dummyCodes[] = Language::fetchLanguageName( $dummyCode ) . ' (' . $dummyCode . ')'; } echo ', as well as the following languages that are not intended for system message translations, usually because they redirect to other language codes: ' . implode( ', ', $dummyCodes ); } diff --git a/maintenance/language/alltrans.php b/maintenance/language/alltrans.php index f872e6a6..8caf8677 100644 --- a/maintenance/language/alltrans.php +++ b/maintenance/language/alltrans.php @@ -17,11 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup MaintenanceLanguage */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); +/** + * Maintenance script that gets all messages as defined by the + * English language file. + * + * @ingroup MaintenanceLanguage + */ class AllTrans extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/language/checkDupeMessages.php b/maintenance/language/checkDupeMessages.php index ea5b1870..6abf7b44 100644 --- a/maintenance/language/checkDupeMessages.php +++ b/maintenance/language/checkDupeMessages.php @@ -1,6 +1,6 @@ <?php /** - * Script to print out duplicates in message array + * Print out duplicates in message array * * 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 @@ -21,8 +21,8 @@ * @ingroup MaintenanceLanguage */ -require_once( dirname( __FILE__ ) . '/../commandLine.inc' ); -$messagesDir = dirname( __FILE__ ) . '/../../languages/messages/'; +require_once( __DIR__ . '/../commandLine.inc' ); +$messagesDir = __DIR__ . '/../../languages/messages/'; $runTest = false; $run = false; $runMode = 'text'; diff --git a/maintenance/language/checkExtensions.php b/maintenance/language/checkExtensions.php index a58a8f5c..ebc62b60 100644 --- a/maintenance/language/checkExtensions.php +++ b/maintenance/language/checkExtensions.php @@ -21,7 +21,7 @@ * @ingroup MaintenanceLanguage */ -require_once( dirname( __FILE__ ) . '/../commandLine.inc' ); +require_once( __DIR__ . '/../commandLine.inc' ); require_once( 'languages.inc' ); require_once( 'checkLanguage.inc' ); diff --git a/maintenance/language/checkLanguage.inc b/maintenance/language/checkLanguage.inc index 8ab6125b..11b00e14 100644 --- a/maintenance/language/checkLanguage.inc +++ b/maintenance/language/checkLanguage.inc @@ -41,7 +41,7 @@ class CheckLanguageCLI { /** * Constructor. - * @param $options Options for script. + * @param $options array Options for script. */ public function __construct( Array $options ) { if ( isset( $options['help'] ) ) { @@ -94,7 +94,7 @@ class CheckLanguageCLI { /** * Get the default checks. - * @return A list of the default checks. + * @return array A list of the default checks. */ protected function defaultChecks() { return array( @@ -107,7 +107,7 @@ class CheckLanguageCLI { /** * Get the checks which check other things than messages. - * @return A list of the non-message checks. + * @return array A list of the non-message checks. */ protected function nonMessageChecks() { return array( @@ -129,7 +129,7 @@ class CheckLanguageCLI { /** * Get all checks. - * @return An array of all check names mapped to their function names. + * @return array An array of all check names mapped to their function names. */ protected function getChecks() { return array( @@ -157,7 +157,7 @@ class CheckLanguageCLI { /** * Get total count for each check non-messages check. - * @return An array of all check names mapped to a two-element array: + * @return array An array of all check names mapped to a two-element array: * function name to get the total count and language code or null * for checked code. */ @@ -176,7 +176,7 @@ class CheckLanguageCLI { /** * Get all check descriptions. - * @return An array of all check names mapped to their descriptions. + * @return array An array of all check names mapped to their descriptions. */ protected function getDescriptions() { return array( @@ -204,7 +204,7 @@ class CheckLanguageCLI { /** * Get help. - * @return The help string. + * @return string The help string. */ protected function help() { return <<<ENDS @@ -222,17 +222,17 @@ Parameters: --links: Link the message values (default off). --prefix: prefix to add to links. --wikilang: For the links, what is the content language of the wiki to display the output in (default en). - --noexif: Don't check for EXIF messages (a bit hard and boring to translate), if you know + --noexif: Do not check for EXIF messages (a bit hard and boring to translate), if you know that they are currently not translated and want to focus on other problems (default off). --whitelist: Do only the following checks (form: code,code). - --blacklist: Don't do the following checks (form: code,code). + --blacklist: Do not do the following checks (form: code,code). --easy: Do only the easy checks, which can be treated by non-speakers of the language. Check codes (ideally, all of them should result 0; all the checks are executed by default (except language-specific check blacklists in checkLanguage.inc): * untranslated: Messages which are required to translate, but are not translated. * duplicate: Messages which translation equal to fallback * obsolete: Messages which are untranslatable or do not exist, but are translated. - * variables: Messages without variables which should be used, or with variables which shouldn't be used. + * variables: Messages without variables which should be used, or with variables which should not be used. * empty: Empty messages and messages that contain only -. * whitespace: Messages which have trailing whitespace. * xhtml: Messages which are not well-formed XHTML (checks only few common errors). @@ -295,7 +295,7 @@ ENDS; /** * Get the check blacklist. - * @return The list of checks which should not be executed. + * @return array The list of checks which should not be executed. */ protected function getCheckBlacklist() { global $checkBlacklist; @@ -336,9 +336,9 @@ ENDS; /** * Format a message key. - * @param $key The message key. - * @param $code The language code. - * @return The formatted message key. + * @param $key string The message key. + * @param $code string The language code. + * @return string The formatted message key. */ protected function formatKey( $key, $code ) { if ( $this->doLinks ) { @@ -355,7 +355,6 @@ ENDS; /** * Output the checks results as plain text. - * @return The checks results as plain text. */ protected function outputText() { foreach ( $this->results as $code => $results ) { @@ -401,10 +400,8 @@ ENDS; /** * Output the checks results as wiki text. - * @return The checks results as wiki text. */ function outputWiki() { - global $wgContLang; $detailText = ''; $rows[] = '! Language !! Code !! Total !! ' . implode( ' !! ', array_diff( $this->checks, $this->nonMessageChecks() ) ); foreach ( $this->results as $code => $results ) { @@ -440,7 +437,7 @@ ENDS; # Don't list languages without problems continue; } - $language = $wgContLang->getLanguageName( $code ); + $language = Language::fetchLanguageName( $code ); $rows[] = "| $language || $code || $problems || " . implode( ' || ', $numbers ); } @@ -462,7 +459,7 @@ EOL; /** * Check if there are any results for the checks, in any language. - * @return True if there are any results, false if not. + * @return bool True if there are any results, false if not. */ protected function isEmpty() { foreach( $this->results as $results ) { @@ -484,8 +481,8 @@ class CheckExtensionsCLI extends CheckLanguageCLI { /** * Constructor. - * @param $options Options for script. - * @param $extension The extension name (or names). + * @param $options array Options for script. + * @param $extension string The extension name (or names). */ public function __construct( Array $options, $extension ) { if ( isset( $options['help'] ) ) { @@ -569,7 +566,7 @@ class CheckExtensionsCLI extends CheckLanguageCLI { /** * Get the default checks. - * @return A list of the default checks. + * @return array A list of the default checks. */ protected function defaultChecks() { return array( @@ -580,7 +577,7 @@ class CheckExtensionsCLI extends CheckLanguageCLI { /** * Get the checks which check other things than messages. - * @return A list of the non-message checks. + * @return array A list of the non-message checks. */ protected function nonMessageChecks() { return array(); @@ -588,7 +585,7 @@ class CheckExtensionsCLI extends CheckLanguageCLI { /** * Get the checks that can easily be treated by non-speakers of the language. - * @return A list of the easy checks. + * @return arrayA list of the easy checks. */ protected function easyChecks() { return array( @@ -598,7 +595,7 @@ class CheckExtensionsCLI extends CheckLanguageCLI { /** * Get help. - * @return The help string. + * @return string The help string. */ protected function help() { return <<<ENDS diff --git a/maintenance/language/checkLanguage.php b/maintenance/language/checkLanguage.php index 69f61084..99ba4e98 100644 --- a/maintenance/language/checkLanguage.php +++ b/maintenance/language/checkLanguage.php @@ -21,7 +21,7 @@ * @ingroup MaintenanceLanguage */ -require_once( dirname( __FILE__ ) . '/../commandLine.inc' ); +require_once( __DIR__ . '/../commandLine.inc' ); require_once( 'checkLanguage.inc' ); require_once( 'languages.inc' ); diff --git a/maintenance/language/countMessages.php b/maintenance/language/countMessages.php index f949ddc2..5058a549 100644 --- a/maintenance/language/countMessages.php +++ b/maintenance/language/countMessages.php @@ -17,11 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup MaintenanceLanguage */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); +/** + * Maintenance script that counts how many messages we have defined + * for each language. + * + * @ingroup MaintenanceLanguage + */ class CountMessages extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/language/date-formats.php b/maintenance/language/date-formats.php index 04f5e8ba..ed12b786 100644 --- a/maintenance/language/date-formats.php +++ b/maintenance/language/date-formats.php @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup MaintenanceLanguage */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); +/** + * Maintenance script that tests various language time and date functions. + * + * @ingroup MaintenanceLanguage + */ class DateFormats extends Maintenance { private $ts = '20010115123456'; diff --git a/maintenance/language/digit2html.php b/maintenance/language/digit2html.php index a80ac014..9d4cbe7e 100644 --- a/maintenance/language/digit2html.php +++ b/maintenance/language/digit2html.php @@ -1,5 +1,7 @@ <?php /** + * Check digit transformation + * * 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 @@ -15,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup MaintenanceLanguage */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); +/** + * Maintenance script that check digit transformation. + * + * @ingroup MaintenanceLanguage + */ class Digit2Html extends Maintenance { # A list of unicode numerals is available at: diff --git a/maintenance/language/dumpMessages.php b/maintenance/language/dumpMessages.php index 9bdda09d..0292d314 100644 --- a/maintenance/language/dumpMessages.php +++ b/maintenance/language/dumpMessages.php @@ -18,24 +18,30 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup MaintenanceLanguage - * @todo Make this more useful, right now just dumps $wgContentLang + * @todo Make this more useful, right now just dumps $wgContLang */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); +/** + * Maintenance script that dumps an entire language, using the keys from English. + * + * @ingroup MaintenanceLanguage + */ class DumpMessages extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Dump an entire language, using the keys from English"; } - + public function execute() { global $wgVersion; $messages = array(); foreach ( array_keys( Language::getMessagesFor( 'en' ) ) as $key ) { - $messages[$key] = wfMsg( $key ); + $messages[$key] = wfMessage( $key )->text(); } $this->output( "MediaWiki $wgVersion language file\n" ); $this->output( serialize( $messages ) ); diff --git a/maintenance/language/generateCollationData.php b/maintenance/language/generateCollationData.php index e5ce5c87..e34d9a13 100644 --- a/maintenance/language/generateCollationData.php +++ b/maintenance/language/generateCollationData.php @@ -1,13 +1,32 @@ <?php /** - * @ingroup Maintenance + * Maintenance script to generate first letter data files for Collation.php. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file + * @ingroup MaintenanceLanguage */ -require_once( dirname( __FILE__ ) .'/../Maintenance.php' ); +require_once( __DIR__ .'/../Maintenance.php' ); /** * Generate first letter data files for Collation.php + * + * @ingroup MaintenanceLanguage */ class GenerateCollationData extends Maintenance { /** The directory with source data files in it */ @@ -386,4 +405,3 @@ class UcdXmlReader { $maintClass = 'GenerateCollationData'; require_once( RUN_MAINTENANCE_IF_MAIN ); - diff --git a/maintenance/language/generateNormalizerData.php b/maintenance/language/generateNormalizerData.php index a958abf1..54dfa39a 100644 --- a/maintenance/language/generateNormalizerData.php +++ b/maintenance/language/generateNormalizerData.php @@ -21,13 +21,15 @@ * @ingroup MaintenanceLanguage */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); -require_once( dirname( __FILE__ ) . '/../../includes/normal/UtfNormalUtil.php' ); +require_once( __DIR__ . '/../../includes/normal/UtfNormalUtil.php' ); /** * Generates normalizer data files for Arabic and Malayalam. * For NFC see includes/normal. + * + * @ingroup MaintenanceLanguage */ class GenerateNormalizerData extends Maintenance { var $dataFile; @@ -155,4 +157,3 @@ class GenerateNormalizerData extends Maintenance { $maintClass = 'GenerateNormalizerData'; require_once( RUN_MAINTENANCE_IF_MAIN ); - diff --git a/maintenance/language/lang2po.php b/maintenance/language/lang2po.php deleted file mode 100644 index 7e5dc472..00000000 --- a/maintenance/language/lang2po.php +++ /dev/null @@ -1,166 +0,0 @@ -<?php -/** - * Convert Language files to .po files ! - * - * Todo: - * - generate .po header - * - fix escaping of \ - * - * 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 - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * http://www.gnu.org/copyleft/gpl.html - * - * @ingroup MaintenanceLanguage - */ - -/** This is a command line script */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); -require_once( dirname( __FILE__ ) . '/languages.inc' ); - -define( 'ALL_LANGUAGES', true ); -define( 'XGETTEXT_BIN', 'xgettext' ); -define( 'MSGMERGE_BIN', 'msgmerge' ); - -// used to generate the .pot -define( 'XGETTEXT_OPTIONS', '-n --keyword=wfMsg --keyword=wfMsgForContent --keyword=wfMsgHtml --keyword=wfMsgWikiHtml ' ); -define( 'MSGMERGE_OPTIONS', ' -v ' ); - -define( 'LOCALE_OUTPUT_DIR', $IP . '/locale' ); - -class Lang2Po extends Maintenance { - public function __construct() { - parent::__construct(); - $this->mDescription = ""; - $this->addOption( 'lang', 'a lang code you want to generate a .po for (default: all langs)', false, true ); - } - - public function execute() { - // Generate a template .pot based on source tree - $this->output( "Getting 'gettext' default messages from sources:" ); - $this->generatePot(); - $this->output( "done.\n" ); - - - $langTool = new languages(); - if ( $this->getOption( 'lang', ALL_LANGUAGES ) === ALL_LANGUAGES ) { - $codes = $langTool->getLanguages(); - } else { - $codes = array( $this->getOption( 'lang' ) ); - } - - // Do all languages - foreach ( $codes as $langcode ) { - $this->output( "Loading messages for $langcode:\n" ); - if ( !$this->generatePo( $langcode, $langTool->getMessages( $langcode ) ) ) { - $this->error( "ERROR: Failed to write file." ); - } else { - $this->output( "Applying template:" ); - $this->applyPot( $langcode ); - } - } - } - - /** - * Return a dummy header for later edition. - * - * @return String: a dummy header - */ - private function poHeader() { - return '# SOME DESCRIPTIVE TITLE. -# Copyright (C) 2005 MediaWiki -# This file is distributed under the same license as the MediaWiki package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: bugzilllaaaaa\n" -"POT-Creation-Date: 2005-08-16 20:13+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: VARIOUS <nobody>\n" -"Language-Team: LANGUAGE <nobody>\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -'; - } - - /** - * generate and write a file in .po format. - * - * @param $langcode String: code of a language it will process. - * @param $messages Array containing the various messages. - * @return string Filename where stuff got saved or false. - */ - private function generatePo( $langcode, $messages ) { - $data = $this->poHeader(); - - // Generate .po entries - foreach ( $messages['all'] as $identifier => $content ) { - $data .= "msgid \"$identifier\"\n"; - - // Escape backslashes - $tmp = str_replace( '\\', '\\\\', $content ); - // Escape doublelquotes - $tmp = preg_replace( "/(?<!\\\\)\"/", '\"', $tmp ); - // Rewrite multilines to gettext format - $tmp = str_replace( "\n", "\"\n\"", $tmp ); - - $data .= 'msgstr "' . $tmp . "\"\n\n"; - } - - // Write the content to a file in locale/XX/messages.po - $dir = LOCALE_OUTPUT_DIR . '/' . $langcode; - if ( !is_dir( $dir ) ) { mkdir( $dir, 0770 ); } - $filename = $dir . '/fromlanguagefile.po'; - - $file = fopen( $filename , 'wb' ); - if ( fwrite( $file, $data ) ) { - fclose( $file ); - return $filename; - } else { - fclose( $file ); - return false; - } - } - - private function generatePot() { - global $IP; - $curdir = getcwd(); - chdir( $IP ); - exec( XGETTEXT_BIN - . ' ' . XGETTEXT_OPTIONS - . ' -o ' . LOCALE_OUTPUT_DIR . '/wfMsg.pot' - . ' includes/*php' - ); - chdir( $curdir ); - } - - private function applyPot( $langcode ) { - $langdir = LOCALE_OUTPUT_DIR . '/' . $langcode; - - $from = $langdir . '/fromlanguagefile.po'; - $pot = LOCALE_OUTPUT_DIR . '/wfMsg.pot'; - $dest = $langdir . '/messages.po'; - - // Merge template and generate file to get final .po - exec( MSGMERGE_BIN . MSGMERGE_OPTIONS . " $from $pot -o $dest " ); - // delete no more needed file - // unlink($from); - } -} - -$maintClass = "Lang2Po"; -require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/language/langmemusage.php b/maintenance/language/langmemusage.php index 28fe120e..2323638e 100644 --- a/maintenance/language/langmemusage.php +++ b/maintenance/language/langmemusage.php @@ -22,8 +22,8 @@ */ /** This is a command line script */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); -require_once( dirname( __FILE__ ) . '/languages.inc' ); +require_once( __DIR__ . '/../Maintenance.php' ); +require_once( __DIR__ . '/languages.inc' ); class LangMemUsage extends Maintenance { diff --git a/maintenance/language/languages.inc b/maintenance/language/languages.inc index 06102ac1..b76f921d 100644 --- a/maintenance/language/languages.inc +++ b/maintenance/language/languages.inc @@ -43,10 +43,10 @@ class languages { * Load the list of languages: all the Messages*.php * files in the languages directory. * - * @param $exif Treat the EXIF messages? + * @param $exif bool Treat the EXIF messages? */ function __construct( $exif = true ) { - require( dirname(__FILE__) . '/messageTypes.inc' ); + require( __DIR__ . '/messageTypes.inc' ); $this->mIgnoredMessages = $wgIgnoredMessages; if ( $exif ) { $this->mOptionalMessages = array_merge( $wgOptionalMessages ); @@ -54,7 +54,7 @@ class languages { $this->mOptionalMessages = array_merge( $wgOptionalMessages, $wgEXIFMessages ); } - $this->mLanguages = array_keys( Language::getLanguageNames( true ) ); + $this->mLanguages = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) ); sort( $this->mLanguages ); } @@ -244,7 +244,7 @@ class languages { * * @param $code string The language code. * - * @return Namespace names. + * @return array Namespace names. */ public function getNamespaceNames( $code ) { $this->loadFile( $code ); @@ -256,7 +256,7 @@ class languages { * * @param $code string The language code. * - * @return Namespace aliases. + * @return array Namespace aliases. */ public function getNamespaceAliases( $code ) { $this->loadFile( $code ); @@ -268,7 +268,7 @@ class languages { * * @param $code string The language code. * - * @return Magic words. + * @return array Magic words. */ public function getMagicWords( $code ) { $this->loadFile( $code ); @@ -280,7 +280,7 @@ class languages { * * @param $code string The language code. * - * @return Special page aliases. + * @return array Special page aliases. */ public function getSpecialPageAliases( $code ) { $this->loadFile( $code ); @@ -734,7 +734,7 @@ class extensionLanguages extends languages { /** * Load the messages group. - * @param $group The messages group. + * @param $group MessageGroup The messages group. */ function __construct( MessageGroup $group ) { $this->mMessageGroup = $group; diff --git a/maintenance/language/messageTypes.inc b/maintenance/language/messageTypes.inc index 1c33667a..ce1dbb9b 100644 --- a/maintenance/language/messageTypes.inc +++ b/maintenance/language/messageTypes.inc @@ -123,6 +123,7 @@ $wgIgnoredMessages = array( 'pubmedurl', 'randompage-url', 'recentchanges-url', + 'recentchangestext', 'revision-info-current', 'revision-nav', 'rfcurl', @@ -136,6 +137,7 @@ $wgIgnoredMessages = array( 'sitetitle', 'sp-contributions-footer', 'sp-contributions-footer-anon', + 'sp-contributions-footer-newbies', 'statistics-summary', 'statistics-footer', 'talkpagetext', @@ -161,11 +163,13 @@ $wgIgnoredMessages = array( 'wantedcategories-summary', 'wantedfiles-summary', 'wantedpages-summary', + 'watchlist-summary', 'mostlinked-summary', 'mostlinkedcategories-summary', 'mostlinkedtemplates-summary', 'mostcategories-summary', 'mostimages-summary', + 'mostinterwikis-summary', 'mostrevisions-summary', 'prefixindex-summary', 'shortpages-summary', @@ -185,12 +189,63 @@ $wgIgnoredMessages = array( 'wantedtemplates-summary', 'activeusers-summary', 'search-summary', + 'editpage-head-copy-warn', 'editpage-tos-summary', 'addsection-preload', 'addsection-editintro', 'longpage-hint', 'javascripttest-backlink', 'javascripttest-qunit-name', + 'revdelete-logentry', + 'logdelete-logentry', + 'revdelete-content', + 'revdelete-summary', + 'revdelete-uname', + 'revdelete-hid', + 'revdelete-unhid', + 'revdelete-log-message', + 'logdelete-log-message', + 'deletedarticle', + 'suppressedarticle', + 'undeletedarticle', + 'patrol-log-line', + 'patrol-log-auto', + 'patrol-log-diff', + '1movedto2', + '1movedto2_redir', + 'move-redirect-suppressed', + // 'newuserlog-byemail', + 'newuserlog-create-entry', + 'newuserlog-create2-entry', + 'newuserlog-autocreate-entry', + 'suppressedarticle', + 'deletedarticle', + // 'uploadedimage', + // 'overwroteimage', + 'userlogout-summary', + 'changeemail-summary', + 'changepassword-summary', + 'unusedcategories-summary', + 'unusedimages-summary', + 'deletedcontributions-summary', + 'linksearch-summary', + 'emailuser-summary', + 'undelete-summary', + 'contributions-summary', + 'unblock-summary', + 'movepage-summary', + 'export-summary', + 'import-summary', + 'editwatchlist-summary', + 'version-summary', + 'tags-summary', + 'comparepages-summary', + 'version-entrypoints-index-php', + 'version-entrypoints-api-php', + 'version-entrypoints-load-php', + 'ipb-default-expiry', + 'pageinfo-header', + 'pageinfo-footer', ); /** Optional messages, which may be translated only if changed in the target language. */ @@ -201,7 +256,6 @@ $wgOptionalMessages = array( 'feed-rss', 'unit-pixel', 'userrights-irreversible-marker', - 'tog-nolangconversion', 'tog-noconvertlink', 'variantname-zh-hans', 'variantname-zh-hant', @@ -402,6 +456,7 @@ $wgOptionalMessages = array( 'ellipsis', 'percent', 'parentheses', + 'brackets', 'autocomment-prefix', 'listgrouprights-right-display', 'listgrouprights-right-revoked', @@ -418,6 +473,12 @@ $wgOptionalMessages = array( 'metadata-langitem', 'metadata-langitem-default', 'nocookiesforlogin', + 'version-entrypoints-articlepath', + 'version-entrypoints-scriptpath', + 'mergehistory-revisionrow', + 'categoryviewer-pagedlinks', + 'undelete-revisionrow', + 'pageinfo-redirects-value', ); /** EXIF messages, which may be set as optional in several checks, but are generally mandatory */ diff --git a/maintenance/language/messages.inc b/maintenance/language/messages.inc index bee5a67c..29269175 100644 --- a/maintenance/language/messages.inc +++ b/maintenance/language/messages.inc @@ -28,7 +28,6 @@ $wgMessageStructure = array( ), 'toggles' => array( 'tog-underline', - 'tog-highlightbroken', 'tog-justify', 'tog-hideminor', 'tog-hidepatrolled', @@ -68,7 +67,6 @@ $wgMessageStructure = array( 'tog-watchlisthideliu', 'tog-watchlisthideanons', 'tog-watchlisthidepatrolled', - 'tog-nolangconversion', 'tog-ccmeonemails', 'tog-diffonly', 'tog-showhiddencats', @@ -158,6 +156,7 @@ $wgMessageStructure = array( 'index-category', 'noindex-category', 'broken-file-category', + 'categoryviewer-pagedlinks', ), 'mainpage' => array( 'linkprefix', @@ -306,6 +305,10 @@ $wgMessageStructure = array( 'youhavenewmessages', 'newmessageslink', 'newmessagesdifflink', + 'youhavenewmessagesfromusers', + 'youhavenewmessagesmanyusers', + 'newmessageslinkplural', + 'newmessagesdifflinkplural', 'youhavenewmessagesmulti', 'newtalkseparator', 'editsection', @@ -368,9 +371,9 @@ $wgMessageStructure = array( 'readonly', 'enterlockreason', 'readonlytext', - 'missing-article', - 'missingarticle-rev', - 'missingarticle-diff', + 'missing-article', // not used anymore in core, but kept for extensions + 'missingarticle-rev', // not used anymore in core, but kept for extensions + 'missingarticle-diff', // not used anymore in core, but kept for extensions 'readonly_lag', 'internalerror', 'internalerror_info', @@ -387,6 +390,7 @@ $wgMessageStructure = array( 'badarticleerror', 'cannotdelete', 'cannotdelete-title', + 'delete-hook-aborted', 'badtitle', 'badtitletext', 'perfcached', @@ -409,6 +413,11 @@ $wgMessageStructure = array( 'customjsprotected', 'ns-specialprotected', 'titleprotected', + 'filereadonlyerror', + 'invalidtitle-knownnamespace', + 'invalidtitle-unknownnamespace', + 'exception-nologin', + 'exception-nologin-text', ), 'virus' => array( 'virus-badscanner', @@ -424,6 +433,7 @@ $wgMessageStructure = array( 'remembermypassword', 'securelogin-stick-https', 'yourdomainname', + 'password-change-forbidden', 'externaldberror', 'login', 'nav-login-createaccount', @@ -432,6 +442,7 @@ $wgMessageStructure = array( 'userloginnocreate', 'logout', 'userlogout', + 'userlogout-summary', 'notloggedin', 'nologin', 'nologinlink', @@ -484,6 +495,7 @@ $wgMessageStructure = array( 'emailconfirmlink', 'invalidemailaddress', 'cannotchangeemail', + 'emaildisabled', 'accountcreated', 'accountcreatedtext', 'createaccount-title', @@ -539,6 +551,7 @@ $wgMessageStructure = array( ), 'changeemail' => array( 'changeemail', + 'changeemail-summary', 'changeemail-header', 'changeemail-text', 'changeemail-no-info', @@ -606,6 +619,7 @@ $wgMessageStructure = array( 'noarticletext', 'noarticletext-nopermission', 'noarticletextanon', + 'missing-revision', 'userpage-userdoesnotexist', 'userpage-userdoesnotexist-view', 'blocked-notice-logextract', @@ -620,12 +634,14 @@ $wgMessageStructure = array( 'updated', 'note', 'previewnote', + 'continue-editing', 'previewconflict', 'session_fail_preview', 'session_fail_preview_html', 'token_suffix_mismatch', 'edit_form_incomplete', 'editing', + 'creating', 'editingsection', 'editingcomment', 'editconflict', @@ -637,6 +653,7 @@ $wgMessageStructure = array( 'yourdiff', 'copyrightwarning', 'copyrightwarning2', + 'editpage-head-copy-warn', 'editpage-tos-summary', 'longpage-hint', 'longpageerror', @@ -671,6 +688,7 @@ $wgMessageStructure = array( 'edit-already-exists', 'addsection-preload', 'addsection-editintro', + 'defaultmessagetext', ), 'parserwarnings' => array( 'expensive-parserfunction-warning', @@ -682,6 +700,13 @@ $wgMessageStructure = array( 'parser-template-loop-warning', 'parser-template-recursion-depth-warning', 'language-converter-depth-warning', + 'node-count-exceeded-category', + 'node-count-exceeded-warning', + 'expansion-depth-exceeded-category', + 'expansion-depth-exceeded-warning', + 'parser-unstrip-loop-warning', + 'parser-unstrip-recursion-limit', + 'converter-manual-rule-error', ), 'undo' => array( 'undo-success', @@ -818,7 +843,8 @@ $wgMessageStructure = array( 'mergehistory-autocomment', 'mergehistory-comment', 'mergehistory-same-destination', - 'mergehistory-reason' + 'mergehistory-reason', + 'mergehistory-revisionrow' ), 'mergelog' => array( 'mergelog', @@ -828,7 +854,8 @@ $wgMessageStructure = array( ), 'diffs' => array( 'history-title', - 'difference', + 'difference-title', + 'difference-title-multipage', 'difference-multipage', 'lineno', 'compareselectedversions', @@ -836,6 +863,7 @@ $wgMessageStructure = array( 'editundo', 'diff-multi', 'diff-multi-manyusers', + 'difference-missing-revision', ), 'search' => array( 'search-summary', @@ -882,8 +910,6 @@ $wgMessageStructure = array( 'search-interwiki-default', 'search-interwiki-custom', 'search-interwiki-more', - 'search-mwsuggest-enabled', - 'search-mwsuggest-disabled', 'search-relatedarticle', 'mwsuggest-disable', 'searcheverything-enable', @@ -926,12 +952,14 @@ $wgMessageStructure = array( 'prefsnologin', 'prefsnologintext', 'changepassword', + 'changepassword-summary', 'prefs-skin', 'skin-preview', 'datedefault', 'prefs-beta', 'prefs-datetime', 'prefs-labs', + 'prefs-user-pages', 'prefs-personal', 'prefs-rc', 'prefs-watchlist', @@ -1112,6 +1140,7 @@ $wgMessageStructure = array( 'right-writeapi', 'right-delete', 'right-bigdelete', + 'right-deletelogentry', 'right-deleterevision', 'right-deletedhistory', 'right-deletedtext', @@ -1197,6 +1226,7 @@ $wgMessageStructure = array( 'recentchanges', 'recentchanges-url', 'recentchanges-legend', + 'recentchanges-summary', 'recentchangestext', 'recentchanges-feed-description', 'recentchanges-label-newpage', @@ -1346,6 +1376,7 @@ $wgMessageStructure = array( 'upload-too-many-redirects', 'upload-unknown-size', 'upload-http-error', + 'upload-copy-upload-invalid-domain', ), 'filebackend-errors' => array( @@ -1365,12 +1396,19 @@ $wgMessageStructure = array( 'backend-fail-closetemp', 'backend-fail-read', 'backend-fail-create', + 'backend-fail-maxsize', 'backend-fail-readonly', 'backend-fail-synced', 'backend-fail-connect', 'backend-fail-internal', 'backend-fail-contenttype', - 'backend-fail-batchsize' + 'backend-fail-batchsize', + 'backend-fail-usable' + ), + + 'filejournal-errors' => array( + 'filejournal-fail-dbconnect', + 'filejournal-fail-dbquery' ), 'lockmanager-errors' => array( @@ -1379,9 +1417,11 @@ $wgMessageStructure = array( 'lockmanager-fail-deletelock', 'lockmanager-fail-acquirelock', 'lockmanager-fail-openlock', + 'lockmanager-fail-acquirelock', 'lockmanager-fail-releaselock', 'lockmanager-fail-db-bucket', 'lockmanager-fail-db-release', + 'lockmanager-fail-svr-acquire', 'lockmanager-fail-svr-release' ), @@ -1484,6 +1524,8 @@ $wgMessageStructure = array( 'sharedupload', 'sharedupload-desc-there', 'sharedupload-desc-here', + 'sharedupload-desc-edit', + 'sharedupload-desc-create', 'shareddescriptionfollows', 'filepage-nofile', 'filepage-nofile-link', @@ -1492,6 +1534,7 @@ $wgMessageStructure = array( 'shared-repo', 'shared-repo-name-wikimediacommons', 'filepage.css', + 'upload-disallowed-here', ), 'filerevert' => array( 'filerevert', @@ -1607,6 +1650,7 @@ $wgMessageStructure = array( 'specialpages' => array( 'nbytes', 'ncategories', + 'ninterwikis', 'nlinks', 'nmembers', 'nrevisions', @@ -1627,7 +1671,9 @@ $wgMessageStructure = array( 'uncategorizedtemplates', 'uncategorizedtemplates-summary', 'unusedcategories', + 'unusedcategories-summary', 'unusedimages', + 'unusedimages-summary', 'popularpages', 'popularpages-summary', 'wantedcategories', @@ -1651,6 +1697,8 @@ $wgMessageStructure = array( 'mostcategories-summary', 'mostimages', 'mostimages-summary', + 'mostinterwikis', + 'mostinterwikis-summary', 'mostrevisions', 'mostrevisions-summary', 'prefixindex', @@ -1718,6 +1766,7 @@ $wgMessageStructure = array( 'alllogstext', 'logempty', 'log-title-wildcard', + 'showhideselectedlogentries', ), 'allpages' => array( 'allpages', @@ -1736,6 +1785,12 @@ $wgMessageStructure = array( 'allpagesprefix', 'allpagesbadtitle', 'allpages-bad-ns', + 'allpages-hide-redirects', + ), + 'cachedspecial' => array( + 'cachedspecial-viewing-cached-ttl', + 'cachedspecial-viewing-cached-ts', + 'cachedspecial-refresh-now', ), 'categories' => array( 'categories', @@ -1747,11 +1802,13 @@ $wgMessageStructure = array( ), 'deletedcontribs' => array( 'deletedcontributions', + 'deletedcontributions-summary', 'deletedcontributions-title', 'sp-deletedcontributions-contribs', ), 'linksearch' => array( 'linksearch', + 'linksearch-summary', 'linksearch-pat', 'linksearch-ns', 'linksearch-ok', @@ -1804,6 +1861,9 @@ $wgMessageStructure = array( 'mailnologin', 'mailnologintext', 'emailuser', + 'emailuser-title-target', + 'emailuser-title-notarget', + 'emailuser-summary', 'emailpage', 'emailpagetext', 'usermailererror', @@ -1837,6 +1897,7 @@ $wgMessageStructure = array( ), 'watchlist' => array( 'watchlist', + 'watchlist-summary', 'mywatchlist', 'watchlistfor2', 'nowatchlist', @@ -1913,6 +1974,8 @@ $wgMessageStructure = array( 'rollback', 'rollback_short', 'rollbacklink', + 'rollbacklinkcount', + 'rollbacklinkcount-morethan', 'rollbackfailed', 'cantrollback', 'alreadyrolled', @@ -1985,6 +2048,7 @@ $wgMessageStructure = array( ), 'undelete' => array( 'undelete', + 'undelete-summary', 'undeletepage', 'undeletepagetitle', 'viewdeletedpage', @@ -2024,6 +2088,7 @@ $wgMessageStructure = array( 'undelete-error-long', 'undelete-show-file-confirm', 'undelete-show-file-submit', + 'undelete-revisionrow', ), 'nsform' => array( 'namespace', @@ -2035,6 +2100,7 @@ $wgMessageStructure = array( ), 'contributions' => array( 'contributions', + 'contributions-summary', 'contributions-title', 'mycontris', 'contribsub2', @@ -2062,6 +2128,7 @@ $wgMessageStructure = array( 'sp-contributions-explain', 'sp-contributions-footer', 'sp-contributions-footer-anon', + 'sp-contributions-footer-newbies', ), 'whatlinkshere' => array( 'whatlinkshere', @@ -2087,6 +2154,7 @@ $wgMessageStructure = array( 'autoblockid', 'block', 'unblock', + 'unblock-summary', 'blockip', 'blockip-title', 'blockip-legend', @@ -2197,6 +2265,7 @@ $wgMessageStructure = array( 'cant-see-hidden-user', 'ipbblocked', 'ipbnounblockself', + 'ipb-default-expiry', ), 'developertools' => array( 'lockdb', @@ -2218,6 +2287,7 @@ $wgMessageStructure = array( ), 'movepage' => array( 'move-page', + 'movepage-summary', 'move-page-legend', 'movepagetext', 'movepagetext-noredirectfixer', @@ -2279,6 +2349,7 @@ $wgMessageStructure = array( ), 'export' => array( 'export', + 'export-summary', 'exporttext', 'exportall', 'exportcuronly', @@ -2325,6 +2396,7 @@ $wgMessageStructure = array( ), 'import' => array( 'import', + 'import-summary', 'importinterwiki', 'import-interwiki-text', 'import-interwiki-source', @@ -2332,6 +2404,7 @@ $wgMessageStructure = array( 'import-interwiki-templates', 'import-interwiki-submit', 'import-interwiki-namespace', + 'import-interwiki-rootpage', 'import-upload-filename', 'import-comment', 'importtext', @@ -2363,6 +2436,9 @@ $wgMessageStructure = array( 'import-error-interwiki', 'import-error-special', 'import-error-invalid', + 'import-options-wrong', + 'import-rootpage-invalid', + 'import-rootpage-nosubpage', ), 'importlog' => array( 'importlogpage', @@ -2583,19 +2659,41 @@ $wgMessageStructure = array( 'spambot_username', 'spam_reverting', 'spam_blanking', + 'spam_deleting', ), 'info' => array( + 'pageinfo-header', 'pageinfo-title', + 'pageinfo-not-current', + 'pageinfo-header-basic', 'pageinfo-header-edits', - 'pageinfo-header-watchlist', - 'pageinfo-header-views', - 'pageinfo-subjectpage', - 'pageinfo-talkpage', + 'pageinfo-header-restrictions', + 'pageinfo-header-properties', + 'pageinfo-display-title', + 'pageinfo-default-sort', + 'pageinfo-length', + 'pageinfo-article-id', + 'pageinfo-robot-policy', + 'pageinfo-robot-index', + 'pageinfo-robot-noindex', + 'pageinfo-views', 'pageinfo-watchers', + 'pageinfo-redirects-name', + 'pageinfo-redirects-value', + 'pageinfo-subpages-name', + 'pageinfo-subpages-value', + 'pageinfo-firstuser', + 'pageinfo-firsttime', + 'pageinfo-lastuser', + 'pageinfo-lasttime', 'pageinfo-edits', 'pageinfo-authors', - 'pageinfo-views', - 'pageinfo-viewsperedit', + 'pageinfo-recent-edits', + 'pageinfo-recent-authors', + 'pageinfo-magic-words', + 'pageinfo-hidden-categories', + 'pageinfo-templates', + 'pageinfo-footer', ), 'skin' => array( 'skinname-standard', @@ -2649,6 +2747,7 @@ $wgMessageStructure = array( 'file-info-size-pages', 'file-nohires', 'svg-long-desc', + 'svg-long-desc-animated', 'show-big-image', 'show-big-image-preview', 'show-big-image-other', @@ -2658,6 +2757,8 @@ $wgMessageStructure = array( 'file-info-png-looped', 'file-info-png-repeat', 'file-info-png-frames', + 'file-no-thumb-animation', + 'file-no-thumb-animation-gif', ), 'newfiles' => array( 'newimages', @@ -3274,6 +3375,7 @@ $wgMessageStructure = array( 'ellipsis', 'percent', 'parentheses', + 'brackets', ), 'imgmulti' => array( 'imgmultipageprev', @@ -3338,6 +3440,7 @@ $wgMessageStructure = array( 'confirm-watch-button', ), 'watchlisteditor' => array( + 'editwatchlist-summary', 'watchlistedit-numitems', 'watchlistedit-noitems', 'watchlistedit-normal-title', @@ -3428,6 +3531,7 @@ $wgMessageStructure = array( ), 'version' => array( 'version', + 'version-summary', 'version-extensions', 'version-specialpages', 'version-parserhooks', @@ -3452,6 +3556,14 @@ $wgMessageStructure = array( 'version-software', 'version-software-product', 'version-software-version', + 'version-entrypoints', + 'version-entrypoints-header-entrypoint', + 'version-entrypoints-header-url', + 'version-entrypoints-articlepath', + 'version-entrypoints-scriptpath', + 'version-entrypoints-index-php', + 'version-entrypoints-api-php', + 'version-entrypoints-load-php', ), 'filepath' => array( 'filepath', @@ -3496,6 +3608,7 @@ $wgMessageStructure = array( ), 'special-tags' => array( 'tags', + 'tags-summary', 'tag-filter', 'tag-filter-submit', 'tags-title', @@ -3509,6 +3622,7 @@ $wgMessageStructure = array( ), 'comparepages' => array( 'comparepages', + 'comparepages-summary', 'compare-selector', 'compare-page1', 'compare-page2', @@ -3579,6 +3693,34 @@ $wgMessageStructure = array( 'logentry-newusers-autocreate', 'newuserlog-byemail', ), + 'logging-irc' => array( + 'revdelete-logentry', + 'logdelete-logentry', + 'revdelete-content', + 'revdelete-summary', + 'revdelete-uname', + 'revdelete-hid', + 'revdelete-unhid', + 'revdelete-log-message', + 'logdelete-log-message', + 'deletedarticle', + 'suppressedarticle', + 'undeletedarticle', + 'patrol-log-line', + 'patrol-log-auto', + 'patrol-log-diff', + '1movedto2', + '1movedto2_redir', + 'move-redirect-suppressed', + // 'newuserlog-byemail', + 'newuserlog-create-entry', + 'newuserlog-create2-entry', + 'newuserlog-autocreate-entry', + 'suppressedarticle', + 'deletedarticle', + // 'uploadedimage', + // 'overwroteimage', + ), 'feedback' => array( 'feedback-bugornote', 'feedback-subject', @@ -3594,6 +3736,10 @@ $wgMessageStructure = array( 'feedback-bugcheck', 'feedback-bugnew', ), + 'searchsuggestions' => array( + 'searchsuggest-search', + 'searchsuggest-containing', + ), 'apierrors' => array( 'api-error-badaccess-groups', 'api-error-badtoken', @@ -3605,9 +3751,12 @@ $wgMessageStructure = array( 'api-error-empty-file', 'api-error-emptypage', 'api-error-fetchfileerror', + 'api-error-fileexists-forbidden', + 'api-error-fileexists-shared-forbidden', 'api-error-file-too-large', 'api-error-filename-tooshort', 'api-error-filetype-banned', + 'api-error-filetype-banned-type', 'api-error-filetype-missing', 'api-error-hookaborted', 'api-error-http', @@ -3632,6 +3781,17 @@ $wgMessageStructure = array( 'api-error-uploaddisabled', 'api-error-verification-error', ), + 'duration' => array( + 'duration-seconds', + 'duration-minutes', + 'duration-hours', + 'duration-days', + 'duration-weeks', + 'duration-years', + 'duration-decades', + 'duration-centuries', + 'duration-millennia' + ), ); /** Comments for each block */ @@ -3696,6 +3856,7 @@ XHTML id names.", 'zip' => 'ZipDirectoryReader', 'upload-errors' => '', 'filebackend-errors' => 'File backend', + 'filejournal-errors' => 'File journal errors', 'lockmanager-errors' => 'Lock manager', 'uploadstash' => 'Special:UploadStash', 'img-auth' => 'img_auth script messages', @@ -3866,6 +4027,10 @@ Variants for Chinese language", 'html-forms' => 'HTML forms', 'sqlite' => 'SQLite database support', 'logging' => 'New logging system', + 'logging-irc' => 'For IRC, see bug 34508. Do not change', 'feedback' => 'Feedback', + 'searchsuggestions' => 'Search suggestions', 'apierrors' => 'API errors', + 'duration' => 'Durations', + 'cachedspecial' => 'SpecialCachedPage', ); diff --git a/maintenance/language/rebuildLanguage.php b/maintenance/language/rebuildLanguage.php index 9b3a4b9d..ad839054 100644 --- a/maintenance/language/rebuildLanguage.php +++ b/maintenance/language/rebuildLanguage.php @@ -22,7 +22,7 @@ * @defgroup MaintenanceLanguage MaintenanceLanguage */ -require_once( dirname( __FILE__ ) . '/../commandLine.inc' ); +require_once( __DIR__ . '/../commandLine.inc' ); require_once( 'languages.inc' ); require_once( 'writeMessagesArray.inc' ); @@ -30,27 +30,28 @@ require_once( 'writeMessagesArray.inc' ); * Rewrite a messages array. * * @param $languages - * @param $code The language code. + * @param $code string The language code. * @param bool $write Write to the messages file? * @param bool $listUnknown List the unknown messages? * @param bool $removeUnknown Remove the unknown messages? * @param bool $removeDupes Remove the duplicated messages? - * @param $dupeMsgSource The source file intended to remove from the array. + * @param $dupeMsgSource string The source file intended to remove from the array. + * @param $messagesFolder String: path to a folder to store the MediaWiki messages. */ -function rebuildLanguage( $languages, $code, $write, $listUnknown, $removeUnknown, $removeDupes, $dupeMsgSource ) { +function rebuildLanguage( $languages, $code, $write, $listUnknown, $removeUnknown, $removeDupes, $dupeMsgSource, $messagesFolder ) { $messages = $languages->getMessages( $code ); $messages = $messages['all']; if ( $removeDupes ) { $messages = removeDupes( $messages, $dupeMsgSource ); } - MessageWriter::writeMessagesToFile( $messages, $code, $write, $listUnknown, $removeUnknown ); + MessageWriter::writeMessagesToFile( $messages, $code, $write, $listUnknown, $removeUnknown, $messagesFolder ); } /** * Remove duplicates from a message array. * - * @param $oldMsgArray The input message array. - * @param $dupeMsgSource The source file path for duplicates. + * @param $oldMsgArray array The input message array. + * @param $dupeMsgSource string The source file path for duplicates. * @return Array $newMsgArray The output message array, with duplicates removed. */ function removeDupes( $oldMsgArray, $dupeMsgSource ) { @@ -85,6 +86,7 @@ Options: * no-unknown: Do not list the unknown messages. * remove-unknown: Remove unknown messages. * remove-duplicates: Remove duplicated messages based on a PHP source file. + * messages-folder: An alternative folder with MediaWiki messages. TEXT; exit( 1 ); @@ -109,6 +111,7 @@ $wgWriteToFile = !isset( $options['dry-run'] ); $wgListUnknownMessages = !isset( $options['no-unknown'] ); $wgRemoveUnknownMessages = isset( $options['remove-unknown'] ); $wgRemoveDuplicateMessages = isset( $options['remove-duplicates'] ); +$messagesFolder = isset( $options['messages-folder'] ) ? $options['messages-folder'] : false; # Get language objects $languages = new languages(); @@ -116,8 +119,8 @@ $languages = new languages(); # Write all the language if ( $wgCode == 'all' ) { foreach ( $languages->getLanguages() as $languageCode ) { - rebuildLanguage( $languages, $languageCode, $wgWriteToFile, $wgListUnknownMessages, $wgRemoveUnknownMessages, $wgRemoveDuplicateMessages, $wgDupeMessageSource ); + rebuildLanguage( $languages, $languageCode, $wgWriteToFile, $wgListUnknownMessages, $wgRemoveUnknownMessages, $wgRemoveDuplicateMessages, $wgDupeMessageSource, $messagesFolder ); } } else { - rebuildLanguage( $languages, $wgCode, $wgWriteToFile, $wgListUnknownMessages, $wgRemoveUnknownMessages, $wgRemoveDuplicateMessages, $wgDupeMessageSource ); + rebuildLanguage( $languages, $wgCode, $wgWriteToFile, $wgListUnknownMessages, $wgRemoveUnknownMessages, $wgRemoveDuplicateMessages, $wgDupeMessageSource, $messagesFolder ); } diff --git a/maintenance/language/transstat.php b/maintenance/language/transstat.php index fb08b7d0..ba503224 100644 --- a/maintenance/language/transstat.php +++ b/maintenance/language/transstat.php @@ -28,9 +28,9 @@ */ $optionsWithArgs = array( 'output' ); -require_once( dirname( __FILE__ ) . '/../commandLine.inc' ); +require_once( __DIR__ . '/../commandLine.inc' ); require_once( 'languages.inc' ); -require_once( dirname( __FILE__ ) . '/StatOutputs.php' ); +require_once( __DIR__ . '/StatOutputs.php' ); if ( isset( $options['help'] ) ) { @@ -102,7 +102,7 @@ foreach ( $wgLanguages->getLanguages() as $code ) { } # Calculate the numbers - $language = $wgContLang->getLanguageName( $code ); + $language = Language::fetchLanguageName( $code ); $fallback = $wgLanguages->getFallback( $code ); $messages = $wgLanguages->getMessages( $code ); $messagesNumber = count( $messages['translated'] ); @@ -134,5 +134,3 @@ foreach ( $wgLanguages->getLanguages() as $code ) { # Footer $output->footer(); - - diff --git a/maintenance/language/validate.php b/maintenance/language/validate.php index 57517644..751e744d 100644 --- a/maintenance/language/validate.php +++ b/maintenance/language/validate.php @@ -30,7 +30,7 @@ array_shift( $argv ); define( 'MEDIAWIKI', 1 ); define( 'NOT_REALLY_MEDIAWIKI', 1 ); -$IP = dirname( __FILE__ ) . '/../..'; +$IP = __DIR__ . '/../..'; require_once( "$IP/includes/Defines.php" ); require_once( "$IP/languages/Language.php" ); @@ -58,4 +58,3 @@ function getVars( $filename ) { unset( $vars['filename'] ); return $vars; } - diff --git a/maintenance/language/writeMessagesArray.inc b/maintenance/language/writeMessagesArray.inc index 524c2ba6..b2e04c7f 100644 --- a/maintenance/language/writeMessagesArray.inc +++ b/maintenance/language/writeMessagesArray.inc @@ -41,16 +41,28 @@ class MessageWriter { * @param $write Boolean: write to the messages file? * @param $listUnknown Boolean: list the unknown messages? * @param $removeUnknown Boolean: whether to remove unkown messages + * @param $messagesFolder String: path to a folder to store the MediaWiki messages. Defaults to the current install. */ - public static function writeMessagesToFile( $messages, $code, $write, $listUnknown, $removeUnknown ) { + public static function writeMessagesToFile( $messages, $code, $write, $listUnknown, $removeUnknown, $messagesFolder = false ) { # Rewrite the messages array $messages = self::writeMessagesArray( $messages, $code == 'en', false, $removeUnknown ); $messagesText = $messages[0]; $sortedMessages = $messages[1]; # Write to the file - $filename = Language::getMessagesFileName( $code ); - $contents = file_get_contents( $filename ); + if ( $messagesFolder ) + $filename = Language::getFileName( "$messagesFolder/Messages", $code ); + else + $filename = Language::getMessagesFileName( $code ); + + if ( file_exists( $filename ) ) + $contents = file_get_contents( $filename ); + else + $contents = '<?php +$messages = array( +); +'; + if( strpos( $contents, '$messages' ) !== false ) { $contents = explode( '$messages', $contents ); if( $messagesText == '$messages' . $contents[1] ) { @@ -93,7 +105,7 @@ class MessageWriter { */ public static function writeMessagesArray( $messages, $ignoredComments = false, $prefix = false, $removeUnknown = false ) { # Load messages - $dir = $prefix ? $prefix : dirname( __FILE__ ); + $dir = $prefix ? $prefix : __DIR__; require( $dir . '/messages.inc' ); self::$messageStructure = $wgMessageStructure; @@ -156,6 +168,7 @@ class MessageWriter { * @param $messages Array: key of messages. * @param $ignored Array: list of ingored message keys. * @param $optional Array: list of optional message keys. + * @return array */ public static function makeComments( $messages, $ignored, $optional ) { # Comment collector @@ -181,7 +194,7 @@ class MessageWriter { * @param $messageComments Array: optional comments for messages in this block. * @param $prefix String: prefix for every line, for indenting purposes. * - * @return The block, formatted in PHP. + * @return string The block, formatted in PHP. */ public static function writeMessagesBlock( $blockComment, $messages, $messageComments = array(), $prefix = '' ) { diff --git a/maintenance/locking/LockServerDaemon.php b/maintenance/locking/LockServerDaemon.php index 1a4a928e..689c9309 100644 --- a/maintenance/locking/LockServerDaemon.php +++ b/maintenance/locking/LockServerDaemon.php @@ -1,12 +1,28 @@ <?php /** + * Simple lock server daemon that accepts lock/unlock requests. + * + * This code should not require MediaWiki setup or PHP files. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup LockManager Maintenance */ -/** - * This code should not require MediaWiki setup or PHP files. - */ if ( php_sapi_name() !== 'cli' ) { die( "This is not a valid entry point.\n" ); } @@ -223,7 +239,7 @@ class LockServerDaemon { list( $session, $key, $command, $type, $values ) = $m; if ( sha1( $session . $command . $type . $values . $this->authKey ) !== $key ) { return 'BAD_KEY'; - } elseif ( strlen( $session ) !== 31 ) { + } elseif ( strlen( $session ) !== 32 ) { return 'BAD_SESSION'; } $values = explode( '|', $values ); @@ -256,9 +272,9 @@ class LockServerDaemon { /** * Remove a socket's corresponding session from tracking and * store it in the dead session tracking if it still has locks. - * + * * @param $socket resource - * @return book + * @return bool */ protected function recordDeadSocket( $socket ) { $session = array_search( $socket, $this->sessions ); @@ -293,7 +309,7 @@ class LockServerDaemon { /** * Get the current timestamp and memory usage - * + * * @return string */ protected function stat() { @@ -382,7 +398,7 @@ class SocketArray { /** * @param $sock resource - * @return string|false + * @return string|bool */ public function readRcvBuffer( $sock ) { $key = array_search( $sock, $this->clients ); @@ -463,10 +479,10 @@ class LockHolder { /** * @param $session string - * @return bool + * @return bool */ public function sessionHasLocks( $session ) { - return isset( $this->sessionIndexSh[$session] ) + return isset( $this->sessionIndexSh[$session] ) || isset( $this->sessionIndexEx[$session] ); } diff --git a/maintenance/mcc.php b/maintenance/mcc.php index 02445278..e07e62db 100644 --- a/maintenance/mcc.php +++ b/maintenance/mcc.php @@ -23,7 +23,7 @@ */ /** */ -require_once( dirname( __FILE__ ) . '/commandLine.inc' ); +require_once( __DIR__ . '/commandLine.inc' ); $mcc = new MWMemcached( array( 'persistent' => true/*, 'debug' => true*/ ) ); $mcc->set_servers( $wgMemCachedServers ); diff --git a/maintenance/mctest.php b/maintenance/mctest.php index 359cd248..691b832b 100644 --- a/maintenance/mctest.php +++ b/maintenance/mctest.php @@ -1,7 +1,7 @@ <?php /** - * This script makes several 'set', 'incr' and 'get' requests on every - * memcached server and shows a report. + * Makes several 'set', 'incr' and 'get' requests on every memcached + * server and shows a report. * * 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 @@ -18,11 +18,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that makes several 'set', 'incr' and 'get' requests + * on every memcached server and shows a report. + * + * @ingroup Maintenance + */ class mcTest extends Maintenance { public function __construct() { parent::__construct(); @@ -33,7 +40,7 @@ class mcTest extends Maintenance { } public function execute() { - global $wgMemCachedServers; + global $wgMemCachedServers, $wgMemCachedTimeout; $iterations = $this->getOption( 'i', 100 ); if ( $this->hasArg() ) { @@ -42,7 +49,10 @@ class mcTest extends Maintenance { foreach ( $wgMemCachedServers as $server ) { $this->output( $server . " ", $server ); - $mcc = new MemCachedClientforWiki( array( 'persistant' => true ) ); + $mcc = new MemCachedClientforWiki( array( + 'persistant' => true, + 'timeout' => $wgMemCachedTimeout + ) ); $mcc->set_servers( array( $server ) ); $set = 0; $incr = 0; diff --git a/maintenance/mergeMessageFileList.php b/maintenance/mergeMessageFileList.php index b5a911aa..cea64333 100644 --- a/maintenance/mergeMessageFileList.php +++ b/maintenance/mergeMessageFileList.php @@ -25,64 +25,99 @@ # Start from scratch define( 'MW_NO_EXTENSION_MESSAGES', 1 ); -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +$maintClass = 'MergeMessageFileList'; +$mmfl = false; +/** + * Maintenance script that merges $wgExtensionMessagesFiles from various + * extensions to produce a single array containing all message files. + * + * @ingroup Maintenance + */ class MergeMessageFileList extends Maintenance { function __construct() { parent::__construct(); $this->addOption( 'list-file', 'A file containing a list of extension setup files, one per line.', true, true ); + $this->addOption( 'extensions-dir', 'Path where extensions can be found.', false, true ); $this->addOption( 'output', 'Send output to this file (omit for stdout)', false, true ); $this->mDescription = 'Merge $wgExtensionMessagesFiles from various extensions to produce a ' . 'single array containing all message files.'; } public function execute() { + global $mmfl; + + # Add setup files contained in file passed to --list-file $lines = file( $this->getOption( 'list-file' ) ); if ( $lines === false ) { $this->error( 'Unable to open list file.' ); } $mmfl = array( 'setupFiles' => array_map( 'trim', $lines ) ); - if ( $this->hasOption( 'output' ) ) { - $mmfl['output'] = $this->getOption( 'output' ); - } - global $IP, $wgExtensionMessagesFiles; - foreach ( $mmfl['setupFiles'] as $fileName ) { - if ( strval( $fileName ) === '' ) { - continue; + # Now find out files in a directory + $hasError = false; + if ( $this->hasOption( 'extensions-dir' ) ) { + $extdir = $this->getOption( 'extensions-dir' ); + $entries = scandir( $extdir ); + foreach( $entries as $extname ) { + if ( $extname == '.' || $extname == '..' || !is_dir( "$extdir/$extname" ) ) { + continue; + } + $extfile = "{$extdir}/{$extname}/{$extname}.php"; + if ( file_exists( $extfile ) ) { + $mmfl['setupFiles'][] = $extfile; + } else { + $hasError = true; + $this->error( "Extension {$extname} in {$extdir} lacks expected {$extname}.php" ); + } } - $fileName = str_replace( '$IP', $IP, $fileName ); - fwrite( STDERR, "Loading data from $fileName\n" ); - include_once( $fileName ); } - fwrite( STDERR, "\n" ); - $s = - "<" . "?php\n" . - "## This file is generated by mergeMessageFileList.php. Do not edit it directly.\n\n" . - "if ( defined( 'MW_NO_EXTENSION_MESSAGES' ) ) return;\n\n" . - '$wgExtensionMessagesFiles = ' . var_export( $wgExtensionMessagesFiles, true ) . ";\n"; - $dirs = array( - $IP, - dirname( dirname( __FILE__ ) ), - realpath( $IP ) - ); - - foreach ( $dirs as $dir ) { - $s = preg_replace( - "/'" . preg_quote( $dir, '/' ) . "([^']*)'/", - '"$IP\1"', - $s ); + if ( $hasError ) { + $this->error( "Some files are missing (see above). Giving up.", 1 ); } - if ( isset( $mmfl['output'] ) ) { - file_put_contents( $mmfl['output'], $s ); - } else { - echo $s; + if ( $this->hasOption( 'output' ) ) { + $mmfl['output'] = $this->getOption( 'output' ); } } } -$maintClass = 'MergeMessageFileList'; require_once( RUN_MAINTENANCE_IF_MAIN ); + +foreach ( $mmfl['setupFiles'] as $fileName ) { + if ( strval( $fileName ) === '' ) { + continue; + } + $fileName = str_replace( '$IP', $IP, $fileName ); + fwrite( STDERR, "Loading data from $fileName\n" ); + include_once( $fileName ); +} +fwrite( STDERR, "\n" ); +$s = + "<" . "?php\n" . + "## This file is generated by mergeMessageFileList.php. Do not edit it directly.\n\n" . + "if ( defined( 'MW_NO_EXTENSION_MESSAGES' ) ) return;\n\n" . + '$wgExtensionMessagesFiles = ' . var_export( $wgExtensionMessagesFiles, true ) . ";\n\n"; + +$dirs = array( + $IP, + dirname( __DIR__ ), + realpath( $IP ) +); + +foreach ( $dirs as $dir ) { + $s = preg_replace( + "/'" . preg_quote( $dir, '/' ) . "([^']*)'/", + '"$IP\1"', + $s ); +} + +if ( isset( $mmfl['output'] ) ) { + file_put_contents( $mmfl['output'], $s ); +} else { + echo $s; +} + diff --git a/maintenance/migrateUserGroup.php b/maintenance/migrateUserGroup.php index 771ed947..496af723 100644 --- a/maintenance/migrateUserGroup.php +++ b/maintenance/migrateUserGroup.php @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that re-assigns users from an old group to a new one. + * + * @ingroup Maintenance + */ class MigrateUserGroup extends Maintenance { public function __construct() { parent::__construct(); @@ -50,14 +56,22 @@ class MigrateUserGroup extends Maintenance { // Migrate users over in batches... while ( $blockEnd <= $end ) { $this->output( "Doing users $blockStart to $blockEnd\n" ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $dbw->update( 'user_groups', array( 'ug_group' => $newGroup ), array( 'ug_group' => $oldGroup, - "ug_user BETWEEN $blockStart AND $blockEnd" ) + "ug_user BETWEEN $blockStart AND $blockEnd" ), + __METHOD__, + array( 'IGNORE' ) + ); + $count += $dbw->affectedRows(); + $dbw->delete( 'user_groups', + array( 'ug_group' => $oldGroup, + "ug_user BETWEEN $blockStart AND $blockEnd" ), + __METHOD__ ); $count += $dbw->affectedRows(); - $dbw->commit(); + $dbw->commit( __METHOD__ ); $blockStart += $this->mBatchSize; $blockEnd += $this->mBatchSize; wfWaitForSlaves(); diff --git a/maintenance/minify.php b/maintenance/minify.php index e1fd862d..9f5a909d 100644 --- a/maintenance/minify.php +++ b/maintenance/minify.php @@ -21,8 +21,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that minifies a file or set of files. + * + * @ingroup Maintenance + */ class MinifyScript extends Maintenance { var $outDir; diff --git a/maintenance/moveBatch.php b/maintenance/moveBatch.php index 6ecc775e..7d15959c 100644 --- a/maintenance/moveBatch.php +++ b/maintenance/moveBatch.php @@ -1,6 +1,6 @@ <?php /** - * Maintenance script to move a batch of pages + * Move a batch of pages. * * 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 @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Tim Starling * @@ -33,8 +34,13 @@ * e.g. immobile_namespace for namespaces which can't be moved */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to move a batch of pages. + * + * @ingroup Maintenance + */ class MoveBatch extends Maintenance { public function __construct() { parent::__construct(); @@ -92,13 +98,13 @@ class MoveBatch extends Maintenance { $this->output( $source->getPrefixedText() . ' --> ' . $dest->getPrefixedText() ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $err = $source->moveTo( $dest, false, $reason ); if ( $err !== true ) { $msg = array_shift( $err[0] ); - $this->output( "\nFAILED: " . wfMsg( $msg, $err[0] ) ); + $this->output( "\nFAILED: " . wfMessage( $msg, $err[0] )->text() ); } - $dbw->commit(); + $dbw->commit( __METHOD__ ); $this->output( "\n" ); if ( $interval ) { diff --git a/maintenance/mssql/tables.sql b/maintenance/mssql/tables.sql index 8c4d5008..a0c3d17b 100644 --- a/maintenance/mssql/tables.sql +++ b/maintenance/mssql/tables.sql @@ -396,6 +396,7 @@ CREATE TABLE /*$wgDBprefix*/ipblocks ( ipb_deleted BIT NOT NULL DEFAULT 0, ipb_block_email BIT NOT NULL DEFAULT 0, ipb_allow_usertalk BIT NOT NULL DEFAULT 0, + ipb_parent_block_id INT DEFAULT NULL, ); -- Unique index to support "user already blocked" messages -- Any new options which prevent collisions should be included diff --git a/maintenance/mwdoc-filter.php b/maintenance/mwdoc-filter.php new file mode 100644 index 00000000..ab05a3e2 --- /dev/null +++ b/maintenance/mwdoc-filter.php @@ -0,0 +1,19 @@ +<?php +/** + * Doxygen filter to show correct member variable types in documentation. + * + * Should be filled in doxygen INPUT_FILTER as "php mwdoc-filter.php" + * + * Original source code by Goran Rakic + * http://blog.goranrakic.com/ + * http://stackoverflow.com/questions/4325224 + * + * @file + */ + +$source = file_get_contents( $argv[1] ); +$regexp = '#\@var\s+([^\s]+)([^/]+)/\s+(var|public|protected|private)\s+(\$[^\s;=]+)#'; +$replac = '${2} */ ${3} ${1} ${4}'; +$source = preg_replace($regexp, $replac, $source); + +echo $source; diff --git a/maintenance/mwdocgen.php b/maintenance/mwdocgen.php index 0c3b262e..583249a5 100644 --- a/maintenance/mwdocgen.php +++ b/maintenance/mwdocgen.php @@ -49,7 +49,7 @@ if ( php_sapi_name() != 'cli' ) { } /** Figure out the base directory for MediaWiki location */ -$mwPath = dirname( dirname( __FILE__ ) ) . DIRECTORY_SEPARATOR; +$mwPath = dirname( __DIR__ ) . DIRECTORY_SEPARATOR; /** doxygen binary script */ $doxygenBin = 'doxygen'; @@ -57,6 +57,9 @@ $doxygenBin = 'doxygen'; /** doxygen configuration template for mediawiki */ $doxygenTemplate = $mwPath . 'maintenance/Doxyfile'; +/** doxygen input filter to tweak source file before they are parsed */ +$doxygenInputFilter = "php {$mwPath}maintenance/mwdoc-filter.php"; + /** svnstat command, used to get the version of each file */ $svnstat = $mwPath . 'bin/svnstat'; @@ -77,7 +80,9 @@ $mwExcludePaths = array( /** Variable to get user input */ $input = ''; -$exclude_patterns = ''; +$excludePatterns = ''; +/** Whether to generates man pages: */ +$doxyGenerateMan = false; # # Functions @@ -114,31 +119,7 @@ function getSvnRevision( $dir ) { $content = file( $entries ); - // check if file is xml (subversion release <= 1.3) or not (subversion release = 1.4) - if ( preg_match( '/^<\?xml/', $content[0] ) ) { - // subversion is release <= 1.3 - if ( !function_exists( 'simplexml_load_file' ) ) { - // We could fall back to expat... YUCK - return false; - } - - $xml = simplexml_load_file( $entries ); - - if ( $xml ) { - foreach ( $xml->entry as $entry ) { - if ( $xml->entry[0]['name'] == '' ) { - // The directory entry should always have a revision marker. - if ( $entry['revision'] ) { - return intval( $entry['revision'] ); - } - } - } - } - return false; - } else { - // subversion is release 1.4 - return intval( $content[3] ); - } + return intval( $content[3] ); } /** @@ -150,16 +131,15 @@ function getSvnRevision( $dir ) { * @param $svnstat String: path to the svnstat file * @param $input String: Path to analyze. * @param $exclude String: Additionals path regex to exclude - * @param $exclude_patterns String: Additionals path regex to exclude + * @param $excludePatterns String: Additionals path regex to exclude * (LocalSettings.php, AdminSettings.php, .svn and .git directories are always excluded) + * @param $doxyGenerateMan Boolean * @return string */ -function generateConfigFile( $doxygenTemplate, $outputDirectory, $stripFromPath, $currentVersion, $svnstat, $input, $exclude, $exclude_patterns ) { - - global $wgDoxyGenerateMan; +function generateConfigFile( $doxygenTemplate, $outputDirectory, $stripFromPath, $currentVersion, $svnstat, $input, $exclude, $excludePatterns, $doxyGenerateMan ) { + global $doxygenInputFilter; $template = file_get_contents( $doxygenTemplate ); - // Replace template placeholders by correct values. $replacements = array( '{{OUTPUT_DIRECTORY}}' => $outputDirectory, @@ -168,9 +148,10 @@ function generateConfigFile( $doxygenTemplate, $outputDirectory, $stripFromPath, '{{SVNSTAT}}' => $svnstat, '{{INPUT}}' => $input, '{{EXCLUDE}}' => $exclude, - '{{EXCLUDE_PATTERNS}}' => $exclude_patterns, + '{{EXCLUDE_PATTERNS}}' => $excludePatterns, '{{HAVE_DOT}}' => `which dot` ? 'YES' : 'NO', - '{{GENERATE_MAN}}' => $wgDoxyGenerateMan ? 'YES' : 'NO', + '{{GENERATE_MAN}}' => $doxyGenerateMan ? 'YES' : 'NO', + '{{INPUT_FILTER}}' => $doxygenInputFilter, ); $tmpCfg = str_replace( array_keys( $replacements ), array_values( $replacements ), $template ); $tmpFileName = tempnam( wfTempDir(), 'mwdocgen-' ); @@ -208,7 +189,7 @@ if ( is_array( $argv ) ) { } break; case '--generate-man': - $wgDoxyGenerateMan = true; + $doxyGenerateMan = true; break; case '--help': print <<<END @@ -271,9 +252,10 @@ case 5: $file = readaline( "Enter file name $mwPath" ); } $input = $mwPath . $file; + break; case 6: $input = $mwPath; - $exclude_patterns = 'extensions'; + $excludePatterns = 'extensions'; } $versionNumber = getSvnRevision( $input ); @@ -289,7 +271,7 @@ if ( $versionNumber === false ) { # Not using subversion ? $excludedPaths = $mwPath . join( " $mwPath", $mwExcludePaths ); print "EXCLUDE: $excludedPaths\n\n"; -$generatedConf = generateConfigFile( $doxygenTemplate, $doxyOutput, $mwPath, $version, $svnstat, $input, $excludedPaths, $exclude_patterns ); +$generatedConf = generateConfigFile( $doxygenTemplate, $doxyOutput, $mwPath, $version, $svnstat, $input, $excludedPaths, $excludePatterns, $doxyGenerateMan ); $command = $doxygenBin . ' ' . $generatedConf; echo <<<TEXT diff --git a/maintenance/namespaceDupes.php b/maintenance/namespaceDupes.php index 0a5fec33..4197a355 100644 --- a/maintenance/namespaceDupes.php +++ b/maintenance/namespaceDupes.php @@ -2,7 +2,7 @@ /** * Check for articles to fix after adding/deleting namespaces * - * Copyright (C) 2005-2007 Brion Vibber <brion@pobox.com> + * Copyright © 2005-2007 Brion Vibber <brion@pobox.com> * http://www.mediawiki.org/ * * This program is free software; you can redistribute it and/or modify @@ -20,11 +20,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that checks for articles to fix after + * adding/deleting namespaces. + * + * @ingroup Maintenance + */ class NamespaceConflictChecker extends Maintenance { /** @@ -257,7 +264,7 @@ class NamespaceConflictChecker extends Maintenance { $newTitle->getDBkey(), $newTitle->getPrefixedText() ) ); - $id = $newTitle->getArticleId(); + $id = $newTitle->getArticleID(); if ( $id ) { $this->output( "... *** cannot resolve automatically; page exists with ID $id ***\n" ); return false; @@ -285,7 +292,7 @@ class NamespaceConflictChecker extends Maintenance { $this->output( "... !!! invalid title\n" ); return false; } - $id = $title->getArticleId(); + $id = $title->getArticleID(); if ( $id ) { $this->output( "... *** page exists with ID $id ***\n" ); } else { diff --git a/maintenance/nextJobDB.php b/maintenance/nextJobDB.php index 67aa3088..e66e981b 100644 --- a/maintenance/nextJobDB.php +++ b/maintenance/nextJobDB.php @@ -17,12 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @todo Make this work on PostgreSQL and maybe other database servers * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that picks a database that has pending jobs. + * + * @ingroup Maintenance + */ class nextJobDB extends Maintenance { public function __construct() { parent::__construct(); @@ -94,11 +100,12 @@ class nextJobDB extends Maintenance { $lb = wfGetLB( $dbName ); $db = $lb->getConnection( DB_MASTER, array(), $dbName ); if ( $type === false ) { - $conds = array(); + $conds = Job::defaultQueueConditions( ); } else { $conds = array( 'job_cmd' => $type ); } + $exists = (bool) $db->selectField( 'job', '1', $conds, __METHOD__ ); $lb->reuseConnection( $db ); return $exists; diff --git a/maintenance/nukeNS.php b/maintenance/nukeNS.php index 57417508..c471a441 100644 --- a/maintenance/nukeNS.php +++ b/maintenance/nukeNS.php @@ -1,5 +1,4 @@ <?php - /** * Remove pages with only 1 revision from the MediaWiki namespace, without * flooding recent changes, delete logs, etc. @@ -28,13 +27,20 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Steve Sanbeg * based on nukePage by Rob Church */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that removes pages with only one revision from the + * MediaWiki namespace. + * + * @ingroup Maintenance + */ class NukeNS extends Maintenance { public function __construct() { parent::__construct(); @@ -49,7 +55,7 @@ class NukeNS extends Maintenance { $delete = $this->getOption( 'delete', false ); $all = $this->getOption( 'all', false ); $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $tbl_pag = $dbw->tableName( 'page' ); $tbl_rev = $dbw->tableName( 'revision' ); @@ -80,7 +86,7 @@ class NukeNS extends Maintenance { // I already have the id & revs if ( $delete ) { $dbw->query( "DELETE FROM $tbl_pag WHERE page_id = $id" ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); // Delete revisions as appropriate $child = $this->runChild( 'NukePage', 'nukePage.php' ); $child->deleteRevisions( $revs ); @@ -91,7 +97,7 @@ class NukeNS extends Maintenance { $this->output( "skip: " . $title->getPrefixedText() . "\n" ); } } - $dbw->commit(); + $dbw->commit( __METHOD__ ); if ( $n_deleted > 0 ) { # update statistics - better to decrement existing count, or just count diff --git a/maintenance/nukePage.php b/maintenance/nukePage.php index c818e73a..89dffe0c 100644 --- a/maintenance/nukePage.php +++ b/maintenance/nukePage.php @@ -18,12 +18,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that erases a page record from the database. + * + * @ingroup Maintenance + */ class NukePage extends Maintenance { public function __construct() { parent::__construct(); @@ -38,7 +44,7 @@ class NukePage extends Maintenance { $delete = $this->getOption( 'delete', false ); $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $tbl_pag = $dbw->tableName( 'page' ); $tbl_rec = $dbw->tableName( 'recentchanges' ); @@ -73,7 +79,7 @@ class NukePage extends Maintenance { $this->output( "done.\n" ); } - $dbw->commit(); + $dbw->commit( __METHOD__ ); # Delete revisions as appropriate if ( $delete && $count ) { @@ -93,20 +99,20 @@ class NukePage extends Maintenance { } } else { $this->output( "not found in database.\n" ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); } } public function deleteRevisions( $ids ) { $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $tbl_rev = $dbw->tableName( 'revision' ); $set = implode( ', ', $ids ); $dbw->query( "DELETE FROM $tbl_rev WHERE rev_id IN ( $set )" ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); } } diff --git a/maintenance/oracle/alterSharedConstraints.php b/maintenance/oracle/alterSharedConstraints.php index aa207821..e222314d 100644 --- a/maintenance/oracle/alterSharedConstraints.php +++ b/maintenance/oracle/alterSharedConstraints.php @@ -26,7 +26,7 @@ * i.e.: GRANT REFERENCES (user_id) ON mwuser TO hubclient; */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); class AlterSharedConstraints extends Maintenance { public function __construct() { diff --git a/maintenance/oracle/archives/patch-ipblocks_i05_index.sql b/maintenance/oracle/archives/patch-ipblocks_i05_index.sql new file mode 100644 index 00000000..14275383 --- /dev/null +++ b/maintenance/oracle/archives/patch-ipblocks_i05_index.sql @@ -0,0 +1,4 @@ +define mw_prefix='{$wgDBprefix}'; + +CREATE INDEX &mw_prefix.ipblocks_i05 ON &mw_prefix.ipblocks (ipb_parent_block_id); + diff --git a/maintenance/oracle/archives/patch-revision_i05_index.sql b/maintenance/oracle/archives/patch-revision_i05_index.sql new file mode 100644 index 00000000..929c7b31 --- /dev/null +++ b/maintenance/oracle/archives/patch-revision_i05_index.sql @@ -0,0 +1,4 @@ +define mw_prefix='{$wgDBprefix}'; + +CREATE INDEX &mw_prefix.revision_i05 ON &mw_prefix.revision (rev_page,rev_user,rev_timestamp); + diff --git a/maintenance/oracle/tables.sql b/maintenance/oracle/tables.sql index 8c0ca30e..26600eba 100644 --- a/maintenance/oracle/tables.sql +++ b/maintenance/oracle/tables.sql @@ -39,7 +39,7 @@ CREATE INDEX &mw_prefix.user_groups_i01 ON &mw_prefix.user_groups (ug_group); CREATE TABLE &mw_prefix.user_former_groups ( ufg_user NUMBER DEFAULT 0 NOT NULL, - ufg_group VARCHAR2(32) NOT NULL + ufg_group VARCHAR2(16) NOT NULL ); ALTER TABLE &mw_prefix.user_former_groups ADD CONSTRAINT &mw_prefix.user_former_groups_fk1 FOREIGN KEY (ufg_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED; CREATE UNIQUE INDEX &mw_prefix.user_former_groups_u01 ON &mw_prefix.user_former_groups (ufg_user,ufg_group); @@ -116,6 +116,7 @@ CREATE INDEX &mw_prefix.revision_i01 ON &mw_prefix.revision (rev_timestamp); CREATE INDEX &mw_prefix.revision_i02 ON &mw_prefix.revision (rev_page,rev_timestamp); CREATE INDEX &mw_prefix.revision_i03 ON &mw_prefix.revision (rev_user,rev_timestamp); CREATE INDEX &mw_prefix.revision_i04 ON &mw_prefix.revision (rev_user_text,rev_timestamp); +CREATE INDEX &mw_prefix.revision_i05 ON &mw_prefix.revision (rev_page,rev_user,rev_timestamp); CREATE SEQUENCE text_old_id_seq; CREATE TABLE &mw_prefix.pagecontent ( -- replaces reserved word 'text' @@ -272,7 +273,8 @@ CREATE TABLE &mw_prefix.ipblocks ( ipb_range_end VARCHAR2(255), ipb_deleted CHAR(1) DEFAULT '0' NOT NULL, ipb_block_email CHAR(1) DEFAULT '0' NOT NULL, - ipb_allow_usertalk CHAR(1) DEFAULT '0' NOT NULL + ipb_allow_usertalk CHAR(1) DEFAULT '0' NOT NULL, + ipb_parent_block_id NUMBER DEFAULT NULL ); ALTER TABLE &mw_prefix.ipblocks ADD CONSTRAINT &mw_prefix.ipblocks_pk PRIMARY KEY (ipb_id); ALTER TABLE &mw_prefix.ipblocks ADD CONSTRAINT &mw_prefix.ipblocks_fk1 FOREIGN KEY (ipb_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED; @@ -282,6 +284,7 @@ CREATE INDEX &mw_prefix.ipblocks_i01 ON &mw_prefix.ipblocks (ipb_user); CREATE INDEX &mw_prefix.ipblocks_i02 ON &mw_prefix.ipblocks (ipb_range_start, ipb_range_end); CREATE INDEX &mw_prefix.ipblocks_i03 ON &mw_prefix.ipblocks (ipb_timestamp); CREATE INDEX &mw_prefix.ipblocks_i04 ON &mw_prefix.ipblocks (ipb_expiry); +CREATE INDEX &mw_prefix.ipblocks_i05 ON &mw_prefix.ipblocks (ipb_parent_block_id); CREATE TABLE &mw_prefix.image ( img_name VARCHAR2(255) NOT NULL, @@ -664,13 +667,6 @@ CREATE TABLE &mw_prefix.module_deps ( ); CREATE UNIQUE INDEX &mw_prefix.module_deps_u01 ON &mw_prefix.module_deps (md_module, md_skin); -CREATE TABLE &mw_prefix.config ( - cf_name VARCHAR2(255) NOT NULL, - cf_value blob NOT NULL -); -ALTER TABLE &mw_prefix.config ADD CONSTRAINT &mw_prefix.config_pk PRIMARY KEY (cf_name); --- leaving index out for now ... - -- do not prefix this table as it breaks parserTests CREATE TABLE wiki_field_info_full ( table_name VARCHAR2(35) NOT NULL, diff --git a/maintenance/orphans.php b/maintenance/orphans.php index faaadd37..78f98f5a 100644 --- a/maintenance/orphans.php +++ b/maintenance/orphans.php @@ -1,11 +1,11 @@ <?php /** - * Look for 'orphan' revisions hooked to pages which don't exist - * And 'childless' pages with no revisions. + * Look for 'orphan' revisions hooked to pages which don't exist and + * 'childless' pages with no revisions. * Then, kill the poor widows and orphans. * Man this is depressing. * - * Copyright (C) 2005 Brion Vibber <brion@pobox.com> + * Copyright © 2005 Brion Vibber <brion@pobox.com> * http://www.mediawiki.org/ * * This program is free software; you can redistribute it and/or modify @@ -23,17 +23,24 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @author <brion@pobox.com> * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that looks for 'orphan' revisions hooked to pages which + * don't exist and 'childless' pages with no revisions. + * + * @ingroup Maintenance + */ class Orphans extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Look for 'orphan' revisions hooked to pages which don't exist\n" . - "And 'childless' pages with no revisions\n" . + "and 'childless' pages with no revisions\n" . "Then, kill the poor widows and orphans\n" . "Man this is depressing"; $this->addOption( 'fix', 'Actually fix broken entries' ); diff --git a/maintenance/parse.php b/maintenance/parse.php index 876f28e9..b0ab6244 100644 --- a/maintenance/parse.php +++ b/maintenance/parse.php @@ -1,6 +1,7 @@ <?php /** - * CLI script to easily parse some wikitext. + * Parse some wikitext. + * * Wikitext can be given by stdin or using a file. The wikitext will be parsed * using 'CLIParser' as a title. This can be overriden with --title option. * @@ -27,12 +28,34 @@ * </p>$ * @endcode * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file * @ingroup Maintenance * @author Antoine Musso <hashar at free dot fr> * @license GNU General Public License 2.0 or later */ -require_once( dirname(__FILE__) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); + +/** + * Maintenance script to parse some wikitext. + * + * @ingroup Maintenance + */ class CLIParser extends Maintenance { protected $parser; @@ -66,7 +89,8 @@ class CLIParser extends Maintenance { $input_file = $this->getArg( 0, $php_stdin ); if( $input_file === $php_stdin ) { - $this->error( basename(__FILE__) .": warning: reading wikitext from STDIN\n" ); + $ctrl = wfIsWindows() ? 'CTRL+Z' : 'CTRL+D'; + $this->error( basename(__FILE__) .": warning: reading wikitext from STDIN. Press $ctrl to parse.\n" ); } return file_get_contents( $input_file ); diff --git a/maintenance/patchSql.php b/maintenance/patchSql.php index 1f96d62c..1f393556 100644 --- a/maintenance/patchSql.php +++ b/maintenance/patchSql.php @@ -18,11 +18,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that manually runs an SQL patch outside of the general updaters. + * + * @ingroup Maintenance + */ class PatchSql extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/populateCategory.php b/maintenance/populateCategory.php index 0b45493e..ae54d698 100644 --- a/maintenance/populateCategory.php +++ b/maintenance/populateCategory.php @@ -1,6 +1,6 @@ <?php /** - * Script to populate category table. + * Populate the category table. * * 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 @@ -22,9 +22,13 @@ * @author Simetrical */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); - +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Mainteance script to populate the category table. + * + * @ingroup Maintenance + */ class PopulateCategory extends Maintenance { const REPORTING_INTERVAL = 1000; diff --git a/maintenance/populateImageSha1.php b/maintenance/populateImageSha1.php index 4cd2747c..37429a34 100644 --- a/maintenance/populateImageSha1.php +++ b/maintenance/populateImageSha1.php @@ -17,15 +17,22 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to populate the img_sha1 field. + * + * @ingroup Maintenance + */ class PopulateImageSha1 extends LoggedUpdateMaintenance { public function __construct() { parent::__construct(); $this->mDescription = "Populate the img_sha1 field"; + $this->addOption( 'force', "Recalculate sha1 for rows that already have a value" ); $this->addOption( 'method', "Use 'pipe' to pipe to mysql command line,\n" . "\t\tdefault uses Database class", false, true ); $this->addOption( 'file', 'Fix for a specific file, without File: namespace prefixed', false, true ); @@ -49,11 +56,13 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance { public function doDBUpdates() { $method = $this->getOption( 'method', 'normal' ); - $file = $this->getOption( 'file' ); + $file = $this->getOption( 'file', '' ); + $force = $this->getOption( 'force' ); + $isRegen = ( $force || $file != '' ); // forced recalculation? $t = -microtime( true ); $dbw = wfGetDB( DB_MASTER ); - if ( $file ) { + if ( $file != '' ) { $res = $dbw->select( 'image', array( 'img_name' ), @@ -66,15 +75,24 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance { } $this->output( "Populating img_sha1 field for specified files\n" ); } else { - $res = $dbw->select( 'image', - array( 'img_name' ), array( 'img_sha1' => '' ), __METHOD__ ); - $this->output( "Populating img_sha1 field\n" ); + if ( $force ) { + $conds = array(); + $this->output( "Populating and recalculating img_sha1 field\n" ); + } else { + $conds = array( 'img_sha1' => '' ); + $this->output( "Populating img_sha1 field\n" ); + } + $res = $dbw->select( 'image', array( 'img_name' ), $conds, __METHOD__ ); } $imageTable = $dbw->tableName( 'image' ); + $oldImageTable = $dbw->tableName( 'oldimage' ); if ( $method == 'pipe' ) { - // @todo FIXME: Kill this and replace with a second unbuffered DB connection. + // Opening a pipe allows the SHA-1 operation to be done in parallel + // with the database write operation, because the writes are queued + // in the pipe buffer. This can improve performance by up to a + // factor of 2. global $wgDBuser, $wgDBserver, $wgDBpassword, $wgDBname; $cmd = 'mysql -u' . wfEscapeShellArg( $wgDBuser ) . ' -h' . wfEscapeShellArg( $wgDBserver ) . @@ -87,21 +105,49 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance { $i = 0; foreach ( $res as $row ) { if ( $i % $this->mBatchSize == 0 ) { - $this->output( sprintf( "Done %d of %d, %5.3f%% \r", $i, $numRows, $i / $numRows * 100 ) ); + $this->output( sprintf( + "Done %d of %d, %5.3f%% \r", $i, $numRows, $i / $numRows * 100 ) ); wfWaitForSlaves(); } $file = wfLocalFile( $row->img_name ); if ( !$file ) { continue; } + // Upgrade the current file version... $sha1 = $file->getRepo()->getFileSha1( $file->getPath() ); - if ( strval( $sha1 ) !== '' ) { - $sql = "UPDATE $imageTable SET img_sha1=" . $dbw->addQuotes( $sha1 ) . - " WHERE img_name=" . $dbw->addQuotes( $row->img_name ); - if ( $method == 'pipe' ) { - fwrite( $pipe, "$sql;\n" ); + if ( strval( $sha1 ) !== '' ) { // file on disk and hashed properly + if ( $isRegen && $file->getSha1() !== $sha1 ) { + // The population was probably done already. If the old SHA1 + // does not match, then both fix the SHA1 and the metadata. + $file->upgradeRow(); } else { - $dbw->query( $sql, __METHOD__ ); + $sql = "UPDATE $imageTable SET img_sha1=" . $dbw->addQuotes( $sha1 ) . + " WHERE img_name=" . $dbw->addQuotes( $file->getName() ); + if ( $method == 'pipe' ) { + fwrite( $pipe, "$sql;\n" ); + } else { + $dbw->query( $sql, __METHOD__ ); + } + } + } + // Upgrade the old file versions... + foreach ( $file->getHistory() as $oldFile ) { + $sha1 = $oldFile->getRepo()->getFileSha1( $oldFile->getPath() ); + if ( strval( $sha1 ) !== '' ) { // file on disk and hashed properly + if ( $isRegen && $oldFile->getSha1() !== $sha1 ) { + // The population was probably done already. If the old SHA1 + // does not match, then both fix the SHA1 and the metadata. + $oldFile->upgradeRow(); + } else { + $sql = "UPDATE $oldImageTable SET oi_sha1=" . $dbw->addQuotes( $sha1 ) . + " WHERE (oi_name=" . $dbw->addQuotes( $oldFile->getName() ) . " AND" . + " oi_archive_name=" . $dbw->addQuotes( $oldFile->getArchiveName() ) . ")"; + if ( $method == 'pipe' ) { + fwrite( $pipe, "$sql;\n" ); + } else { + $dbw->query( $sql, __METHOD__ ); + } + } } } $i++; diff --git a/maintenance/populateLogSearch.php b/maintenance/populateLogSearch.php index e3f6067f..99d81557 100644 --- a/maintenance/populateLogSearch.php +++ b/maintenance/populateLogSearch.php @@ -18,11 +18,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that makes the required database updates for populating the + * log_search table retroactively + * + * @ingroup Maintenance + */ class PopulateLogSearch extends LoggedUpdateMaintenance { static $tableMap = array( 'rev' => 'revision', 'fa' => 'filearchive', 'oi' => 'oldimage', 'ar' => 'archive' ); diff --git a/maintenance/populateLogUsertext.php b/maintenance/populateLogUsertext.php index 2b0e2d64..059b6fe2 100644 --- a/maintenance/populateLogUsertext.php +++ b/maintenance/populateLogUsertext.php @@ -20,11 +20,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that makes the required database updates for + * Special:ProtectedPages to show all protected pages. + * + * @ingroup Maintenance + */ class PopulateLogUsertext extends LoggedUpdateMaintenance { public function __construct() { parent::__construct(); @@ -59,12 +66,12 @@ class PopulateLogUsertext extends LoggedUpdateMaintenance { $res = $db->select( array( 'logging', 'user' ), array( 'log_id', 'user_name' ), $cond, __METHOD__ ); - $db->begin(); + $db->begin( __METHOD__ ); foreach ( $res as $row ) { $db->update( 'logging', array( 'log_user_text' => $row->user_name ), array( 'log_id' => $row->log_id ), __METHOD__ ); } - $db->commit(); + $db->commit( __METHOD__ ); $blockStart += $this->mBatchSize; $blockEnd += $this->mBatchSize; wfWaitForSlaves(); diff --git a/maintenance/populateParentId.php b/maintenance/populateParentId.php index 14f158c9..e81d4ffb 100644 --- a/maintenance/populateParentId.php +++ b/maintenance/populateParentId.php @@ -19,11 +19,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that makes the required database updates for rev_parent_id + * to be of any use. + * + * @ingroup Maintenance + */ class PopulateParentId extends LoggedUpdateMaintenance { public function __construct() { parent::__construct(); @@ -61,7 +68,7 @@ class PopulateParentId extends LoggedUpdateMaintenance { $cond = "rev_id BETWEEN $blockStart AND $blockEnd"; $res = $db->select( 'revision', array( 'rev_id', 'rev_page', 'rev_timestamp', 'rev_parent_id' ), - $cond, __METHOD__ ); + array( $cond, 'rev_parent_id' => null ), __METHOD__ ); # Go through and update rev_parent_id from these rows. # Assume that the previous revision of the title was # the original previous revision of the title when the diff --git a/maintenance/populateRevisionLength.php b/maintenance/populateRevisionLength.php index 6626cbc1..6c835f4e 100644 --- a/maintenance/populateRevisionLength.php +++ b/maintenance/populateRevisionLength.php @@ -17,11 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that populates the rev_len field for old revisions + * created before MW 1.10. + * + * @ingroup Maintenance + */ class PopulateRevisionLength extends LoggedUpdateMaintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/populateRevisionSha1.php b/maintenance/populateRevisionSha1.php index 55e2a93d..2e14d31e 100644 --- a/maintenance/populateRevisionSha1.php +++ b/maintenance/populateRevisionSha1.php @@ -18,11 +18,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that fills the rev_sha1 and ar_sha1 columns of revision + * and archive tables for revisions created before MW 1.19. + * + * @ingroup Maintenance + */ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { public function __construct() { parent::__construct(); @@ -81,13 +88,13 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { AND $idCol IS NOT NULL AND {$prefix}_sha1 = ''"; $res = $db->select( $table, '*', $cond, __METHOD__ ); - $db->begin(); + $db->begin( __METHOD__ ); foreach ( $res as $row ) { if ( $this->upgradeRow( $row, $table, $idCol, $prefix ) ) { $count++; } } - $db->commit(); + $db->commit( __METHOD__ ); $blockStart += $this->mBatchSize; $blockEnd += $this->mBatchSize; @@ -102,23 +109,24 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { protected function doSha1LegacyUpdates() { $count = 0; $db = $this->getDB( DB_MASTER ); - $res = $db->select( 'archive', '*', array( 'ar_rev_id IS NULL' ), __METHOD__ ); + $res = $db->select( 'archive', '*', + array( 'ar_rev_id IS NULL', 'ar_sha1' => '' ), __METHOD__ ); $updateSize = 0; - $db->begin(); + $db->begin( __METHOD__ ); foreach ( $res as $row ) { if ( $this->upgradeLegacyArchiveRow( $row ) ) { ++$count; } if ( ++$updateSize >= 100 ) { $updateSize = 0; - $db->commit(); + $db->commit( __METHOD__ ); $this->output( "Commited row with ar_timestamp={$row->ar_timestamp}\n" ); wfWaitForSlaves(); - $db->begin(); + $db->begin( __METHOD__ ); } } - $db->commit(); + $db->commit( __METHOD__ ); return $count; } @@ -131,12 +139,15 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { */ protected function upgradeRow( $row, $table, $idCol, $prefix ) { $db = $this->getDB( DB_MASTER ); - if ( $table === 'archive' ) { - $rev = Revision::newFromArchiveRow( $row ); - } else { - $rev = new Revision( $row ); + try { + $rev = ( $table === 'archive' ) + ? Revision::newFromArchiveRow( $row ) + : new Revision( $row ); + $text = $rev->getRawText(); + } catch ( MWException $e ) { + $this->output( "Text of revision with {$idCol}={$row->$idCol} unavailable!\n" ); + return false; // bug 22624? } - $text = $rev->getRawText(); if ( !is_string( $text ) ) { # This should not happen, but sometimes does (bug 20757) $this->output( "Text of revision with {$idCol}={$row->$idCol} unavailable!\n" ); @@ -145,7 +156,7 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { $db->update( $table, array( "{$prefix}_sha1" => Revision::base36Sha1( $text ) ), array( $idCol => $row->$idCol ), - __METHOD__ + __METHOD__ ); return true; } @@ -157,7 +168,12 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { */ protected function upgradeLegacyArchiveRow( $row ) { $db = $this->getDB( DB_MASTER ); - $rev = Revision::newFromArchiveRow( $row ); + try { + $rev = Revision::newFromArchiveRow( $row ); + } catch ( MWException $e ) { + $this->output( "Text of revision with timestamp {$row->ar_timestamp} unavailable!\n" ); + return false; // bug 22624? + } $text = $rev->getRawText(); if ( !is_string( $text ) ) { # This should not happen, but sometimes does (bug 20757) @@ -174,7 +190,7 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { 'ar_timestamp' => $row->ar_timestamp, 'ar_len' => $row->ar_len // extra sanity ), - __METHOD__ + __METHOD__ ); return true; } diff --git a/maintenance/postgres/archives/patch-add_interwiki.sql b/maintenance/postgres/archives/patch-add_interwiki.sql new file mode 100644 index 00000000..6c08af7a --- /dev/null +++ b/maintenance/postgres/archives/patch-add_interwiki.sql @@ -0,0 +1,14 @@ +DROP FUNCTION IF EXISTS add_interwiki(TEXT,INT,CHARACTER) CASCADE; +CREATE OR REPLACE FUNCTION "add_interwiki" (TEXT,INT,SMALLINT) RETURNS INT LANGUAGE SQL AS +$mw$ + INSERT INTO interwiki (iw_prefix, iw_url, iw_local) VALUES ($1,$2,$3); + SELECT 1; +$mw$; + +DROP FUNCTION IF EXISTS add_interwiki(TEXT,INT,CHARACTER) CASCADE; +CREATE OR REPLACE FUNCTION "add_interwiki" (TEXT,INT,SMALLINT) RETURNS INT LANGUAGE SQL AS +$mw$ + INSERT INTO interwiki (iw_prefix, iw_url, iw_local) VALUES ($1,$2,$3); + SELECT 1; +$mw$; + diff --git a/maintenance/postgres/archives/patch-category.sql b/maintenance/postgres/archives/patch-category.sql index 5e0d620f..266b1d00 100644 --- a/maintenance/postgres/archives/patch-category.sql +++ b/maintenance/postgres/archives/patch-category.sql @@ -1,8 +1,8 @@ -CREATE SEQUENCE category_id_seq; +CREATE SEQUENCE category_cat_id_seq; CREATE TABLE category ( - cat_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('category_id_seq'), + cat_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('category_cat_id_seq'), cat_title TEXT NOT NULL, cat_pages INTEGER NOT NULL DEFAULT 0, cat_subcats INTEGER NOT NULL DEFAULT 0, diff --git a/maintenance/postgres/archives/patch-external_user.sql b/maintenance/postgres/archives/patch-external_user.sql new file mode 100644 index 00000000..6058a706 --- /dev/null +++ b/maintenance/postgres/archives/patch-external_user.sql @@ -0,0 +1,6 @@ +CREATE TABLE external_user ( + eu_local_id INTEGER NOT NULL PRIMARY KEY, + eu_external_id TEXT +); + +CREATE UNIQUE INDEX eu_external_id ON external_user (eu_external_id); diff --git a/maintenance/postgres/archives/patch-ipb_address_unique.sql b/maintenance/postgres/archives/patch-ipb_address_unique.sql index e618f99c..e69de29b 100644 --- a/maintenance/postgres/archives/patch-ipb_address_unique.sql +++ b/maintenance/postgres/archives/patch-ipb_address_unique.sql @@ -1 +0,0 @@ -CREATE UNIQUE INDEX ipb_address_unique ON ipblocks (ipb_address,ipb_user,ipb_auto,ipb_anon_only); diff --git a/maintenance/postgres/archives/patch-log_search.sql b/maintenance/postgres/archives/patch-log_search.sql index 20a61fd7..4c0b3c61 100644 --- a/maintenance/postgres/archives/patch-log_search.sql +++ b/maintenance/postgres/archives/patch-log_search.sql @@ -5,5 +5,5 @@ CREATE TABLE log_search ( ls_log_id INTEGER NOT NULL DEFAULT 0 ); -ALTER TABLE log_search ADD CONSTRAINT log_search_pk PRIMARY KEY(ls_field, ls_value, ls_log_id); +ALTER TABLE log_search ADD CONSTRAINT log_search_pkey PRIMARY KEY(ls_field, ls_value, ls_log_id); CREATE INDEX ls_log_id ON log_search (ls_log_id); diff --git a/maintenance/postgres/archives/patch-module_deps.sql b/maintenance/postgres/archives/patch-module_deps.sql index 703dcdaf..bd7bb1f0 100644 --- a/maintenance/postgres/archives/patch-module_deps.sql +++ b/maintenance/postgres/archives/patch-module_deps.sql @@ -4,4 +4,4 @@ CREATE TABLE module_deps ( md_deps TEXT NOT NULL ); -CREATE UNIQUE INDEX md_module_skin_idx ON module_deps (md_module, md_skin); +CREATE UNIQUE INDEX md_module_skin ON module_deps (md_module, md_skin); diff --git a/maintenance/postgres/archives/patch-msg_resource.sql b/maintenance/postgres/archives/patch-msg_resource.sql index 00d82073..68756d1a 100644 --- a/maintenance/postgres/archives/patch-msg_resource.sql +++ b/maintenance/postgres/archives/patch-msg_resource.sql @@ -5,4 +5,4 @@ CREATE TABLE msg_resource ( mr_timestamp TIMESTAMPTZ NOT NULL ); -CREATE UNIQUE INDEX mr_resource_lang_idx ON msg_resource (mr_resource, mr_lang); +CREATE UNIQUE INDEX mr_resource_lang ON msg_resource (mr_resource, mr_lang); diff --git a/maintenance/postgres/archives/patch-msg_resource_links.sql b/maintenance/postgres/archives/patch-msg_resource_links.sql index e7b80219..88109da3 100644 --- a/maintenance/postgres/archives/patch-msg_resource_links.sql +++ b/maintenance/postgres/archives/patch-msg_resource_links.sql @@ -3,4 +3,4 @@ CREATE TABLE msg_resource_links ( mrl_message TEXT NOT NULL ); -CREATE UNIQUE INDEX mrl_message_resource_idx ON msg_resource_links (mrl_message, mrl_resource); +CREATE UNIQUE INDEX mrl_message_resource ON msg_resource_links (mrl_message, mrl_resource); diff --git a/maintenance/postgres/compare_schemas.pl b/maintenance/postgres/compare_schemas.pl index 18210fcf..53aeb147 100644 --- a/maintenance/postgres/compare_schemas.pl +++ b/maintenance/postgres/compare_schemas.pl @@ -38,7 +38,7 @@ while (<DATA>) { my $datatype = join '|' => qw( bool -tinyint int bigint real float +tinyint smallint int bigint real float tinytext mediumtext text char varchar varbinary binary timestamp datetime tinyblob mediumblob blob @@ -94,7 +94,7 @@ sub parse_sql { next if /^\s*\-\-/ or /^\s+$/; s/\s*\-\- [\w ]+$//; chomp; - + if (/CREATE\s*TABLE/i) { if (m{^CREATE TABLE /\*_\*/(\w+) \($}) { $table = $1; @@ -158,16 +158,17 @@ for my $table (sort keys %{$old{$oldfile}}) { } } -my $dtype = join '|' => qw( +my $dtypelist = join '|' => qw( SMALLINT INTEGER BIGINT NUMERIC SERIAL TEXT CHAR VARCHAR BYTEA TIMESTAMPTZ CIDR ); -$dtype = qr{($dtype)}; +my $dtype = qr{($dtypelist)}; my %new; my ($infunction,$inview,$inrule,$lastcomma) = (0,0,0,0); +my %custom_type; seek $newfh, 0, 0; while (<$newfh>) { next if /^\s*\-\-/ or /^\s*$/; @@ -182,6 +183,11 @@ while (<$newfh>) { next if /^DROP SEQUENCE/; next if /^DROP FUNCTION/; + if (/^CREATE TYPE (\w+)/) { + die "Type $1 declared more than once!\n" if $custom_type{$1}++; + $dtype = qr{($dtypelist|$1)}; + next; + } chomp; @@ -233,6 +239,7 @@ my $COLMAP = q{ ## INTS: tinyint SMALLINT int INTEGER SERIAL +smallint SMALLINT bigint BIGINT real NUMERIC float NUMERIC @@ -276,6 +283,9 @@ rc_log_type varbinary(255) TEXT ## Simple text-only strings: ar_flags tinyblob TEXT +cf_name varbinary(255) TEXT +cf_value blob TEXT +ar_sha1 varbinary(32) TEXT cl_collation varbinary(32) TEXT cl_sortkey varbinary(230) TEXT ct_params blob TEXT @@ -298,8 +308,13 @@ log_params blob TEXT # LF separated list of args log_type varbinary(10) TEXT ls_field varbinary(32) TEXT md_deps mediumblob TEXT # JSON +md_module varbinary(255) TEXT +md_skin varbinary(32) TEXT mr_blob mediumblob TEXT # JSON mr_lang varbinary(32) TEXT +mr_resource varbinary(255) TEXT +mrl_message varbinary(255) TEXT +mrl_resource varbinary(255) TEXT oi_minor_mime varbinary(100) TEXT oi_sha1 varbinary(32) TEXT old_flags tinyblob TEXT @@ -316,12 +331,17 @@ qc_type varbinary(32) TEXT qcc_type varbinary(32) TEXT qci_type varbinary(32) TEXT rc_params blob TEXT +rev_sha1 varbinary(32) TEXT rlc_to_blob blob TEXT ts_tags blob TEXT -ug_group varbinary(16) TEXT +ufg_group varbinary(32) TEXT +ug_group varbinary(32) TEXT ul_value blob TEXT -up_property varbinary(32) TEXT +up_property varbinary(255) TEXT up_value blob TEXT +us_sha1 varchar(31) TEXT +us_source_type varchar(50) TEXT +us_status varchar(50) TEXT user_email_token binary(32) TEXT user_ip varbinary(40) TEXT user_newpassword tinyblob TEXT @@ -434,6 +454,9 @@ for my $t (sort keys %{$old{$oldfile}}) { next if exists $colmapok{$c}{$old}{$new}; $old =~ s/ENUM.*/ENUM/; + + next if $old eq 'ENUM' and $new eq 'media_type'; + if (! exists $colmap{$old}{$new}) { print "Column types for $t.$c do not match: $old does not map to $new\n"; } diff --git a/maintenance/postgres/tables.sql b/maintenance/postgres/tables.sql index 6890df91..3ac19cb4 100644 --- a/maintenance/postgres/tables.sql +++ b/maintenance/postgres/tables.sql @@ -36,7 +36,6 @@ CREATE TABLE mwuser ( -- replace reserved word 'user' user_email_token TEXT, user_email_token_expires TIMESTAMPTZ, user_email_authenticated TIMESTAMPTZ, - user_options TEXT, user_touched TIMESTAMPTZ, user_registration TIMESTAMPTZ, user_editcount INTEGER @@ -278,12 +277,14 @@ CREATE TABLE ipblocks ( ipb_range_end TEXT, ipb_deleted SMALLINT NOT NULL DEFAULT 0, ipb_block_email SMALLINT NOT NULL DEFAULT 0, - ipb_allow_usertalk SMALLINT NOT NULL DEFAULT 0 + ipb_allow_usertalk SMALLINT NOT NULL DEFAULT 0, + ipb_parent_block_id INTEGER NULL REFERENCES ipblocks(ipb_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED ); CREATE UNIQUE INDEX ipb_address_unique ON ipblocks (ipb_address,ipb_user,ipb_auto,ipb_anon_only); CREATE INDEX ipb_user ON ipblocks (ipb_user); CREATE INDEX ipb_range ON ipblocks (ipb_range_start,ipb_range_end); +CREATE INDEX ipb_parent_block_id ON ipblocks (ipb_parent_block_id); CREATE TABLE image ( @@ -378,7 +379,7 @@ CREATE TABLE uploadstash ( us_media_type media_type DEFAULT NULL, us_image_width INTEGER, us_image_height INTEGER, - us_image_bits INTEGER + us_image_bits SMALLINT ); CREATE INDEX us_user_idx ON uploadstash (us_user); diff --git a/maintenance/preprocessDump.php b/maintenance/preprocessDump.php index ad9b4f14..5952fd96 100644 --- a/maintenance/preprocessDump.php +++ b/maintenance/preprocessDump.php @@ -1,10 +1,10 @@ <?php /** * Take page text out of an XML dump file and preprocess it to obj. - * It may be useful for getting preprocessor statistics or filling the + * It may be useful for getting preprocessor statistics or filling the * preprocessor cache. * - * Copyright (C) 2011 Platonides - http://www.mediawiki.org/ + * Copyright © 2011 Platonides - http://www.mediawiki.org/ * * 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 @@ -25,8 +25,14 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/dumpIterator.php' ); +require_once( __DIR__ . '/dumpIterator.php' ); +/** + * Maintenance script that takes page text out of an XML dump file and + * preprocesses it to obj. + * + * @ingroup Maintenance + */ class PreprocessDump extends DumpIterator { /* Variables for dressing up as a parser */ diff --git a/maintenance/preprocessorFuzzTest.php b/maintenance/preprocessorFuzzTest.php index 9dee67e2..a53bc88c 100644 --- a/maintenance/preprocessorFuzzTest.php +++ b/maintenance/preprocessorFuzzTest.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/commandLine.inc' ); +require_once( __DIR__ . '/commandLine.inc' ); $wgHooks['BeforeParserFetchTemplateAndtitle'][] = 'PPFuzzTester::templateHook'; diff --git a/maintenance/protect.php b/maintenance/protect.php index 56958ea7..2f6aa1ae 100644 --- a/maintenance/protect.php +++ b/maintenance/protect.php @@ -1,6 +1,6 @@ <?php /** - * Protect or unprotect an article. + * Protect or unprotect a page. * * 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 @@ -17,15 +17,21 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that protects or unprotects a page. + * + * @ingroup Maintenance + */ class Protect extends Maintenance { public function __construct() { parent::__construct(); - $this->mDescription = "Protect or unprotect an article from the command line."; + $this->mDescription = "Protect or unprotect a page from the command line."; $this->addOption( 'unprotect', 'Removes protection' ); $this->addOption( 'semiprotect', 'Adds semi-protection' ); $this->addOption( 'cascade', 'Add cascading protection' ); @@ -35,8 +41,6 @@ class Protect extends Maintenance { } public function execute() { - global $wgUser; - $userName = $this->getOption( 'u', 'Maintenance script' ); $reason = $this->getOption( 'r', '' ); diff --git a/maintenance/proxy_check.php b/maintenance/proxy_check.php index 9c5f32b2..10892c42 100644 --- a/maintenance/proxy_check.php +++ b/maintenance/proxy_check.php @@ -1,6 +1,21 @@ <?php /** - * Command line script to check for an open proxy at a specified location + * Command line script to check for an open proxy at a specified location. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html * * @file * @ingroup Maintenance diff --git a/maintenance/pruneFileCache.php b/maintenance/pruneFileCache.php index f1a1cfd4..e058e3ec 100644 --- a/maintenance/pruneFileCache.php +++ b/maintenance/pruneFileCache.php @@ -1,6 +1,6 @@ <?php /** - * Prune file cache for pages, objects, resources, ect... + * Prune file cache for pages, objects, resources, etc. * * 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 @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that prunes file cache for pages, objects, resources, etc. + * + * @ingroup Maintenance + */ class PruneFileCache extends Maintenance { protected $minSurviveTimestamp; diff --git a/maintenance/purgeDeletedFiles.php b/maintenance/purgeDeletedFiles.php index c8d4fc07..cd62716b 100644 --- a/maintenance/purgeDeletedFiles.php +++ b/maintenance/purgeDeletedFiles.php @@ -1,6 +1,6 @@ <?php /** - * Scans the deletion log and purges affected files within a timeframe. + * Scan the deletion log and purges affected files within a timeframe. * * 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 @@ -17,11 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that scans the deletion log and purges affected files + * within a timeframe. + * + * @ingroup Maintenance + */ class PurgeDeletedFiles extends Maintenance { public function __construct() { parent::__construct(); @@ -74,7 +81,7 @@ class PurgeDeletedFiles extends Maintenance { protected function purgeFromArchiveTable( LocalFile $file ) { $db = $file->getRepo()->getSlaveDB(); - $res = $db->select( 'filearchive', + $res = $db->select( 'filearchive', array( 'fa_archive_name' ), array( 'fa_name' => $file->getName() ), __METHOD__ diff --git a/maintenance/purgeList.php b/maintenance/purgeList.php index f1452bca..4b3c3821 100644 --- a/maintenance/purgeList.php +++ b/maintenance/purgeList.php @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that sends purge requests for listed pages to squid. + * + * @ingroup Maintenance + */ class PurgeList extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/purgeOldText.inc b/maintenance/purgeOldText.inc index 45a7ae28..111c786a 100644 --- a/maintenance/purgeOldText.inc +++ b/maintenance/purgeOldText.inc @@ -27,7 +27,7 @@ function PurgeRedundantText( $delete = false ) { # Data should come off the master, wrapped in a transaction $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $tbl_arc = $dbw->tableName( 'archive' ); $tbl_rev = $dbw->tableName( 'revision' ); @@ -73,6 +73,6 @@ function PurgeRedundantText( $delete = false ) { } # Done - $dbw->commit(); + $dbw->commit( __METHOD__ ); } diff --git a/maintenance/purgeOldText.php b/maintenance/purgeOldText.php index 0cbc724e..1f0b063b 100644 --- a/maintenance/purgeOldText.php +++ b/maintenance/purgeOldText.php @@ -17,12 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that purges old text records from the database. + * + * @ingroup Maintenance + */ class PurgeOldText extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/purgeParserCache.php b/maintenance/purgeParserCache.php index 4d775f95..1c417980 100644 --- a/maintenance/purgeParserCache.php +++ b/maintenance/purgeParserCache.php @@ -1,22 +1,45 @@ <?php /** - * @ingroup Maintenance + * Remove old objects from the parser cache. + * This only works when the parser cache is in an SQL database. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file + * @ingroup Maintenance */ -require( dirname( __FILE__ ) . '/Maintenance.php' ); +require( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to remove old objects from the parser cache. + * + * @ingroup Maintenance + */ class PurgeParserCache extends Maintenance { var $lastProgress; function __construct() { parent::__construct(); - $this->addDescription( "Remove old objects from the parser cache. " . + $this->addDescription( "Remove old objects from the parser cache. " . "This only works when the parser cache is in an SQL database." ); $this->addOption( 'expiredate', 'Delete objects expiring before this date.', false, true ); - $this->addOption( 'age', - 'Delete objects created more than this many seconds ago, assuming $wgParserCacheExpireTime '. - 'has been consistent.', + $this->addOption( 'age', + 'Delete objects created more than this many seconds ago, assuming $wgParserCacheExpireTime ' . + 'has been consistent.', false, true ); } diff --git a/maintenance/purgeStaleMemcachedText.php b/maintenance/purgeStaleMemcachedText.php deleted file mode 100644 index fc9a6a89..00000000 --- a/maintenance/purgeStaleMemcachedText.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -/** - * @ingroup Maintenance Memcached - * @file - */ - -require_once( dirname( __FILE__ ) . '/commandLine.inc' ); - -function purgeStaleMemcachedText() { - global $wgMemc, $wgDBname; - $db = wfGetDB( DB_MASTER ); - $maxTextId = $db->selectField( 'text', 'max(old_id)' ); - $latestReplicatedTextId = $db->selectField( array( 'recentchanges', 'revision' ), 'rev_text_id', - array( 'rev_id = rc_this_oldid', "rc_timestamp < '20101225183000'"), 'purgeStaleMemcachedText', - array( 'ORDER BY' => 'rc_timestamp DESC' ) ); - $latestReplicatedTextId -= 100; # A bit of paranoia - - echo "Going to purge text entries from $latestReplicatedTextId to $maxTextId in $wgDBname\n"; - - for ( $i = $latestReplicatedTextId; $i < $maxTextId; $i++ ) { - $key = wfMemcKey( 'revisiontext', 'textid', $i ); - - while (1) { - if (! $wgMemc->delete( $key ) ) { - echo "Memcache delete for $key returned false\n"; - } - if ( $wgMemc->get( $key ) ) { - echo "There's still content in $key!\n"; - } else { - break; - } - } - - } -} - -purgeStaleMemcachedText(); - diff --git a/maintenance/reassignEdits.php b/maintenance/reassignEdits.php index 3830fe38..a91abf93 100644 --- a/maintenance/reassignEdits.php +++ b/maintenance/reassignEdits.php @@ -17,13 +17,20 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> * @licence GNU General Public Licence 2.0 or later */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that reassigns edits from a user or IP address + * to another user. + * + * @ingroup Maintenance + */ class ReassignEdits extends Maintenance { public function __construct() { parent::__construct(); @@ -62,13 +69,13 @@ class ReassignEdits extends Maintenance { * * @param $from User to take edits from * @param $to User to assign edits to - * @param $rc Update the recent changes table - * @param $report Don't change things; just echo numbers + * @param $rc bool Update the recent changes table + * @param $report bool Don't change things; just echo numbers * @return integer Number of entries changed, or that would be changed */ private function doReassignEdits( &$from, &$to, $rc = false, $report = false ) { $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); # Count things $this->output( "Checking current edits..." ); @@ -117,7 +124,7 @@ class ReassignEdits extends Maintenance { } } - $dbw->commit(); + $dbw->commit( __METHOD__ ); return (int)$total; } @@ -150,7 +157,7 @@ class ReassignEdits extends Maintenance { /** * Initialise the user object * - * @param $username Username or IP address + * @param $username string Username or IP address * @return User */ private function initialiseUser( $username ) { diff --git a/maintenance/rebuildFileCache.php b/maintenance/rebuildFileCache.php index e7ce3521..3165b97f 100644 --- a/maintenance/rebuildFileCache.php +++ b/maintenance/rebuildFileCache.php @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that builds file cache for content pages. + * + * @ingroup Maintenance + */ class RebuildFileCache extends Maintenance { public function __construct() { parent::__construct(); @@ -93,11 +99,11 @@ class RebuildFileCache extends Maintenance { array( 'ORDER BY' => 'page_id ASC', 'USE INDEX' => 'PRIMARY' ) ); - $dbw->begin(); // for any changes + $dbw->begin( __METHOD__ ); // for any changes foreach ( $res as $row ) { $rebuilt = false; $wgRequestTime = microtime( true ); # bug 22852 - + $wgTitle = Title::makeTitleSafe( $row->page_namespace, $row->page_title ); if ( null == $wgTitle ) { $this->output( "Page {$row->page_id} has bad title\n" ); @@ -139,7 +145,7 @@ class RebuildFileCache extends Maintenance { $this->output( "Page {$row->page_id} not cacheable\n" ); } } - $dbw->commit(); // commit any changes (just for sanity) + $dbw->commit( __METHOD__ ); // commit any changes (just for sanity) $blockStart += $this->mBatchSize; $blockEnd += $this->mBatchSize; diff --git a/maintenance/rebuildImages.php b/maintenance/rebuildImages.php index fe3b35c9..2842b402 100644 --- a/maintenance/rebuildImages.php +++ b/maintenance/rebuildImages.php @@ -1,6 +1,6 @@ <?php /** - * Script to update image metadata records + * Update image metadata records. * * Usage: php rebuildImages.php [--missing] [--dry-run] * Options: @@ -30,8 +30,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to update image metadata records. + * + * @ingroup Maintenance + */ class ImageBuilder extends Maintenance { /** @@ -86,7 +91,7 @@ class ImageBuilder extends Maintenance { $this->processed = 0; $this->updated = 0; $this->count = $count; - $this->startTime = wfTime(); + $this->startTime = microtime( true ); $this->table = $table; } @@ -99,7 +104,7 @@ class ImageBuilder extends Maintenance { $portion = $this->processed / $this->count; $updateRate = $this->updated / $this->processed; - $now = wfTime(); + $now = microtime( true ); $delta = $now - $this->startTime; $estimatedTotalTime = $delta / $portion; $eta = $this->startTime + $estimatedTotalTime; @@ -189,7 +194,7 @@ class ImageBuilder extends Maintenance { $filename = $altname; $this->output( "Estimating transcoding... $altname\n" ); } else { - # @FIXME: create renameFile() + # @todo FIXME: create renameFile() $filename = $this->renameFile( $filename ); } } diff --git a/maintenance/rebuildLocalisationCache.php b/maintenance/rebuildLocalisationCache.php index 831d808a..83849de6 100644 --- a/maintenance/rebuildLocalisationCache.php +++ b/maintenance/rebuildLocalisationCache.php @@ -25,21 +25,32 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to rebuild the localisation cache. + * + * @ingroup Maintenance + */ class RebuildLocalisationCache extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Rebuild the localisation cache"; $this->addOption( 'force', 'Rebuild all files, even ones not out of date' ); $this->addOption( 'threads', 'Fork more than one thread', false, true ); + $this->addOption( 'outdir', 'Override the output directory (normally $wgCacheDirectory)', + false, true ); } public function memoryLimit() { - return '200M'; + if ( $this->hasOption( 'memory-limit' ) ) { + return parent::memoryLimit(); + } + return '1000M'; } public function execute() { @@ -65,9 +76,12 @@ class RebuildLocalisationCache extends Maintenance { if ( $force ) { $conf['forceRecache'] = true; } + if ( $this->hasOption( 'outdir' ) ) { + $conf['storeDirectory'] = $this->getOption( 'outdir' ); + } $lc = new LocalisationCache_BulkLoad( $conf ); - $codes = array_keys( Language::getLanguageNames( true ) ); + $codes = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) ); sort( $codes ); // Initialise and split into chunks @@ -111,7 +125,7 @@ class RebuildLocalisationCache extends Maintenance { /** * Helper function to rebuild list of languages codes. Prints the code * for each language which is rebuilt. - * @param $codes list List of language codes to rebuild. + * @param $codes array List of language codes to rebuild. * @param $lc LocalisationCache Instance of LocalisationCache_BulkLoad (?) * @param $force bool Rebuild up-to-date languages * @return int Number of rebuilt languages diff --git a/maintenance/rebuildall.php b/maintenance/rebuildall.php index dbbed86d..882ae1b3 100644 --- a/maintenance/rebuildall.php +++ b/maintenance/rebuildall.php @@ -18,11 +18,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that rebuilds link tracking tables from scratch. + * + * @ingroup Maintenance + */ class RebuildAll extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/rebuildmessages.php b/maintenance/rebuildmessages.php index de37da7e..a70e591f 100644 --- a/maintenance/rebuildmessages.php +++ b/maintenance/rebuildmessages.php @@ -1,6 +1,6 @@ <?php /** - * This script purges all language messages from the cache + * Purge all languages from the message cache. * * 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 @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that purges all languages from the message cache. + * + * @ingroup Maintenance + */ class RebuildMessages extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/rebuildrecentchanges.php b/maintenance/rebuildrecentchanges.php index 92d60902..0278f72c 100644 --- a/maintenance/rebuildrecentchanges.php +++ b/maintenance/rebuildrecentchanges.php @@ -1,7 +1,7 @@ <?php /** - * Rebuild link tracking tables from scratch. This takes several - * hours, depending on the database size and server configuration. + * Rebuild recent changes from scratch. This takes several hours, + * depending on the database size and server configuration. * * 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 @@ -18,12 +18,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @todo Document */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that rebuilds recent changes from scratch. + * + * @ingroup Maintenance + */ class RebuildRecentchanges extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/rebuildtextindex.php b/maintenance/rebuildtextindex.php index 494e0a75..41b245f8 100644 --- a/maintenance/rebuildtextindex.php +++ b/maintenance/rebuildtextindex.php @@ -20,12 +20,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @todo document */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that rebuilds search index table from scratch. + * + * @ingroup Maintenance + */ class RebuildTextIndex extends Maintenance { const RTI_CHUNK_SIZE = 500; diff --git a/maintenance/refreshImageMetadata.php b/maintenance/refreshImageMetadata.php index 958b2ba1..12da7a8b 100644 --- a/maintenance/refreshImageMetadata.php +++ b/maintenance/refreshImageMetadata.php @@ -1,6 +1,6 @@ <?php /** - * Script to refresh image metadata fields. See also rebuildImages.php + * Refresh image metadata fields. See also rebuildImages.php * * Usage: php refreshImageMetadata.php * @@ -27,8 +27,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to refresh image metadata fields. + * + * @ingroup Maintenance + */ class RefreshImageMetadata extends Maintenance { /** diff --git a/maintenance/refreshLinks.php b/maintenance/refreshLinks.php index c16b6963..3d9270b8 100644 --- a/maintenance/refreshLinks.php +++ b/maintenance/refreshLinks.php @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to refresh link tables. + * + * @ingroup Maintenance + */ class RefreshLinks extends Maintenance { public function __construct() { parent::__construct(); @@ -174,10 +180,10 @@ class RefreshLinks extends Maintenance { * @param $id int The page_id of the redirect */ private function fixRedirect( $id ) { - $title = Title::newFromID( $id ); + $page = WikiPage::newFromID( $id ); $dbw = wfGetDB( DB_MASTER ); - if ( is_null( $title ) ) { + if ( $page === null ) { // This page doesn't exist (any more) // Delete any redirect table entry for it $dbw->delete( 'redirect', array( 'rd_from' => $id ), @@ -185,11 +191,10 @@ class RefreshLinks extends Maintenance { return; } - $page = WikiPage::factory( $title ); $rt = $page->getRedirectTarget(); if ( $rt === null ) { - // $title is not a redirect + // The page is not a redirect // Delete any redirect table entry for it $dbw->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ ); @@ -201,37 +206,38 @@ class RefreshLinks extends Maintenance { * @param $id int The page_id */ public static function fixLinksFromArticle( $id ) { - global $wgParser; + global $wgParser, $wgContLang; - $title = Title::newFromID( $id ); - $dbw = wfGetDB( DB_MASTER ); + $page = WikiPage::newFromID( $id ); LinkCache::singleton()->clear(); - if ( is_null( $title ) ) { + if ( $page === null ) { return; } - $revision = Revision::newFromTitle( $title ); - if ( !$revision ) { + $text = $page->getRawText(); + if ( $text === false ) { return; } - $dbw->begin(); + $dbw = wfGetDB( DB_MASTER ); + $dbw->begin( __METHOD__ ); - $options = new ParserOptions; - $parserOutput = $wgParser->parse( $revision->getText(), $title, $options, true, true, $revision->getId() ); - $update = new LinksUpdate( $title, $parserOutput, false ); + $options = ParserOptions::newFromUserAndLang( new User, $wgContLang ); + $parserOutput = $wgParser->parse( $text, $page->getTitle(), $options, true, true, $page->getLatest() ); + $update = new LinksUpdate( $page->getTitle(), $parserOutput, false ); $update->doUpdate(); - $dbw->commit(); + + $dbw->commit( __METHOD__ ); } /** * Removes non-existing links from pages from pagelinks, imagelinks, * categorylinks, templatelinks, externallinks, interwikilinks, langlinks and redirect tables. * - * @param $maxLag - * @param $batchSize The size of deletion batches + * @param $maxLag int + * @param $batchSize int The size of deletion batches * * @author Merlijn van Deen <valhallasw@arctus.nl> */ @@ -287,6 +293,7 @@ class RefreshLinks extends Maintenance { $dbw->delete( $table, array( $field => $list ), __METHOD__ ); } $this->output( "\n" ); + wfWaitForSlaves(); } $lb->closeAll(); } diff --git a/maintenance/removeUnusedAccounts.php b/maintenance/removeUnusedAccounts.php index ba25efdd..8bc27c18 100644 --- a/maintenance/removeUnusedAccounts.php +++ b/maintenance/removeUnusedAccounts.php @@ -18,12 +18,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that removes unused user accounts from the database. + * + * @ingroup Maintenance + */ class RemoveUnusedAccounts extends Maintenance { public function __construct() { parent::__construct(); @@ -86,7 +92,7 @@ class RemoveUnusedAccounts extends Maintenance { * (No edits, no deleted edits, no log entries, no current/old uploads) * * @param $id User's ID - * @param $master Perform checking on the master + * @param $master bool Perform checking on the master * @return bool */ private function isInactiveAccount( $id, $master = false ) { @@ -95,12 +101,12 @@ class RemoveUnusedAccounts extends Maintenance { 'image' => 'img', 'oldimage' => 'oi', 'filearchive' => 'fa' ); $count = 0; - $dbo->begin(); + $dbo->begin( __METHOD__ ); foreach ( $checks as $table => $fprefix ) { $conds = array( $fprefix . '_user' => $id ); $count += (int)$dbo->selectField( $table, 'COUNT(*)', $conds, __METHOD__ ); } - $dbo->commit(); + $dbo->commit( __METHOD__ ); return $count == 0; } diff --git a/maintenance/renameDbPrefix.php b/maintenance/renameDbPrefix.php index 289e747f..6f244791 100644 --- a/maintenance/renameDbPrefix.php +++ b/maintenance/renameDbPrefix.php @@ -1,5 +1,6 @@ <?php /** + * Change the prefix of database tables. * Run this script to after changing $wgDBprefix on a wiki. * The wiki will have to get downtime to do this correctly. * @@ -18,11 +19,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that changes the prefix of database tables. + * + * @ingroup Maintenance + */ class RenameDbPrefix extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/renderDump.php b/maintenance/renderDump.php index 78c5b6f3..24bedfa4 100644 --- a/maintenance/renderDump.php +++ b/maintenance/renderDump.php @@ -28,8 +28,14 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that takes page text out of an XML dump file + * and render basic HTML out to files. + * + * @ingroup Maintenance + */ class DumpRenderer extends Maintenance { private $count = 0; @@ -46,7 +52,7 @@ class DumpRenderer extends Maintenance { public function execute() { $this->outputDirectory = $this->getOption( 'output-dir' ); $this->prefix = $this->getOption( 'prefix', 'wiki' ); - $this->startTime = wfTime(); + $this->startTime = microtime( true ); if ( $this->hasOption( 'parser' ) ) { global $wgParserConf; @@ -62,7 +68,7 @@ class DumpRenderer extends Maintenance { $importer->doImport(); - $delta = wfTime() - $this->startTime; + $delta = microtime( true ) - $this->startTime; $this->error( "Rendered {$this->count} pages in " . round($delta, 2) . " seconds " ); if ($delta > 0) $this->error( round($this->count / $delta, 2) . " pages/sec" ); diff --git a/maintenance/resetUserTokens.php b/maintenance/resetUserTokens.php index a1c4eaeb..d7f8c6d0 100644 --- a/maintenance/resetUserTokens.php +++ b/maintenance/resetUserTokens.php @@ -1,7 +1,7 @@ <?php /** - * Script to reset the user_token for all users on the wiki. Useful if you - * believe that your user table was acidentally leaked to an external source. + * Reset the user_token for all users on the wiki. Useful if you believe + * that your user table was acidentally leaked to an external source. * * 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 @@ -23,8 +23,13 @@ * @author Daniel Friesen <mediawiki@danielfriesen.name> */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to reset the user_token for all users on the wiki. + * + * @ingroup Maintenance + */ class ResetUserTokens extends Maintenance { public function __construct() { parent::__construct(); @@ -33,7 +38,7 @@ class ResetUserTokens extends Maintenance { } public function execute() { - + if ( !$this->getOption( 'nowarn' ) ) { $this->output( "The script is about to reset the user_token for ALL USERS in the database.\n" ); $this->output( "This may log some of them out and is not necessary unless you believe your\n" ); @@ -42,7 +47,7 @@ class ResetUserTokens extends Maintenance { $this->output( "Abort with control-c in the next five seconds (skip this countdown with --nowarn) ... " ); wfCountDown( 5 ); } - + // We list user by user_id from one of the slave database $dbr = wfGetDB( DB_SLAVE ); $result = $dbr->select( 'user', @@ -53,19 +58,19 @@ class ResetUserTokens extends Maintenance { foreach ( $result as $id ) { $user = User::newFromId( $id->user_id ); - + $username = $user->getName(); - + $this->output( "Resetting user_token for $username: " ); - + // Change value $user->setToken(); $user->saveSettings(); - + $this->output( " OK\n" ); - + } - + } } diff --git a/maintenance/rollbackEdits.php b/maintenance/rollbackEdits.php index 3e57e01f..4660bcef 100644 --- a/maintenance/rollbackEdits.php +++ b/maintenance/rollbackEdits.php @@ -18,11 +18,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to rollback all edits by a given user or IP provided + * they're the most recent edit. + * + * @ingroup Maintenance + */ class RollbackEdits extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/runBatchedQuery.php b/maintenance/runBatchedQuery.php index 83e0cab8..e1139164 100644 --- a/maintenance/runBatchedQuery.php +++ b/maintenance/runBatchedQuery.php @@ -19,11 +19,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to run a database query in batches and wait for slaves. + * + * @ingroup Maintenance + */ class BatchedQueryRunner extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/runJobs.php b/maintenance/runJobs.php index 6068311e..e909bc06 100644 --- a/maintenance/runJobs.php +++ b/maintenance/runJobs.php @@ -1,8 +1,8 @@ <?php /** - * This script starts pending jobs. + * Run pending jobs. * - * Usage: + * Options: * --maxjobs <num> (default 10000) * --type <job_cmd> * @@ -21,11 +21,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that runs pending jobs. + * + * @ingroup Maintenance + */ class RunJobs extends Maintenance { public function __construct() { parent::__construct(); @@ -37,6 +43,9 @@ class RunJobs extends Maintenance { } public function memoryLimit() { + if ( $this->hasOption( 'memory-limit' ) ) { + return parent::memoryLimit(); + } // Don't eat all memory on the machine if we get a bad job. return "150M"; } @@ -60,9 +69,11 @@ class RunJobs extends Maintenance { $wgTitle = Title::newFromText( 'RunJobs.php' ); $dbw = wfGetDB( DB_MASTER ); $n = 0; - $conds = ''; - if ( $type !== false ) { - $conds = "job_cmd = " . $dbw->addQuotes( $type ); + + if ( $type === false ) { + $conds = Job::defaultQueueConditions( ); + } else { + $conds = array( 'job_cmd' => $type ); } while ( $dbw->selectField( 'job', 'job_id', $conds, 'runJobs.php' ) ) { @@ -77,6 +88,7 @@ class RunJobs extends Maintenance { wfWaitForSlaves(); $t = microtime( true ); $offset = $job->id; + $this->runJobsLog( $job->toString() . " STARTING" ); $status = $job->run(); $t = microtime( true ) - $t; $timeMs = intval( $t * 1000 ); diff --git a/maintenance/showJobs.php b/maintenance/showJobs.php index ff7d3fc0..1dceb790 100644 --- a/maintenance/showJobs.php +++ b/maintenance/showJobs.php @@ -1,9 +1,9 @@ <?php /** - * Based on runJobs.php - * * Report number of jobs currently waiting in master database. * + * Based on runJobs.php + * * 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 @@ -19,13 +19,20 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Tim Starling * @author Antoine Musso */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that reports the number of jobs currently waiting + * in master database. + * + * @ingroup Maintenance + */ class ShowJobs extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/showStats.php b/maintenance/showStats.php index b284a9ac..982c7cbb 100644 --- a/maintenance/showStats.php +++ b/maintenance/showStats.php @@ -1,7 +1,7 @@ <?php /** - * Maintenance script to show the cached statistics. + * Show the cached statistics. * Give out the same output as [[Special:Statistics]] * * This program is free software; you can redistribute it and/or modify @@ -19,6 +19,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance * @author Antoine Musso <hashar at free dot fr> * Based on initStats.php by: @@ -28,8 +29,13 @@ * @license GNU General Public License 2.0 or later */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to show the cached statistics. + * + * @ingroup Maintenance + */ class ShowStats extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/sql.php b/maintenance/sql.php index c4af6307..04e98d91 100644 --- a/maintenance/sql.php +++ b/maintenance/sql.php @@ -18,11 +18,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that sends SQL queries from the specified file to the database. + * + * @ingroup Maintenance + */ class MwSql extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/sqlite.inc b/maintenance/sqlite.inc index 1f821917..a8a1fce6 100644 --- a/maintenance/sqlite.inc +++ b/maintenance/sqlite.inc @@ -23,6 +23,8 @@ /** * This class contains code common to different SQLite-related maintenance scripts + * + * @ingroup Maintenance */ class Sqlite { @@ -85,4 +87,4 @@ class Sqlite { $db->close(); return true; } - };
\ No newline at end of file + }; diff --git a/maintenance/sqlite.php b/maintenance/sqlite.php index 864d5ab6..4085c59b 100644 --- a/maintenance/sqlite.php +++ b/maintenance/sqlite.php @@ -1,6 +1,6 @@ <?php /** - * Performs some operations specific to SQLite database backend + * Performs some operations specific to SQLite database backend. * * 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 @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that performs some operations specific to SQLite database backend. + * + * @ingroup Maintenance + */ class SqliteMaintenance extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/sqlite/archives/patch-cat_hidden.sql b/maintenance/sqlite/archives/patch-cat_hidden.sql new file mode 100644 index 00000000..272b8ef3 --- /dev/null +++ b/maintenance/sqlite/archives/patch-cat_hidden.sql @@ -0,0 +1,20 @@ +-- cat_hidden is no longer used, delete it + +CREATE TABLE /*_*/category_tmp ( + cat_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, + cat_title varchar(255) binary NOT NULL, + cat_pages int signed NOT NULL default 0, + cat_subcats int signed NOT NULL default 0, + cat_files int signed NOT NULL default 0 +) /*$wgDBTableOptions*/; + +INSERT INTO /*_*/category_tmp + SELECT cat_id, cat_title, cat_pages, cat_subcats, cat_files + FROM /*_*/category; + +DROP TABLE /*_*/category; + +ALTER TABLE /*_*/category_tmp RENAME TO /*_*/category; + +CREATE UNIQUE INDEX /*i*/cat_title ON /*_*/category (cat_title); +CREATE INDEX /*i*/cat_pages ON /*_*/category (cat_pages); diff --git a/maintenance/sqlite/archives/patch-revision-user-page-index.sql b/maintenance/sqlite/archives/patch-revision-user-page-index.sql new file mode 100644 index 00000000..a4554c8f --- /dev/null +++ b/maintenance/sqlite/archives/patch-revision-user-page-index.sql @@ -0,0 +1,4 @@ +-- New index on revision table to allow searches for all edits by a given user +-- to a given page. Added 2007-08-28 + +CREATE INDEX /*i*/page_user_timestamp ON /*_*/revision (rev_page,rev_user,rev_timestamp); diff --git a/maintenance/stats.php b/maintenance/stats.php index 46926dd0..be448f99 100644 --- a/maintenance/stats.php +++ b/maintenance/stats.php @@ -1,6 +1,6 @@ <?php /** - * Show statistics from the cache + * Show statistics from the cache. * * 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 @@ -17,11 +17,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that shows statistics from the cache. + * + * @ingroup Maintenance + */ class CacheStats extends Maintenance { public function __construct() { diff --git a/maintenance/storage/checkStorage.php b/maintenance/storage/checkStorage.php index af1f9ee2..6c669bfa 100644 --- a/maintenance/storage/checkStorage.php +++ b/maintenance/storage/checkStorage.php @@ -22,7 +22,7 @@ */ if ( !defined( 'MEDIAWIKI' ) ) { - require_once( dirname( __FILE__ ) . '/../commandLine.inc' ); + require_once( __DIR__ . '/../commandLine.inc' ); $cs = new CheckStorage; $fix = isset( $options['fix'] ); @@ -381,14 +381,15 @@ class CheckStorage { $extDb->freeResult( $res ); // Print errors for missing blobs rows - foreach ( $oldIds as $blobId => $oldIds ) { - $this->error( 'restore text', "Error: missing target $cluster/$blobId for two-part ES URL", $oldIds ); + foreach ( $oldIds as $blobId => $oldIds2 ) { + $this->error( 'restore text', "Error: missing target $cluster/$blobId for two-part ES URL", $oldIds2 ); } } } function restoreText( $revIds, $xml ) { - global $wgTmpDirectory, $wgDBname; + global $wgDBname; + $tmpDir = wfTempDir(); if ( !count( $revIds ) ) { return; @@ -396,8 +397,8 @@ class CheckStorage { print "Restoring text from XML backup...\n"; - $revFileName = "$wgTmpDirectory/broken-revlist-$wgDBname"; - $filteredXmlFileName = "$wgTmpDirectory/filtered-$wgDBname.xml"; + $revFileName = "$tmpDir/broken-revlist-$wgDBname"; + $filteredXmlFileName = "$tmpDir/filtered-$wgDBname.xml"; // Write revision list if ( !file_put_contents( $revFileName, implode( "\n", $revIds ) ) ) { @@ -481,4 +482,3 @@ class CheckStorage { $this->errors['fixed'][$id] = true; } } - diff --git a/maintenance/storage/compressOld.php b/maintenance/storage/compressOld.php index afe01458..4594db71 100644 --- a/maintenance/storage/compressOld.php +++ b/maintenance/storage/compressOld.php @@ -17,8 +17,9 @@ * -c <chunk-size> maximum number of revisions in a concat chunk * -b <begin-date> earliest date to check for uncompressed revisions * -e <end-date> latest revision date to compress - * -s <startid> the old_id to start from - * -n <endid> the old_id to stop at + * -s <startid> the id to start from (referring to the text table for + * type gzip, and to the page table for type concat) + * -n <endid> the page_id to stop at (only when using concat compression type) * --extdb <cluster> store specified revisions in an external cluster (untested) * * This program is free software; you can redistribute it and/or modify @@ -40,7 +41,7 @@ * @ingroup Maintenance ExternalStorage */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); class CompressOld extends Maintenance { /** @@ -56,9 +57,9 @@ class CompressOld extends Maintenance { $this->addOption( 'chunksize', 'Maximum number of revisions in a concat chunk', false, true, 'c' ); $this->addOption( 'begin-date', 'Earliest date to check for uncompressed revisions', false, true, 'b' ); $this->addOption( 'end-date', 'Latest revision date to compress', false, true, 'e' ); - $this->addOption( 'startid', 'The old_id to start from', false, true, 's' ); + $this->addOption( 'startid', 'The id to start from (gzip -> text table, concat -> page table)', false, true, 's' ); $this->addOption( 'extdb', 'Store specified revisions in an external cluster (untested)', false, true ); - $this->addOption( 'endid', 'Stop at this old_id', false, true, 'n' ); + $this->addOption( 'endid', 'The page_id to stop at (only when using concat compression type)', false, true, 'n' ); } public function execute() { @@ -293,7 +294,7 @@ class CompressOld extends Maintenance { $chunk = new ConcatenatedGzipHistoryBlob(); $stubs = array(); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $usedChunk = false; $primaryOldid = $revs[$i]->rev_text_id; @@ -393,7 +394,7 @@ class CompressOld extends Maintenance { } # Done, next $this->output( "/" ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); $i += $thisChunkSize; wfWaitForSlaves(); } diff --git a/maintenance/storage/dumpRev.php b/maintenance/storage/dumpRev.php index b200d8af..6020f22e 100644 --- a/maintenance/storage/dumpRev.php +++ b/maintenance/storage/dumpRev.php @@ -18,7 +18,7 @@ * @ingroup Maintenance ExternalStorage */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); class DumpRev extends Maintenance { public function __construct() { diff --git a/maintenance/storage/fixBug20757.php b/maintenance/storage/fixBug20757.php index cb2663d1..52ee825c 100644 --- a/maintenance/storage/fixBug20757.php +++ b/maintenance/storage/fixBug20757.php @@ -21,7 +21,7 @@ * @ingroup Maintenance ExternalStorage */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); class FixBug20757 extends Maintenance { var $batchSize = 10000; @@ -213,7 +213,7 @@ class FixBug20757 extends Maintenance { if ( !$dryRun ) { // Reset the text row to point to the original copy - $dbw->begin(); + $dbw->begin( __METHOD__ ); $dbw->update( 'text', // SET @@ -241,7 +241,7 @@ class FixBug20757 extends Maintenance { ), __METHOD__ ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); $this->waitForSlaves(); } diff --git a/maintenance/storage/moveToExternal.php b/maintenance/storage/moveToExternal.php index 64f3adaa..2dcc25c2 100644 --- a/maintenance/storage/moveToExternal.php +++ b/maintenance/storage/moveToExternal.php @@ -24,8 +24,8 @@ define( 'REPORTING_INTERVAL', 1 ); if ( !defined( 'MEDIAWIKI' ) ) { - require_once( dirname( __FILE__ ) . '/../commandLine.inc' ); - require_once( dirname( __FILE__ ) . '/../../includes/ExternalStoreDB.php' ); + require_once( __DIR__ . '/../commandLine.inc' ); + require_once( __DIR__ . '/../../includes/ExternalStoreDB.php' ); require_once( 'resolveStubs.php' ); $fname = 'moveToExternal'; diff --git a/maintenance/storage/orphanStats.php b/maintenance/storage/orphanStats.php index f30f07e4..82ee135b 100644 --- a/maintenance/storage/orphanStats.php +++ b/maintenance/storage/orphanStats.php @@ -20,7 +20,7 @@ * * @ingroup Maintenance ExternalStorage */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); class OrphanStats extends Maintenance { public function __construct() { @@ -28,7 +28,7 @@ class OrphanStats extends Maintenance { $this->mDescription = "how some statistics on the blob_orphans table, created with trackBlobs.php"; } - private function getDB( $cluster ) { + protected function &getDB( $cluster, $groups = array(), $wiki = false ) { $lb = wfGetLBFactory()->getExternalLB( $cluster ); return $lb->getConnection( DB_SLAVE ); } diff --git a/maintenance/storage/recompressTracked.php b/maintenance/storage/recompressTracked.php index c8aac64b..4098077f 100644 --- a/maintenance/storage/recompressTracked.php +++ b/maintenance/storage/recompressTracked.php @@ -23,7 +23,7 @@ */ $optionsWithArgs = RecompressTracked::getOptionsWithArgs(); -require( dirname( __FILE__ ) . '/../commandLine.inc' ); +require( __DIR__ . '/../commandLine.inc' ); if ( count( $args ) < 1 ) { echo "Usage: php recompressTracked.php [options] <cluster> [... <cluster>...] @@ -528,7 +528,7 @@ class RecompressTracked { exit( 1 ); } $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $dbw->update( 'text', array( // set 'old_text' => $url, @@ -544,7 +544,7 @@ class RecompressTracked { array( 'bt_text_id' => $textId ), __METHOD__ ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); } /** @@ -739,7 +739,7 @@ class CgzCopyTransaction { // // We do a locking read to prevent closer-run race conditions. $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); + $dbw->begin( __METHOD__ ); $res = $dbw->select( 'blob_tracking', array( 'bt_text_id', 'bt_moved' ), array( 'bt_text_id' => array_keys( $this->referrers ) ), @@ -773,7 +773,7 @@ class CgzCopyTransaction { $store = $this->parent->store; $targetDB = $store->getMaster( $targetCluster ); $targetDB->clearFlag( DBO_TRX ); // we manage the transactions - $targetDB->begin(); + $targetDB->begin( __METHOD__ ); $baseUrl = $this->parent->store->store( $targetCluster, serialize( $this->cgz ) ); // Write the new URLs to the blob_tracking table @@ -789,10 +789,10 @@ class CgzCopyTransaction { ); } - $targetDB->commit(); + $targetDB->commit( __METHOD__ ); // Critical section here: interruption at this point causes blob duplication // Reversing the order of the commits would cause data loss instead - $dbw->commit(); + $dbw->commit( __METHOD__ ); // Write the new URLs to the text table and set the moved flag if ( !$this->parent->copyOnly ) { diff --git a/maintenance/storage/resolveStubs.php b/maintenance/storage/resolveStubs.php index 08d0ee04..7e288e13 100644 --- a/maintenance/storage/resolveStubs.php +++ b/maintenance/storage/resolveStubs.php @@ -27,7 +27,7 @@ define( 'REPORTING_INTERVAL', 100 ); if ( !defined( 'MEDIAWIKI' ) ) { $optionsWithArgs = array( 'm' ); - require_once( dirname( __FILE__ ) . '/../commandLine.inc' ); + require_once( __DIR__ . '/../commandLine.inc' ); resolveStubs(); } diff --git a/maintenance/storage/storageTypeStats.php b/maintenance/storage/storageTypeStats.php index 817659fc..1afecc4e 100644 --- a/maintenance/storage/storageTypeStats.php +++ b/maintenance/storage/storageTypeStats.php @@ -19,7 +19,7 @@ * @ingroup Maintenance ExternalStorage */ -require_once( dirname( __FILE__ ) . '/../Maintenance.php' ); +require_once( __DIR__ . '/../Maintenance.php' ); class StorageTypeStats extends Maintenance { function execute() { diff --git a/maintenance/storage/testCompression.php b/maintenance/storage/testCompression.php index 9ae26335..998ebe48 100644 --- a/maintenance/storage/testCompression.php +++ b/maintenance/storage/testCompression.php @@ -21,7 +21,7 @@ */ $optionsWithArgs = array( 'start', 'limit', 'type' ); -require( dirname( __FILE__ ) . '/../commandLine.inc' ); +require( __DIR__ . '/../commandLine.inc' ); if ( !isset( $args[0] ) ) { echo "Usage: php testCompression.php [--type=<type>] [--start=<start-date>] [--limit=<num-revs>] <page-title>\n"; diff --git a/maintenance/storage/trackBlobs.php b/maintenance/storage/trackBlobs.php index b5f80047..214168a8 100644 --- a/maintenance/storage/trackBlobs.php +++ b/maintenance/storage/trackBlobs.php @@ -22,7 +22,7 @@ * @see wfWaitForSlaves() */ -require( dirname( __FILE__ ) . '/../commandLine.inc' ); +require( __DIR__ . '/../commandLine.inc' ); if ( count( $args ) < 1 ) { @@ -113,7 +113,7 @@ class TrackBlobs { $dbw->query( 'DROP TABLE ' . $dbw->tableName( 'blob_tracking' ) ); $dbw->query( 'DROP TABLE ' . $dbw->tableName( 'blob_orphans' ) ); } - $dbw->sourceFile( dirname( __FILE__ ) . '/blob_tracking.sql' ); + $dbw->sourceFile( __DIR__ . '/blob_tracking.sql' ); } function getTextClause() { diff --git a/maintenance/syncFileBackend.php b/maintenance/syncFileBackend.php new file mode 100644 index 00000000..a29647b5 --- /dev/null +++ b/maintenance/syncFileBackend.php @@ -0,0 +1,252 @@ +<?php +/** + * Sync one file backend to another based on the journal of later. + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Maintenance + */ + +require_once( __DIR__ . '/Maintenance.php' ); + +/** + * Maintenance script that syncs one file backend to another based on + * the journal of later. + * + * @ingroup Maintenance + */ +class SyncFileBackend extends Maintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = "Sync one file backend with another using the journal"; + $this->addOption( 'src', 'Name of backend to sync from', true, true ); + $this->addOption( 'dst', 'Name of destination backend to sync', true, true ); + $this->addOption( 'start', 'Starting journal ID', false, true ); + $this->addOption( 'end', 'Ending journal ID', false, true ); + $this->addOption( 'posdir', 'Directory to read/record journal positions', false, true ); + $this->addOption( 'verbose', 'Verbose mode', false, false, 'v' ); + $this->setBatchSize( 50 ); + } + + public function execute() { + $src = FileBackendGroup::singleton()->get( $this->getOption( 'src' ) ); + $dst = FileBackendGroup::singleton()->get( $this->getOption( 'dst' ) ); + + $posDir = $this->getOption( 'posdir' ); + $posFile = $posDir ? $posDir . '/' . wfWikiID() : false; + + $start = $this->getOption( 'start', 0 ); + if ( !$start && $posFile && is_dir( $posDir ) ) { + $start = is_file( $posFile ) + ? (int)trim( file_get_contents( $posFile ) ) + : 0; + ++$start; // we already did this ID, start with the next one + $startFromPosFile = true; + } else { + $startFromPosFile = false; + } + $end = $this->getOption( 'end', INF ); + + $this->output( "Synchronizing backend '{$dst->getName()}' to '{$src->getName()}'...\n" ); + $this->output( "Starting journal position is $start.\n" ); + if ( is_finite( $end ) ) { + $this->output( "Ending journal position is $end.\n" ); + } + + // Actually sync the dest backend with the reference backend + $lastOKPos = $this->syncBackends( $src, $dst, $start, $end ); + + // Update the sync position file + if ( $startFromPosFile && $lastOKPos >= $start ) { // successfully advanced + if ( file_put_contents( $posFile, $lastOKPos, LOCK_EX ) !== false ) { + $this->output( "Updated journal position file.\n" ); + } else { + $this->output( "Could not update journal position file.\n" ); + } + } + + if ( $lastOKPos === false ) { + if ( !$start ) { + $this->output( "No journal entries found.\n" ); + } else { + $this->output( "No new journal entries found.\n" ); + } + } else { + $this->output( "Stopped synchronization at journal position $lastOKPos.\n" ); + } + + if ( $this->isQuiet() ) { + print $lastOKPos; // give a single machine-readable number + } + } + + /** + * Sync $dst backend to $src backend based on the $src logs given after $start. + * Returns the journal entry ID this advanced to and handled (inclusive). + * + * @param $src FileBackend + * @param $dst FileBackend + * @param $start integer Starting journal position + * @param $end integer Starting journal position + * @return integer|false Journal entry ID or false if there are none + */ + protected function syncBackends( FileBackend $src, FileBackend $dst, $start, $end ) { + $lastOKPos = 0; // failed + $first = true; // first batch + + if ( $start > $end ) { // sanity + $this->error( "Error: given starting ID greater than ending ID.", 1 ); + } + + do { + $limit = min( $this->mBatchSize, $end - $start + 1 ); // don't go pass ending ID + $this->output( "Doing id $start to " . ( $start + $limit - 1 ) . "...\n" ); + + $entries = $src->getJournal()->getChangeEntries( $start, $limit, $next ); + $start = $next; // start where we left off next time + if ( $first && !count( $entries ) ) { + return false; // nothing to do + } + $first = false; + + $lastPosInBatch = 0; + $pathsInBatch = array(); // changed paths + foreach ( $entries as $entry ) { + if ( $entry['op'] !== 'null' ) { // null ops are just for reference + $pathsInBatch[$entry['path']] = 1; // remove duplicates + } + $lastPosInBatch = $entry['id']; + } + + $status = $this->syncFileBatch( array_keys( $pathsInBatch ), $src, $dst ); + if ( $status->isOK() ) { + $lastOKPos = max( $lastOKPos, $lastPosInBatch ); + } else { + $this->error( print_r( $status->getErrorsArray(), true ) ); + break; // no gaps; everything up to $lastPos must be OK + } + + if ( !$start ) { + $this->output( "End of journal entries.\n" ); + } + } while ( $start && $start <= $end ); + + return $lastOKPos; + } + + /** + * Sync particular files of backend $src to the corresponding $dst backend files + * + * @param $paths Array + * @param $src FileBackend + * @param $dst FileBackend + * @return Status + */ + protected function syncFileBatch( array $paths, FileBackend $src, FileBackend $dst ) { + $status = Status::newGood(); + if ( !count( $paths ) ) { + return $status; // nothing to do + } + + // Source: convert internal backend names (FileBackendMultiWrite) to the public one + $sPaths = $this->replaceNamePaths( $paths, $src ); + // Destination: get corresponding path name + $dPaths = $this->replaceNamePaths( $paths, $dst ); + + // Lock the live backend paths from modification + $sLock = $src->getScopedFileLocks( $sPaths, LockManager::LOCK_UW, $status ); + $eLock = $dst->getScopedFileLocks( $dPaths, LockManager::LOCK_EX, $status ); + if ( !$status->isOK() ) { + return $status; + } + + $ops = array(); + $fsFiles = array(); + foreach ( $sPaths as $i => $sPath ) { + $dPath = $dPaths[$i]; // destination + $sExists = $src->fileExists( array( 'src' => $sPath, 'latest' => 1 ) ); + if ( $sExists === true ) { // exists in source + if ( $this->filesAreSame( $src, $dst, $sPath, $dPath ) ) { + continue; // avoid local copies for non-FS backends + } + // Note: getLocalReference() is fast for FS backends + $fsFile = $src->getLocalReference( array( 'src' => $sPath, 'latest' => 1 ) ); + if ( !$fsFile ) { + $this->error( "Unable to sync '$dPath': could not get local copy." ); + $status->fatal( 'backend-fail-internal', $src->getName() ); + return $status; + } + $fsFiles[] = $fsFile; // keep TempFSFile objects alive as needed + // Note: prepare() is usually fast for key/value backends + $status->merge( $dst->prepare( array( + 'dir' => dirname( $dPath ), 'bypassReadOnly' => 1 ) ) ); + if ( !$status->isOK() ) { + return $status; + } + $ops[] = array( 'op' => 'store', + 'src' => $fsFile->getPath(), 'dst' => $dPath, 'overwrite' => 1 ); + } elseif ( $sExists === false ) { // does not exist in source + $ops[] = array( 'op' => 'delete', 'src' => $dPath, 'ignoreMissingSource' => 1 ); + } else { // error + $this->error( "Unable to sync '$dPath': could not stat file." ); + $status->fatal( 'backend-fail-internal', $src->getName() ); + return $status; + } + } + + $t_start = microtime( true ); + $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); + if ( !$status->isOK() ) { + sleep( 10 ); // wait and retry copy again + $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); + } + $ellapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); + if ( $status->isOK() && $this->getOption( 'verbose' ) ) { + $this->output( "Synchronized these file(s) [{$ellapsed_ms}ms]:\n" . + implode( "\n", $dPaths ) . "\n" ); + } + + return $status; + } + + /** + * Substitute the backend name of storage paths with that of a given one + * + * @param $paths Array|string List of paths or single string path + * @return Array|string + */ + protected function replaceNamePaths( $paths, FileBackend $backend ) { + return preg_replace( + '!^mwstore://([^/]+)!', + StringUtils::escapeRegexReplacement( "mwstore://" . $backend->getName() ), + $paths // string or array + ); + } + + protected function filesAreSame( FileBackend $src, FileBackend $dst, $sPath, $dPath ) { + return ( + ( $src->getFileSize( array( 'src' => $sPath ) ) + === $dst->getFileSize( array( 'src' => $dPath ) ) // short-circuit + ) && ( $src->getFileSha1Base36( array( 'src' => $sPath ) ) + === $dst->getFileSha1Base36( array( 'src' => $dPath ) ) + ) + ); + } +} + +$maintClass = "SyncFileBackend"; +require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/tables.sql b/maintenance/tables.sql index db89c37e..52b835fd 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -25,7 +25,7 @@ -- in early 2002 after a lot of trouble with the fields -- auto-updating. -- --- The Postgres backend uses DATETIME fields for timestamps, +-- The Postgres backend uses TIMESTAMPTZ fields for timestamps, -- and we will migrate the MySQL definitions at some point as -- well. -- @@ -159,7 +159,8 @@ CREATE UNIQUE INDEX /*i*/ug_user_group ON /*_*/user_groups (ug_user,ug_group); CREATE INDEX /*i*/ug_group ON /*_*/user_groups (ug_group); -- Stores the groups the user has once belonged to. --- The user may still belong these groups. Check user_groups. +-- The user may still belong to these groups (check user_groups). +-- Users are not autopromoted to groups from which they were removed. CREATE TABLE /*_*/user_former_groups ( -- Key to user_id ufg_user int unsigned NOT NULL default 0, @@ -325,6 +326,7 @@ CREATE INDEX /*i*/rev_timestamp ON /*_*/revision (rev_timestamp); CREATE INDEX /*i*/page_timestamp ON /*_*/revision (rev_page,rev_timestamp); CREATE INDEX /*i*/user_timestamp ON /*_*/revision (rev_user,rev_timestamp); CREATE INDEX /*i*/usertext_timestamp ON /*_*/revision (rev_user_text,rev_timestamp); +CREATE INDEX /*i*/page_user_timestamp ON /*_*/revision (rev_page,rev_user,rev_timestamp); -- -- Holds text of individual page revisions. @@ -569,10 +571,7 @@ CREATE TABLE /*_*/category ( -- ing is not. cat_pages int signed NOT NULL default 0, cat_subcats int signed NOT NULL default 0, - cat_files int signed NOT NULL default 0, - - -- Reserved for future use - cat_hidden tinyint unsigned NOT NULL default 0 + cat_files int signed NOT NULL default 0 ) /*$wgDBTableOptions*/; CREATE UNIQUE INDEX /*i*/cat_title ON /*_*/category (cat_title); @@ -770,7 +769,13 @@ CREATE TABLE /*_*/ipblocks ( ipb_block_email bool NOT NULL default 0, -- Block allows user to edit their own talk page - ipb_allow_usertalk bool NOT NULL default 0 + ipb_allow_usertalk bool NOT NULL default 0, + + -- ID of the block that caused this block to exist + -- Autoblocks set this to the original block + -- so that the original block being deleted also + -- deletes the autoblocks + ipb_parent_block_id int default NULL ) /*$wgDBTableOptions*/; @@ -782,6 +787,7 @@ CREATE INDEX /*i*/ipb_user ON /*_*/ipblocks (ipb_user); CREATE INDEX /*i*/ipb_range ON /*_*/ipblocks (ipb_range_start(8), ipb_range_end(8)); CREATE INDEX /*i*/ipb_timestamp ON /*_*/ipblocks (ipb_timestamp); CREATE INDEX /*i*/ipb_expiry ON /*_*/ipblocks (ipb_expiry); +CREATE INDEX /*i*/ipb_parent_block_id ON /*_*/ipblocks (ipb_parent_block_id); -- @@ -944,44 +950,44 @@ CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timesta -- moved into the actual filestore -- CREATE TABLE /*_*/uploadstash ( - us_id int unsigned NOT NULL PRIMARY KEY auto_increment, + us_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - -- the user who uploaded the file. - us_user int unsigned NOT NULL, + -- the user who uploaded the file. + us_user int unsigned NOT NULL, - -- file key. this is how applications actually search for the file. - -- this might go away, or become the primary key. - us_key varchar(255) NOT NULL, + -- file key. this is how applications actually search for the file. + -- this might go away, or become the primary key. + us_key varchar(255) NOT NULL, - -- the original path - us_orig_path varchar(255) NOT NULL, + -- the original path + us_orig_path varchar(255) NOT NULL, - -- the temporary path at which the file is actually stored - us_path varchar(255) NOT NULL, + -- the temporary path at which the file is actually stored + us_path varchar(255) NOT NULL, - -- which type of upload the file came from (sometimes) - us_source_type varchar(50), + -- which type of upload the file came from (sometimes) + us_source_type varchar(50), - -- the date/time on which the file was added - us_timestamp varbinary(14) not null, + -- the date/time on which the file was added + us_timestamp varbinary(14) NOT NULL, - us_status varchar(50) not null, + us_status varchar(50) NOT NULL, - -- chunk counter starts at 0, current offset is stored in us_size - us_chunk_inx int unsigned NULL, + -- chunk counter starts at 0, current offset is stored in us_size + us_chunk_inx int unsigned NULL, - -- file properties from File::getPropsFromPath. these may prove unnecessary. - -- - us_size int unsigned NOT NULL, - -- this hash comes from File::sha1Base36(), and is 31 characters - us_sha1 varchar(31) NOT NULL, - us_mime varchar(255), - -- Media type as defined by the MEDIATYPE_xxx constants, should duplicate definition in the image table - us_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - -- image-specific properties - us_image_width int unsigned, - us_image_height int unsigned, - us_image_bits smallint unsigned + -- file properties from File::getPropsFromPath. these may prove unnecessary. + -- + us_size int unsigned NOT NULL, + -- this hash comes from File::sha1Base36(), and is 31 characters + us_sha1 varchar(31) NOT NULL, + us_mime varchar(255), + -- Media type as defined by the MEDIATYPE_xxx constants, should duplicate definition in the image table + us_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, + -- image-specific properties + us_image_width int unsigned, + us_image_height int unsigned, + us_image_bits smallint unsigned ) /*$wgDBTableOptions*/; @@ -1235,7 +1241,7 @@ CREATE INDEX /*i*/page_time ON /*_*/logging (log_namespace, log_title, log_times CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp); CREATE INDEX /*i*/log_user_type_time ON /*_*/logging (log_user, log_type, log_timestamp); CREATE INDEX /*i*/log_page_id_time ON /*_*/logging (log_page,log_timestamp); -CREATE INDEX /*i*/type_action ON /*_*/logging(log_type, log_action, log_timestamp); +CREATE INDEX /*i*/type_action ON /*_*/logging (log_type, log_action, log_timestamp); CREATE TABLE /*_*/log_search ( @@ -1273,7 +1279,7 @@ CREATE TABLE /*_*/job ( ) /*$wgDBTableOptions*/; CREATE INDEX /*i*/job_cmd ON /*_*/job (job_cmd, job_namespace, job_title, job_params(128)); -CREATE INDEX /*i*/job_timestamp ON /*_*/job(job_timestamp); +CREATE INDEX /*i*/job_timestamp ON /*_*/job (job_timestamp); -- Details of updates to cached special pages @@ -1439,7 +1445,7 @@ CREATE TABLE /*_*/l10n_cache ( ) /*$wgDBTableOptions*/; CREATE INDEX /*i*/lc_lang_key ON /*_*/l10n_cache (lc_lang, lc_key); --- Table for storing JSON message blobs for the resource loader +-- Table for caching JSON message blobs for the resource loader CREATE TABLE /*_*/msg_resource ( -- Resource name mr_resource varbinary(255) NOT NULL, @@ -1460,8 +1466,8 @@ CREATE TABLE /*_*/msg_resource_links ( ) /*$wgDBTableOptions*/; CREATE UNIQUE INDEX /*i*/mrl_message_resource ON /*_*/msg_resource_links (mrl_message, mrl_resource); --- Table for tracking which local files a module depends on that aren't --- registered directly. +-- Table caching which local files a module depends on that aren't +-- registered directly, used for fast retrieval of file dependency. -- Currently only used for tracking images that CSS depends on CREATE TABLE /*_*/module_deps ( -- Module name diff --git a/maintenance/term/MWTerm.php b/maintenance/term/MWTerm.php index 36fb8eec..ca0f95d2 100644 --- a/maintenance/term/MWTerm.php +++ b/maintenance/term/MWTerm.php @@ -1,14 +1,31 @@ <?php - /** - * @ingroup Testing - * * Set of classes to help with test output and such. Right now pretty specific * to the parser tests but could be more useful one day :) * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Testing * @todo Fixme: Make this more generic */ +/** + * Terminal that supports ANSI escape sequences. + */ class AnsiTermColorer { function __construct() { } @@ -37,7 +54,9 @@ class AnsiTermColorer { } } -/* A colour-less terminal */ +/** + * A colour-less terminal + */ class DummyTermColorer { public function color( $color ) { return ''; diff --git a/maintenance/undelete.php b/maintenance/undelete.php index 1c3b14a5..ea8b0c4b 100644 --- a/maintenance/undelete.php +++ b/maintenance/undelete.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); class Undelete extends Maintenance { public function __construct() { diff --git a/maintenance/update.php b/maintenance/update.php index c4bf3b22..877f1366 100644 --- a/maintenance/update.php +++ b/maintenance/update.php @@ -25,15 +25,20 @@ * @ingroup Maintenance */ -if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.2.3' ) < 0 ) ) { - echo "You are using PHP version " . phpversion() . " but MediaWiki needs PHP 5.2.3 or higher. ABORTING.\n" . +if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.3.2' ) < 0 ) ) { + echo "You are using PHP version " . phpversion() . " but MediaWiki needs PHP 5.3.2 or higher. ABORTING.\n" . "Check if you have a newer php executable with a different name, such as php5.\n"; die( 1 ); } $wgUseMasterForMaintenance = true; -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to run database schema updates. + * + * @ingroup Maintenance + */ class UpdateMediaWiki extends Maintenance { function __construct() { diff --git a/maintenance/updateArticleCount.php b/maintenance/updateArticleCount.php index dbbfb80c..4d49dd2d 100644 --- a/maintenance/updateArticleCount.php +++ b/maintenance/updateArticleCount.php @@ -1,7 +1,7 @@ <?php /** - * Maintenance script to provide a better count of the number of articles - * and update the site statistics table, if desired + * Provide a better count of the number of articles + * and update the site statistics table, if desired. * * 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 @@ -23,8 +23,14 @@ * @author Rob Church <robchur@gmail.com> */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to provide a better count of the number of articles + * and update the site statistics table, if desired. + * + * @ingroup Maintenance + */ class UpdateArticleCount extends Maintenance { public function __construct() { diff --git a/maintenance/updateCollation.php b/maintenance/updateCollation.php index 023409fa..b732508f 100644 --- a/maintenance/updateCollation.php +++ b/maintenance/updateCollation.php @@ -1,7 +1,7 @@ <?php /** - * Script will find all rows in the categorylinks table whose collation is - * out-of-date (cl_collation != $wgCategoryCollation) and repopulate cl_sortkey + * Find all rows in the categorylinks table whose collation is out-of-date + * (cl_collation != $wgCategoryCollation) and repopulate cl_sortkey * using the page title and cl_sortkey_prefix. * * This program is free software; you can redistribute it and/or modify @@ -26,12 +26,20 @@ #$optionsWithArgs = array( 'begin', 'max-slave-lag' ); -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that will find all rows in the categorylinks table + * whose collation is out-of-date. + * + * @ingroup Maintenance + */ class UpdateCollation extends Maintenance { const BATCH_SIZE = 50; // Number of rows to process in one batch const SYNC_INTERVAL = 20; // Wait for slaves after this many batches + var $sizeHistogram = array(); + public function __construct() { parent::__construct(); @@ -50,6 +58,13 @@ TEXT; 'categorylinks table is large. This will only update rows with that ' . 'collation, though, so it may miss out-of-date rows with a different, ' . 'even older collation.', false, true ); + $this->addOption( 'target-collation', 'Set this to the new collation type to ' . + 'use instead of $wgCategoryCollation. Usually you should not use this, ' . + 'you should just update $wgCategoryCollation in LocalSettings.php.', + false, true ); + $this->addOption( 'dry-run', 'Don\'t actually change the collations, just ' . + 'compile statistics.' ); + $this->addOption( 'verbose-stats', 'Show more statistics.' ); } public function execute() { @@ -57,10 +72,19 @@ TEXT; $dbw = $this->getDB( DB_MASTER ); $force = $this->getOption( 'force' ); + $dryRun = $this->getOption( 'dry-run' ); + $verboseStats = $this->getOption( 'verbose-stats' ); + if ( $this->hasOption( 'target-collation' ) ) { + $collationName = $this->getOption( 'target-collation' ); + $collation = Collation::factory( $collationName ); + } else { + $collationName = $wgCategoryCollation; + $collation = Collation::singleton(); + } $options = array( 'LIMIT' => self::BATCH_SIZE, 'STRAIGHT_JOIN' ); - if ( $force ) { + if ( $force || $dryRun ) { $options['ORDER BY'] = 'cl_from, cl_to'; $collationConds = array(); } else { @@ -68,7 +92,7 @@ TEXT; $collationConds['cl_collation'] = $this->getOption( 'previous-collation' ); } else { $collationConds = array( 0 => - 'cl_collation != ' . $dbw->addQuotes( $wgCategoryCollation ) + 'cl_collation != ' . $dbw->addQuotes( $collationName ) ); } @@ -79,13 +103,19 @@ TEXT; $collationConds, __METHOD__ ); - - if ( $count == 0 ) { - $this->output( "Collations up-to-date.\n" ); - return; - } - $this->output( "Fixing collation for $count rows.\n" ); + } else { + $count = $dbw->estimateRowCount( + 'categorylinks', + '*', + $collationConds, + __METHOD__ + ); + } + if ( $count == 0 ) { + $this->output( "Collations up-to-date.\n" ); + return; } + $this->output( "Fixing collation for $count rows.\n" ); } $count = 0; @@ -104,7 +134,9 @@ TEXT; ); $this->output( " processing..." ); - $dbw->begin(); + if ( !$dryRun ) { + $dbw->begin( __METHOD__ ); + } foreach ( $res as $row ) { $title = Title::newFromRow( $row ); if ( !$row->cl_collation ) { @@ -129,23 +161,32 @@ TEXT; } else { $type = 'page'; } - $dbw->update( - 'categorylinks', - array( - 'cl_sortkey' => Collation::singleton()->getSortKey( - $title->getCategorySortkey( $prefix ) ), - 'cl_sortkey_prefix' => $prefix, - 'cl_collation' => $wgCategoryCollation, - 'cl_type' => $type, - 'cl_timestamp = cl_timestamp', - ), - array( 'cl_from' => $row->cl_from, 'cl_to' => $row->cl_to ), - __METHOD__ - ); + $newSortKey = $collation->getSortKey( + $title->getCategorySortkey( $prefix ) ); + if ( $verboseStats ) { + $this->updateSortKeySizeHistogram( $newSortKey ); + } + + if ( !$dryRun ) { + $dbw->update( + 'categorylinks', + array( + 'cl_sortkey' => $newSortKey, + 'cl_sortkey_prefix' => $prefix, + 'cl_collation' => $collationName, + 'cl_type' => $type, + 'cl_timestamp = cl_timestamp', + ), + array( 'cl_from' => $row->cl_from, 'cl_to' => $row->cl_to ), + __METHOD__ + ); + } + } + if ( !$dryRun ) { + $dbw->commit( __METHOD__ ); } - $dbw->commit(); - if ( $force && $row ) { + if ( ( $force || $dryRun ) && $row ) { $encFrom = $dbw->addQuotes( $row->cl_from ); $encTo = $dbw->addQuotes( $row->cl_to ); $batchConds = array( @@ -156,12 +197,83 @@ TEXT; $count += $res->numRows(); $this->output( "$count done.\n" ); - if ( ++$batchCount % self::SYNC_INTERVAL == 0 ) { + if ( !$dryRun && ++$batchCount % self::SYNC_INTERVAL == 0 ) { $this->output( "Waiting for slaves ... " ); wfWaitForSlaves(); $this->output( "done\n" ); } } while ( $res->numRows() == self::BATCH_SIZE ); + + $this->output( "$count rows processed\n" ); + + if ( $verboseStats ) { + $this->output( "\n" ); + $this->showSortKeySizeHistogram(); + } + } + + function updateSortKeySizeHistogram( $key ) { + $length = strlen( $key ); + if ( !isset( $this->sizeHistogram[$length] ) ) { + $this->sizeHistogram[$length] = 0; + } + $this->sizeHistogram[$length]++; + } + + function showSortKeySizeHistogram() { + $maxLength = max( array_keys( $this->sizeHistogram ) ); + if ( $maxLength == 0 ) { + return; + } + $numBins = 20; + $coarseHistogram = array_fill( 0, $numBins, 0 ); + $coarseBoundaries = array(); + $boundary = 0; + for ( $i = 0; $i < $numBins - 1; $i++ ) { + $boundary += $maxLength / $numBins; + $coarseBoundaries[$i] = round( $boundary ); + } + $coarseBoundaries[$numBins - 1] = $maxLength + 1; + $raw = ''; + for ( $i = 0; $i <= $maxLength; $i++ ) { + if ( $raw !== '' ) { + $raw .= ', '; + } + if ( !isset( $this->sizeHistogram[$i] ) ) { + $val = 0; + } else { + $val = $this->sizeHistogram[$i]; + } + for ( $coarseIndex = 0; $coarseIndex < $numBins - 1; $coarseIndex++ ) { + if ( $coarseBoundaries[$coarseIndex] > $i ) { + $coarseHistogram[$coarseIndex] += $val; + break; + } + } + if ( $coarseIndex == $numBins - 1 ) { + $coarseHistogram[$coarseIndex] += $val; + } + $raw .= $val; + } + + $this->output( "Sort key size histogram\nRaw data: $raw\n\n" ); + + $maxBinVal = max( $coarseHistogram ); + $scale = 60 / $maxBinVal; + $prevBoundary = 0; + for ( $coarseIndex = 0; $coarseIndex < $numBins; $coarseIndex++ ) { + if ( !isset( $coarseHistogram[$coarseIndex] ) ) { + $val = 0; + } else { + $val = $coarseHistogram[$coarseIndex]; + } + $boundary = $coarseBoundaries[$coarseIndex]; + $this->output( sprintf( "%-10s %-10d |%s\n", + $prevBoundary . '-' . ( $boundary - 1 ) . ': ', + $val, + str_repeat( '*', $scale * $val ) ) ); + $prevBoundary = $boundary; + } } } diff --git a/maintenance/updateDoubleWidthSearch.php b/maintenance/updateDoubleWidthSearch.php index 61545f8d..dc7398ad 100644 --- a/maintenance/updateDoubleWidthSearch.php +++ b/maintenance/updateDoubleWidthSearch.php @@ -1,6 +1,6 @@ <?php /** - * Script to normalize double-byte latin UTF-8 characters + * Normalize double-byte latin UTF-8 characters * * Usage: php updateDoubleWidthSearch.php * @@ -23,8 +23,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to normalize double-byte latin UTF-8 characters. + * + * @ingroup Maintenance + */ class UpdateDoubleWidthSearch extends Maintenance { public function __construct() { diff --git a/maintenance/updateRestrictions.php b/maintenance/updateRestrictions.php index ffbdb2ba..8699dc26 100644 --- a/maintenance/updateRestrictions.php +++ b/maintenance/updateRestrictions.php @@ -24,8 +24,14 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script that updates page_restrictions table from + * old page_restriction column. + * + * @ingroup Maintenance + */ class UpdateRestrictions extends Maintenance { public function __construct() { parent::__construct(); diff --git a/maintenance/updateSearchIndex.php b/maintenance/updateSearchIndex.php index eed3571c..2a71e7ed 100644 --- a/maintenance/updateSearchIndex.php +++ b/maintenance/updateSearchIndex.php @@ -1,6 +1,6 @@ <?php /** - * Script for periodic off-peak updating of the search index + * Periodic off-peak updating of the search index. * * Usage: php updateSearchIndex.php [-s START] [-e END] [-p POSFILE] [-l LOCKTIME] [-q] * Where START is the starting timestamp @@ -28,8 +28,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script for periodic off-peak updating of the search index. + * + * @ingroup Maintenance + */ class UpdateSearchIndex extends Maintenance { public function __construct() { diff --git a/maintenance/updateSpecialPages.php b/maintenance/updateSpecialPages.php index ddf1601b..3f1a90bb 100644 --- a/maintenance/updateSpecialPages.php +++ b/maintenance/updateSpecialPages.php @@ -1,7 +1,7 @@ <?php /** - * Run this script periodically if you have miser mode enabled, to refresh the - * caches + * Update for cached special pages. + * Run this script periodically if you have miser mode enabled. * * 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 @@ -22,8 +22,13 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to update cached special pages. + * + * @ingroup Maintenance + */ class UpdateSpecialPages extends Maintenance { public function __construct() { parent::__construct(); @@ -128,7 +133,7 @@ class UpdateSpecialPages extends Maintenance { $this->output( "Reconnected\n\n" ); } else { # Commit the results - $dbw->commit(); + $dbw->commit( __METHOD__ ); } # Wait for the slave to catch up wfWaitForSlaves(); diff --git a/maintenance/upgrade1_5.php b/maintenance/upgrade1_5.php index 1577c237..1e268de3 100644 --- a/maintenance/upgrade1_5.php +++ b/maintenance/upgrade1_5.php @@ -28,7 +28,7 @@ * @ingroup Maintenance */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); define( 'MW_UPGRADE_COPY', false ); define( 'MW_UPGRADE_ENCODE', true ); @@ -116,7 +116,7 @@ class FiveUpgrade extends Maintenance { /** * Open a connection to the master server with the admin rights. - * @return Database + * @return DatabaseBase * @access private */ function newConnection() { @@ -141,7 +141,7 @@ class FiveUpgrade extends Maintenance { * Open a second connection to the master server, with buffering off. * This will let us stream large datasets in and write in chunks on the * other end. - * @return Database + * @return DatabaseBase * @access private */ function streamConnection() { @@ -252,7 +252,7 @@ class FiveUpgrade extends Maintenance { $this->chunkSize = $chunksize; $this->chunkFinal = $final; $this->chunkCount = 0; - $this->chunkStartTime = wfTime(); + $this->chunkStartTime = microtime( true ); $this->chunkOptions = array( 'IGNORE' ); $this->chunkTable = $table; $this->chunkFunction = $fname; @@ -273,7 +273,7 @@ class FiveUpgrade extends Maintenance { $this->insertChunk( $chunk ); $this->chunkCount += count( $chunk ); - $now = wfTime(); + $now = microtime( true ); $delta = $now - $this->chunkStartTime; $rate = $this->chunkCount / $delta; @@ -342,7 +342,7 @@ class FiveUpgrade extends Maintenance { * MW_UPGRADE_COPY - straight copy * MW_UPGRADE_ENCODE - for old Latin1 wikis, conv to UTF-8 * MW_UPGRADE_NULL - just put NULL - * @param callable $callback An optional callback to modify the data + * @param $callback callback An optional callback to modify the data * or perform other processing. Func should be * ( object $row, array $copy ) and return $copy * @access private diff --git a/maintenance/userOptions.inc b/maintenance/userOptions.inc index a6659fe7..2a066579 100644 --- a/maintenance/userOptions.inc +++ b/maintenance/userOptions.inc @@ -25,7 +25,7 @@ $options = array( 'list', 'nowarn', 'quiet', 'usage', 'dry' ); $optionsWithArgs = array( 'old', 'new' ); -require_once( dirname( __FILE__ ) . '/commandLine.inc' ); +require_once( __DIR__ . '/commandLine.inc' ); /** * @ingroup Maintenance @@ -76,7 +76,7 @@ class userOptions { * @param $opts array * @param $args array * - * @return true + * @return bool */ private function initializeOpts( $opts, $args ) { diff --git a/maintenance/userOptions.php b/maintenance/userOptions.php index 64368f63..2181e44d 100644 --- a/maintenance/userOptions.php +++ b/maintenance/userOptions.php @@ -1,8 +1,6 @@ <?php /** - * Script to change users skins on the fly. - * This is for at least MediaWiki 1.10alpha (r19611) and have not been - * tested with previous versions. It should probably work with 1.7+. + * Script to change users preferences on the fly. * * Made on an original idea by Fooey (freenode) * diff --git a/maintenance/waitForSlave.php b/maintenance/waitForSlave.php index 720ca288..655be43d 100644 --- a/maintenance/waitForSlave.php +++ b/maintenance/waitForSlave.php @@ -1,6 +1,6 @@ <?php /** - * Script to wait until slave lag goes under a certain value. + * Wait until slave lag goes under a certain value. * * 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 @@ -22,8 +22,13 @@ * @see wfWaitForSlaves() */ -require_once( dirname( __FILE__ ) . '/Maintenance.php' ); +require_once( __DIR__ . '/Maintenance.php' ); +/** + * Maintenance script to wait until slave lag goes under a certain value. + * + * @ingroup Maintenance + */ class WaitForSlave extends Maintenance { public function __construct() { $this->addArg( 'maxlag', 'How long to wait for the slaves, default 10 seconds', false ); |