diff options
Diffstat (limited to 'maintenance')
189 files changed, 4411 insertions, 1711 deletions
diff --git a/maintenance/Doxyfile b/maintenance/Doxyfile index 6c9811d0..df67ba60 100644 --- a/maintenance/Doxyfile +++ b/maintenance/Doxyfile @@ -1,16 +1,18 @@ -# Doxyfile 1.4.6 +# Doxyfile 1.5.1 # # Some placeholders have been added for MediaWiki usage: # {{OUTPUT_DIRECTORY}} +# {{CURRENT_VERSION}} # {{STRIP_FROM_PATH}} +# {{SVNSTAT}} # {{INPUT}} #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = MediaWiki -PROJECT_NUMBER = trunk +PROJECT_NUMBER = {{CURRENT_VERSION}} OUTPUT_DIRECTORY = {{OUTPUT_DIRECTORY}} CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English @@ -39,7 +41,7 @@ MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO -TAB_SIZE = 8 +TAB_SIZE = 4 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO @@ -74,7 +76,7 @@ ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = {{SVNSTAT}} #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- @@ -132,7 +134,7 @@ FILE_PATTERNS = *.c \ *.PY RECURSIVE = YES EXCLUDE = -EXCLUDE_SYMLINKS = NO +EXCLUDE_SYMLINKS = YES EXCLUDE_PATTERNS = LocalSettings.php AdminSettings.php EXAMPLE_PATH = EXAMPLE_PATTERNS = * diff --git a/maintenance/FiveUpgrade.inc b/maintenance/FiveUpgrade.inc index 9a882bc6..7ae8f5d0 100644 --- a/maintenance/FiveUpgrade.inc +++ b/maintenance/FiveUpgrade.inc @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup Maintenance + */ require_once( 'cleanupDupes.inc' ); require_once( 'userDupes.inc' ); @@ -9,6 +13,9 @@ define( 'MW_UPGRADE_ENCODE', true ); define( 'MW_UPGRADE_NULL', null ); define( 'MW_UPGRADE_CALLBACK', null ); // for self-documentation only +/** + * @ingroup Maintenance + */ class FiveUpgrade { function FiveUpgrade() { $this->conversionTables = $this->prepareWindows1252(); @@ -61,9 +68,10 @@ class FiveUpgrade { * @access private */ function &newConnection() { - global $wgDBadminuser, $wgDBadminpassword; + global $wgDBadminuser, $wgDBadminpassword, $wgDBtype; global $wgDBserver, $wgDBname; - $db = new Database( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname ); + $dbclass = 'Database' . ucfirst( $wgDBtype ) ; + $db = new $dbclass( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname ); return $db; } @@ -75,11 +83,15 @@ class FiveUpgrade { * @access private */ function &streamConnection() { + global $wgDBtype; + $timeout = 3600 * 24; $db =& $this->newConnection(); $db->bufferResults( false ); - $db->query( "SET net_read_timeout=$timeout" ); - $db->query( "SET net_write_timeout=$timeout" ); + if ($wgDBtype == 'mysql') { + $db->query( "SET net_read_timeout=$timeout" ); + $db->query( "SET net_write_timeout=$timeout" ); + } return $db; } @@ -702,7 +714,7 @@ END; 'major' => '', 'minor' => '' ); - $magic =& wfGetMimeMagic(); + $magic = MimeMagic::singleton(); $mime = $magic->guessMimeType( $filename, true ); list( $info['major'], $info['minor'] ) = explode( '/', $mime ); @@ -1165,5 +1177,3 @@ ENDS; } } - -?> diff --git a/maintenance/Makefile b/maintenance/Makefile index e84cfdf3..82476139 100644 --- a/maintenance/Makefile +++ b/maintenance/Makefile @@ -1,17 +1,10 @@ -mediawiki_version := $(shell php -r "include('commandLine.inc'); print SpecialVersion::getVersion();") - help: @echo "Run 'make test' to run the parser tests." - @echo "Run 'make doc' to run the phpdoc generation." - @echo "Run 'make doxydoc' (unsupported doxygen generation)." + @echo "Run 'make doc' to run the doxygen generation." test: php parserTests.php --quiet doc: - php mwdocgen.php -all - echo 'Doc generation done. Look at ./docs/html/' - -doxydoc: - cd .. && /bin/sed -e "s/MW_VERSION_PLACEHOLDER/$(mediawiki_version)/" maintenance/mwdoxygen.cfg | doxygen - - echo 'Doc generation done. Look at ./docs/html/' + php mwdocgen.php --all + @echo 'Doc generation done. Look at ./docs/html/' diff --git a/maintenance/README b/maintenance/README index 7ef358b8..e4c01b53 100644 --- a/maintenance/README +++ b/maintenance/README @@ -48,8 +48,11 @@ installations. dumpBackup.php Backup dump script - dumpHTML.php - Produce an HTML dump of a wiki + edit.php + Edit a page to change its content + + findhooks.php + Find hooks that aren't documented in docs/hooks.txt importDump.php XML dump importer @@ -60,6 +63,12 @@ installations. importTextFile.php Import the contents of a text file into a wiki page + moveBatch.php + Move a batch of pages + + namespaceDupes.php + Check articles name to see if they conflict with new/existing namespaces + nukePage.php Wipe a page and all revisions from the database @@ -84,5 +93,17 @@ installations. runJobs.php Immediately complete all jobs in the job queue + stats.php + Show all statistics stored in memcached + + undelete.php + Undelete all revisions of a page + update.php Check and upgrade the database schema to the current version + + updateRestrictions.php + Update pages restriction to the new schema + + userOptions.php + Change user options
\ No newline at end of file diff --git a/maintenance/addwiki.php b/maintenance/addwiki.php index a19b24ce..b9c48506 100644 --- a/maintenance/addwiki.php +++ b/maintenance/addwiki.php @@ -1,4 +1,11 @@ <?php +/** + * Add a new wiki + * Wikimedia specific! + * + * @file + * @ingroup Maintenance + */ $wgNoDBParam = true; @@ -6,7 +13,7 @@ require_once( "commandLine.inc" ); require_once( "rebuildInterwiki.inc" ); require_once( "languages/Names.php" ); if ( count( $args ) != 3 ) { - wfDie( "Usage: php addwiki.php <language> <site> <dbname>\n" ); + wfDie( "Usage: php addwiki.php <language> <site> <dbname>\nThe site for Wikipedia is 'wikipedia'.\n" ); } addWiki( $args[0], $args[1], $args[2] ); @@ -17,13 +24,17 @@ function addWiki( $lang, $site, $dbName ) { global $IP, $wgLanguageNames, $wgDefaultExternalStore; + if ( !isset( $wgLanguageNames[$lang] ) ) { + print "Language $lang not found in \$wgLanguageNames\n"; + return; + } $name = $wgLanguageNames[$lang]; - $dbw = wfGetDB( DB_WRITE ); + $dbw = wfGetDB( DB_MASTER ); $common = "/home/wikipedia/common"; $maintenance = "$IP/maintenance"; - print "Creating database $dbName for $lang.$site\n"; + print "Creating database $dbName for $lang.$site ($name)\n"; # Set up the database $dbw->query( "SET table_type=Innodb" ); @@ -33,8 +44,12 @@ function addWiki( $lang, $site, $dbName ) print "Initialising tables\n"; dbsource( "$maintenance/tables.sql", $dbw ); dbsource( "$IP/extensions/OAI/update_table.sql", $dbw ); - dbsource( "$IP/extensions/AntiSpoof/mysql/patch-antispoof.sql", $dbw ); + dbsource( "$IP/extensions/AntiSpoof/sql/patch-antispoof.mysql.sql", $dbw ); dbsource( "$IP/extensions/CheckUser/cu_changes.sql", $dbw ); + dbsource( "$IP/extensions/CheckUser/cu_log.sql", $dbw ); + dbsource( "$IP/extensions/TitleKey/titlekey.sql", $dbw ); + dbsource( "$IP/extensions/Oversight/hidden.sql", $dbw ); + $dbw->query( "INSERT INTO site_stats(ss_row_id) VALUES (1)" ); # Initialise external storage @@ -72,7 +87,8 @@ function addWiki( $lang, $site, $dbName ) } global $wgTitle, $wgArticle; - $wgTitle = Title::newMainPage(); + $wgTitle = Title::newFromText( wfMsgWeirdKey( "mainpage/$lang" ) ); + print "Writing main page to " . $wgTitle->getPrefixedDBkey() . "\n"; $wgArticle = new Article( $wgTitle ); $ucsite = ucfirst( $site ); @@ -218,32 +234,16 @@ EOT fclose( $file ); # Update the sublists - system("cd $common && ./refresh-dblist"); + shell_exec("cd $common && ./refresh-dblist"); - print "Constructing interwiki SQL\n"; + #print "Constructing interwiki SQL\n"; # Rebuild interwiki tables - $sql = getRebuildInterwikiSQL(); - $tempname = tempnam( '/tmp', 'addwiki' ); - $file = fopen( $tempname, 'w' ); - if ( !$file ) { - wfDie( "Error, unable to open temporary file $tempname\n" ); - } - fwrite( $file, $sql ); - fclose( $file ); - print "Sourcing interwiki SQL\n"; - dbsource( $tempname, $dbw ); - #unlink( $tempname ); - - # Create the upload dir - global $wgUploadDirectory; - if( file_exists( $wgUploadDirectory ) ) { - echo "$wgUploadDirectory already exists.\n"; - } else { - echo "Creating $wgUploadDirectory...\n"; - mkdir( $wgUploadDirectory, 0777 ); - chmod( $wgUploadDirectory, 0777 ); - } + #passthru( '/home/wikipedia/conf/interwiki/update' ); - print "Script ended. You now want to run sync-common-all to publish *dblist files (check them for duplicates first)\n"; + print "Script ended. You still have to: +* Add any required settings in InitialiseSettings.php +* Run sync-common-all +* Run /home/wikipedia/conf/interwiki/update +"; } diff --git a/maintenance/archives/patch-ar_parent_id.sql b/maintenance/archives/patch-ar_parent_id.sql new file mode 100644 index 00000000..b24cf46c --- /dev/null +++ b/maintenance/archives/patch-ar_parent_id.sql @@ -0,0 +1,3 @@ +-- Adding ar_deleted field for revisiondelete +ALTER TABLE /*$wgDBprefix*/archive + ADD ar_parent_id int unsigned default NULL; diff --git a/maintenance/archives/patch-category.sql b/maintenance/archives/patch-category.sql new file mode 100644 index 00000000..416500c3 --- /dev/null +++ b/maintenance/archives/patch-category.sql @@ -0,0 +1,17 @@ +CREATE TABLE /*$wgDBprefix*/category ( + cat_id int unsigned NOT NULL 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, + + cat_hidden tinyint(1) unsigned NOT NULL default 0, + + PRIMARY KEY (cat_id), + UNIQUE KEY (cat_title), + + KEY (cat_pages) +) /*$wgDBTableOptions*/; + diff --git a/maintenance/archives/patch-filearhive-user-index.sql b/maintenance/archives/patch-filearhive-user-index.sql new file mode 100644 index 00000000..c79000ad --- /dev/null +++ b/maintenance/archives/patch-filearhive-user-index.sql @@ -0,0 +1,5 @@ +-- Adding index to sort by uploader +ALTER TABLE /*$wgDBprefix*/filearchive + ADD INDEX fa_user_timestamp (fa_user_text,fa_timestamp), + -- Remove useless, incomplete index + DROP INDEX fa_deleted_user; diff --git a/maintenance/archives/patch-hitcounter.sql b/maintenance/archives/patch-hitcounter.sql index 260f717f..50e56e0c 100644 --- a/maintenance/archives/patch-hitcounter.sql +++ b/maintenance/archives/patch-hitcounter.sql @@ -6,4 +6,4 @@ CREATE TABLE /*$wgDBprefix*/hitcounter ( hc_id INTEGER UNSIGNED NOT NULL -) TYPE=HEAP MAX_ROWS=25000; +) ENGINE=HEAP MAX_ROWS=25000; diff --git a/maintenance/archives/patch-ipb_by_text.sql b/maintenance/archives/patch-ipb_by_text.sql new file mode 100644 index 00000000..c0b620d3 --- /dev/null +++ b/maintenance/archives/patch-ipb_by_text.sql @@ -0,0 +1,10 @@ +-- Adding colomn with username of blocker and sets it. +-- Required for crosswiki blocks. + +ALTER TABLE /*$wgDBprefix*/ipblocks + ADD ipb_by_text varchar(255) binary NOT NULL default ''; + +UPDATE /*$wgDBprefix*/ipblocks + JOIN /*$wgDBprefix*/user ON ipb_by = user_id + SET ipb_by_text = user_name + WHERE ipb_by != 0;
\ No newline at end of file diff --git a/maintenance/archives/patch-page_props.sql b/maintenance/archives/patch-page_props.sql new file mode 100644 index 00000000..15a35581 --- /dev/null +++ b/maintenance/archives/patch-page_props.sql @@ -0,0 +1,9 @@ +-- Name/value pairs indexed by page_id +CREATE TABLE /*$wgDBprefix*/page_props ( + pp_page int NOT NULL, + pp_propname varbinary(60) NOT NULL, + pp_value blob NOT NULL, + + PRIMARY KEY (pp_page,pp_propname) +) /*$wgDBTableOptions*/; + diff --git a/maintenance/archives/patch-profiling-memory.sql b/maintenance/archives/patch-profiling-memory.sql new file mode 100644 index 00000000..ddd851e1 --- /dev/null +++ b/maintenance/archives/patch-profiling-memory.sql @@ -0,0 +1,2 @@ +ALTER TABLE /*$wgDBprefix*/profiling + ADD pf_memory float NOT NULL default 0; diff --git a/maintenance/archives/patch-profiling.sql b/maintenance/archives/patch-profiling.sql index bafd2b67..e748ca31 100644 --- a/maintenance/archives/patch-profiling.sql +++ b/maintenance/archives/patch-profiling.sql @@ -4,7 +4,8 @@ CREATE TABLE /*$wgDBprefix*/profiling ( pf_count int NOT NULL default 0, pf_time float NOT NULL default 0, + pf_memory float NOT NULL default 0, pf_name varchar(255) NOT NULL default '', pf_server varchar(30) NOT NULL default '', UNIQUE KEY pf_name_server (pf_name, pf_server) -) TYPE=HEAP; +) ENGINE=HEAP; diff --git a/maintenance/archives/patch-protected_titles.sql b/maintenance/archives/patch-protected_titles.sql index 5307cbdd..20b6035d 100644 --- a/maintenance/archives/patch-protected_titles.sql +++ b/maintenance/archives/patch-protected_titles.sql @@ -1,7 +1,7 @@ -- Protected titles - nonexistent pages that have been protected CREATE TABLE /*$wgDBprefix*/protected_titles ( pt_namespace int NOT NULL, - pt_title varchar(255) NOT NULL, + pt_title varchar(255) binary NOT NULL, pt_user int unsigned NOT NULL, pt_reason tinyblob, pt_timestamp binary(14) NOT NULL, diff --git a/maintenance/archives/patch-pt_title-encoding.sql b/maintenance/archives/patch-pt_title-encoding.sql new file mode 100644 index 00000000..b0a23932 --- /dev/null +++ b/maintenance/archives/patch-pt_title-encoding.sql @@ -0,0 +1,5 @@ +-- pt_title was accidentally left with the wrong collation. +-- This might cause failures with JOINs, and could protect the wrong pages +-- with different case variants or unrelated UTF-8 chars. +ALTER TABLE /*$wgDBprefix*/protected_titles + CHANGE COLUMN pt_title pt_title varchar(255) binary NOT NULL; diff --git a/maintenance/archives/patch-searchindex.sql b/maintenance/archives/patch-searchindex.sql index 452c4548..9b635a8f 100644 --- a/maintenance/archives/patch-searchindex.sql +++ b/maintenance/archives/patch-searchindex.sql @@ -19,7 +19,7 @@ CREATE TABLE /*$wgDBprefix*/searchindex ( UNIQUE KEY (si_page) -) TYPE=MyISAM; +) ENGINE=MyISAM; -- Copying data into new table... INSERT INTO /*$wgDBprefix*/searchindex diff --git a/maintenance/archives/patch-updatelog.sql b/maintenance/archives/patch-updatelog.sql new file mode 100644 index 00000000..168ad082 --- /dev/null +++ b/maintenance/archives/patch-updatelog.sql @@ -0,0 +1,4 @@ +CREATE TABLE /*$wgDBprefix*/updatelog ( + ul_key varchar(255) NOT NULL, + PRIMARY KEY (ul_key) +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-user_last_timestamp.sql b/maintenance/archives/patch-user_last_timestamp.sql new file mode 100644 index 00000000..b6d5f0f3 --- /dev/null +++ b/maintenance/archives/patch-user_last_timestamp.sql @@ -0,0 +1,3 @@ +-- For getting diff since last view +ALTER TABLE /*$wgDBprefix*/user_newtalk + ADD user_last_timestamp binary(14) NOT NULL default ''; diff --git a/maintenance/archives/populateSha1.php b/maintenance/archives/populateSha1.php index 45f29c43..487d3bad 100644 --- a/maintenance/archives/populateSha1.php +++ b/maintenance/archives/populateSha1.php @@ -1,6 +1,10 @@ <?php - -# Optional upgrade script to populate the img_sha1 field +/** + * Optional upgrade script to populate the img_sha1 field + * + * @file + * @ingroup MaintenanceArchive + */ $optionsWithArgs = array( 'method' ); require_once( dirname(__FILE__).'/../commandLine.inc' ); diff --git a/maintenance/archives/rebuildRecentchanges.inc b/maintenance/archives/rebuildRecentchanges.inc index 1eaadc4d..65ba560c 100644 --- a/maintenance/archives/rebuildRecentchanges.inc +++ b/maintenance/archives/rebuildRecentchanges.inc @@ -2,8 +2,10 @@ /** * Rebuild recent changes table * + * @file * @deprecated - * @addtogroup MaintenanceArchive + * @ingroup MaintenanceArchive + * @defgroup MaintenanceArchive MaintenanceArchive */ /** */ @@ -30,7 +32,7 @@ function rebuildRecentChangesTable() INDEX rc_timestamp (rc_timestamp), INDEX rc_namespace (rc_namespace), INDEX rc_title (rc_title) -) TYPE=MyISAM PACK_KEYS=1;"; +) ENGINE=MyISAM PACK_KEYS=1;"; wfQuery( $sql ); print( "Loading from CUR table...\n" ); diff --git a/maintenance/archives/upgradeLogging.php b/maintenance/archives/upgradeLogging.php new file mode 100644 index 00000000..f79bbabc --- /dev/null +++ b/maintenance/archives/upgradeLogging.php @@ -0,0 +1,189 @@ +<?php +/** + * Replication-safe online upgrade script for log_id/log_deleted + * + * @file + * @ingroup MaintenanceArchive + */ + +require( dirname(__FILE__).'/../commandLine.inc' ); + +class UpdateLogging { + var $dbw; + var $batchSize = 1000; + var $minTs = false; + + function execute() { + $this->dbw = wfGetDB( DB_MASTER ); + $logging = $this->dbw->tableName( 'logging' ); + $logging_1_10 = $this->dbw->tableName( 'logging_1_10' ); + $logging_pre_1_10 = $this->dbw->tableName( 'logging_pre_1_10' ); + + if ( $this->dbw->tableExists( 'logging_pre_1_10' ) && !$this->dbw->tableExists( 'logging' ) ) { + # Fix previous aborted run + echo "Cleaning up from previous aborted run\n"; + $this->dbw->query( "RENAME TABLE $logging_pre_1_10 TO $logging", __METHOD__ ); + } + + if ( $this->dbw->tableExists( 'logging_pre_1_10' ) ) { + echo "This script has already been run to completion\n"; + return; + } + + # Create the target table + if ( !$this->dbw->tableExists( 'logging_1_10' ) ) { + global $wgDBTableOptions; + + $sql = <<<EOT +CREATE TABLE $logging_1_10 ( + -- Log ID, for referring to this specific log entry, probably for deletion and such. + log_id int unsigned NOT NULL auto_increment, + + -- Symbolic keys for the general log type and the action type + -- within the log. The output format will be controlled by the + -- 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, + + -- rev_deleted for logs + log_deleted tinyint unsigned NOT NULL default '0', + + PRIMARY KEY log_id (log_id), + KEY type_time (log_type, log_timestamp), + KEY user_time (log_user, log_timestamp), + KEY page_time (log_namespace, log_title, log_timestamp), + KEY times (log_timestamp) + +) $wgDBTableOptions +EOT; + echo "Creating table logging_1_10\n"; + $this->dbw->query( $sql, __METHOD__ ); + } + + # Synchronise the tables + echo "Doing initial sync...\n"; + $this->sync( 'logging', 'logging_1_10' ); + echo "Sync done\n\n"; + + # Rename the old table away + echo "Renaming the old table to $logging_pre_1_10\n"; + $this->dbw->query( "RENAME TABLE $logging TO $logging_pre_1_10", __METHOD__ ); + + # Copy remaining old rows + # Done before the new table is active so that $copyPos is accurate + echo "Doing final sync...\n"; + $this->sync( 'logging_pre_1_10', 'logging_1_10' ); + + # Move the new table in + echo "Moving the new table in...\n"; + $this->dbw->query( "RENAME TABLE $logging_1_10 TO $logging", __METHOD__ ); + echo "Finished.\n"; + } + + /** + * Copy all rows from $srcTable to $dstTable + */ + function sync( $srcTable, $dstTable ) { + $batchSize = 1000; + $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__ ); + $maxTsUnix = wfTimestamp( TS_UNIX, $maxTs ); + $copyPosUnix = wfTimestamp( TS_UNIX, $copyPos ); + + if ( $copyPos === null ) { + $percent = 0; + } else { + $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 ); + } + + # Now copy a batch of rows + if ( $copyPos === null ) { + $conds = false; + } else { + $conds = array( 'log_timestamp > ' . $this->dbw->addQuotes( $copyPos ) ); + } + $srcRes = $this->dbw->select( $srcTable, '*', $conds, __METHOD__, + array( 'LIMIT' => $batchSize, 'ORDER BY' => 'log_timestamp' ) ); + + if ( ! $srcRes->numRows() ) { + # All done + break; + } + + $batch = array(); + foreach ( $srcRes as $srcRow ) { + $batch[] = (array)$srcRow; + } + $this->dbw->insert( $dstTable, $batch, __METHOD__ ); + $numRowsCopied += count( $batch ); + + wfWaitForSlaves( 5 ); + } + echo "Copied $numRowsCopied rows\n"; + } + + function copyExactMatch( $srcTable, $dstTable, $copyPos ) { + $numRowsCopied = 0; + $srcRes = $this->dbw->select( $srcTable, '*', array( 'log_timestamp' => $copyPos ), __METHOD__ ); + $dstRes = $this->dbw->select( $dstTable, '*', array( 'log_timestamp' => $copyPos ), __METHOD__ ); + + if ( $srcRes->numRows() ) { + $srcRow = $srcRes->fetchObject(); + $srcFields = array_keys( (array)$srcRow ); + $srcRes->seek( 0 ); + $dstRowsSeen = array(); + + # Make a hashtable of rows that already exist in the destination + foreach ( $dstRes as $dstRow ) { + $reducedDstRow = array(); + foreach ( $srcFields as $field ) { + $reducedDstRow[$field] = $dstRow->$field; + } + $hash = md5( serialize( $reducedDstRow ) ); + $dstRowsSeen[$hash] = true; + } + + # Copy all the source rows that aren't already in the destination + foreach ( $srcRes as $srcRow ) { + $hash = md5( serialize( (array)$srcRow ) ); + if ( !isset( $dstRowsSeen[$hash] ) ) { + $this->dbw->insert( $dstTable, (array)$srcRow, __METHOD__ ); + $numRowsCopied++; + } + } + } + return $numRowsCopied; + } +} + +$ul = new UpdateLogging; +$ul->execute(); + diff --git a/maintenance/archives/upgradeWatchlist.php b/maintenance/archives/upgradeWatchlist.php index e62a39ad..9788aa56 100644 --- a/maintenance/archives/upgradeWatchlist.php +++ b/maintenance/archives/upgradeWatchlist.php @@ -1,7 +1,8 @@ <?php /** + * @file * @deprecated - * @addtogroup MaintenanceArchive + * @ingroup MaintenanceArchive */ /** */ @@ -29,7 +30,7 @@ $sql = "CREATE TABLE watchlist ( wl_user int(5) unsigned NOT NULL, wl_page int(8) unsigned NOT NULL, UNIQUE KEY (wl_user, wl_page) -) TYPE=MyISAM PACK_KEYS=1"; +) ENGINE=MyISAM PACK_KEYS=1"; wfQuery( $sql, DB_MASTER ); $lc = new LinkCache; diff --git a/maintenance/attachLatest.php b/maintenance/attachLatest.php index 22cd7372..8d680afa 100644 --- a/maintenance/attachLatest.php +++ b/maintenance/attachLatest.php @@ -21,7 +21,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ require_once( 'commandLine.inc' ); diff --git a/maintenance/attribute.php b/maintenance/attribute.php index 999c0117..63f19435 100644 --- a/maintenance/attribute.php +++ b/maintenance/attribute.php @@ -1,8 +1,10 @@ <?php /** * Script for re-attributing edits + * Use reassingEdits.php * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ /** */ diff --git a/maintenance/backup.inc b/maintenance/backup.inc index 94fb48c9..bf52c1f3 100644 --- a/maintenance/backup.inc +++ b/maintenance/backup.inc @@ -18,15 +18,22 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @addtogroup SpecialPage + * @file + * @ingroup Dump Maintenance */ +/** + * @ingroup Dump Maintenance + */ class DumpDBZip2Output extends DumpPipeOutput { function DumpDBZip2Output( $file ) { parent::DumpPipeOutput( "dbzip2", $file ); } } +/** + * @ingroup Dump Maintenance + */ class BackupDumper { var $reportingInterval = 100; var $reporting = true; @@ -40,6 +47,7 @@ class BackupDumper { var $endId = 0; var $sink = null; // Output filters var $stubText = false; // include rev_text_id instead of text; for 2-pass dump + var $dumpUploads = false; function BackupDumper( $args ) { $this->stderr = fopen( "php://stderr", "wt" ); @@ -177,6 +185,7 @@ class BackupDumper { $db = $this->backupDb(); $exporter = new WikiExporter( $db, $history, WikiExporter::STREAM, $text ); + $exporter->dumpUploads = $this->dumpUploads; $wrapper = new ExportProgressFilter( $this->sink, $this ); $exporter->setOutputSink( $wrapper ); @@ -293,5 +302,3 @@ class ExportProgressFilter extends DumpFilter { $this->progress->revCount(); } } - -?> diff --git a/maintenance/backupPrefetch.inc b/maintenance/backupPrefetch.inc index 413247d7..512af1c7 100644 --- a/maintenance/backupPrefetch.inc +++ b/maintenance/backupPrefetch.inc @@ -52,6 +52,7 @@ foreach( $xmlReaderConstants as $name ) { * recorded, so the previous dump is a reliable source * * Requires PHP 5 and the XMLReader PECL extension. + * @ingroup Maintenance */ class BaseDump { var $reader = null; @@ -199,5 +200,3 @@ class BaseDump { return null; } } - -?> diff --git a/maintenance/benchmarkPurge.php b/maintenance/benchmarkPurge.php index 0ceb8445..76302a01 100644 --- a/maintenance/benchmarkPurge.php +++ b/maintenance/benchmarkPurge.php @@ -1,7 +1,9 @@ <?php /** * Squid purge benchmark script - * @addtogroup Maintenance + * + * @file + * @ingroup Maintenance */ /** */ diff --git a/maintenance/changePassword.php b/maintenance/changePassword.php index d6121280..d4370376 100644 --- a/maintenance/changePassword.php +++ b/maintenance/changePassword.php @@ -2,7 +2,8 @@ /** * Change the password of a given user * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason @@ -25,6 +26,9 @@ if( in_array( '--help', $argv ) ) $cp = new ChangePassword( @$options['user'], @$options['password'] ); $cp->main(); +/** + * @ingroup Maintenance + */ class ChangePassword { var $dbw; var $user, $password; @@ -36,7 +40,7 @@ class ChangePassword { } $this->user = User::newFromName( $user ); - if ( !$this->user->getID() ) { + if ( !$this->user->getId() ) { die ( "No such user: $user\n" ); } @@ -48,16 +52,7 @@ class ChangePassword { function main() { $fname = 'ChangePassword::main'; - $this->dbw->update( 'user', - array( - 'user_password' => wfEncryptPassword( $this->user->getID(), $this->password ) - ), - array( - 'user_id' => $this->user->getID() - ), - $fname - ); + $this->user->setPassword( $this->password ); + $this->user->saveSettings(); } } - - diff --git a/maintenance/checkAutoLoader.php b/maintenance/checkAutoLoader.php new file mode 100644 index 00000000..c2909ef7 --- /dev/null +++ b/maintenance/checkAutoLoader.php @@ -0,0 +1,22 @@ +<?php +if ( php_sapi_name() != 'cli' ) exit; + +$IP = dirname(__FILE__) .'/..'; +require( "$IP/includes/AutoLoader.php" ); +$files = array_unique( AutoLoader::$localClasses ); + +foreach ( $files as $file ) { + $parseInfo = parsekit_compile_file( "$IP/$file" ); + $classes = array_keys( $parseInfo['class_table'] ); + foreach ( $classes as $class ) { + if ( !isset( AutoLoader::$localClasses[$class] ) ) { + //printf( "%-50s Unlisted, in %s\n", $class, $file ); + echo " '$class' => '$file',\n"; + } elseif ( AutoLoader::$localClasses[$class] !== $file ) { + echo "$class: Wrong file: found in $file, listed in " . AutoLoader::$localClasses[$class] . "\n"; + } + } + +} + + diff --git a/maintenance/checkUsernames.php b/maintenance/checkUsernames.php index 3441aeeb..77565b99 100644 --- a/maintenance/checkUsernames.php +++ b/maintenance/checkUsernames.php @@ -1,4 +1,12 @@ <?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 + * @file + * @ingroup Maintenance + */ + error_reporting(E_ALL ^ E_NOTICE); require_once 'commandLine.inc'; diff --git a/maintenance/cleanupCaps.php b/maintenance/cleanupCaps.php index 77a95ffa..e959d4b7 100644 --- a/maintenance/cleanupCaps.php +++ b/maintenance/cleanupCaps.php @@ -24,8 +24,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @author Brion Vibber <brion at pobox.com> - * @addtogroup maintenance + * @ingroup maintenance */ $options = array( 'dry-run' ); @@ -33,6 +34,9 @@ $options = array( 'dry-run' ); require_once( 'commandLine.inc' ); require_once( 'FiveUpgrade.inc' ); +/** + * @ingroup Maintenance + */ class CapsCleanup extends FiveUpgrade { function CapsCleanup( $dryrun = false, $namespace=0 ) { parent::FiveUpgrade(); @@ -152,5 +156,3 @@ $wgUser->setName( 'Conversion script' ); $ns = isset( $options['namespace'] ) ? $options['namespace'] : 0; $caps = new CapsCleanup( isset( $options['dry-run'] ), $ns ); $caps->cleanup(); - - diff --git a/maintenance/cleanupDupes.inc b/maintenance/cleanupDupes.inc index ce1ffc6e..bb408007 100644 --- a/maintenance/cleanupDupes.inc +++ b/maintenance/cleanupDupes.inc @@ -21,7 +21,8 @@ * If on the old non-unique indexes, check the cur table for duplicate * entries and remove them... * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ function fixDupes( $fixthem = false) { @@ -125,5 +126,3 @@ function checkDupes( $fixthem = false, $indexonly = false ) { } } } - -?> diff --git a/maintenance/cleanupImages.php b/maintenance/cleanupImages.php index d6ed5a7a..79ff54e8 100644 --- a/maintenance/cleanupImages.php +++ b/maintenance/cleanupImages.php @@ -24,13 +24,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @author Brion Vibber <brion at pobox.com> - * @addtogroup maintenance + * @ingroup Maintenance */ require_once( 'commandLine.inc' ); require_once( 'cleanupTable.inc' ); +/** + * @ingroup Maintenance + */ class ImageCleanup extends TableCleanup { function __construct( $dryrun = false ) { parent::__construct( 'image', $dryrun ); diff --git a/maintenance/cleanupSpam.php b/maintenance/cleanupSpam.php index 36d8b258..eb9bd914 100644 --- a/maintenance/cleanupSpam.php +++ b/maintenance/cleanupSpam.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup Maintenance + */ require_once( 'commandLine.inc' ); require_once( "$IP/includes/LinkFilter.php" ); @@ -58,7 +62,7 @@ $username = wfMsg( 'spambot_username' ); $fname = $username; $wgUser = User::newFromName( $username ); // Create the user if necessary -if ( !$wgUser->getID() ) { +if ( !$wgUser->getId() ) { $wgUser->addToDatabase(); } diff --git a/maintenance/cleanupTable.inc b/maintenance/cleanupTable.inc index cf33e8f0..26b0a0e2 100644 --- a/maintenance/cleanupTable.inc +++ b/maintenance/cleanupTable.inc @@ -2,6 +2,9 @@ require_once( 'FiveUpgrade.inc' ); +/** + * @ingroup Maintenance + */ abstract class TableCleanup extends FiveUpgrade { function __construct( $table, $dryrun = false ) { parent::__construct(); @@ -82,5 +85,3 @@ abstract class TableCleanup extends FiveUpgrade { abstract function processPage( $row ); } - -?> diff --git a/maintenance/cleanupTitles.php b/maintenance/cleanupTitles.php index 1f06b165..a6991829 100644 --- a/maintenance/cleanupTitles.php +++ b/maintenance/cleanupTitles.php @@ -24,13 +24,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @author Brion Vibber <brion at pobox.com> - * @addtogroup maintenance + * @ingroup Maintenance */ require_once( 'commandLine.inc' ); require_once( 'cleanupTable.inc' ); +/** + * @ingroup Maintenance + */ class TitleCleanup extends TableCleanup { function __construct( $dryrun = false ) { parent::__construct( 'page', $dryrun ); @@ -125,7 +129,7 @@ class TitleCleanup extends TableCleanup { ), array( 'page_id' => $row->page_id ), 'cleanupTitles::moveInconsistentPage' ); - $linkCache =& LinkCache::singleton(); + $linkCache = LinkCache::singleton(); $linkCache->clear(); } } diff --git a/maintenance/cleanupWatchlist.php b/maintenance/cleanupWatchlist.php index bcf05730..a6cedb2e 100644 --- a/maintenance/cleanupWatchlist.php +++ b/maintenance/cleanupWatchlist.php @@ -24,8 +24,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @author Brion Vibber <brion at pobox.com> - * @addtogroup maintenance + * @ingroup Maintenance */ $options = array( 'fix' ); @@ -33,6 +34,9 @@ $options = array( 'fix' ); require_once( 'commandLine.inc' ); require_once( 'FiveUpgrade.inc' ); +/** + * @ingroup Maintenance + */ class WatchlistCleanup extends FiveUpgrade { function WatchlistCleanup( $dryrun = false ) { parent::FiveUpgrade(); diff --git a/maintenance/clear_interwiki_cache.php b/maintenance/clear_interwiki_cache.php index af5d9b2f..ce154779 100644 --- a/maintenance/clear_interwiki_cache.php +++ b/maintenance/clear_interwiki_cache.php @@ -2,7 +2,9 @@ /** * This script is used to clear the interwiki links for ALL languages in * memcached. - * @addtogroup Maintenance + * + * @file + * @ingroup Maintenance */ /** */ diff --git a/maintenance/clear_stats.php b/maintenance/clear_stats.php index 5c1dce97..4cacd74c 100644 --- a/maintenance/clear_stats.php +++ b/maintenance/clear_stats.php @@ -1,4 +1,11 @@ <?php +/** + * This script remove all statistics tracking from memcached + * + * @file + * @ingroup Maintenance + */ + require_once('commandLine.inc'); foreach ( $wgLocalDatabases as $db ) { diff --git a/maintenance/commandLine.inc b/maintenance/commandLine.inc index f7bb53ff..a23bb6eb 100644 --- a/maintenance/commandLine.inc +++ b/maintenance/commandLine.inc @@ -1,7 +1,9 @@ <?php /** + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance + * @defgroup Maintenance Maintenance */ $wgRequestTime = microtime(true); @@ -35,9 +37,12 @@ if ( !isset( $optionsWithArgs ) ) { } $optionsWithArgs[] = 'conf'; # For specifying the location of LocalSettings.php $optionsWithArgs[] = 'aconf'; # As above for AdminSettings.php +$optionsWithArgs[] = 'wiki'; # For specifying the wiki ID $self = array_shift( $argv ); -$IP = realpath( dirname( __FILE__ ) . '/..' ); +$IP = ( getenv('MW_INSTALL_PATH') !== false + ? getenv('MW_INSTALL_PATH') + : realpath( dirname( __FILE__ ) . '/..' ) ); #chdir( $IP ); require_once( "$IP/StartProfiler.php" ); @@ -61,7 +66,7 @@ for( $arg = reset( $argv ); $arg !== false; $arg = next( $argv ) ) { if ( in_array( $option, $optionsWithArgs ) ) { $param = next( $argv ); if ( $param === false ) { - echo "$arg needs an value after it\n"; + echo "$arg needs a value after it\n"; die( -1 ); } $options[$option] = $param; @@ -82,7 +87,7 @@ for( $arg = reset( $argv ); $arg !== false; $arg = next( $argv ) ) { if ( in_array( $option, $optionsWithArgs ) ) { $param = next( $argv ); if ( $param === false ) { - echo "$arg needs an value after it\n"; + echo "$arg needs a value after it\n"; die( -1 ); } $options[$option] = $param; @@ -109,7 +114,9 @@ if (!isset( $wgUseNormalUser ) ) { if ( file_exists( '/home/wikipedia/common/langlist' ) ) { $wgWikiFarm = true; - $cluster = trim( file_get_contents( '/etc/cluster' ) ); + #$cluster = trim( file_get_contents( '/etc/cluster' ) ); + $cluster = 'pmtpa'; + require_once( "$IP/includes/AutoLoader.php" ); require_once( "$IP/includes/SiteConfiguration.php" ); # Get $wgConf @@ -117,7 +124,11 @@ if ( file_exists( '/home/wikipedia/common/langlist' ) ) { if ( empty( $wgNoDBParam ) ) { # Check if we were passed a db name - $db = array_shift( $args ); + if ( isset( $options['wiki'] ) ) { + $db = $options['wiki']; + } else { + $db = array_shift( $args ); + } list( $site, $lang ) = $wgConf->siteFromDB( $db ); # If not, work out the language and site the old way @@ -150,6 +161,10 @@ if ( file_exists( '/home/wikipedia/common/langlist' ) ) { $DP = $IP; ini_set( 'include_path', ".:$IP:$IP/includes:$IP/languages:$IP/maintenance" ); + if ( $lang == 'test' && $site == 'wikipedia' ) { + define( 'TESTWIKI', 1 ); + } + #require_once( $IP.'/includes/ProfilerStub.php' ); require_once( $IP.'/includes/Defines.php' ); require_once( $IP.'/CommonSettings.php' ); @@ -169,6 +184,14 @@ if ( file_exists( '/home/wikipedia/common/langlist' ) ) { } else { $settingsFile = "$IP/LocalSettings.php"; } + if ( isset( $options['wiki'] ) ) { + $bits = explode( '-', $options['wiki'] ); + if ( count( $bits ) == 1 ) { + $bits[] = ''; + } + define( 'MW_DB', $bits[0] ); + define( 'MW_PREFIX', $bits[1] ); + } if ( ! is_readable( $settingsFile ) ) { print "A copy of your installation's LocalSettings.php\n" . @@ -177,6 +200,7 @@ if ( file_exists( '/home/wikipedia/common/langlist' ) ) { } $wgCommandLineMode = true; $DP = $IP; + require_once( "$IP/includes/AutoLoader.php" ); #require_once( $IP.'/includes/ProfilerStub.php' ); require_once( $IP.'/includes/Defines.php' ); require_once( $settingsFile ); @@ -207,6 +231,10 @@ if ( empty( $wgUseNormalUser ) && isset( $wgDBadminuser ) ) { $wgDBservers[$i]['password'] = $wgDBpassword; } } + if( isset( $wgLBFactoryConf['serverTemplate'] ) ) { + $wgLBFactoryConf['serverTemplate']['user'] = $wgDBuser; + $wgLBFactoryConf['serverTemplate']['password'] = $wgDBpassword; + } } if ( defined( 'MW_CMDLINE_CALLBACK' ) ) { @@ -235,28 +263,4 @@ $wgShowSQLErrors = true; require_once( "$IP/includes/Setup.php" ); require_once( "$IP/install-utils.inc" ); $wgTitle = null; # Much much faster startup than creating a title object -set_time_limit(0); - -// -------------------------------------------------------------------- -// Functions -// -------------------------------------------------------------------- - -function wfWaitForSlaves( $maxLag ) { - global $wgLoadBalancer; - if ( $maxLag ) { - list( $host, $lag ) = $wgLoadBalancer->getMaxLag(); - while ( $lag > $maxLag ) { - $name = @gethostbyaddr( $host ); - if ( $name !== false ) { - $host = $name; - } - print "Waiting for $host (lagged $lag seconds)...\n"; - sleep($maxLag); - list( $host, $lag ) = $wgLoadBalancer->getMaxLag(); - } - } -} - - - -?> +@set_time_limit(0); diff --git a/maintenance/convertLinks.inc b/maintenance/convertLinks.inc index d0c57f78..e4deb22b 100644 --- a/maintenance/convertLinks.inc +++ b/maintenance/convertLinks.inc @@ -1,7 +1,8 @@ <?php /** + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** */ @@ -213,7 +214,3 @@ function getMicroTime() { # return time in seconds, with microsecond accuracy list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } - - - -?> diff --git a/maintenance/convertLinks.php b/maintenance/convertLinks.php index bc0aef49..e86d1e7c 100644 --- a/maintenance/convertLinks.php +++ b/maintenance/convertLinks.php @@ -3,7 +3,8 @@ * 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 * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ /** */ @@ -11,5 +12,3 @@ require_once( "commandLine.inc" ); require_once( "convertLinks.inc" ); convertLinks(); - - diff --git a/maintenance/counter.php b/maintenance/counter.php index 67b9ce21..67575ec1 100644 --- a/maintenance/counter.php +++ b/maintenance/counter.php @@ -1,4 +1,11 @@ <?php +/** + * Helper file for update.php + * + * @file + * @ingroup Maintenance + */ + function print_c($last, $current) { echo str_repeat( chr(8), strlen( $last ) ) . $current; } diff --git a/maintenance/createAndPromote.php b/maintenance/createAndPromote.php index 0d30fe73..a5a8f88d 100644 --- a/maintenance/createAndPromote.php +++ b/maintenance/createAndPromote.php @@ -3,7 +3,8 @@ /** * Maintenance script to create an account and grant it administrator rights * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/deleteArchivedFiles.inc b/maintenance/deleteArchivedFiles.inc index 32ddf4c8..da1c14d5 100644 --- a/maintenance/deleteArchivedFiles.inc +++ b/maintenance/deleteArchivedFiles.inc @@ -3,17 +3,18 @@ /** * Support functions for the deleteArchivedFiles script * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Aaron Schulz */ require_once( "$IP/includes/FileStore.php" ); +require_once( "$IP/includes/filerepo/File.php" ); function DeleteArchivedFiles( $delete = false ) { # Data should come off the master, wrapped in a transaction $dbw = wfGetDB( DB_MASTER ); - $dbw->begin(); $transaction = new FSTransaction(); if( !FileStore::lock() ) { @@ -32,25 +33,24 @@ function DeleteArchivedFiles( $delete = false ) { $id = $row->fa_id; $store = FileStore::get( $group ); - if ( $store ) { + if( $store ) { $path = $store->filePath( $key ); - if ( $path && file_exists($path) ) { + $sha1 = substr( $key, 0, strcspn( $key, '.' ) ); + $inuse = $dbw->selectField( 'oldimage', '1', + array( 'oi_sha1' => $sha1, + 'oi_deleted & '.File::DELETED_FILE => File::DELETED_FILE ), + __METHOD__, array( 'FOR UPDATE' ) ); + if ( $path && file_exists($path) && !$inuse ) { $transaction->addCommit( FSTransaction::DELETE_FILE, $path ); $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" ); } else { echo( "Notice - file '$key' not found in group '$group'\n" ); } } else { - echo( "Notice - invalid file storage group '$group'\n" ); + echo( "Notice - invalid file storage group '$group' for file '$key'\n" ); } } echo( "done.\n" ); $transaction->commit(); - - # This bit's done - $dbw->commit(); - } - -?>
\ No newline at end of file diff --git a/maintenance/deleteArchivedFiles.php b/maintenance/deleteArchivedFiles.php index a556c3b9..97dc5824 100644 --- a/maintenance/deleteArchivedFiles.php +++ b/maintenance/deleteArchivedFiles.php @@ -3,7 +3,8 @@ /** * Delete archived (non-current) files from the database * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Aaron Schulz * Based on deleteOldRevisions.php by Rob Church */ diff --git a/maintenance/deleteArchivedRevisions.inc b/maintenance/deleteArchivedRevisions.inc index f820ccb0..67e4c5a2 100644 --- a/maintenance/deleteArchivedRevisions.inc +++ b/maintenance/deleteArchivedRevisions.inc @@ -3,7 +3,8 @@ /** * Support functions for the deleteArchivedRevisions script * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Aaron Schulz */ @@ -31,5 +32,3 @@ function DeleteArchivedRevisions( $delete = false ) { } } - -?>
\ No newline at end of file diff --git a/maintenance/deleteArchivedRevisions.php b/maintenance/deleteArchivedRevisions.php index 53aec4c3..87eebfad 100644 --- a/maintenance/deleteArchivedRevisions.php +++ b/maintenance/deleteArchivedRevisions.php @@ -1,9 +1,10 @@ <?php /** - * Delete arcived (deleted from public) revisions from the database + * Delete archived (deleted from public) revisions from the database * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Aaron Schulz * Shamelessly stolen from deleteOldRevisions.php by Rob Church :) */ diff --git a/maintenance/deleteBatch.php b/maintenance/deleteBatch.php index 62169641..d10948a0 100644 --- a/maintenance/deleteBatch.php +++ b/maintenance/deleteBatch.php @@ -1,12 +1,17 @@ <?php -# delete 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 deleted. -# <user> is the username -# <reason> is the delete reason -# <interval> is the number of seconds to sleep for after each delete +/** + * 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 deleted. + * <user> is the username + * <reason> is the delete reason + * <interval> is the number of seconds to sleep for after each delete + * + * @file + * @ingroup Maintenance + */ $oldCwd = getcwd(); $optionsWithArgs = array( 'u', 'r', 'i' ); diff --git a/maintenance/deleteDefaultMessages.php b/maintenance/deleteDefaultMessages.php index 9a7f5c6a..77e85741 100644 --- a/maintenance/deleteDefaultMessages.php +++ b/maintenance/deleteDefaultMessages.php @@ -3,6 +3,9 @@ /** * Deletes all pages in the MediaWiki namespace which were last edited by * "MediaWiki default". + * + * @file + * @ingroup Maintenance */ if ( !defined( 'MEDIAWIKI' ) ) { diff --git a/maintenance/deleteImageMemcached.php b/maintenance/deleteImageMemcached.php index 7ec9953c..2c3afa86 100644 --- a/maintenance/deleteImageMemcached.php +++ b/maintenance/deleteImageMemcached.php @@ -1,9 +1,21 @@ <?php -// php deleteImageMemcached.php --until "2005-09-05 00:00:00" --sleep 0 --report 10 +/** + * This script delete image information from memcached. + * + * Usage example: + * php deleteImageMemcached.php --until "2005-09-05 00:00:00" --sleep 0 --report 10 + * + * @file + * @ingroup Maintenance + */ + $optionsWithArgs = array( 'until', 'sleep', 'report' ); require_once 'commandLine.inc'; +/** + * @ingroup Maintenance + */ class DeleteImageCache { var $until, $sleep, $report; diff --git a/maintenance/deleteOldRevisions.inc b/maintenance/deleteOldRevisions.inc index 03fb2306..b681b9d0 100644 --- a/maintenance/deleteOldRevisions.inc +++ b/maintenance/deleteOldRevisions.inc @@ -1,9 +1,9 @@ <?php - /** * Support functions for the deleteOldRevisions script * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -66,5 +66,3 @@ function DeleteOldRevisions( $delete = false, $args = array() ) { } } - -?>
\ No newline at end of file diff --git a/maintenance/deleteOldRevisions.php b/maintenance/deleteOldRevisions.php index 8454479b..c283c607 100644 --- a/maintenance/deleteOldRevisions.php +++ b/maintenance/deleteOldRevisions.php @@ -3,7 +3,8 @@ /** * Delete old (non-current) revisions from the database * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/deleteOrphanedRevisions.inc.php b/maintenance/deleteOrphanedRevisions.inc.php index 707eaf98..6678d5b8 100644 --- a/maintenance/deleteOrphanedRevisions.inc.php +++ b/maintenance/deleteOrphanedRevisions.inc.php @@ -3,7 +3,8 @@ /** * Support functions for the deleteOrphanedRevisions maintenance script * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/deleteOrphanedRevisions.php b/maintenance/deleteOrphanedRevisions.php index 0842018e..78441f8e 100644 --- a/maintenance/deleteOrphanedRevisions.php +++ b/maintenance/deleteOrphanedRevisions.php @@ -4,7 +4,8 @@ * Maintenance script to delete revisions which refer to a nonexisting page * Sometimes manual deletion done in a rush leaves crap in the database * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> * @todo More efficient cleanup of text records */ diff --git a/maintenance/deleteRevision.php b/maintenance/deleteRevision.php index 0876efc9..0c203ab0 100644 --- a/maintenance/deleteRevision.php +++ b/maintenance/deleteRevision.php @@ -1,4 +1,11 @@ <?php +/** + * Delete one or more revisions by moving them to the archive table. + * + * @file + * @ingroup Maintenance + */ + require_once( 'commandLine.inc' ); $dbw = wfGetDB( DB_MASTER ); diff --git a/maintenance/dumpBackup.php b/maintenance/dumpBackup.php index 9ec5674d..bb431242 100644 --- a/maintenance/dumpBackup.php +++ b/maintenance/dumpBackup.php @@ -18,7 +18,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @addtogroup SpecialPage + * @file + * @ingroup Dump Maintenance */ $originalDir = getcwd(); @@ -54,6 +55,7 @@ if( isset( $options['end'] ) ) { } $dumper->skipHeader = isset( $options['skip-header'] ); $dumper->skipFooter = isset( $options['skip-footer'] ); +$dumper->dumpUploads = isset( $options['uploads'] ); $textMode = isset( $options['stub'] ) ? WikiExporter::STUB : WikiExporter::TEXT; @@ -62,7 +64,7 @@ if( isset( $options['full'] ) ) { } elseif( isset( $options['current'] ) ) { $dumper->dump( WikiExporter::CURRENT, $textMode ); } else { - $dumper->progress( <<<END + $dumper->progress( <<<ENDS This script dumps the wiki page database into an XML interchange wrapper format for export or backup. @@ -83,6 +85,7 @@ Options: --skip-header Don't output the <mediawiki> header --skip-footer Don't output the </mediawiki> footer --stub Don't perform old_text lookups; for 2-pass dump + --uploads Include upload records (experimental) Fancy stuff: --plugin=<class>[:<file>] Load a dump plugin class @@ -90,7 +93,7 @@ Fancy stuff: <type>s: file, gzip, bzip2, 7zip --filter=<type>[:<options>] Add a filter on an output branch -END +ENDS ); } diff --git a/maintenance/dumpInterwiki.inc b/maintenance/dumpInterwiki.inc index 9af6ccc5..481e21cc 100644 --- a/maintenance/dumpInterwiki.inc +++ b/maintenance/dumpInterwiki.inc @@ -3,20 +3,19 @@ * Rebuild interwiki table using the file on meta and the language list * Wikimedia specific! * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ -/** */ - /** * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ class Site { var $suffix, $lateral, $url; - function Site( $s, $l, $u ) { + function __construct( $s, $l, $u ) { $this->suffix = $s; $this->lateral = $l; $this->url = $u; @@ -92,7 +91,7 @@ function getRebuildInterwikiDump() { } # Extract the intermap from meta - $intermap = wfGetHTTP( 'http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw', 30 ); + $intermap = Http::get( 'http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw', 30 ); $lines = array_map( 'trim', explode( "\n", trim( $intermap ) ) ); if ( !$lines || count( $lines ) < 2 ) { @@ -207,5 +206,3 @@ function makeLink( $entry, $source ) { print "{$source}:{$entry['iw_prefix']} {$entry['iw_url']} {$entry['iw_local']}\n"; } - -?> diff --git a/maintenance/dumpInterwiki.php b/maintenance/dumpInterwiki.php index 02116a53..91cdbe8a 100644 --- a/maintenance/dumpInterwiki.php +++ b/maintenance/dumpInterwiki.php @@ -2,8 +2,10 @@ /** * Rebuild interwiki table using the file on meta and the language list * Wikimedia specific! + * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** */ diff --git a/maintenance/dumpLinks.php b/maintenance/dumpLinks.php index f61c398b..65dfac64 100644 --- a/maintenance/dumpLinks.php +++ b/maintenance/dumpLinks.php @@ -26,7 +26,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @addtogroup SpecialPage + * @file + * @ingroup Mainatenance */ require_once 'commandLine.inc'; diff --git a/maintenance/dumpSisterSites.php b/maintenance/dumpSisterSites.php index 0c2fff46..2a7369c0 100644 --- a/maintenance/dumpSisterSites.php +++ b/maintenance/dumpSisterSites.php @@ -21,7 +21,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @addtogroup SpecialPage + * @file + * @ingroup SpecialPage */ require_once( 'commandLine.inc' ); diff --git a/maintenance/dumpTextPass.php b/maintenance/dumpTextPass.php index 440f6d27..eb4cc072 100644 --- a/maintenance/dumpTextPass.php +++ b/maintenance/dumpTextPass.php @@ -18,7 +18,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @addtogroup SpecialPage + * @file + * @ingroup Maintenance */ $originalDir = getcwd(); @@ -30,6 +31,8 @@ require_once( 'backup.inc' ); * Stream wrapper around 7za filter program. * Required since we can't pass an open file resource to XMLReader->open() * which is used for the text prefetch. + * + * @ingroup Maintenance */ class SevenZipStream { var $stream; @@ -93,7 +96,9 @@ class SevenZipStream { } stream_wrapper_register( 'mediawiki.compress.7z', 'SevenZipStream' ); - +/** + * @ingroup Maintenance + */ class TextPassDumper extends BackupDumper { var $prefetch = null; var $input = "php://stdin"; @@ -494,7 +499,7 @@ $dumper = new TextPassDumper( $argv ); if( true ) { $dumper->dump(); } else { - $dumper->progress( <<<END + $dumper->progress( <<<ENDS This script postprocesses XML dumps from dumpBackup.php to add page text which was stubbed out (using --stub). @@ -513,7 +518,7 @@ Options: --server=h Force reading from MySQL server h --current Base ETA on number of pages in database instead of all revisions --spawn Spawn a subprocess for loading text records -END +ENDS ); } diff --git a/maintenance/dumpUploads.php b/maintenance/dumpUploads.php index 50d03ae1..c237feee 100644 --- a/maintenance/dumpUploads.php +++ b/maintenance/dumpUploads.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup Maintenance + */ require_once 'commandLine.inc'; diff --git a/maintenance/edit.php b/maintenance/edit.php index 75b6c333..037f9a9a 100644 --- a/maintenance/edit.php +++ b/maintenance/edit.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup Maintenance + */ $optionsWithArgs = array( 'u', 's' ); diff --git a/maintenance/eval.php b/maintenance/eval.php index 519411df..a990a4d8 100644 --- a/maintenance/eval.php +++ b/maintenance/eval.php @@ -12,15 +12,11 @@ * To get decent line editing behavior, you should compile PHP with support * for GNU readline (pass --with-readline to configure). * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ -$wgForceLoadBalancing = (getenv('MW_BALANCE') ? true : false); -$wgUseNormalUser = (getenv('MW_WIKIUSER') ? true : false); -if (getenv('MW_PROFILING')) { - define('MW_CMDLINE_CALLBACK', 'wfSetProfiling'); -} -function wfSetProfiling() { $GLOBALS['wgProfiling'] = true; } +$wgUseNormalUser = (bool)getenv('MW_WIKIUSER'); $optionsWithArgs = array( 'd' ); @@ -33,8 +29,9 @@ if ( isset( $options['d'] ) ) { $wgDebugLogFile = '/dev/stdout'; } if ( $d > 1 ) { - foreach ( $wgLoadBalancer->mServers as $i => $server ) { - $wgLoadBalancer->mServers[$i]['flags'] |= DBO_DEBUG; + $lb = wfGetLB(); + foreach ( $lb->mServers as $i => $server ) { + $lb->mServers[$i]['flags'] |= DBO_DEBUG; } } if ( $d > 2 ) { @@ -42,8 +39,24 @@ if ( isset( $options['d'] ) ) { } } +if ( function_exists( 'readline_add_history' ) + && function_exists( 'posix_isatty' ) && posix_isatty( 0 /*STDIN*/ ) ) +{ + $useReadline = true; +} else { + $useReadline = false; +} + +if ( $useReadline ) { + $historyFile = "{$_ENV['HOME']}/.mweval_history"; + readline_read_history( $historyFile ); +} while ( ( $line = readconsole( '> ' ) ) !== false ) { + if ( $useReadline ) { + readline_add_history( $line ); + readline_write_history( $historyFile ); + } $val = eval( $line . ";" ); if( is_null( $val ) ) { echo "\n"; @@ -52,9 +65,6 @@ while ( ( $line = readconsole( '> ' ) ) !== false ) { } else { var_dump( $val ); } - if ( function_exists( "readline_add_history" ) ) { - readline_add_history( $line ); - } } print "\n"; diff --git a/maintenance/fetchText.php b/maintenance/fetchText.php index 3b745c0a..91b78be3 100644 --- a/maintenance/fetchText.php +++ b/maintenance/fetchText.php @@ -1,7 +1,9 @@ <?php - /** * Communications protocol... + * + * @file + * @ingroup Maintenance */ require "commandLine.inc"; @@ -10,6 +12,10 @@ $db = wfGetDB( DB_SLAVE ); $stdin = fopen( "php://stdin", "rt" ); while( !feof( $stdin ) ) { $line = fgets( $stdin ); + if( $line === false ) { + // We appear to have lost contact... + break; + } $textId = intval( $line ); $text = doGetText( $db, $textId ); echo strlen( $text ) . "\n"; @@ -31,6 +37,3 @@ function doGetText( $db, $id ) { } return $text; } - - -?>
\ No newline at end of file diff --git a/maintenance/findhooks.php b/maintenance/findhooks.php index 8433571d..7a2ba53f 100644 --- a/maintenance/findhooks.php +++ b/maintenance/findhooks.php @@ -7,37 +7,56 @@ * - hooks names in hooks.txt are at the beginning of a line and single quoted. * - hooks names in code are the first parameter of wfRunHooks. * + * if --online option is passed, the script will compare the hooks in the code + * with the ones at http://www.mediawiki.org/wiki/Manual:Hooks + * * Any instance of wfRunHooks that doesn't meet these parameters will be noted. * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * * @author Ashar Voultoiz <hashar@altern.org> * @copyright Copyright © Ashar voultoiz * @license http://www.gnu.org/copyleft/gpl.html GNU General Public Licence 2.0 or later */ - + /** This is a command line script*/ include('commandLine.inc'); - - + # GLOBALS - + $doc = $IP . '/docs/hooks.txt'; -$pathinc = array( $IP.'/includes/', $IP.'/includes/api/', $IP.'/includes/filerepo/', $IP.'/languages/', $IP.'/maintenance/', $IP.'/skins/' ); - +$pathinc = array( + $IP.'/', + $IP.'/includes/', + $IP.'/includes/api/', + $IP.'/includes/db/', + $IP.'/includes/filerepo/', + $IP.'/includes/parser/', + $IP.'/includes/specials/', + $IP.'/languages/', + $IP.'/maintenance/', + $IP.'/skins/', +); + # FUNCTIONS - + /** * @return array of documented hooks */ function getHooksFromDoc() { - global $doc; - $content = file_get_contents( $doc ); + global $doc, $options; $m = array(); - preg_match_all( "/\n'(.*?)'/", $content, $m); - return $m[1]; + if( isset( $options['online'] ) ){ + $content = Http::get( 'http://www.mediawiki.org/w/index.php?title=Manual:Hooks&action=raw' ); + preg_match_all( '/\[\[\/([a-zA-Z0-9-_:]+)\|/', $content, $m ); + } else { + $content = file_get_contents( $doc ); + preg_match_all( "/\n'(.*?)'/", $content, $m ); + } + return array_unique( $m[1] ); } - + /** * Get hooks from a PHP file * @param $file Full filename to the PHP file. @@ -49,7 +68,7 @@ function getHooksFromFile( $file ) { preg_match_all( '/wfRunHooks\(\s*([\'"])(.*?)\1/', $content, $m); return $m[2]; } - + /** * Get hooks from the source code. * @param $path Directory where the include files can be found @@ -67,7 +86,7 @@ function getHooksFromPath( $path ) { } return $hooks; } - + /** * Get bad hooks (where the hook name could not be determined) from a PHP file * @param $file Full filename to the PHP file. @@ -84,7 +103,7 @@ function getBadHooksFromFile( $file ) { } return $list; } - + /** * Get bad hooks from the source code. * @param $path Directory where the include files can be found @@ -103,7 +122,7 @@ function getBadHooksFromPath( $path ) { } return $hooks; } - + /** * Nicely output the array * @param $msg A message to show before the value @@ -114,10 +133,9 @@ function printArray( $msg, $arr, $sort = true ) { if($sort) asort($arr); foreach($arr as $v) echo "$msg: $v\n"; } - - + # MAIN - + $documented = getHooksFromDoc($doc); $potential = array(); $bad = array(); @@ -125,12 +143,12 @@ foreach( $pathinc as $dir ) { $potential = array_merge( $potential, getHooksFromPath( $dir ) ); $bad = array_merge( $bad, getBadHooksFromPath( $dir ) ); } - + $potential = array_unique( $potential ); $bad = array_unique( $bad ); $todo = array_diff( $potential, $documented ); $deprecated = array_diff( $documented, $potential ); - + // let's show the results: printArray('undocumented', $todo ); printArray('not found', $deprecated ); diff --git a/maintenance/fixSlaveDesync.php b/maintenance/fixSlaveDesync.php index daa5bbb4..7817bc56 100644 --- a/maintenance/fixSlaveDesync.php +++ b/maintenance/fixSlaveDesync.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup Maintenance + */ $wgUseRootUser = true; require_once( 'commandLine.inc' ); @@ -7,13 +11,13 @@ require_once( 'commandLine.inc' ); $slaveIndexes = array(); for ( $i = 1; $i < count( $wgDBservers ); $i++ ) { - if ( $wgLoadBalancer->isNonZeroLoad( $i ) ) { + if ( wfGetLB()->isNonZeroLoad( $i ) ) { $slaveIndexes[] = $i; } } /* -foreach ( $wgLoadBalancer->mServers as $i => $server ) { - $wgLoadBalancer->mServers[$i]['flags'] |= DBO_DEBUG; +foreach ( wfGetLB()->mServers as $i => $server ) { + wfGetLB()->mServers[$i]['flags'] |= DBO_DEBUG; }*/ $reportingInterval = 1000; diff --git a/maintenance/fixTimestamps.php b/maintenance/fixTimestamps.php index 39cdaae1..f6794141 100644 --- a/maintenance/fixTimestamps.php +++ b/maintenance/fixTimestamps.php @@ -1,11 +1,13 @@ <?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. + * + * @file + * @ingroup Maintenance */ require_once( 'commandLine.inc' ); diff --git a/maintenance/fixUserRegistration.php b/maintenance/fixUserRegistration.php index b342a86d..eb5b7f7d 100644 --- a/maintenance/fixUserRegistration.php +++ b/maintenance/fixUserRegistration.php @@ -2,6 +2,9 @@ /** * Fix the user_registration field. * In particular, for values which are NULL, set them to the date of the first edit + * + * @file + * @ingroup Maintenance */ require_once( 'commandLine.inc' ); diff --git a/maintenance/fuzz-tester.php b/maintenance/fuzz-tester.php index af12d6a1..1ca496ae 100644 --- a/maintenance/fuzz-tester.php +++ b/maintenance/fuzz-tester.php @@ -1,6 +1,7 @@ <?php /** -* @addtogroup Maintenance +* @file +* @ingroup Maintenance * @author Nick Jenkins ( http://nickj.org/ ). * @copyright 2006 Nick Jenkins * @licence GNU General Public Licence 2.0 @@ -1318,7 +1319,7 @@ class viewPageTest extends pageTest { "li", "lo", "lt", "lv", "mk", "ml", "ms", "nah", "nap", "nds", "nds-nl", "nl", "nn", "no", "non", "nv", "oc", "or", "os", "pa", "pl", "pms", "ps", "pt", "pt-br", "qu", "rmy", "ro", "ru", "sc", - "sd", "sk", "sl", "sq", "sr", "sr-ec", "sr-el", "sr-jc", "sr-jl", + "sd", "sk", "sl", "sq", "sr", "sr-ec", "sr-el", "su", "sv", "ta", "te", "th", "tlh", "tr", "tt", "ty", "tyv", "udm", "ug", "uk", "ur", "utf8", "vec", "vi", "wa", "xal", "yi", "za", "zh", "zh-cn", "zh-hk", "zh-sg", "zh-tw", "zh-tw") ), diff --git a/maintenance/generateSitemap.php b/maintenance/generateSitemap.php index 657437bc..cc3f523a 100644 --- a/maintenance/generateSitemap.php +++ b/maintenance/generateSitemap.php @@ -2,16 +2,16 @@ define( 'GS_MAIN', -2 ); define( 'GS_TALK', -1 ); /** - * Creates a Google sitemap for the site + * Creates a sitemap for the site * - * @addtogroup Maintenance + * @ingroup Maintenance * * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason * @copyright Copyright © 2005, Jens Frank <jeluf@gmx.de> * @copyright Copyright © 2005, Brion Vibber <brion@pobox.com> * - * @see http://www.google.com/webmasters/sitemaps/docs/en/about.html - * @see http://www.google.com/schemas/sitemap/0.84/sitemap.xsd + * @see http://www.sitemaps.org/ + * @see http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd * * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later */ @@ -20,7 +20,7 @@ class GenerateSitemap { /** * The maximum amount of urls in a sitemap file * - * @link http://www.google.com/schemas/sitemap/0.84/sitemap.xsd + * @link http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd * * @var int */ @@ -29,7 +29,7 @@ class GenerateSitemap { /** * The maximum size of a sitemap file * - * @link http://www.google.com/webmasters/sitemaps/docs/en/protocol.html#faq_sitemap_size + * @link http://www.sitemaps.org/faq.php#faq_sitemap_size * * @var int */ @@ -148,22 +148,47 @@ class GenerateSitemap { $this->url_limit = 50000; $this->size_limit = pow( 2, 20 ) * 10; - $this->fspath = isset( $fspath ) ? $fspath : ''; + $this->fspath = self::init_path( $fspath ); + $this->compress = $compress; $this->stderr = fopen( 'php://stderr', 'wt' ); $this->dbr = wfGetDB( DB_SLAVE ); $this->generateNamespaces(); $this->timestamp = wfTimestamp( TS_ISO_8601, wfTimestampNow() ); + + $this->findex = fopen( "{$this->fspath}sitemap-index-" . wfWikiID() . ".xml", 'wb' ); } /** + * Create directory if it does not exist and return pathname with a trailing slash + */ + private static function init_path( $fspath ) { + if( !isset( $fspath ) ) { + return null; + } + # Create directory if needed + if( $fspath && !is_dir( $fspath ) ) { + mkdir( $fspath, 0755 ) or die("Can not create directory $fspath.\n"); + } + + return realpath( $fspath ). DIRECTORY_SEPARATOR ; + } + + /** * Generate a one-dimensional array of existing namespaces */ function generateNamespaces() { $fname = 'GenerateSitemap::generateNamespaces'; + // Only generate for specific namespaces if $wgSitemapNamespaces is an array. + global $wgSitemapNamespaces; + if( is_array( $wgSitemapNamespaces ) ) { + $this->namespaces = $wgSitemapNamespaces; + return; + } + $res = $this->dbr->select( 'page', array( 'page_namespace' ), array(), @@ -200,7 +225,7 @@ class GenerateSitemap { * @return string */ function guessPriority( $namespace ) { - return Namespace::isMain( $namespace ) ? $this->priorities[GS_MAIN] : $this->priorities[GS_TALK]; + return MWNamespace::isMain( $namespace ) ? $this->priorities[GS_MAIN] : $this->priorities[GS_TALK]; } /** @@ -253,7 +278,7 @@ class GenerateSitemap { $this->file = $this->open( $this->fspath . $filename, 'wb' ); $this->write( $this->file, $this->openFile() ); fwrite( $this->findex, $this->indexEntry( $filename ) ); - $this->debug( "\t$filename" ); + $this->debug( "\t$this->fspath$filename" ); $length = $this->limit[0]; $i = 1; } @@ -345,7 +370,7 @@ class GenerateSitemap { * @returns string */ function xmlSchema() { - return 'http://www.google.com/schemas/sitemap/0.84'; + return 'http://www.sitemaps.org/schemas/sitemap/0.9'; } /** @@ -450,7 +475,7 @@ if ( in_array( '--help', $argv ) ) { Usage: php generateSitemap.php [options] --help show this message - --fspath=<path> The file system path to save to, e.g /tmp/sitemap/ + --fspath=<path> The file system path to save to, e.g /tmp/sitemap --server=<server> The protocol and server name to use in URLs, e.g. http://en.wikipedia.org. This is sometimes necessary because diff --git a/maintenance/getLagTimes.php b/maintenance/getLagTimes.php index d3934592..0f750caf 100644 --- a/maintenance/getLagTimes.php +++ b/maintenance/getLagTimes.php @@ -1,14 +1,20 @@ <?php +/** + * @file + * @ingroup Maintenance + */ require 'commandLine.inc'; -if( empty( $wgDBservers ) ) { +$lb = wfGetLB(); + +if( $lb->getServerCount() == 1 ) { echo "This script dumps replication lag times, but you don't seem to have\n"; echo "a multi-host db server configuration.\n"; } else { - $lags = $wgLoadBalancer->getLagTimes(); + $lags = $lb->getLagTimes(); foreach( $lags as $n => $lag ) { - $host = $wgDBservers[$n]["host"]; + $host = $lb->getServerName( $n ); if( IP::isValid( $host ) ) { $ip = $host; $host = gethostbyaddr( $host ); diff --git a/maintenance/getSlaveServer.php b/maintenance/getSlaveServer.php index 9aca1043..25258267 100644 --- a/maintenance/getSlaveServer.php +++ b/maintenance/getSlaveServer.php @@ -1,13 +1,26 @@ <?php +/** + * This script reports the hostname of a slave server. + * + * @file + * @ingroup Maintenance + */ require_once( dirname(__FILE__).'/commandLine.inc' ); +if ( $wgAllDBsAreLocalhost ) { + # Can't fool the backup script + print "localhost\n"; + exit; +} + if( isset( $options['group'] ) ) { $db = wfGetDB( DB_SLAVE, $options['group'] ); - $host = $db->getProperty( 'mServer' ); + $host = $db->getServer(); } else { - $i = $wgLoadBalancer->getReaderIndex(); - $host = $wgDBservers[$i]['host']; + $lb = wfGetLB(); + $i = $lb->getReaderIndex(); + $host = $lb->getServerName( $i ); } print "$host\n"; diff --git a/maintenance/importDump.php b/maintenance/importDump.php index 211d0a9e..99e69ce8 100644 --- a/maintenance/importDump.php +++ b/maintenance/importDump.php @@ -18,19 +18,25 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ $optionsWithArgs = array( 'report' ); require_once( 'commandLine.inc' ); +/** + * @ingroup Maintenance + */ class BackupReader { var $reportingInterval = 100; var $reporting = true; var $pageCount = 0; var $revCount = 0; var $dryRun = false; + var $debug = false; + var $uploads = false; function BackupReader() { $this->stderr = fopen( "php://stderr", "wt" ); @@ -57,6 +63,21 @@ class BackupReader { call_user_func( $this->importCallback, $rev ); } } + + function handleUpload( $revision ) { + if( $this->uploads ) { + $this->uploadCount++; + //$this->report(); + $this->progress( "upload: " . $revision->getFilename() ); + + if( !$this->dryRun ) { + // bluuuh hack + //call_user_func( $this->uploadCallback, $revision ); + $dbw = wfGetDB( DB_MASTER ); + return $dbw->deadlockLoop( array( $revision, 'importUpload' ) ); + } + } + } function report( $final = false ) { if( $final xor ( $this->pageCount % $this->reportingInterval == 0 ) ) { @@ -76,6 +97,7 @@ class BackupReader { } $this->progress( "$this->pageCount ($rate pages/sec $revrate revs/sec)" ); } + wfWaitForSlaves(5); } function progress( $string ) { @@ -101,9 +123,12 @@ class BackupReader { $source = new ImportStreamSource( $handle ); $importer = new WikiImporter( $source ); + $importer->setDebug( $this->debug ); $importer->setPageCallback( array( &$this, 'reportPage' ) ); $this->importCallback = $importer->setRevisionCallback( array( &$this, 'handleRevision' ) ); + $this->uploadCallback = $importer->setUploadCallback( + array( &$this, 'handleUpload' ) ); return $importer->doImport(); } @@ -123,6 +148,12 @@ if( isset( $options['report'] ) ) { if( isset( $options['dry-run'] ) ) { $reader->dryRun = true; } +if( isset( $options['debug'] ) ) { + $reader->debug = true; +} +if( isset( $options['uploads'] ) ) { + $reader->uploads = true; // experimental! +} if( isset( $args[0] ) ) { $result = $reader->importFromFile( $args[0] ); diff --git a/maintenance/importImages.inc.php b/maintenance/importImages.inc.php index 9a68bac0..53895778 100644 --- a/maintenance/importImages.inc.php +++ b/maintenance/importImages.inc.php @@ -3,7 +3,8 @@ /** * Support functions for the importImages script * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/importImages.php b/maintenance/importImages.php index 660d831c..63bbec5f 100644 --- a/maintenance/importImages.php +++ b/maintenance/importImages.php @@ -4,7 +4,8 @@ * Maintenance script to import one or more images from the local file system into * the wiki without using the web-based interface * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/importLogs.inc b/maintenance/importLogs.inc index 0dc87eab..a008e6c7 100644 --- a/maintenance/importLogs.inc +++ b/maintenance/importLogs.inc @@ -22,8 +22,9 @@ * * Not yet complete. * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** */ @@ -35,7 +36,7 @@ require_once( 'LogPage.php' ); /** * Log importer * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ class LogImporter { var $dummy = false; @@ -141,5 +142,3 @@ function wfUnescapeWikiText( $text ) { $text ); return $text; } - -?> diff --git a/maintenance/importLogs.php b/maintenance/importLogs.php index 199a7f0c..059c2f17 100644 --- a/maintenance/importLogs.php +++ b/maintenance/importLogs.php @@ -1,7 +1,8 @@ <?php /** * @todo document - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ /** */ diff --git a/maintenance/importTextFile.php b/maintenance/importTextFile.php index 676acbdb..5004c3c0 100644 --- a/maintenance/importTextFile.php +++ b/maintenance/importTextFile.php @@ -4,7 +4,8 @@ * Maintenance script allows creating or editing pages using * the contents of a text file * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/importUseModWiki.php b/maintenance/importUseModWiki.php index 4febc497..05a4c78c 100644 --- a/maintenance/importUseModWiki.php +++ b/maintenance/importUseModWiki.php @@ -22,7 +22,8 @@ * 2005-03-14 * * @todo document - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ if( php_sapi_name() != 'cli' ) { diff --git a/maintenance/initEditCount.php b/maintenance/initEditCount.php index 5a4367d0..d26349bb 100644 --- a/maintenance/initEditCount.php +++ b/maintenance/initEditCount.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup Maintenance + */ require_once "commandLine.inc"; diff --git a/maintenance/initStats.inc b/maintenance/initStats.inc index 673742e3..d098bc36 100644 --- a/maintenance/initStats.inc +++ b/maintenance/initStats.inc @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup Maintenance + */ function wfInitStats( $options=array() ) { $dbr = wfGetDB( DB_SLAVE ); @@ -51,5 +55,3 @@ function wfInitStats( $options=array() ) { echo( "done.\n" ); } - -?>
\ No newline at end of file diff --git a/maintenance/initStats.php b/maintenance/initStats.php index 05377481..d206c202 100644 --- a/maintenance/initStats.php +++ b/maintenance/initStats.php @@ -3,7 +3,8 @@ /** * Maintenance script to re-initialise or update the site statistics table * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Brion Vibber * @author Rob Church <robchur@gmail.com> * @licence GNU General Public Licence 2.0 or later diff --git a/maintenance/installExtension.php b/maintenance/installExtension.php index 549c4a68..d5c4f4be 100644 --- a/maintenance/installExtension.php +++ b/maintenance/installExtension.php @@ -17,7 +17,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ $optionsWithArgs = array( 'target', 'repository', 'repos' ); @@ -28,6 +29,9 @@ define('EXTINST_NOPATCH', 0); define('EXTINST_WRITEPATCH', 6); define('EXTINST_HOTPATCH', 10); +/** + * @ingroup Maintenance + */ class InstallerRepository { var $path; @@ -43,7 +47,7 @@ class InstallerRepository { trigger_error( 'override InstallerRepository::getResource()', E_USER_ERROR ); } - /*static*/ function makeRepository( $path, $type = NULL ) { + static function makeRepository( $path, $type = NULL ) { if ( !$type ) { $m = array(); preg_match( '!(([-+\w]+)://)?.*?(\.[-\w\d.]+)?$!', $path, $m ); @@ -64,6 +68,9 @@ class InstallerRepository { } } +/** + * @ingroup Maintenance + */ class LocalInstallerRepository extends InstallerRepository { function LocalInstallerRepository ( $path ) { @@ -101,6 +108,9 @@ class LocalInstallerRepository extends InstallerRepository { } } +/** + * @ingroup Maintenance + */ class WebInstallerRepository extends InstallerRepository { function WebInstallerRepository ( $path ) { @@ -144,6 +154,9 @@ class WebInstallerRepository extends InstallerRepository { } } +/** + * @ingroup Maintenance + */ class SVNInstallerRepository extends InstallerRepository { function SVNInstallerRepository ( $path ) { @@ -176,6 +189,9 @@ class SVNInstallerRepository extends InstallerRepository { } } +/** + * @ingroup Maintenance + */ class InstallerResource { var $path; var $isdir; @@ -243,6 +259,9 @@ class InstallerResource { } } +/** + * @ingroup Maintenance + */ class LocalInstallerResource extends InstallerResource { function LocalInstallerResource( $path ) { InstallerResource::InstallerResource( $path, is_dir( $path ), true ); @@ -255,6 +274,9 @@ class LocalInstallerResource extends InstallerResource { } +/** + * @ingroup Maintenance + */ class WebInstallerResource extends InstallerResource { function WebInstallerResource( $path ) { InstallerResource::InstallerResource( $path, false, false ); @@ -278,6 +300,9 @@ class WebInstallerResource extends InstallerResource { } } +/** + * @ingroup Maintenance + */ class SVNInstallerResource extends InstallerResource { function SVNInstallerResource( $path ) { InstallerResource::InstallerResource( $path, true, false ); @@ -297,6 +322,9 @@ class SVNInstallerResource extends InstallerResource { } } +/** + * @ingroup Maintenance + */ class ExtensionInstaller { var $source; var $target; @@ -319,15 +347,15 @@ class ExtensionInstaller { #TODO: allow a config file different from "LocalSettings.php" } - function note( $msg ) { + static function note( $msg ) { print "$msg\n"; } - function warn( $msg ) { + static function warn( $msg ) { print "WARNING: $msg\n"; } - function error( $msg ) { + static function error( $msg ) { print "ERROR: $msg\n"; } @@ -470,18 +498,18 @@ class ExtensionInstaller { #TODO: allow custom installer scripts + sql patches if ( !file_exists( $f ) ) { - $this->warn( "No install.settings file provided!" ); + self::warn( "No install.settings file provided!" ); $this->tasks[] = "Please read the instructions and edit LocalSettings.php manually to activate the extension."; return '?'; } else { - $this->note( "applying settings patch..." ); + self::note( "applying settings patch..." ); } $settings = file_get_contents( $f ); if ( !$settings ) { - $this->error( "failed to read settings from $f!" ); + self::error( "failed to read settings from $f!" ); return false; } @@ -489,7 +517,7 @@ class ExtensionInstaller { if ( $mode == EXTINST_NOPATCH ) { $this->tasks[] = "Please put the following into your LocalSettings.php:" . "\n$settings\n"; - $this->note( "Skipping patch phase, automatic patching is off." ); + self::note( "Skipping patch phase, automatic patching is off." ); return true; } @@ -500,18 +528,18 @@ class ExtensionInstaller { $ok = copy( $t, $bak ); if ( !$ok ) { - $this->warn( "failed to create backup of LocalSettings.php!" ); + self::warn( "failed to create backup of LocalSettings.php!" ); return false; } else { - $this->note( "created backup of LocalSettings.php at $bak" ); + self::note( "created backup of LocalSettings.php at $bak" ); } } $localsettings = file_get_contents( $t ); if ( !$settings ) { - $this->error( "failed to read $t for patching!" ); + self::error( "failed to read $t for patching!" ); return false; } @@ -534,14 +562,14 @@ class ExtensionInstaller { $ok = file_put_contents( $t, $localsettings ); if ( !$ok ) { - $this->error( "failed to patch $t!" ); + self::error( "failed to patch $t!" ); return false; } else if ( $mode == EXTINST_HOTPATCH ) { - $this->note( "successfully patched $t" ); + self::note( "successfully patched $t" ); } else { - $this->note( "created patched settings file $t" ); + self::note( "created patched settings file $t" ); $this->tasks[] = "Replace your current LocalSettings.php with ".basename($t); } diff --git a/maintenance/interwiki.sql b/maintenance/interwiki.sql index ed71c067..c8e088f5 100644 --- a/maintenance/interwiki.sql +++ b/maintenance/interwiki.sql @@ -2,152 +2,87 @@ -- Default interwiki prefixes... REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES -('abbenormal','http://www.ourpla.net/cgi-bin/pikie.cgi?$1',0), ('acronym','http://www.acronymfinder.com/af-query.asp?String=exact&Acronym=$1',0), ('advogato','http://www.advogato.org/$1',0), -('aiwiki','http://www.ifi.unizh.ch/ailab/aiwiki/aiw.cgi?$1',0), ('annotationwiki','http://www.seedwiki.com/page.cfm?wikiid=368&doc=$1',0), ('arxiv','http://www.arxiv.org/abs/$1',0), -('bemi','http://bemi.free.fr/vikio/index.php?$1',0), ('c2find','http://c2.com/cgi/wiki?FindPage&value=$1',0), ('cache','http://www.google.com/search?q=cache:$1',0), -('cliki','http://ww.telent.net/cliki/$1',0), -('cmwiki','http://www.ourpla.net/cgi-bin/wiki.pl?$1',0), -('codersbase','http://www.codersbase.com/index.php/$1',0), +('codersbase','http://www.codersbase.com/index.php/$1',0), # 2008-02-27: Fatal error ('commons','http://commons.wikimedia.org/wiki/$1',0), -('consciousness','http://teadvus.inspiral.org/',0), ('corpknowpedia','http://corpknowpedia.org/wiki/index.php/$1',0), -('creationmatters','http://www.ourpla.net/cgi-bin/wiki.pl?$1',0), -('dejanews','http://www.deja.com/=dnc/getdoc.xp?AN=$1',0), ('dictionary','http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=$1',0), ('disinfopedia','http://www.disinfopedia.org/wiki.phtml?title=$1',0), -('diveintoosx','http://diveintoosx.org/$1',0), ('docbook','http://wiki.docbook.org/topic/$1',0), -('dolphinwiki','http://www.object-arts.com/wiki/html/Dolphin/$1',0), ('drumcorpswiki','http://www.drumcorpswiki.com/index.php/$1',0), ('dwjwiki','http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1',0), -('eĉei','http://www.ikso.net/cgi-bin/wiki.pl?$1',0), -('echei','http://www.ikso.net/cgi-bin/wiki.pl?$1',0), -('ecxei','http://www.ikso.net/cgi-bin/wiki.pl?$1',0), -('efnetceewiki','http://purl.net/wiki/c/$1',0), -('efnetcppwiki','http://purl.net/wiki/cpp/$1',0), -('efnetpythonwiki','http://purl.net/wiki/python/$1',0), -('efnetxmlwiki','http://purl.net/wiki/xml/$1',0), -('eljwiki','http://elj.sourceforge.net/phpwiki/index.php/$1',0), +('efnetceewiki','http://purl.net/wiki/c/$1',0), # 2008-02-27: does not appear to be working +('efnetcppwiki','http://purl.net/wiki/cpp/$1',0), # 2008-02-27: does not appear to be working +('efnetpythonwiki','http://purl.net/wiki/python/$1',0), # 2008-02-27: does not appear to be working +('efnetxmlwiki','http://purl.net/wiki/xml/$1',0), # 2008-02-27: does not appear to be working +('eljwiki','http://elj.sourceforge.net/phpwiki/index.php/$1',0), # 2008-02-27: Fatal PhpWiki Error ('emacswiki','http://www.emacswiki.org/cgi-bin/wiki.pl?$1',0), ('elibre','http://enciclopedia.us.es/index.php/$1',0), -('eokulturcentro','http://esperanto.toulouse.free.fr/wakka.php?wiki=$1',0), -('evowiki','http://www.evowiki.org/index.php/$1',0), -('finalempire','http://final-empire.sourceforge.net/cgi-bin/wiki.pl?$1',0), -('firstwiki','http://firstwiki.org/index.php/$1',0), -('foldoc','http://www.foldoc.org/foldoc/foldoc.cgi?$1',0), +('eokulturcentro','http://esperanto.toulouse.free.fr/wakka.php?wiki=$1',0), # 2007-02-27: no access to database +('foldoc','http://foldoc.org/?$1',0), ('foxwiki','http://fox.wikis.com/wc.dll?Wiki~$1',0), -('fr.be','http://fr.wikinations.be/$1',0), -('fr.ca','http://fr.ca.wikinations.org/$1',0), -('fr.fr','http://fr.fr.wikinations.org/$1',0), -('fr.org','http://fr.wikinations.org/$1',0), ('freebsdman','http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1',0), -('gamewiki','http://gamewiki.org/wiki/index.php/$1',0), ('gej','http://www.esperanto.de/cgi-bin/aktivikio/wiki.pl?$1',0), ('gentoo-wiki','http://gentoo-wiki.com/$1',0), -('globalvoices','http://cyber.law.harvard.edu/dyn/globalvoices/wiki/$1',0), -('gmailwiki','http://www.gmailwiki.com/index.php/$1',0), ('google','http://www.google.com/search?q=$1',0), ('googlegroups','http://groups.google.com/groups?q=$1',0), -('gotamac','http://www.got-a-mac.org/$1',0), -('greencheese','http://www.greencheese.org/$1',0), -('hammondwiki','http://www.dairiki.org/HammondWiki/index.php3?$1',0), -('haribeau','http://wiki.haribeau.de/cgi-bin/wiki.pl?$1',0), +('gotamac','http://www.got-a-mac.org/$1',0), # 2008-02-27: appears ill maintained; loads of spambots +('hammondwiki','http://www.dairiki.org/HammondWiki/$1',0), ('hewikisource','http://he.wikisource.org/wiki/$1',1), -('herzkinderwiki','http://www.herzkinderinfo.de/Mediawiki/index.php/$1',0), ('hrwiki','http://www.hrwiki.org/index.php/$1',0), -('iawiki','http://www.IAwiki.net/$1',0), ('imdb','http://us.imdb.com/Title?$1',0), -('infosecpedia','http://www.infosecpedia.org/pedia/index.php/$1',0), +('infosecpedia','http://www.infosecpedia.org/pedia/index.php/$1',0), # 2008-02-27: lot of spambot activity ('jargonfile','http://sunir.org/apps/meta.pl?wiki=JargonFile&redirect=$1',0), -('jefo','http://www.esperanto-jeunes.org/vikio/index.php?$1',0), -('jiniwiki','http://www.cdegroot.com/cgi-bin/jini?$1',0), -('jspwiki','http://www.ecyrd.com/JSPWiki/Wiki.jsp?page=$1',0), +('jspwiki','http://www.jspwiki.org/wiki/$1',0), ('keiki','http://kei.ki/en/$1',0), -('kerimwiki','http://wiki.oxus.net/$1',0), -('kmwiki','http://www.voght.com/cgi-bin/pywiki?$1',0), -('knowhow','http://www2.iro.umontreal.ca/~paquetse/cgi-bin/wiki.cgi?$1',0), -('lanifexwiki','http://opt.lanifex.com/cgi-bin/wiki.pl?$1',0), -('lasvegaswiki','http://wiki.gmnow.com/index.php/$1',0), -('linuxwiki','http://www.linuxwiki.de/$1',0), +('kmwiki','http://kmwiki.wikispaces.com/$1',0), +('linuxwiki','http://linuxwiki.de/$1',0), ('lojban','http://www.lojban.org/tiki/tiki-index.php?page=$1',0), ('lqwiki','http://wiki.linuxquestions.org/wiki/$1',0), ('lugkr','http://lug-kr.sourceforge.net/cgi-bin/lugwiki.pl?$1',0), -('lutherwiki','http://www.lutheranarchives.com/mw/index.php/$1',0), ('mathsongswiki','http://SeedWiki.com/page.cfm?wikiid=237&doc=$1',0), -('mbtest','http://www.usemod.com/cgi-bin/mbtest.pl?$1',0), ('meatball','http://www.usemod.com/cgi-bin/mb.pl?$1',0), ('mediazilla','http://bugzilla.wikipedia.org/$1',1), ('mediawikiwiki','http://www.mediawiki.org/wiki/$1',0), ('memoryalpha','http://www.memory-alpha.org/en/index.php/$1',0), -('metaweb','http://www.metaweb.com/wiki/wiki.phtml?title=$1',0), ('metawiki','http://sunir.org/apps/meta.pl?$1',0), ('metawikipedia','http://meta.wikimedia.org/wiki/$1',0), ('moinmoin','http://purl.net/wiki/moin/$1',0), ('mozillawiki','http://wiki.mozilla.org/index.php/$1',0), -('muweb','http://www.dunstable.com/scripts/MuWebWeb?$1',0), -('netvillage','http://www.netbros.com/?$1',0), ('oeis','http://www.research.att.com/cgi-bin/access.cgi/as/njas/sequences/eisA.cgi?Anum=$1',0), ('openfacts','http://openfacts.berlios.de/index.phtml?title=$1',0), ('openwiki','http://openwiki.com/?$1',0), -('opera7wiki','http://nontroppo.org/wiki/$1',0), -('orgpatterns','http://www.bell-labs.com/cgi-user/OrgPatterns/OrgPatterns?$1',0), -('osi reference model','http://wiki.tigma.ee/',0), -('pangalacticorg','http://www.pangalactic.org/Wiki/$1',0), -('personaltelco','http://www.personaltelco.net/index.cgi/$1',0), -('patwiki','http://gauss.ffii.org/$1',0), -('phpwiki','http://phpwiki.sourceforge.net/phpwiki/index.php?$1',0), -('pikie','http://pikie.darktech.org/cgi/pikie?$1',0), +('orgpatterns','http://www.bell-labs.com/cgi-user/OrgPatterns/OrgPatterns?$1',0), # 2008-02-27: may not be working. Please double check +('patwiki','http://gauss.ffii.org/$1',0), # 2008-02-27: lots of spambots ('pmeg','http://www.bertilow.com/pmeg/$1.php',0), ('ppr','http://c2.com/cgi/wiki?$1',0), -('purlnet','http://purl.oclc.org/NET/$1',0), -('pythoninfo','http://www.python.org/cgi-bin/moinmoin/$1',0), -('pythonwiki','http://www.pythonwiki.de/$1',0), -('pywiki','http://www.voght.com/cgi-bin/pywiki?$1',0), -('raec','http://www.raec.clacso.edu.ar:8080/raec/Members/raecpedia/$1',0), -('revo','http://purl.org/NET/voko/revo/art/$1.html',0), +('pythoninfo','http://wiki.python.org/moin/$1',0), ('rfc','http://www.rfc-editor.org/rfc/rfc$1.txt',0), ('s23wiki','http://is-root.de/wiki/index.php/$1',0), -('scoutpedia','http://www.scoutpedia.info/index.php/$1',0), -('seapig','http://www.seapig.org/$1',0), -('seattlewiki','http://seattlewiki.org/wiki/$1',0), +('seattlewiki','http://seattle.wikia.com/wiki/$1',0), ('seattlewireless','http://seattlewireless.net/?$1',0), -('seeds','http://www.IslandSeeds.org/wiki/$1',0), ('senseislibrary','http://senseis.xmp.net/?$1',0), -('shakti','http://cgi.algonet.se/htbin/cgiwrap/pgd/ShaktiWiki/$1',0), -('slashdot','http://slashdot.org/article.pl?sid=$1',0), -('smikipedia','http://www.smikipedia.org/$1',0), -('sockwiki','http://wiki.socklabs.com/$1',0), +('slashdot','http://slashdot.org/article.pl?sid=$1',0), # 2008-02-27: update me ('sourceforge','http://sourceforge.net/$1',0), -('squeak','http://minnow.cc.gatech.edu/squeak/$1',0), -('strikiwiki','http://ch.twi.tudelft.nl/~mostert/striki/teststriki.pl?$1',0), +('squeak','http://wiki.squeak.org/squeak/$1',0), ('susning','http://www.susning.nu/$1',0), -('svgwiki','http://www.protocol7.com/svg-wiki/default.asp?$1',0), +('svgwiki','http://wiki.svg.org/$1',0), ('tavi','http://tavi.sourceforge.net/$1',0), ('tejo','http://www.tejo.org/vikio/$1',0), -('terrorwiki','http://www.liberalsagainstterrorism.com/wiki/index.php/$1',0), -('tmbw','http://www.tmbw.net/wiki/index.php/$1',0), +('tmbw','http://www.tmbw.net/wiki/$1',0), ('tmnet','http://www.technomanifestos.net/?$1',0), ('tmwiki','http://www.EasyTopicMaps.com/?page=$1',0), -('turismo','http://www.tejo.org/turismo/$1',0), ('theopedia','http://www.theopedia.com/$1',0), ('twiki','http://twiki.org/cgi-bin/view/$1',0), -('twistedwiki','http://purl.net/wiki/twisted/$1',0), ('uea','http://www.tejo.org/uea/$1',0), ('unreal','http://wiki.beyondunreal.com/wiki/$1',0), -('ursine','http://wiki.ursine.ca/$1',0), -('usej','http://www.tejo.org/usej/$1',0), ('usemod','http://www.usemod.com/cgi-bin/wiki.pl?$1',0), ('vinismo','http://vinismo.com/en/$1',0), -('visualworks','http://wiki.cs.uiuc.edu/VisualWorks/$1',0), -('warpedview','http://www.warpedview.com/index.php/$1',0), -('webdevwikinl','http://www.promo-it.nl/WebDevWiki/index.php?page=$1',0), -('webisodes','http://www.webisodes.org/$1',0), ('webseitzwiki','http://webseitz.fluxent.com/wiki/$1',0), ('why','http://clublet.com/c/c/why?$1',0), ('wiki','http://c2.com/cgi/wiki?$1',0), @@ -163,13 +98,9 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('wikisource','http://sources.wikipedia.org/wiki/$1',1), ('wikispecies','http://species.wikipedia.org/wiki/$1',1), ('wikitravel','http://wikitravel.org/en/$1',0), -('wikiworld','http://WikiWorld.com/wiki/index.php/$1',0), ('wiktionary','http://en.wiktionary.org/wiki/$1',1), ('wikipedia', 'http://en.wikipedia.org/wiki/$1', 1), ('wlug','http://www.wlug.org.nz/$1',0), -('wlwiki','http://winslowslair.supremepixels.net/wiki/index.php/$1',0), -('ypsieyeball','http://sknkwrks.dyndns.org:1957/writewiki/wiki.pl?$1',0), -('zwiki','http://www.zwiki.org/$1',0), -('zzz wiki','http://wiki.zzz.ee/',0), +('zwiki','http://zwiki.org/$1',0), +('zzz wiki','http://wiki.zzz.ee/index.php/$1',0), ('wikt','http://en.wiktionary.org/wiki/$1',1); - diff --git a/maintenance/language/StatOutputs.php b/maintenance/language/StatOutputs.php index 50829cbe..f65b263e 100644 --- a/maintenance/language/StatOutputs.php +++ b/maintenance/language/StatOutputs.php @@ -3,6 +3,8 @@ if (!defined('MEDIAWIKI')) die(); /** * Statistic output classes. * + * @file + * @ingroup MaintenanceLanguage * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> * @author Ashar Voultoiz <thoane@altern.org> */ diff --git a/maintenance/language/alltrans.php b/maintenance/language/alltrans.php index 4adc2a66..67c870e6 100644 --- a/maintenance/language/alltrans.php +++ b/maintenance/language/alltrans.php @@ -1,6 +1,7 @@ <?php /** - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage * * Get all the translations messages, as defined in the English language file. */ diff --git a/maintenance/language/checkExtensions.php b/maintenance/language/checkExtensions.php index 1cfb0de8..ab6f9ba8 100644 --- a/maintenance/language/checkExtensions.php +++ b/maintenance/language/checkExtensions.php @@ -1,269 +1,25 @@ <?php /** - * Copyright (C) 2007 Ashar Voultoiz <hashar@altern.org> + * Check the extensions language files. * - * Based on dumpBackup: - * 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 - * - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage */ -# -# Lacking documentation. Examples: -# php checkExtensions.php /opt/mw/extensions/CentralAuth/CentralAuth.i18n.php wgCentralAuthMessages -# php checkExtensions.php --extdir /opt/mw/extensions/ -# -# BUGS: cant guess registered extensions :) -# TODO: let users set parameters to configure checklanguage.inc - -// Filename for the extension i18n files database: -define( 'EXT_I18N_DB', 'i18n.db' ); - -$optionsWithArgs = array( 'extdir', 'lang' ); - require_once( dirname(__FILE__).'/../commandLine.inc' ); require_once( 'languages.inc' ); require_once( 'checkLanguage.inc' ); - -class extensionLanguages extends languages { - private $mExt18nFilename, $mExtArrayName ; - private $mExtArray; - - function __construct( $ext18nFilename, $extArrayName ) { - $this->mExt18nFilename = $ext18nFilename; - $this->mExtArrayName = $extArrayName; - - $this->mIgnoredMessages = array(); - $this->mOptionalMessages = array(); - - if ( file_exists( $this->mExt18nFilename ) ) { - require_once( $this->mExt18nFilename ); - - $foundarray = false; - if( isset( ${$this->mExtArrayName} ) ) { - // File provided in the db file - $foundarray = ${$this->mExtArrayName}; - } else { - - /* For extensions included elsewhere. For some reason other extensions - * break with the global statement, so recheck here. - */ - global ${$this->mExtArrayName}; - if( is_array( ${$this->mExtArrayName} ) ) { - $foundarray = ${$this->mExtArrayName}; - } - - /* we might have been given a function name, test it too */ - if( function_exists( $this->mExtArrayName ) ) { - // Load data - $funcName = $this->mExtArrayName ; - $foundarray = $funcName(); - } - - if(!$foundarray) { - // Provided array could not be found we try to guess it. - - # Using the extension path ($m[1]) and filename ($m[2]): - $m = array(); - preg_match( '%.*/(.*)/(.*).i18n\.php%', $this->mExt18nFilename, $m); - $arPathCandidate = 'wg' . $m[1].'Messages'; - $arFileCandidate = 'wg' . $m[2].'Messages'; - $funcCandidate = "ef{$m[2]}Messages"; - - // Try them: - if( isset($$arPathCandidate) && is_array( $$arPathCandidate ) ) { - print "warning> messages from guessed path array \$$arPathCandidate.\n"; - $foundarray = $$arPathCandidate; - } elseif( isset($$arFileCandidate) && is_array( $$arFileCandidate ) ) { - print "warning> messages from guessed file array \$$arFileCandidate.\n"; - $foundarray = $$arFileCandidate; - } elseif( function_exists( $funcCandidate ) ) { - print "warning> messages build from guessed function {$funcCandidate}().\n"; - $foundarray = $funcCandidate(); - } - } - - # We are unlucky, return empty stuff - if(!$foundarray) { - print "ERROR> failed to guess an array to use.\n"; - $this->mExtArray = null; - $this->mLanguages = null; - return; - } - } - - $this->mExtArray = $foundarray ; - $this->mLanguages = array_keys( $this->mExtArray ); - } else { - wfDie( "File $this->mExt18nFilename not found\n" ); - } - } - - protected function loadRawMessages( $code ) { - if ( isset( $this->mRawMessages[$code] ) ) { - return; - } - if( isset( $this->mExtArray[$code] ) ) { - $this->mRawMessages[$code] = $this->mExtArray[$code] ; - } else { - $this->mRawMessages[$code] = array(); - } - } - - public function getLanguages() { - return $this->mLanguages; - } -} - -/** - * @param $filename Filename containing the extension i18n - * @param $arrayname The name of the array in the filename - * @param $filter Optional, restrict check to a given language code (default; null) - */ -function checkExtensionLanguage( $filename, $arrayname, $filter = null ) { - $extLanguages = new extensionLanguages($filename, $arrayname); - - $langs = $extLanguages->getLanguages(); - if( !$langs ) { - print "ERROR> \$$arrayname array does not exist.\n"; - return false; - } - - $nErrors = 0; - if( $filter ) { - $nErrors += checkLanguage( $extLanguages, $filter ); - } else { - print "Will check ". count($langs) . " languages : " . implode(' ', $langs) .".\n"; - foreach( $langs as $lang ) { - if( $lang == 'en' ) { - #print "Skipped english language\n"; - continue; - } - - $nErrors += checkLanguage( $extLanguages, $lang ); - } - } - - return $nErrors; -} - -/** - * Read the db file, parse it, start the check. - */ -function checkExtensionRepository( $extdir, $db ) { - $fh = fopen( $extdir. '/' . $db, 'r' ); - - $line_number = 0; - while( $line = fgets( $fh ) ) { - $line_number++; - - // Ignore comments - if( preg_match( '/^#/', $line ) ) { - continue; - } - - // Load data from i18n database - $data = split( ' ', chop($line) ); - $i18n_file = @$data[0]; - $arrayname = @$data[1]; - - print "------------------------------------------------------\n"; - print "Checking $i18n_file (\$$arrayname).\n"; - - // Check data - if( !file_exists( $extdir . '/' . $i18n_file ) ) { - print "ERROR> $i18n_file not found ($db:$line_number).\n"; - continue; - } -# if( $arrayname == '' ) { -# print "warning> no array name for $i18n_file ($db:$line_number).\n"; -# } - - $i18n_file = $extdir . '/' . $i18n_file ; - - global $myLang; - $nErrors = checkExtensionLanguage( $i18n_file, $arrayname, $myLang ); - if($nErrors == 1 ) { - print "\nFound $nErrors error for this extension.\n"; - } elseif($nErrors) { - print "\nFound $nErrors errors for this extension.\n"; - } else { - print "Looks OK.\n"; - } - - print "\n"; - } -} - - -function usage() { -// Usage -print <<<END -Usage: - php checkExtensions.php <filename> <arrayname> - php checkExtensions.php --extdir <extension repository> - -Common option: - --lang <language code> : only check the given language. - +if( !class_exists( 'MessageGroups' ) || !class_exists( 'PremadeMediawikiExtensionGroups' ) ) { + echo <<<END +Please add the Translate extension to LocalSettings.php, and enable the extension groups: + require_once( 'extensions/Translate/Translate.php' ); + \$wgTranslateEC = array_keys( \$wgTranslateAC ); +If you still get this message, update Translate to its latest version. END; -die; -} - -// Play with options and arguments -$myLang = isset($options['lang']) ? $options['lang'] : null; - -if( isset( $options['extdir'] ) ) { - $extdb = $options['extdir'] . '/' . EXT_I18N_DB ; - - if( file_exists( $extdb ) ) { - checkExtensionRepository( $options['extdir'], EXT_I18N_DB ); - } else { - print "$extdb does not exist\n"; - } - -} else { - // Check arguments - if ( isset( $argv[0] ) ) { - - if (file_exists( $argv[0] ) ) { - $filename = $argv[0]; - } else { - print "Unable to open file '{$argv[0]}'\n"; - usage(); - } - - if ( isset( $argv[1] ) ) { - $arrayname = $argv[1]; - } else { - print "You must give an array name to be checked\n"; - usage(); - } - - global $myLang; - checkExtensionLanguage( $filename, $arrayname, $myLang ); - } else { - usage(); - } + exit(-1); } - +$cli = new CheckExtensionsCLI( $options, $argv[0] ); +$cli->execute(); diff --git a/maintenance/language/checkLanguage.inc b/maintenance/language/checkLanguage.inc index 51de8014..2cfd1b04 100644 --- a/maintenance/language/checkLanguage.inc +++ b/maintenance/language/checkLanguage.inc @@ -1,15 +1,491 @@ <?php +/** + * @ingroup MaintenanceLanguage + */ + +class CheckLanguageCLI { + protected $code = null; + protected $level = 2; + protected $doLinks = false; + protected $wikiCode = 'en'; + protected $checkAll = false; + protected $output = 'plain'; + protected $checks = array(); + protected $L = null; + + protected $defaultChecks = array( + 'untranslated', 'obsolete', 'variables', 'empty', 'plural', + 'whitespace', 'xhtml', 'chars', 'links', 'unbalanced' + ); + + protected $results = array(); + + private $includeExif = false; + + /** + * GLOBALS: $wgLanguageCode; + */ + public function __construct( Array $options ) { + + if ( isset( $options['help'] ) ) { + echo $this->help(); + exit(); + } + + if ( isset($options['lang']) ) { + $this->code = $options['lang']; + } else { + global $wgLanguageCode; + $this->code = $wgLanguageCode; + } + + if ( isset($options['level']) ) { + $this->level = $options['level']; + } + + $this->doLinks = isset($options['links']); + $this->includeExif = !isset($options['noexif']); + $this->checkAll = isset($options['all']); + + if ( isset($options['wikilang']) ) { + $this->wikiCode = $options['wikilang']; + } + + if ( isset( $options['whitelist'] ) ) { + $this->checks = explode( ',', $options['whitelist'] ); + } elseif ( isset( $options['blacklist'] ) ) { + $this->checks = array_diff( + $this->defaultChecks, + explode( ',', $options['blacklist'] ) + ); + } else { + $this->checks = $this->defaultChecks; + } + + if ( isset($options['output']) ) { + $this->output = $options['output']; + } + + # Some additional checks not enabled by default + if ( isset( $options['duplicate'] ) ) { + $this->checks[] = 'duplicate'; + } + + $this->L = new languages( $this->includeExif ); + } + + protected function getChecks() { + $checks = array(); + $checks['untranslated'] = 'getUntranslatedMessages'; + $checks['duplicate'] = 'getDuplicateMessages'; + $checks['obsolete'] = 'getObsoleteMessages'; + $checks['variables'] = 'getMessagesWithoutVariables'; + $checks['plural'] = 'getMessagesWithoutPlural'; + $checks['empty'] = 'getEmptyMessages'; + $checks['whitespace'] = 'getMessagesWithWhitespace'; + $checks['xhtml'] = 'getNonXHTMLMessages'; + $checks['chars'] = 'getMessagesWithWrongChars'; + $checks['links'] = 'getMessagesWithDubiousLinks'; + $checks['unbalanced'] = 'getMessagesWithUnbalanced'; + return $checks; + } + + protected function getDescriptions() { + $descriptions = array(); + $descriptions['untranslated'] = '$1 message(s) of $2 are not translated to $3, but exist in en:'; + $descriptions['duplicate'] = '$1 message(s) of $2 are translated the same in en and $3:'; + $descriptions['obsolete'] = '$1 message(s) of $2 do not exist in en or are in the ignore list, but are in $3'; + $descriptions['variables'] = '$1 message(s) of $2 in $3 don\'t use some variables that en uses:'; + $descriptions['plural'] = '$1 message(s) of $2 in $3 don\'t use {{plural}} while en uses:'; + $descriptions['empty'] = '$1 message(s) of $2 in $3 are empty or -:'; + $descriptions['whitespace'] = '$1 message(s) of $2 in $3 have trailing whitespace:'; + $descriptions['xhtml'] = '$1 message(s) of $2 in $3 contain illegal XHTML:'; + $descriptions['chars'] = '$1 message(s) of $2 in $3 include hidden chars which should not be used in the messages:'; + $descriptions['links'] = '$1 message(s) of $2 in $3 have problematic link(s):'; + $descriptions['unbalanced'] = '$1 message(s) of $2 in $3 have unbalanced {[]}:'; + return $descriptions; + } + + protected function help() { + return <<<ENDS +Run this script to check a specific language file, or all of them. +Command line settings are in form --parameter[=value]. +Parameters: + * lang: Language code (default: the installation default language). + * all: Check all customized languages. + * help: Show this help. + * level: Show the following level (default: 2). + * links: Link the message values (default off). + * wikilang: For the links, what is the content language of the wiki to display the output in (default en). + * whitelist: Do only the following checks (form: code,code). + * blacklist: Don't do the following checks (form: code,code). + * duplicate: Additionally check for messages which are translated the same to English (default off). + * noexif: Don't 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). +Check codes (ideally, all of them should result 0; all the checks are executed by default (except duplicate and 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, but translated. + * variables: Messages without variables which should be used. + * empty: Empty messages. + * whitespace: Messages which have trailing whitespace. + * xhtml: Messages which are not well-formed XHTML (checks only few common errors). + * chars: Messages with hidden characters. + * links: Messages which contains broken links to pages (does not find all). + * unbalanced: Messages which contains unequal numbers of opening {[ and closing ]}. +Display levels (default: 2): + * 0: Skip the checks (useful for checking syntax). + * 1: Show only the stub headers and number of wrong messages, without list of messages. + * 2: Show only the headers and the message keys, without the message values. + * 3: Show both the headers and the complete messages, with both keys and values. + +ENDS; + } + + public function execute() { + $this->doChecks(); + if ( $this->level > 0 ) { + switch ($this->output) { + case 'plain': + $this->outputText(); + break; + case 'wiki': + $this->outputWiki(); + break; + default: + throw new MWException( "Invalid output type $this->output"); + } + } + } + + protected function doChecks() { + $ignoredCodes = array( 'en', 'enRTL' ); + + $this->results = array(); + # Check the language + if ( $this->checkAll ) { + foreach ( $this->L->getLanguages() as $language ) { + if ( !in_array($language, $ignoredCodes) ) { + $this->results[$language] = $this->checkLanguage( $language ); + } + } + } else { + if ( in_array($this->code, $ignoredCodes) ) { + throw new MWException("Cannot check code $this->code."); + } else { + $this->results[$this->code] = $this->checkLanguage( $this->code ); + } + } + } + + protected function getCheckBlacklist() { + global $checkBlacklist; + return $checkBlacklist; + } + + protected function checkLanguage( $code ) { + # Syntax check only + if ( $this->level === 0 ) { + $this->L->getMessages( $code ); + return; + } + + $results = array(); + $checkFunctions = $this->getChecks(); + $checkBlacklist = $this->getCheckBlacklist(); + foreach ( $this->checks as $check ) { + if ( isset($checkBlacklist[$code]) && + in_array($check, $checkBlacklist[$code]) ) { + $result[$check] = array(); + continue; + } + + $callback = array( $this->L, $checkFunctions[$check] ); + if ( !is_callable($callback ) ) { + throw new MWException( "Unkown check $check." ); + } + $results[$check] = call_user_func( $callback , $code ); + } + + return $results; + } + + protected function formatKey( $key, $code ) { + if ( $this->doLinks ) { + $displayKey = ucfirst( $key ); + if ( $code == $this->wikiCode ) { + return "[[MediaWiki:$displayKey|$key]]"; + } else { + return "[[MediaWiki:$displayKey/$code|$key]]"; + } + } else { + return $key; + } + } + + protected function outputText() { + foreach ( $this->results as $code => $results ) { + $translated = $this->L->getMessages( $code ); + $translated = count( $translated['translated'] ); + $translatable = $this->L->getGeneralMessages(); + $translatable = count( $translatable['translatable'] ); + foreach ( $results as $check => $messages ) { + $count = count( $messages ); + if ( $count ) { + $search = array( '$1', '$2', '$3' ); + $replace = array( $count, $check == 'untranslated' ? $translatable: $translated, $code ); + $descriptions = $this->getDescriptions(); + echo "\n" . str_replace( $search, $replace, $descriptions[$check] ) . "\n"; + if ( $this->level == 1 ) { + echo "[messages are hidden]\n"; + } else { + foreach ( $messages as $key => $value ) { + $displayKey = $this->formatKey( $key, $code ); + if ( $this->level == 2 ) { + echo "* $displayKey\n"; + } else { + echo "* $displayKey: '$value'\n"; + } + } + } + } + } + } + } + + /** + * Globals: $wgContLang, $IP + */ + function outputWiki() { + global $wgContLang, $IP; + $detailText = ''; + $rows[] = '! Language !! Code !! Total !! ' . implode( ' !! ', $this->checks ); + foreach ( $this->results as $code => $results ) { + $detailTextForLang = "==$code==\n"; + $numbers = array(); + $problems = 0; + $detailTextForLangChecks = array(); + foreach ( $results as $check => $messages ) { + $count = count( $messages ); + if ( $count ) { + $problems += $count; + $messageDetails = array(); + foreach ( $messages as $key => $details ) { + $displayKey = $this->formatKey( $key, $code ); + $messageDetails[] = $displayKey; + } + $detailTextForLangChecks[] = "===$code-$check===\n* " . implode( ', ', $messageDetails ); + $numbers[] = "'''[[#$code-$check|$count]]'''"; + } else { + $numbers[] = $count; + } + + } + + if ( count( $detailTextForLangChecks ) ) { + $detailText .= $detailTextForLang . implode( "\n", $detailTextForLangChecks ) . "\n"; + } + + if ( !$problems ) { continue; } // Don't list languages without problems + $language = $wgContLang->getLanguageName( $code ); + $rows[] = "| $language || $code || $problems || " . implode( ' || ', $numbers ); + } + + $tableRows = implode( "\n|-\n", $rows ); + + $version = SpecialVersion::getVersion( $IP ); + echo <<<EOL +'''Check results are for:''' <code>$version</code> + + +{| class="sortable wikitable" border="2" cellpadding="4" cellspacing="0" style="background-color: #F9F9F9; border: 1px #AAAAAA solid; border-collapse: collapse; clear:both;" +$tableRows +|} + +$detailText + +EOL; + } + + protected function isEmpty() { + $empty = true; + foreach( $this->results as $code => $results ) { + foreach( $results as $check => $messages ) { + if( !empty( $messages ) ) { + $empty = false; + break; + } + } + if( !$empty ) { + break; + } + } + return $empty; + } +} + +class CheckExtensionsCLI extends CheckLanguageCLI { + private $extensions; + + public function __construct( Array $options, $extension ) { + if ( isset( $options['help'] ) ) { + echo $this->help(); + exit(); + } + + if ( isset($options['lang']) ) { + $this->code = $options['lang']; + } else { + global $wgLanguageCode; + $this->code = $wgLanguageCode; + } + + if ( isset($options['level']) ) { + $this->level = $options['level']; + } + + $this->doLinks = isset($options['links']); + + if ( isset($options['wikilang']) ) { + $this->wikiCode = $options['wikilang']; + } + + if ( isset( $options['whitelist'] ) ) { + $this->checks = explode( ',', $options['whitelist'] ); + } elseif ( isset( $options['blacklist'] ) ) { + $this->checks = array_diff( + $this->defaultChecks, + explode( ',', $options['blacklist'] ) + ); + } else { + $this->checks = $this->defaultChecks; + } + + if ( isset($options['output']) ) { + $this->output = $options['output']; + } + + # Some additional checks not enabled by default + if ( isset( $options['duplicate'] ) ) { + $this->checks[] = 'duplicate'; + } + + $this->extensions = array(); + $extensions = new PremadeMediawikiExtensionGroups(); + $extensions->addAll(); + if( $extension == 'all' ) { + foreach( MessageGroups::singleton()->getGroups() as $group ) { + if( strpos( $group->getId(), 'ext-' ) === 0 && !$group->isMeta() ) { + $this->extensions[] = new extensionLanguages( $group ); + } + } + } elseif( $extension == 'wikimedia' ) { + $wikimedia = MessageGroups::getGroup( 'ext-0-wikimedia' ); + foreach( $wikimedia->wmfextensions() as $extension ) { + $group = MessageGroups::getGroup( $extension ); + $this->extensions[] = new extensionLanguages( $group ); + } + } else { + $extensions = explode( ',', $extension ); + foreach( $extensions as $extension ) { + $group = MessageGroups::getGroup( 'ext-' . $extension ); + if( $group ) { + $extension = new extensionLanguages( $group ); + $this->extensions[] = $extension; + } else { + print "No such extension $extension.\n"; + } + } + } + } + + protected function help() { + return <<<ENDS +Run this script to check the status of a specific language in extensions, or all of them. +Command line settings are in form --parameter[=value], except for the first one. +Parameters: + * First parameter (mandatory): Extension name, multiple extension names (separated by commas), "all" for all the extensions or "wikimedia" for extensions used by Wikimedia. + * lang: Language code (default: the installation default language). + * help: Show this help. + * level: Show the following level (default: 2). + * links: Link the message values (default off). + * wikilang: For the links, what is the content language of the wiki to display the output in (default en). + * whitelist: Do only the following checks (form: code,code). + * blacklist: Do not perform the following checks (form: code,code). + * duplicate: Additionally check for messages which are translated the same to English (default off). +Check codes (ideally, all of them should result 0; all the checks are executed by default (except duplicate and 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, but translated. + * variables: Messages without variables which should be used. + * empty: Empty messages. + * whitespace: Messages which have trailing whitespace. + * xhtml: Messages which are not well-formed XHTML (checks only few common errors). + * chars: Messages with hidden characters. + * links: Messages which contains broken links to pages (does not find all). + * unbalanced: Messages which contains unequal numbers of opening {[ and closing ]}. +Display levels (default: 2): + * 0: Skip the checks (useful for checking syntax). + * 1: Show only the stub headers and number of wrong messages, without list of messages. + * 2: Show only the headers and the message keys, without the message values. + * 3: Show both the headers and the complete messages, with both keys and values. + +ENDS; + } + + public function execute() { + $this->doChecks(); + } + + protected function checkLanguage( $code ) { + foreach( $this->extensions as $extension ) { + $this->L = $extension; + $this->results = array(); + $this->results[$code] = parent::checkLanguage( $code ); + + if( !$this->isEmpty() ) { + echo $extension->name() . ":\n"; + + if( $this->level > 0 ) { + switch( $this->output ) { + case 'plain': + $this->outputText(); + break; + case 'wiki': + $this->outputWiki(); + break; + default: + throw new MWException( "Invalid output type $this->output" ); + } + } + + echo "\n"; + } + } + } +} # Blacklist some checks for some languages $checkBlacklist = array( #'code' => array( 'check1', 'check2' ... ) 'gan' => array( 'plural' ), +'gn' => array( 'plural' ), 'hak' => array( 'plural' ), +'hu' => array( 'plural' ), 'ja' => array( 'plural' ), // Does not use plural +'ka' => array( 'plural' ), +'kk-arab' => array( 'plural' ), +'kk-cyrl' => array( 'plural' ), +'kk-latn' => array( 'plural' ), +'ko' => array( 'plural' ), +'mn' => array( 'plural' ), +'ms' => array( 'plural' ), 'my' => array( 'chars' ), // Uses a lot zwnj +'sah' => array( 'plural' ), +'sq' => array( 'plural' ), 'tet' => array( 'plural' ), 'th' => array( 'plural' ), 'wuu' => array( 'plural' ), +'xmf' => array( 'plural' ), 'yue' => array( 'plural' ), 'zh' => array( 'plural' ), 'zh-classical' => array( 'plural' ), diff --git a/maintenance/language/checkLanguage.php b/maintenance/language/checkLanguage.php index 36d32a48..f8553a1e 100644 --- a/maintenance/language/checkLanguage.php +++ b/maintenance/language/checkLanguage.php @@ -2,313 +2,13 @@ /** * Check a language file. * - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage */ require_once( dirname(__FILE__).'/../commandLine.inc' ); +require_once( 'checkLanguage.inc' ); require_once( 'languages.inc' ); $cli = new CheckLanguageCLI( $options ); $cli->execute(); - -class CheckLanguageCLI { - private $code = null; - private $level = 2; - private $doLinks = false; - private $wikiCode = 'en'; - private $includeExif = false; - private $checkAll = false; - private $output = 'plain'; - private $checks = array(); - - private $defaultChecks = array( - 'untranslated', 'obsolete', 'variables', 'empty', 'plural', - 'whitespace', 'xhtml', 'chars', 'links', 'unbalanced' - ); - - private $L = null; - - /** - * GLOBALS: $wgLanguageCode; - */ - public function __construct( Array $options ) { - - if ( isset( $options['help'] ) ) { - echo $this->help(); - exit(); - } - - if ( isset($options['lang']) ) { - $this->code = $options['lang']; - } else { - global $wgLanguageCode; - $this->code = $wgLanguageCode; - } - - if ( isset($options['level']) ) { - $this->level = $options['level']; - } - - $this->doLinks = isset($options['links']); - $this->includeExif = !isset($options['noexif']); - $this->checkAll = isset($options['all']); - - if ( isset($options['wikilang']) ) { - $this->wikiCode = $options['wikilang']; - } - - if ( isset( $options['whitelist'] ) ) { - $this->checks = explode( ',', $options['whitelist'] ); - } elseif ( isset( $options['blacklist'] ) ) { - $this->checks = array_diff( - $this->defaultChecks, - explode( ',', $options['blacklist'] ) - ); - } else { - $this->checks = $this->defaultChecks; - } - - if ( isset($options['output']) ) { - $this->output = $options['output']; - } - - # Some additional checks not enabled by default - if ( isset( $options['duplicate'] ) ) { - $this->checks[] = 'duplicate'; - } - - $this->L = new languages( $this->includeExif ); - } - - protected function getChecks() { - $checks = array(); - $checks['untranslated'] = 'getUntranslatedMessages'; - $checks['duplicate'] = 'getDuplicateMessages'; - $checks['obsolete'] = 'getObsoleteMessages'; - $checks['variables'] = 'getMessagesWithoutVariables'; - $checks['plural'] = 'getMessagesWithoutPlural'; - $checks['empty'] = 'getEmptyMessages'; - $checks['whitespace'] = 'getMessagesWithWhitespace'; - $checks['xhtml'] = 'getNonXHTMLMessages'; - $checks['chars'] = 'getMessagesWithWrongChars'; - $checks['links'] = 'getMessagesWithDubiousLinks'; - $checks['unbalanced'] = 'getMessagesWithUnbalanced'; - return $checks; - } - - protected function getDescriptions() { - $descriptions = array(); - $descriptions['untranslated'] = '$1 message(s) of $2 are not translated to $3, but exist in en:'; - $descriptions['duplicate'] = '$1 message(s) of $2 are translated the same in en and $3:'; - $descriptions['obsolete'] = '$1 message(s) of $2 do not exist in en or are in the ignore list, but are in $3'; - $descriptions['variables'] = '$1 message(s) of $2 in $3 don\'t use some variables that en uses:'; - $descriptions['plural'] = '$1 message(s) of $2 in $3 don\'t use {{plural}} while en uses:'; - $descriptions['empty'] = '$1 message(s) of $2 in $3 are empty or -:'; - $descriptions['whitespace'] = '$1 message(s) of $2 in $3 have trailing whitespace:'; - $descriptions['xhtml'] = '$1 message(s) of $2 in $3 contain illegal XHTML:'; - $descriptions['chars'] = '$1 message(s) of $2 in $3 include hidden chars which should not be used in the messages:'; - $descriptions['links'] = '$1 message(s) of $2 in $3 have problematic link(s):'; - $descriptions['unbalanced'] = '$1 message(s) of $2 in $3 have unbalanced {[]}:'; - return $descriptions; - } - - protected function help() { - return <<<ENDS -Run this script to check a specific language file, or all of them. -Command line settings are in form --parameter[=value]. -Parameters: - * lang: Language code (default: the installation default language). - * all: Check all customized languages - * help: Show this help. - * level: Show the following level (default: 2). - * links: Link the message values (default off). - * wikilang: For the links, what is the content language of the wiki to display the output in (default en). - * whitelist: Do only the following checks (form: code,code). - * blacklist: Don't do the following checks (form: code,code). - * duplicate: Additionally check for messages which are translated the same to English (default off). - * noexif: Don't 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). -Check codes (ideally, all of them should result 0; all the checks are executed by default (except duplicate and 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, but translated. - * variables: Messages without variables which should be used. - * empty: Empty messages. - * whitespace: Messages which have trailing whitespace. - * xhtml: Messages which are not well-formed XHTML (checks only few common errors). - * chars: Messages with hidden characters. - * links: Messages which contains broken links to pages (does not find all). - * unbalanced: Messages which contains unequal numbers of opening {[ and closing ]}. -Display levels (default: 2): - * 0: Skip the checks (useful for checking syntax). - * 1: Show only the stub headers and number of wrong messages, without list of messages. - * 2: Show only the headers and the message keys, without the message values. - * 3: Show both the headers and the complete messages, with both keys and values. - -ENDS; - } - - private $results = array(); - - public function execute() { - $this->doChecks(); - if ( $this->level > 0 ) { - switch ($this->output) { - case 'plain': - $this->outputText(); - break; - case 'wiki': - $this->outputWiki(); - break; - default: - throw new MWException( "Invalid output type $this->output"); - } - } - } - - protected function doChecks() { - $ignoredCodes = array( 'en', 'enRTL' ); - - $this->results = array(); - # Check the language - if ( $this->checkAll ) { - foreach ( $this->L->getLanguages() as $language ) { - if ( !in_array($language, $ignoredCodes) ) { - $this->results[$language] = $this->checkLanguage( $language ); - } - } - } else { - if ( in_array($this->code, $ignoredCodes) ) { - throw new MWException("Cannot check code $this->code."); - } else { - $this->results[$this->code] = $this->checkLanguage( $this->code ); - } - } - } - - protected function getCheckBlacklist() { - static $checkBlacklist = null; - if ( $checkBlacklist === null ) { - $checkBlacklist = array(); - require( dirname(__FILE__) . '/checkLanguage.inc' ); - } - return $checkBlacklist; - } - - protected function checkLanguage( $code ) { - # Syntax check only - if ( $this->level === 0 ) { - $this->L->getMessages( $code ); - return; - } - - $results = array(); - $checkFunctions = $this->getChecks(); - $checkBlacklist = $this->getCheckBlacklist(); - foreach ( $this->checks as $check ) { - if ( isset($checkBlacklist[$code]) && - in_array($check, $checkBlacklist[$code]) ) { - $result[$check] = array(); - continue; - } - - $callback = array( $this->L, $checkFunctions[$check] ); - if ( !is_callable($callback ) ) { - throw new MWException( "Unkown check $check." ); - } - $results[$check] = call_user_func( $callback , $code ); - } - - return $results; - } - - protected function outputText( ) { - foreach ( $this->results as $code => $results ) { - $translated = $this->L->getMessages( $code ); - $translated = count( $translated['translated'] ); - foreach ( $results as $check => $messages ) { - $count = count( $messages ); - if ( $count ) { - $search = array( '$1', '$2', '$3' ); - $replace = array( $count, $translated, $code ); - $descriptions = $this->getDescriptions(); - echo "\n" . str_replace( $search, $replace, $descriptions[$check] ) . "\n"; - if ( $this->level == 1 ) { - echo "[messages are hidden]\n"; - } else { - foreach ( $messages as $key => $value ) { - if ( $this->doLinks ) { - $displayKey = ucfirst( $key ); - if ( $code == $this->wikiCode ) { - $displayKey = "[[MediaWiki:$displayKey|$key]]"; - } else { - $displayKey = "[[MediaWiki:$displayKey/$code|$key]]"; - } - } else { - $displayKey = $key; - } - if ( $this->level == 2 ) { - echo "* $displayKey\n"; - } else { - echo "* $displayKey: '$value'\n"; - } - } - } - } - } - } - } - - /** - * Globals: $wgContLang, $IP - */ - function outputWiki() { - global $wgContLang, $IP; - $detailText = ''; - $rows[] = '! Language !! Code !! Total !! ' . implode( ' !! ', $this->checks ); - foreach ( $this->results as $code => $results ) { - $detailTextForLang = "==$code==\n"; - $numbers = array(); - $problems = 0; - $detailTextForLangChecks = array(); - foreach ( $results as $check => $messages ) { - $count = count( $messages ); - if ( $count ) { - $problems += $count; - $messageDetails = array(); - foreach ( $messages as $key => $details ) { - $messageDetails[] = $key; - } - $detailTextForLangChecks[] = "===$code-$check===\n* " . implode( ', ', $messageDetails ); - $numbers[] = "'''[[#$code-$check|$count]]'''"; - } else { - $numbers[] = $count; - } - - } - - if ( count( $detailTextForLangChecks ) ) { - $detailText .= $detailTextForLang . implode( "\n", $detailTextForLangChecks ) . "\n"; - } - - if ( !$problems ) { continue; } // Don't list languages without problems - $language = $wgContLang->getLanguageName( $code ); - $rows[] = "| $language || $code || $problems || " . implode( ' || ', $numbers ); - } - - $tableRows = implode( "\n|-\n", $rows ); - - $version = SpecialVersion::getVersion( $IP ); - echo <<<EOL -'''Check results are for:''' <code>$version</code> - - -{| class="sortable wikitable" border="2" cellpadding="4" cellspacing="0" style="background-color: #F9F9F9; border: 1px #AAAAAA solid; border-collapse: collapse; clear:both;" -$tableRows -|} - -$detailText - -EOL; - } - -} diff --git a/maintenance/language/date-formats.php b/maintenance/language/date-formats.php index 1efa84b5..834d2bd8 100644 --- a/maintenance/language/date-formats.php +++ b/maintenance/language/date-formats.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup MaintenanceLanguage + */ $ts = '20010115123456'; diff --git a/maintenance/language/diffLanguage.php b/maintenance/language/diffLanguage.php index 05a6e4b1..389b01d5 100644 --- a/maintenance/language/diffLanguage.php +++ b/maintenance/language/diffLanguage.php @@ -35,7 +35,8 @@ * percentage of messages correctly localised and the number of messages to be * translated. * - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage */ /** This script run from the commandline */ diff --git a/maintenance/language/digit2html.php b/maintenance/language/digit2html.php index 3b690461..b020d812 100644 --- a/maintenance/language/digit2html.php +++ b/maintenance/language/digit2html.php @@ -1,4 +1,9 @@ <?php +/** + * @file + * @ingroup MaintenanceLanguage + */ + require( '../commandLine.inc' ); # A list of unicode numerals is available at: diff --git a/maintenance/language/dumpMessages.php b/maintenance/language/dumpMessages.php index e57bfeec..5669e58c 100644 --- a/maintenance/language/dumpMessages.php +++ b/maintenance/language/dumpMessages.php @@ -1,7 +1,8 @@ <?php /** * @todo document - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage */ /** */ diff --git a/maintenance/language/function-list.php b/maintenance/language/function-list.php index 67bcab03..f0c398a6 100644 --- a/maintenance/language/function-list.php +++ b/maintenance/language/function-list.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup MaintenanceLanguage + */ define( 'MEDIAWIKI', 1 ); define( 'NOT_REALLY_MEDIAWIKI', 1 ); diff --git a/maintenance/language/lang2po.php b/maintenance/language/lang2po.php index a5aa81aa..1009ed6c 100644 --- a/maintenance/language/lang2po.php +++ b/maintenance/language/lang2po.php @@ -5,6 +5,9 @@ * Todo: * - generate .po header * - fix escaping of \ + * + * @file + * @ingroup MaintenanceLanguage */ $optionsWithArgs[] = 'lang'; diff --git a/maintenance/language/langmemusage.php b/maintenance/language/langmemusage.php index 929976d3..9bfb3cdc 100644 --- a/maintenance/language/langmemusage.php +++ b/maintenance/language/langmemusage.php @@ -2,6 +2,9 @@ /** * Dumb program that tries to get the memory usage * for each language file. + * + * @file + * @ingroup MaintenanceLanguage */ /** This is a command line script */ diff --git a/maintenance/language/languages.inc b/maintenance/language/languages.inc index 9472e254..6d16f80c 100644 --- a/maintenance/language/languages.inc +++ b/maintenance/language/languages.inc @@ -2,9 +2,13 @@ /** * Handle messages in the language files. * - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage */ +/** + * @ingroup MaintenanceLanguage + */ class languages { protected $mLanguages; # List of languages protected $mRawMessages; # Raw list of the messages in each language @@ -322,6 +326,8 @@ class languages { '<br *\\?>', '<hr/>', '<br/>', + '<hr>', + '<br>', ); $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu'; $nonXHTMLMessages = array(); @@ -418,4 +424,41 @@ class languages { } -?> +class extensionLanguages extends languages { + private $mMessageGroup; # The message group + + /** + * Load the messages group. + * @param $group The messages group. + */ + function __construct( MessageGroup $group ) { + $this->mMessageGroup = $group; + + $bools = $this->mMessageGroup->getBools(); + $this->mIgnoredMessages = $bools['ignored']; + $this->mOptionalMessages = $bools['optional']; + } + + /** + * Get the extension name. + * + * @return The extension name. + */ + public function name() { + return $this->mMessageGroup->getLabel(); + } + + /** + * Load the raw messages for a specific language. + * + * @param $code The language code. + */ + protected function loadRawMessages( $code ) { + if( !isset( $this->mRawMessages[$code] ) ) { + $this->mRawMessages[$code] = $this->mMessageGroup->load( $code ); + if( empty( $this->mRawMessages[$code] ) ) { + $this->mRawMessages[$code] = array(); + } + } + } +} diff --git a/maintenance/language/messageTypes.inc b/maintenance/language/messageTypes.inc index 43ca41c2..67caaddd 100644 --- a/maintenance/language/messageTypes.inc +++ b/maintenance/language/messageTypes.inc @@ -2,10 +2,11 @@ /** * Several types of messages. * - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage */ -/** Ignored messages, which should be exist only in the English messages file. */ +/** Ignored messages, which should exist only in the English messages file. */ $wgIgnoredMessages = array( 'sidebar', 'accesskey-pt-userpage', @@ -39,7 +40,6 @@ $wgIgnoredMessages = array( 'accesskey-n-recentchanges', 'accesskey-n-randompage', 'accesskey-n-help', - 'accesskey-n-sitesupport', 'accesskey-t-whatlinkshere', 'accesskey-t-recentchangeslinked', 'accesskey-feed-rss', @@ -70,8 +70,8 @@ $wgIgnoredMessages = array( 'addsection', 'anonnotice', 'autoblock_whitelist', - 'catseparator', 'googlesearch', + 'opensearch-desc', 'exif-make-value', 'exif-model-value', 'exif-software-value', @@ -87,10 +87,10 @@ $wgIgnoredMessages = array( 'noarticletextanon', 'number_of_watching_users_RCview', 'pagecategorieslink', - 'patrol-log-header', 'pubmedurl', 'randompage-url', 'recentchanges-url', + 'cantcreateaccount-nonblock-text', 'revision-info-current', 'revision-nav', 'rfcurl', @@ -107,19 +107,12 @@ $wgIgnoredMessages = array( 'talkpagetext', 'trackback', 'trackbackexcerpt', -); - -/** Optional messages, which may be translated only if changed in the other language. */ -$wgOptionalMessages = array( - 'imgmultigotopost', - 'linkprefix', - 'editsection-brackets', - 'feed-atom', - 'feed-rss', - 'sectionlink', - 'unit-pixel', + 'uploadfooter', + 'listgrouprights-link', + 'search-interwiki-custom', 'allpages-summary', 'booksources-summary', + 'categories-summary', 'ipblocklist-summary', 'protectedtitles-summary', 'listusers-summary', @@ -127,8 +120,6 @@ $wgOptionalMessages = array( 'preferences-summary', 'specialpages-summary', 'whatlinkshere-summary', - 'whatlinkshere-barrow', - 'imagelist-summary', 'listredirects-summary', 'uncategorizedpages-summary', 'uncategorizedcategories-summary', @@ -147,7 +138,6 @@ $wgOptionalMessages = array( 'shortpages-summary', 'newpages-summary', 'ancientpages-summary', - 'newimages-summary', 'unwatchedpages-summary', 'userrights-summary', 'brokenredirects-summary', @@ -158,8 +148,19 @@ $wgOptionalMessages = array( 'lonelypages-summary', 'unusedtemplates-summary', 'fewestrevisions-summary', - 'withoutinterwiki-summary', + 'missingfiles-summary', 'upload-summary', +); + +/** Optional messages, which may be translated only if changed in the target language. */ +$wgOptionalMessages = array( + 'linkprefix', + 'editsection-brackets', + 'feed-atom', + 'feed-rss', + 'sectionlink', + 'unit-pixel', + 'userrights-irreversible-marker', 'tog-nolangconversion', 'yourvariant', 'variantname-zh-hans', @@ -167,12 +168,12 @@ $wgOptionalMessages = array( 'variantname-zh-cn', 'variantname-zh-tw', 'variantname-zh-hk', + 'variantname-zh-mo', + 'variantname-zh-my', 'variantname-zh-sg', 'variantname-zh', 'variantname-sr-ec', 'variantname-sr-el', - 'variantname-sr-jc', - 'variantname-sr-jl', 'variantname-sr', 'variantname-kk-arab', 'variantname-kk-cyrl', @@ -184,14 +185,31 @@ $wgOptionalMessages = array( 'variantname-ku-latn', 'variantname-ku-arab', 'variantname-ku', + 'variantname-tg-cyrl', + 'variantname-tg-latn', + 'variantname-tg', 'rc-change-size', 'resetpass_text', 'image_sample', 'media_sample', 'common.css', + 'standard.css', + 'nostalgia.css', + 'cologneblue.css', 'monobook.css', + 'myskin.css', + 'chick.css', + 'simple.css', + 'modern.css', 'common.js', + 'standard.js', + 'nostalgia.js', + 'cologneblue.js', 'monobook.js', + 'myskin.js', + 'chick.js', + 'simple.js', + 'modern.js', 'widthheight', 'exif-fnumber-format', 'exif-focallength-format', @@ -214,7 +232,6 @@ $wgOptionalMessages = array( 'exif-lightsource-23', 'exif-filesource-3', 'booksources-isbn', - 'isbn', 'sp-contributions-explain', 'sorbs', 'video-dims', @@ -224,6 +241,8 @@ $wgOptionalMessages = array( 'filerevert-backlink', 'filedelete-backlink', 'delete-backlink', + 'move-page-backlink', + 'protect-backlink', 'pagetitle', 'filename-prefix-blacklist', 'edittools', @@ -244,6 +263,18 @@ $wgOptionalMessages = array( 'iranian-calendar-m10', 'iranian-calendar-m11', 'iranian-calendar-m12', + 'hijri-calendar-m1', + 'hijri-calendar-m2', + 'hijri-calendar-m3', + 'hijri-calendar-m4', + 'hijri-calendar-m5', + 'hijri-calendar-m6', + 'hijri-calendar-m7', + 'hijri-calendar-m8', + 'hijri-calendar-m9', + 'hijri-calendar-m10', + 'hijri-calendar-m11', + 'hijri-calendar-m12', 'hebrew-calendar-m1', 'hebrew-calendar-m2', 'hebrew-calendar-m3', @@ -272,8 +303,14 @@ $wgOptionalMessages = array( 'hebrew-calendar-m10-gen', 'hebrew-calendar-m11-gen', 'hebrew-calendar-m12-gen', + 'catseparator', 'semicolon-separator', 'comma-separator', + 'colon-separator', + 'autocomment-prefix', + 'listgrouprights-right-display', + 'timezone-utc', + 'whatlinkshere-barrow', ); /** 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 8b818d16..50d45e6e 100644 --- a/maintenance/language/messages.inc +++ b/maintenance/language/messages.inc @@ -2,7 +2,8 @@ /** * Define the messages structure in the messages file, for an automated rewriting. * - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage */ /** The structure of the messages, divided to blocks */ @@ -50,6 +51,7 @@ $wgMessageStructure = array( 'tog-nolangconversion', 'tog-ccmeonemails', 'tog-diffonly', + 'tog-showhiddencats', ), 'underline' => array( 'underline-always', @@ -111,14 +113,22 @@ $wgMessageStructure = array( 'nov', 'dec', ), - 'categories' => array( - 'categories', + 'categorypages' => array( 'pagecategories', 'pagecategorieslink', 'category_header', 'subcategories', 'category-media-header', 'category-empty', + 'hidden-categories', + 'hidden-category-category', + 'category-subcat-count', + 'category-subcat-count-limited', + 'category-article-count', + 'category-article-count-limited', + 'category-file-count', + 'category-file-count-limited', + 'listingcontinuesabbrev', ), 'mainpage' => array( 'linkprefix', @@ -164,7 +174,9 @@ $wgMessageStructure = array( 'permalink', 'print', 'edit', + 'create', 'editthispage', + 'create-this-page', 'delete', 'deletethispage', 'undelete_short', @@ -221,13 +233,12 @@ $wgMessageStructure = array( 'help', 'helppage', 'mainpage', + 'mainpage-description', 'policy-url', 'portal', 'portal-url', 'privacy', 'privacypage', - 'sitesupport', - 'sitesupport-url', ), 'badaccess' => array( 'badaccess', @@ -254,6 +265,7 @@ $wgMessageStructure = array( 'editsection', 'editsection-brackets', 'editold', + 'viewsourceold', 'editsectionhint', 'toc', 'showtoc', @@ -305,7 +317,9 @@ $wgMessageStructure = array( 'readonly', 'enterlockreason', 'readonlytext', - 'missingarticle', + 'missing-article', + 'missingarticle-rev', + 'missingarticle-diff', 'readonly_lag', 'internalerror', 'internalerror_info', @@ -341,6 +355,11 @@ $wgMessageStructure = array( 'ns-specialprotected', 'titleprotected', ), + 'virus' => array( + 'virus-badscanner', + 'virus-scanfailed', + 'virus-unknownscanner', + ), 'login' => array( 'logouttitle', 'logouttext', @@ -354,6 +373,7 @@ $wgMessageStructure = array( 'externaldberror', 'loginproblem', 'login', + 'nav-login-createaccount', 'loginprompt', 'userlogin', 'logout', @@ -370,6 +390,7 @@ $wgMessageStructure = array( 'youremail', 'username', 'uid', + 'prefs-memberingroups', 'yourrealname', 'yourlanguage', 'yourvariant', @@ -508,7 +529,6 @@ $wgMessageStructure = array( 'session_fail_preview_html', 'token_suffix_mismatch', 'editing', - 'editinguser', 'editingsection', 'editingcomment', 'editconflict', @@ -532,29 +552,40 @@ $wgMessageStructure = array( 'templatesusedsection', 'template-protected', 'template-semiprotected', + 'hiddencategories', 'edittools', 'nocreatetitle', 'nocreatetext', 'nocreate-loggedin', 'permissionserrors', 'permissionserrorstext', + 'permissionserrorstext-withaction', 'recreate-deleted-warn', ), + 'parserwarnings' => array( + 'expensive-parserfunction-warning', + 'expensive-parserfunction-category', + 'post-expand-template-inclusion-warning', + 'post-expand-template-inclusion-category', + 'post-expand-template-argument-warning', + 'post-expand-template-argument-category', + ), 'undo' => array( 'undo-success', 'undo-failure', + 'undo-norev', 'undo-summary', ), 'cantcreateaccount' => array( 'cantcreateaccounttitle', 'cantcreateaccount-text', + 'cantcreateaccount-nonblock-text', ), 'history' => array( 'viewpagelogs', 'nohistory', 'revnotfound', 'revnotfoundtext', - 'loadhist', 'currentrev', 'revisionasof', 'revision-info', @@ -566,7 +597,6 @@ $wgMessageStructure = array( 'cur', 'next', 'last', - 'orig', 'page_first', 'page_last', 'histlegend', @@ -613,10 +643,22 @@ $wgMessageStructure = array( 'logdelete-logaction', 'revdelete-success', 'logdelete-success', - ), - 'oversightlog' => array( - 'oversightlog', - 'overlogpagetext', + 'revdel-restore', + 'pagehist', + 'deletedhist', + 'revdelete-content', + 'revdelete-summary', + 'revdelete-uname', + 'revdelete-restricted', + 'revdelete-unrestricted', + 'revdelete-hid', + 'revdelete-unhid', + 'revdelete-log-message', + 'logdelete-log-message', + ), + 'suppression' => array( + 'suppressionlog', + 'suppressionlogtext', ), 'mergehistory' => array( 'mergehistory', @@ -635,6 +677,8 @@ $wgMessageStructure = array( 'mergehistory-no-destination', 'mergehistory-invalid-source', 'mergehistory-invalid-destination', + 'mergehistory-autocomment', + 'mergehistory-comment', ), 'mergelog' => array( 'mergelog', @@ -665,14 +709,37 @@ $wgMessageStructure = array( 'prevn', 'nextn', 'viewprevnext', + 'search-result-size', + 'search-result-score', + 'search-redirect', + 'search-section', + 'search-suggest', + 'search-interwiki-caption', + 'search-interwiki-default', + 'search-interwiki-custom', + 'search-interwiki-more', + 'search-mwsuggest-enabled', + 'search-mwsuggest-disabled', + 'search-relatedarticle', + 'mwsuggest-disable', + 'searchrelated', + 'searchall', 'showingresults', 'showingresultsnum', + 'showingresultstotal', 'nonefound', 'powersearch', - 'powersearchtext', + 'powersearch-legend', + 'powersearch-ns', + 'powersearch-redir', + 'powersearch-field', + 'search-external', 'searchdisabled', 'googlesearch', ), + 'opensearch' => array( + 'opensearch-desc', + ), 'preferences' => array( 'preferences', 'preferences-summary', @@ -731,50 +798,110 @@ $wgMessageStructure = array( 'servertime', 'guesstimezone', 'allowemail', + 'prefs-searchoptions', + 'prefs-namespaces', 'defaultns', 'default', 'files', ), 'userrights' => array( + 'userrights', + 'userrights-summary', 'userrights-lookup-user', 'userrights-user-editname', 'editusergroup', + 'editinguser', 'userrights-editusergroup', 'saveusergroups', 'userrights-groupsmember', - 'userrights-groupsremovable', - 'userrights-groupsavailable', - 'userrights-groupshelp', + 'userrights-groups-help', 'userrights-reason', - 'userrights-available-none', - 'userrights-available-add', - 'userrights-available-remove', - 'userrights-available-add-self', - 'userrights-available-remove-self', 'userrights-no-interwiki', 'userrights-nodatabase', 'userrights-nologin', 'userrights-notallowed', + 'userrights-changeable-col', + 'userrights-unchangeable-col', + 'userrights-irreversible-marker', ), 'group' => array( 'group', + 'group-user', 'group-autoconfirmed', 'group-bot', 'group-sysop', 'group-bureaucrat', + 'group-suppress', 'group-all', ), 'group-member' => array( + 'group-user-member', 'group-autoconfirmed-member', 'group-bot-member', 'group-sysop-member', 'group-bureaucrat-member', + 'group-suppress-member', ), 'grouppage' => array( + 'grouppage-user', 'grouppage-autoconfirmed', 'grouppage-bot', 'grouppage-sysop', 'grouppage-bureaucrat', + 'grouppage-suppress', + ), + 'right' => array( + 'right-read', + 'right-edit', + 'right-createpage', + 'right-createtalk', + 'right-createaccount', + 'right-minoredit', + 'right-move', + 'right-move-subpages', + 'right-suppressredirect', + 'right-upload', + 'right-reupload', + 'right-reupload-own', + 'right-reupload-shared', + 'right-upload_by_url', + 'right-purge', + 'right-autoconfirmed', + 'right-bot', + 'right-nominornewtalk', + 'right-apihighlimits', + 'right-writeapi', + 'right-delete', + 'right-bigdelete', + 'right-deleterevision', + 'right-deletedhistory', + 'right-browsearchive', + 'right-undelete', + 'right-suppressrevision', + 'right-suppressionlog', + 'right-block', + 'right-blockemail', + 'right-hideuser', + 'right-ipblock-exempt', + 'right-proxyunbannable', + 'right-protect', + 'right-editprotected', + 'right-editinterface', + 'right-editusercssjs', + 'right-rollback', + 'right-markbotedits', + 'right-noratelimit', + 'right-import', + 'right-importupload', + 'right-patrol', + 'right-autopatrol', + 'right-patrolmarks', + 'right-unwatchedpages', + 'right-trackback', + 'right-mergehistory', + 'right-userrights', + 'right-userrights-interwiki', + 'right-siteadmin', ), 'rightslog' => array( 'rightslog', @@ -818,6 +945,8 @@ $wgMessageStructure = array( 'recentchangeslinked-title', 'recentchangeslinked-noresult', 'recentchangeslinked-summary', + 'recentchangeslinked-page', + 'recentchangeslinked-to', ), 'upload' => array( 'upload', @@ -826,6 +955,7 @@ $wgMessageStructure = array( 'reuploaddesc', 'uploadnologin', 'uploadnologintext', + 'upload_directory_missing', 'upload_directory_read_only', 'uploaderror', 'upload-summary', @@ -833,6 +963,7 @@ $wgMessageStructure = array( 'upload-permitted', 'upload-preferred', 'upload-prohibited', + 'uploadfooter', 'uploadlog', 'uploadlogpage', 'uploadlogpagetext', @@ -862,6 +993,7 @@ $wgMessageStructure = array( 'file-thumbnail-no', 'fileexists-forbidden', 'fileexists-shared-forbidden', + 'file-exists-duplicate', 'successfulupload', 'uploadwarning', 'savefile', @@ -874,6 +1006,7 @@ $wgMessageStructure = array( 'uploadvirus', 'sourcefilename', 'destfilename', + 'upload-maxfilesize', 'watchthisupload', 'filewasdeleted', 'upload-wasdeleted', @@ -903,18 +1036,17 @@ $wgMessageStructure = array( 'upload_source_file', ), 'imagelist' => array( - 'imagelist', 'imagelist-summary', - 'imagelisttext', - 'getimagelist', - 'ilsubmit', - 'showlast', - 'byname', - 'bydate', - 'bysize', - 'imgdelete', - 'imgdesc', + 'imagelist_search_for', 'imgfile', + 'imagelist', + 'imagelist_date', + 'imagelist_name', + 'imagelist_user', + 'imagelist_size', + 'imagelist_description', + ), + 'imagedesciption' => array( 'filehist', 'filehist-help', 'filehist-deleteall', @@ -929,20 +1061,22 @@ $wgMessageStructure = array( 'imagelinks', 'linkstoimage', 'nolinkstoimage', + 'morelinkstoimage', + 'redirectstofile', + 'duplicatesoffile', 'sharedupload', 'shareduploadwiki', 'shareduploadwiki-desc', 'shareduploadwiki-linktext', 'shareddescriptionfollows', + 'shareduploadduplicate', + 'shareduploadduplicate-linktext', + 'shareduploadconflict', + 'shareduploadconflict-linktext', 'noimage', 'noimage-linktext', 'uploadnewversion-linktext', - 'imagelist_date', - 'imagelist_name', - 'imagelist_user', - 'imagelist_size', - 'imagelist_description', - 'imagelist_search_for', + 'imagepage-searchdupe', ), 'filerevert' => array( 'filerevert', @@ -971,6 +1105,7 @@ $wgMessageStructure = array( 'filedelete-otherreason', 'filedelete-reason-otherlist', 'filedelete-reason-dropdown', + 'filedelete-edit-reasonlist', ), 'mimesearch' => array( 'mimesearch', @@ -1020,6 +1155,8 @@ $wgMessageStructure = array( 'doubleredirects', 'doubleredirects-summary', 'doubleredirectstext', + 'double-redirect-fixed-move', + 'double-redirect-fixer', ), 'brokenredirects' => array( 'brokenredirects', @@ -1030,8 +1167,8 @@ $wgMessageStructure = array( ), 'withoutinterwiki' => array( 'withoutinterwiki', - 'withoutinterwiki-header', 'withoutinterwiki-summary', + 'withoutinterwiki-legend', 'withoutinterwiki-submit', ), 'fewestrevisions' => array( @@ -1066,6 +1203,8 @@ $wgMessageStructure = array( 'wantedcategories-summary', 'wantedpages', 'wantedpages-summary', + 'missingfiles', + 'missingfiles-summary', 'mostlinked', 'mostlinked-summary', 'mostlinkedcategories', @@ -1078,8 +1217,6 @@ $wgMessageStructure = array( 'mostimages-summary', 'mostrevisions', 'mostrevisions-summary', - 'allpages', - 'allpages-summary', 'prefixindex', 'prefixindex-summary', 'shortpages', @@ -1090,6 +1227,7 @@ $wgMessageStructure = array( 'deadendpages-summary', 'deadendpagestext', 'protectedpages', + 'protectedpages-indef', 'protectedpages-summary', 'protectedpagestext', 'protectedpagesempty', @@ -1099,24 +1237,22 @@ $wgMessageStructure = array( 'protectedtitlesempty', 'listusers', 'listusers-summary', - 'specialpages', - 'specialpages-summary', - 'spheading', - 'restrictedpheading', 'newpages', 'newpages-summary', 'newpages-username', 'ancientpages', 'ancientpages-summary', - 'intl', 'move', 'movethispage', 'unusedimagestext', 'unusedcategoriestext', 'notargettitle', 'notargettext', + 'nopagetitle', + 'nopagetext', 'pager-newer-n', 'pager-older-n', + 'suppress', ), 'booksources' => array( 'booksources', @@ -1126,17 +1262,9 @@ $wgMessageStructure = array( 'booksources-go', 'booksources-text', ), - 'specialpages2' => array( - 'categoriespagetext', - 'data', - 'userrights', - 'userrights-summary', - 'groups', - 'isbn', + 'magicwords' => array( 'rfcurl', 'pubmedurl', - 'alphaindexline', - 'version', ), 'logpages' => array( 'specialloguserlabel', @@ -1150,6 +1278,9 @@ $wgMessageStructure = array( 'log-title-wildcard', ), 'allpages' => array( + 'allpages', + 'allpages-summary', + 'alphaindexline', 'nextpage', 'prevpage', 'allpagesfrom', @@ -1163,11 +1294,28 @@ $wgMessageStructure = array( 'allpagesbadtitle', 'allpages-bad-ns', ), + 'categories' => array( + 'categories', + 'categories-summary', + 'categoriespagetext', + 'categoriesfrom', + 'special-categories-sort-count', + 'special-categories-sort-abc', + ), 'listusers' => array( 'listusersfrom', 'listusers-submit', 'listusers-noresult', ), + 'listgrouprights' => array( + 'listgrouprights', + 'listgrouprights-summary', + 'listgrouprights-group', + 'listgrouprights-rights', + 'listgrouprights-helppage', + 'listgrouprights-members', + 'listgrouprights-right-display', + ), 'emailuser' => array( 'mailnologin', 'mailnologintext', @@ -1187,6 +1335,7 @@ $wgMessageStructure = array( 'emailccsubject', 'emailsent', 'emailsenttext', + 'emailuserfooter', ), 'watchlist' => array( 'watchlist', @@ -1205,6 +1354,7 @@ $wgMessageStructure = array( 'unwatch', 'unwatchthispage', 'notanarticle', + 'notvisiblerev', 'watchnochange', 'watchlist-details', 'wlheader-enotif', @@ -1254,6 +1404,7 @@ $wgMessageStructure = array( 'actioncomplete', 'deletedtext', 'deletedarticle', + 'suppressedarticle', 'dellogpage', 'dellogpagetext', 'deletionlog', @@ -1262,6 +1413,7 @@ $wgMessageStructure = array( 'deleteotherreason', 'deletereasonotherlist', 'deletereason-dropdown', + 'delete-edit-reasonlist', 'delete-toobig', 'delete-warning-toobig', 'rollback', @@ -1279,13 +1431,14 @@ $wgMessageStructure = array( 'protectedarticle', 'modifiedarticleprotection', 'unprotectedarticle', - 'protectsub', + 'protect-title', + 'protect-backlink', + 'protect-legend', 'confirmprotect', 'protectcomment', 'protectexpiry', 'protect_expiry_invalid', 'protect_expiry_old', - 'unprotectsub', 'protect-unchain', 'protect-text', 'protect-locked-blocked', @@ -1310,6 +1463,7 @@ $wgMessageStructure = array( 'restriction-edit', 'restriction-move', 'restriction-create', + 'restriction-upload', ), 'restriction-levels' => array( 'restriction-level-sysop', @@ -1319,8 +1473,10 @@ $wgMessageStructure = array( 'undelete' => array( 'undelete', 'undeletepage', + 'undeletepagetitle', 'viewdeletedpage', 'undeletepagetext', + 'undelete-fieldset-title', 'undeleteextrahelp', 'undeleterevisions', 'undeletehistory', @@ -1361,8 +1517,6 @@ $wgMessageStructure = array( 'mycontris', 'contribsub2', 'nocontribs', - 'ucnote', - 'uclinks', 'uctop', 'month', 'year', @@ -1378,9 +1532,6 @@ $wgMessageStructure = array( 'sp-contributions-footer', 'sp-contributions-footer-anon', ), - 'newimages-showfrom' => array( - 'sp-newimages-showfrom', - ), 'whatlinkshere' => array( 'whatlinkshere', 'whatlinkshere-title', @@ -1393,12 +1544,19 @@ $wgMessageStructure = array( 'nolinkshere-ns', 'isredirect', 'istemplate', + 'isimage', 'whatlinkshere-prev', 'whatlinkshere-next', 'whatlinkshere-links', + 'whatlinkshere-hideredirs', + 'whatlinkshere-hidetrans', + 'whatlinkshere-hidelinks', + 'whatlinkshere-hideimages', + 'whatlinkshere-filters', ), 'block' => array( 'blockip', + 'blockip-legend', 'blockiptext', 'ipaddress', 'ipadressorusername', @@ -1416,6 +1574,7 @@ $wgMessageStructure = array( 'ipbotheroption', 'ipbotherreason', 'ipbhidename', + 'ipbwatchuser', 'badipaddress', 'blockipsuccesssub', 'blockipsuccesstext', @@ -1455,8 +1614,10 @@ $wgMessageStructure = array( 'block-log-flags-nocreate', 'block-log-flags-noautoblock', 'block-log-flags-noemail', + 'block-log-flags-angry-autoblock', 'range_block_disabled', 'ipb_expiry_invalid', + 'ipb_expiry_temp', 'ipb_already_blocked', 'ipb_cant_unblock', 'ipb_blocked_as_range', @@ -1488,7 +1649,9 @@ $wgMessageStructure = array( 'databasenotlocked', ), 'movepage' => array( - 'movepage', + 'move-page', + 'move-page-backlink', + 'move-page-legend', 'movepagetext', 'movepagetalktext', 'movearticle', @@ -1505,8 +1668,12 @@ $wgMessageStructure = array( 'talkexists', 'movedto', 'movetalk', - 'talkpagemoved', - 'talkpagenotmoved', + 'move-subpages', + 'move-talk-subpages', + 'movepage-page-exists', + 'movepage-page-moved', + 'movepage-page-unmoved', + 'movepage-max-pages', '1movedto2', '1movedto2_redir', 'movelogpage', @@ -1519,6 +1686,10 @@ $wgMessageStructure = array( 'delete_and_move_reason', 'selfmove', 'immobile_namespace', + 'imagenocrossnamespace', + 'imagetypemismatch', + 'imageinvalidfilename', + 'fix-double-redirects', ), 'export' => array( 'export', @@ -1577,6 +1748,7 @@ $wgMessageStructure = array( 'import-noarticle', 'import-nonewrevisions', 'xml-error-string', + 'import-upload', ), 'importlog' => array( 'importlogpage', @@ -1618,7 +1790,6 @@ $wgMessageStructure = array( 'accesskey-n-recentchanges', 'accesskey-n-randompage', 'accesskey-n-help', - 'accesskey-n-sitesupport', 'accesskey-t-whatlinkshere', 'accesskey-t-recentchangeslinked', 'accesskey-t-random', @@ -1680,7 +1851,6 @@ $wgMessageStructure = array( 'tooltip-n-recentchanges', 'tooltip-n-randompage', 'tooltip-n-help', - 'tooltip-n-sitesupport', 'tooltip-t-whatlinkshere', 'tooltip-t-recentchangeslinked', 'tooltip-t-random', @@ -1713,11 +1883,25 @@ $wgMessageStructure = array( ), 'stylesheets' => array( 'common.css', + 'standard.css', + 'nostalgia.css', + 'cologneblue.css', 'monobook.css', + 'myskin.css', + 'chick.css', + 'simple.css', + 'modern.css', ), 'scripts' => array( 'common.js', + 'standard.js', + 'nostalgia.js', + 'cologneblue.js', 'monobook.js', + 'myskin.js', + 'chick.js', + 'simple.js', + 'modern.js', ), 'metadata_cc' => array( 'nodublincore', @@ -1738,10 +1922,6 @@ $wgMessageStructure = array( 'spamprotectiontitle', 'spamprotectiontext', 'spamprotectionmatch', - 'subcategorycount', - 'categoryarticlecount', - 'category-media-count', - 'listingcontinuesabbrev', 'spambot_username', 'spam_reverting', 'spam_blanking', @@ -1809,9 +1989,13 @@ $wgMessageStructure = array( ), 'newimages' => array( 'newimages', + 'imagelisttext', 'newimages-summary', 'showhidebots', 'noimages', + 'ilsubmit', + 'bydate', + 'sp-newimages-showfrom', ), 'video-info' => array( 'video-dims', @@ -1828,14 +2012,14 @@ $wgMessageStructure = array( 'variantname-zh-cn', 'variantname-zh-tw', 'variantname-zh-hk', + 'variantname-zh-mo', 'variantname-zh-sg', + 'variantname-zh-my', 'variantname-zh', ), 'variantname-sr' => array( 'variantname-sr-ec', 'variantname-sr-el', - 'variantname-sr-jc', - 'variantname-sr-jl', 'variantname-sr', ), 'variantname-kk' => array( @@ -1852,6 +2036,11 @@ $wgMessageStructure = array( 'variantname-ku-latn', 'variantname-ku', ), + 'variantname-tg' => array( + 'variantname-tg-cyrl', + 'variantname-tg-latn', + 'variantname-tg', + ), 'metadata' => array( 'metadata', 'metadata-help', @@ -2192,6 +2381,8 @@ $wgMessageStructure = array( 'confirmemail_error', 'confirmemail_subject', 'confirmemail_body', + 'confirmemail_invalidated', + 'invalidateemail', ), 'scarytransclusion' => array( 'scarytranscludedisabled', @@ -2232,13 +2423,14 @@ $wgMessageStructure = array( 'catseparator', 'semicolon-separator', 'comma-separator', + 'colon-separator', + 'autocomment-prefix', ), 'imgmulti' => array( 'imgmultipageprev', 'imgmultipagenext', 'imgmultigo', - 'imgmultigotopre', - 'imgmultigotopost', + 'imgmultigoto', ), 'tablepager' => array( 'ascending_abbrev', @@ -2312,6 +2504,20 @@ $wgMessageStructure = array( 'iranian-calendar-m11', 'iranian-calendar-m12', ), + 'hijri-dates' => array( + 'hijri-calendar-m1', + 'hijri-calendar-m2', + 'hijri-calendar-m3', + 'hijri-calendar-m4', + 'hijri-calendar-m5', + 'hijri-calendar-m6', + 'hijri-calendar-m7', + 'hijri-calendar-m8', + 'hijri-calendar-m9', + 'hijri-calendar-m10', + 'hijri-calendar-m11', + 'hijri-calendar-m12', + ), 'hebrew-dates' => array( 'hebrew-calendar-m1', 'hebrew-calendar-m2', @@ -2345,11 +2551,13 @@ $wgMessageStructure = array( 'signatures' => array( 'signature', 'signature-anon', + 'timezone-utc', ), 'CoreParserFunctions' => array( 'unknown_extension_tag', ), 'version' => array( + 'version', 'version-extensions', 'version-specialpages', 'version-parserhooks', @@ -2375,12 +2583,44 @@ $wgMessageStructure = array( 'filepath-submit', 'filepath-summary', ), + 'fileduplicatesearch' => array( + 'fileduplicatesearch', + 'fileduplicatesearch-summary', + 'fileduplicatesearch-legend', + 'fileduplicatesearch-filename', + 'fileduplicatesearch-submit', + 'fileduplicatesearch-info', + 'fileduplicatesearch-result-1', + 'fileduplicatesearch-result-n', + ), + 'special-specialpages' => array( + 'specialpages', + 'specialpages-summary', + 'specialpages-note', + 'specialpages-group-maintenance', + 'specialpages-group-other', + 'specialpages-group-login', + 'specialpages-group-changes', + 'specialpages-group-media', + 'specialpages-group-users', + 'specialpages-group-highuse', + 'specialpages-group-pages', + 'specialpages-group-pagetools', + 'specialpages-group-wiki', + 'specialpages-group-redirects', + 'specialpages-group-spam', + ), + 'special-blank' => array( + 'blankpage', + 'intentionallyblankpage', + ), ); + /** Comments for each block */ $wgBlockComments = array( 'sidebar' => "The sidebar for MonoBook is generated from this message, lines that do not begin with * or ** are discarded, furthermore lines that do begin with ** and -do not contain | are also discarded, but don't depend on this behaviour for +do not contain | are also discarded, but do not depend on this behaviour for future releases. Also note that since each list value is wrapped in a unique XHTML id it should only appear once and include characters that are legal XHTML id names.", @@ -2388,7 +2628,7 @@ XHTML id names.", 'underline' => '', 'skinpreview' => '', 'dates' => 'Dates', - 'categories' => 'Bits of text used by many pages', + 'categorypages' => 'Categories related messages', 'mainpage' => '', 'miscellaneous1' => '', 'metadata_help' => 'Metadata in edit box', @@ -2400,25 +2640,29 @@ XHTML id names.", 'nstab' => "Short words for each namespace, by default used in the namespace tab in monobook", 'main' => 'Main script and global functions', 'errors' => 'General errors', + 'virus' => 'Virus scanner', 'login' => 'Login and logout pages', 'resetpass' => 'Password reset dialog', 'toolbar' => 'Edit page toolbar', 'edit' => 'Edit pages', + 'parserwarnings' => 'Parser/template warnings', 'undo' => '"Undo" feature', 'cantcreateaccount' => 'Account creation failure', 'history' => 'History pages', 'history-feed' => 'Revision feed', 'revdelete' => 'Revision deletion', - 'oversightlog' => 'Oversight log', + 'suppression' => 'Suppression log', 'mergehistory' => 'History merging', 'mergelog' => 'Merge log', 'diffs' => 'Diffs', 'search' => 'Search results', + 'opensearch' => 'OpenSearch description', 'preferences' => 'Preferences page', 'userrights' => 'User rights', 'group' => 'Groups', 'group-member' => '', 'grouppage' => '', + 'right' => 'Rights', 'rightslog' => 'User rights log', 'recentchanges' => 'Recent changes', 'recentchangeslinked' => 'Recent changes linked', @@ -2426,9 +2670,10 @@ XHTML id names.", 'upload-errors' => '', 'upload-curl-errors' => 'Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>', 'licenses' => '', - 'imagelist' => 'Image list', + 'imagelist' => 'Special:ImageList', + 'imagedesciption' => 'Image description page', 'filerevert' => 'File reversion', - 'filedelete' => 'File deletion', + 'filedelete' => 'File deletion', 'mimesearch' => 'MIME search', 'unwatchedpages' => 'Unwatched pages', 'listredirects' => 'List redirects', @@ -2443,13 +2688,15 @@ XHTML id names.", 'fewestrevisions' => '', 'specialpages' => 'Miscellaneous special pages', 'booksources' => 'Book sources', - 'specialpages2' => '', + 'magicwords' => 'Magic words', 'logpages' => 'Special:Log', - 'allpages' => 'Special:Allpages', - 'listusers' => 'Special:Listusers', + 'allpages' => 'Special:AllPages', + 'categories' => 'Special:Categories', + 'listusers' => 'Special:ListUsers', + 'listgrouprights' => 'Special:ListGroupRights', 'emailuser' => 'E-mail user', 'watchlist' => 'Watchlist', - 'watching' => 'Displayed when you click the "watch" button and it\'s in the process of watching', + 'watching' => 'Displayed when you click the "watch" button and it is in the process of watching', 'enotif' => '', 'deleteprotectrev' => 'Delete/protect/revert', 'restrictions' => 'Restrictions (nouns)', @@ -2458,7 +2705,6 @@ XHTML id names.", 'nsform' => 'Namespace form on various pages', 'contributions' => 'Contributions', 'sp-contributions' => '', - 'newimages-showfrom' => '', 'whatlinkshere' => 'What links here', 'block' => 'Block/unblock', 'developertools' => 'Developer tools', @@ -2481,7 +2727,7 @@ XHTML id names.", 'patrol-log' => 'Patrol log', 'imagedeletion' => 'Image deletion', 'browsediffs' => 'Browsing diffs', - 'newimages' => 'Special:Newimages', + 'newimages' => 'Special:NewImages', 'video-info' => 'Video information, used by Language::formatTimePeriod() to format lengths in the above messages', 'badimagelist' => 'Bad image list', 'variantname-zh' => "Short names for language variants used for language conversion links. @@ -2491,6 +2737,7 @@ Variants for Chinese language", 'variantname-sr' => 'Variants for Serbian language', 'variantname-kk' => 'Variants for Kazakh language', 'variantname-ku' => 'Variants for Kurdish language', + 'variantname-tg' => 'Variants for Tajiki language', 'media-info' => 'Media information', 'metadata' => 'Metadata', 'exif' => 'EXIF tags', @@ -2536,7 +2783,7 @@ Variants for Chinese language", 'htmldump' => 'HTML dump', 'purge' => 'action=purge', 'search2' => 'AJAX search', - 'separators' => 'Separators for various lists', + 'separators' => 'Separators for various lists, etc.', 'imgmulti' => 'Multipage image navigation', 'tablepager' => 'Table pager', 'autosumm' => 'Auto-summaries', @@ -2547,15 +2794,20 @@ Variants for Chinese language", 'watchlisteditor' => 'Watchlist editor', 'watchlisttools' => 'Watchlist editing tools', 'iranian-dates' => 'Iranian month names', + 'hijri-dates' => 'Hijri month names', 'hebrew-dates' => 'Hebrew month names', 'signatures' => 'Signatures', 'CoreParserFunctions' => 'Core parser functions', 'version' => 'Special:Version', - 'filepath' => 'Special:Filepath', + 'filepath' => 'Special:FilePath', + 'fileduplicatesearch' => 'Special:FileDuplicateSearch', + 'special-specialpages' => 'Special:SpecialPages', + 'special-blank' => 'Special:BlankPage', ); /** Short comments for standalone messages */ $wgMessageComments = array( + 'hidden-category-category' => 'Name of the category where hidden categories will be listed', 'lastmodifiedat' => '$1 date, $2 time', 'sitenotice' => 'the equivalent to wgSiteNotice', 'history-feed-item-nocomment' => 'user at time', @@ -2573,4 +2825,6 @@ $wgMessageComments = array( 'movepage-moved' => 'The two titles are passed in plain text as $3 and $4 to allow additional goodies in the message.', 'ipboptions' => 'display1:time1,display2:time2,...', 'metadata-fields' => 'Do not translate list items', + 'version' => 'Not used as normal message but as header for the special page itself', + 'userrights' => 'Not used as normal message but as header for the special page itself', ); diff --git a/maintenance/language/rebuildLanguage.php b/maintenance/language/rebuildLanguage.php index 6c2076eb..91fda3f4 100644 --- a/maintenance/language/rebuildLanguage.php +++ b/maintenance/language/rebuildLanguage.php @@ -1,8 +1,10 @@ <?php /** - * Rewrite the messages array in the files languages/messages/MessagesXX.php. + * Rewrite the messages array in the files languages/messages/MessagesXx.php. * - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage + * @defgroup MaintenanceLanguage MaintenanceLanguage */ require_once( dirname(__FILE__).'/../commandLine.inc' ); @@ -15,12 +17,13 @@ require_once( 'writeMessagesArray.inc' ); * @param $code The language code. * @param $write Write to the messages file? * @param $listUnknown List the unknown messages? + * @param $removeUnKnown Remove the unknown messages? */ -function rebuildLanguage( $code, $write, $listUnknown ) { +function rebuildLanguage( $code, $write, $listUnknown, $removeUnknown ) { global $wgLanguages; $messages = $wgLanguages->getMessages( $code ); $messages = $messages['all']; - MessageWriter::writeMessagesToFile( $messages, $code, $write, $listUnknown ); + MessageWriter::writeMessagesToFile( $messages, $code, $write, $listUnknown, $removeUnknown ); } # Show help @@ -31,8 +34,9 @@ Parameters: * lang: Language code (default: the installation default language). You can also specify "all" to check all the languages. * help: Show this help. Options: - * dry-run: Don't write the array to the file. - * no-unknown: Don't list the unknown messages. + * dry-run: Do not write the array to the file. + * no-unknown: Do not list the unknown messages. + * remove-unknown: Remove unknown messages. END; exit(); @@ -48,6 +52,7 @@ if ( isset( $options['lang'] ) ) { # Get the options $wgWriteToFile = !isset( $options['dry-run'] ); $wgListUnknownMessages = !isset( $options['no-unknown'] ); +$wgRemoveUnknownMessages = isset( $options['remove-unknown'] ); # Get language objects $wgLanguages = new languages(); @@ -55,10 +60,8 @@ $wgLanguages = new languages(); # Write all the language if ( $wgCode == 'all' ) { foreach ( $wgLanguages->getLanguages() as $language ) { - rebuildLanguage( $language, $wgWriteToFile, $wgListUnknownMessages ); + rebuildLanguage( $language, $wgWriteToFile, $wgListUnknownMessages, $wgRemoveUnknownMessages ); } } else { - rebuildLanguage( $wgCode, $wgWriteToFile, $wgListUnknownMessages ); + rebuildLanguage( $wgCode, $wgWriteToFile, $wgListUnknownMessages, $wgRemoveUnknownMessages ); } - - diff --git a/maintenance/language/transstat.php b/maintenance/language/transstat.php index 410bd695..ee2b844c 100644 --- a/maintenance/language/transstat.php +++ b/maintenance/language/transstat.php @@ -2,7 +2,8 @@ /** * Statistics about the localisation. * - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage * * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> * @author Ashar Voultoiz <thoane@altern.org> diff --git a/maintenance/language/validate.php b/maintenance/language/validate.php index 5e96c2d2..e84aa29d 100644 --- a/maintenance/language/validate.php +++ b/maintenance/language/validate.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup MaintenanceLanguage + */ if ( !isset( $argv[1] ) ) { print "Usage: php {$argv[0]} <filename>\n"; diff --git a/maintenance/language/writeMessagesArray.inc b/maintenance/language/writeMessagesArray.inc index 2324785e..3a279cb6 100644 --- a/maintenance/language/writeMessagesArray.inc +++ b/maintenance/language/writeMessagesArray.inc @@ -2,14 +2,17 @@ /** * Write a messages array as a PHP text. * - * @addtogroup Maintenance + * @file + * @ingroup MaintenanceLanguage */ +/** + * @ingroup MaintenanceLanguage + */ class MessageWriter { static $optionalComment = 'only translate this message to other languages if you have to change it'; - static $ignoredComment = "don't translate or duplicate this message to other languages"; + static $ignoredComment = "do not translate or duplicate this message to other languages"; - static $loaded = false; static $messageStructure; static $blockComments; static $messageComments; @@ -24,9 +27,9 @@ class MessageWriter { * @param $write Write to the messages file? * @param $listUnknown List the unknown messages? */ - public static function writeMessagesToFile( $messages, $code, $write, $listUnknown ) { + public static function writeMessagesToFile( $messages, $code, $write, $listUnknown, $removeUnknown ) { # Rewrite the messages array - $messages = self::writeMessagesArray( $messages, $code == 'en' ); + $messages = self::writeMessagesArray( $messages, $code == 'en', false, $removeUnknown ); $messagesText = $messages[0]; $sortedMessages = $messages[1]; @@ -48,13 +51,16 @@ class MessageWriter { } } if( $listUnknown && isset( $sortedMessages['unknown'] ) && !empty( $sortedMessages['unknown'] ) ) { - echo "\nThere are " . count( $sortedMessages['unknown'] ) . " unknown messages, please check them:\n"; + if ( $removeUnknown ) + echo "\nThe following " . count( $sortedMessages['unknown'] ) . " unknown messages have been removed:\n"; + else + echo "\nThere are " . count( $sortedMessages['unknown'] ) . " unknown messages, please check them:\n"; foreach( $sortedMessages['unknown'] as $key => $value ) { echo "* " . $key . "\n"; } } } else { - echo "Generated messages for language $code. There seems to be no messages array in the file.\n"; + echo "Generated messages for language $code. There seem to be no messages array in the file.\n"; } } @@ -66,20 +72,19 @@ class MessageWriter { * * @return Array of the PHP text and the sorted messages array. */ - public static function writeMessagesArray( $messages, $ignoredComments = false ) { + public static function writeMessagesArray( $messages, $ignoredComments = false, $prefix = false, $removeUnknown = false ) { # Load messages - if( !self::$loaded ) { - require( dirname( __FILE__ ) . '/messages.inc' ); - self::$messageStructure = $wgMessageStructure; - self::$blockComments = $wgBlockComments; - self::$messageComments = $wgMessageComments; + $dir = $prefix ? $prefix : dirname( __FILE__ ); - require( dirname( __FILE__ ) . '/messageTypes.inc' ); - self::$ignoredMessages = $wgIgnoredMessages; - self::$optionalMessages = $wgOptionalMessages; + require( $dir . '/messages.inc' ); + self::$messageStructure = $wgMessageStructure; + self::$blockComments = $wgBlockComments; + self::$messageComments = $wgMessageComments; + + require( $dir . '/messageTypes.inc' ); + self::$ignoredMessages = $wgIgnoredMessages; + self::$optionalMessages = $wgOptionalMessages; - self::$loaded = true; - } # Sort messages to blocks $sortedMessages['unknown'] = $messages; @@ -115,12 +120,13 @@ class MessageWriter { } # Write the unknown messages, alphabetically sorted. - # Of course, we don't have any comments for them, because the are unknown. - ksort( $sortedMessages['unknown'] ); - $messagesText .= self::writeMessagesBlock( 'Unknown messages', $sortedMessages['unknown'] ); + # Of course, we don't have any comments for them, because they are unknown. + if ( !$removeUnknown ) { + ksort( $sortedMessages['unknown'] ); + $messagesText .= self::writeMessagesBlock( 'Unknown messages', $sortedMessages['unknown'] ); + } $messagesText .= "); "; - return array( $messagesText, $sortedMessages ); } diff --git a/maintenance/mcc.php b/maintenance/mcc.php index 97a344fb..89605871 100644 --- a/maintenance/mcc.php +++ b/maintenance/mcc.php @@ -2,8 +2,9 @@ /** * memcached diagnostic tool * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** */ diff --git a/maintenance/mctest.php b/maintenance/mctest.php index 3ceda8e1..aef6d6db 100644 --- a/maintenance/mctest.php +++ b/maintenance/mctest.php @@ -1,5 +1,12 @@ <?php -/* $Id: mctest.php 23531 2007-06-29 01:19:14Z simetrical $ */ +/** + * This script makes several 'set', 'incr' and 'get' requests on every + * memcached server and shows a report. + * + * $Id: mctest.php 37886 2008-07-21 17:06:35Z greg $ + * @file + * @ingroup Maintenance + */ $optionsWithArgs = array( 'i' ); diff --git a/maintenance/moveBatch.php b/maintenance/moveBatch.php index f30bb591..52e6ddc6 100644 --- a/maintenance/moveBatch.php +++ b/maintenance/moveBatch.php @@ -3,7 +3,8 @@ /** * Maintenance script to move a batch of pages * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Tim Starling * * USAGE: php moveBatch.php [-u <user>] [-r <reason>] [-i <interval>] <listfile> diff --git a/maintenance/mssql/README b/maintenance/mssql/README new file mode 100644 index 00000000..bcdeb82a --- /dev/null +++ b/maintenance/mssql/README @@ -0,0 +1,78 @@ +== Syntax differences between MySQL and MSSQL == +{| border cellspacing=0 cellpadding=4 +!MySQL!!MSSQL +|- + +|AUTO_INCREMENT +|IDENTITY(1,1) +|- + +|binary +|varchar NULL ''(MSSQL doesn't allow setting of binary's to string values, and won't implicitly allow NULL's)'' +|- + +|bool +|bit +|- + +|[UN]SIGNED +|''not valid'' +|- + +|SELECT * FROM foo LIMIT x +|SELECT TOP x * FROM foo +|- + +|SELECT * FROM foo LIMIT x,y| +''not sure how to implement yet because it must be applied from within '''DatabaseMssql::limitResult''''' +|- + +|INSERT IGNORE INTO foo (foo_id,bar) VALUES ('1','xyz') +|IF NOT EXISTS (SELECT * FROM foo WHERE foo_id = '1') INSERT INTO foo (foo_id,bar) VALUES ('1','xyz') +|- + +|IF(cond,trueVal,falseVal) +|CASE WHEN cond THEN trueVal ELSE falseVal END +|- + +|SHOW TABLES +|SELECT * FROM INFORMATION_SCHEMA.TABLES +|- + +|ENUM +|''not natively supported, change to text'' +|} + +== MSSQL Variables == +{| border cellspacing=0 cellpadding=4 + +|@@VERSION +|Server version information +|- + +|@@IDENTITY +|Last inserted row +|- + +|@@ERROR +|Last error number +|} + +== Changes to INSERT wrapper == +=== AUTOINCREMENT vs IDENTITY === +MySQL style ''AUTOINCREMENT'' columns are inplemented in MSSQL using ''IDENTITY(x,y)'' where ''x'' is the initial value and ''y'' is the amount to add on each insert. The last value resulting from an insert into an IDENTITY column is stored in the ''@@IDENTITY'' variable. These kinds of columns are usually used as primary keys and are therefore assigned the ''NOT NULL'' property. + +In MySQL the standard way of inserting data into rows exhibiting AUTOINCREMENT columns is simply to use a ''NULL'' value which will be ignored. In MSSQL however assigning a ''NULL'' to an ''IDENTITY'' column is not allowed, instead the best way is not to include those items in the list of columns to be updated at all. + +To get round this in the MediaWiki MSSQL layer, I've modified the insert wrapper in the ''DatabaseMssql'' class to check if the primary key is used in the insert and remove it if so. It checks this by assuming that the primary key will be of the same name as the table but with ''_id'' on the end, and that it will the first item in the list of columns to update. + +=== IGNORE === +As you can see from the comparison table above, the MySQL ''INSERT IGNORE'' option takes quite a different form in MSSQL. This is handled in the ''insert'' wrapper method. In the case of multiple row inserts, a separate conditional insert query is performed for each item. + +== NULL values and NOT NULL columns == +MySQL implicitly casts NULL assignments to NOT NULL columns to an empty string or zero value accordingly, but MSSQL raises an error instead. This is a big problem within the MediaWiki environment because the code relies heavily on this implicit NULL casting. I've tried to get round the problem by replacing NULL's with empty strings from update and insert queries, and MSSQL is happy to cast the empty string to a numeric zero if necessary. + +== See also == +*[http://msdn.microsoft.com/en-us/library/ms188783.aspx MSSQL reference] +*[http://doc.ddart.net/mssql/sql70/ca-co_1.htm Type casting] +*[http://msdn.microsoft.com/en-us/library/ms187752.aspx TransactSQL datatypes] diff --git a/maintenance/mssql/tables.sql b/maintenance/mssql/tables.sql new file mode 100644 index 00000000..24847330 --- /dev/null +++ b/maintenance/mssql/tables.sql @@ -0,0 +1,395 @@ +CREATE TABLE /*$wgDBprefix*/user ( + user_id int NOT NULL IDENTITY(1,1), + user_name varchar(255) NOT NULL default '', + user_real_name varchar(255) NOT NULL default '', + user_password text NOT NULL, + user_newpassword text NOT NULL, + user_newpass_time varchar(5) NULL, + user_email text NOT NULL, + user_options text NOT NULL, + user_touched varchar(5) NOT NULL default '', + user_token varchar(10) NOT NULL default '', + user_email_authenticated varchar(5) NULL, + user_email_token varchar(10) NULL, + user_email_token_expires varchar(5) NULL, + user_registration varchar(5) NULL, + user_editcount int, + PRIMARY KEY (user_id) +); + +CREATE TABLE /*$wgDBprefix*/user_groups ( + ug_user int NOT NULL default '0', + ug_group varchar(5) NOT NULL default '', + PRIMARY KEY (ug_user,ug_group) +); + +CREATE TABLE /*$wgDBprefix*/user_newtalk ( + user_id int NOT NULL default '0', + user_ip varchar(13) NOT NULL default '', + user_last_timestamp varchar(5) NOT NULL default '' +); + +CREATE TABLE /*$wgDBprefix*/page ( + page_id int NOT NULL IDENTITY(1,1), + page_namespace int NOT NULL, + page_title varchar(255) NOT NULL, + page_restrictions text NOT NULL, + page_counter bigint NOT NULL default '0', + page_is_redirect tinyint NOT NULL default '0', + page_is_new tinyint NOT NULL default '0', + page_random real NOT NULL, + page_touched varchar(5) NOT NULL default '', + page_latest int NOT NULL, + page_len int NOT NULL, + PRIMARY KEY (page_id) +); + +CREATE TABLE /*$wgDBprefix*/revision ( + rev_id int NOT NULL IDENTITY(1,1), + rev_page int NOT NULL, + rev_text_id int NOT NULL, + rev_comment text NOT NULL, + rev_user int NOT NULL default '0', + rev_user_text varchar(255) NOT NULL default '', + rev_timestamp varchar(5) NOT NULL default '', + rev_minor_edit tinyint NOT NULL default '0', + rev_deleted tinyint NOT NULL default '0', + rev_len int, + rev_parent_id int default NULL, + PRIMARY KEY (rev_page, rev_id) +); + +CREATE TABLE /*$wgDBprefix*/text ( + old_id int NOT NULL IDENTITY(1,1), + old_text text NOT NULL, + old_flags text NOT NULL, + PRIMARY KEY (old_id) +); + +CREATE TABLE /*$wgDBprefix*/archive ( + ar_namespace int NOT NULL default '0', + ar_title varchar(255) NOT NULL default '', + ar_text text NOT NULL, + ar_comment text NOT NULL, + ar_user int NOT NULL default '0', + ar_user_text varchar(255) NOT NULL, + ar_timestamp varchar(5) NOT NULL default '', + ar_minor_edit tinyint NOT NULL default '0', + ar_flags text NOT NULL, + ar_rev_id int, + ar_text_id int, + ar_deleted tinyint NOT NULL default '0', + ar_len int, + ar_page_id int, + ar_parent_id int default NULL +); + +CREATE TABLE /*$wgDBprefix*/pagelinks ( + pl_from int NOT NULL default '0', + pl_namespace int NOT NULL default '0', + pl_title varchar(255) NOT NULL default '' +); + +CREATE TABLE /*$wgDBprefix*/templatelinks ( + tl_from int NOT NULL default '0', + tl_namespace int NOT NULL default '0', + tl_title varchar(255) NOT NULL default '' +); + +CREATE TABLE /*$wgDBprefix*/imagelinks ( + il_from int NOT NULL default '0', + il_to varchar(255) NOT NULL default '' +); + +CREATE TABLE /*$wgDBprefix*/categorylinks ( + cl_from int NOT NULL default '0', + cl_to varchar(255) NOT NULL default '', + cl_sortkey varchar(70) NOT NULL default '', + cl_timestamp timestamp NOT NULL +); + +CREATE TABLE /*$wgDBprefix*/category ( + cat_id int NOT NULL IDENTITY(1,1), + cat_title varchar(255) NOT NULL, + cat_pages int NOT NULL default 0, + cat_subcats int NOT NULL default 0, + cat_files int NOT NULL default 0, + cat_hidden tinyint NOT NULL default 0, + PRIMARY KEY (cat_id) +); + +CREATE TABLE /*$wgDBprefix*/externallinks ( + el_from int NOT NULL default '0', + el_to text NOT NULL, + el_index text NOT NULL +); + +CREATE TABLE /*$wgDBprefix*/langlinks ( + ll_from int NOT NULL default '0', + ll_lang varchar(7) NOT NULL default '', + ll_title varchar(255) NOT NULL default '' +); + +CREATE TABLE /*$wgDBprefix*/site_stats ( + ss_row_id int NOT NULL, + ss_total_views bigint default '0', + ss_total_edits bigint default '0', + ss_good_articles bigint default '0', + ss_total_pages bigint default '-1', + ss_users bigint default '-1', + ss_admins int default '-1', + ss_images int default '0' +); + +CREATE TABLE /*$wgDBprefix*/hitcounter ( + hc_id int NOT NULL +); + +CREATE TABLE /*$wgDBprefix*/ipblocks ( + ipb_id int NOT NULL IDENTITY(1,1), + ipb_address text NOT NULL, + ipb_user int NOT NULL default '0', + ipb_by int NOT NULL default '0', + ipb_by_text varchar(255) NOT NULL default '', + ipb_reason text NOT NULL, + ipb_timestamp varchar(5) NOT NULL default '', + ipb_auto bit NOT NULL default 0, + ipb_anon_only bit NOT NULL default 0, + ipb_create_account bit NOT NULL default 1, + ipb_enable_autoblock bit NOT NULL default '1', + ipb_expiry varchar(5) NOT NULL default '', + ipb_range_start text NOT NULL, + ipb_range_end text NOT NULL, + ipb_deleted bit NOT NULL default 0, + ipb_block_email bit NOT NULL default 0, + PRIMARY KEY (ipb_id) +); + +CREATE TABLE /*$wgDBprefix*/image ( + img_name varchar(255) NOT NULL default '', + img_size int NOT NULL default '0', + img_width int NOT NULL default '0', + img_height int NOT NULL default '0', + img_metadata text NOT NULL, + img_bits int NOT NULL default '0', + img_media_type TEXT default NULL, + img_major_mime TEXT NOT NULL default "unknown", + img_minor_mime varchar(10) NOT NULL default "unknown", + img_description text NOT NULL, + img_user int NOT NULL default '0', + img_user_text varchar(255) NOT NULL, + img_timestamp varchar(5) NOT NULL default '', + img_sha1 varchar(10) NOT NULL default '', + PRIMARY KEY (img_name) +); + +CREATE TABLE /*$wgDBprefix*/oldimage ( + oi_name varchar(255) NOT NULL default '', + oi_archive_name varchar(255) NOT NULL default '', + oi_size int NOT NULL default 0, + oi_width int NOT NULL default 0, + oi_height int NOT NULL default 0, + oi_bits int NOT NULL default 0, + oi_description text NOT NULL, + oi_user int NOT NULL default '0', + oi_user_text varchar(255) NOT NULL, + oi_timestamp varchar(5) NOT NULL default '', + oi_metadata text NOT NULL, + oi_media_type TEXT default NULL, + oi_major_mime TEXT NOT NULL default "unknown", + oi_minor_mime varchar(10) NOT NULL default "unknown", + oi_deleted tinyint NOT NULL default '0', + oi_sha1 varchar(10) NOT NULL default '' +); + +CREATE TABLE /*$wgDBprefix*/filearchive ( + fa_id int NOT NULL IDENTITY(1,1), + fa_name varchar(255) NOT NULL default '', + fa_archive_name varchar(255) NULL default '', + fa_storage_group varchar(5) NULL, + fa_storage_key varchar(17) NULL default '', + fa_deleted_user int, + fa_deleted_timestamp varchar(5) NULL default '', + fa_deleted_reason text, + fa_size int default '0', + fa_width int default '0', + fa_height int default '0', + fa_metadata text, + fa_bits int default '0', + fa_media_type TEXT default NULL, + fa_major_mime TEXT default "unknown", + fa_minor_mime varchar(10) NULL default "unknown", + fa_description text, + fa_user int default '0', + fa_user_text varchar(255) NULL, + fa_timestamp varchar(5) NULL default '', + fa_deleted tinyint NOT NULL default '0', + PRIMARY KEY (fa_id) +); + +CREATE TABLE /*$wgDBprefix*/recentchanges ( + rc_id int NOT NULL IDENTITY(1,1), + rc_timestamp varchar(5) NOT NULL default '', + rc_cur_time varchar(5) NOT NULL default '', + rc_user int NOT NULL default '0', + rc_user_text varchar(255) NOT NULL, + rc_namespace int NOT NULL default '0', + rc_title varchar(255) NOT NULL default '', + rc_comment varchar(255) NOT NULL default '', + rc_minor tinyint NOT NULL default '0', + rc_bot tinyint NOT NULL default '0', + rc_new tinyint NOT NULL default '0', + rc_cur_id int NOT NULL default '0', + rc_this_oldid int NOT NULL default '0', + rc_last_oldid int NOT NULL default '0', + rc_type tinyint NOT NULL default '0', + rc_moved_to_ns tinyint NOT NULL default '0', + rc_moved_to_title varchar(255) NOT NULL default '', + rc_patrolled tinyint NOT NULL default '0', + rc_ip varchar(13) NOT NULL default '', + rc_old_len int, + rc_new_len int, + rc_deleted tinyint NOT NULL default '0', + rc_logid int NOT NULL default '0', + rc_log_type varchar(17) NULL default NULL, + rc_log_action varchar(17) NULL default NULL, + rc_params text NULL, + PRIMARY KEY (rc_id) +); + +CREATE TABLE /*$wgDBprefix*/watchlist ( + wl_user int NOT NULL, + wl_namespace int NOT NULL default '0', + wl_title varchar(255) NOT NULL default '', + wl_notificationtimestamp varchar(5) NULL +); + +CREATE TABLE /*$wgDBprefix*/math ( + math_inputhash varchar(5) NOT NULL, + math_outputhash varchar(5) NOT NULL, + math_html_conservativeness tinyint NOT NULL, + math_html text, + math_mathml text +); + +CREATE TABLE /*$wgDBprefix*/searchindex ( + si_page int NOT NULL, + si_title varchar(255) NOT NULL default '', + si_text text NOT NULL +); + +CREATE TABLE /*$wgDBprefix*/interwiki ( + iw_prefix varchar(32) NOT NULL, + iw_url text NOT NULL, + iw_local bit NOT NULL, + iw_trans tinyint NOT NULL default 0 +); + +CREATE TABLE /*$wgDBprefix*/querycache ( + qc_type varchar(10) NOT NULL, + qc_value int NOT NULL default '0', + qc_namespace int NOT NULL default '0', + qc_title varchar(255) NOT NULL default '' +); + +CREATE TABLE /*$wgDBprefix*/objectcache ( + keyname varchar(17) NOT NULL default '', + value text, + exptime datetime +); + +CREATE TABLE /*$wgDBprefix*/transcache ( + tc_url varchar(17) NOT NULL, + tc_contents text, + tc_time int NOT NULL +); + +CREATE TABLE /*$wgDBprefix*/logging ( + log_id int NOT NULL IDENTITY(1,1), + log_type varchar(4) NOT NULL default '', + log_action varchar(4) NOT NULL default '', + log_timestamp varchar(5) NOT NULL default '19700101000000', + log_user int NOT NULL default 0, + log_namespace int NOT NULL default 0, + log_title varchar(255) NOT NULL default '', + log_comment varchar(255) NOT NULL default '', + log_params text NOT NULL, + log_deleted tinyint NOT NULL default '0', + PRIMARY KEY (log_id) +); + +CREATE TABLE /*$wgDBprefix*/trackbacks ( + tb_id int IDENTITY(1,1), + tb_page int REFERENCES /*$wgDBprefix*/page(page_id) ON DELETE CASCADE, + tb_title varchar(255) NOT NULL, + tb_url text NOT NULL, + tb_ex text, + tb_name varchar(255) NULL, + PRIMARY KEY (tb_id) +); + +CREATE TABLE /*$wgDBprefix*/job ( + job_id int NOT NULL IDENTITY(1,1), + job_cmd varchar(17) NOT NULL default '', + job_namespace int NOT NULL, + job_title varchar(255) NOT NULL, + job_params text NOT NULL, + PRIMARY KEY (job_id) +); + +CREATE TABLE /*$wgDBprefix*/querycache_info ( + qci_type varchar(10) NOT NULL default '', + qci_timestamp varchar(5) NOT NULL default '19700101000000' +); + +CREATE TABLE /*$wgDBprefix*/redirect ( + rd_from int NOT NULL default '0', + rd_namespace int NOT NULL default '0', + rd_title varchar(255) NOT NULL default '', + PRIMARY KEY (rd_from) +); + +CREATE TABLE /*$wgDBprefix*/querycachetwo ( + qcc_type varchar(10) NOT NULL, + qcc_value int NOT NULL default '0', + qcc_namespace int NOT NULL default '0', + qcc_title varchar(255) NOT NULL default '', + qcc_namespacetwo int NOT NULL default '0', + qcc_titletwo varchar(255) NOT NULL default '' +); + +CREATE TABLE /*$wgDBprefix*/page_restrictions ( + pr_page int NOT NULL, + pr_type varchar(17) NOT NULL, + pr_level varchar(17) NOT NULL, + pr_cascade tinyint NOT NULL, + pr_user int NULL, + pr_expiry varchar(5) NULL, + pr_id int NOT NULL IDENTITY(1,1), + PRIMARY KEY (pr_page,pr_type) +); + +CREATE TABLE /*$wgDBprefix*/protected_titles ( + pt_namespace int NOT NULL, + pt_title varchar(255) NOT NULL, + pt_user int NOT NULL, + pt_reason text, + pt_timestamp varchar(5) NOT NULL, + pt_expiry varchar(5) NOT NULL default '', + pt_create_perm varchar(17) NOT NULL, + PRIMARY KEY (pt_namespace,pt_title) +); + +CREATE TABLE /*$wgDBprefix*/page_props ( + pp_page int NOT NULL, + pp_propname varchar(17) NOT NULL, + pp_value text NOT NULL, + PRIMARY KEY (pp_page,pp_propname) +); + +CREATE TABLE /*$wgDBprefix*/updatelog ( + ul_key varchar(255) NOT NULL, + PRIMARY KEY (ul_key) +); + + diff --git a/maintenance/mwdocgen.php b/maintenance/mwdocgen.php index d66e6874..378229e0 100644 --- a/maintenance/mwdocgen.php +++ b/maintenance/mwdocgen.php @@ -17,8 +17,9 @@ * - the menu doesnt work, got disabled at revision 13740. Need to code it. * * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance * * @author Ashar Voultoiz <thoane@altern.org> * @version first release @@ -45,6 +46,9 @@ $doxygenBin = 'doxygen'; /** doxygen configuration template for mediawiki */ $doxygenTemplate = $mwPath . 'maintenance/Doxyfile'; +/** svnstat command, used to get the version of each file */ +$svnstat = $mwPath . 'bin/svnstat'; + /** where Phpdoc should output documentation */ #$doxyOutput = '/var/www/mwdoc/'; $doxyOutput = $mwPath . 'docs' . DIRECTORY_SEPARATOR ; @@ -58,47 +62,87 @@ $mwPathS = $mwPath.'skins/'; /** Variable to get user input */ $input = ''; -/** shell command that will be run */ -$command = $doxygenBin; - # # Functions # -function readaline( $prompt = '') { +/** + * Read a line from the shell + * @param $prompt String + */ +function readaline( $prompt = '' ){ print $prompt; $fp = fopen( "php://stdin", "r" ); $resp = trim( fgets( $fp, 1024 ) ); fclose( $fp ); return $resp; +} + +/** + * Copied from SpecialVersion::getSvnRevision() + * @param $dir String + * @return Mixed: string or false + */ +function getSvnRevision( $dir ) { + // http://svnbook.red-bean.com/nightly/en/svn.developer.insidewc.html + $entries = $dir . '/.svn/entries'; + + if( !file_exists( $entries ) ) { + return false; } + $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] ); + } +} + /** * Generate a configuration file given user parameters and return the temporary filename. * @param $doxygenTemplate String: full path for the template. * @param $outputDirectory String: directory where the stuff will be output. * @param $stripFromPath String: path that should be stripped out (usually mediawiki base path). + * @param $currentVersion String: Version number of the software + * @param $svnstat String: path to the svnstat file * @param $input String: Path to analyze. */ -function generateConfigFile($doxygenTemplate, $outputDirectory, $stripFromPath, $input) { - global $tmpPath ; +function generateConfigFile( $doxygenTemplate, $outputDirectory, $stripFromPath, $currentVersion, $svnstat, $input ){ + global $tmpPath; - $template = file_get_contents($doxygenTemplate); + $template = file_get_contents( $doxygenTemplate ); // Replace template placeholders by correct values. - $tmpCfg = str_replace( - array( - '{{OUTPUT_DIRECTORY}}', - '{{STRIP_FROM_PATH}}', - '{{INPUT}}', - ), - array( - $outputDirectory, - $stripFromPath, - $input, - ), - $template - ); + $replacements = array( + '{{OUTPUT_DIRECTORY}}' => $outputDirectory, + '{{STRIP_FROM_PATH}}' => $stripFromPath, + '{{CURRENT_VERSION}}' => $currentVersion, + '{{SVNSTAT}}' => $svnstat, + '{{INPUT}}' => $input, + ); + $tmpCfg = str_replace( array_keys( $replacements ), array_values( $replacements ), $template ); $tmpFileName = $tmpPath . 'mwdocgen'. rand() .'.tmp'; file_put_contents( $tmpFileName , $tmpCfg ) or die("Could not write doxygen configuration to file $tmpFileName\n"); @@ -127,14 +171,18 @@ if( is_array( $argv ) && isset( $argv[1] ) ) { } } +// TODO : generate a list of paths )) + if( $input === '' ) { -?>Several documentation possibilities: + echo <<<OPTIONS +Several documentation possibilities: 0 : whole documentation (1 + 2 + 3 + 4) 1 : only includes 2 : only languages 3 : only maintenance 4 : only skins - 5 : only a given file<?php + 5 : only a given file +OPTIONS; while ( !is_numeric($input) ) { $input = readaline( "\nEnter your choice [0]:" ); @@ -143,62 +191,48 @@ if( $input === '' ) { } } } -/* + switch ($input) { -case 0: - $command .= " -f $mwBaseFiles -d $mwPathI,$mwPathL,$mwPathM,$mwPathS"; - break; -case 1: - $command .= "-d $mwPathI"; - break; -case 2: - $command .= "-d $mwPathL"; - break; -case 3: - $command .= "-d $mwPathM"; - break; -case 4: - $command .= "-d $mwPathS"; - break; +case 0: $input = $mwPath; break; +case 1: $input = $mwPathI; break; +case 2: $input = $mwPathL; break; +case 3: $input = $mwPathM; break; +case 4: $input = $mwPathS; break; case 5: if( !isset( $file ) ) { - $file = readaline("Enter file name $mwPath"); + $file = readaline( "Enter file name $mwPath" ); } - $command .= ' -f '.$mwPath.$file; + $input = $mwPath.$file; } -$command .= " -t $pdOutput ".$pdOthers; - -*/ - -// TODO : generate a list of paths )) -$input = $mwPath; +$versionNumber = getSvnRevision( $input ); +if( $versionNumber === false ){ #Not using subversion ? + $svnstat = ''; # Not really useful if subversion not available + $version = 'trunk'; # FIXME +} else { + $version = "trunk (r$versionNumber)"; +} -$generatedConf = generateConfigFile($doxygenTemplate, $doxyOutput, $mwPath, $input ); -$command = $doxygenBin . ' ' . $generatedConf ; +$generatedConf = generateConfigFile( $doxygenTemplate, $doxyOutput, $mwPath, $version, $svnstat, $input ); +$command = $doxygenBin . ' ' . $generatedConf; -?> +echo <<<TEXT --------------------------------------------------- Launching the command: -<?php echo $command ?> +$command --------------------------------------------------- -<?php -passthru($command); +TEXT; -?> +passthru( $command ); + +echo <<<TEXT --------------------------------------------------- Doxygen execution finished. Check above for possible errors. -You might want to deleted the temporary file <?php echo $generatedConf; ?> - -<?php - -# phpdoc -d ./mediawiki/includes/ ./mediawiki/maintenance/ -f ./mediawiki/*php -t ./mwdoc/ -dn 'MediaWiki' --title 'MediaWiki generated documentation' -o 'HTML:frames:DOM/earthli' - -# phpdoc -f ./mediawiki/includes/GlobalFunctions.php -t ./mwdoc/ -dn 'MediaWiki' --title 'MediaWiki generated documentation' -o 'HTML:frames:DOM/earthli' +You might want to deleted the temporary file $generatedConf -?> +TEXT; diff --git a/maintenance/namespace2sql.php b/maintenance/namespace2sql.php index 94bd9671..43a8cc64 100644 --- a/maintenance/namespace2sql.php +++ b/maintenance/namespace2sql.php @@ -1,7 +1,11 @@ <?php -# -# Print SQL to insert namespace names into database. -# This source code is in the public domain. +/** + * Print SQL to insert namespace names into database. + * This source code is in the public domain. + * + * @file + * @ingroup Maintenance + */ require_once( "commandLine.inc" ); diff --git a/maintenance/namespaceDupes.php b/maintenance/namespaceDupes.php index dcde7c61..92296eb9 100644 --- a/maintenance/namespaceDupes.php +++ b/maintenance/namespaceDupes.php @@ -17,6 +17,11 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # http://www.gnu.org/copyleft/gpl.html +/** + * @file + * @ingroup Maintenance + */ + $options = array( 'fix', 'suffix', 'help' ); /** */ diff --git a/maintenance/nextJobDB.php b/maintenance/nextJobDB.php index b2500caf..6af5cbec 100644 --- a/maintenance/nextJobDB.php +++ b/maintenance/nextJobDB.php @@ -1,7 +1,9 @@ <?php - -/* +/** * Pick a database that has pending jobs + * + * @file + * @ingroup Maintenance */ $options = array( 'type' ); @@ -21,19 +23,13 @@ if ( !$pendingDBs ) { $pendingDBs = array(); # Cross-reference DBs by master DB server $dbsByMaster = array(); - $defaultMaster = isset( $wgAlternateMaster['DEFAULT'] ) - ? $wgAlternateMaster['DEFAULT'] - : $wgDBserver; foreach ( $wgLocalDatabases as $db ) { - if ( isset( $wgAlternateMaster[$db] ) ) { - $dbsByMaster[$wgAlternateMaster[$db]][] = $db; - } else { - $dbsByMaster[$defaultMaster][] = $db; - } + $lb = wfGetLB( $db ); + $dbsByMaster[$lb->getServerName(0)][] = $db; } foreach ( $dbsByMaster as $master => $dbs ) { - $dbConn = new Database( $master, $wgDBuser, $wgDBpassword, $dbs[0] ); + $dbConn = wfGetDB( DB_MASTER, array(), $dbs[0] ); $stype = $dbConn->addQuotes($type); # Padding row for MySQL bug diff --git a/maintenance/nukeNS.php b/maintenance/nukeNS.php index 9bf7004b..4f9fe926 100644 --- a/maintenance/nukeNS.php +++ b/maintenance/nukeNS.php @@ -13,7 +13,8 @@ * back up your DB if there's anything in the MediaWiki that is important to * you. * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Steve Sanbeg * based on nukePage by Rob Church */ diff --git a/maintenance/nukePage.inc b/maintenance/nukePage.inc index 804651b1..9ac28034 100644 --- a/maintenance/nukePage.inc +++ b/maintenance/nukePage.inc @@ -3,7 +3,8 @@ /** * Support functions for the nukeArticle script * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/nukePage.php b/maintenance/nukePage.php index f1ebe734..b3bfc762 100644 --- a/maintenance/nukePage.php +++ b/maintenance/nukePage.php @@ -4,7 +4,8 @@ * Erase a page record from the database * Irreversible (can't use standard undelete) and does not update link tables * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/orphans.php b/maintenance/orphans.php index 954117ce..8ecd9b81 100644 --- a/maintenance/orphans.php +++ b/maintenance/orphans.php @@ -23,8 +23,9 @@ * Then, kill the poor widows and orphans. * Man this is depressing. * + * @file * @author <brion@pobox.com> - * @addtogroup Maintenance + * @ingroup Maintenance */ $options = array( 'fix' ); diff --git a/maintenance/ourusers.php b/maintenance/ourusers.php index 8f1e7c06..620393fb 100644 --- a/maintenance/ourusers.php +++ b/maintenance/ourusers.php @@ -1,7 +1,14 @@ <?php /** + * Wikimedia specific + * + * This script generates SQL used to update MySQL users on a hardcoded + * list of hosts. It takes care of setting the wikiuser for every + * database as well as setting up wikiadmin. + * * @todo document - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ /** */ @@ -40,15 +47,17 @@ if ( @$argv[1] == 'yaseo' ) { 'localhost', '10.0.%', '66.230.200.%', + '208.80.152.%', ); } $databases = array( '%wik%', + 'centralauth', ); -print "/*!40100 set old_passwords=1 */;"; -print "/*!40100 set global old_passwords=1 */;"; +print "/*!40100 set old_passwords=1 */;\n"; +print "/*!40100 set global old_passwords=1 */;\n"; foreach( $hosts as $host ) { print "--\n-- $host\n--\n\n-- wikiuser\n\n"; diff --git a/maintenance/parserTests.inc b/maintenance/parserTests.inc index d333d873..2cb85d2c 100644 --- a/maintenance/parserTests.inc +++ b/maintenance/parserTests.inc @@ -20,7 +20,8 @@ /** * @todo Make this more independent of the configuration (and if possible the database) * @todo document - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ /** */ @@ -33,7 +34,7 @@ require_once( "$IP/maintenance/parserTestsStaticParserHook.php" ); require_once( "$IP/maintenance/parserTestsParserTime.php" ); /** - * @addtogroup Maintenance + * @ingroup Maintenance */ class ParserTest { /** @@ -47,6 +48,21 @@ class ParserTest { private $showOutput; /** + * boolean $useTemporaryTables Use temporary tables for the temporary database + */ + private $useTemporaryTables = true; + + /** + * boolean $databaseSetupDone True if the database has been set up + */ + private $databaseSetupDone = false; + + /** + * string $oldTablePrefix Original table prefix + */ + private $oldTablePrefix; + + /** * Sets terminal colorization and diff/quick modes depending on OS and * command-line options (--color and --quick). */ @@ -82,6 +98,10 @@ class ParserTest { if (isset($options['regex'])) { + if ( isset( $options['record'] ) ) { + echo "Warning: --record cannot be used with --regex, disabling --record\n"; + unset( $options['record'] ); + } $this->regex = $options['regex']; } else { # Matches anything @@ -89,11 +109,11 @@ class ParserTest { } if( isset( $options['record'] ) ) { - $this->recorder = new DbTestRecorder( $this->term ); + $this->recorder = new DbTestRecorder( $this ); } elseif( isset( $options['compare'] ) ) { - $this->recorder = new DbTestPreviewer( $this->term ); + $this->recorder = new DbTestPreviewer( $this ); } else { - $this->recorder = new TestRecorder( $this->term ); + $this->recorder = new TestRecorder( $this ); } $this->keepUploads = isset( $options['keep-uploads'] ); @@ -126,10 +146,12 @@ class ParserTest { */ public function runTestsFromFiles( $filenames ) { $this->recorder->start(); + $this->setupDatabase(); $ok = true; foreach( $filenames as $filename ) { $ok = $this->runFile( $filename ) && $ok; } + $this->teardownDatabase(); $this->recorder->report(); $this->recorder->end(); return $ok; @@ -142,10 +164,7 @@ class ParserTest { } else { global $IP; $relative = wfRelativePath( $filename, $IP ); - print $this->term->color( 1 ) . - "Reading tests from \"$relative\"..." . - $this->term->reset() . - "\n"; + $this->showRunFile( $relative ); } $data = array(); @@ -316,7 +335,8 @@ class ParserTest { } else if (preg_match('/\\bcat\\b/i', $opts)) { global $wgOut; $wgOut->addCategoryLinks($output->getCategories()); - $out = $this->tidy ( implode( ' ', $wgOut->getCategoryLinks() ) ); + $cats = $wgOut->getCategoryLinks(); + $out = $this->tidy( implode( ' ', $cats['normal'] ) ); } $result = $this->tidy($result); @@ -352,12 +372,6 @@ class ParserTest { * Ideally this should replace the global configuration entirely. */ private function setupGlobals($opts = '') { - # Save the prefixed / quoted table names for later use when we make the temporaries. - $db = wfGetDB( DB_READ ); - $this->oldTableNames = array(); - foreach( $this->listTables() as $table ) { - $this->oldTableNames[$table] = $db->tableName( $table ); - } if( !isset( $this->uploadDir ) ) { $this->uploadDir = $this->setupUploadDir(); } @@ -405,6 +419,15 @@ class ParserTest { 'wgUseTidy' => false, 'wgDefaultLanguageVariant' => $variant, 'wgVariantArticlePath' => false, + 'wgGroupPermissions' => array( '*' => array( + 'createaccount' => true, + 'read' => true, + 'edit' => true, + 'createpage' => true, + 'createtalk' => true, + ) ), + 'wgDefaultExternalStore' => array(), + 'wgForeignFileRepos' => array(), ); $this->savedGlobals = array(); foreach( $settings as $var => $val ) { @@ -415,9 +438,7 @@ class ParserTest { $GLOBALS['wgLang'] = $langObj; $GLOBALS['wgContLang'] = $langObj; - $GLOBALS['wgLoadBalancer']->loadMasterPos(); //$GLOBALS['wgMessageCache'] = new MessageCache( new BagOStuff(), false, 0, $GLOBALS['wgDBname'] ); - $this->setupDatabase(); global $wgUser; $wgUser = new User(); @@ -435,7 +456,7 @@ class ParserTest { 'site_stats', 'hitcounter', 'ipblocks', 'image', 'oldimage', 'recentchanges', 'watchlist', 'math', 'interwiki', 'querycache', 'objectcache', 'job', 'redirect', 'querycachetwo', - 'archive', 'user_groups' + 'archive', 'user_groups', 'page_props', 'category' ); if ($wgDBtype === 'mysql') @@ -455,98 +476,147 @@ class ParserTest { * the db will be visible to later tests in the run. */ private function setupDatabase() { - static $setupDB = false; global $wgDBprefix; + if ( $this->databaseSetupDone ) { + return; + } + if ( $wgDBprefix === 'parsertest_' ) { + throw new MWException( 'setupDatabase should be called before setupGlobals' ); + } + $this->databaseSetupDone = true; - # Make sure we don't mess with the live DB - if (!$setupDB && $wgDBprefix === 'parsertest_') { - # oh teh horror - $GLOBALS['wgLoadBalancer'] = LoadBalancer::newFromParams( $GLOBALS['wgDBservers'] ); - $db = wfGetDB( DB_MASTER ); - - $tables = $this->listTables(); - - if (!(strcmp($db->getServerVersion(), '4.1') < 0 and stristr($db->getSoftwareLink(), 'MySQL'))) { - # Database that supports CREATE TABLE ... LIKE - global $wgDBtype; - if( $wgDBtype == 'postgres' ) { - $def = 'INCLUDING DEFAULTS'; - } else { - $def = ''; - } - foreach ($tables as $tbl) { - $newTableName = $db->tableName( $tbl ); - $tableName = $this->oldTableNames[$tbl]; - $db->query("CREATE TEMPORARY TABLE $newTableName (LIKE $tableName $def)"); - } + # CREATE TEMPORARY TABLE breaks if there is more than one server + if ( wfGetLB()->getServerCount() != 1 ) { + $this->useTemporaryTables = false; + } + + $temporary = $this->useTemporaryTables ? 'TEMPORARY' : ''; + + $db = wfGetDB( DB_MASTER ); + $tables = $this->listTables(); + + if (!(strcmp($db->getServerVersion(), '4.1') < 0 and stristr($db->getSoftwareLink(), 'MySQL'))) { + # Database that supports CREATE TABLE ... LIKE + global $wgDBtype; + if( $wgDBtype == 'postgres' ) { + $def = 'INCLUDING DEFAULTS'; } else { - # Hack for MySQL versions < 4.1, which don't support - # "CREATE TABLE ... LIKE". Note that - # "CREATE TEMPORARY TABLE ... SELECT * FROM ... LIMIT 0" - # would not create the indexes we need.... - foreach ($tables as $tbl) { - $res = $db->query("SHOW CREATE TABLE {$this->oldTableNames[$tbl]}"); - $row = $db->fetchRow($res); - $create = $row[1]; - $create_tmp = preg_replace('/CREATE TABLE `(.*?)`/', 'CREATE TEMPORARY TABLE `' - . $wgDBprefix . $tbl .'`', $create); - if ($create === $create_tmp) { - # Couldn't do replacement - wfDie("could not create temporary table $tbl"); - } - $db->query($create_tmp); + $def = ''; + } + foreach ($tables as $tbl) { + $oldTableName = $db->tableName( $tbl ); + # Clean up from previous aborted run + if ( $db->tableExists( "`parsertest_$tbl`" ) ) { + $db->query("DROP TABLE `parsertest_$tbl`"); } - + # Create new table + $db->query("CREATE $temporary TABLE `parsertest_$tbl` (LIKE $oldTableName $def)"); + } + } else { + # Hack for MySQL versions < 4.1, which don't support + # "CREATE TABLE ... LIKE". Note that + # "CREATE TEMPORARY TABLE ... SELECT * FROM ... LIMIT 0" + # would not create the indexes we need.... + foreach ($tables as $tbl) { + $oldTableName = $db->tableName( $tbl ); + $res = $db->query("SHOW CREATE TABLE $oldTableName"); + $row = $db->fetchRow($res); + $create = $row[1]; + $create_tmp = preg_replace('/CREATE TABLE `(.*?)`/', + "CREATE $temporary TABLE `parsertest_$tbl`", $create); + if ($create === $create_tmp) { + # Couldn't do replacement + wfDie("could not create temporary table $tbl"); + } + $db->query($create_tmp); } - - # Hack: insert a few Wikipedia in-project interwiki prefixes, - # for testing inter-language links - $db->insert( 'interwiki', array( - array( 'iw_prefix' => 'Wikipedia', - 'iw_url' => 'http://en.wikipedia.org/wiki/$1', - 'iw_local' => 0 ), - array( 'iw_prefix' => 'MeatBall', - 'iw_url' => 'http://www.usemod.com/cgi-bin/mb.pl?$1', - 'iw_local' => 0 ), - array( 'iw_prefix' => 'zh', - 'iw_url' => 'http://zh.wikipedia.org/wiki/$1', - 'iw_local' => 1 ), - array( 'iw_prefix' => 'es', - 'iw_url' => 'http://es.wikipedia.org/wiki/$1', - 'iw_local' => 1 ), - array( 'iw_prefix' => 'fr', - 'iw_url' => 'http://fr.wikipedia.org/wiki/$1', - 'iw_local' => 1 ), - array( 'iw_prefix' => 'ru', - 'iw_url' => 'http://ru.wikipedia.org/wiki/$1', - 'iw_local' => 1 ), - ) ); - - # Hack: Insert an image to work with - $db->insert( 'image', array( - 'img_name' => 'Foobar.jpg', - 'img_size' => 12345, - 'img_description' => 'Some lame file', - 'img_user' => 1, - 'img_user_text' => 'WikiSysop', - 'img_timestamp' => $db->timestamp( '20010115123500' ), - 'img_width' => 1941, - 'img_height' => 220, - 'img_bits' => 24, - 'img_media_type' => MEDIATYPE_BITMAP, - 'img_major_mime' => "image", - 'img_minor_mime' => "jpeg", - 'img_metadata' => serialize( array() ), - ) ); - - # Update certain things in site_stats - $db->insert( 'site_stats', array( 'ss_row_id' => 1, 'ss_images' => 1, 'ss_good_articles' => 1 ) ); - - $setupDB = true; } + + # Hack: insert a few Wikipedia in-project interwiki prefixes, + # for testing inter-language links + $db->insert( '`parsertest_interwiki`', array( + array( 'iw_prefix' => 'Wikipedia', + 'iw_url' => 'http://en.wikipedia.org/wiki/$1', + 'iw_local' => 0 ), + array( 'iw_prefix' => 'MeatBall', + 'iw_url' => 'http://www.usemod.com/cgi-bin/mb.pl?$1', + 'iw_local' => 0 ), + array( 'iw_prefix' => 'zh', + 'iw_url' => 'http://zh.wikipedia.org/wiki/$1', + 'iw_local' => 1 ), + array( 'iw_prefix' => 'es', + 'iw_url' => 'http://es.wikipedia.org/wiki/$1', + 'iw_local' => 1 ), + array( 'iw_prefix' => 'fr', + 'iw_url' => 'http://fr.wikipedia.org/wiki/$1', + 'iw_local' => 1 ), + array( 'iw_prefix' => 'ru', + 'iw_url' => 'http://ru.wikipedia.org/wiki/$1', + 'iw_local' => 1 ), + ) ); + + # Hack: Insert an image to work with + $db->insert( '`parsertest_image`', array( + 'img_name' => 'Foobar.jpg', + 'img_size' => 12345, + 'img_description' => 'Some lame file', + 'img_user' => 1, + 'img_user_text' => 'WikiSysop', + 'img_timestamp' => $db->timestamp( '20010115123500' ), + 'img_width' => 1941, + 'img_height' => 220, + 'img_bits' => 24, + 'img_media_type' => MEDIATYPE_BITMAP, + 'img_major_mime' => "image", + 'img_minor_mime' => "jpeg", + 'img_metadata' => serialize( array() ), + ) ); + + # Update certain things in site_stats + $db->insert( '`parsertest_site_stats`', array( 'ss_row_id' => 1, 'ss_images' => 1, 'ss_good_articles' => 1 ) ); + + # Change the table prefix + $this->oldTablePrefix = $wgDBprefix; + $this->changePrefix( 'parsertest_' ); } /** + * Change the table prefix on all open DB connections/ + */ + protected function changePrefix( $prefix ) { + global $wgDBprefix; + wfGetLBFactory()->forEachLB( array( $this, 'changeLBPrefix' ), array( $prefix ) ); + $wgDBprefix = $prefix; + } + + public function changeLBPrefix( $lb, $prefix ) { + $lb->forEachOpenConnection( array( $this, 'changeDBPrefix' ), array( $prefix ) ); + } + + public function changeDBPrefix( $db, $prefix ) { + $db->tablePrefix( $prefix ); + } + + private function teardownDatabase() { + global $wgDBprefix; + if ( !$this->databaseSetupDone ) { + return; + } + $this->changePrefix( $this->oldTablePrefix ); + $this->databaseSetupDone = false; + if ( $this->useTemporaryTables ) { + # Don't need to do anything + return; + } + + $tables = $this->listTables(); + $db = wfGetDB( DB_MASTER ); + foreach ( $tables as $table ) { + $db->query( "DROP TABLE `parsertest_$table`" ); + } + } + + /** * Create a dummy uploads directory which will contain a couple * of files in order to pass existence tests. * @return string The directory @@ -646,7 +716,7 @@ class ParserTest { /** * "Running test $desc..." */ - private function showTesting( $desc ) { + protected function showTesting( $desc ) { print "Running test $desc... "; } @@ -656,7 +726,7 @@ class ParserTest { * @param string $desc The test name * @return bool */ - private function showSuccess( $desc ) { + protected function showSuccess( $desc ) { if( $this->showProgress ) { print $this->term->color( '1;32' ) . 'PASSED' . $this->term->reset() . "\n"; } @@ -672,7 +742,7 @@ class ParserTest { * @param string $html Actual HTML output * @return bool */ - private function showFailure( $desc, $result, $html ) { + protected function showFailure( $desc, $result, $html ) { if( $this->showFailure ) { if( !$this->showProgress ) { # In quiet mode we didn't show the 'Testing' message before the @@ -703,7 +773,7 @@ class ParserTest { * @param string $outFileTail Tailing for the output file name * @return string */ - private function quickDiff( $input, $output, $inFileTail='expected', $outFileTail='actual' ) { + protected function quickDiff( $input, $output, $inFileTail='expected', $outFileTail='actual' ) { $prefix = wfTempDir() . "/mwParser-" . mt_rand(); $infile = "$prefix-$inFileTail"; @@ -738,7 +808,7 @@ class ParserTest { * @param string $text * @return string */ - private function colorDiff( $text ) { + protected function colorDiff( $text ) { return preg_replace( array( '/^(-.*)$/m', '/^(\+.*)$/m' ), array( $this->term->color( 34 ) . '$1' . $this->term->reset(), @@ -747,6 +817,18 @@ class ParserTest { } /** + * Show "Reading tests from ..." + * + * @param String $path + */ + protected function showRunFile( $path ){ + print $this->term->color( 1 ) . + "Reading tests from \"$path\"..." . + $this->term->reset() . + "\n"; + } + + /** * Insert a temporary test article * @param string $name the title, including any prefix * @param string $text the article text @@ -902,8 +984,12 @@ class DummyTermColorer { } class TestRecorder { - function __construct( $term ) { - $this->term = $term; + var $parent; + var $term; + + function __construct( $parent ) { + $this->parent = $parent; + $this->term = $parent->term; } function start() { @@ -942,14 +1028,21 @@ class TestRecorder { } } -class DbTestRecorder extends TestRecorder { +class DbTestPreviewer extends TestRecorder { + protected $lb; ///< Database load balancer protected $db; ///< Database connection to the main DB protected $curRun; ///< run ID number for the current run protected $prevRun; ///< run ID number for the previous run, if any + protected $results; ///< Result array - function __construct( $term ) { - parent::__construct( $term ); - $this->db = wfGetDB( DB_MASTER ); + /** + * This should be called before the table prefix is changed + */ + function __construct( $parent ) { + parent::__construct( $parent ); + $this->lb = wfGetLBFactory()->newMainLB(); + // This connection will have the wiki's table prefix, not parsertest_ + $this->db = $this->lb->getConnection( DB_MASTER ); } /** @@ -957,81 +1050,82 @@ class DbTestRecorder extends TestRecorder { * and all that fun stuff */ function start() { - global $wgDBtype; + global $wgDBtype, $wgDBprefix; parent::start(); - $this->db->begin(); - - if( ! $this->db->tableExists( 'testrun' ) or ! $this->db->tableExists( 'testitem') ) { - print "WARNING> `testrun` table not found in database. Trying to create table.\n"; - if ($wgDBtype === 'postgres') - dbsource( dirname(__FILE__) . '/testRunner.postgres.sql', $this->db ); - else - dbsource( dirname(__FILE__) . '/testRunner.sql', $this->db ); - echo "OK, resuming.\n"; + if( ! $this->db->tableExists( 'testrun' ) + or ! $this->db->tableExists( 'testitem' ) ) + { + print "WARNING> `testrun` table not found in database.\n"; + $this->prevRun = false; + } else { + // We'll make comparisons against the previous run later... + $this->prevRun = $this->db->selectField( 'testrun', 'MAX(tr_id)' ); } - - // We'll make comparisons against the previous run later... - $this->prevRun = $this->db->selectField( 'testrun', 'MAX(tr_id)' ); - - $this->db->insert( 'testrun', - array( - 'tr_date' => $this->db->timestamp(), - 'tr_mw_version' => SpecialVersion::getVersion(), - 'tr_php_version' => phpversion(), - 'tr_db_version' => $this->db->getServerVersion(), - 'tr_uname' => php_uname() - ), - __METHOD__ ); - if ($wgDBtype === 'postgres') - $this->curRun = $this->db->currentSequenceValue('testrun_id_seq'); - else - $this->curRun = $this->db->insertId(); + $this->results = array(); } - /** - * Record an individual test item's success or failure to the db - * @param string $test - * @param bool $result - */ function record( $test, $result ) { parent::record( $test, $result ); - $this->db->insert( 'testitem', - array( - 'ti_run' => $this->curRun, - 'ti_name' => $test, - 'ti_success' => $result ? 1 : 0, - ), - __METHOD__ ); - } - - /** - * Commit transaction and clean up for result recording - */ - function end() { - $this->db->commit(); - parent::end(); + $this->results[$test] = $result; } function report() { if( $this->prevRun ) { + // f = fail, p = pass, n = nonexistent + // codes show before then after $table = array( - array( 'previously failing test(s) now PASSING! :)', 0, 1 ), - array( 'previously PASSING test(s) removed o_O', 1, null ), - array( 'new PASSING test(s) :)', null, 1 ), - - array( 'previously passing test(s) now FAILING! :(', 1, 0 ), - array( 'previously FAILING test(s) removed O_o', 0, null ), - array( 'new FAILING test(s) :(', null, 0 ), - array( 'still FAILING test(s) :(', 0, 0 ), + 'fp' => 'previously failing test(s) now PASSING! :)', + 'pn' => 'previously PASSING test(s) removed o_O', + 'np' => 'new PASSING test(s) :)', + + 'pf' => 'previously passing test(s) now FAILING! :(', + 'fn' => 'previously FAILING test(s) removed O_o', + 'nf' => 'new FAILING test(s) :(', + 'ff' => 'still FAILING test(s) :(', ); - foreach( $table as $criteria ) { - list( $label, $before, $after ) = $criteria; - $differences = $this->compareResult( $before, $after ); - if( $differences ) { - $count = count($differences); + + $res = $this->db->select( 'testitem', array( 'ti_name', 'ti_success' ), + array( 'ti_run' => $this->prevRun ), __METHOD__ ); + foreach ( $res as $row ) { + if ( !$this->parent->regex + || preg_match( "/{$this->parent->regex}/i", $row->ti_name ) ) + { + $prevResults[$row->ti_name] = $row->ti_success; + } + } + + $combined = array_keys( $this->results + $prevResults ); + + # Determine breakdown by change type + $breakdown = array(); + foreach ( $combined as $test ) { + if ( !isset( $prevResults[$test] ) ) { + $before = 'n'; + } elseif ( $prevResults[$test] == 1 ) { + $before = 'p'; + } else /* if ( $prevResults[$test] == 0 )*/ { + $before = 'f'; + } + if ( !isset( $this->results[$test] ) ) { + $after = 'n'; + } elseif ( $this->results[$test] == 1 ) { + $after = 'p'; + } else /*if ( $this->results[$test] == 0 ) */ { + $after = 'f'; + } + $code = $before . $after; + if ( isset( $table[$code] ) ) { + $breakdown[$code][$test] = $this->getTestStatusInfo( $test, $after ); + } + } + + # Write out results + foreach ( $table as $code => $label ) { + if( !empty( $breakdown[$code] ) ) { + $count = count($breakdown[$code]); printf( "\n%4d %s\n", $count, $label ); - foreach ($differences as $differing_test_name => $statusInfo) { + foreach ($breakdown[$code] as $differing_test_name => $statusInfo) { print " * $differing_test_name [$statusInfo]\n"; } } @@ -1044,53 +1138,14 @@ class DbTestRecorder extends TestRecorder { } /** - ** Returns an array of the test names with changed results, based on the specified - ** before/after criteria. - */ - private function compareResult( $before, $after ) { - $testitem = $this->db->tableName( 'testitem' ); - $prevRun = intval( $this->prevRun ); - $curRun = intval( $this->curRun ); - $prevStatus = $this->condition( $before ); - $curStatus = $this->condition( $after ); - - // note: requires mysql >= ver 4.1 for subselects - if( is_null( $after ) ) { - $sql = " - select prev.ti_name as t from $testitem as prev - where prev.ti_run=$prevRun and - prev.ti_success $prevStatus and - (select current.ti_success from $testitem as current - where current.ti_run=$curRun - and prev.ti_name=current.ti_name) $curStatus"; - } else { - $sql = " - select current.ti_name as t from $testitem as current - where current.ti_run=$curRun and - current.ti_success $curStatus and - (select prev.ti_success from $testitem as prev - where prev.ti_run=$prevRun - and prev.ti_name=current.ti_name) $prevStatus"; - } - $result = $this->db->query( $sql, __METHOD__ ); - $retval = array(); - while ($row = $this->db->fetchObject( $result )) { - $testname = $row->t; - $retval[$testname] = $this->getTestStatusInfo( $testname, $after, $curRun ); - } - $this->db->freeResult( $result ); - return $retval; - } - - /** ** Returns a string giving information about when a test last had a status change. ** Could help to track down when regressions were introduced, as distinct from tests ** which have never passed (which are more change requests than regressions). */ - private function getTestStatusInfo($testname, $after, $curRun) { + private function getTestStatusInfo($testname, $after) { // If we're looking at a test that has just been removed, then say when it first appeared. - if ( is_null( $after ) ) { + if ( $after == 'n' ) { $changedRun = $this->db->selectField ( 'testitem', 'MIN(ti_run)', array( 'ti_name' => $testname ), @@ -1106,18 +1161,18 @@ class DbTestRecorder extends TestRecorder { // Otherwise, this test has previous recorded results. // See when this test last had a different result to what we're seeing now. - $changedRun = $this->db->selectField ( 'testitem', - 'MAX(ti_run)', - array( - 'ti_name' => $testname, - 'ti_success' => ($after ? "0" : "1"), - "ti_run != " . $this->db->addQuotes ( $curRun ) - ), - __METHOD__ ); + $conds = array( + 'ti_name' => $testname, + 'ti_success' => ($after == 'f' ? "1" : "0") ); + if ( $this->curRun ) { + $conds[] = "ti_run != " . $this->db->addQuotes ( $this->curRun ); + } + + $changedRun = $this->db->selectField ( 'testitem', 'MAX(ti_run)', $conds, __METHOD__ ); // If no record of ever having had a different result. if ( is_null ( $changedRun ) ) { - if ($after == "0") { + if ($after == "f") { return "Has never passed"; } else { return "Has never failed"; @@ -1138,33 +1193,78 @@ class DbTestRecorder extends TestRecorder { array( "LIMIT" => 1, "ORDER BY" => 'tr_id' ) ); - return ( $after == "0" ? "Introduced" : "Fixed" ) . " between " + if ( $post ) { + $postDate = date( "d-M-Y H:i:s", strtotime ( $post->tr_date ) ) . ", {$post->tr_mw_version}"; + } else { + $postDate = 'now'; + } + return ( $after == "f" ? "Introduced" : "Fixed" ) . " between " . date( "d-M-Y H:i:s", strtotime ( $pre->tr_date ) ) . ", " . $pre->tr_mw_version - . " and " - . date( "d-M-Y H:i:s", strtotime ( $post->tr_date ) ) . ", " . $post->tr_mw_version ; + . " and $postDate"; + } /** - ** Helper function for compareResult() database querying. + * Commit transaction and clean up for result recording */ - private function condition( $value ) { - if( is_null( $value ) ) { - return 'IS NULL'; - } else { - return '=' . intval( $value ); - } + function end() { + $this->lb->commitMasterChanges(); + $this->lb->closeAll(); + parent::end(); } } -class DbTestPreviewer extends DbTestRecorder { +class DbTestRecorder extends DbTestPreviewer { /** - * Commit transaction and clean up for result recording + * Set up result recording; insert a record for the run with the date + * and all that fun stuff */ - function end() { - $this->db->rollback(); - TestRecorder::end(); + function start() { + global $wgDBtype, $wgDBprefix; + $this->db->begin(); + + if( ! $this->db->tableExists( 'testrun' ) + or ! $this->db->tableExists( 'testitem' ) ) + { + print "WARNING> `testrun` table not found in database. Trying to create table.\n"; + if ($wgDBtype === 'postgres') + $this->db->sourceFile( dirname(__FILE__) . '/testRunner.postgres.sql' ); + else + $this->db->sourceFile( dirname(__FILE__) . '/testRunner.sql' ); + echo "OK, resuming.\n"; + } + + parent::start(); + + $this->db->insert( 'testrun', + array( + 'tr_date' => $this->db->timestamp(), + 'tr_mw_version' => SpecialVersion::getVersion(), + 'tr_php_version' => phpversion(), + 'tr_db_version' => $this->db->getServerVersion(), + 'tr_uname' => php_uname() + ), + __METHOD__ ); + if ($wgDBtype === 'postgres') + $this->curRun = $this->db->currentSequenceValue('testrun_id_seq'); + else + $this->curRun = $this->db->insertId(); } -} -?> + /** + * Record an individual test item's success or failure to the db + * @param string $test + * @param bool $result + */ + function record( $test, $result ) { + parent::record( $test, $result ); + $this->db->insert( 'testitem', + array( + 'ti_run' => $this->curRun, + 'ti_name' => $test, + 'ti_success' => $result ? 1 : 0, + ), + __METHOD__ ); + } +} diff --git a/maintenance/parserTests.php b/maintenance/parserTests.php index 0ee7e8f2..192eeaa8 100644 --- a/maintenance/parserTests.php +++ b/maintenance/parserTests.php @@ -18,7 +18,8 @@ # http://www.gnu.org/copyleft/gpl.html /** - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ /** */ diff --git a/maintenance/parserTests.txt b/maintenance/parserTests.txt index b1ddb9b0..07c897f1 100644 --- a/maintenance/parserTests.txt +++ b/maintenance/parserTests.txt @@ -461,7 +461,7 @@ Definition list with wikilink containing colon !! input ; [[Help:FAQ]]: The least-read page on Wikipedia !! result -<dl><dt> <a href="/index.php?title=Help:FAQ&action=edit" class="new" title="Help:FAQ">Help:FAQ</a></dt><dd> The least-read page on Wikipedia +<dl><dt> <a href="/index.php?title=Help:FAQ&action=edit&redlink=1" class="new" title="Help:FAQ (not yet written)">Help:FAQ</a></dt><dd> The least-read page on Wikipedia </dd></dl> !! end @@ -536,11 +536,11 @@ External links: numbered !! input Numbered: [http://example.com] Numbered: [http://example.net] -Numbered: [http://example.org] +Numbered: [http://example.com] !! result <p>Numbered: <a href="http://example.com" class="external autonumber" title="http://example.com" rel="nofollow">[1]</a> Numbered: <a href="http://example.net" class="external autonumber" title="http://example.net" rel="nofollow">[2]</a> -Numbered: <a href="http://example.org" class="external autonumber" title="http://example.org" rel="nofollow">[3]</a> +Numbered: <a href="http://example.com" class="external autonumber" title="http://example.com" rel="nofollow">[3]</a> </p> !!end @@ -887,7 +887,7 @@ External links: wiki links within external link (Bug 3695) !! input [http://example.com [[wikilink]] embedded in ext link] !! result -<p><a href="http://example.com" class="external text" title="http://example.com" rel="nofollow"></a><a href="/index.php?title=Wikilink&action=edit" class="new" title="Wikilink">wikilink</a><a href="http://example.com" class="external text" title="http://example.com" rel="nofollow"> embedded in ext link</a> +<p><a href="http://example.com" class="external text" title="http://example.com" rel="nofollow"></a><a href="/index.php?title=Wikilink&action=edit&redlink=1" class="new" title="Wikilink (not yet written)">wikilink</a><a href="http://example.com" class="external text" title="http://example.com" rel="nofollow"> embedded in ext link</a> </p> !! end @@ -1316,7 +1316,7 @@ Broken link !! input [[Zigzagzogzagzig]] !! result -<p><a href="/index.php?title=Zigzagzogzagzig&action=edit" class="new" title="Zigzagzogzagzig">Zigzagzogzagzig</a> +<p><a href="/index.php?title=Zigzagzogzagzig&action=edit&redlink=1" class="new" title="Zigzagzogzagzig (not yet written)">Zigzagzogzagzig</a> </p> !! end @@ -1332,9 +1332,9 @@ xxx[[main Page]], xxx[[Main Page]], Xxx[[main Page]] XXX[[main Page]], XXX[[Main !! test Link with suffix !! input -[[Main Page]]xxx, [[Main Page]]XXX +[[Main Page]]xxx, [[Main Page]]XXX, [[Main Page]]!!! !! result -<p><a href="/wiki/Main_Page" title="Main Page">Main Pagexxx</a>, <a href="/wiki/Main_Page" title="Main Page">Main Page</a>XXX +<p><a href="/wiki/Main_Page" title="Main Page">Main Pagexxx</a>, <a href="/wiki/Main_Page" title="Main Page">Main PageXXX</a>, <a href="/wiki/Main_Page" title="Main Page">Main Page</a>!!! </p> !! end @@ -1370,7 +1370,7 @@ Link to namespaces !! input [[Talk:Parser testing]], [[Meta:Disclaimers]] !! result -<p><a href="/index.php?title=Talk:Parser_testing&action=edit" class="new" title="Talk:Parser testing">Talk:Parser testing</a>, <a href="/index.php?title=Meta:Disclaimers&action=edit" class="new" title="Meta:Disclaimers">Meta:Disclaimers</a> +<p><a href="/index.php?title=Talk:Parser_testing&action=edit&redlink=1" class="new" title="Talk:Parser testing (not yet written)">Talk:Parser testing</a>, <a href="/index.php?title=Meta:Disclaimers&action=edit&redlink=1" class="new" title="Meta:Disclaimers (not yet written)">Meta:Disclaimers</a> </p> !! end @@ -1379,7 +1379,7 @@ Piped link to namespace !! input [[Meta:Disclaimers|The disclaimers]] !! result -<p><a href="/index.php?title=Meta:Disclaimers&action=edit" class="new" title="Meta:Disclaimers">The disclaimers</a> +<p><a href="/index.php?title=Meta:Disclaimers&action=edit&redlink=1" class="new" title="Meta:Disclaimers (not yet written)">The disclaimers</a> </p> !! end @@ -1397,7 +1397,7 @@ Link containing % (not as a hex sequence) !! input [[7% Solution]] !! result -<p><a href="/index.php?title=7%25_Solution&action=edit" class="new" title="7% Solution">7% Solution</a> +<p><a href="/index.php?title=7%25_Solution&action=edit&redlink=1" class="new" title="7% Solution (not yet written)">7% Solution</a> </p> !! end @@ -1406,7 +1406,7 @@ Link containing % as a single hex sequence interpreted to char !! input [[7%25 Solution]] !! result -<p><a href="/index.php?title=7%25_Solution&action=edit" class="new" title="7% Solution">7% Solution</a> +<p><a href="/index.php?title=7%25_Solution&action=edit&redlink=1" class="new" title="7% Solution (not yet written)">7% Solution</a> </p> !!end @@ -1452,7 +1452,7 @@ Link containing double-single-quotes '' in text (bug 4598 sanity check) !! input Some [[Link|pretty ''italics'' and stuff]]! !! result -<p>Some <a href="/index.php?title=Link&action=edit" class="new" title="Link">pretty <i>italics</i> and stuff</a>! +<p>Some <a href="/index.php?title=Link&action=edit&redlink=1" class="new" title="Link (not yet written)">pretty <i>italics</i> and stuff</a>! </p> !! end @@ -1461,16 +1461,16 @@ Link containing double-single-quotes '' in text embedded in italics (bug 4598 sa !! input ''Some [[Link|pretty ''italics'' and stuff]]! !! result -<p><i>Some </i><a href="/index.php?title=Link&action=edit" class="new" title="Link"><i>pretty </i>italics<i> and stuff</i></a><i>!</i> +<p><i>Some </i><a href="/index.php?title=Link&action=edit&redlink=1" class="new" title="Link (not yet written)"><i>pretty </i>italics<i> and stuff</i></a><i>!</i> </p> !! end !! test Plain link to URL !! input -[[http://www.example.org]] +[[http://www.example.com]] !! result -<p>[<a href="http://www.example.org" class="external autonumber" title="http://www.example.org" rel="nofollow">[1]</a>] +<p>[<a href="http://www.example.com" class="external autonumber" title="http://www.example.com" rel="nofollow">[1]</a>] </p> !! end @@ -1481,16 +1481,16 @@ Plain link to URL # ---- # I'm changing it to match the current output--it arguably makes more # sense in the light of the test above. Old expected result was: -#<p>Piped link to URL: <a href="/index.php?title=Http://www.example.org&action=edit" class="new" title="Http://www.example.org">an example URL</a> +#<p>Piped link to URL: <a href="/index.php?title=Http://www.example.com&action=edit" class="new" title="Http://www.example.com">an example URL</a> #</p> # But I think this test is bordering on "garbage in, garbage out" anyway. # -- wtm !! test Piped link to URL !! input -Piped link to URL: [[http://www.example.org|an example URL]] +Piped link to URL: [[http://www.example.com|an example URL]] !! result -<p>Piped link to URL: [<a href="http://www.example.org|an" class="external text" title="http://www.example.org|an" rel="nofollow">example URL</a>] +<p>Piped link to URL: [<a href="http://www.example.com|an" class="external text" title="http://www.example.com|an" rel="nofollow">example URL</a>] </p> !! end @@ -2084,7 +2084,7 @@ Magic links: internal link to RFC (bug 479) !! input [[RFC 123]] !! result -<p><a href="/index.php?title=RFC_123&action=edit" class="new" title="RFC 123">RFC 123</a> +<p><a href="/index.php?title=RFC_123&action=edit&redlink=1" class="new" title="RFC 123 (not yet written)">RFC 123</a> </p> !! end @@ -2102,7 +2102,7 @@ Magic links: ISBN (bug 1937) !! input ISBN 0-306-40615-2 !! result -<p><a href="/index.php?title=Special:Booksources&isbn=0306406152" class="internal">ISBN 0-306-40615-2</a> +<p><a href="/wiki/Special:BookSources/0306406152" class="internal">ISBN 0-306-40615-2</a> </p> !! end @@ -2124,7 +2124,7 @@ Nonexistant template !! input {{thistemplatedoesnotexist}} !! result -<p><a href="/index.php?title=Template:Thistemplatedoesnotexist&action=edit" class="new" title="Template:Thistemplatedoesnotexist">Template:Thistemplatedoesnotexist</a> +<p><a href="/index.php?title=Template:Thistemplatedoesnotexist&action=edit&redlink=1" class="new" title="Template:Thistemplatedoesnotexist (not yet written)">Template:Thistemplatedoesnotexist</a> </p> !! end @@ -2306,7 +2306,7 @@ Template with thumb image (with link in description) {{paramtest| param =[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]}} !! result -This is a test template with parameter <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&wpDestFile=Noimage.png" class="new" title="Image:Noimage.png">Image:Noimage.png</a> <div class="thumbcaption"><a href="/index.php?title=No_link&action=edit" class="new" title="No link">link</a> <a href="/index.php?title=No_link&action=edit" class="new" title="No link">caption</a></div></div></div> +This is a test template with parameter <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&wpDestFile=Noimage.png" class="new" title="Image:Noimage.png">Image:Noimage.png</a> <div class="thumbcaption"><a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (not yet written)">link</a> <a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (not yet written)">caption</a></div></div></div> !! end @@ -3022,7 +3022,7 @@ msg !! input {{#special:Recentchanges}} !! result -Special:Recentchanges +Special:RecentChanges !! end !! test @@ -3081,7 +3081,7 @@ Add test with existing image page !! input [[:Image:test]] !! result -<p><a href="/index.php?title=Image:Test&action=edit" class="new" title="Image:Test">Image:test</a> +<p><a href="/index.php?title=Image:Test&action=edit&redlink=1" class="new" title="Image:Test (not yet written)">Image:test</a> </p> !! end @@ -3108,7 +3108,7 @@ BUG 1887: A ISBN with a thumbnail !! input [[Image:foobar.jpg|thumb|ISBN 1235467890]] !! result -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="image" title="ISBN 1235467890"><img alt="ISBN 1235467890" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" border="0" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/Image:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a href="/index.php?title=Special:Booksources&isbn=1235467890" class="internal">ISBN 1235467890</a></div></div></div> +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="image" title="ISBN 1235467890"><img alt="ISBN 1235467890" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" border="0" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/Image:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><a href="/wiki/Special:BookSources/1235467890" class="internal">ISBN 1235467890</a></div></div></div> !! end @@ -3281,7 +3281,7 @@ Disabled subpages !! input [[/subpage]] !! result -<p><a href="/index.php?title=/subpage&action=edit" class="new" title="/subpage">/subpage</a> +<p><a href="/index.php?title=/subpage&action=edit&redlink=1" class="new" title="/subpage (not yet written)">/subpage</a> </p> !! end @@ -3292,7 +3292,7 @@ subpage title=[[Page]] !! input {{/Subpage}} !! result -<p><a href="/index.php?title=Page/Subpage&action=edit" class="new" title="Page/Subpage">Page/Subpage</a> +<p><a href="/index.php?title=Page/Subpage&action=edit&redlink=1" class="new" title="Page/Subpage (not yet written)">Page/Subpage</a> </p> !! end @@ -3324,6 +3324,15 @@ cat <a href="/wiki/Category:MediaWiki_User%27s_Guide" title="Category:MediaWiki User's Guide">MediaWiki User's Guide</a> !! end +!! test +PAGESINCATEGORY invalid title fatal (r33546 fix) +!! input +{{PAGESINCATEGORY:<bogus>}} +!! result +<p>0 +</p> +!! end + ### ### Inter-language links ### @@ -3551,6 +3560,17 @@ Resolving duplicate section names !! end +!! test +Resolving duplicate section names with differing case (bug 10721) +!! input +== Foo bar == +== Foo Bar == +!! result +<a name="Foo_bar"></a><h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: Foo bar">edit</a>]</span> <span class="mw-headline"> Foo bar </span></h2> +<a name="Foo_Bar_2"></a><h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: Foo Bar">edit</a>]</span> <span class="mw-headline"> Foo Bar </span></h2> + +!! end + !! article Template:sections !! text @@ -3594,6 +3614,29 @@ Link inside a section heading !! end +!! test +TOC regression (bug 12077) +!! input +__TOC__ +== title 1 == +=== title 1.1 === +== title 2 == +!! result +<table id="toc" class="toc" summary="Contents"><tr><td><div id="toctitle"><h2>Contents</h2></div> +<ul> +<li class="toclevel-1"><a href="#title_1"><span class="tocnumber">1</span> <span class="toctext">title 1</span></a> +<ul> +<li class="toclevel-2"><a href="#title_1.1"><span class="tocnumber">1.1</span> <span class="toctext">title 1.1</span></a></li> +</ul> +</li> +<li class="toclevel-1"><a href="#title_2"><span class="tocnumber">2</span> <span class="toctext">title 2</span></a></li> +</ul> +</td></tr></table><script type="text/javascript"> if (window.showTocToggle) { var tocShowText = "show"; var tocHideText = "hide"; showTocToggle(); } </script> +<a name="title_1"></a><h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: title 1">edit</a>]</span> <span class="mw-headline"> title 1 </span></h2> +<a name="title_1.1"></a><h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: title 1.1">edit</a>]</span> <span class="mw-headline"> title 1.1 </span></h3> +<a name="title_2"></a><h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: title 2">edit</a>]</span> <span class="mw-headline"> title 2 </span></h2> + +!! end !! test BUG 1219 URL next to image (good) @@ -3804,7 +3847,7 @@ Image link to nonexistent file (bug 1850 - good) !! input [[:Image:No such.jpg]] !! result -<p><a href="/index.php?title=Image:No_such.jpg&action=edit" class="new" title="Image:No such.jpg">Image:No such.jpg</a> +<p><a href="/index.php?title=Image:No_such.jpg&action=edit&redlink=1" class="new" title="Image:No such.jpg (not yet written)">Image:No such.jpg</a> </p> !! end @@ -4519,6 +4562,34 @@ Self closed html pairs (bug 5487) # !! test +Punctuation: nbsp before exclamation +!! input +C'est grave ! +!! result +<p>C'est grave ! +</p> +!! end + +!! test +Punctuation: CSS !important (bug 11874) +!! input +<div style="width:50% !important">important</div> +!! result +<div style="width:50% !important">important</div> + +!!end + +!! test +Punctuation: CSS ! important (bug 11874; with space after) +!! input +<div style="width:50% ! important">important</div> +!! result +<div style="width:50% ! important">important</div> + +!!end + + +!! test HTML bullet list, closed tags (bug 5497) !! input <ul> @@ -5037,7 +5108,7 @@ Transclusion of nonexistent MediaWiki message !! input {{MediaWiki:Mainpagexxx}} !!result -<p><a href="/index.php?title=MediaWiki:Mainpagexxx&action=edit" class="new" title="MediaWiki:Mainpagexxx">MediaWiki:Mainpagexxx</a> +<p><a href="/index.php?title=MediaWiki:Mainpagexxx&action=edit&redlink=1" class="new" title="MediaWiki:Mainpagexxx (not yet written)">MediaWiki:Mainpagexxx</a> </p> !! end @@ -5795,6 +5866,20 @@ start xxx !! end +!! test +Section replacement test with initial whitespace (bug 13728) +!! options +replace=2,"xxx" +!! input + Preformatted initial line +==a== +===a=== +!! result + Preformatted initial line +==a== +xxx +!! end + !! test Section extraction, heading followed by pre with 20 spaces (bug 6398) @@ -5925,7 +6010,7 @@ Say the magic word </li><li> Talk </li><li> </li><li> -</li><li> <a href="/index.php?title=Template:Dynamic&action=edit" class="new" title="Template:Dynamic">Template:Dynamic</a> +</li><li> <a href="/index.php?title=Template:Dynamic&action=edit&redlink=1" class="new" title="Template:Dynamic (not yet written)">Template:Dynamic</a> </li></ul> !! end @@ -6014,7 +6099,7 @@ ISBN code coverage !! input ISBN 978-0-1234-56 789 !! result -<p><a href="/index.php?title=Special:Booksources&isbn=9780123456" class="internal">ISBN 978-0-1234-56</a> 789 +<p><a href="/wiki/Special:BookSources/9780123456" class="internal">ISBN 978-0-1234-56</a> 789 </p> !! end @@ -6032,7 +6117,7 @@ Double ISBN !! input ISBN ISBN 1234567890 !! result -<p>ISBN <a href="/index.php?title=Special:Booksources&isbn=1234567890" class="internal">ISBN 1234567890</a> +<p>ISBN <a href="/wiki/Special:BookSources/1234567890" class="internal">ISBN 1234567890</a> </p> !! end @@ -6050,7 +6135,7 @@ Double RFC with a wiki link !! input RFC [[RFC 1234]] !! result -<p>RFC <a href="/index.php?title=RFC_1234&action=edit" class="new" title="RFC 1234">RFC 1234</a> +<p>RFC <a href="/index.php?title=RFC_1234&action=edit&redlink=1" class="new" title="RFC 1234 (not yet written)">RFC 1234</a> </p> !! end @@ -6155,7 +6240,7 @@ subpage title=[[Subpage test/L1/L2/L3]] !! input [[../|L2]] !! result -<p><a href="/index.php?title=Subpage_test/L1/L2&action=edit" class="new" title="Subpage test/L1/L2">L2</a> +<p><a href="/index.php?title=Subpage_test/L1/L2&action=edit&redlink=1" class="new" title="Subpage test/L1/L2 (not yet written)">L2</a> </p> !! end @@ -6167,7 +6252,7 @@ subpage title=[[Subpage test/L1/L2/L3]] !! input [[../]] !! result -<p><a href="/index.php?title=Subpage_test/L1/L2&action=edit" class="new" title="Subpage test/L1/L2">Subpage test/L1/L2</a> +<p><a href="/index.php?title=Subpage_test/L1/L2&action=edit&redlink=1" class="new" title="Subpage test/L1/L2 (not yet written)">Subpage test/L1/L2</a> </p> !! end @@ -6181,7 +6266,7 @@ subpage title=[[Subpage test/L1/L2/L3]] !! input [[../../|L1]]2 !! result -<p><a href="/index.php?title=Subpage_test/L1&action=edit" class="new" title="Subpage test/L1">L1</a> +<p><a href="/index.php?title=Subpage_test/L1&action=edit&redlink=1" class="new" title="Subpage test/L1 (not yet written)">L1</a> </p> !! end @@ -6194,7 +6279,7 @@ subpage title=[[Subpage test/L1/L2/L3]] !! input [[../..]] !! result -<p><a href="/index.php?title=Subpage_test/L1/L2/..&action=edit" class="new" title="Subpage test/L1">../..</a> +<p><a href="/index.php?title=Subpage_test/L1/L2/..&action=edit&redlink=1" class="new" title="Subpage test/L1 (not yet written)">../..</a> </p> !! end @@ -6207,7 +6292,7 @@ subpage title=[[Subpage test/L1/L2/L3]] !! input [[../../////]] !! result -<p><a href="/index.php?title=Subpage_test/L1&action=edit" class="new" title="Subpage test/L1">Subpage test/L1</a> +<p><a href="/index.php?title=Subpage_test/L1&action=edit&redlink=1" class="new" title="Subpage test/L1 (not yet written)">Subpage test/L1</a> </p> !! end @@ -6248,7 +6333,7 @@ RAW magic word !! input {{RAW:QUERTY}} !! result -<p><a href="/index.php?title=Template:QUERTY&action=edit" class="new" title="Template:QUERTY">Template:QUERTY</a> +<p><a href="/index.php?title=Template:QUERTY&action=edit&redlink=1" class="new" title="Template:QUERTY (not yet written)">Template:QUERTY</a> </p> !! end @@ -6308,10 +6393,10 @@ Out-of-order TOC heading levels <li class="toclevel-2"><a href="#3"><span class="tocnumber">1.2</span> <span class="toctext">3</span></a></li> </ul> </li> -<li class="toclevel-1"><a href="#1_7"><span class="tocnumber">2</span> <span class="toctext">1</span></a> +<li class="toclevel-1"><a href="#1"><span class="tocnumber">2</span> <span class="toctext">1</span></a> <ul> <li class="toclevel-2"><a href="#5"><span class="tocnumber">2.1</span> <span class="toctext">5</span></a></li> -<li class="toclevel-2"><a href="#2_4"><span class="tocnumber">2.2</span> <span class="toctext">2</span></a></li> +<li class="toclevel-2"><a href="#2_2"><span class="tocnumber">2.2</span> <span class="toctext">2</span></a></li> </ul> </li> </ul> @@ -6319,9 +6404,9 @@ Out-of-order TOC heading levels <a name="2"></a><h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=1" title="Edit section: 2">edit</a>]</span> <span class="mw-headline">2</span></h2> <a name="6"></a><h6><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=2" title="Edit section: 6">edit</a>]</span> <span class="mw-headline">6</span></h6> <a name="3"></a><h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: 3">edit</a>]</span> <span class="mw-headline">3</span></h3> -<a name="1_7"></a><h1><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: 1">edit</a>]</span> <span class="mw-headline">1</span></h1> +<a name="1"></a><h1><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: 1">edit</a>]</span> <span class="mw-headline">1</span></h1> <a name="5"></a><h5><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=5" title="Edit section: 5">edit</a>]</span> <span class="mw-headline">5</span></h5> -<a name="2_4"></a><h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=6" title="Edit section: 2">edit</a>]</span> <span class="mw-headline">2</span></h2> +<a name="2_2"></a><h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=6" title="Edit section: 2">edit</a>]</span> <span class="mw-headline">2</span></h2> !! end @@ -6341,7 +6426,7 @@ ISBN with space-delimited number !! input ISBN 92 9017 032 8 !! result -<p><a href="/index.php?title=Special:Booksources&isbn=9290170328" class="internal">ISBN 92 9017 032 8</a> +<p><a href="/wiki/Special:BookSources/9290170328" class="internal">ISBN 92 9017 032 8</a> </p> !! end @@ -6366,7 +6451,7 @@ ISBN 1234567890 ISBN 12345678901 !! result <p>ISBN 123456789 -</p><p><a href="/index.php?title=Special:Booksources&isbn=1234567890" class="internal">ISBN 1234567890</a> +</p><p><a href="/wiki/Special:BookSources/1234567890" class="internal">ISBN 1234567890</a> </p><p>ISBN 12345678901 </p> !! end @@ -6379,8 +6464,8 @@ ISBN 1-234-56789-0 - 2006 ISBN 1 234 56789 0 - 2006 !! result -<p><a href="/index.php?title=Special:Booksources&isbn=1234567890" class="internal">ISBN 1-234-56789-0</a> - 2006 -</p><p><a href="/index.php?title=Special:Booksources&isbn=1234567890" class="internal">ISBN 1 234 56789 0</a> - 2006 +<p><a href="/wiki/Special:BookSources/1234567890" class="internal">ISBN 1-234-56789-0</a> - 2006 +</p><p><a href="/wiki/Special:BookSources/1234567890" class="internal">ISBN 1 234 56789 0</a> - 2006 </p> !! end diff --git a/maintenance/parserTestsParserHook.php b/maintenance/parserTestsParserHook.php index 0005e999..f55cd0e4 100644 --- a/maintenance/parserTestsParserHook.php +++ b/maintenance/parserTestsParserHook.php @@ -5,7 +5,8 @@ if ( ! defined( 'MEDIAWIKI' ) ) * A basic extension that's used by the parser tests to test whether input and * arguments are passed to extensions properly. * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> * @copyright Copyright © 2005, 2006 Ævar Arnfjörð Bjarmason diff --git a/maintenance/parserTestsParserTime.php b/maintenance/parserTestsParserTime.php index 70a04d91..c5903f25 100644 --- a/maintenance/parserTestsParserTime.php +++ b/maintenance/parserTestsParserTime.php @@ -8,7 +8,8 @@ if ( ! defined( 'MEDIAWIKI' ) ) * compensate with the passage of time and certainly less expensive than a * time-freezing device, get yours now! * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> * @copyright Copyright © 2005, 2006 Ævar Arnfjörð Bjarmason diff --git a/maintenance/parserTestsStaticParserHook.php b/maintenance/parserTestsStaticParserHook.php index f72fcda9..5a98a89d 100644 --- a/maintenance/parserTestsStaticParserHook.php +++ b/maintenance/parserTestsStaticParserHook.php @@ -5,7 +5,8 @@ if ( ! defined( 'MEDIAWIKI' ) ) * A basic extension that's used by the parser tests to test whether the parser * calls extensions when they're called inside comments, it shouldn't do that * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> * @copyright Copyright © 2005, 2006 Ævar Arnfjörð Bjarmason diff --git a/maintenance/patchSql.php b/maintenance/patchSql.php new file mode 100644 index 00000000..42380eea --- /dev/null +++ b/maintenance/patchSql.php @@ -0,0 +1,36 @@ +<?php +/** + * Manually run an SQL patch outside of the general updaters. + * This ensures that the DB options (charset, prefix, engine) are correctly set. + * + * @file + * @ingroup Maintenance + */ + +require_once 'commandLine.inc'; +require_once "$IP/maintenance/updaters.inc"; + +if( $args ) { + foreach( $args as $arg ) { + $files = array( + $arg, + archive( $arg ), + archive( "patch-$arg.sql" ), + ); + foreach( $files as $file ) { + if( file_exists( $file ) ) { + echo "$file ...\n"; + dbsource( $file ); + continue 2; + } + } + echo "Could not find $arg\n"; + } + echo "done.\n"; +} else { + echo "Run an SQL file into the DB, replacing prefix and charset vars.\n"; + echo "Usage:\n"; + echo " php maintenance/patchSql.php file1.sql file2.sql ...\n"; + echo "\n"; + echo "Paths in maintenance/archive are automatically expanded if a local file isn't found.\n"; +} diff --git a/maintenance/populateCategory.inc b/maintenance/populateCategory.inc new file mode 100644 index 00000000..3d04a30b --- /dev/null +++ b/maintenance/populateCategory.inc @@ -0,0 +1,85 @@ +<?php +/** + * @file + * @ingroup Maintenance + * @author Simetrical + */ + +define( 'REPORTING_INTERVAL', 1000 ); + +function populateCategory( $begin, $maxlag, $throttle, $force ) { + $dbw = wfGetDB( DB_MASTER ); + + if( !$force ) { + $row = $dbw->selectRow( + 'updatelog', + '1', + array( 'ul_key' => 'populate category' ), + __FUNCTION__ + ); + if( $row ) { + echo "Category table already populated. Use php ". + "maintenance/populateCategory.php\n--force from the command line ". + "to override.\n"; + return true; + } + } + + $maxlag = intval( $maxlag ); + $throttle = intval( $throttle ); + $force = (bool)$force; + if( $begin !== '' ) { + $where = 'cl_to > '.$dbw->addQuotes( $begin ); + } else { + $where = null; + } + $i = 0; + + while( true ) { + # Find which category to update + $row = $dbw->selectRow( + 'categorylinks', + 'cl_to', + $where, + __FUNCTION__, + array( + 'ORDER BY' => 'cl_to' + ) + ); + if( !$row ) { + # Done, hopefully. + break; + } + $name = $row->cl_to; + $where = 'cl_to > '.$dbw->addQuotes( $name ); + + # Use the row to update the category count + $cat = Category::newFromName( $name ); + if( !is_object( $cat ) ) { + echo "The category named $name is not valid?!\n"; + } else { + $cat->refreshCounts(); + } + + ++$i; + if( !($i % REPORTING_INTERVAL) ) { + echo "$name\n"; + wfWaitForSlaves( $maxlag ); + } + usleep( $throttle*1000 ); + } + + if( $dbw->insert( + 'updatelog', + array( 'ul_key' => 'populate category' ), + __FUNCTION__, + 'IGNORE' + ) + ) { + echo "Category population complete.\n"; + return true; + } else { + echo "Could not insert category population row.\n"; + return false; + } +} diff --git a/maintenance/populateCategory.php b/maintenance/populateCategory.php new file mode 100644 index 00000000..cb22e7f8 --- /dev/null +++ b/maintenance/populateCategory.php @@ -0,0 +1,52 @@ +<?php +/** + * @file + * @ingroup Maintenance + * @author Simetrical + */ + +$optionsWithArgs = array( 'begin', 'max-slave-lag', 'throttle' ); + +require_once "commandLine.inc"; +require_once "populateCategory.inc"; + +if( isset( $options['help'] ) ) { + echo <<<TEXT +This script will populate the category table, added in MediaWiki 1.13. It will +print out progress indicators every 1000 categories it adds to the table. The +script is perfectly safe to run on large, live wikis, and running it multiple +times is harmless. You may want to use the throttling options if it's causing +too much load; they will not affect correctness. + +If the script is stopped and later resumed, you can use the --begin option with +the last printed progress indicator to pick up where you left off. This is +safe, because any newly-added categories before this cutoff will have been +added after the software update and so will be populated anyway. + +When the script has finished, it will make a note of this in the database, and +will not run again without the --force option. + +Usage: + php populateCategory.php [--max-slave-lag <seconds>] [--begin <name>] +[--throttle <seconds>] [--force] + + --begin: Only do categories whose names are alphabetically after the pro- +vided name. Default: empty (start from beginning). + --max-slave-lag: If slave lag exceeds this many seconds, wait until it +drops before continuing. Default: 10. + --throttle: Wait this many milliseconds after each category. Default: 0. + --force: Run regardless of whether the database says it's been run already. +TEXT; + exit( 0 ); +} + +$defaults = array( + 'begin' => '', + 'max-slave-lag' => 10, + 'throttle' => 0, + 'force' => false +); +$options = array_merge( $defaults, $options ); + +populateCategory( $options['begin'], $options['max-slave-lag'], + $options['throttle'], $options['force'] ); diff --git a/maintenance/populateParentId.inc b/maintenance/populateParentId.inc new file mode 100644 index 00000000..3fecc63b --- /dev/null +++ b/maintenance/populateParentId.inc @@ -0,0 +1,83 @@ +<?php + +define( 'BATCH_SIZE', 200 ); + +function populate_rev_parent_id( $db ) { + echo "Populating rev_parent_id column\n"; + $start = $db->selectField( 'revision', 'MIN(rev_id)', false, __FUNCTION__ ); + $end = $db->selectField( 'revision', 'MAX(rev_id)', false, __FUNCTION__ ); + if( is_null( $start ) || is_null( $end ) ){ + echo "...revision table seems to be empty.\n"; + $db->insert( 'updatelog', + array( 'ul_key' => 'populate rev_parent_id' ), + __FUNCTION__, + 'IGNORE' ); + return; + } + # Do remaining chunk + $end += BATCH_SIZE - 1; + $blockStart = $start; + $blockEnd = $start + BATCH_SIZE - 1; + $count = 0; + $changed = 0; + while( $blockEnd <= $end ) { + echo "...doing rev_id from $blockStart to $blockEnd\n"; + $cond = "rev_id BETWEEN $blockStart AND $blockEnd"; + $res = $db->select( 'revision', + array('rev_id','rev_page','rev_timestamp','rev_parent_id'), + $cond, __FUNCTION__ ); + # 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 + # edit was made... + foreach( $res as $row ) { + # First, check rows with the same timestamp other than this one + # with a smaller rev ID. The highest ID "wins". This avoids loops + # as timestamp can only decrease and never loops with IDs (from parent to parent) + $previousID = $db->selectField( 'revision', 'rev_id', + array( 'rev_page' => $row->rev_page, 'rev_timestamp' => $row->rev_timestamp, + "rev_id < {$row->rev_id}" ), + __FUNCTION__, + array( 'ORDER BY' => 'rev_id DESC' ) ); + # If there are none, check the the highest ID with a lower timestamp + if( !$previousID ) { + # Get the highest older timestamp + $lastTimestamp = $db->selectField( 'revision', 'rev_timestamp', + array( 'rev_page' => $row->rev_page, "rev_timestamp < '{$row->rev_timestamp}'" ), + __FUNCTION__, + array( 'ORDER BY' => 'rev_timestamp DESC' ) ); + # If there is one, let the highest rev ID win + if( $lastTimestamp ) { + $previousID = $db->selectField( 'revision', 'rev_id', + array( 'rev_page' => $row->rev_page, 'rev_timestamp' => $lastTimestamp ), + __FUNCTION__, + array( 'ORDER BY' => 'rev_id DESC' ) ); + } + } + $previousID = intval($previousID); + if( $previousID != $row->rev_parent_id ) + $changed++; + # Update the row... + $db->update( 'revision', + array( 'rev_parent_id' => $previousID ), + array( 'rev_id' => $row->rev_id ), + __FUNCTION__ ); + $count++; + } + $blockStart += BATCH_SIZE - 1; + $blockEnd += BATCH_SIZE - 1; + wfWaitForSlaves( 5 ); + } + $logged = $db->insert( 'updatelog', + array( 'ul_key' => 'populate rev_parent_id' ), + __FUNCTION__, + 'IGNORE' ); + if( $logged ) { + echo "rev_parent_id population complete ... {$count} rows [{$changed} changed]\n"; + return true; + } else { + echo "Could not insert rev_parent_id population row.\n"; + return false; + } +} + diff --git a/maintenance/populateParentId.php b/maintenance/populateParentId.php new file mode 100644 index 00000000..01730033 --- /dev/null +++ b/maintenance/populateParentId.php @@ -0,0 +1,18 @@ +<?php + +/* + * Makes the required database updates for rev_parent_id + * to be of any use. It can be used for some simple tracking + * and to find new page edits by users. + */ + +require_once 'commandLine.inc'; +require_once 'populateParentId.inc'; + +$db =& wfGetDB( DB_MASTER ); +if ( !$db->tableExists( 'revision' ) ) { + echo "revision table does not exist\n"; + exit( 1 ); +} + +populate_rev_parent_id( $db ); diff --git a/maintenance/postgres/archives/patch-category.sql b/maintenance/postgres/archives/patch-category.sql new file mode 100644 index 00000000..5e0d620f --- /dev/null +++ b/maintenance/postgres/archives/patch-category.sql @@ -0,0 +1,15 @@ + +CREATE SEQUENCE category_id_seq; + +CREATE TABLE category ( + cat_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('category_id_seq'), + cat_title TEXT NOT NULL, + cat_pages INTEGER NOT NULL DEFAULT 0, + cat_subcats INTEGER NOT NULL DEFAULT 0, + cat_files INTEGER NOT NULL DEFAULT 0, + cat_hidden SMALLINT NOT NULL DEFAULT 0 +); + +CREATE UNIQUE INDEX category_title ON category(cat_title); +CREATE INDEX category_pages ON category(cat_pages); + diff --git a/maintenance/postgres/archives/patch-page_props.sql b/maintenance/postgres/archives/patch-page_props.sql new file mode 100644 index 00000000..ab707022 --- /dev/null +++ b/maintenance/postgres/archives/patch-page_props.sql @@ -0,0 +1,9 @@ + +CREATE TABLE page_props ( + pp_page INTEGER NOT NULL REFERENCES page (page_id) ON DELETE CASCADE, + pp_propname TEXT NOT NULL, + pp_value TEXT NOT NULL +); +ALTER TABLE page_props ADD CONSTRAINT page_props_pk PRIMARY KEY (pp_page,pp_propname); +CREATE INDEX page_props_propname ON page_props (pp_propname); + diff --git a/maintenance/postgres/archives/patch-tsearch2funcs.sql b/maintenance/postgres/archives/patch-tsearch2funcs.sql new file mode 100644 index 00000000..c24efef3 --- /dev/null +++ b/maintenance/postgres/archives/patch-tsearch2funcs.sql @@ -0,0 +1,29 @@ +-- Should be run on Postgres 8.3 or newer to remove the 'default' + +CREATE OR REPLACE FUNCTION ts2_page_title() +RETURNS TRIGGER +LANGUAGE plpgsql AS +$mw$ +BEGIN +IF TG_OP = 'INSERT' THEN + NEW.titlevector = to_tsvector(REPLACE(NEW.page_title,'/',' ')); +ELSIF NEW.page_title != OLD.page_title THEN + NEW.titlevector := to_tsvector(REPLACE(NEW.page_title,'/',' ')); +END IF; +RETURN NEW; +END; +$mw$; + +CREATE OR REPLACE FUNCTION ts2_page_text() +RETURNS TRIGGER +LANGUAGE plpgsql AS +$mw$ +BEGIN +IF TG_OP = 'INSERT' THEN + NEW.textvector = to_tsvector(NEW.old_text); +ELSIF NEW.old_text != OLD.old_text THEN + NEW.textvector := to_tsvector(NEW.old_text); +END IF; +RETURN NEW; +END; +$mw$; diff --git a/maintenance/postgres/archives/patch-updatelog.sql b/maintenance/postgres/archives/patch-updatelog.sql new file mode 100644 index 00000000..dda80aa4 --- /dev/null +++ b/maintenance/postgres/archives/patch-updatelog.sql @@ -0,0 +1,4 @@ + +CREATE TABLE updatelog ( + ul_key TEXT NOT NULL PRIMARY KEY +); diff --git a/maintenance/postgres/compare_schemas.pl b/maintenance/postgres/compare_schemas.pl index 6f639eca..84415d79 100644 --- a/maintenance/postgres/compare_schemas.pl +++ b/maintenance/postgres/compare_schemas.pl @@ -2,10 +2,14 @@ ## Rough check that the base and postgres "tables.sql" are in sync ## Should be run from maintenance/postgres +## Checks a few other things as well... use strict; use warnings; use Data::Dumper; +use Cwd; + +check_valid_sql(); my @old = ('../tables.sql'); my $new = 'tables.sql'; @@ -44,7 +48,7 @@ $datatype = qr{($datatype)}; my $typeval = qr{(\(\d+\))?}; -my $typeval2 = qr{ unsigned| binary| NOT NULL| NULL| auto_increment| default ['\-\d\w"]+| REFERENCES .+CASCADE}; +my $typeval2 = qr{ signed| unsigned| binary| NOT NULL| NULL| auto_increment| default ['\-\d\w"]+| REFERENCES .+CASCADE}; my $indextype = join '|' => qw(INDEX KEY FULLTEXT), 'PRIMARY KEY', 'UNIQUE INDEX', 'UNIQUE KEY'; $indextype = qr{$indextype}; @@ -64,7 +68,7 @@ my ($table,%old); my %xinfo; for my $xfile (@xfile) { print "Loading $xfile\n"; - my $info = &parse_sql($xfile); + my $info = parse_sql($xfile); for (keys %$info) { $xinfo{$_} = $info->{$_}; } @@ -72,7 +76,7 @@ for my $xfile (@xfile) { for my $oldfile (@old) { print "Loading $oldfile\n"; - my $info = &parse_sql($oldfile); + my $info = parse_sql($oldfile); for (keys %xinfo) { $info->{$_} = $xinfo{$_}; } @@ -97,8 +101,8 @@ sub parse_sql { $table = $1; $info{$table}{name}=$table; } - elsif (m#^\) /\*\$wgDBTableOptions\*/#) { - $info{$table}{engine} = 'TYPE'; + elsif (m{^\) /\*\$wgDBTableOptions\*/}) { + $info{$table}{engine} = 'ENGINE'; $info{$table}{type} = 'variable'; } elsif (/^\) ($engine)=($tabletype);$/) { @@ -124,7 +128,7 @@ sub parse_sql { } } - close $oldfh; + close $oldfh or die qq{Could not close "$oldfile": $!\n}; return \%info; @@ -142,10 +146,10 @@ while (<$pfh>) { } next; } - $ptable{$1}=2 while /'(\w+)'/g; + $ptable{$1}=2 while m{'(\w+)'}g; last if /\);/; } -close $pfh; +close $pfh or die qq{Could not close "$parsefile": $!\n}; my $OK_NOT_IN_PTABLE = ' filearchive @@ -156,9 +160,10 @@ searchindex trackbacks transcache user_newtalk +updatelog '; -## Make sure all tables in main tables.sql are accounted for int the parsertest. +## Make sure all tables in main tables.sql are accounted for in the parsertest. for my $table (sort keys %{$old{'../tables.sql'}}) { $ptable{$table}++; next if $ptable{$table} > 2; @@ -177,9 +182,7 @@ for my $oldfile (@old) { ## MySQL sanity checks for my $table (sort keys %{$old{$oldfile}}) { my $t = $old{$oldfile}{$table}; - if (($oldfile =~ /5/ and $t->{engine} ne 'ENGINE') - or - ($oldfile !~ /5/ and $t->{engine} ne 'TYPE')) { + if ($t->{engine} eq 'TYPE') { die "Invalid engine for $oldfile: $t->{engine}\n" unless $t->{name} eq 'profiling'; } my $charset = $t->{charset} || ''; @@ -261,6 +264,7 @@ real NUMERIC float NUMERIC ## TEXT: +varchar(15) TEXT varchar(32) TEXT varchar(70) TEXT varchar(255) TEXT @@ -279,7 +283,7 @@ timestamp TIMESTAMPTZ mediumblob BYTEA ## OTHER: -bool CHAR # Sigh +bool SMALLINT # Sigh }; ## Allow specific exceptions to the above @@ -314,6 +318,8 @@ oi_minor_mime varbinary(32) TEXT oi_sha1 varbinary(32) TEXT old_flags tinyblob TEXT old_text mediumblob TEXT +pp_propname varbinary(60) TEXT +pp_value blob TEXT page_restrictions tinyblob TEXT # CSV string pf_server varchar(30) TEXT pr_level varbinary(60) TEXT @@ -324,6 +330,7 @@ qc_type varbinary(32) TEXT qcc_type varbinary(32) TEXT qci_type varbinary(32) TEXT rc_params blob TEXT +rlc_to_blob blob TEXT ug_group varbinary(16) TEXT user_email_token binary(32) TEXT user_ip varbinary(40) TEXT @@ -358,30 +365,18 @@ math_inputhash varbinary(16) BYTEA math_outputhash varbinary(16) BYTEA ## Namespaces: not need for such a high range -ar_namespace int SMALLINT -job_namespace int SMALLINT -log_namespace int SMALLINT -page_namespace int SMALLINT -pl_namespace int SMALLINT -pt_namespace int SMALLINT -qc_namespace int SMALLINT -rc_namespace int SMALLINT -rd_namespace int SMALLINT -tl_namespace int SMALLINT -wl_namespace int SMALLINT - -## "Bools" -ar_minor_edit tinyint CHAR -iw_trans tinyint CHAR -page_is_new tinyint CHAR -page_is_redirect tinyint CHAR -rc_bot tinyint CHAR -rc_deleted tinyint CHAR -rc_minor tinyint CHAR -rc_new tinyint CHAR -rc_patrolled tinyint CHAR -rev_deleted tinyint CHAR -rev_minor_edit tinyint CHAR +ar_namespace int SMALLINT +job_namespace int SMALLINT +log_namespace int SMALLINT +page_namespace int SMALLINT +pl_namespace int SMALLINT +pt_namespace int SMALLINT +qc_namespace int SMALLINT +rc_namespace int SMALLINT +rd_namespace int SMALLINT +rlc_to_namespace int SMALLINT +tl_namespace int SMALLINT +wl_namespace int SMALLINT ## Easy enough to change if a wiki ever does grow this big: ss_good_articles bigint INTEGER @@ -463,6 +458,67 @@ for (sort keys %new) { } ## end each file to be parsed +sub check_valid_sql { + + ## Check for a few common problems in most php files + + my $olddir = getcwd(); + chdir("../.."); + for my $basedir (qw/includes extensions/) { + scan_dir($basedir); + } + chdir $olddir; + + return; + +} ## end of check_valid_sql + + +sub scan_dir { + + my $dir = shift; + + opendir my $dh, $dir or die qq{Could not opendir $dir: $!\n}; + print "Scanning $dir...\n"; + for my $file (grep { -f "$dir/$_" and /\.php$/ } readdir $dh) { + find_problems("$dir/$file"); + } + rewinddir $dh; + for my $subdir (grep { -d "$dir/$_" and ! /\./ } readdir $dh) { + scan_dir("$dir/$subdir"); + } + closedir $dh or die qq{Closedir failed: $!\n}; + return; + +} ## end of scan_dir + +sub find_problems { + + my $file = shift; + open my $fh, '<', $file or die qq{Could not open "$file": $!\n}; + while (<$fh>) { + if (/FORCE INDEX/ and $file !~ /Database\w*\.php/) { + warn "Found FORCE INDEX string at line $. of $file\n"; + } + if (/REPLACE INTO/ and $file !~ /Database\w*\.php/) { + warn "Found REPLACE INTO string at line $. of $file\n"; + } + if (/\bIF\s*\(/ and $file !~ /DatabaseMySQL\.php/) { + warn "Found IF string at line $. of $file\n"; + } + if (/\bCONCAT\b/ and $file !~ /Database\w*\.php/) { + warn "Found CONCAT string at line $. of $file\n"; + } + if (/\bGROUP\s+BY\s*\d\b/i and $file !~ /Database\w*\.php/) { + warn "Found GROUP BY # at line $. of $file\n"; + } + } + close $fh or die qq{Could not close "$file": $!\n}; + return; + +} ## end of find_problems + + __DATA__ ## Known exceptions OLD: searchindex ## We use tsearch2 directly on the page table instead diff --git a/maintenance/postgres/mediawiki_mysql2postgres.pl b/maintenance/postgres/mediawiki_mysql2postgres.pl index 75749dd5..47fa3c0c 100644 --- a/maintenance/postgres/mediawiki_mysql2postgres.pl +++ b/maintenance/postgres/mediawiki_mysql2postgres.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl ## Convert data from a MySQL mediawiki database into a Postgres mediawiki database -## svn: $Id: mediawiki_mysql2postgres.pl 26564 2007-10-10 01:24:18Z greg $ +## svn: $Id: mediawiki_mysql2postgres.pl 33556 2008-04-18 16:27:57Z greg $ ## NOTE: It is probably easier to dump your wiki using maintenance/dumpBackup.php ## and then import it with maintenance/importDump.php @@ -9,7 +9,6 @@ ## If having UTF-8 problems, there are reports that adding --compatible=postgresql ## may help. - use strict; use warnings; use Data::Dumper; @@ -182,7 +181,7 @@ $MYSQLSOCKET and $conninfo .= "\n-- socket $MYSQLSOCKET"; print qq{ -- Dump of MySQL Mediawiki tables for import into a Postgres Mediawiki schema -- Performed by the program: $0 --- Version: $VERSION (subversion }.q{$LastChangedRevision: 26564 $}.qq{) +-- Version: $VERSION (subversion }.q{$LastChangedRevision: 33556 $}.qq{) -- Author: Greg Sabino Mullane <greg\@turnstep.com> Comments welcome -- -- This file was created: $now @@ -203,6 +202,7 @@ print q{ BEGIN; SET client_min_messages = 'WARNING'; SET timezone = 'GMT'; +SET DateStyle = 'ISO, YMD'; }; warn qq{Reading in the Postgres schema information\n} if $verbose; @@ -275,7 +275,7 @@ $verbose and warn qq{Writing truncates to empty existing tables\n}; for my $t (@torder, 'objectcache', 'querycache') { next if $t eq '---'; my $tname = $special{$t}||$t; - printf qq{TRUNCATE TABLE %-20s CASCADE;\n}, qq{"$tname"}; + printf qq{TRUNCATE TABLE %-20s;\n}, qq{"$tname"}; } print "\n\n"; diff --git a/maintenance/postgres/tables.sql b/maintenance/postgres/tables.sql index dc1d7e92..083af727 100644 --- a/maintenance/postgres/tables.sql +++ b/maintenance/postgres/tables.sql @@ -4,8 +4,7 @@ -- This is the PostgreSQL version. -- For information about each table, please see the notes in maintenance/tables.sql -- Please make sure all dollar-quoting uses $mw$ at the start of the line --- We can't use SERIAL everywhere: the sequence names are hard-coded into the PHP --- TODO: Change CHAR/SMALLINT to BOOL (still needed as CHAR due to some PHP code) +-- TODO: Change CHAR/SMALLINT to BOOL (still used in a non-bool fashion in PHP code) BEGIN; SET client_min_messages = 'ERROR'; @@ -41,8 +40,9 @@ CREATE TABLE user_groups ( CREATE UNIQUE INDEX user_groups_unique ON user_groups (ug_user, ug_group); CREATE TABLE user_newtalk ( - user_id INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE CASCADE, - user_ip TEXT NULL + user_id INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE CASCADE, + user_ip TEXT NULL, + user_last_timestamp TIMESTAMPTZ ); CREATE INDEX user_newtalk_id_idx ON user_newtalk (user_id); CREATE INDEX user_newtalk_ip_idx ON user_newtalk (user_ip); @@ -123,12 +123,20 @@ CREATE TABLE page_restrictions ( ); ALTER TABLE page_restrictions ADD CONSTRAINT page_restrictions_pk PRIMARY KEY (pr_page,pr_type); +CREATE TABLE page_props ( + pp_page INTEGER NOT NULL REFERENCES page (page_id) ON DELETE CASCADE, + pp_propname TEXT NOT NULL, + pp_value TEXT NOT NULL +); +ALTER TABLE page_props ADD CONSTRAINT page_props_pk PRIMARY KEY (pp_page,pp_propname); +CREATE INDEX page_props_propname ON page_props (pp_propname); CREATE TABLE archive ( ar_namespace SMALLINT NOT NULL, ar_title TEXT NOT NULL, ar_text TEXT, -- technically should be bytea, but not used anymore ar_page_id INTEGER NULL, + ar_parent_id INTEGER NULL, ar_comment TEXT, ar_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, ar_user_text TEXT NOT NULL, @@ -220,6 +228,7 @@ CREATE TABLE ipblocks ( ipb_address TEXT NULL, ipb_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, ipb_by INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE CASCADE, + ipb_by_text TEXT NOT NULL DEFAULT '', ipb_reason TEXT NOT NULL, ipb_timestamp TIMESTAMPTZ NOT NULL, ipb_auto SMALLINT NOT NULL DEFAULT 0, @@ -282,8 +291,9 @@ CREATE INDEX oi_name_archive_name ON oldimage (oi_name,oi_archive_name); CREATE INDEX oi_sha1 ON oldimage (oi_sha1); +CREATE SEQUENCE filearchive_fa_id_seq; CREATE TABLE filearchive ( - fa_id SERIAL NOT NULL PRIMARY KEY, + fa_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('filearchive_fa_id_seq'), fa_name TEXT NOT NULL, fa_archive_name TEXT, fa_storage_group TEXT, @@ -430,8 +440,9 @@ CREATE INDEX logging_user_time ON logging (log_timestamp, log_user); CREATE INDEX logging_page_time ON logging (log_namespace, log_title, log_timestamp); +CREATE SEQUENCE trackbacks_tb_id_seq; CREATE TABLE trackbacks ( - tb_id SERIAL NOT NULL PRIMARY KEY, + tb_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('trackbacks_tb_id_seq'), tb_page INTEGER REFERENCES page(page_id) ON DELETE CASCADE, tb_title TEXT NOT NULL, tb_url TEXT NOT NULL, @@ -453,6 +464,7 @@ CREATE INDEX job_cmd_namespace_title ON job (job_cmd, job_namespace, job_title); -- Tsearch2 2 stuff. Will fail if we don't have proper access to the tsearch2 tables -- Note: if version 8.3 or higher, we remove the 'default' arg +-- Make sure you also change patch-tsearch2funcs.sql if the funcs below change. ALTER TABLE page ADD titlevector tsvector; CREATE FUNCTION ts2_page_title() RETURNS TRIGGER LANGUAGE plpgsql AS @@ -503,6 +515,7 @@ $mw$; CREATE TABLE profiling ( pf_count INTEGER NOT NULL DEFAULT 0, pf_time NUMERIC(18,10) NOT NULL DEFAULT 0, + pf_memory NUMERIC(18,10) NOT NULL DEFAULT 0, pf_name TEXT NOT NULL, pf_server TEXT NULL ); @@ -519,6 +532,24 @@ CREATE TABLE protected_titles ( ); CREATE UNIQUE INDEX protected_titles_unique ON protected_titles(pt_namespace, pt_title); + +CREATE TABLE updatelog ( + ul_key TEXT NOT NULL PRIMARY KEY +); + + +CREATE SEQUENCE category_id_seq; +CREATE TABLE category ( + cat_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('category_id_seq'), + cat_title TEXT NOT NULL, + cat_pages INTEGER NOT NULL DEFAULT 0, + cat_subcats INTEGER NOT NULL DEFAULT 0, + cat_files INTEGER NOT NULL DEFAULT 0, + cat_hidden SMALLINT NOT NULL DEFAULT 0 +); +CREATE UNIQUE INDEX category_title ON category(cat_title); +CREATE INDEX category_pages ON category(cat_pages); + CREATE TABLE mediawiki_version ( type TEXT NOT NULL, mw_version TEXT NOT NULL, @@ -538,5 +569,5 @@ CREATE TABLE mediawiki_version ( ); INSERT INTO mediawiki_version (type,mw_version,sql_version,sql_date) - VALUES ('Creation','??','$LastChangedRevision: 30800 $','$LastChangedDate: 2008-02-10 08:50:38 -0800 (Sun, 10 Feb 2008) $'); + VALUES ('Creation','??','$LastChangedRevision: 37542 $','$LastChangedDate: 2008-07-11 08:11:11 +1000 (Fri, 11 Jul 2008) $'); diff --git a/maintenance/preprocessorFuzzTest.php b/maintenance/preprocessorFuzzTest.php index d814c4fe..34960e01 100644 --- a/maintenance/preprocessorFuzzTest.php +++ b/maintenance/preprocessorFuzzTest.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup Maintenance + */ require_once( dirname( __FILE__ ). '/../maintenance/commandLine.inc' ); diff --git a/maintenance/purgeList.php b/maintenance/purgeList.php index 99fb8a87..ab8ff9fb 100644 --- a/maintenance/purgeList.php +++ b/maintenance/purgeList.php @@ -1,7 +1,9 @@ <?php - /** * Send purge requests for listed pages to squid + * + * @file + * @ingroup Maintenance */ require_once( "commandLine.inc" ); diff --git a/maintenance/purgeOldText.inc b/maintenance/purgeOldText.inc index c4732e97..e41c374d 100644 --- a/maintenance/purgeOldText.inc +++ b/maintenance/purgeOldText.inc @@ -3,7 +3,8 @@ /** * Support functions for cleaning up redundant text records * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -59,5 +60,3 @@ function PurgeRedundantText( $delete = false ) { $dbw->commit(); } - -?> diff --git a/maintenance/purgeOldText.php b/maintenance/purgeOldText.php index 3e80c320..4a4be482 100644 --- a/maintenance/purgeOldText.php +++ b/maintenance/purgeOldText.php @@ -3,7 +3,8 @@ /** * Purge old text records from the database * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/reassignEdits.inc.php b/maintenance/reassignEdits.inc.php index da050163..e68b4cf5 100644 --- a/maintenance/reassignEdits.inc.php +++ b/maintenance/reassignEdits.inc.php @@ -3,7 +3,8 @@ /** * Support functions for the reassignEdits script * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> * @licence GNU General Public Licence 2.0 or later */ @@ -80,7 +81,7 @@ function reassignEdits( &$from, &$to, $rc = false, $report = false ) { * @return array */ function userConditions( &$user, $idfield, $utfield ) { - return $user->getId() ? array( $idfield => $user->getID() ) : array( $utfield => $user->getName() ); + return $user->getId() ? array( $idfield => $user->getId() ) : array( $utfield => $user->getName() ); } /** diff --git a/maintenance/reassignEdits.php b/maintenance/reassignEdits.php index 07f81b8a..0d640202 100644 --- a/maintenance/reassignEdits.php +++ b/maintenance/reassignEdits.php @@ -3,7 +3,8 @@ /** * Reassign edits from a user or IP address to another user * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> * @licence GNU General Public Licence 2.0 or later */ diff --git a/maintenance/rebuildImages.php b/maintenance/rebuildImages.php index dfdb3b20..46b5d0ed 100644 --- a/maintenance/rebuildImages.php +++ b/maintenance/rebuildImages.php @@ -25,8 +25,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @author Brion Vibber <brion at pobox.com> - * @addtogroup maintenance + * @ingrouo maintenance */ $options = array( 'missing', 'dry-run' ); diff --git a/maintenance/rebuildInterwiki.inc b/maintenance/rebuildInterwiki.inc index a14f8897..923c25a9 100644 --- a/maintenance/rebuildInterwiki.inc +++ b/maintenance/rebuildInterwiki.inc @@ -3,20 +3,19 @@ * Rebuild interwiki table using the file on meta and the language list * Wikimedia specific! * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ -/** */ - /** * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ class Site { var $suffix, $lateral, $url; - function Site( $s, $l, $u ) { + function __construct( $s, $l, $u ) { $this->suffix = $s; $this->lateral = $l; $this->url = $u; @@ -98,7 +97,7 @@ function makeInterwikiSQL( $destDir ) { } # Extract the intermap from meta - $intermap = wfGetHTTP( 'http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw', 30 ); + $intermap = Http::get( 'http://meta.wikimedia.org/w/index.php?title=Interwiki_map&action=raw', 30 ); $lines = array_map( 'trim', explode( "\n", trim( $intermap ) ) ); if ( !$lines || count( $lines ) < 2 ) { @@ -257,5 +256,3 @@ function makeLink( $entry, &$first, $source ) { $sql .= "(" . $dbr->makeList( $entry ) . ")"; return $sql; } - -?> diff --git a/maintenance/rebuildInterwiki.php b/maintenance/rebuildInterwiki.php index 08968421..9a3cfd98 100644 --- a/maintenance/rebuildInterwiki.php +++ b/maintenance/rebuildInterwiki.php @@ -2,8 +2,10 @@ /** * Rebuild interwiki table using the file on meta and the language list * Wikimedia specific! + * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** */ diff --git a/maintenance/rebuildall.php b/maintenance/rebuildall.php index 1c2647b2..ca7e4c06 100644 --- a/maintenance/rebuildall.php +++ b/maintenance/rebuildall.php @@ -2,8 +2,10 @@ /** * Rebuild link tracking tables from scratch. This takes several * hours, depending on the database size and server configuration. + * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** */ @@ -14,12 +16,15 @@ require_once( "refreshLinks.inc" ); require_once( "rebuildtextindex.inc" ); require_once( "rebuildrecentchanges.inc" ); -$database = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname ); +$dbclass = 'Database' . ucfirst( $wgDBtype ) ; +$database = new $dbclass( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname ); -print "** Rebuilding fulltext search index (if you abort this will break searching; run this script again to fix):\n"; -dropTextIndex( $database ); -rebuildTextIndex( $database ); -createTextIndex( $database ); +if ($wgDBtype == 'mysql') { + print "** Rebuilding fulltext search index (if you abort this will break searching; run this script again to fix):\n"; + dropTextIndex( $database ); + rebuildTextIndex( $database ); + createTextIndex( $database ); +} print "\n\n** Rebuilding recentchanges table:\n"; rebuildRecentChangesTable(); diff --git a/maintenance/rebuildmessages.php b/maintenance/rebuildmessages.php index dea70ef8..b0adc875 100644 --- a/maintenance/rebuildmessages.php +++ b/maintenance/rebuildmessages.php @@ -1,4 +1,9 @@ <?php +/** + * This script purges all language messages from memcached + * @file + * @ingroup Maintenance + */ require_once( 'commandLine.inc' ); @@ -10,8 +15,8 @@ if( $wgLocalDatabases ) { foreach( $databases as $db ) { echo "Deleting message cache for {$db}... "; - $wgMessageCache->mMemc->delete( "{$db}:messages" ); + $messageMemc->delete( "{$db}:messages" ); if( $wgEnableSidebarCache ) - $wgMessageCache->mMemc->delete( "{$db}:sidebar" ); + $messageMemc->delete( "{$db}:sidebar" ); echo "Deleted\n"; -}
\ No newline at end of file +} diff --git a/maintenance/rebuildrecentchanges.inc b/maintenance/rebuildrecentchanges.inc index 8b2c7805..f846d2b7 100644 --- a/maintenance/rebuildrecentchanges.inc +++ b/maintenance/rebuildrecentchanges.inc @@ -2,8 +2,9 @@ /** * Rebuild recent changes table. * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** Public entry; more passes might come in! :) */ @@ -11,12 +12,12 @@ function rebuildRecentChangesTable() { rebuildRecentChangesTablePass1(); rebuildRecentChangesTablePass2(); rebuildRecentChangesTablePass3(); + rebuildRecentChangesTablePass4(); } /** */ function rebuildRecentChangesTablePass1() { - $fname = 'rebuildRecentChangesTablePass1'; $dbw = wfGetDB( DB_MASTER ); $dbw->delete( 'recentchanges', '*' ); @@ -24,6 +25,15 @@ function rebuildRecentChangesTablePass1() print( "Loading from page and revision tables...\n" ); global $wgRCMaxAge; + + print( '$wgRCMaxAge=' . $wgRCMaxAge ); + $days = $wgRCMaxAge / 24 / 3600; + if ( intval($days) == $days ) { + print( " (" . $days . " days)\n" ); + } else { + print( " (approx. " . intval($days) . " days)\n" ); + } + $cutoff = time() - $wgRCMaxAge; $dbw->insertSelect( 'recentchanges', array( 'page', 'revision' ), array( @@ -41,10 +51,11 @@ function rebuildRecentChangesTablePass1() 'rc_this_oldid' => 'rev_id', 'rc_last_oldid' => 0, // is this ok? 'rc_type' => $dbw->conditional( 'page_is_new != 0', RC_NEW, RC_EDIT ), + 'rc_deleted' => 'rev_deleted' ), array( 'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ), 'rev_page=page_id' - ), $fname, + ), __METHOD__, array(), // INSERT options array( 'ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 5000 ) // SELECT options ); @@ -70,18 +81,19 @@ function rebuildRecentChangesTablePass2() # Switch! Look up the previous last edit, if any $lastCurId = intval( $obj->rc_cur_id ); $emit = $obj->rc_timestamp; - $sql2 = "SELECT rev_id, rev_len FROM $revision " . + $sql2 = "SELECT rev_id,rev_len FROM $revision " . "WHERE rev_page={$lastCurId} ". "AND rev_timestamp<'{$emit}' ORDER BY rev_timestamp DESC LIMIT 1"; $res2 = $dbw->query( $sql2 ); if( $row = $dbw->fetchObject( $res2 ) ) { - $lastOldId = intval( $row->rev_id ); - $lastSize = $row->rev_len; # Grab the last text size + $lastOldId = intval($row->rev_id); + # Grab the last text size if available + $lastSize = !is_null($row->rev_len) ? intval($row->rev_len) : 'NULL'; } else { # No previous edit $lastOldId = 0; $lastSize = 'NULL'; - $new = 1; + $new = 1; // probably true } $dbw->freeResult( $res2 ); } @@ -90,10 +102,10 @@ function rebuildRecentChangesTablePass2() } else { # Grab the entry's text size $size = $dbw->selectField( 'revision', 'rev_len', array('rev_id' => $obj->rc_this_oldid ) ); - $size = $size ? $size : 'NULL'; + $size = !is_null($size) ? intval($size) : 'NULL'; $sql3 = "UPDATE $recentchanges SET rc_last_oldid=$lastOldId,rc_new=$new,rc_type=$new," . - "rc_old_len='$lastSize',rc_new_len='$size' " . + "rc_old_len=$lastSize,rc_new_len=$size " . "WHERE rc_cur_id={$lastCurId} AND rc_this_oldid={$obj->rc_this_oldid}"; $dbw->query( $sql3 ); @@ -105,6 +117,67 @@ function rebuildRecentChangesTablePass2() function rebuildRecentChangesTablePass3() { + $dbw = wfGetDB( DB_MASTER ); + + print( "Loading from user, page, and logging tables...\n" ); + + global $wgRCMaxAge; + // Some logs don't go in RC. This can't really detect all of those. + // At least do the basics logs for a standard install... + // FIXME: this needs to be maintained + $basicRCLogs = array( + 'block', + 'protect', + 'rights', + 'delete', + 'upload', + 'move', + 'import', + 'merge' ); + // Escape...blah blah + $selectLogs = array(); + foreach( $basicRCLogs as $logtype ) { + $safetype = $dbw->strencode( $logtype ); + $selectLogs[] = "'$safetype'"; + } + + $cutoff = time() - $wgRCMaxAge; + $dbw->insertSelect( 'recentchanges', array( 'logging', 'page', 'user' ), + array( + 'rc_timestamp' => 'log_timestamp', + 'rc_cur_time' => 'log_timestamp', + 'rc_user' => 'log_user', + 'rc_user_text' => 'user_name', + 'rc_namespace' => 'log_namespace', + 'rc_title' => 'log_title', + 'rc_comment' => 'log_comment', + 'rc_minor' => 0, + 'rc_bot' => 0, + 'rc_patrolled' => 1, + 'rc_new' => 0, + 'rc_this_oldid' => 0, + 'rc_last_oldid' => 0, + 'rc_type' => RC_LOG, + 'rc_cur_id' => 'page_id', + 'rc_log_type' => 'log_type', + 'rc_log_action' => 'log_action', + 'rc_logid' => 'log_id', + 'rc_params' => 'log_params', + 'rc_deleted' => 'log_deleted' + ), array( + 'log_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ), + 'log_user=user_id', + 'log_namespace=page_namespace', + 'log_title=page_title', + 'log_type IN(' . implode(',',$selectLogs) . ')' + ), __METHOD__, + array(), // INSERT options + array( 'ORDER BY' => 'log_timestamp DESC', 'LIMIT' => 5000 ) // SELECT options + ); +} + +function rebuildRecentChangesTablePass4() +{ global $wgGroupPermissions, $wgUseRCPatrol; $dbw = wfGetDB( DB_MASTER ); @@ -143,8 +216,9 @@ function rebuildRecentChangesTablePass3() $dbw->query( $sql2 ); } } + global $wgMiserMode; # Flag our recent autopatrolled edits - if( !empty($autopatrolgroups) ) { + if( !$wgMiserMode && !empty($autopatrolgroups) ) { $patrolwhere = implode(',',$autopatrolgroups); $patrolusers = array(); @@ -170,5 +244,3 @@ function rebuildRecentChangesTablePass3() $dbw->freeResult( $res ); } - -?> diff --git a/maintenance/rebuildrecentchanges.php b/maintenance/rebuildrecentchanges.php index 3c455c55..9311d0fa 100644 --- a/maintenance/rebuildrecentchanges.php +++ b/maintenance/rebuildrecentchanges.php @@ -3,8 +3,9 @@ * Rebuild link tracking tables from scratch. This takes several * hours, depending on the database size and server configuration. * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** */ diff --git a/maintenance/rebuildtextindex.inc b/maintenance/rebuildtextindex.inc index ef65eeda..0f58fffa 100644 --- a/maintenance/rebuildtextindex.inc +++ b/maintenance/rebuildtextindex.inc @@ -7,8 +7,9 @@ require_once 'counter.php'; * Rebuilding is faster if you drop the index and recreate it, * but that will prevent searches from working while it runs. * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** */ @@ -63,5 +64,3 @@ function rebuildTextIndex( &$database ) $n += RTI_CHUNK_SIZE; } } - -?> diff --git a/maintenance/rebuildtextindex.php b/maintenance/rebuildtextindex.php index 47d297a9..73dca87f 100644 --- a/maintenance/rebuildtextindex.php +++ b/maintenance/rebuildtextindex.php @@ -3,11 +3,12 @@ * Rebuild search index table from scratch. This takes several * hours, depending on the database size and server configuration. * - * This is only for MySQL (see bug 9905). For postgres we can probably - * use SearchPostgres::update($pageid); + * This is only for MySQL (see bug 9905). + * Postgres is trigger-based and should never need rebuilding. * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** */ diff --git a/maintenance/refreshImageCount.php b/maintenance/refreshImageCount.php index 0f06c985..14f842b9 100644 --- a/maintenance/refreshImageCount.php +++ b/maintenance/refreshImageCount.php @@ -1,7 +1,11 @@ <?php - -// Quickie hack; patch-ss_images.sql uses variables which don't -// replicate properly. +/** + * Quickie hack; patch-ss_images.sql uses variables which don't + * replicate properly. + * + * @file + * @ingroup Maintenance + */ require_once( "commandLine.inc" ); diff --git a/maintenance/refreshLinks.inc b/maintenance/refreshLinks.inc index e89db8aa..6d68e277 100644 --- a/maintenance/refreshLinks.inc +++ b/maintenance/refreshLinks.inc @@ -1,16 +1,14 @@ <?php /** * @todo document - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ -/** */ -define( "REPORTING_INTERVAL", 100 ); -#define( "REPORTING_INTERVAL", 1 ); - -function refreshLinks( $start, $newOnly = false, $maxLag = false, $end = 0, $redirectsOnly = false ) { - global $wgUser, $wgParser, $wgUseImageResize, $wgUseTidy; +function refreshLinks( $start, $newOnly = false, $maxLag = false, $end = 0, $redirectsOnly = false, $oldRedirectsOnly = false ) { + global $wgUser, $wgParser, $wgUseTidy; + $reportingInterval = 100; $fname = 'refreshLinks'; $dbr = wfGetDB( DB_SLAVE ); $start = intval( $start ); @@ -21,19 +19,39 @@ function refreshLinks( $start, $newOnly = false, $maxLag = false, $end = 0, $red # Don't generate extension images (e.g. Timeline) $wgParser->clearTagHooks(); - # Don't generate thumbnail images - $wgUseImageResize = false; + # Don't use HTML tidy $wgUseTidy = false; - $what = ($redirectsOnly)? "redirects" : "links"; + $what = $redirectsOnly ? "redirects" : "links"; + + if( $oldRedirectsOnly ) { + # This entire code path is cut-and-pasted from below. Hurrah. + $res = $dbr->query( + "SELECT page_id ". + "FROM page ". + "LEFT JOIN redirect ON page_id=rd_from ". + "WHERE page_is_redirect=1 AND rd_from IS NULL AND ". + ($end == 0 ? "page_id >= $start" + : "page_id BETWEEN $start AND $end"), + $fname + ); + $num = $dbr->numRows( $res ); + print "Refreshing $num old redirects from $start...\n"; - if ( $newOnly ) { + while( $row = $dbr->fetchObject( $res ) ) { + if ( !( ++$i % $reportingInterval ) ) { + print "$i\n"; + wfWaitForSlaves( $maxLag ); + } + fixRedirect( $row->page_id ); + } + } elseif( $newOnly ) { print "Refreshing $what from "; $res = $dbr->select( 'page', array( 'page_id' ), array( 'page_is_new' => 1, - "page_id > $start" ), + "page_id >= $start" ), $fname ); $num = $dbr->numRows( $res ); @@ -41,7 +59,7 @@ function refreshLinks( $start, $newOnly = false, $maxLag = false, $end = 0, $red $i = 0; while ( $row = $dbr->fetchObject( $res ) ) { - if ( !( ++$i % REPORTING_INTERVAL ) ) { + if ( !( ++$i % $reportingInterval ) ) { print "$i\n"; wfWaitForSlaves( $maxLag ); } @@ -59,7 +77,7 @@ function refreshLinks( $start, $newOnly = false, $maxLag = false, $end = 0, $red for ($id = $start; $id <= $end; $id++) { - if ( !($id % REPORTING_INTERVAL) ) { + if ( !($id % $reportingInterval) ) { print "$id\n"; wfWaitForSlaves( $maxLag ); } @@ -121,7 +139,7 @@ function deleteLinksFromNonexistent( $maxLag = 0 ) { wfWaitForSlaves( $maxLag ); - $dbw = wfGetDB( DB_WRITE ); + $dbw = wfGetDB( DB_MASTER ); $linksTables = array( 'pagelinks' => 'pl_from', diff --git a/maintenance/refreshLinks.php b/maintenance/refreshLinks.php index 67fb77ae..4893d580 100644 --- a/maintenance/refreshLinks.php +++ b/maintenance/refreshLinks.php @@ -1,6 +1,7 @@ <?php /** - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ /** */ @@ -11,13 +12,20 @@ require_once( "refreshLinks.inc" ); if( isset( $options['help'] ) ) { echo <<<TEXT -Usage: php refreshLinks.php [<start>] [-e <end>] [-m <maxlag>] [--help] - - --help : This help message - --dfn-only : Delete links from nonexistent articles only - -m <number> : Maximum replication lag - <start> : First page id to refresh - -e <number> : Last page id to refresh +Usage: + php refreshLinks.php --help + php refreshLinks.php [<start>] [-e <end>] [-m <maxlag>] [--dfn-only] + [--new-only] [--redirects-only] + php refreshLinks.php [<start>] [-e <end>] [-m <maxlag>] --old-redirects-only + + --help : This help message + --dfn-only : Delete links from nonexistent articles only + --new-only : Only affect articles with just a single edit + --redirects-only : Only fix redirects, not all links + --old-redirects-only : Only fix redirects with no redirect table entry + -m <number> : Maximum replication lag + <start> : First page id to refresh + -e <number> : Last page id to refresh TEXT; exit(0); @@ -32,7 +40,7 @@ if ( !$options['dfn-only'] ) { $start = 1; } - refreshLinks( $start, $options['new-only'], $options['m'], $options['e'], $options['redirects-only'] ); + refreshLinks( $start, $options['new-only'], $options['m'], $options['e'], $options['redirects-only'], $options['old-redirects-only'] ); } // this bit's bad for replication: disabling temporarily // --brion 2005-07-16 diff --git a/maintenance/removeUnusedAccounts.inc b/maintenance/removeUnusedAccounts.inc index 20791230..8f900272 100644 --- a/maintenance/removeUnusedAccounts.inc +++ b/maintenance/removeUnusedAccounts.inc @@ -3,8 +3,8 @@ /** * Support functions for the removeUnusedAccounts maintenance script * - * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -42,5 +42,3 @@ function showHelp() { echo( " --delete : Delete accounts which are discovered to be inactive\n" ); echo( "\n" ); } - -?>
\ No newline at end of file diff --git a/maintenance/removeUnusedAccounts.php b/maintenance/removeUnusedAccounts.php index 26be1309..636832cb 100644 --- a/maintenance/removeUnusedAccounts.php +++ b/maintenance/removeUnusedAccounts.php @@ -1,10 +1,10 @@ <?php - /** * Remove unused user accounts from the database * An unused account is one which has made no edits * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/renamewiki.php b/maintenance/renamewiki.php index d9fe6e76..66de326b 100644 --- a/maintenance/renamewiki.php +++ b/maintenance/renamewiki.php @@ -1,11 +1,14 @@ <?php -require_once( "commandLine.inc" ); - /** * Why yes, this *is* another special-purpose Wikimedia maintenance script! * Should be fixed up and generalized. + * + * @file + * @ingroup Maintenance */ +require_once( "commandLine.inc" ); + if ( count( $args ) != 2 ) { wfDie( "Rename external storage dbs and leave a new one...\n" . "Usage: php renamewiki.php <olddb> <newdb>\n" ); diff --git a/maintenance/renderDump.php b/maintenance/renderDump.php index 4b6322d5..97797792 100644 --- a/maintenance/renderDump.php +++ b/maintenance/renderDump.php @@ -24,7 +24,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ $optionsWithArgs = array( 'report' ); diff --git a/maintenance/runJobs.php b/maintenance/runJobs.php index 799092e1..14d08091 100644 --- a/maintenance/runJobs.php +++ b/maintenance/runJobs.php @@ -1,4 +1,14 @@ <?php +/** + * This script starts pending jobs. + * + * Usage: + * --maxjobs <num> (default 10000) + * --type <job_cmd> + * + * @file + * @ingroup Maintenance + */ $optionsWithArgs = array( 'maxjobs', 'type' ); $wgUseNormalUser = true; @@ -35,10 +45,10 @@ while ( $dbw->selectField( 'job', 'count(*)', $conds, 'runJobs.php' ) ) { break; wfWaitForSlaves( 5 ); - print $job->id . " " . $job->toString() . "\n"; + print wfTimestamp( TS_DB ) . " " . $job->id . " " . $job->toString() . "\n"; $offset=$job->id; if ( !$job->run() ) { - print "Error: {$job->error}\n"; + print wfTimestamp( TS_DB ) . " Error: {$job->error}\n"; } if ( $maxJobs && ++$n > $maxJobs ) { break 2; diff --git a/maintenance/showJobs.php b/maintenance/showJobs.php index 2ecc8aca..d4f68db7 100644 --- a/maintenance/showJobs.php +++ b/maintenance/showJobs.php @@ -2,6 +2,10 @@ /** * Based on runJobs.php * + * Report number of jobs currently waiting in master database. + * + * @file + * @ingroup Maintenance * @author Tim Starling * @author Ashar Voultoiz */ diff --git a/maintenance/showStats.php b/maintenance/showStats.php index 97b6a199..ef13f654 100644 --- a/maintenance/showStats.php +++ b/maintenance/showStats.php @@ -4,6 +4,8 @@ * Maintenance script to show the cached statistics. * Give out the same output as [[Special:Statistics]] * + * @file + * @ingroup Maintenance * @author Ashar Voultoiz <hashar@altern.org> * Based on initStats.php by: * @author Brion Vibber diff --git a/maintenance/sql.php b/maintenance/sql.php index 5ec1d8d3..38c995ac 100644 --- a/maintenance/sql.php +++ b/maintenance/sql.php @@ -1,10 +1,10 @@ <?php - /** * Send SQL queries from the specified file to the database, performing * variable replacement along the way. - * - * @addtogroup Database + * + * @file + * @ingroup Database Maintenance */ require_once( dirname(__FILE__) . '/' . 'commandLine.inc' ); diff --git a/maintenance/sqlite/tables.sql b/maintenance/sqlite/tables.sql new file mode 100644 index 00000000..13e2a19b --- /dev/null +++ b/maintenance/sqlite/tables.sql @@ -0,0 +1,340 @@ +CREATE TABLE /*$wgDBprefix*/user ( + user_id INTEGER PRIMARY KEY AUTOINCREMENT, + user_name varchar(255) default '', + user_real_name varchar(255) default '', + user_password tinyblob , + user_newpassword tinyblob , + user_newpass_time BLOB, + user_email tinytext , + user_options blob , + user_touched BLOB default '', + user_token BLOB default '', + user_email_authenticated BLOB, + user_email_token BLOB, + user_email_token_expires BLOB, + user_registration BLOB, + user_editcount int) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/user_groups ( + ug_user INTEGER default '0', + ug_group varBLOB default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/user_newtalk ( + user_id INTEGER default '0', + user_ip varBLOB default '', + user_last_timestamp BLOB default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/page ( + page_id INTEGER PRIMARY KEY AUTOINCREMENT, + page_namespace INTEGER , + page_title varchar(255) , + page_restrictions tinyblob , + page_counter bigint default '0', + page_is_redirect tinyint default '0', + page_is_new tinyint default '0', + page_random real , + page_touched BLOB default '', + page_latest INTEGER , + page_len INTEGER ) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/revision ( + rev_id INTEGER PRIMARY KEY AUTOINCREMENT, + rev_page INTEGER , + rev_text_id INTEGER , + rev_comment tinyblob , + rev_user INTEGER default '0', + rev_user_text varchar(255) default '', + rev_timestamp BLOB default '', + rev_minor_edit tinyint default '0', + rev_deleted tinyint default '0', + rev_len int, + rev_parent_id INTEGER default NULL) /*$wgDBTableOptions*/ ; + +CREATE TABLE /*$wgDBprefix*/text ( + old_id INTEGER PRIMARY KEY AUTOINCREMENT, + old_text mediumblob , + old_flags tinyblob ) /*$wgDBTableOptions*/ ; + +CREATE TABLE /*$wgDBprefix*/archive ( + ar_namespace INTEGER default '0', + ar_title varchar(255) default '', + ar_text mediumblob , + ar_comment tinyblob , + ar_user INTEGER default '0', + ar_user_text varchar(255) , + ar_timestamp BLOB default '', + ar_minor_edit tinyint default '0', + ar_flags tinyblob , + ar_rev_id int, + ar_text_id int, + ar_deleted tinyint default '0', + ar_len int, + ar_page_id int, + ar_parent_id INTEGER default NULL) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/pagelinks ( + pl_from INTEGER default '0', + pl_namespace INTEGER default '0', + pl_title varchar(255) default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/templatelinks ( + tl_from INTEGER default '0', + tl_namespace INTEGER default '0', + tl_title varchar(255) default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/imagelinks ( + il_from INTEGER default '0', + il_to varchar(255) default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/categorylinks ( + cl_from INTEGER default '0', + cl_to varchar(255) default '', + cl_sortkey varchar(70) default '', + cl_timestamp timestamp ) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/category ( + cat_id INTEGER PRIMARY KEY AUTOINCREMENT, + cat_title varchar(255) , + cat_pages INTEGER signed default 0, + cat_subcats INTEGER signed default 0, + cat_files INTEGER signed default 0, + cat_hidden tinyint default 0) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/externallinks ( + el_from INTEGER default '0', + el_to blob , + el_index blob ) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/langlinks ( + ll_from INTEGER default '0', + ll_lang varBLOB default '', + ll_title varchar(255) default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/site_stats ( + ss_row_id INTEGER , + ss_total_views bigint default '0', + ss_total_edits bigint default '0', + ss_good_articles bigint default '0', + ss_total_pages bigint default '-1', + ss_users bigint default '-1', + ss_admins INTEGER default '-1', + ss_images INTEGER default '0') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/hitcounter ( + hc_id INTEGER +) ; + +CREATE TABLE /*$wgDBprefix*/ipblocks ( + ipb_id INTEGER PRIMARY KEY AUTOINCREMENT, + ipb_address tinyblob , + ipb_user INTEGER default '0', + ipb_by INTEGER default '0', + ipb_by_text varchar(255) default '', + ipb_reason tinyblob , + ipb_timestamp BLOB default '', + ipb_auto bool default 0, + ipb_anon_only bool default 0, + ipb_create_account bool default 1, + ipb_enable_autoblock bool default '1', + ipb_expiry varBLOB default '', + ipb_range_start tinyblob , + ipb_range_end tinyblob , + ipb_deleted bool default 0, + ipb_block_email bool default 0) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/image ( + img_name varchar(255) default '', + img_size INTEGER default '0', + img_width INTEGER default '0', + img_height INTEGER default '0', + img_metadata mediumblob , + img_bits INTEGER default '0', + img_media_type TEXT default NULL, + img_major_mime TEXT default "unknown", + img_minor_mime varBLOB default "unknown", + img_description tinyblob , + img_user INTEGER default '0', + img_user_text varchar(255) , + img_timestamp varBLOB default '', + img_sha1 varBLOB default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/oldimage ( + oi_name varchar(255) default '', + oi_archive_name varchar(255) default '', + oi_size INTEGER default 0, + oi_width INTEGER default 0, + oi_height INTEGER default 0, + oi_bits INTEGER default 0, + oi_description tinyblob , + oi_user INTEGER default '0', + oi_user_text varchar(255) , + oi_timestamp BLOB default '', + oi_metadata mediumblob , + oi_media_type TEXT default NULL, + oi_major_mime TEXT default "unknown", + oi_minor_mime varBLOB default "unknown", + oi_deleted tinyint default '0', + oi_sha1 varBLOB default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/filearchive ( + fa_id INTEGER PRIMARY KEY AUTOINCREMENT, + fa_name varchar(255) default '', + fa_archive_name varchar(255) default '', + fa_storage_group varBLOB, + fa_storage_key varBLOB default '', + fa_deleted_user int, + fa_deleted_timestamp BLOB default '', + fa_deleted_reason text, + fa_size INTEGER default '0', + fa_width INTEGER default '0', + fa_height INTEGER default '0', + fa_metadata mediumblob, + fa_bits INTEGER default '0', + fa_media_type TEXT default NULL, + fa_major_mime TEXT default "unknown", + fa_minor_mime varBLOB default "unknown", + fa_description tinyblob, + fa_user INTEGER default '0', + fa_user_text varchar(255) , + fa_timestamp BLOB default '', + fa_deleted tinyint default '0') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/recentchanges ( + rc_id INTEGER PRIMARY KEY AUTOINCREMENT, + rc_timestamp varBLOB default '', + rc_cur_time varBLOB default '', + rc_user INTEGER default '0', + rc_user_text varchar(255) , + rc_namespace INTEGER default '0', + rc_title varchar(255) default '', + rc_comment varchar(255) default '', + rc_minor tinyint default '0', + rc_bot tinyint default '0', + rc_new tinyint default '0', + rc_cur_id INTEGER default '0', + rc_this_oldid INTEGER default '0', + rc_last_oldid INTEGER default '0', + rc_type tinyint default '0', + rc_moved_to_ns tinyint default '0', + rc_moved_to_title varchar(255) default '', + rc_patrolled tinyint default '0', + rc_ip varBLOB default '', + rc_old_len int, + rc_new_len int, + rc_deleted tinyint default '0', + rc_logid INTEGER default '0', + rc_log_type varBLOB NULL default NULL, + rc_log_action varBLOB NULL default NULL, + rc_params blob NULL) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/watchlist ( + wl_user INTEGER , + wl_namespace INTEGER default '0', + wl_title varchar(255) default '', + wl_notificationtimestamp varBLOB) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/math ( + math_inputhash varBLOB , + math_outputhash varBLOB , + math_html_conservativeness tinyint , + math_html text, + math_mathml text) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/searchindex ( + si_page INTEGER , + si_title varchar(255) default '', + si_text mediumtext ) ; + +CREATE TABLE /*$wgDBprefix*/interwiki ( + iw_prefix varchar(32) , + iw_url blob , + iw_local bool , + iw_trans tinyint default 0) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/querycache ( + qc_type varBLOB , + qc_value INTEGER default '0', + qc_namespace INTEGER default '0', + qc_title varchar(255) default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/objectcache ( + keyname varBLOB default '', + value mediumblob, + exptime datetime) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/transcache ( + tc_url varBLOB , + tc_contents text, + tc_time INTEGER ) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/logging ( + log_id INTEGER PRIMARY KEY AUTOINCREMENT, + log_type varBLOB default '', + log_action varBLOB default '', + log_timestamp BLOB default '19700101000000', + log_user INTEGER default 0, + log_namespace INTEGER default 0, + log_title varchar(255) default '', + log_comment varchar(255) default '', + log_params blob , + log_deleted tinyint default '0') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/trackbacks ( + tb_id INTEGER PRIMARY KEY AUTOINCREMENT, + tb_page INTEGER REFERENCES /*$wgDBprefix*/page(page_id) ON DELETE CASCADE, + tb_title varchar(255) , + tb_url blob , + tb_ex text, + tb_name varchar(255)) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/job ( + job_id INTEGER PRIMARY KEY AUTOINCREMENT, + job_cmd varBLOB default '', + job_namespace INTEGER , + job_title varchar(255) , + job_params blob ) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/querycache_info ( + qci_type varBLOB default '', + qci_timestamp BLOB default '19700101000000') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/redirect ( + rd_from INTEGER default '0', + rd_namespace INTEGER default '0', + rd_title varchar(255) default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/querycachetwo ( + qcc_type varBLOB , + qcc_value INTEGER default '0', + qcc_namespace INTEGER default '0', + qcc_title varchar(255) default '', + qcc_namespacetwo INTEGER default '0', + qcc_titletwo varchar(255) default '') /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/page_restrictions ( + pr_page INTEGER , + pr_type varBLOB , + pr_level varBLOB , + pr_cascade tinyint , + pr_user INTEGER NULL, + pr_expiry varBLOB NULL, + pr_id INTEGER PRIMARY KEY AUTOINCREMENT) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/protected_titles ( + pt_namespace INTEGER , + pt_title varchar(255) , + pt_user INTEGER , + pt_reason tinyblob, + pt_timestamp BLOB , + pt_expiry varBLOB default '', + pt_create_perm varBLOB ) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/page_props ( + pp_page INTEGER , + pp_propname varBLOB , + pp_value blob ) /*$wgDBTableOptions*/; + +CREATE TABLE /*$wgDBprefix*/updatelog ( + ul_key varchar(255) ) /*$wgDBTableOptions*/; + + diff --git a/maintenance/stats.php b/maintenance/stats.php index dc8d4b05..9c16e12d 100644 --- a/maintenance/stats.php +++ b/maintenance/stats.php @@ -1,4 +1,11 @@ <?php +/** + * Show statistics from memcached + * + * @file + * @ingroup Maintenance + */ + require_once('commandLine.inc'); if( get_class( $wgMemc ) == 'FakeMemCachedClient' ) { diff --git a/maintenance/storage/blobs.sql b/maintenance/storage/blobs.sql index b50865c6..0b1b82d8 100644 --- a/maintenance/storage/blobs.sql +++ b/maintenance/storage/blobs.sql @@ -4,5 +4,5 @@ CREATE TABLE /*$wgDBprefix*/blobs ( blob_id integer UNSIGNED NOT NULL AUTO_INCREMENT, blob_text longblob, PRIMARY KEY (blob_id) -) TYPE=MyISAM MAX_ROWS=1000000 AVG_ROW_LENGTH=1000000; +) ENGINE=MyISAM MAX_ROWS=1000000 AVG_ROW_LENGTH=1000000; diff --git a/maintenance/storage/checkStorage.php b/maintenance/storage/checkStorage.php index d50ef366..245c2fec 100644 --- a/maintenance/storage/checkStorage.php +++ b/maintenance/storage/checkStorage.php @@ -1,7 +1,9 @@ <?php - /** * Fsck for MediaWiki + * + * @file + * @ingroup Maintenance ExternalStorage */ define( 'CONCAT_HEADER', 'O:27:"concatenatedgziphistoryblob"' ); @@ -22,8 +24,10 @@ if ( !defined( 'MEDIAWIKI' ) ) { //---------------------------------------------------------------------------------- -class CheckStorage -{ +/** + * @ingroup Maintenance ExternalStorage + */ +class CheckStorage { var $oldIdMap, $errors; var $dbStore = null; diff --git a/maintenance/storage/compressOld.inc b/maintenance/storage/compressOld.inc index 421f5304..52b9c40b 100644 --- a/maintenance/storage/compressOld.inc +++ b/maintenance/storage/compressOld.inc @@ -1,6 +1,7 @@ <?php /** - * @addtogroup Maintenance + * @file + * @ingroup Maintenance ExternalStorage */ /** */ @@ -300,4 +301,3 @@ function compressWithConcat( $startId, $maxChunkSize, $maxChunkFactor, $factorTh } return true; } -?> diff --git a/maintenance/storage/compressOld.php b/maintenance/storage/compressOld.php index 794e89d1..dda765d7 100644 --- a/maintenance/storage/compressOld.php +++ b/maintenance/storage/compressOld.php @@ -1,13 +1,7 @@ <?php /** - * Compress the text of a wiki + * Compress the text of a wiki. * - * @addtogroup Maintenance - */ - -/** */ - -/** * Usage: * * Non-wikimedia @@ -28,6 +22,8 @@ * -h <threshold> is a minimum number of KB, where <max-factor> cuts in * --extdb <cluster> store specified revisions in an external cluster (untested) * + * @file + * @ingroup Maintenance ExternalStorage */ $optionsWithArgs = array( 't', 'c', 's', 'f', 'h', 'extdb', 'endid', 'e' ); diff --git a/maintenance/storage/dumpRev.php b/maintenance/storage/dumpRev.php index 4c31b4e1..720eb958 100644 --- a/maintenance/storage/dumpRev.php +++ b/maintenance/storage/dumpRev.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup Maintenance ExternalStorage + */ require_once( dirname(__FILE__) . '/../commandLine.inc' ); diff --git a/maintenance/storage/moveToExternal.php b/maintenance/storage/moveToExternal.php index 993aa64c..a8b2f93b 100644 --- a/maintenance/storage/moveToExternal.php +++ b/maintenance/storage/moveToExternal.php @@ -1,9 +1,15 @@ <?php +/** + * Move revision's text to external storage + * + * @file + * @ingroup Maintenance ExternalStorage + */ define( 'REPORTING_INTERVAL', 1 ); if ( !defined( 'MEDIAWIKI' ) ) { - $optionsWithArgs = array( 'm', 's' ); + $optionsWithArgs = array( 'e', 's' ); require_once( dirname(__FILE__) . '/../commandLine.inc' ); require_once( 'ExternalStoreDB.php' ); diff --git a/maintenance/storage/resolveStubs.php b/maintenance/storage/resolveStubs.php index 5dfaa598..3db9e480 100644 --- a/maintenance/storage/resolveStubs.php +++ b/maintenance/storage/resolveStubs.php @@ -1,4 +1,8 @@ <?php +/** + * @file + * @ingroup Maintenance ExternalStorage + */ define( 'REPORTING_INTERVAL', 100 ); diff --git a/maintenance/tables.sql b/maintenance/tables.sql index 6282f522..11ed7cb2 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -166,6 +166,9 @@ CREATE TABLE /*$wgDBprefix*/user_newtalk ( -- If the user is an anonymous user their IP address is stored here -- since the user_id of 0 is ambiguous user_ip varbinary(40) NOT NULL default '', + -- The highest timestamp of revisions of the talk page viewed + -- by this user + user_last_timestamp binary(14) NOT NULL default '', INDEX user_id (user_id), INDEX user_ip (user_ip) @@ -384,6 +387,9 @@ CREATE TABLE /*$wgDBprefix*/archive ( -- Will be NULL for pages deleted prior to 1.11. ar_page_id int unsigned, + -- Original previous revision + ar_parent_id int unsigned default NULL, + KEY name_title_timestamp (ar_namespace,ar_title,ar_timestamp), KEY usertext_timestamp (ar_user_text,ar_timestamp) @@ -486,6 +492,39 @@ CREATE TABLE /*$wgDBprefix*/categorylinks ( ) /*$wgDBTableOptions*/; +-- +-- Track all existing categories. Something is a category if 1) it has an en- +-- try somewhere in categorylinks, or 2) it once did. Categories might not +-- have corresponding pages, so they need to be tracked separately. +-- +CREATE TABLE /*$wgDBprefix*/category ( + -- Primary key + cat_id int unsigned NOT NULL auto_increment, + + -- Name of the category, in the same form as page_title (with underscores). + -- If there is a category page corresponding to this category, by definition, + -- it has this name (in the Category namespace). + cat_title varchar(255) binary NOT NULL, + + -- The numbers of member pages (including categories and media), subcatego- + -- ries, and Image: namespace members, respectively. These are signed to + -- make underflow more obvious. We make the first number include the second + -- two for better sorting: subtracting for display is easy, adding for order- + -- 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, + + PRIMARY KEY (cat_id), + UNIQUE KEY (cat_title), + + -- For Special:Mostlinkedcategories + KEY (cat_pages) +) /*$wgDBTableOptions*/; + -- -- Track links to external URLs -- @@ -577,7 +616,7 @@ CREATE TABLE /*$wgDBprefix*/site_stats ( -- CREATE TABLE /*$wgDBprefix*/hitcounter ( hc_id int unsigned NOT NULL -) TYPE=HEAP MAX_ROWS=25000; +) ENGINE=HEAP MAX_ROWS=25000; -- @@ -597,6 +636,9 @@ CREATE TABLE /*$wgDBprefix*/ipblocks ( -- User ID who made the block. ipb_by int unsigned NOT NULL default '0', + -- User name of blocker + ipb_by_text varchar(255) binary NOT NULL default '', + -- Text comment made by blocker. ipb_reason tinyblob NOT NULL, @@ -703,8 +745,7 @@ CREATE TABLE /*$wgDBprefix*/image ( INDEX img_size (img_size), -- Used by Special:Newimages and Special:Imagelist INDEX img_timestamp (img_timestamp), - - -- For future use + -- Used in API and duplicate search INDEX img_sha1 (img_sha1) @@ -799,7 +840,7 @@ CREATE TABLE /*$wgDBprefix*/filearchive ( INDEX (fa_name, fa_timestamp), -- pick out by image name INDEX (fa_storage_group, fa_storage_key), -- pick out dupe files INDEX (fa_deleted_timestamp), -- sort by deletion time - INDEX (fa_deleted_user) -- sort by deleter + INDEX fa_user_timestamp (fa_user_text,fa_timestamp) -- sort by uploader ) /*$wgDBTableOptions*/; @@ -953,7 +994,7 @@ CREATE TABLE /*$wgDBprefix*/searchindex ( FULLTEXT si_title (si_title), FULLTEXT si_text (si_text) -) TYPE=MyISAM; +) ENGINE=MyISAM; -- -- Recognized interwiki link prefixes @@ -1019,6 +1060,9 @@ CREATE TABLE /*$wgDBprefix*/transcache ( ) /*$wgDBTableOptions*/; CREATE TABLE /*$wgDBprefix*/logging ( + -- Log ID, for referring to this specific log entry, probably for deletion and such. + log_id int unsigned NOT NULL auto_increment, + -- Symbolic keys for the general log type and the action type -- within the log. The output format will be controlled by the -- action field, but only the type controls categorization. @@ -1042,9 +1086,6 @@ CREATE TABLE /*$wgDBprefix*/logging ( -- LF separated list of miscellaneous parameters log_params blob NOT NULL, - -- Log ID, for referring to this specific log entry, probably for deletion and such. - log_id int unsigned NOT NULL auto_increment, - -- rev_deleted for logs log_deleted tinyint unsigned NOT NULL default '0', @@ -1058,7 +1099,7 @@ CREATE TABLE /*$wgDBprefix*/logging ( CREATE TABLE /*$wgDBprefix*/trackbacks ( tb_id int auto_increment, - tb_page int REFERENCES page(page_id) ON DELETE CASCADE, + tb_page int REFERENCES /*$wgDBprefix*/page(page_id) ON DELETE CASCADE, tb_title varchar(255) NOT NULL, tb_url blob NOT NULL, tb_ex text, @@ -1171,7 +1212,7 @@ CREATE TABLE /*$wgDBprefix*/page_restrictions ( -- Protected titles - nonexistent pages that have been protected CREATE TABLE /*$wgDBprefix*/protected_titles ( pt_namespace int NOT NULL, - pt_title varchar(255) NOT NULL, + pt_title varchar(255) binary NOT NULL, pt_user int unsigned NOT NULL, pt_reason tinyblob, pt_timestamp binary(14) NOT NULL, @@ -1181,4 +1222,19 @@ CREATE TABLE /*$wgDBprefix*/protected_titles ( KEY pt_timestamp (pt_timestamp) ) /*$wgDBTableOptions*/; +-- Name/value pairs indexed by page_id +CREATE TABLE /*$wgDBprefix*/page_props ( + pp_page int NOT NULL, + pp_propname varbinary(60) NOT NULL, + pp_value blob NOT NULL, + + PRIMARY KEY (pp_page,pp_propname) +) /*$wgDBTableOptions*/; + +-- A table to log updates, one text key row per update. +CREATE TABLE /*$wgDBprefix*/updatelog ( + ul_key varchar(255) NOT NULL, + PRIMARY KEY (ul_key) +) /*$wgDBTableOptions*/; + -- vim: sw=2 sts=2 et diff --git a/maintenance/undelete.php b/maintenance/undelete.php index c9a2f9ed..b7b7df97 100644 --- a/maintenance/undelete.php +++ b/maintenance/undelete.php @@ -1,4 +1,10 @@ <?php +/** + * Undelete a page by fetching it from the archive table + * + * @file + * @ingroup Maintenance + */ $usage = <<<EOT Undelete a page diff --git a/maintenance/update.php b/maintenance/update.php index 2da51b22..3f484137 100644 --- a/maintenance/update.php +++ b/maintenance/update.php @@ -3,8 +3,11 @@ require_once 'counter.php'; /** * Run all updaters. * + * This is used when the database schema is modified and we need to apply patches. + * + * @file * @todo document - * @addtogroup Maintenance + * @ingroup Maintenance */ /** */ diff --git a/maintenance/updateArticleCount.inc.php b/maintenance/updateArticleCount.inc.php index 84fdfddb..de19191e 100644 --- a/maintenance/updateArticleCount.inc.php +++ b/maintenance/updateArticleCount.inc.php @@ -1,9 +1,9 @@ <?php - /** * Support class for the updateArticleCount.php maintenance script * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/updateArticleCount.php b/maintenance/updateArticleCount.php index eda67d8f..a24984a8 100644 --- a/maintenance/updateArticleCount.php +++ b/maintenance/updateArticleCount.php @@ -1,10 +1,10 @@ <?php - /** * Maintenance script to provide a better count of the number of articles * and update the site statistics table, if desired * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/updateRestrictions.php b/maintenance/updateRestrictions.php index c8cebfc4..c2d256e3 100644 --- a/maintenance/updateRestrictions.php +++ b/maintenance/updateRestrictions.php @@ -1,10 +1,12 @@ <?php - -/* +/** * Makes the required database updates for Special:ProtectedPages * to show all protected pages, even ones before the page restrictions * schema change. All remaining page_restriction column values are moved * to the new table. + * + * @file + * @ingroup Maintenance */ define( 'BATCH_SIZE', 100 ); @@ -23,10 +25,13 @@ function migrate_page_restrictions( $db ) { $start = $db->selectField( 'page', 'MIN(page_id)', false, __FUNCTION__ ); $end = $db->selectField( 'page', 'MAX(page_id)', false, __FUNCTION__ ); + # Do remaining chunk + $end += BATCH_SIZE - 1; $blockStart = $start; $blockEnd = $start + BATCH_SIZE - 1; $encodedExpiry = 'infinity'; while ( $blockEnd <= $end ) { + echo "...doing page_id from $blockStart to $blockEnd\n"; $cond = "page_id BETWEEN $blockStart AND $blockEnd AND page_restrictions !='' AND page_restrictions !='edit=:move='"; $res = $db->select( 'page', array('page_id', 'page_restrictions'), $cond, __FUNCTION__ ); $batch = array(); @@ -58,8 +63,8 @@ function migrate_page_restrictions( $db ) { if ( count( $batch ) ) { $db->insert( 'page_restrictions', $batch, __FUNCTION__, array( 'IGNORE' ) ); } - $blockStart += BATCH_SIZE; - $blockEnd += BATCH_SIZE; + $blockStart += BATCH_SIZE - 1; + $blockEnd += BATCH_SIZE - 1; wfWaitForSlaves( 5 ); } } diff --git a/maintenance/updateSearchIndex.inc b/maintenance/updateSearchIndex.inc index bf2b8c37..0cac4508 100644 --- a/maintenance/updateSearchIndex.inc +++ b/maintenance/updateSearchIndex.inc @@ -1,6 +1,7 @@ <?php /** - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ /** */ @@ -112,5 +113,3 @@ function output( $text ) { print $text; } } - -?> diff --git a/maintenance/updateSearchIndex.php b/maintenance/updateSearchIndex.php index a7f25624..f51617bb 100644 --- a/maintenance/updateSearchIndex.php +++ b/maintenance/updateSearchIndex.php @@ -9,7 +9,8 @@ * LOCKTIME is how long the searchindex and cur tables will be locked for * -q means quiet * - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ /** */ diff --git a/maintenance/updateSpecialPages.php b/maintenance/updateSpecialPages.php index 5e0f2ceb..ac7ee11f 100644 --- a/maintenance/updateSpecialPages.php +++ b/maintenance/updateSpecialPages.php @@ -1,6 +1,11 @@ <?php - -# Run this script periodically if you have miser mode enabled, to refresh the caches +/** + * Run this script periodically if you have miser mode enabled, to refresh the + * caches + * + * @file + * @ingroup Maintenance + */ $options = array('only','help'); require_once( 'commandLine.inc' ); @@ -73,12 +78,12 @@ foreach ( $wgQueryPages as $page ) { } # Reopen any connections that have closed - if ( !$wgLoadBalancer->pingAll()) { + if ( !wfGetLB()->pingAll()) { print "\n"; do { print "Connection failed, reconnecting in 10 seconds...\n"; sleep(10); - } while ( !$wgLoadBalancer->pingAll() ); + } while ( !wfGetLB()->pingAll() ); print "Reconnected\n\n"; } else { # Commit the results diff --git a/maintenance/updaters.inc b/maintenance/updaters.inc index 9d7e32cb..67680c49 100644 --- a/maintenance/updaters.inc +++ b/maintenance/updaters.inc @@ -1,10 +1,9 @@ <?php /** - * @addtogroup Maintenance + * @file + * @ingroup Maintenance */ - /** */ - if ( !defined( 'MEDIAWIKI' ) ) { echo "This file is not a valid entry point\n"; exit( 1 ); @@ -57,7 +56,7 @@ $wgMysqlUpdates = array( // 1.5 array( 'do_schema_restructuring' ), array( 'add_field', 'logging', 'log_params', 'patch-log_params.sql' ), - array( 'do_logging_encoding' ), + array( 'check_bin', 'logging', 'log_title', 'patch-logging-title.sql', ), array( 'add_field', 'archive', 'ar_rev_id', 'patch-archive-rev_id.sql' ), array( 'add_field', 'page', 'page_len', 'patch-page_len.sql' ), array( 'do_inverse_timestamp' ), @@ -127,7 +126,23 @@ $wgMysqlUpdates = array( array( 'do_oldimage_user_index' ), array( 'add_field', 'archive', 'ar_page_id', 'patch-archive-page_id.sql'), array( 'add_field', 'image', 'img_sha1', 'patch-img_sha1.sql' ), + + // 1.12 array( 'add_table', 'protected_titles', 'patch-protected_titles.sql' ), + + // 1.13 + array( 'add_field', 'ipblocks', 'ipb_by_text', 'patch-ipb_by_text.sql' ), + array( 'add_table', 'page_props', 'patch-page_props.sql' ), + array( 'add_table', 'updatelog', 'patch-updatelog.sql' ), + array( 'add_table', 'category', 'patch-category.sql' ), + array( 'do_category_population' ), + array( 'add_field', 'archive', 'ar_parent_id', 'patch-ar_parent_id.sql'), + array( 'add_field', 'user_newtalk', 'user_last_timestamp', 'patch-user_last_timestamp.sql'), + array( 'do_populate_parent_id' ), + array( 'check_bin', 'protected_titles', 'pt_title', 'patch-pt_title-encoding.sql', ), + array( 'maybe_do_profiling_memory_update' ), + array( 'do_filearchive_indices_update' ), + array( 'update_password_format' ), ); @@ -138,6 +153,20 @@ $wgExtNewFields = array(); // table, column, dir $wgExtPGNewFields = array(); // table, column attributes; for PostgreSQL $wgExtNewIndexes = array(); // table, index, dir +# Helper function: check if the given key is present in the updatelog table. +# Obviously, only use this for updates that occur after the updatelog table was +# created! +function update_row_exists( $key ) { + $dbr = wfGetDB( DB_SLAVE ); + $row = $dbr->selectRow( + 'updatelog', + '1', + array( 'ul_key' => $key ), + __FUNCTION__ + ); + return (bool)$row; +} + function rename_table( $from, $to, $patch ) { global $wgDatabase; if ( $wgDatabase->tableExists( $from ) ) { @@ -420,20 +449,20 @@ function do_user_update() { * 1.4 betas were missing the 'binary' marker from logging.log_title, * which causes a collation mismatch error on joins in MySQL 4.1. */ -function do_logging_encoding() { +function check_bin( $table, $field, $patchFile ) { global $wgDatabase, $wgDBtype; if ($wgDBtype != 'mysql') return; - $logging = $wgDatabase->tableName( 'logging' ); - $res = $wgDatabase->query( "SELECT log_title FROM $logging LIMIT 0" ); + $tableName = $wgDatabase->tableName( $table ); + $res = $wgDatabase->query( "SELECT $field FROM $tableName LIMIT 0" ); $flags = explode( ' ', mysql_field_flags( $res->result, 0 ) ); $wgDatabase->freeResult( $res ); if( in_array( 'binary', $flags ) ) { - echo "Logging table has correct title encoding.\n"; + echo "$table table has correct $field encoding.\n"; } else { - echo "Fixing title encoding on logging table... "; - dbsource( archive( 'patch-logging-title.sql' ), $wgDatabase ); + echo "Fixing $field encoding on $table table... "; + dbsource( archive( $patchFile ), $wgDatabase ); echo "ok\n"; } } @@ -526,7 +555,7 @@ function do_schema_restructuring() { UNIQUE INDEX name_title (page_namespace,page_title), INDEX (page_random), INDEX (page_len) - ) TYPE=InnoDB", $fname ); + ) ENGINE=InnoDB", $fname ); $wgDatabase->query("CREATE TABLE $revision ( rev_id int(8) unsigned NOT NULL auto_increment, rev_page int(8) unsigned NOT NULL, @@ -544,7 +573,7 @@ function do_schema_restructuring() { INDEX page_timestamp (rev_page,rev_timestamp), INDEX user_timestamp (rev_user,rev_timestamp), INDEX usertext_timestamp (rev_user_text,rev_timestamp) - ) TYPE=InnoDB", $fname ); + ) ENGINE=InnoDB", $fname ); echo wfTimestamp( TS_DB ); echo "......Locking tables.\n"; @@ -942,6 +971,7 @@ function do_backlinking_indices_update() { !index_has_field('imagelinks', 'il_to', 'il_from')) { dbsource( archive( 'patch-backlinkindexes.sql' ) ); + echo( "...backlinking indices updated\n" ); } } @@ -950,6 +980,31 @@ function do_categorylinks_indices_update() { if (!index_has_field('categorylinks', 'cl_sortkey', 'cl_from')) { dbsource( archive( 'patch-categorylinksindex.sql' ) ); + echo( "...categorylinks indices updated\n" ); + } +} + +function do_filearchive_indices_update() { + global $wgDatabase; + echo( "Checking filearchive indices...\n" ); + $info = $wgDatabase->indexInfo( 'filearchive', 'fa_user_timestamp', __METHOD__ ); + if ( !$info ) + { + dbsource( archive( 'patch-filearhive-user-index.sql' ) ); + echo( "...filearchive indices updated\n" ); + } +} + +function maybe_do_profiling_memory_update() { + global $wgDatabase; + if ( !$wgDatabase->tableExists( 'profiling' ) ) { + // Simply ignore + } elseif ( $wgDatabase->fieldExists( 'profiling', 'pf_memory' ) ) { + echo "profiling table has pf_memory field.\n"; + } else { + echo "Adding pf_memory field to table profiling..."; + dbsource( archive( 'patch-profiling-memory.sql' ), $wgDatabase ); + echo "ok\n"; } } @@ -979,11 +1034,11 @@ function purge_cache() { } function do_all_updates( $shared = false, $purge = true ) { - global $wgNewTables, $wgNewFields, $wgRenamedTables, $wgSharedDB, $wgDatabase, $wgDBtype, $IP; + global $wgNewTables, $wgNewFields, $wgRenamedTables, $wgSharedDB, $wgSharedTables, $wgDatabase, $wgDBtype, $IP; wfRunHooks('LoadExtensionSchemaUpdates'); - $doUser = !$wgSharedDB || $shared; + $doUser = $shared ? $wgSharedDB && in_array('user', $wgSharedTables) : !$wgSharedDB || !in_array('user', $wgSharedTables); if ($wgDBtype === 'postgres') { do_postgres_updates(); @@ -1114,7 +1169,54 @@ function do_restrictions_update() { } print "ok\n"; } +} + +function do_category_population() { + if( update_row_exists( 'populate category' ) ) { + echo "...category table already populated.\n"; + return; + } + require_once( 'populateCategory.inc' ); + echo "Populating category table, printing progress markers. ". +"For large databases, you\n". +"may want to hit Ctrl-C and do this manually with maintenance/\n". +"populateCategory.php.\n"; + populateCategory( '', 10, 0, true ); + echo "Done populating category table.\n"; +} + +function do_populate_parent_id() { + if( update_row_exists( 'populate rev_parent_id' ) ) { + echo "...rev_parent_id column already populated.\n"; + return; + } + require_once( 'populateParentId.inc' ); + global $wgDatabase; + populate_rev_parent_id( $wgDatabase ); +} + +function update_password_format() { + if ( update_row_exists( 'password format' ) ) { + echo "...password hash format already changed\n"; + return; + } + + echo "Updating password hash format..."; + + global $wgDatabase, $wgPasswordSalt; + $user = $wgDatabase->tableName( 'user' ); + if ( $wgPasswordSalt ) { + $sql = "UPDATE $user SET user_password=CONCAT(':B:', user_id, ':', user_password) " . + "WHERE user_password NOT LIKE ':%'"; + } else { + $sql = "UPDATE $user SET user_password=CONCAT(':A:', user_password) " . + "WHERE user_password NOT LIKE ':%'"; + } + $wgDatabase->query( $sql, __METHOD__ ); + $wgDatabase->insert( 'updatelog', array( 'ul_key' => 'password format' ), __METHOD__ ); + + echo "done\n"; } function @@ -1267,21 +1369,23 @@ function do_postgres_updates() { list( $x,$y ) = explode( '=', $c ); $conf[$x] = $y; } - $newpath = array(); - if( $wgDBmwschema === 'mediawiki' ) { - if (!array_key_exists( 'search_path', $conf ) or strpos( $conf['search_path'],$wgDBmwschema ) === false ) { - echo "Adding in schema \"$wgDBmwschema\" to search_path for user \"$wgDBuser\"\n"; - $newpath[$wgDBmwschema] = 1; - } + if( !array_key_exists( 'search_path', $conf ) ) { + $search_path = ''; + } + else { + $search_path = $conf['search_path']; } - if( !array_key_exists( 'search_path', $conf ) or strpos( $conf['search_path'],$wgDBts2schema ) === false ) { + if( strpos( $search_path, $wgDBmwschema ) === false ) { + echo "Adding in schema \"$wgDBmwschema\" to search_path for user \"$wgDBuser\"\n"; + $search_path = "$wgDBmwschema, $search_path"; + } + if( strpos( $search_path, $wgDBts2schema ) === false ) { echo "Adding in schema \"$wgDBts2schema\" to search_path for user \"$wgDBuser\"\n"; - $newpath[$wgDBts2schema] = 1; + $search_path = "$search_path, $wgDBts2schema"; } - $searchpath = implode( ',', array_keys( $newpath ) ); - if( strlen( $searchpath ) ) { - $wgDatabase->doQuery( "ALTER USER $wgDBuser SET search_path = $searchpath" ); - $wgDatabase->doQuery( "SET search_path = $searchpath" ); + if( array_key_exists( 'search_path', $conf ) === false || $search_path != $conf['search_path'] ) { + $wgDatabase->doQuery( "ALTER USER $wgDBuser SET search_path = $search_path" ); + $wgDatabase->doQuery( "SET search_path = $search_path" ); } else { $path = $conf['search_path']; @@ -1310,22 +1414,27 @@ function do_postgres_updates() { ); $newtables = array( + array("category", "patch-category.sql"), array("mediawiki_version", "patch-mediawiki_version.sql"), array("mwuser", "patch-mwuser.sql"), array("pagecontent", "patch-pagecontent.sql"), array("querycachetwo", "patch-querycachetwo.sql"), + array("page_props", "patch-page_props.sql"), array("page_restrictions", "patch-page_restrictions.sql"), array("profiling", "patch-profiling.sql"), array("protected_titles", "patch-protected_titles.sql"), array("redirect", "patch-redirect.sql"), + array("updatelog", "patch-updatelog.sql"), ); $newcols = array( array("archive", "ar_deleted", "SMALLINT NOT NULL DEFAULT 0"), array("archive", "ar_len", "INTEGER"), array("archive", "ar_page_id", "INTEGER"), + array("archive", "ar_parent_id", "INTEGER"), array("image", "img_sha1", "TEXT NOT NULL DEFAULT ''"), array("ipblocks", "ipb_anon_only", "CHAR NOT NULL DEFAULT '0'"), + array("ipblocks", "ipb_by_text", "TEXT NOT NULL DEFAULT ''"), array("ipblocks", "ipb_block_email", "CHAR NOT NULL DEFAULT '0'"), array("ipblocks", "ipb_create_account", "CHAR NOT NULL DEFAULT '1'"), array("ipblocks", "ipb_deleted", "SMALLINT NOT NULL DEFAULT 0"), @@ -1343,6 +1452,7 @@ function do_postgres_updates() { array("oldimage", "oi_minor_mime", "TEXT NOT NULL DEFAULT 'unknown'"), array("oldimage", "oi_sha1", "TEXT NOT NULL DEFAULT ''"), array("page_restrictions", "pr_id", "INTEGER NOT NULL UNIQUE DEFAULT nextval('pr_id_val')"), + array("profiling", "pf_memory", "NUMERIC(18,10) NOT NULL DEFAULT 0"), array("recentchanges", "rc_deleted", "SMALLINT NOT NULL DEFAULT 0"), array("recentchanges", "rc_log_action", "TEXT"), array("recentchanges", "rc_log_type", "TEXT"), @@ -1352,6 +1462,7 @@ function do_postgres_updates() { array("recentchanges", "rc_params", "TEXT"), array("revision", "rev_len", "INTEGER"), array("revision", "rev_deleted", "SMALLINT NOT NULL DEFAULT 0"), + array("user_newtalk", "user_last_timestamp", "TIMESTAMPTZ"), ); @@ -1373,12 +1484,12 @@ function do_postgres_updates() { array("interwiki", "iw_local", "smallint", "iw_local::smallint DEFAULT 0"), array("interwiki", "iw_trans", "smallint", "iw_trans::smallint DEFAULT 0"), array("ipblocks", "ipb_auto", "smallint", "ipb_auto::smallint DEFAULT 0"), - array("ipblocks", "ipb_anon_only", "smallint", "ipb_anon_only::smallint DEFAULT 0"), - array("ipblocks", "ipb_create_account", "smallint", "ipb_create_account::smallint DEFAULT 1"), - array("ipblocks", "ipb_enable_autoblock", "smallint", "ipb_enable_autoblock::smallint DEFAULT 1"), - array("ipblocks", "ipb_block_email", "smallint", "ipb_block_email::smallint DEFAULT 0"), + array("ipblocks", "ipb_anon_only", "smallint", "CASE WHEN ipb_anon_only=' ' THEN 0 ELSE ipb_anon_only::smallint END DEFAULT 0"), + array("ipblocks", "ipb_create_account", "smallint", "CASE WHEN ipb_create_account=' ' THEN 0 ELSE ipb_create_account::smallint END DEFAULT 1"), + array("ipblocks", "ipb_enable_autoblock", "smallint", "CASE WHEN ipb_enable_autoblock=' ' THEN 0 ELSE ipb_enable_autoblock::smallint END DEFAULT 1"), + array("ipblocks", "ipb_block_email", "smallint", "CASE WHEN ipb_block_email=' ' THEN 0 ELSE ipb_block_email::smallint END DEFAULT 0"), array("ipblocks", "ipb_address", "text", "ipb_address::text"), - array("ipblocks", "ipb_deleted", "smallint", ""), + array("ipblocks", "ipb_deleted", "smallint", "ipb_deleted::smallint"), array("math", "math_inputhash", "bytea", "decode(math_inputhash,'escape')"), array("math", "math_outputhash", "bytea", "decode(math_outputhash,'escape')"), array("mwuser", "user_token", "text", ""), @@ -1397,6 +1508,7 @@ function do_postgres_updates() { array("recentchanges","rc_new", "smallint", "rc_new::smallint DEFAULT 0"), array("recentchanges","rc_type", "smallint", "rc_type::smallint DEFAULT 0"), array("recentchanges","rc_patrolled", "smallint", "rc_patrolled::smallint DEFAULT 0"), + array("revision", "rev_deleted", "smallint", "rev_deleted::smallint DEFAULT 0"), array("revision", "rev_minor_edit", "smallint", "rev_minor_edit::smallint DEFAULT 0"), array("templatelinks","tl_namespace", "smallint", "tl_namespace::smallint"), array("user_newtalk", "user_ip", "text", "host(user_ip)"), @@ -1602,3 +1714,4 @@ function do_postgres_updates() { return; } + diff --git a/maintenance/upgrade1_5.php b/maintenance/upgrade1_5.php index 1c939a9b..dd4acaae 100644 --- a/maintenance/upgrade1_5.php +++ b/maintenance/upgrade1_5.php @@ -1,16 +1,17 @@ <?php - -// Alternate 1.4 -> 1.5 schema upgrade -// This does only the main tables + UTF-8 -// and is designed to allow upgrades to interleave -// with other updates on the replication stream so -// that large wikis can be upgraded without disrupting -// other services. -// -// Note: this script DOES NOT apply every update, nor -// will it probably handle much older versions, etc. -// Run this, FOLLOWED BY update.php, for upgrading -// from 1.4.5 release to 1.5. +/** + * Alternate 1.4 -> 1.5 schema upgrade. + * This does only the main tables + UTF-8 and is designed to allow upgrades to + * interleave with other updates on the replication stream so that large wikis + * can be upgraded without disrupting other services. + * + * Note: this script DOES NOT apply every update, nor will it probably handle + * much older versions, etc. + * Run this, FOLLOWED BY update.php, for upgrading from 1.4.5 release to 1.5. + * + * @file + * @ingroup Maintenance + */ $options = array( 'step', 'noimages' ); diff --git a/maintenance/userDupes.inc b/maintenance/userDupes.inc index 00c4e345..86b70e3b 100644 --- a/maintenance/userDupes.inc +++ b/maintenance/userDupes.inc @@ -18,7 +18,13 @@ # http://www.gnu.org/copyleft/gpl.html /** + * @file + * @ingroup Maintenance + */ + +/** * Look for duplicate user table entries and optionally prune them. + * @ingroup Maintenance */ class UserDupes { var $db; @@ -74,8 +80,8 @@ class UserDupes { * not requested. (If doing resolution, edits may be reassigned.) * Status information will be echo'd to stdout. * - * @param bool $doDelete pass true to actually remove things - * from the database; false to just check. + * @param $doDelete bool: pass true to actually remove things + * from the database; false to just check. * @return bool */ function checkDupes( $doDelete = false ) { @@ -196,8 +202,8 @@ class UserDupes { * Examine user records for the given name. Try to see which record * will be the one that actually gets used, then check remaining records * for edits. If the dupes have no edits, we can safely remove them. - * @param string $name - * @param bool $doDelete + * @param $name string + * @param $doDelete bool * @access private */ function examine( $name, $doDelete ) { @@ -247,7 +253,7 @@ class UserDupes { * Count the number of edits attributed to this user. * Does not currently check log table or other things * where it might show up... - * @param int $userid + * @param $userid int * @return int * @access private */ @@ -262,9 +268,9 @@ class UserDupes { /** * Count the number of hits on a given table for this account. - * @param string $table - * @param string $field - * @param int $userid + * @param $table string + * @param $field string + * @param $userid int * @return int * @access private */ @@ -278,8 +284,8 @@ class UserDupes { } /** - * @param int $from - * @param int $to + * @param $from int + * @param $to int * @access private */ function reassignEdits( $from, $to ) { @@ -292,10 +298,10 @@ class UserDupes { } /** - * @param string $table - * @param string $field - * @param int $from - * @param int $to + * @param $table string + * @param $field string + * @param $from int + * @param $to int * @access private */ function reassignEditsOn( $table, $field, $from, $to ) { @@ -310,7 +316,7 @@ class UserDupes { /** * Remove a user account line. - * @param int $userid + * @param $userid int * @access private */ function trimAccount( $userid ) { @@ -321,6 +327,3 @@ class UserDupes { } } - - -?> diff --git a/maintenance/userOptions.inc b/maintenance/userOptions.inc index b889e1b8..00278f51 100644 --- a/maintenance/userOptions.inc +++ b/maintenance/userOptions.inc @@ -1,10 +1,18 @@ <?php +/** + * @file + * @ingroup Maintenance + */ + // Options we will use $options = array( 'list', 'nowarn', 'quiet', 'usage', 'dry' ); $optionsWithArgs = array( 'old', 'new' ); require_once( 'commandLine.inc' ); +/** + * @ingroup Maintenance + */ class userOptions { public $mQuick; public $mQuiet; @@ -249,4 +257,3 @@ WARN; } } -?> diff --git a/maintenance/userOptions.php b/maintenance/userOptions.php index cb460b71..d4098ab2 100644 --- a/maintenance/userOptions.php +++ b/maintenance/userOptions.php @@ -6,6 +6,8 @@ * * Made on an original idea by Fooey (freenode) * + * @file + * @ingroup Maintenance * @author Ashar Voultoiz <hashar@altern.org> */ diff --git a/maintenance/waitForSlave.php b/maintenance/waitForSlave.php index 73a47364..309d0e7d 100644 --- a/maintenance/waitForSlave.php +++ b/maintenance/waitForSlave.php @@ -1,12 +1,11 @@ <?php -require_once( "commandLine.inc" ); +/** + * @see wfWaitForSlaves() + * @file + * @ingroup Maintenance + */ -# Don't wait for benet -foreach ( $wgLoadBalancer->mServers as $i => $server ) { - if ( $server['host'] == '10.0.0.29' ) { - unset($wgLoadBalancer->mServers[$i]); - } -} +require_once( "commandLine.inc" ); if ( isset( $args[0] ) ) { wfWaitForSlaves($args[0]); } else { diff --git a/maintenance/wikipedia-interwiki.sql b/maintenance/wikipedia-interwiki.sql index cfef8562..5c0857b5 100644 --- a/maintenance/wikipedia-interwiki.sql +++ b/maintenance/wikipedia-interwiki.sql @@ -5,7 +5,9 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES -- Non-Wikipedia sites: ('q','http://en.wikiquote.org/wiki/$1',1), ('b','http://en.wikibooks.org/wiki/$1',1), +('s','http://en.wikisource.org/wiki/$1',1), ('n','http://en.wikinews.org/wiki/$1',1), +('v','http://en.wikiversity.org/wiki/$1',1), ('meta','http://meta.wikimedia.org/wiki/$1',1), ('m','http://meta.wikimedia.org/wiki/$1',1), -- An alphabetical list of Wikipedia sites: @@ -15,10 +17,10 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('ak','http://ak.wikipedia.org/wiki/$1',1), ('als','http://als.wikipedia.org/wiki/$1',1), ('am','http://am.wikipedia.org/wiki/$1',1), -('ang','http://ang.wikipedia.org/wiki/$1',1), ('an','http://an.wikipedia.org/wiki/$1',1), -('arc','http://arc.wikipedia.org/wiki/$1',1), +('ang','http://ang.wikipedia.org/wiki/$1',1), ('ar','http://ar.wikipedia.org/wiki/$1',1), +('arc','http://arc.wikipedia.org/wiki/$1',1), ('as','http://as.wikipedia.org/wiki/$1',1), ('ast','http://ast.wikipedia.org/wiki/$1',1), ('av','http://av.wikipedia.org/wiki/$1',1), @@ -27,31 +29,42 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('ba','http://ba.wikipedia.org/wiki/$1',1), ('bar','http://bar.wikipedia.org/wiki/$1',1), ('bat-smg','http://bat-smg.wikipedia.org/wiki/$1',1), +('bcl','http://bcl.wikipedia.org/wiki/$1',1), ('be','http://be.wikipedia.org/wiki/$1',1), +('be-x-old','http://be-x-old.wikipedia.org/wiki/$1',1), ('bg','http://bg.wikipedia.org/wiki/$1',1), ('bh','http://bh.wikipedia.org/wiki/$1',1), ('bi','http://bi.wikipedia.org/wiki/$1',1), ('bm','http://bm.wikipedia.org/wiki/$1',1), ('bn','http://bn.wikipedia.org/wiki/$1',1), ('bo','http://bo.wikipedia.org/wiki/$1',1), +('bpy','http://bpy.wikipedia.org/wiki/$1',1), ('br','http://br.wikipedia.org/wiki/$1',1), ('bs','http://bs.wikipedia.org/wiki/$1',1), +('bug','http://bug.wikipedia.org/wiki/$1',1), +('bxr','http://bxr.wikipedia.org/wiki/$1',1), ('ca','http://ca.wikipedia.org/wiki/$1',1), +('cbk-zam','http://cbk-zam.wikipedia.org/wiki/$1',1), +('cdo','http://cdo.wikipedia.org/wiki/$1',1), ('ce','http://ce.wikipedia.org/wiki/$1',1), +('ceb','http://ceb.wikipedia.org/wiki/$1',1), ('ch','http://ch.wikipedia.org/wiki/$1',1), ('cho','http://cho.wikipedia.org/wiki/$1',1), ('chr','http://chr.wikipedia.org/wiki/$1',1), ('chy','http://chy.wikipedia.org/wiki/$1',1), ('co','http://co.wikipedia.org/wiki/$1',1), ('cr','http://cr.wikipedia.org/wiki/$1',1), -('csb','http://csb.wikipedia.org/wiki/$1',1), +('crh','http://crh.wikipedia.org/wiki/$1',1), ('cs','http://cs.wikipedia.org/wiki/$1',1), +('csb','http://csb.wikipedia.org/wiki/$1',1), ('cu','http://cu.wikipedia.org/wiki/$1',1), ('cv','http://cv.wikipedia.org/wiki/$1',1), ('cy','http://cy.wikipedia.org/wiki/$1',1), ('da','http://da.wikipedia.org/wiki/$1',1), ('de','http://de.wikipedia.org/wiki/$1',1), +('diq','http://diq.wikipedia.org/wiki/$1',1), ('dk','http://da.wikipedia.org/wiki/$1',1), +('dsb','http://dsb.wikipedia.org/wiki/$1',1), ('dv','http://dv.wikipedia.org/wiki/$1',1), ('dz','http://dz.wikipedia.org/wiki/$1',1), ('ee','http://ee.wikipedia.org/wiki/$1',1), @@ -61,9 +74,11 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('es','http://es.wikipedia.org/wiki/$1',1), ('et','http://et.wikipedia.org/wiki/$1',1), ('eu','http://eu.wikipedia.org/wiki/$1',1), +('ext','http://ext.wikipedia.org/wiki/$1',1), ('fa','http://fa.wikipedia.org/wiki/$1',1), ('ff','http://ff.wikipedia.org/wiki/$1',1), ('fi','http://fi.wikipedia.org/wiki/$1',1), +('fiu-vro','http://fiu-vro.wikipedia.org/wiki/$1',1), ('fj','http://fj.wikipedia.org/wiki/$1',1), ('fo','http://fo.wikipedia.org/wiki/$1',1), ('fr','http://fr.wikipedia.org/wiki/$1',1), @@ -71,18 +86,23 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('fur','http://fur.wikipedia.org/wiki/$1',1), ('fy','http://fy.wikipedia.org/wiki/$1',1), ('ga','http://ga.wikipedia.org/wiki/$1',1), +('gan','http://gan.wikipedia.org/wiki/$1',1), ('gd','http://gd.wikipedia.org/wiki/$1',1), ('gl','http://gl.wikipedia.org/wiki/$1',1), +('glk','http://glk.wikipedia.org/wiki/$1',1), ('gn','http://gn.wikipedia.org/wiki/$1',1), ('got','http://got.wikipedia.org/wiki/$1',1), ('gu','http://gu.wikipedia.org/wiki/$1',1), ('gv','http://gv.wikipedia.org/wiki/$1',1), ('ha','http://ha.wikipedia.org/wiki/$1',1), +('hak','http://hak.wikipedia.org/wiki/$1',1), ('haw','http://haw.wikipedia.org/wiki/$1',1), ('he','http://he.wikipedia.org/wiki/$1',1), ('hi','http://hi.wikipedia.org/wiki/$1',1), +('hif','http://hif.wikipedia.org/wiki/$1',1), ('ho','http://ho.wikipedia.org/wiki/$1',1), ('hr','http://hr.wikipedia.org/wiki/$1',1), +('hsb','http://hsb.wikipedia.org/wiki/$1',1), ('ht','http://ht.wikipedia.org/wiki/$1',1), ('hu','http://hu.wikipedia.org/wiki/$1',1), ('hy','http://hy.wikipedia.org/wiki/$1',1), @@ -102,6 +122,7 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('jbo','http://jbo.wikipedia.org/wiki/$1',1), ('jv','http://jv.wikipedia.org/wiki/$1',1), ('ka','http://ka.wikipedia.org/wiki/$1',1), +('kab','http://kab.wikipedia.org/wiki/$1',1), ('kg','http://kg.wikipedia.org/wiki/$1',1), ('ki','http://ki.wikipedia.org/wiki/$1',1), ('kj','http://kj.wikipedia.org/wiki/$1',1), @@ -112,20 +133,25 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('ko','http://ko.wikipedia.org/wiki/$1',1), ('kr','http://kr.wikipedia.org/wiki/$1',1), ('ks','http://ks.wikipedia.org/wiki/$1',1), +('ksh','http://ksh.wikipedia.org/wiki/$1',1), ('ku','http://ku.wikipedia.org/wiki/$1',1), ('kv','http://kv.wikipedia.org/wiki/$1',1), ('kw','http://kw.wikipedia.org/wiki/$1',1), ('ky','http://ky.wikipedia.org/wiki/$1',1), -('lad','http://lad.wikipedia.org/wiki/$1',1), ('la','http://la.wikipedia.org/wiki/$1',1), +('lad','http://lad.wikipedia.org/wiki/$1',1), ('lb','http://lb.wikipedia.org/wiki/$1',1), +('lbe','http://lbe.wikipedia.org/wiki/$1',1), ('lg','http://lg.wikipedia.org/wiki/$1',1), ('li','http://li.wikipedia.org/wiki/$1',1), +('lij','http://lij.wikipedia.org/wiki/$1',1), ('lmo','http://lmo.wikipedia.org/wiki/$1',1), ('ln','http://ln.wikipedia.org/wiki/$1',1), ('lo','http://lo.wikipedia.org/wiki/$1',1), ('lt','http://lt.wikipedia.org/wiki/$1',1), ('lv','http://lv.wikipedia.org/wiki/$1',1), +('map-bms','http://map-bms.wikipedia.org/wiki/$1',1), +('mdf','http://mdf.wikipedia.org/wiki/$1',1), ('mg','http://mg.wikipedia.org/wiki/$1',1), ('mh','http://mh.wikipedia.org/wiki/$1',1), ('mi','http://mi.wikipedia.org/wiki/$1',1), @@ -139,9 +165,11 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('mt','http://mt.wikipedia.org/wiki/$1',1), ('mus','http://mus.wikipedia.org/wiki/$1',1), ('my','http://my.wikipedia.org/wiki/$1',1), +('myv','http://myv.wikipedia.org/wiki/$1',1), +('mzn','http://mzn.wikipedia.org/wiki/$1',1), +('na','http://na.wikipedia.org/wiki/$1',1), ('nah','http://nah.wikipedia.org/wiki/$1',1), ('nan','http://zh-min-nan.wikipedia.org/wiki/$1',1), -('na','http://na.wikipedia.org/wiki/$1',1), ('nap','http://nap.wikipedia.org/wiki/$1',1), ('nb','http://nb.wikipedia.org/wiki/$1',1), ('nds','http://nds.wikipedia.org/wiki/$1',1), @@ -151,6 +179,7 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('nl','http://nl.wikipedia.org/wiki/$1',1), ('nn','http://nn.wikipedia.org/wiki/$1',1), ('no','http://no.wikipedia.org/wiki/$1',1), +('nov','http://nov.wikipedia.org/wiki/$1',1), ('nrm','http://nrm.wikipedia.org/wiki/$1',1), ('nv','http://nv.wikipedia.org/wiki/$1',1), ('ny','http://ny.wikipedia.org/wiki/$1',1), @@ -159,21 +188,27 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('or','http://or.wikipedia.org/wiki/$1',1), ('os','http://os.wikipedia.org/wiki/$1',1), ('pa','http://pa.wikipedia.org/wiki/$1',1), +('pag','http://pag.wikipedia.org/wiki/$1',1), ('pam','http://pam.wikipedia.org/wiki/$1',1), +('pap','http://pap.wikipedia.org/wiki/$1',1), ('pdc','http://pdc.wikipedia.org/wiki/$1',1), ('pi','http://pi.wikipedia.org/wiki/$1',1), +('pih','http://pih.wikipedia.org/wiki/$1',1), ('pl','http://pl.wikipedia.org/wiki/$1',1), +('pms','http://pms.wikipedia.org/wiki/$1',1), ('ps','http://ps.wikipedia.org/wiki/$1',1), ('pt','http://pt.wikipedia.org/wiki/$1',1), ('qu','http://qu.wikipedia.org/wiki/$1',1), ('rm','http://rm.wikipedia.org/wiki/$1',1), ('rmy','http://rmy.wikipedia.org/wiki/$1',1), ('rn','http://rn.wikipedia.org/wiki/$1',1), -('roa-rup','http://roa-rup.wikipedia.org/wiki/$1',1), ('ro','http://ro.wikipedia.org/wiki/$1',1), +('roa-rup','http://roa-rup.wikipedia.org/wiki/$1',1), +('roa-tara','http://roa-tara.wikipedia.org/wiki/$1',1), ('ru','http://ru.wikipedia.org/wiki/$1',1), ('rw','http://rw.wikipedia.org/wiki/$1',1), ('sa','http://sa.wikipedia.org/wiki/$1',1), +('sah','http://sah.wikipedia.org/wiki/$1',1), ('sc','http://sc.wikipedia.org/wiki/$1',1), ('scn','http://scn.wikipedia.org/wiki/$1',1), ('sco','http://sco.wikipedia.org/wiki/$1',1), @@ -191,19 +226,23 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('so','http://so.wikipedia.org/wiki/$1',1), ('sq','http://sq.wikipedia.org/wiki/$1',1), ('sr','http://sr.wikipedia.org/wiki/$1',1), +('srn','http://srn.wikipedia.org/wiki/$1',1), ('ss','http://ss.wikipedia.org/wiki/$1',1), ('st','http://st.wikipedia.org/wiki/$1',1), +('stq','http://stq.wikipedia.org/wiki/$1',1), ('su','http://su.wikipedia.org/wiki/$1',1), ('sv','http://sv.wikipedia.org/wiki/$1',1), ('sw','http://sw.wikipedia.org/wiki/$1',1), +('szl','http://szl.wikipedia.org/wiki/$1',1), ('ta','http://ta.wikipedia.org/wiki/$1',1), ('te','http://te.wikipedia.org/wiki/$1',1), +('tet','http://tet.wikipedia.org/wiki/$1',1), ('tg','http://tg.wikipedia.org/wiki/$1',1), ('th','http://th.wikipedia.org/wiki/$1',1), ('ti','http://ti.wikipedia.org/wiki/$1',1), ('tk','http://tk.wikipedia.org/wiki/$1',1), -('tlh','http://tlh.wikipedia.org/wiki/$1',1), ('tl','http://tl.wikipedia.org/wiki/$1',1), +('tlh','http://tlh.wikipedia.org/wiki/$1',1), ('tn','http://tn.wikipedia.org/wiki/$1',1), ('to','http://to.wikipedia.org/wiki/$1',1), ('tokipona','http://tokipona.wikipedia.org/wiki/$1',1), @@ -214,25 +253,32 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('tum','http://tum.wikipedia.org/wiki/$1',1), ('tw','http://tw.wikipedia.org/wiki/$1',1), ('ty','http://ty.wikipedia.org/wiki/$1',1), +('udm','http://udm.wikipedia.org/wiki/$1',1), ('ug','http://ug.wikipedia.org/wiki/$1',1), ('uk','http://uk.wikipedia.org/wiki/$1',1), ('ur','http://ur.wikipedia.org/wiki/$1',1), ('uz','http://uz.wikipedia.org/wiki/$1',1), ('ve','http://ve.wikipedia.org/wiki/$1',1), +('vec','http://vec.wikipedia.org/wiki/$1',1), ('vi','http://vi.wikipedia.org/wiki/$1',1), +('vls','http://vls.wikipedia.org/wiki/$1',1), ('vo','http://vo.wikipedia.org/wiki/$1',1), -('wa','http://wa.wikipedia.org/wiki/$1',1), ('w','http://en.wikipedia.org/wiki/$1',1), +('wa','http://wa.wikipedia.org/wiki/$1',1), +('war','http://war.wikipedia.org/wiki/$1',1), ('wo','http://wo.wikipedia.org/wiki/$1',1), +('wuu','http://wuu.wikipedia.org/wiki/$1',1), +('xal','http://xal.wikipedia.org/wiki/$1',1), ('xh','http://xh.wikipedia.org/wiki/$1',1), ('yi','http://yi.wikipedia.org/wiki/$1',1), ('yo','http://yo.wikipedia.org/wiki/$1',1), ('yue','http://zh-yue.wikipedia.org/wiki/$1',1), ('za','http://za.wikipedia.org/wiki/$1',1), +('zea','http://zea.wikipedia.org/wiki/$1',1), +('zh','http://zh.wikipedia.org/wiki/$1',1), ('zh-cfr','http://zh-min-nan.wikipedia.org/wiki/$1',1), ('zh-classical','http://zh-classical.wikipedia.org/wiki/$1',1), ('zh-cn','http://zh.wikipedia.org/wiki/$1',1), -('zh','http://zh.wikipedia.org/wiki/$1',1), ('zh-min-nan','http://zh-min-nan.wikipedia.org/wiki/$1',1), ('zh-tw','http://zh.wikipedia.org/wiki/$1',1), ('zh-yue','http://zh-yue.wikipedia.org/wiki/$1',1), diff --git a/maintenance/wiktionary-interwiki.sql b/maintenance/wiktionary-interwiki.sql index 787962d5..3dc62e5e 100644 --- a/maintenance/wiktionary-interwiki.sql +++ b/maintenance/wiktionary-interwiki.sql @@ -1,5 +1,5 @@ -- For convenience, here are the *in-project* interwiki prefixes --- for Wikipedia. +-- for Wiktionary. REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('w','http://www.wikipedia.org/wiki/$1',1), @@ -10,10 +10,15 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('aa','http://aa.wiktionary.org/wiki/$1',1), ('ab','http://ab.wiktionary.org/wiki/$1',1), ('af','http://af.wiktionary.org/wiki/$1',1), +('ak','http://ak.wiktionary.org/wiki/$1',1), ('als','http://als.wiktionary.org/wiki/$1',1), ('am','http://am.wiktionary.org/wiki/$1',1), +('an','http://an.wiktionary.org/wiki/$1',1), +('ang','http://ang.wiktionary.org/wiki/$1',1), ('ar','http://ar.wiktionary.org/wiki/$1',1), ('as','http://as.wiktionary.org/wiki/$1',1), +('ast','http://ast.wiktionary.org/wiki/$1',1), +('av','http://av.wiktionary.org/wiki/$1',1), ('ay','http://ay.wiktionary.org/wiki/$1',1), ('az','http://az.wiktionary.org/wiki/$1',1), ('ba','http://ba.wiktionary.org/wiki/$1',1), @@ -21,18 +26,23 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('bg','http://bg.wiktionary.org/wiki/$1',1), ('bh','http://bh.wiktionary.org/wiki/$1',1), ('bi','http://bi.wiktionary.org/wiki/$1',1), +('bm','http://bm.wiktionary.org/wiki/$1',1), ('bn','http://bn.wiktionary.org/wiki/$1',1), ('bo','http://bo.wiktionary.org/wiki/$1',1), +('br','http://br.wiktionary.org/wiki/$1',1), ('bs','http://bs.wiktionary.org/wiki/$1',1), ('ca','http://ca.wiktionary.org/wiki/$1',1), +('ch','http://ch.wiktionary.org/wiki/$1',1), ('chr','http://chr.wiktionary.org/wiki/$1',1), ('co','http://co.wiktionary.org/wiki/$1',1), +('cr','http://cr.wiktionary.org/wiki/$1',1), ('cs','http://cs.wiktionary.org/wiki/$1',1), ('csb','http://csb.wiktionary.org/wiki/$1',1), ('cy','http://cy.wiktionary.org/wiki/$1',1), ('da','http://da.wiktionary.org/wiki/$1',1), ('de','http://de.wiktionary.org/wiki/$1',1), ('dk','http://da.wiktionary.org/wiki/$1',1), +('dv','http://dv.wiktionary.org/wiki/$1',1), ('dz','http://dz.wiktionary.org/wiki/$1',1), ('el','http://el.wiktionary.org/wiki/$1',1), ('en','http://en.wiktionary.org/wiki/$1',1), @@ -56,16 +66,19 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('he','http://he.wiktionary.org/wiki/$1',1), ('hi','http://hi.wiktionary.org/wiki/$1',1), ('hr','http://hr.wiktionary.org/wiki/$1',1), +('hsb','http://hsb.wiktionary.org/wiki/$1',1), ('hu','http://hu.wiktionary.org/wiki/$1',1), ('hy','http://hy.wiktionary.org/wiki/$1',1), ('ia','http://ia.wiktionary.org/wiki/$1',1), ('id','http://id.wiktionary.org/wiki/$1',1), +('ie','http://ie.wiktionary.org/wiki/$1',1), ('ik','http://ik.wiktionary.org/wiki/$1',1), ('io','http://io.wiktionary.org/wiki/$1',1), ('is','http://is.wiktionary.org/wiki/$1',1), ('it','http://it.wiktionary.org/wiki/$1',1), ('iu','http://iu.wiktionary.org/wiki/$1',1), ('ja','http://ja.wiktionary.org/wiki/$1',1), +('jbo','http://jbo.wiktionary.org/wiki/$1',1), ('jv','http://jv.wiktionary.org/wiki/$1',1), ('ka','http://ka.wiktionary.org/wiki/$1',1), ('kk','http://kk.wiktionary.org/wiki/$1',1), @@ -75,12 +88,17 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('ko','http://ko.wiktionary.org/wiki/$1',1), ('ks','http://ks.wiktionary.org/wiki/$1',1), ('ku','http://ku.wiktionary.org/wiki/$1',1), +('kw','http://kw.wiktionary.org/wiki/$1',1), ('ky','http://ky.wiktionary.org/wiki/$1',1), ('la','http://la.wiktionary.org/wiki/$1',1), +('lb','http://lb.wiktionary.org/wiki/$1',1), +('li','http://li.wiktionary.org/wiki/$1',1), +('ln','http://ln.wiktionary.org/wiki/$1',1), ('lo','http://lo.wiktionary.org/wiki/$1',1), ('lt','http://lt.wiktionary.org/wiki/$1',1), ('lv','http://lv.wiktionary.org/wiki/$1',1), ('mg','http://mg.wiktionary.org/wiki/$1',1), +('mh','http://mh.wiktionary.org/wiki/$1',1), ('mi','http://mi.wiktionary.org/wiki/$1',1), ('mk','http://mk.wiktionary.org/wiki/$1',1), ('ml','http://ml.wiktionary.org/wiki/$1',1), @@ -88,6 +106,7 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('mo','http://mo.wiktionary.org/wiki/$1',1), ('mr','http://mr.wiktionary.org/wiki/$1',1), ('ms','http://ms.wiktionary.org/wiki/$1',1), +('mt','http://mt.wiktionary.org/wiki/$1',1), ('my','http://my.wiktionary.org/wiki/$1',1), ('na','http://na.wiktionary.org/wiki/$1',1), ('nah','http://nah.wiktionary.org/wiki/$1',1), @@ -95,11 +114,13 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('nds','http://nds.wiktionary.org/wiki/$1',1), ('ne','http://ne.wiktionary.org/wiki/$1',1), ('nl','http://nl.wiktionary.org/wiki/$1',1), +('nn','http://nn.wiktionary.org/wiki/$1',1), ('no','http://no.wiktionary.org/wiki/$1',1), ('oc','http://oc.wiktionary.org/wiki/$1',1), ('om','http://om.wiktionary.org/wiki/$1',1), ('or','http://or.wiktionary.org/wiki/$1',1), ('pa','http://pa.wiktionary.org/wiki/$1',1), +('pi','http://pi.wiktionary.org/wiki/$1',1), ('pl','http://pl.wiktionary.org/wiki/$1',1), ('ps','http://ps.wiktionary.org/wiki/$1',1), ('pt','http://pt.wiktionary.org/wiki/$1',1), @@ -107,9 +128,12 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('rm','http://rm.wiktionary.org/wiki/$1',1), ('rn','http://rn.wiktionary.org/wiki/$1',1), ('ro','http://ro.wiktionary.org/wiki/$1',1), +('roa-rup','http://roa-rup.wiktionary.org/wiki/$1',1), ('ru','http://ru.wiktionary.org/wiki/$1',1), ('rw','http://rw.wiktionary.org/wiki/$1',1), ('sa','http://sa.wiktionary.org/wiki/$1',1), +('sc','http://sc.wiktionary.org/wiki/$1',1), +('scn','http://scn.wiktionary.org/wiki/$1',1), ('sd','http://sd.wiktionary.org/wiki/$1',1), ('sg','http://sg.wiktionary.org/wiki/$1',1), ('sh','http://sh.wiktionary.org/wiki/$1',1), @@ -155,6 +179,7 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('za','http://za.wiktionary.org/wiki/$1',1), ('zh','http://zh.wiktionary.org/wiki/$1',1), ('zh-cn','http://zh.wiktionary.org/wiki/$1',1), +('zh-min-nan','http://zh-min-nan.wiktionary.org/wiki/$1',1), ('zh-tw','http://zh.wiktionary.org/wiki/$1',1), ('zu','http://zu.wiktionary.org/wiki/$1',1); |