diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2007-05-16 20:58:53 +0000 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2007-05-16 20:58:53 +0000 |
commit | cecb985bee3bdd252e1b8dc0bd500b37cd52be01 (patch) | |
tree | 17266aa237742640aabee7856f0202317a45d540 /maintenance | |
parent | 0bac06c301f2a83edb0236e4c2434da16848d549 (diff) |
Aktualisierung auf MediaWiki 1.10.0
Plugins angepasst und verbessert
kleine Korrekturen am Design
Diffstat (limited to 'maintenance')
197 files changed, 4514 insertions, 2330 deletions
diff --git a/maintenance/Doxyfile b/maintenance/Doxyfile index 44e8e495..6c9811d0 100644 --- a/maintenance/Doxyfile +++ b/maintenance/Doxyfile @@ -34,7 +34,7 @@ FULL_PATH_NAMES = YES STRIP_FROM_PATH = {{STRIP_FROM_PATH}} STRIP_FROM_INC_PATH = SHORT_NAMES = NO -JAVADOC_AUTOBRIEF = NO +JAVADOC_AUTOBRIEF = YES MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES @@ -204,7 +204,7 @@ RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- -GENERATE_MAN = NO +GENERATE_MAN = YES MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO diff --git a/maintenance/FiveUpgrade.inc b/maintenance/FiveUpgrade.inc index d21d8b43..c32f1b2e 100644 --- a/maintenance/FiveUpgrade.inc +++ b/maintenance/FiveUpgrade.inc @@ -11,7 +11,6 @@ define( 'MW_UPGRADE_CALLBACK', null ); // for self-documentation only class FiveUpgrade { function FiveUpgrade() { - global $wgDatabase; $this->conversionTables = $this->prepareWindows1252(); $this->dbw =& $this->newConnection(); @@ -275,7 +274,6 @@ class FiveUpgrade { $name_temp = $name . '_temp'; $this->log( "Migrating $name table to $name_temp..." ); - $table = $this->dbw->tableName( $name ); $table_temp = $this->dbw->tableName( $name_temp ); // Create temporary table; we're going to copy everything in there, @@ -335,7 +333,7 @@ class FiveUpgrade { $this->log( "...converting from cur/old to page/revision/text DB structure." ); - extract( $this->dbw->tableNames( 'cur', 'old', 'page', 'revision', 'text' ) ); + list ($cur, $old, $page, $revision, $text) = $this->dbw->tableNamesN( 'cur', 'old', 'page', 'revision', 'text' ); $this->log( "Creating page and revision tables..." ); $this->dbw->query("CREATE TABLE $page ( @@ -497,14 +495,15 @@ class FiveUpgrade { function upgradeLinks() { $fname = 'FiveUpgrade::upgradeLinks'; $chunksize = 200; - extract( $this->dbw->tableNames( 'links', 'brokenlinks', 'pagelinks', 'cur' ) ); + list ($links, $brokenlinks, $pagelinks, $cur) = $this->dbw->tableNamesN( 'links', 'brokenlinks', 'pagelinks', 'cur' ); $this->log( 'Checking for interwiki table change in case of bogus items...' ); if( $this->dbw->fieldExists( 'interwiki', 'iw_trans' ) ) { $this->log( 'interwiki has iw_trans.' ); } else { + global $IP; $this->log( 'adding iw_trans...' ); - dbsource( 'maintenance/archives/patch-interwiki-trans.sql', $this->dbw ); + dbsource( $IP . '/maintenance/archives/patch-interwiki-trans.sql', $this->dbw ); $this->log( 'added iw_trans.' ); } @@ -740,7 +739,7 @@ END; function clearTable( $table ) { print "Clearing $table...\n"; $tableName = $this->db->tableName( $table ); - $this->db->query( 'TRUNCATE $tableName' ); + $this->db->query( "TRUNCATE $tableName" ); } /** @@ -765,7 +764,7 @@ END; $this->log( "$oldpath -> $newpath" ); if( rename( $oldpath, $newpath ) ) { - $relpath = $this->relativize( $newpath, dirname( $oldpath ) ); + $relpath = wfRelativePath( $newpath, dirname( $oldpath ) ); if( !symlink( $relpath, $oldpath ) ) { $this->log( "... symlink failed!" ); } @@ -776,38 +775,6 @@ END; } } - /** - * Generate a relative path name to the given file. - * Assumes Unix-style paths, separators, and semantics. - * - * @param string $path Absolute destination path including target filename - * @param string $from Absolute source path, directory only - * @return string - * @access private - * @static - */ - function relativize( $path, $from ) { - $pieces = explode( '/', dirname( $path ) ); - $against = explode( '/', $from ); - - // Trim off common prefix - while( count( $pieces ) && count( $against ) - && $pieces[0] == $against[0] ) { - array_shift( $pieces ); - array_shift( $against ); - } - - // relative dots to bump us to the parent - while( count( $against ) ) { - array_unshift( $pieces, '..' ); - array_shift( $against ); - } - - array_push( $pieces, wfBaseName( $path ) ); - - return implode( '/', $pieces ); - } - function upgradeOldImage() { $tabledef = <<<END CREATE TABLE $1 ( @@ -868,7 +835,7 @@ END; $fname = 'FiveUpgrade::upgradeWatchlist'; $chunksize = 100; - extract( $this->dbw->tableNames( 'watchlist', 'watchlist_temp' ) ); + list ($watchlist, $watchlist_temp) = $this->dbw->tableNamesN( 'watchlist', 'watchlist_temp' ); $this->log( 'Migrating watchlist table to watchlist_temp...' ); $this->dbw->query( @@ -907,7 +874,6 @@ END; $add = array(); while( $row = $this->dbr->fetchObject( $result ) ) { - $now = $this->dbw->timestamp(); $add[] = array( 'wl_user' => $row->wl_user, 'wl_namespace' => Namespace::getSubject( $row->wl_namespace ), diff --git a/maintenance/Makefile b/maintenance/Makefile index 97f8b60b..e84cfdf3 100644 --- a/maintenance/Makefile +++ b/maintenance/Makefile @@ -1,20 +1,17 @@ -.PHONY: help test test-light +mediawiki_version := $(shell php -r "include('commandLine.inc'); print SpecialVersion::getVersion();") + help: - # Run 'make test' to run the parser tests. - # Run 'make doc' to run the phpdoc generation. - # Run 'make doxydoc' (unsupported doxygen generation). + @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)." test: - php parserTests.php - -test-light: - php parserTests.php --color=light + php parserTests.php --quiet doc: php mwdocgen.php -all echo 'Doc generation done. Look at ./docs/html/' doxydoc: - cd .. && doxygen maintenance/mwdoxygen.cfg + cd .. && /bin/sed -e "s/MW_VERSION_PLACEHOLDER/$(mediawiki_version)/" maintenance/mwdoxygen.cfg | doxygen - echo 'Doc generation done. Look at ./docs/html/' - diff --git a/maintenance/addwiki.php b/maintenance/addwiki.php index b7843632..642b1324 100644 --- a/maintenance/addwiki.php +++ b/maintenance/addwiki.php @@ -19,7 +19,7 @@ function addWiki( $lang, $site, $dbName ) $name = $wgLanguageNames[$lang]; - $dbw =& wfGetDB( DB_WRITE ); + $dbw = wfGetDB( DB_WRITE ); $common = "/home/wikipedia/common"; $maintenance = "$IP/maintenance"; @@ -34,6 +34,7 @@ function addWiki( $lang, $site, $dbName ) 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/CheckUser/cu_changes.sql", $dbw ); $dbw->query( "INSERT INTO site_stats(ss_row_id) VALUES (1)" ); # Initialise external storage @@ -49,6 +50,7 @@ function addWiki( $lang, $site, $dbName ) print "Initialising external storage $store...\n"; global $wgDBuser, $wgDBpassword, $wgExternalServers; foreach ( $stores as $storeURL ) { + $m = array(); if ( !preg_match( '!^DB://(.*)$!', $storeURL, $m ) ) { continue; } diff --git a/maintenance/archives/patch-ar_deleted.sql b/maintenance/archives/patch-ar_deleted.sql new file mode 100644 index 00000000..b1d37a5c --- /dev/null +++ b/maintenance/archives/patch-ar_deleted.sql @@ -0,0 +1,3 @@ +-- Adding ar_deleted field for revisiondelete +ALTER TABLE /*$wgDBprefix*/archive + ADD ar_deleted tinyint(1) unsigned NOT NULL default '0'; diff --git a/maintenance/archives/patch-ar_len.sql b/maintenance/archives/patch-ar_len.sql new file mode 100644 index 00000000..69e634b0 --- /dev/null +++ b/maintenance/archives/patch-ar_len.sql @@ -0,0 +1,3 @@ +ALTER TABLE /*$wgDBprefix*/archive + ADD ar_len INT(8) UNSIGNED; + diff --git a/maintenance/archives/patch-categorylinks.sql b/maintenance/archives/patch-categorylinks.sql index 53c82fc0..c5eb396e 100644 --- a/maintenance/archives/patch-categorylinks.sql +++ b/maintenance/archives/patch-categorylinks.sql @@ -36,4 +36,4 @@ CREATE TABLE /*$wgDBprefix*/categorylinks ( -- Not really used? KEY cl_timestamp(cl_to,cl_timestamp) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-externallinks.sql b/maintenance/archives/patch-externallinks.sql index 52fb5bae..0a4768ca 100644 --- a/maintenance/archives/patch-externallinks.sql +++ b/maintenance/archives/patch-externallinks.sql @@ -9,5 +9,5 @@ CREATE TABLE /*$wgDBprefix*/externallinks ( KEY (el_from, el_to(40)), KEY (el_to(60), el_from), KEY (el_index(60)) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-fa_deleted.sql b/maintenance/archives/patch-fa_deleted.sql new file mode 100644 index 00000000..78163149 --- /dev/null +++ b/maintenance/archives/patch-fa_deleted.sql @@ -0,0 +1,3 @@ +-- Adding fa_deleted field for additional content suppression +ALTER TABLE /*$wgDBprefix*/filearchive + ADD fa_deleted tinyint(1) unsigned NOT NULL default '0'; diff --git a/maintenance/archives/patch-filearchive.sql b/maintenance/archives/patch-filearchive.sql index cc50f2ae..71f8a5eb 100644 --- a/maintenance/archives/patch-filearchive.sql +++ b/maintenance/archives/patch-filearchive.sql @@ -48,4 +48,4 @@ CREATE TABLE /*$wgDBprefix*/filearchive ( INDEX (fa_deleted_timestamp), -- sort by deletion time INDEX (fa_deleted_user) -- sort by deleter -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-indexes.sql b/maintenance/archives/patch-indexes.sql index 23eec07d..6a86c0fd 100644 --- a/maintenance/archives/patch-indexes.sql +++ b/maintenance/archives/patch-indexes.sql @@ -4,7 +4,7 @@ -- Fix up table indexes; new to stable release in November 2003 -- -ALTER TABLE /*$wgDBprefix*/links +ALTER TABLE IF EXISTS/*$wgDBprefix*/links DROP INDEX l_from, ADD INDEX l_from (l_from); diff --git a/maintenance/archives/patch-interwiki.sql b/maintenance/archives/patch-interwiki.sql index 90b162ef..3efdac8b 100644 --- a/maintenance/archives/patch-interwiki.sql +++ b/maintenance/archives/patch-interwiki.sql @@ -17,4 +17,4 @@ CREATE TABLE /*$wgDBprefix*/interwiki ( UNIQUE KEY iw_prefix (iw_prefix) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-ipb_anon_only.sql b/maintenance/archives/patch-ipb_anon_only.sql index b3738168..d46c04e8 100644 --- a/maintenance/archives/patch-ipb_anon_only.sql +++ b/maintenance/archives/patch-ipb_anon_only.sql @@ -30,7 +30,7 @@ CREATE TABLE /*$wgDBprefix*/ipblocks_newunique ( INDEX ipb_timestamp (ipb_timestamp), INDEX ipb_expiry (ipb_expiry) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; INSERT IGNORE INTO /*$wgDBprefix*/ipblocks_newunique (ipb_id, ipb_address, ipb_user, ipb_by, ipb_reason, ipb_timestamp, ipb_auto, ipb_expiry, ipb_range_start, ipb_range_end, ipb_anon_only, ipb_create_account) diff --git a/maintenance/archives/patch-ipb_deleted.sql b/maintenance/archives/patch-ipb_deleted.sql new file mode 100644 index 00000000..fad94778 --- /dev/null +++ b/maintenance/archives/patch-ipb_deleted.sql @@ -0,0 +1,3 @@ +-- Adding ipb_deleted field for hiding usernames +ALTER TABLE /*$wgDBprefix*/ipblocks + ADD ipb_deleted bool NOT NULL default 0; diff --git a/maintenance/archives/patch-job.sql b/maintenance/archives/patch-job.sql index d904fbeb..d931124d 100644 --- a/maintenance/archives/patch-job.sql +++ b/maintenance/archives/patch-job.sql @@ -17,4 +17,4 @@ CREATE TABLE /*$wgDBprefix*/job ( PRIMARY KEY job_id (job_id), KEY (job_cmd, job_namespace, job_title) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-langlinks.sql b/maintenance/archives/patch-langlinks.sql index 9c3b7e54..33eb419d 100644 --- a/maintenance/archives/patch-langlinks.sql +++ b/maintenance/archives/patch-langlinks.sql @@ -10,5 +10,5 @@ CREATE TABLE /*$wgDBprefix*/langlinks ( UNIQUE KEY (ll_from, ll_lang), KEY (ll_lang, ll_title) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-linkscc.sql b/maintenance/archives/patch-linkscc.sql index 91d4da56..684384f5 100644 --- a/maintenance/archives/patch-linkscc.sql +++ b/maintenance/archives/patch-linkscc.sql @@ -9,4 +9,4 @@ CREATE TABLE /*$wgDBprefix*/linkscc ( lcc_pageid INT UNSIGNED NOT NULL UNIQUE KEY, lcc_cacheobj MEDIUMBLOB NOT NULL -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-linktables.sql b/maintenance/archives/patch-linktables.sql index bb9bd033..8c521ad9 100644 --- a/maintenance/archives/patch-linktables.sql +++ b/maintenance/archives/patch-linktables.sql @@ -16,7 +16,7 @@ CREATE TABLE /*$wgDBprefix*/links ( UNIQUE KEY l_from(l_from,l_to), KEY (l_to) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Track links to pages that don't yet exist. @@ -35,7 +35,7 @@ CREATE TABLE /*$wgDBprefix*/brokenlinks ( UNIQUE KEY bl_from(bl_from,bl_to), KEY (bl_to) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Track links to images *used inline* @@ -55,7 +55,7 @@ CREATE TABLE /*$wgDBprefix*/imagelinks ( UNIQUE KEY il_from(il_from,il_to), KEY (il_to) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Stores (possibly gzipped) serialized objects with @@ -67,4 +67,4 @@ CREATE TABLE /*$wgDBprefix*/linkscc ( lcc_pageid INT UNSIGNED NOT NULL UNIQUE KEY, lcc_cacheobj MEDIUMBLOB NOT NULL -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-log_deleted.sql b/maintenance/archives/patch-log_deleted.sql new file mode 100644 index 00000000..6c777134 --- /dev/null +++ b/maintenance/archives/patch-log_deleted.sql @@ -0,0 +1,3 @@ +-- Adding ar_deleted field for revisiondelete +ALTER TABLE /*$wgDBprefix*/logging + ADD log_deleted tinyint(1) unsigned NOT NULL default '0';
\ No newline at end of file diff --git a/maintenance/archives/patch-log_id.sql b/maintenance/archives/patch-log_id.sql new file mode 100644 index 00000000..bd69ddb6 --- /dev/null +++ b/maintenance/archives/patch-log_id.sql @@ -0,0 +1,8 @@ +-- Log_id field that means one log entry can be referred to with a single number, +-- rather than a dirty great big mess of features. +-- This might be useful for single-log-entry deletion, et cetera. +-- Andrew Garrett, February 2007. + +ALTER TABLE /*$wgDBprefix*/logging + ADD COLUMN log_id int unsigned not null auto_increment, + ADD PRIMARY KEY log_id (log_id); diff --git a/maintenance/archives/patch-logging.sql b/maintenance/archives/patch-logging.sql index 54146fb7..96847526 100644 --- a/maintenance/archives/patch-logging.sql +++ b/maintenance/archives/patch-logging.sql @@ -29,7 +29,7 @@ CREATE TABLE /*$wgDBprefix*/logging ( KEY user_time (log_user, log_timestamp), KEY page_time (log_namespace, log_title, log_timestamp) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- Change from unsigned to signed so we can store special pages diff --git a/maintenance/archives/patch-math.sql b/maintenance/archives/patch-math.sql index aee24a8a..d217ecea 100644 --- a/maintenance/archives/patch-math.sql +++ b/maintenance/archives/patch-math.sql @@ -25,4 +25,4 @@ CREATE TABLE /*$wgDBprefix*/math ( UNIQUE KEY math_inputhash (math_inputhash) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-objectcache.sql b/maintenance/archives/patch-objectcache.sql index 18572aa0..a439dd03 100644 --- a/maintenance/archives/patch-objectcache.sql +++ b/maintenance/archives/patch-objectcache.sql @@ -6,4 +6,4 @@ CREATE TABLE /*$wgDBprefix*/objectcache ( unique key (keyname), key (exptime) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-page_restrictions.sql b/maintenance/archives/patch-page_restrictions.sql new file mode 100644 index 00000000..c0eafab9 --- /dev/null +++ b/maintenance/archives/patch-page_restrictions.sql @@ -0,0 +1,22 @@ +--- Used for storing page restrictions (i.e. protection levels) +CREATE TABLE /*$wgDBprefix*/page_restrictions ( + -- Page to apply restrictions to (Foreign Key to page). + pr_page int(8) NOT NULL, + -- The protection type (edit, move, etc) + pr_type varchar(255) NOT NULL, + -- The protection level (Sysop, autoconfirmed, etc) + pr_level varchar(255) NOT NULL, + -- Whether or not to cascade the protection down to pages transcluded. + pr_cascade tinyint(4) NOT NULL, + -- Field for future support of per-user restriction. + pr_user int(8) NULL, + -- Field for time-limited protection. + pr_expiry char(14) binary NULL, + + PRIMARY KEY pr_pagetype (pr_page,pr_type), + + KEY pr_page (pr_page), + KEY pr_typelevel (pr_type,pr_level), + KEY pr_level (pr_level), + KEY pr_cascade (pr_cascade) +) /*$wgDBTableOptions*/;
\ No newline at end of file diff --git a/maintenance/archives/patch-page_restrictions_sortkey.sql b/maintenance/archives/patch-page_restrictions_sortkey.sql new file mode 100644 index 00000000..6b24e3a5 --- /dev/null +++ b/maintenance/archives/patch-page_restrictions_sortkey.sql @@ -0,0 +1,8 @@ +-- Add a sort-key to page_restrictions table. +-- First immediate use of this is as a sort-key for coming modifications +-- of Special:Protectedpages. +-- Andrew Garrett, February 2007 + +ALTER TABLE /*$wgDBprefix*/page_restrictions + ADD COLUMN pr_id int unsigned not null auto_increment, + ADD UNIQUE KEY pr_id (pr_id); diff --git a/maintenance/archives/patch-pagelinks.sql b/maintenance/archives/patch-pagelinks.sql index 7240cff9..91e279da 100644 --- a/maintenance/archives/patch-pagelinks.sql +++ b/maintenance/archives/patch-pagelinks.sql @@ -30,7 +30,7 @@ CREATE TABLE /*$wgDBprefix*/pagelinks ( UNIQUE KEY pl_from(pl_from,pl_namespace,pl_title), KEY (pl_namespace,pl_title) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- Import existing-page links diff --git a/maintenance/archives/patch-parsercache.sql b/maintenance/archives/patch-parsercache.sql index 854e6c57..395a81bd 100644 --- a/maintenance/archives/patch-parsercache.sql +++ b/maintenance/archives/patch-parsercache.sql @@ -12,4 +12,4 @@ CREATE TABLE /*$wgDBprefix*/parsercache ( PRIMARY KEY (pc_pageid, pc_prefhash), KEY(pc_title), KEY(pc_expire) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-querycache.sql b/maintenance/archives/patch-querycache.sql index 7df9129e..d0a592ac 100644 --- a/maintenance/archives/patch-querycache.sql +++ b/maintenance/archives/patch-querycache.sql @@ -13,4 +13,4 @@ CREATE TABLE /*$wgDBprefix*/querycache ( KEY (qc_type,qc_value) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-querycacheinfo.sql b/maintenance/archives/patch-querycacheinfo.sql index 0e34b3a5..d90189e2 100644 --- a/maintenance/archives/patch-querycacheinfo.sql +++ b/maintenance/archives/patch-querycacheinfo.sql @@ -9,4 +9,4 @@ CREATE TABLE /*$wgDBprefix*/querycache_info ( UNIQUE KEY ( qci_type ) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-querycachetwo.sql b/maintenance/archives/patch-querycachetwo.sql index cda5b90d..4f7a60ac 100644 --- a/maintenance/archives/patch-querycachetwo.sql +++ b/maintenance/archives/patch-querycachetwo.sql @@ -19,4 +19,4 @@ CREATE TABLE /*$wgDBprefix*/querycachetwo ( KEY qcc_title (qcc_type,qcc_namespace,qcc_title), KEY qcc_titletwo (qcc_type,qcc_namespacetwo,qcc_titletwo) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-rc_deleted.sql b/maintenance/archives/patch-rc_deleted.sql new file mode 100644 index 00000000..a2bdca9b --- /dev/null +++ b/maintenance/archives/patch-rc_deleted.sql @@ -0,0 +1,8 @@ +-- Adding rc_deleted field for revisiondelete +-- Add rc_logid to match log_id +ALTER TABLE /*$wgDBprefix*/recentchanges + ADD rc_deleted tinyint(1) unsigned NOT NULL default '0', + ADD rc_logid int(10) unsigned NOT NULL default '0', + ADD rc_log_type varchar(255) binary NULL default NULL, + ADD rc_log_action varchar(255) binary NULL default NULL, + ADD rc_params blob NOT NULL default ''; diff --git a/maintenance/archives/patch-redirect.sql b/maintenance/archives/patch-redirect.sql index d377f1b1..455a674f 100644 --- a/maintenance/archives/patch-redirect.sql +++ b/maintenance/archives/patch-redirect.sql @@ -15,7 +15,7 @@ CREATE TABLE /*$wgDBprefix*/redirect ( PRIMARY KEY rd_from (rd_from), KEY rd_ns_title (rd_namespace,rd_title,rd_from) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- Import existing redirects -- Using ignore because some of the redirect pages contain more than one link diff --git a/maintenance/archives/patch-rev_len.sql b/maintenance/archives/patch-rev_len.sql new file mode 100644 index 00000000..b861a2bc --- /dev/null +++ b/maintenance/archives/patch-rev_len.sql @@ -0,0 +1,3 @@ +ALTER TABLE /*$wgDBprefix*/revision + ADD rev_len INT(8) UNSIGNED; + diff --git a/maintenance/archives/patch-rev_parent_id.sql b/maintenance/archives/patch-rev_parent_id.sql new file mode 100644 index 00000000..971122bb --- /dev/null +++ b/maintenance/archives/patch-rev_parent_id.sql @@ -0,0 +1,9 @@ +-- +-- Key to revision.rev_id +-- This field is used to add support for a tree structure (The Adjacency List Model) +-- +-- 2007-03-04 +-- + +ALTER TABLE /*$wgDBprefix*/revision + ADD rev_parent_id int(8) unsigned default NULL; diff --git a/maintenance/archives/patch-templatelinks.sql b/maintenance/archives/patch-templatelinks.sql index 49bd9c5e..31318ba7 100644 --- a/maintenance/archives/patch-templatelinks.sql +++ b/maintenance/archives/patch-templatelinks.sql @@ -15,5 +15,5 @@ CREATE TABLE /*$wgDBprefix*/templatelinks ( UNIQUE KEY tl_from(tl_from,tl_namespace,tl_title), KEY (tl_namespace,tl_title) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-transcache.sql b/maintenance/archives/patch-transcache.sql index a244bff8..0d2204e4 100644 --- a/maintenance/archives/patch-transcache.sql +++ b/maintenance/archives/patch-transcache.sql @@ -3,5 +3,5 @@ CREATE TABLE /*$wgDBprefix*/transcache ( tc_contents TEXT, tc_time INT NOT NULL, UNIQUE INDEX tc_url_idx(tc_url) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-user_groups.sql b/maintenance/archives/patch-user_groups.sql index 50f99993..20e00520 100644 --- a/maintenance/archives/patch-user_groups.sql +++ b/maintenance/archives/patch-user_groups.sql @@ -22,4 +22,4 @@ CREATE TABLE /*$wgDBprefix*/user_groups ( PRIMARY KEY (ug_user,ug_group), KEY (ug_group) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-user_rights.sql b/maintenance/archives/patch-user_rights.sql index a32ef457..4c6846e0 100644 --- a/maintenance/archives/patch-user_rights.sql +++ b/maintenance/archives/patch-user_rights.sql @@ -14,7 +14,7 @@ CREATE TABLE /*$wgDBprefix*/user_rights ( UNIQUE KEY ur_user (ur_user) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; INSERT INTO /*$wgDBprefix*/user_rights SELECT user_id,user_rights FROM /*$wgDBprefix*/user; diff --git a/maintenance/archives/patch-userlevels.sql b/maintenance/archives/patch-userlevels.sql index ab3a9a7b..17ff3c5d 100644 --- a/maintenance/archives/patch-userlevels.sql +++ b/maintenance/archives/patch-userlevels.sql @@ -11,7 +11,7 @@ CREATE TABLE /*$wgDBprefix*/groups ( gr_rights tinyblob, PRIMARY KEY (gr_id) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- Relation table between user and groups CREATE TABLE /*$wgDBprefix*/user_groups ( @@ -19,4 +19,4 @@ CREATE TABLE /*$wgDBprefix*/user_groups ( ug_group int(5) unsigned NOT NULL default '0', PRIMARY KEY (ug_user,ug_group) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-validate.sql b/maintenance/archives/patch-validate.sql index 3fa7e844..9701083c 100644 --- a/maintenance/archives/patch-validate.sql +++ b/maintenance/archives/patch-validate.sql @@ -10,4 +10,4 @@ CREATE TABLE /*$wgDBprefix*/validate ( `val_comment` varchar(255) NOT NULL default '', `val_ip` varchar(20) NOT NULL default '', KEY `val_user` (`val_user`,`val_revision`) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/rebuildRecentchanges.inc b/maintenance/archives/rebuildRecentchanges.inc index 54f6cb38..1eaadc4d 100644 --- a/maintenance/archives/rebuildRecentchanges.inc +++ b/maintenance/archives/rebuildRecentchanges.inc @@ -3,8 +3,7 @@ * Rebuild recent changes table * * @deprecated - * @package MediaWiki - * @subpackage MaintenanceArchive + * @addtogroup MaintenanceArchive */ /** */ diff --git a/maintenance/archives/upgradeWatchlist.php b/maintenance/archives/upgradeWatchlist.php index b4605a50..250c6677 100644 --- a/maintenance/archives/upgradeWatchlist.php +++ b/maintenance/archives/upgradeWatchlist.php @@ -1,8 +1,7 @@ <?php /** * @deprecated - * @package MediaWiki - * @subpackage MaintenanceArchive + * @addtogroup MaintenanceArchive */ /** */ diff --git a/maintenance/attachLatest.php b/maintenance/attachLatest.php index f4c11c01..b24143ca 100644 --- a/maintenance/attachLatest.php +++ b/maintenance/attachLatest.php @@ -21,8 +21,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ require_once( 'commandLine.inc' ); @@ -31,7 +30,7 @@ $fixit = isset( $options['fix'] ); $fname = 'attachLatest'; echo "Looking for pages with page_latest set to 0...\n"; -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); $result = $dbw->select( 'page', array( 'page_id', 'page_namespace', 'page_title' ), array( 'page_latest' => 0 ), diff --git a/maintenance/attribute.php b/maintenance/attribute.php index 3326180c..4f575cba 100644 --- a/maintenance/attribute.php +++ b/maintenance/attribute.php @@ -2,8 +2,7 @@ /** * Script for re-attributing edits * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -23,7 +22,7 @@ if ( count( $args ) < 2 ) { $source = $args[0]; $dest = $args[1]; -$dbr =& wfGetDB( DB_SLAVE ); +$dbr = wfGetDB( DB_SLAVE ); extract( $dbr->tableNames( 'page', 'revision','user' )); $eSource = $dbr->strencode( $source ); $eDest = $dbr->strencode( $dest ); diff --git a/maintenance/backup.inc b/maintenance/backup.inc index 1a8ff4fe..ee44954c 100644 --- a/maintenance/backup.inc +++ b/maintenance/backup.inc @@ -18,8 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @package MediaWiki - * @subpackage SpecialPage + * @addtogroup SpecialPage */ class DumpDBZip2Output extends DumpPipeOutput { @@ -98,8 +97,9 @@ class BackupDumper { $sink = null; $sinks = array(); foreach( $args as $arg ) { + $matches = array(); if( preg_match( '/^--(.+?)(?:=(.+?)(?::(.+?))?)?$/', $arg, $matches ) ) { - @list( $full, $opt, $val, $param ) = $matches; + @list( /* $full */ , $opt, $val, $param ) = $matches; switch( $opt ) { case "plugin": $this->loadPlugin( $val, $param ); @@ -174,7 +174,7 @@ class BackupDumper { $this->initProgress( $history ); - $db =& $this->backupDb(); + $db = $this->backupDb(); $exporter = new WikiExporter( $db, $history, WikiExporter::STREAM, $text ); $wrapper = new ExportProgressFilter( $this->sink, $this ); @@ -209,19 +209,23 @@ class BackupDumper { $table = ($history == WikiExporter::CURRENT) ? 'page' : 'revision'; $field = ($history == WikiExporter::CURRENT) ? 'page_id' : 'rev_id'; - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $this->maxCount = $dbr->selectField( $table, "MAX($field)", '', 'BackupDumper::dump' ); $this->startTime = wfTime(); } - function &backupDb() { + function backupDb() { global $wgDBadminuser, $wgDBadminpassword; - global $wgDBname, $wgDebugDumpSql; + global $wgDBname, $wgDebugDumpSql, $wgDBtype; $flags = ($wgDebugDumpSql ? DBO_DEBUG : 0) | DBO_DEFAULT; // god-damn hack - $db = new Database( $this->backupServer(), $wgDBadminuser, $wgDBadminpassword, $wgDBname, false, $flags ); - $timeout = 3600 * 24; - $db->query( "SET net_read_timeout=$timeout" ); - $db->query( "SET net_write_timeout=$timeout" ); + + $class = 'Database' . ucfirst($wgDBtype); + $db = new $class( $this->backupServer(), $wgDBadminuser, $wgDBadminpassword, $wgDBname, false, $flags ); + + // Discourage the server from disconnecting us if it takes a long time + // to read out the big ol' batch query. + $db->setTimeout( 3600 * 24 ); + return $db; } diff --git a/maintenance/benchmarkPurge.php b/maintenance/benchmarkPurge.php index 69127681..bbe73b74 100644 --- a/maintenance/benchmarkPurge.php +++ b/maintenance/benchmarkPurge.php @@ -1,8 +1,7 @@ <?php /** * Squid purge benchmark script - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/changePassword.php b/maintenance/changePassword.php index 591a82b3..82913411 100644 --- a/maintenance/changePassword.php +++ b/maintenance/changePassword.php @@ -2,8 +2,7 @@ /** * Change the password of a given user * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason @@ -18,7 +17,7 @@ class ChangePassword { $this->user = User::newFromName( $user ); $this->password = $password; - $this->dbw =& wfGetDB( DB_MASTER ); + $this->dbw = wfGetDB( DB_MASTER ); } function main() { diff --git a/maintenance/checkUsernames.php b/maintenance/checkUsernames.php index 60e52181..cfff3468 100644 --- a/maintenance/checkUsernames.php +++ b/maintenance/checkUsernames.php @@ -11,7 +11,7 @@ class checkUsernames { function main() { $fname = 'checkUsernames::main'; - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( 'user', array( 'user_id', 'user_name' ), diff --git a/maintenance/cleanupCaps.php b/maintenance/cleanupCaps.php index afcd1b33..5a61bf23 100644 --- a/maintenance/cleanupCaps.php +++ b/maintenance/cleanupCaps.php @@ -25,8 +25,7 @@ * http://www.gnu.org/copyleft/gpl.html * * @author Brion Vibber <brion at pobox.com> - * @package MediaWiki - * @subpackage maintenance + * @addtogroup maintenance */ $options = array( 'dry-run' ); @@ -100,7 +99,7 @@ class CapsCleanup extends FiveUpgrade { $result = $this->dbr->query( $sql, $fname ); while( $row = $this->dbr->fetchObject( $result ) ) { - $updated = call_user_func( $callback, $row ); + call_user_func( $callback, $row ); } $this->log( "Finished $table... $this->updated of $this->processed rows updated" ); $this->dbr->freeResult( $result ); @@ -137,7 +136,6 @@ class CapsCleanup extends FiveUpgrade { if( $row->page_namespace == $this->namespace ) { $talk = $target->getTalkPage(); - $xrow = $row; $row->page_namespace = $talk->getNamespace(); if( $talk->exists() ) { return $this->processPage( $row ); diff --git a/maintenance/cleanupDupes.inc b/maintenance/cleanupDupes.inc index 5db6bb39..ce1ffc6e 100644 --- a/maintenance/cleanupDupes.inc +++ b/maintenance/cleanupDupes.inc @@ -21,12 +21,11 @@ * If on the old non-unique indexes, check the cur table for duplicate * entries and remove them... * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ function fixDupes( $fixthem = false) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $cur = $dbw->tableName( 'cur' ); $old = $dbw->tableName( 'old' ); $dbw->query( "LOCK TABLES $cur WRITE, $old WRITE" ); @@ -113,7 +112,7 @@ END } function checkDupes( $fixthem = false, $indexonly = false ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); if( $dbw->indexExists( 'cur', 'name_title' ) && $dbw->indexUnique( 'cur', 'name_title' ) ) { echo wfWikiID().": cur table has the current unique index; no duplicate entries.\n"; diff --git a/maintenance/cleanupDupes.php b/maintenance/cleanupDupes.php index 3aea2304..4d87da46 100644 --- a/maintenance/cleanupDupes.php +++ b/maintenance/cleanupDupes.php @@ -21,8 +21,7 @@ * If on the old non-unique indexes, check the cur table for duplicate * entries and remove them... * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ $options = array( 'fix', 'index' ); diff --git a/maintenance/cleanupImages.php b/maintenance/cleanupImages.php index 8ae5561a..3ec2c443 100644 --- a/maintenance/cleanupImages.php +++ b/maintenance/cleanupImages.php @@ -25,8 +25,7 @@ * http://www.gnu.org/copyleft/gpl.html * * @author Brion Vibber <brion at pobox.com> - * @package MediaWiki - * @subpackage maintenance + * @addtogroup maintenance */ require_once( 'commandLine.inc' ); diff --git a/maintenance/cleanupSpam.php b/maintenance/cleanupSpam.php index 65d6bc4d..534e160d 100644 --- a/maintenance/cleanupSpam.php +++ b/maintenance/cleanupSpam.php @@ -12,7 +12,6 @@ function cleanupArticle( $id, $domain ) { print $title->getPrefixedDBkey() . " ..."; $rev = Revision::newFromTitle( $title ); - $reverted = false; $revId = $rev->getId(); $currentRevId = $revId; $regex = LinkFilter::makeRegex( $domain ); @@ -32,7 +31,7 @@ function cleanupArticle( $id, $domain ) { // This happens e.g. when a link comes from a template rather than the page itself print "False match\n"; } else { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->immediateBegin(); if ( !$rev ) { // Didn't find a non-spammy revision, blank the page @@ -75,11 +74,11 @@ if ( !$like ) { exit(1); } -$dbr =& wfGetDB( DB_SLAVE ); +$dbr = wfGetDB( DB_SLAVE ); -if ( $options['all'] ) { +if ( isset($options['all']) ) { // Clean up spam on all wikis - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); print "Finding spam on " . count($wgLocalDatabases) . " wikis\n"; $found = false; foreach ( $wgLocalDatabases as $db ) { diff --git a/maintenance/cleanupTable.inc b/maintenance/cleanupTable.inc index cc551bce..cf33e8f0 100644 --- a/maintenance/cleanupTable.inc +++ b/maintenance/cleanupTable.inc @@ -69,7 +69,7 @@ abstract class TableCleanup extends FiveUpgrade { $result = $this->dbr->query( $sql, $fname ); while( $row = $this->dbr->fetchObject( $result ) ) { - $updated = call_user_func( $callback, $row ); + call_user_func( $callback, $row ); } $this->log( "Finished $table... $this->updated of $this->processed rows updated" ); $this->dbr->freeResult( $result ); diff --git a/maintenance/cleanupTitles.php b/maintenance/cleanupTitles.php index 12e07b67..0fb97c6e 100644 --- a/maintenance/cleanupTitles.php +++ b/maintenance/cleanupTitles.php @@ -25,8 +25,7 @@ * http://www.gnu.org/copyleft/gpl.html * * @author Brion Vibber <brion at pobox.com> - * @package MediaWiki - * @subpackage maintenance + * @addtogroup maintenance */ require_once( 'commandLine.inc' ); @@ -38,8 +37,6 @@ class TitleCleanup extends TableCleanup { } function processPage( $row ) { - global $wgContLang; - $current = Title::makeTitle( $row->page_namespace, $row->page_title ); $display = $current->getPrefixedText(); @@ -87,7 +84,7 @@ class TitleCleanup extends TableCleanup { $this->log( "DRY RUN: would rename $row->page_id ($row->page_namespace,'$row->page_title') to ($row->page_namespace,'$dest')" ); } else { $this->log( "renaming $row->page_id ($row->page_namespace,'$row->page_title') to ($row->page_namespace,'$dest')" ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->update( 'page', array( 'page_title' => $dest ), array( 'page_id' => $row->page_id ), @@ -120,7 +117,7 @@ class TitleCleanup extends TableCleanup { $this->log( "DRY RUN: would rename $row->page_id ($row->page_namespace,'$row->page_title') to ($row->page_namespace,'$dest')" ); } else { $this->log( "renaming $row->page_id ($row->page_namespace,'$row->page_title') to ($ns,'$dest')" ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->update( 'page', array( 'page_namespace' => $ns, diff --git a/maintenance/cleanupWatchlist.php b/maintenance/cleanupWatchlist.php index 027859a4..161a9846 100644 --- a/maintenance/cleanupWatchlist.php +++ b/maintenance/cleanupWatchlist.php @@ -25,8 +25,7 @@ * http://www.gnu.org/copyleft/gpl.html * * @author Brion Vibber <brion at pobox.com> - * @package MediaWiki - * @subpackage maintenance + * @addtogroup maintenance */ $options = array( 'fix' ); @@ -95,15 +94,13 @@ class WatchlistCleanup extends FiveUpgrade { $result = $this->dbr->query( $sql, $fname ); while( $row = $this->dbr->fetchObject( $result ) ) { - $updated = call_user_func( $callback, $row ); + call_user_func( $callback, $row ); } $this->log( "Finished $table... $this->updated of $this->processed rows updated" ); $this->dbr->freeResult( $result ); } function processEntry( $row ) { - global $wgContLang; - $current = Title::makeTitle( $row->wl_namespace, $row->wl_title ); $display = $current->getPrefixedText(); @@ -122,7 +119,7 @@ class WatchlistCleanup extends FiveUpgrade { function removeWatch( $row ) { if( !$this->dryrun) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->delete( 'watchlist', array( 'wl_user' => $row->wl_user, 'wl_namespace' => $row->wl_namespace, diff --git a/maintenance/clear_interwiki_cache.php b/maintenance/clear_interwiki_cache.php index 97869728..6f4cfe17 100644 --- a/maintenance/clear_interwiki_cache.php +++ b/maintenance/clear_interwiki_cache.php @@ -2,14 +2,13 @@ /** * This script is used to clear the interwiki links for ALL languages in * memcached. - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ require_once('commandLine.inc'); -$dbr =& wfGetDB( DB_SLAVE ); +$dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( 'interwiki', array( 'iw_prefix' ), false ); $prefixes = array(); while ( $row = $dbr->fetchObject( $res ) ) { diff --git a/maintenance/commandLine.inc b/maintenance/commandLine.inc index 18a1d712..3bf7f1b2 100644 --- a/maintenance/commandLine.inc +++ b/maintenance/commandLine.inc @@ -1,8 +1,7 @@ <?php /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ $wgRequestTime = microtime(true); @@ -172,7 +171,7 @@ if ( file_exists( '/home/wikipedia/common/langlist' ) ) { if ( ! is_readable( $settingsFile ) ) { print "A copy of your installation's LocalSettings.php\n" . - "must exist in the source directory.\n"; + "must exist and be readable in the source directory.\n"; exit( 1 ); } $wgCommandLineMode = true; diff --git a/maintenance/convertLinks.inc b/maintenance/convertLinks.inc index 5f8c27a5..d0c57f78 100644 --- a/maintenance/convertLinks.inc +++ b/maintenance/convertLinks.inc @@ -1,8 +1,7 @@ <?php /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -18,7 +17,7 @@ function convertLinks() { global $wgLang, $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname; global $noKeys, $logPerformance, $fh; - $numRows = $tuplesAdded = $numBadLinks = $curRowsRead = 0; #counters etc + $tuplesAdded = $numBadLinks = $curRowsRead = 0; #counters etc $totalTuplesInserted = 0; # total tuples INSERTed into links_temp $reportCurReadProgress = true; #whether or not to give progress reports while reading IDs from cur table @@ -43,8 +42,8 @@ function convertLinks() { $perfLogFilename = "convLinksPerf.txt"; #-------------------------------------------------------------------- - $dbw =& wfGetDB( DB_MASTER ); - extract( $dbw->tableNames( 'cur', 'links', 'links_temp', 'links_backup' ) ); + $dbw = wfGetDB( DB_MASTER ); + list ($cur, $links, $links_temp, $links_backup) = $dbw->tableNamesN( 'cur', 'links', 'links_temp', 'links_backup' ); $res = $dbw->query( "SELECT l_from FROM $links LIMIT 1" ); if ( $dbw->fieldType( $res, 0 ) == "int" ) { diff --git a/maintenance/convertLinks.php b/maintenance/convertLinks.php index 5939b943..6d07df50 100644 --- a/maintenance/convertLinks.php +++ b/maintenance/convertLinks.php @@ -3,8 +3,7 @@ * 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 * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/createAndPromote.php b/maintenance/createAndPromote.php index 43ddcdd1..7ef48e08 100644 --- a/maintenance/createAndPromote.php +++ b/maintenance/createAndPromote.php @@ -3,8 +3,7 @@ /** * Maintenance script to create an account and grant it administrator rights * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/deleteBatch.php b/maintenance/deleteBatch.php index 14da6d84..3021b118 100644 --- a/maintenance/deleteBatch.php +++ b/maintenance/deleteBatch.php @@ -45,7 +45,7 @@ if ( !$file ) { exit; } -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); for ( $linenum = 1; !feof( $file ); $linenum++ ) { $line = trim( fgets( $file ) ); diff --git a/maintenance/deleteDefaultMessages.php b/maintenance/deleteDefaultMessages.php index 76924002..a649da4c 100644 --- a/maintenance/deleteDefaultMessages.php +++ b/maintenance/deleteDefaultMessages.php @@ -18,7 +18,7 @@ function deleteDefaultMessages() { $wgUser = User::newFromName( $user ); $wgUser->addGroup( 'bot' ); - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( array( 'page', 'revision' ), array( 'page_namespace', 'page_title' ), array( @@ -28,7 +28,7 @@ function deleteDefaultMessages() { ) ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); while ( $row = $dbr->fetchObject( $res ) ) { if ( function_exists( 'wfWaitForSlaves' ) ) { diff --git a/maintenance/deleteImageMemcached.php b/maintenance/deleteImageMemcached.php index 6af0e3a9..267c2a6b 100644 --- a/maintenance/deleteImageMemcached.php +++ b/maintenance/deleteImageMemcached.php @@ -19,7 +19,7 @@ class DeleteImageCache { ini_set( 'display_errors', false ); - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( 'image', array( 'img_name' ), @@ -46,7 +46,7 @@ class DeleteImageCache { function getImageCount() { $fname = 'DeleteImageCache::getImageCount'; - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); return $dbr->selectField( 'image', 'COUNT(*)', array(), $fname ); } } diff --git a/maintenance/deleteOldRevisions.inc b/maintenance/deleteOldRevisions.inc index dd48028a..8d8ca9a1 100644 --- a/maintenance/deleteOldRevisions.inc +++ b/maintenance/deleteOldRevisions.inc @@ -3,8 +3,7 @@ /** * Support functions for the deleteOldRevisions script * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -13,7 +12,7 @@ require_once( 'purgeOldText.inc' ); function DeleteOldRevisions( $delete = false ) { # Data should come off the master, wrapped in a transaction - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->begin(); $tbl_pag = $dbw->tableName( 'page' ); diff --git a/maintenance/deleteOldRevisions.php b/maintenance/deleteOldRevisions.php index 9695a8c5..404f1353 100644 --- a/maintenance/deleteOldRevisions.php +++ b/maintenance/deleteOldRevisions.php @@ -3,8 +3,7 @@ /** * Delete old (non-current) revisions from the database * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/deleteOrphanedRevisions.inc.php b/maintenance/deleteOrphanedRevisions.inc.php index 7cfb1c6b..c935a1c2 100644 --- a/maintenance/deleteOrphanedRevisions.inc.php +++ b/maintenance/deleteOrphanedRevisions.inc.php @@ -3,8 +3,7 @@ /** * Support functions for the deleteOrphanedRevisions maintenance script * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/deleteOrphanedRevisions.php b/maintenance/deleteOrphanedRevisions.php index b4f5b517..302099e6 100644 --- a/maintenance/deleteOrphanedRevisions.php +++ b/maintenance/deleteOrphanedRevisions.php @@ -4,8 +4,7 @@ * Maintenance script to delete revisions which refer to a nonexisting page * Sometimes manual deletion done in a rush leaves crap in the database * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> * @todo More efficient cleanup of text records */ @@ -20,7 +19,7 @@ if( isset( $options['help'] ) ) $report = isset( $options['report'] ); -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); $dbw->immediateBegin(); extract( $dbw->tableNames( 'page', 'revision' ) ); diff --git a/maintenance/deleteRevision.php b/maintenance/deleteRevision.php index eb65e234..af972600 100644 --- a/maintenance/deleteRevision.php +++ b/maintenance/deleteRevision.php @@ -1,7 +1,7 @@ <?php require_once( 'commandLine.inc' ); -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); if ( count( $args ) == 0 ) { echo "Usage: php deleteRevision.php <revid> [<revid> ...]\n"; diff --git a/maintenance/dumpBackup.php b/maintenance/dumpBackup.php index ef5d47c9..8e0941e2 100644 --- a/maintenance/dumpBackup.php +++ b/maintenance/dumpBackup.php @@ -18,8 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @package MediaWiki - * @subpackage SpecialPage + * @addtogroup SpecialPage */ $originalDir = getcwd(); diff --git a/maintenance/dumpHTML.inc b/maintenance/dumpHTML.inc index 702c7df9..ca2a7df6 100644 --- a/maintenance/dumpHTML.inc +++ b/maintenance/dumpHTML.inc @@ -1,7 +1,6 @@ <?php /** - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ define( 'REPORTING_INTERVAL', 10 ); @@ -244,10 +243,9 @@ class DumpHTML { * have a local image */ function doLocalImageDescriptions() { - global $wgSharedUploadDirectory; $chunkSize = 1000; - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $cp = $this->getCheckpoint( 'local image' ); if ( $cp == 'done' ) { @@ -347,7 +345,7 @@ class DumpHTML { $chunkSize = 1000; $this->setupGlobals(); - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $cp = $this->getCheckpoint( 'category' ); if ( $cp == 'done' ) { @@ -410,7 +408,7 @@ class DumpHTML { } $this->setupGlobals(); - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $i = 0; for ( $chunkStart = $start; $chunkStart <= $end; $chunkStart += $chunkSize ) { @@ -443,9 +441,6 @@ class DumpHTML { /** Write an article specified by title */ function doArticle( $title ) { - global $wgTitle, $wgSharedUploadPath, $wgSharedUploadDirectory; - global $wgUploadDirectory; - if ( $this->noOverwrite ) { $fileName = $this->dest.'/'.$this->getHashedFilename( $title ); if ( file_exists( $fileName ) ) { @@ -484,7 +479,7 @@ class DumpHTML { print "Writing $file\n"; $file = fopen( $path, 'w' ); if ( !$file ) { - print("Can't open file $fullName for writing\n"); + print("Can't open file $path for writing\n"); continue; } fwrite( $file, $text ); @@ -496,7 +491,7 @@ class DumpHTML { } /** Write the given text to the file identified by the given title object */ - function writeArticle( &$title, $text ) { + function writeArticle( $title, $text ) { $filename = $this->getHashedFilename( $title ); # Temporary hack for current dump, this should be moved to @@ -536,7 +531,7 @@ class DumpHTML { /** Set up globals required for parsing */ function setupGlobals( $currentDepth = NULL ) { - global $wgUser, $wgTitle, $wgStylePath, $wgArticlePath, $wgMathPath; + global $wgUser, $wgStylePath, $wgArticlePath, $wgMathPath; global $wgUploadPath, $wgLogo, $wgMaxCredits, $wgSharedUploadPath; global $wgHideInterlanguageLinks, $wgUploadDirectory, $wgThumbnailScriptPath; global $wgSharedThumbnailScriptPath, $wgEnableParserCache, $wgHooks, $wgServer; @@ -623,7 +618,7 @@ class DumpHTML { } /** Reads the content of a title object, executes the skin and captures the result */ - function getArticleHTML( &$title ) { + function getArticleHTML( $title ) { global $wgOut, $wgTitle, $wgArticle, $wgUser; $linkCache =& LinkCache::singleton(); @@ -800,6 +795,7 @@ ENDTEXT; $url = false; if ( $query != '' ) { + $params = array(); parse_str( $query, $params ); if ( isset($params['action']) && $params['action'] == 'raw' ) { if ( $params['gen'] == 'css' || $params['gen'] == 'js' ) { @@ -807,6 +803,7 @@ ENDTEXT; } else { $file = $this->getFriendlyName( $title->getPrefixedDBkey() ); // Clean up Monobook.css etc. + $matches = array(); if ( preg_match( '/^(.*)\.(css|js)_[0-9a-f]{4}$/', $file, $matches ) ) { $file = $matches[1] . '.' . $matches[2]; } @@ -882,6 +879,7 @@ ENDTEXT; } # Split into characters + $m = array(); preg_match_all( '/./us', $dbk, $m ); $chars = $m[0]; @@ -958,7 +956,7 @@ ENDTEXT; function getMaxPageID() { if ( $this->maxPageID === false ) { - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $this->maxPageID = $dbr->selectField( 'page', 'max(page_id)', false, __METHOD__ ); } return $this->maxPageID; diff --git a/maintenance/dumpHTML.php b/maintenance/dumpHTML.php index 2c0c29c4..b9b052ed 100644 --- a/maintenance/dumpHTML.php +++ b/maintenance/dumpHTML.php @@ -1,8 +1,7 @@ <?php /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** @@ -62,7 +61,7 @@ if ( !empty( $options['s'] ) ) { if ( !empty( $options['e'] ) ) { $end = $options['e']; } else { - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $end = $dbr->selectField( 'page', 'max(page_id)', false ); } @@ -117,7 +116,7 @@ if ( $options['special'] ) { $wgHTMLDump->doSharedImageDescriptions(); } else { print "Creating static HTML dump in directory $dest. \n"; - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $server = $dbr->getProperty( 'mServer' ); print "Using database {$server}\n"; diff --git a/maintenance/dumpInterwiki.inc b/maintenance/dumpInterwiki.inc index 2039f2df..9af6ccc5 100644 --- a/maintenance/dumpInterwiki.inc +++ b/maintenance/dumpInterwiki.inc @@ -4,16 +4,14 @@ * Wikimedia specific! * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ class Site { var $suffix, $lateral, $url; @@ -52,15 +50,10 @@ function getRebuildInterwikiDump() { # List of all database names $dblist = array_map( "trim", file( "/home/wikipedia/common/all.dblist" ) ); - # Special-case hostnames - $specials = array( - 'sourceswiki' => 'sources.wikipedia.org', - 'quotewiki' => 'wikiquote.org', - 'textbookwiki' => 'wikibooks.org', - 'sep11wiki' => 'sep11.wikipedia.org', - 'metawiki' => 'meta.wikimedia.org', - 'commonswiki' => 'commons.wikimedia.org', - ); + # Special-case databases + $specials = array_flip( + array_map( "trim", + file( "/home/wikipedia/common/special.dblist" ) ) ); # Extra interwiki links that can't be in the intermap for some reason $extraLinks = array( @@ -106,8 +99,7 @@ function getRebuildInterwikiDump() { wfDie( "m:Interwiki_map not found" ); } - $iwArray = array(); - # Global iterwiki map + # Global iterwiki map foreach ( $lines as $line ) { if ( preg_match( '/^\|\s*(.*?)\s*\|\|\s*(.*?)\s*$/', $line, $matches ) ) { $prefix = strtolower( $matches[1] ); @@ -130,7 +122,7 @@ function getRebuildInterwikiDump() { #Multilanguage sites foreach ($sites as $site) - $sql .= makeLanguageLinks ( $site, "_".$site->suffix ); + makeLanguageLinks ( $site, "_".$site->suffix ); foreach ( $dblist as $db ) { @@ -162,7 +154,6 @@ function getRebuildInterwikiDump() { continue; } $lang = $matches[1]; - $host = "$lang." . $site->url; # Lateral links foreach ( $sites as $targetSite ) { @@ -187,7 +178,7 @@ function getRebuildInterwikiDump() { # ------------------------------------------------------------------------------------------ -# Returns part of an INSERT statement, corresponding to all interlanguage links to a particular site +# Executes part of an INSERT statement, corresponding to all interlanguage links to a particular site function makeLanguageLinks( &$site, $source ) { global $langlist, $languageAliases; # Actual languages with their own databases diff --git a/maintenance/dumpInterwiki.php b/maintenance/dumpInterwiki.php index 411260ac..ba3ac18b 100644 --- a/maintenance/dumpInterwiki.php +++ b/maintenance/dumpInterwiki.php @@ -3,8 +3,7 @@ * Rebuild interwiki table using the file on meta and the language list * Wikimedia specific! * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/dumpLinks.php b/maintenance/dumpLinks.php index f040f390..2caa873c 100644 --- a/maintenance/dumpLinks.php +++ b/maintenance/dumpLinks.php @@ -26,13 +26,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @package MediaWiki - * @subpackage SpecialPage + * @addtogroup SpecialPage */ require_once 'commandLine.inc'; -$dbr =& wfGetDB( DB_SLAVE ); +$dbr = wfGetDB( DB_SLAVE ); $result = $dbr->select( array( 'pagelinks', 'page' ), array( 'page_id', @@ -42,7 +41,7 @@ $result = $dbr->select( array( 'pagelinks', 'page' ), 'pl_title' ), array( 'page_id=pl_from' ), 'dumpLinks', - array( 'ORDER BY page_id' ) ); + array( 'ORDER BY' => 'page_id' ) ); $lastPage = null; while( $row = $dbr->fetchObject( $result ) ) { diff --git a/maintenance/dumpReplayLog.php b/maintenance/dumpReplayLog.php index aa1d5b9a..07749f41 100644 --- a/maintenance/dumpReplayLog.php +++ b/maintenance/dumpReplayLog.php @@ -1,7 +1,6 @@ <?php /** - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ error_reporting(E_ALL); @@ -11,7 +10,7 @@ require_once( 'includes/SpecialExport.php' ); /** */ function dumpReplayLog( $start ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $recentchanges = $dbw->tableName( 'recentchanges' ); $result =& $dbw->safeQuery( "SELECT * FROM $recentchanges WHERE rc_timestamp >= " . $dbw->timestamp( $start ) . ' ORDER BY rc_timestamp'); @@ -34,7 +33,7 @@ function dumpReplayEntry( $row ) { case RC_EDIT: case RC_NEW: # Edit - $dbr =& wfGetDB( DB_MASTER ); + $dbr = wfGetDB( DB_MASTER ); $out = " <edit>\n"; $out .= " <title>" . xmlsafe( $title->getPrefixedText() ) . "</title>\n"; @@ -65,7 +64,7 @@ function dumpReplayEntry( $row ) { $out .= " </edit>\n"; break; case RC_LOG: - $dbr =& wfGetDB( DB_MASTER ); + $dbr = wfGetDB( DB_MASTER ); $s = $dbr->selectRow( 'logging', array( 'log_type', 'log_action', 'log_timestamp', 'log_user', 'log_namespace', 'log_title', 'log_comment' ), diff --git a/maintenance/dumpSisterSites.php b/maintenance/dumpSisterSites.php index 50e121e6..45927b0d 100644 --- a/maintenance/dumpSisterSites.php +++ b/maintenance/dumpSisterSites.php @@ -21,8 +21,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @package MediaWiki - * @subpackage SpecialPage + * @addtogroup SpecialPage */ require_once( 'commandLine.inc' ); diff --git a/maintenance/dumpTextPass.php b/maintenance/dumpTextPass.php index 8c1563ad..494c5ad4 100644 --- a/maintenance/dumpTextPass.php +++ b/maintenance/dumpTextPass.php @@ -18,8 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @package MediaWiki - * @subpackage SpecialPage + * @addtogroup SpecialPage */ $originalDir = getcwd(); @@ -117,7 +116,7 @@ class TextPassDumper extends BackupDumper { $this->initProgress( $this->history ); - $this->db =& $this->backupDb(); + $this->db = $this->backupDb(); $this->egress = new ExportProgressFilter( $this->sink, $this ); diff --git a/maintenance/eval.php b/maintenance/eval.php index 4e477f4c..421db682 100644 --- a/maintenance/eval.php +++ b/maintenance/eval.php @@ -12,8 +12,7 @@ * To get decent line editing behavior, you should compile PHP with support * for GNU readline (pass --with-readline to configure). * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ $wgForceLoadBalancing = (getenv('MW_BALANCE') ? true : false); diff --git a/maintenance/findhooks.php b/maintenance/findhooks.php index 4f446f2b..0308ad13 100644 --- a/maintenance/findhooks.php +++ b/maintenance/findhooks.php @@ -7,8 +7,7 @@ * - 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. * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * * @author Ashar Voultoiz <hashar@altern.org> * @copyright Copyright © Ashar voultoiz @@ -33,6 +32,7 @@ $pathinc = $IP . '/includes/'; function getHooksFromDoc() { global $doc; $content = file_get_contents( $doc ); + $m = array(); preg_match_all( "/\n'(.*?)'/", $content, $m); return $m[1]; } @@ -44,6 +44,7 @@ function getHooksFromDoc() { */ function getHooksFromFile( $file ) { $content = file_get_contents( $file ); + $m = array(); preg_match_all( "/wfRunHooks\(\s*\'(.*?)\'/", $content, $m); return $m[1]; } diff --git a/maintenance/fixSlaveDesync.php b/maintenance/fixSlaveDesync.php index d2dffe54..aec77b1e 100644 --- a/maintenance/fixSlaveDesync.php +++ b/maintenance/fixSlaveDesync.php @@ -20,7 +20,7 @@ $reportingInterval = 1000; if ( isset( $args[0] ) ) { desyncFixPage( $args[0] ); } else { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $maxPage = $dbw->selectField( 'page', 'MAX(page_id)', false, 'fixDesync.php' ); $corrupt = findPageLatestCorruption(); foreach ( $corrupt as $id => $dummy ) { @@ -38,7 +38,7 @@ if ( isset( $args[0] ) ) { function findPageLatestCorruption() { $desync = array(); $n = 0; - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $masterIDs = array(); $res = $dbw->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ ); print "Number of pages: " . $dbw->numRows( $res ) . "\n"; @@ -53,8 +53,7 @@ function findPageLatestCorruption() { global $slaveIndexes; foreach ( $slaveIndexes as $i ) { - $slaveIDs = array(); - $db =& wfGetDB( $i ); + $db = wfGetDB( $i ); $res = $db->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ ); while ( $row = $db->fetchObject( $res ) ) { if ( isset( $masterIDs[$row->page_id] ) && $masterIDs[$row->page_id] != $row->page_latest ) { @@ -73,14 +72,14 @@ function desyncFixPage( $pageID ) { $fname = 'desyncFixPage'; # Check for a corrupted page_latest - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->begin(); $realLatest = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), $fname, 'FOR UPDATE' ); #list( $masterFile, $masterPos ) = $dbw->getMasterPos(); $found = false; foreach ( $slaveIndexes as $i ) { - $db =& wfGetDB( $i ); + $db = wfGetDB( $i ); /* if ( !$db->masterPosWait( $masterFile, $masterPos, 10 ) ) { echo "Slave is too lagged, aborting\n"; @@ -122,7 +121,6 @@ function desyncFixPage( $pageID ) { if ( count( $missingIDs ) ) { print "Found " . count( $missingIDs ) . " lost in master, copying from slave... "; $dbFrom = $db; - $dbTo = $dbw; $found = true; $toMaster = true; } else { @@ -133,7 +131,6 @@ function desyncFixPage( $pageID ) { if ( count( $missingIDs ) ) { print "Found " . count( $missingIDs ) . " missing revision(s), copying from master... "; $dbFrom = $dbw; - $dbTo = $db; $found = true; $toMaster = false; } else { @@ -158,7 +155,7 @@ function desyncFixPage( $pageID ) { } } else { foreach ( $slaveIndexes as $i ) { - $db =& wfGetDB( $i ); + $db = wfGetDB( $i ); $db->insert( 'revision', get_object_vars( $row ), $fname, 'IGNORE' ); } } @@ -169,7 +166,7 @@ function desyncFixPage( $pageID ) { $dbw->insert( 'text', get_object_vars( $row ), $fname, 'IGNORE' ); } else { foreach ( $slaveIndexes as $i ) { - $db =& wfGetDB( $i ); + $db = wfGetDB( $i ); $db->insert( 'text', get_object_vars( $row ), $fname, 'IGNORE' ); } } @@ -183,7 +180,7 @@ function desyncFixPage( $pageID ) { #$dbw->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), $fname ); } else { foreach ( $slaveIndexes as $i ) { - $db =& wfGetDB( $i ); + $db = wfGetDB( $i ); $db->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), $fname ); } } diff --git a/maintenance/fixTimestamps.php b/maintenance/fixTimestamps.php index 784e35cd..abd861d4 100644 --- a/maintenance/fixTimestamps.php +++ b/maintenance/fixTimestamps.php @@ -22,7 +22,7 @@ $fname = 'fixTimestamps.php'; $grace = 60; // maximum normal clock offset # Find bounding revision IDs -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); $revisionTable = $dbw->tableName( 'revision' ); $res = $dbw->query( "SELECT MIN(rev_id) as minrev, MAX(rev_id) as maxrev FROM $revisionTable " . "WHERE rev_timestamp BETWEEN '{$start}' AND '{$end}'", $fname ); diff --git a/maintenance/fixUserRegistration.php b/maintenance/fixUserRegistration.php index af8a68c2..471ef055 100644 --- a/maintenance/fixUserRegistration.php +++ b/maintenance/fixUserRegistration.php @@ -8,8 +8,8 @@ require_once( 'commandLine.inc' ); $fname = 'fixUserRegistration.php'; -$dbr =& wfGetDB( DB_SLAVE ); -$dbw =& wfGetDB( DB_MASTER ); +$dbr = wfGetDB( DB_SLAVE ); +$dbw = wfGetDB( DB_MASTER ); // Get user IDs which need fixing $res = $dbr->select( 'user', 'user_id', 'user_registration IS NULL', $fname ); diff --git a/maintenance/fuzz-tester.php b/maintenance/fuzz-tester.php index 0ee052b2..4e90d52b 100644 --- a/maintenance/fuzz-tester.php +++ b/maintenance/fuzz-tester.php @@ -1,7 +1,6 @@ <?php /** -* @package MediaWiki -* @subpackage Maintainance +* @addtogroup Maintenance * @author Nick Jenkins ( http://nickj.org/ ). * @copyright 2006 Nick Jenkins * @licence GNU General Public Licence 2.0 @@ -106,6 +105,9 @@ Wiki configuration for testing: //$wgUseTrackbacks = true; // enable trackbacks; However this breaks the viewPageTest, so currently disabled. $wgDBerrorLog = "/root/mediawiki-db-error-log.txt"; // log DB errors, replace with suitable path. $wgShowSQLErrors = true; // Show SQL errors (instead of saying the query was hidden). + $wgShowExceptionDetails = true; // want backtraces. + $wgEnableAPI = true; // enable API. + $wgEnableWriteAPI = true; // enable API. // Install & enable Parser Hook extensions to increase code coverage. E.g.: require_once("extensions/ParserFunctions/ParserFunctions.php"); @@ -124,6 +126,16 @@ Wiki configuration for testing: require_once("extensions/Renameuser/SpecialRenameuser.php"); require_once("extensions/LinkSearch/LinkSearch.php"); // --------- End --------- + + If you want to try E_STRICT error logging, add this to the above: + // --------- Start --------- + error_reporting (E_ALL | E_STRICT); + set_error_handler( 'error_handler' ); + function error_handler ($type, $message, $file=__FILE__, $line=__LINE__) { + if ($message == "var: Deprecated. Please use the public/private/protected modifiers") return; + print "<br />\n<b>Strict Standards:</b> Type: <b>$type</b>: $message in <b>$file</b> on line <b>$line</b><br />\n"; + } + // --------- End --------- Also add/change this in AdminSettings.php: // --------- Start --------- @@ -190,6 +202,7 @@ Options: Only applies to new tests, not --rerun-failed-tests --specific-test : Runs only the specified fuzz test. Only applies to new tests, not --rerun-failed-tests + --keep-passed-tests : Saves all test files, even those that pass. --help : Show this help message. Example: @@ -209,7 +222,7 @@ ENDS; $validOptions = array ("quiet", "base-url", "directory", "include-binary", "w3c-validate", "user", "password", "delete-passed-retests", "rerun-failed-tests", "max-errors", - "max-runtime", "specific-test", "help" ); + "max-runtime", "specific-test", "keep-passed-tests", "help" ); if (!empty($options)) { $unknownArgs = array_diff (array_keys($options), $validOptions); foreach ($unknownArgs as $invalidArg) { @@ -278,6 +291,10 @@ define("DB_ERROR_LOG_FILE", $wgDBerrorLog ); // Run in chatty mode (all output, default), or run in quiet mode (only prints out details of failed tests)? define("QUIET", isset($options["quiet"]) ); +// Keep all test files, even those that pass. Potentially useful to tracking input that causes something +// unusual to happen, if you don't know what "unusual" is until later. +define("KEEP_PASSED_TESTS", isset($options["keep-passed-tests"]) ); + // The maximum runtime, if specified. if (!empty($options["max-runtime"]) && intval($options["max-runtime"])>0) { define("MAX_RUNTIME", intval($options["max-runtime"]) ); @@ -371,6 +388,11 @@ class wikiFuzz { "sort" => array("order", "class"), "ref" => array("name"), "categorytree" => array("hideroot", "mode", "style"), + "chemform" => array("link", "wikilink", "query"), + "section" => array("begin", "new"), + + // older MW transclusion. + "transclude" => array("page"), ); // The types of the HTML that we will be testing were defined above @@ -581,7 +603,7 @@ class wikiFuzz { "}}", "{{MSGNW:", "}}", - "{{INT:", + "{{INT:", "}}", '{{SITENAME}}', "{{NS:", @@ -625,6 +647,10 @@ class wikiFuzz { "{{PAGESINNAMESPACE:}}", "{{#language:", "}}", + "{{#special:", + "}}", + "{{#special:emailuser", + "}}", // Some raw link for magic words. "{{NUMBEROFPAGES:R", @@ -641,6 +667,8 @@ class wikiFuzz { "}}", "{{padright:", "}}", + "{{DEFAULTSORT:", + "}}", // internal Math "extension": "<math>", @@ -680,7 +708,7 @@ class wikiFuzz { "<gallery>", "</gallery>", - // FixedImage: + // FixedImage extension. "<fundraising/>", // Timeline extension: currently untested. @@ -691,6 +719,14 @@ class wikiFuzz { // an external image to test the external image displaying code "http://debian.org/Pics/debian.png", + + // LabeledSectionTransclusion extension. + "{{#lstx:", + "}}", + "{{#lst:", + "}}", + "{{#lst:Main Page|", + "}}" ); /** @@ -730,6 +766,8 @@ class wikiFuzz { // "&#" . wikiFuzz::randnum(255) . ";" // Hex version: ? "&#x" . str_pad(dechex(wikiFuzz::randnum(255)), wikiFuzz::randnum(2, 7), "0", STR_PAD_LEFT) . ";" + // A truly binary version: + // ? chr(wikiFuzz::randnum(0,255)) : chr(wikiFuzz::randnum(126,32)); $length = wikiFuzz::randnum(8); @@ -833,6 +871,7 @@ class wikiFuzz { ** 1) Form parameters. ** 2) the URL we are going to test those parameters on. ** 3) Any cookies required for the test. + ** 4) Whether Tidy should validate the page. Defaults to true, but can be turned off. ** Declared abstract because it should be extended by a class ** that supplies these parameters. */ @@ -840,6 +879,7 @@ abstract class pageTest { protected $params; protected $pagePath; protected $cookie = ""; + protected $tidyValidate = true; public function getParams() { return $this->params; @@ -852,6 +892,10 @@ abstract class pageTest { public function getCookie() { return $this->cookie; } + + public function tidyValidate() { + return $this->tidyValidate; + } } @@ -892,7 +936,7 @@ class editPageTest extends pageTest { */ class listusersTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Listusers"; + $this->pagePath = "index.php?title=Special:Listusers"; $this->params = array ( "title" => wikiFuzz::makeFuzz(2), @@ -911,10 +955,10 @@ class listusersTest extends pageTest { */ class searchTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Search"; + $this->pagePath = "index.php?title=Special:Search"; $this->params = array ( - "action" => "index.php/Special:Search", + "action" => "index.php?title=Special:Search", "ns0" => wikiFuzz::makeFuzz(2), "ns1" => wikiFuzz::makeFuzz(2), "ns2" => wikiFuzz::makeFuzz(2), @@ -946,7 +990,7 @@ class searchTest extends pageTest { */ class recentchangesTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Recentchanges"; + $this->pagePath = "index.php?title=Special:Recentchanges"; $this->params = array ( "action" => wikiFuzz::makeFuzz(2), @@ -975,7 +1019,7 @@ class recentchangesTest extends pageTest { */ class prefixindexTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Prefixindex"; + $this->pagePath = "index.php?title=Special:Prefixindex"; $this->params = array ( "title" => "Special:Prefixindex", @@ -1001,10 +1045,10 @@ class prefixindexTest extends pageTest { */ class mimeSearchTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:MIMEsearch"; + $this->pagePath = "index.php?title=Special:MIMEsearch"; $this->params = array ( - "action" => "/wiki/index.php/Special:MIMEsearch", + "action" => "index.php?title=Special:MIMEsearch", "mime" => wikiFuzz::makeFuzz(3), 'limit' => wikiFuzz::chooseInput( array("0", "-1", "-------'------0", "+1", "81342321351235325", wikiFuzz::makeFuzz(2)) ), 'offset' => wikiFuzz::chooseInput( array("0", "-1", "-----'--------0", "+1", "81341231235365252234324", wikiFuzz::makeFuzz(2)) ) @@ -1018,7 +1062,7 @@ class mimeSearchTest extends pageTest { */ class specialLogTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Log"; + $this->pagePath = "index.php?title=Special:Log"; $this->params = array ( "type" => wikiFuzz::chooseInput( array("", wikiFuzz::makeFuzz(2)) ), @@ -1058,7 +1102,7 @@ class successfulUserLoginTest extends pageTest { class userLoginTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Userlogin"; + $this->pagePath = "index.php?title=Special:Userlogin"; $this->params = array ( 'wpRetype' => wikiFuzz::makeFuzz(2), @@ -1088,7 +1132,7 @@ class userLoginTest extends pageTest { */ class ipblocklistTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Ipblocklist"; + $this->pagePath = "index.php?title=Special:Ipblocklist"; $this->params = array ( 'wpUnblockAddress'=> wikiFuzz::makeFuzz(2), @@ -1121,7 +1165,7 @@ class ipblocklistTest extends pageTest { */ class newImagesTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Newimages"; + $this->pagePath = "index.php?title=Special:Newimages"; $this->params = array ( 'hidebots' => wikiFuzz::chooseInput( array(wikiFuzz::makeFuzz(2), "1", "", "-1") ), @@ -1142,7 +1186,7 @@ class newImagesTest extends pageTest { */ class imagelistTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Imagelist"; + $this->pagePath = "index.php?title=Special:Imagelist"; $this->params = array ( 'sort' => wikiFuzz::chooseInput( array("bysize", "byname" , "bydate", wikiFuzz::makeFuzz(2)) ), @@ -1159,7 +1203,7 @@ class imagelistTest extends pageTest { */ class specialExportTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Export"; + $this->pagePath = "index.php?title=Special:Export"; $this->params = array ( 'action' => wikiFuzz::chooseInput( array("submit", "", wikiFuzz::makeFuzz(2)) ), @@ -1175,6 +1219,9 @@ class specialExportTest extends pageTest { // Sometimes remove the history field. if (wikiFuzz::randnum(2) == 0) unset($this->params["history"]); + + // page does not produce HTML. + $this->tidyValidate = false; } } @@ -1184,7 +1231,7 @@ class specialExportTest extends pageTest { */ class specialBooksourcesTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Booksources"; + $this->pagePath = "index.php?title=Special:Booksources"; $this->params = array ( 'go' => wikiFuzz::makeFuzz(2), @@ -1236,10 +1283,10 @@ class pageHistoryTest extends pageTest { */ class contributionsTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Contributions/" . USER_ON_WIKI; + $this->pagePath = "index.php?title=Special:Contributions/" . USER_ON_WIKI; $this->params = array ( - 'target' => wikiFuzz::chooseInput( array(wikiFuzz::makeFuzz(2), "newbies") ), + 'target' => wikiFuzz::chooseInput( array(wikiFuzz::makeFuzz(2), "newbies", USER_ON_WIKI) ), 'namespace' => wikiFuzz::chooseInput( array(-1, 15, 1, wikiFuzz::makeFuzz(2)) ), 'offset' => wikiFuzz::chooseInput( array("0", "-1", "------'-------0", "+1", "982342131232131231241", wikiFuzz::makeFuzz(2)) ), 'bot' => wikiFuzz::chooseInput( array("", "-1", "0", "1", wikiFuzz::makeFuzz(2)) ), @@ -1254,7 +1301,7 @@ class contributionsTest extends pageTest { */ class viewPageTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Main_Page"; + $this->pagePath = "index.php?title=Main_Page"; $this->params = array ( "useskin" => wikiFuzz::chooseInput( array("chick", "cologneblue", "myskin", @@ -1298,8 +1345,8 @@ class viewPageTest extends pageTest { ); // Tidy does not know how to valid atom or rss, so exclude from testing for the time being. - if ($this->params["feed"] == "atom") unset($this->params["feed"]); - else if ($this->params["feed"] == "rss") unset($this->params["feed"]); + if ($this->params["feed"] == "atom") { unset($this->params["feed"]); } + else if ($this->params["feed"] == "rss") { unset($this->params["feed"]); } // Raw pages cannot really be validated if ($this->params["action"] == "raw") unset($this->params["action"]); @@ -1335,7 +1382,7 @@ class specialAllmessagesTest extends pageTest { */ class specialNewpages extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Newpages"; + $this->pagePath = "index.php?title=Special:Newpages"; $this->params = array ( "namespace" => wikiFuzz::chooseInput( range(-1, 15) ), @@ -1345,8 +1392,8 @@ class specialNewpages extends pageTest { ); // Tidy does not know how to valid atom or rss, so exclude from testing for the time being. - if ($this->params["feed"] == "atom") unset($this->params["feed"]); - else if ($this->params["feed"] == "rss") unset($this->params["feed"]); + if ($this->params["feed"] == "atom") { unset($this->params["feed"]); } + else if ($this->params["feed"] == "rss") { unset($this->params["feed"]); } } } @@ -1533,7 +1580,7 @@ class specialLockdb extends pageTest { */ class specialUserrights extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Userrights"; + $this->pagePath = "index.php?title=Special:Userrights"; $this->params = array ( 'wpEditToken' => wikiFuzz::chooseInput( array("20398702394", "", wikiFuzz::makeFuzz(2)) ), @@ -1580,7 +1627,7 @@ class pageProtectionForm extends pageTest { */ class specialBlockip extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Blockip"; + $this->pagePath = "index.php?title=Special:Blockip"; $this->params = array ( "action" => wikiFuzz::chooseInput( array("submit", "", wikiFuzz::makeFuzz(2)) ), @@ -1619,7 +1666,7 @@ class specialBlockip extends pageTest { */ class imagepageTest extends pageTest { function __construct() { - $this->pagePath = "index.php/Image:Small-email.png"; + $this->pagePath = "index.php?title=Image:Small-email.png"; $this->params = array ( "image" => wikiFuzz::chooseInput( array("Small-email.png", wikifuzz::makeFuzz(2)) ), @@ -1695,7 +1742,7 @@ class specialRevisionDelete extends pageTest { */ class specialImport extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Import"; + $this->pagePath = "index.php?title=Special:Import"; $this->params = array ( "action" => "submit", @@ -1722,7 +1769,6 @@ class specialImport extends pageTest { } - /** ** a test for thumb.php */ @@ -1762,6 +1808,9 @@ class trackbackTest extends pageTest { // sometimes we don't want to specify certain parameters. if (wikiFuzz::randnum(3) == 0) unset($this->params["title"]); if (wikiFuzz::randnum(3) == 0) unset($this->params["excerpt"]); + + // page does not produce HTML. + $this->tidyValidate = false; } } @@ -1810,7 +1859,7 @@ class specialCite extends pageTest { */ class specialFilepath extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Filepath"; + $this->pagePath = "index.php?title=Special:Filepath"; $this->params = array ( "file" => wikiFuzz::chooseInput( array("Small-email.png", "Small-email.png" . wikifuzz::makeFuzz(1), wikiFuzz::makeFuzz(2)) ), @@ -1824,7 +1873,7 @@ class specialFilepath extends pageTest { */ class specialMakebot extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Makebot"; + $this->pagePath = "index.php?title=Special:Makebot"; $this->params = array ( "username" => wikiFuzz::chooseInput( array("Nickj2", "192.168.0.2", wikifuzz::makeFuzz(1) ) ), @@ -1847,7 +1896,7 @@ class specialMakebot extends pageTest { */ class specialMakesysop extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Makesysop"; + $this->pagePath = "index.php?title=Special:Makesysop"; $this->params = array ( "wpMakesysopUser" => wikiFuzz::chooseInput( array("Nickj2", "192.168.0.2", wikifuzz::makeFuzz(1) ) ), @@ -1870,7 +1919,7 @@ class specialMakesysop extends pageTest { */ class specialRenameuser extends pageTest { function __construct() { - $this->pagePath = "index.php/Special:Renameuser"; + $this->pagePath = "index.php?title=Special:Renameuser"; $this->params = array ( "oldusername" => wikiFuzz::chooseInput( array("Nickj2", "192.168.0.2", wikifuzz::makeFuzz(1) ) ), @@ -1910,7 +1959,7 @@ class specialCategoryTree extends pageTest { "from" => wikifuzz::makeFuzz(2), "until" => wikifuzz::makeFuzz(2), "showas" => wikifuzz::makeFuzz(2), - "mode" => wikiFuzz::chooseInput( array("pages", "categories", "all", wikifuzz::makeFuzz(2)) ), + "mode" => wikiFuzz::chooseInput( array("pages", "categories", "all", wikifuzz::makeFuzz(2)) ), ); // sometimes we do want to specify certain parameters. @@ -1919,6 +1968,239 @@ class specialCategoryTree extends pageTest { } +/** + ** a test for "Special:Chemicalsources" (extension Special page). + */ +class specialChemicalsourcesTest extends pageTest { + function __construct() { + $this->pagePath = "index.php?title=Special:Chemicalsources"; + + // choose an input format to use. + $format = wikiFuzz::chooseInput( + array( 'go', + 'CAS', + 'EINECS', + 'CHEBI', + 'PubChem', + 'SMILES', + 'InChI', + 'ATCCode', + 'KEGG', + 'RTECS', + 'ECNumber', + 'DrugBank', + 'Formula', + 'Name' + ) + ); + + // values for different formats usually start with either letters or numbers. + switch ($format) { + case 'Name' : $value = "A"; break; + case 'InChI' : + case 'SMILES' : + case 'Formula': $value = "C"; break; + default : $value = "0"; break; + } + + // and then we append the fuzz input. + $this->params = array ($format => $value . wikifuzz::makeFuzz(2) ); + } +} + + +/** + ** A test for api.php (programmatic interface to MediaWiki in XML/JSON/RSS/etc formats). + ** Quite involved to test because there are lots of options/parameters, and because + ** for a lot of the functionality if all the parameters don't make sense then it just + ** returns the help screen - so currently a lot of the tests aren't actually doing much + ** because something wasn't right in the query. + ** + ** @todo: Incomplete / unfinished; Runs too fast (suggests not much testing going on). + */ +class api extends pageTest { + + // API login mode. + private static function loginMode() { + $arr = array ( "lgname" => wikifuzz::makeFuzz(2), + "lgpassword" => wikifuzz::makeFuzz(2), + ); + // sometimes we want to specify the extra "lgdomain" parameter. + if (wikiFuzz::randnum(3) == 0) { + $arr["lgdomain"] = wikiFuzz::chooseInput( array("1", 0, "", wikiFuzz::makeFuzz(2)) ); + } + + return $arr; + } + + // API OpenSearch mode. + private static function opensearchMode() { + return array ("search" => wikifuzz::makeFuzz(2)); + } + + // API watchlist feed mode. + private static function feedwatchlistMode() { + // FIXME: add "wikifuzz::makeFuzz(2)" as possible value below? + return array ("feedformat" => wikiFuzz::chooseInput( array("rss", "atom") ) ); + } + + // API query mode. + private static function queryMode() { + // FIXME: add "wikifuzz::makeFuzz(2)" as possible params for the elements below? + // Suspect this will stuff up the tests more, but need to check. + $params = array ( + // FIXME: More titles. + "titles" => wikiFuzz::chooseInput( array("Main Page")), + // FIXME: More pageids. + "pageids" => 1, + "prop" => wikiFuzz::chooseInput( array("info", "revisions", "watchlist")), + "list" => wikiFuzz::chooseInput( array("allpages", "logevents", "watchlist", "usercontribs", "recentchanges", "backlinks", "embeddedin", "imagelinks") ), + "meta" => wikiFuzz::chooseInput( array("siteinfo")), + "generator" => wikiFuzz::chooseInput( array("allpages", "logevents", "watchlist", "info", "revisions") ), + "siprop" => wikiFuzz::chooseInput( array("general", "namespaces", "general|namespaces") ), + ); + + // Add extra parameters based on what list choice we got. + switch ($params["list"]) { + case "usercontribs" : self::addListParams ($params, "uc", array("limit", "start", "end", "user", "dir") ); break; + case "allpages" : self::addListParams ($params, "ap", array("from", "prefix", "namespace", "filterredir", "limit") ); break; + case "watchlist" : self::addListParams ($params, "wl", array("allrev", "start", "end", "namespace", "dir", "limit", "prop") ); break; + case "logevents" : self::addListParams ($params, "le", array("limit", "type", "start", "end", "user", "dir") ); break; + case "recentchanges": self::addListParams ($params, "rc", array("limit", "prop", "show", "namespace", "start", "end", "dir") ); break; + case "backlinks" : self::addListParams ($params, "bl", array("continue", "namespace", "redirect", "limit") ); break; + case "embeddedin" : self::addListParams ($params, "ei", array("continue", "namespace", "redirect", "limit") ); break; + case "imagelinks" : self::addListParams ($params, "il", array("continue", "namespace", "redirect", "limit") ); break; + } + + if ($params["prop"] == "revisions") { + self::addListParams ($params, "rv", array("prop", "limit", "startid", "endid", "end", "dir") ); + } + + // Sometimes we want redirects, sometimes we don't. + if (wikiFuzz::randnum(3) == 0) { + $params["redirects"] = wikiFuzz::chooseInput( array("1", 0, "", wikiFuzz::makeFuzz(2)) ); + } + + return $params; + } + + // Adds all the elements to the array, using the specified prefix. + private static function addListParams(&$array, $prefix, $elements) { + foreach ($elements as $element) { + $array[$prefix . $element] = self::getParamDetails($element); + } + } + + // For a given element name, returns the data for that element. + private static function getParamDetails($element) { + switch ($element) { + case 'startid' : + case 'endid' : + case 'start' : + case 'end' : + case 'limit' : return wikiFuzz::chooseInput( array("0", "-1", "---'----------0", "+1", "8134", "320742734234235", "20060230121212", wikiFuzz::randnum(9000, -100), wikiFuzz::makeFuzz(2)) ); + case 'dir' : return wikiFuzz::chooseInput( array("newer", "older", wikifuzz::makeFuzz(2) ) ); + case 'user' : return wikiFuzz::chooseInput( array(USER_ON_WIKI, wikifuzz::makeFuzz(2) ) ); + case 'namespace' : return wikiFuzz::chooseInput( array(-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 200000, wikifuzz::makeFuzz(2)) ); + case 'filterredir': return wikiFuzz::chooseInput( array("all", "redirects", "nonredirectsallpages", wikifuzz::makeFuzz(2)) ); + case 'allrev' : return wikiFuzz::chooseInput( array("1", 0, "", wikiFuzz::makeFuzz(2)) ); + case 'prop' : return wikiFuzz::chooseInput( array("user", "comment", "timestamp", "patrol", "flags", "user|user|comment|flags", wikifuzz::makeFuzz(2) ) ); + case 'type' : return wikiFuzz::chooseInput( array("block", "protect", "rights", "delete", "upload", "move", "import", "renameuser", "newusers", "makebot", wikifuzz::makeFuzz(2) ) ); + case 'hide' : return wikiFuzz::chooseInput( array("minor", "bots", "anons", "liu", "liu|bots|", wikifuzz::makeFuzz(2) ) ); + case 'show' : return wikiFuzz::chooseInput( array('minor', '!minor', 'bot', '!bot', 'anon', '!anon', wikifuzz::makeFuzz(2) ) ); + default : return wikifuzz::makeFuzz(2); + } + } + + // Entry point. + function __construct() { + $this->pagePath = "api.php"; + + $modes = array ("help", + "login", + "opensearch", + "feedwatchlist", + "query"); + $action = wikiFuzz::chooseInput( array_merge ($modes, array(wikifuzz::makeFuzz(2))) ); + + switch ($action) { + case "login" : $this->params = self::loginMode(); + break; + case "opensearch" : $this->params = self::opensearchMode(); + break; + case "feedwatchlist" : $this->params = self::feedwatchlistMode(); + break; + case "query" : $this->params = self::queryMode(); + break; + case "help" : + default : // Do something random - "Crazy Ivan" mode. + $random_mode = wikiFuzz::chooseInput( $modes ) . "Mode"; + // There is no "helpMode". + if ($random_mode == "helpMode") $random_mode = "queryMode"; + $this->params = self::$random_mode(); + break; + } + + // Save the selected action. + $this->params["action"] = $action; + + // Set the cookie: + // FIXME: need to get this cookie dynamically set, rather than hard-coded. + $this->cookie = "wikidbUserID=10001; wikidbUserName=Test; wikidb_session=178df0fe68c75834643af65dec9ec98a; wikidbToken=1adc6753d62c44aec950c024d7ae0540"; + + // Output format + $this->params["format"] = wikiFuzz::chooseInput( array("json", "jsonfm", "php", "phpfm", + "wddx", "wddxfm", "xml", "xmlfm", + "yaml", "yamlfm", "raw", "rawfm", + wikifuzz::makeFuzz(2) ) ); + + // Page does not produce HTML (sometimes). + $this->tidyValidate = false; + } +} + + +/** + ** a page test for the GeSHi extension. + */ +class GeSHi_Test extends pageTest { + + private function getGeSHiContent() { + return "<source lang=\"" . $this->getLang() . "\" " + . (wikiFuzz::randnum(2) == 0 ? "line " : "") + . (wikiFuzz::randnum(2) == 0 ? "strict " : "") + . "start=" . wikiFuzz::chooseInput( array(wikiFuzz::randnum(-6000,6000), wikifuzz::makeFuzz(2)) ) + . ">" + . wikiFuzz::makeFuzz(2) + . "</source>"; + } + + private function getLang() { + return wikiFuzz::chooseInput( array( "actionscript", "ada", "apache", "applescript", "asm", "asp", "autoit", "bash", "blitzbasic", "bnf", "c", "c_mac", "caddcl", "cadlisp", "cfdg", "cfm", "cpp", "cpp-qt", + "csharp", "css", "d", "delphi", "diff", "div", "dos", "eiffel", "fortran", "freebasic", "gml", "groovy", "html4strict", "idl", "ini", "inno", "io", "java", "java5", + "javascript", "latex", "lisp", "lua", "matlab", "mirc", "mpasm", "mysql", "nsis", "objc", "ocaml", "ocaml-brief", "oobas", "oracle8", "pascal", "perl", "php", + "php-brief", "plsql", "python", "qbasic", "rails", "reg", "robots", "ruby", "sas", "scheme", "sdlbasic", "smalltalk", "smarty", "sql", "tcl", "text", "thinbasic", + "tsql", "vb", "vbnet", "vhdl", "visualfoxpro", "winbatch", "xml", "xpp", "z80", wikifuzz::makeFuzz(1) ) ); + } + + function __construct() { + $this->pagePath = "index.php?title=WIKIFUZZ"; + + $this->params = array ( + "action" => "submit", + "wpMinoredit" => "test", + "wpPreview" => "test", + "wpSection" => "test", + "wpEdittime" => "test", + "wpSummary" => "test", + "wpScrolltop" => "test", + "wpStarttime" => "test", + "wpAutoSummary" => "test", + "wpTextbox1" => $this->getGeSHiContent() // the main wiki text, contains fake GeSHi content. + ); + } +} + /** ** selects a page test to run. @@ -1979,6 +2261,8 @@ function selectPageTest($count) { case 42: return new specialRenameuser(); case 43: return new specialLinksearch(); case 44: return new specialCategoryTree(); + case 45: return new api(); + case 45: return new specialChemicalsourcesTest(); default: return new editPageTest(); } } @@ -2001,7 +2285,7 @@ function saveFile($data, $name) { */ function getAsURL(pageTest $test) { $used_question_mark = (strpos($test->getPagePath(), "?") !== false); - $retval = "http://get-to-post.nickj.org/?http://" . WIKI_BASE_URL . $test->getPagePath(); + $retval = "http://get-to-post.nickj.org/?" . WIKI_BASE_URL . $test->getPagePath(); foreach ($test->getParams() as $param => $value) { if (!$used_question_mark) { $retval .= "?"; @@ -2253,10 +2537,12 @@ function runWikiTest(pageTest $test, &$testname, $can_overwrite = false) { saveFile($wiki_preview, $html_file); // if there were PHP errors in the output, then that's interesting too. - if ( strpos($wiki_preview, "<b>Warning</b>: " ) !== false - || strpos($wiki_preview, "<b>Fatal error</b>: ") !== false - || strpos($wiki_preview, "<b>Notice</b>: " ) !== false - || strpos($wiki_preview, "<b>Error</b>: " ) !== false ) { + if ( strpos($wiki_preview, "<b>Warning</b>: " ) !== false + || strpos($wiki_preview, "<b>Fatal error</b>: " ) !== false + || strpos($wiki_preview, "<b>Notice</b>: " ) !== false + || strpos($wiki_preview, "<b>Error</b>: " ) !== false + || strpos($wiki_preview, "<b>Strict Standards:</b>") !== false + ) { $error = substr($wiki_preview, strpos($wiki_preview, "</b>:") + 7, 50); // Avoid probable PHP bug with bad session ids; http://bugs.php.net/bug.php?id=38224 if ($error != "Unknown: The session id contains illegal character") { @@ -2266,32 +2552,32 @@ function runWikiTest(pageTest $test, &$testname, $can_overwrite = false) { } // if there was a MediaWiki Backtrace message in the output, then that's also interesting. - if (strpos($wiki_preview, "Backtrace:") !== false) { + if( strpos($wiki_preview, "Backtrace:") !== false ) { print "\nInternal MediaWiki error in HTML output: $html_file"; return false; } // if there was a Parser error comment in the output, then that's potentially interesting. - if (strpos($wiki_preview, "!-- ERR") !== false) { + if( strpos($wiki_preview, "!-- ERR") !== false ) { print "\nParser Error comment in HTML output: $html_file"; return false; } // if a database error was logged, then that's definitely interesting. - if (dbErrorLogged()) { + if( dbErrorLogged() ) { print "\nDatabase Error logged for: $filename"; return false; } // validate result $valid = true; - if (VALIDATE_ON_WEB) { + if( VALIDATE_ON_WEB ) { list ($valid, $validator_output) = validateHTML($wiki_preview); if (!$valid) print "\nW3C web validation failed - view details with: html2text " . DIRECTORY . "/" . $testname . ".validator_output.html"; } - // Get tidy to check the page, unless it is a test which produces XML. - if (!$test instanceof trackbackTest && !$test instanceof specialExportTest) { + // Get tidy to check the page, unless we already know it produces non-XHTML output. + if( $test->tidyValidate() ) { $valid = tidyCheckFile( $testname . HTML_FILE ) && $valid; } @@ -2397,14 +2683,13 @@ else if (RERUN_OLD_TESTS) { rerunPreviousTests(); } -// seed the random number generator -mt_srand(crc32(microtime())); - // main loop. $start_time = date("U"); $num_errors = 0; -if (!QUIET) print "Beginning main loop. Results are stored in the " . DIRECTORY . " directory.\n"; -if (!QUIET) print "Press CTRL+C to stop testing.\n"; +if (!QUIET) { + print "Beginning main loop. Results are stored in the " . DIRECTORY . " directory.\n"; + print "Press CTRL+C to stop testing.\n"; +} for ($count=0; true; $count++) { if (!QUIET) { @@ -2434,7 +2719,7 @@ for ($count=0; true; $count++) { $valid = runWikiTest($test, $testname, false); // save the failed test - if (!$valid) { + if ( ! $valid ) { if (QUIET) { print "\nTest: " . get_class($test) . " ; Testname: $testname\n------"; } else { @@ -2442,6 +2727,10 @@ for ($count=0; true; $count++) { } saveTest($test, $testname); $num_errors += 1; + } else if ( KEEP_PASSED_TESTS ) { + // print current time, with microseconds (matches "strace" format), and the test name. + print " " . date("H:i:s.") . substr(current(explode(" ", microtime())), 2) . " " . $testname; + saveTest($test, $testname); } // stop if we have reached max number of errors. diff --git a/maintenance/generateSitemap.php b/maintenance/generateSitemap.php index b8d6a5d6..7fff0069 100644 --- a/maintenance/generateSitemap.php +++ b/maintenance/generateSitemap.php @@ -4,8 +4,7 @@ define( 'GS_TALK', -1 ); /** * Creates a Google sitemap for the site * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason * @copyright Copyright © 2005, Jens Frank <jeluf@gmx.de> @@ -144,17 +143,16 @@ class GenerateSitemap { * @param string $path The path to append to the domain name * @param bool $compress Whether to compress the sitemap files */ - function GenerateSitemap( $fspath, $path, $compress ) { + function GenerateSitemap( $fspath, $compress ) { global $wgScriptPath; $this->url_limit = 50000; $this->size_limit = pow( 2, 20 ) * 10; $this->fspath = isset( $fspath ) ? $fspath : ''; - $this->path = isset( $path ) ? $path : $wgScriptPath; $this->compress = $compress; $this->stderr = fopen( 'php://stderr', 'wt' ); - $this->dbr =& wfGetDB( DB_SLAVE ); + $this->dbr = wfGetDB( DB_SLAVE ); $this->generateNamespaces(); $this->timestamp = wfTimestamp( TS_ISO_8601, wfTimestampNow() ); $this->findex = fopen( "{$this->fspath}sitemap-index-" . wfWikiID() . ".xml", 'wb' ); @@ -448,23 +446,29 @@ class GenerateSitemap { } if ( in_array( '--help', $argv ) ) { - echo - "Usage: php generateSitemap.php [host] [options]\n" . - "\thost = hostname\n" . - "\toptions:\n" . - "\t\t--help\tshow this message\n" . - "\t\t--fspath\tThe file system path to save to, e.g /tmp/sitemap/\n" . - "\t\t--path\tThe http path to use, e.g. /wiki\n" . - "\t\t--compress=[yes|no]\tcompress the sitemap files, default yes\n"; + echo <<<EOT +Usage: php generateSitemap.php [options] + --help show this message + + --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 + server name detection may fail in command line scripts. + + --compress=[yes|no] compress the sitemap files, default yes + +EOT; die( -1 ); } -if ( isset( $argv[1] ) && strpos( $argv[1], '--' ) !== 0 ) - $_SERVER['SERVER_NAME'] = $argv[1]; +$optionsWithArgs = array( 'fspath', 'server', 'compress' ); +require_once( dirname( __FILE__ ) . '/commandLine.inc' ); -$optionsWithArgs = array( 'fspath', 'path', 'compress' ); -require_once 'commandLine.inc'; +if ( isset( $options['server'] ) ) { + $wgServer = $options['server']; +} -$gs = new GenerateSitemap( @$options['fspath'], @$options['path'], @$options['compress'] !== 'no' ); +$gs = new GenerateSitemap( @$options['fspath'], @$options['compress'] !== 'no' ); $gs->main(); ?> diff --git a/maintenance/getLagTimes.php b/maintenance/getLagTimes.php index f2c06f6a..5c55d52c 100644 --- a/maintenance/getLagTimes.php +++ b/maintenance/getLagTimes.php @@ -15,7 +15,8 @@ if( empty( $wgDBservers ) ) { } else { $ip = gethostbyname( $host ); } - $stars = str_repeat( '*', intval( $lag ) ); + $starLen = min( intval( $lag ), 40 ); + $stars = str_repeat( '*', $starLen ); printf( "%10s %20s %3d %s\n", $ip, $host, $lag, $stars ); } } diff --git a/maintenance/getSlaveServer.php b/maintenance/getSlaveServer.php index ebeddc4c..5e1b0689 100644 --- a/maintenance/getSlaveServer.php +++ b/maintenance/getSlaveServer.php @@ -1,7 +1,15 @@ <?php require_once( dirname(__FILE__).'/commandLine.inc' ); -$i = $wgLoadBalancer->getReaderIndex(); -print $wgDBservers[$i]['host'] . "\n"; + +if( isset( $options['group'] ) ) { + $db = wfGetDB( DB_SLAVE, $options['group'] ); + $host = $db->getProperty( 'mServer' ); +} else { + $i = $wgLoadBalancer->getReaderIndex(); + $host = $wgDBservers[$i]['host']; +} + +print "$host\n"; ?> diff --git a/maintenance/importDump.php b/maintenance/importDump.php index 22709f64..c7d36042 100644 --- a/maintenance/importDump.php +++ b/maintenance/importDump.php @@ -18,8 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ $optionsWithArgs = array( 'report' ); @@ -48,8 +47,8 @@ class BackupReader { $this->progress( "Got bogus revision with null title!" ); return; } - $display = $title->getPrefixedText(); - $timestamp = $rev->getTimestamp(); + #$timestamp = $rev->getTimestamp(); + #$display = $title->getPrefixedText(); #echo "$display $timestamp\n"; $this->revCount++; @@ -70,8 +69,8 @@ class BackupReader { if( $this->reporting ) { $delta = wfTime() - $this->startTime; if( $delta ) { - $rate = $this->pageCount / $delta; - $revrate = $this->revCount / $delta; + $rate = sprintf("%.2f", $this->pageCount / $delta); + $revrate = sprintf("%.2f", $this->revCount / $delta); } else { $rate = '-'; $revrate = '-'; @@ -137,7 +136,7 @@ if( WikiError::isError( $result ) ) { } else { echo "Done!\n"; echo "You might want to run rebuildrecentchanges.php to regenerate\n"; - echo "the recentchanges page."; + echo "the recentchanges page.\n"; } ?> diff --git a/maintenance/importImages.inc.php b/maintenance/importImages.inc.php index bf48c0c7..c8fbc541 100644 --- a/maintenance/importImages.inc.php +++ b/maintenance/importImages.inc.php @@ -3,8 +3,7 @@ /** * Support functions for the importImages script * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -20,7 +19,7 @@ function findFiles( $dir, $exts ) { if( $dhl = opendir( $dir ) ) { while( ( $file = readdir( $dhl ) ) !== false ) { if( is_file( $dir . '/' . $file ) ) { - list( $name, $ext ) = splitFilename( $dir . '/' . $file ); + list( /* $name */, $ext ) = splitFilename( $dir . '/' . $file ); if( array_search( strtolower( $ext ), $exts ) !== false ) $files[] = $dir . '/' . $file; } diff --git a/maintenance/importImages.php b/maintenance/importImages.php index abf0ec09..8302982c 100644 --- a/maintenance/importImages.php +++ b/maintenance/importImages.php @@ -4,8 +4,7 @@ * Maintenance script to import one or more images from the local file system into * the wiki without using the web-based interface * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -25,15 +24,13 @@ if( count( $args ) > 1 ) { # Search the directory given and pull out suitable candidates $files = findFiles( $dir, $exts ); - # Set up a fake user for this operation - if( isset( $options['user'] ) ) { - $wgUser = User::newFromName( $options['user'] ); - } else { - $wgUser = User::newFromName( 'Image import script' ); - } - if ( $wgUser->isAnon() ) { - $wgUser->addToDatabase(); - } + # Initialise the user for this operation + $user = isset( $options['user'] ) + ? User::newFromName( $options['user'] ) + : User::newFromName( 'Maintenance script' ); + if( !$user instanceof User ) + $user = User::newFromName( 'Maintenance script' ); + $wgUser = $user; # Get the upload comment $comment = isset( $options['comment'] ) diff --git a/maintenance/importLogs.inc b/maintenance/importLogs.inc index 154657c8..0dc87eab 100644 --- a/maintenance/importLogs.inc +++ b/maintenance/importLogs.inc @@ -23,8 +23,7 @@ * Not yet complete. * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -36,15 +35,14 @@ require_once( 'LogPage.php' ); /** * Log importer * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ class LogImporter { var $dummy = false; function LogImporter( $type ) { $this->type = $type; - $this->db =& wfGetDB( DB_MASTER ); + $this->db = wfGetDB( DB_MASTER ); $this->actions = $this->setupActions(); } @@ -77,6 +75,7 @@ class LogImporter { } $lines = explode( '<li>', $text ); foreach( $lines as $line ) { + $matches = array(); if( preg_match( '!^(.*)</li>!', $line, $matches ) ) { $this->importLine( $matches[1] ); } @@ -88,6 +87,7 @@ class LogImporter { # 01:55, 23 Aug 2004 - won't take in strtotimr # "Aug 23 2004 01:55" - seems ok # TODO: multilingual attempt to extract from the data in Language + $matches = array(); if( preg_match( '/^(\d+:\d+(?::\d+)?), (.*)$/', $date, $matches ) ) { $date = $matches[2] . ' ' . $matches[1]; } @@ -99,6 +99,7 @@ class LogImporter { function importLine( $line ) { foreach( $this->actions as $action => $regexp ) { + $matches = array(); if( preg_match( $regexp, $line, $matches ) ) { if( $this->dummy ) { #var_dump( $matches ); diff --git a/maintenance/importLogs.php b/maintenance/importLogs.php index 6187c2e6..54cee1dd 100644 --- a/maintenance/importLogs.php +++ b/maintenance/importLogs.php @@ -1,8 +1,7 @@ <?php /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/importPhase2.php b/maintenance/importPhase2.php index a73657b5..a923b3da 100644 --- a/maintenance/importPhase2.php +++ b/maintenance/importPhase2.php @@ -24,8 +24,7 @@ /** * @todo document * @deprecated - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -61,8 +60,7 @@ require_once( "rebuildtextindex.inc" ); /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ class Phase2Importer { var $olddb, $titleCache; @@ -137,7 +135,7 @@ class Phase2Importer { wfQuery( "DELETE FROM user", DB_MASTER ); print "Importing user data...\n"; - wfQuery( "INSERT INTO $newdb.user (user_id,user_name,user_rights, + wfQuery( "INSERT INTO user (user_id,user_name,user_rights, user_password,user_newpassword,user_email,user_options,user_touched) SELECT user_id,user_name,REPLACE(user_rights,'is_',''), MD5(CONCAT(user_id,'-',MD5(user_password))),'',user_email,user_options,NOW()+0 @@ -240,6 +238,7 @@ class Phase2Importer { $a = explode( "\n", $s ); foreach ( $a as $l ) { + $m = array(); if ( preg_match( "/^([A-Za-z0-9_]+)=(.*)/", $l, $m ) ) { $ops[$m[1]] = $m[2]; } @@ -324,17 +323,16 @@ class Phase2Importer { /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ class TitleCache { var $hash = array(); function &fetch( $dbkey ) { - if( !isset( $hash[$dbkey] ) ) { - $hash[$dbkey] = Title::newFromDBkey( $dbkey ); + if( !isset( $this->hash[$dbkey] ) ) { + $this->hash[$dbkey] = Title::newFromDBkey( $dbkey ); } - return $hash[$dbkey]; + return $this->hash[$dbkey]; } } diff --git a/maintenance/importTextFile.php b/maintenance/importTextFile.php index 92c31fd0..60ee228e 100644 --- a/maintenance/importTextFile.php +++ b/maintenance/importTextFile.php @@ -4,17 +4,16 @@ * Maintenance script allows creating or editing pages using * the contents of a text file * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ - -$options = array( 'help', 'nooverwrite' ); + +$options = array( 'help', 'nooverwrite', 'norc' ); $optionsWithArgs = array( 'title', 'user', 'comment' ); require_once( 'commandLine.inc' ); echo( "Import Text File\n\n" ); -if( isset( $options['help'] ) ) { +if( count( $args ) < 1 || isset( $options['help'] ) ) { showHelp(); } else { @@ -31,7 +30,7 @@ if( isset( $options['help'] ) ) { if( !$title->exists() || !isset( $options['nooverwrite'] ) ) { $text = file_get_contents( $filename ); - $user = isset( $options['user'] ) ? $options['user'] : 'MediaWiki default'; + $user = isset( $options['user'] ) ? $options['user'] : 'Maintenance script'; $user = User::newFromName( $user ); echo( "\nUsing username '" . $user->getName() . "'..." ); @@ -39,11 +38,11 @@ if( isset( $options['help'] ) ) { $wgUser =& $user; $comment = isset( $options['comment'] ) ? $options['comment'] : 'Importing text file'; - $comment = str_replace( '_', ' ', $comment ); + $flags = 0 | ( isset( $options['norc'] ) ? EDIT_SUPPRESS_RC : 0 ); echo( "\nPerforming edit..." ); $article = new Article( $title ); - $article->doEdit( $text, $comment ); + $article->doEdit( $text, $comment, $flags ); echo( "done.\n" ); } else { @@ -71,14 +70,17 @@ function titleFromFilename( $filename ) { } function showHelp() { - echo( "Import the contents of a text file into a wiki page.\n\n" ); - echo( "USAGE: php importTextFile.php [--help|--title <title>|--user <user>|--comment <comment>|--nooverwrite] <filename>\n\n" ); - echo( " --help: Show this help information\n" ); - echo( " --title <title> : Title for the new page; if not supplied, the filename is used as a base for the title\n" ); - echo( " --user <user> : User to be associated with the edit; if not supplied, a default is used\n" ); - echo( "--comment <comment> : Edit summary to be associated with the edit; underscores are transformed into spaces; if not supplied, a default is used\n" ); - echo( " --nooverwrite : Don't overwrite existing page content\n" ); - echo( " <filename> : Path to the file containing the wikitext to import\n\n" ); + echo( "Import the contents of a text file into a wiki page.\n" ); + echo( "USAGE: php importTextFile.php <options> <filename>\n\n" ); + echo( "<filename> : Path to the file containing page content to import\n\n" ); + echo( "Options:\n\n" ); + echo( "--title <title>\n\tTitle for the new page; default is to use the filename as a base\n" ); + echo( "--user <user>\n\tUser to be associated with the edit\n" ); + echo( "--comment <comment>\n\tEdit summary\n" ); + echo( "--nooverwrite\n\tDon't overwrite existing content\n" ); + echo( "--norc\n\tDon't update recent changes\n" ); + echo( "--help\n\tShow this information\n" ); + echo( "\n" ); } ?>
\ No newline at end of file diff --git a/maintenance/importUseModWiki.php b/maintenance/importUseModWiki.php index 15f5e444..ae5dd23b 100644 --- a/maintenance/importUseModWiki.php +++ b/maintenance/importUseModWiki.php @@ -22,8 +22,7 @@ * 2005-03-14 * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ if( php_sapi_name() != 'cli' ) { @@ -90,6 +89,7 @@ function importPageDirectory( $dir, $prefix = "" ) echo "\n<!-- Checking page directory " . xmlCommentSafe( $dir ) . " -->\n"; $mydir = opendir( $dir ); while( $entry = readdir( $mydir ) ) { + $m = array(); if( preg_match( '/^(.+)\.db$/', $entry, $m ) ) { echo importPage( $prefix . $m[1] ); } else { @@ -121,7 +121,7 @@ function useModFilename( $title ) { function fetchPage( $title ) { - global $FS,$FS1,$FS2,$FS3, $wgRootDirectory; + global $FS1,$FS2,$FS3, $wgRootDirectory; $fname = $wgRootDirectory . "/page/" . useModFilename( $title ) . ".db"; if( !file_exists( $fname ) ) { @@ -140,7 +140,7 @@ function fetchPage( $title ) function fetchKeptPages( $title ) { - global $FS,$FS1,$FS2,$FS3, $wgRootDirectory, $wgTimezoneCorrection; + global $FS1,$FS2,$FS3, $wgRootDirectory; $fname = $wgRootDirectory . "/keep/" . useModFilename( $title ) . ".kp"; if( !file_exists( $fname ) ) return array(); @@ -235,13 +235,13 @@ END; # History $revisions = array_merge( $revisions, fetchKeptPages( $title ) ); if(count( $revisions ) == 0 ) { - return $sql; + return NULL; // Was "$sql", which does not appear to be defined. } foreach( $revisions as $rev ) { $text = xmlsafe( recodeText( $rev->text ) ); $minor = ($rev->minor ? '<minor/>' : ''); - list( $userid, $username ) = checkUserCache( $rev->username, $rev->host ); + list( /* $userid */ , $username ) = checkUserCache( $rev->username, $rev->host ); $username = xmlsafe( recodeText( $username ) ); $timestamp = xmlsafe( timestamp2ISO8601( $rev->ts ) ); $comment = xmlsafe( recodeText( $rev->summary ) ); diff --git a/maintenance/initStats.inc b/maintenance/initStats.inc new file mode 100644 index 00000000..673742e3 --- /dev/null +++ b/maintenance/initStats.inc @@ -0,0 +1,55 @@ +<?php + +function wfInitStats( $options=array() ) { + $dbr = wfGetDB( DB_SLAVE ); + + echo "Counting total edits..."; + $edits = $dbr->selectField( 'revision', 'COUNT(*)', '', __METHOD__ ); + $edits += $dbr->selectField( 'archive', 'COUNT(*)', '', __METHOD__ ); + echo "{$edits}\nCounting number of articles..."; + + global $wgContentNamespaces; + $good = $dbr->selectField( 'page', 'COUNT(*)', array( 'page_namespace' => $wgContentNamespaces, 'page_is_redirect' => 0, 'page_len > 0' ), __METHOD__ ); + echo "{$good}\nCounting total pages..."; + + $pages = $dbr->selectField( 'page', 'COUNT(*)', '', __METHOD__ ); + echo "{$pages}\nCounting number of users..."; + + $users = $dbr->selectField( 'user', 'COUNT(*)', '', __METHOD__ ); + echo "{$users}\nCounting number of admins..."; + + $admin = $dbr->selectField( 'user_groups', 'COUNT(*)', array( 'ug_group' => 'sysop' ), __METHOD__ ); + echo "{$admin}\nCounting number of images..."; + + $image = $dbr->selectField( 'image', 'COUNT(*)', '', __METHOD__ ); + echo "{$image}\n"; + + if( !isset( $options['noviews'] ) ) { + echo "Counting total page views..."; + $views = $dbr->selectField( 'page', 'SUM(page_counter)', '', __METHOD__ ); + echo "{$views}\n"; + } + + echo "\nUpdating site statistics..."; + + $dbw = wfGetDB( DB_MASTER ); + $values = array( 'ss_total_edits' => $edits, + 'ss_good_articles' => $good, + 'ss_total_pages' => $pages, + 'ss_users' => $users, + 'ss_admins' => $admin, + 'ss_images' => $image ); + $conds = array( 'ss_row_id' => 1 ); + $views = array( 'ss_total_views' => isset( $views ) ? $views : 0 ); + + if( isset( $options['update'] ) ) { + $dbw->update( 'site_stats', $values, $conds, __METHOD__ ); + } else { + $dbw->delete( 'site_stats', $conds, __METHOD__ ); + $dbw->insert( 'site_stats', array_merge( $values, $conds, $views ), __METHOD__ ); + } + + echo( "done.\n" ); +} + +?>
\ No newline at end of file diff --git a/maintenance/initStats.php b/maintenance/initStats.php index 291de1ee..850d816c 100644 --- a/maintenance/initStats.php +++ b/maintenance/initStats.php @@ -3,8 +3,7 @@ /** * Maintenance script to re-initialise or update the site statistics table * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Brion Vibber * @author Rob Church <robchur@gmail.com> * @licence GNU General Public Licence 2.0 or later @@ -13,66 +12,19 @@ $options = array( 'help', 'update', 'noviews' ); require_once( 'commandLine.inc' ); echo( "Refresh Site Statistics\n\n" ); -$dbr =& wfGetDB( DB_SLAVE ); -$fname = 'initStats'; if( isset( $options['help'] ) ) { showHelp(); exit(); } -echo( "Counting total edits..." ); -$edits = $dbr->selectField( 'revision', 'COUNT(*)', '', $fname ); -$edits += $dbr->selectField( 'archive', 'COUNT(*)', '', $fname ); -echo( "{$edits}\nCounting number of articles..." ); - -global $wgContentNamespaces; -$good = $dbr->selectField( 'page', 'COUNT(*)', array( 'page_namespace' => $wgContentNamespaces, 'page_is_redirect' => 0, 'page_len > 0' ), $fname ); -echo( "{$good}\nCounting total pages..." ); - -$pages = $dbr->selectField( 'page', 'COUNT(*)', '', $fname ); -echo( "{$pages}\nCounting number of users..." ); - -$users = $dbr->selectField( 'user', 'COUNT(*)', '', $fname ); -echo( "{$users}\nCounting number of admins..." ); - -$admin = $dbr->selectField( 'user_groups', 'COUNT(*)', array( 'ug_group' => 'sysop' ), $fname ); -echo( "{$admin}\nCounting number of images..." ); - -$image = $dbr->selectField( 'image', 'COUNT(*)', '', $fname ); -echo( "{$image}\n" ); - -if( !isset( $options['noviews'] ) ) { - echo( "Counting total page views..." ); - $views = $dbr->selectField( 'page', 'SUM(page_counter)', '', $fname ); - echo( "{$views}\n" ); -} - -echo( "\nUpdating site statistics..." ); - -$dbw =& wfGetDB( DB_MASTER ); -$values = array( 'ss_total_edits' => $edits, - 'ss_good_articles' => $good, - 'ss_total_pages' => $pages, - 'ss_users' => $users, - 'ss_admins' => $admin, - 'ss_images' => $image ); -$conds = array( 'ss_row_id' => 1 ); -$views = array( 'ss_total_views' => isset( $views ) ? $views : 0 ); - -if( isset( $options['update'] ) ) { - $dbw->update( 'site_stats', $values, $conds, $fname ); -} else { - $dbw->delete( 'site_stats', $conds, $fname ); - $dbw->insert( 'site_stats', array_merge( $values, $conds, $views ), $fname ); -} - -echo( "done.\n\n" ); +require "$IP/maintenance/initStats.inc"; +wfInitStats( $options ); function showHelp() { echo( "Re-initialise the site statistics tables.\n\n" ); echo( "Usage: php initStats.php [--update|--noviews]\n\n" ); - echo( " --update : Update the existing statistics (preserves the ss_total_views field)\n" ); + echo( " --update : Update the existing statistics (preserves the ss_total_views field)\n" ); echo( "--noviews : Don't update the page view counter\n\n" ); } diff --git a/maintenance/installExtension.php b/maintenance/installExtension.php index f6b2dff4..063002f5 100644 --- a/maintenance/installExtension.php +++ b/maintenance/installExtension.php @@ -17,8 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ $optionsWithArgs = array( 'target', 'repository', 'repos' ); @@ -46,18 +45,22 @@ class InstallerRepository { /*static*/ function makeRepository( $path, $type = NULL ) { if ( !$type ) { + $m = array(); preg_match( '!(([-+\w]+)://)?.*?(\.[-\w\d.]+)?$!', $path, $m ); $proto = @$m[2]; - if( !$proto ) $type = 'dir'; - else if ( ( $proto == 'http' || $proto == 'https' ) - && preg_match( '!([^\w]svn|svn[^\w])!i', $path) ) $type = 'svn'; #HACK! - else $type = $proto; + if ( !$proto ) { + $type = 'dir'; + } else if ( ( $proto == 'http' || $proto == 'https' ) && preg_match( '!([^\w]svn|svn[^\w])!i', $path) ) { + $type = 'svn'; #HACK! + } else { + $type = $proto; + } } - if ( $type == 'dir' || $type == 'file' ) return new LocalInstallerRepository( $path ); - else if ( $type == 'http' || $type == 'http' ) return new WebInstallerRepository( $path ); - else return new SVNInstallerRepository( $path ); + if ( $type == 'dir' || $type == 'file' ) { return new LocalInstallerRepository( $path ); } + else if ( $type == 'http' || $type == 'http' ) { return new WebInstallerRepository( $path ); } + else { return new SVNInstallerRepository( $path ); } } } @@ -70,7 +73,7 @@ class LocalInstallerRepository extends InstallerRepository { function printListing( ) { $ff = glob( "{$this->path}/*" ); if ( $ff === false || $ff === NULL ) { - ExtensionInstaller::error( "listing directory $repos failed!" ); + ExtensionInstaller::error( "listing directory {$this->path} failed!" ); return false; } @@ -78,6 +81,7 @@ class LocalInstallerRepository extends InstallerRepository { $n = basename($f); if ( !is_dir( $f ) ) { + $m = array(); if ( !preg_match( '/(.*)\.(tgz|tar\.gz|zip)/', $n, $m ) ) continue; $n = $m[1]; } @@ -118,7 +122,8 @@ class WebInstallerRepository extends InstallerRepository { print ( $txt ); return false; } - + + $m = array(); $ok = preg_match_all( '!<a\s[^>]*href\s*=\s*['."'".'"]([^/'."'".'"]+)\.tgz['."'".'"][^>]*>.*?</a>!si', $txt, $m, PREG_SET_ORDER ); if ( !$ok ) { ExtensionInstaller::error( "listing index from {$this->path} does not match!" ); @@ -147,6 +152,7 @@ class SVNInstallerRepository extends InstallerRepository { function printListing( ) { ExtensionInstaller::note( "SVN list {$this->path}..." ); + $code = null; // Shell Exec return value. $txt = wfShellExec( 'svn ls ' . escapeshellarg( $this->path ), $code ); if ( $code !== 0 ) { ExtensionInstaller::error( "svn list for {$this->path} failed!" ); @@ -156,6 +162,7 @@ class SVNInstallerRepository extends InstallerRepository { $ll = preg_split('/(\s*[\r\n]\s*)+/', $txt); foreach ( $ll as $line ) { + $m = array(); if ( !preg_match('!^(.*)/$!', $line, $m) ) continue; $n = $m[1]; @@ -180,6 +187,7 @@ class InstallerResource { $this->isdir= $isdir; $this->islocal = $islocal; + $m = array(); preg_match( '!([-+\w]+://)?.*?(\.[-\w\d.]+)?$!', $path, $m ); $this->protocol = @$m[1]; @@ -196,6 +204,7 @@ class InstallerResource { if ( $this->extensions == '.tgz' || $this->extensions == '.tar.gz' ) { #tgz file ExtensionInstaller::note( "extracting $file..." ); + $code = null; // shell Exec return value. wfShellExec( 'tar zxvf ' . escapeshellarg( $file ) . ' -C ' . escapeshellarg( $target ), $code ); if ( $code !== 0 ) { @@ -205,6 +214,7 @@ class InstallerResource { } else if ( $this->extensions == '.zip' ) { #zip file ExtensionInstaller::note( "extracting $file..." ); + $code = null; // shell Exec return value. wfShellExec( 'unzip ' . escapeshellarg( $file ) . ' -d ' . escapeshellarg( $target ) , $code ); if ( $code !== 0 ) { @@ -221,14 +231,15 @@ class InstallerResource { } /*static*/ function makeResource( $url ) { + $m = array(); preg_match( '!(([-+\w]+)://)?.*?(\.[-\w\d.]+)?$!', $url, $m ); $proto = @$m[2]; $ext = @$m[3]; if ( $ext ) $ext = strtolower( $ext ); - if ( !$proto ) return new LocalInstallerResource( $url, $ext ? false : true ); - else if ( $ext && ( $proto == 'http' || $proto == 'http' || $proto == 'ftp' ) ) return new WebInstallerResource( $url ); - else return new SVNInstallerResource( $url ); + if ( !$proto ) { return new LocalInstallerResource( $url, $ext ? false : true ); } + else if ( $ext && ( $proto == 'http' || $proto == 'http' || $proto == 'ftp' ) ) { return new WebInstallerResource( $url ); } + else { return new SVNInstallerResource( $url ); } } } @@ -274,6 +285,7 @@ class SVNInstallerResource extends InstallerResource { function fetch( $target ) { ExtensionInstaller::note( "SVN checkout of {$this->path}..." ); + $code = null; // shell exec return val. wfShellExec( 'svn co ' . escapeshellarg( $this->path ) . ' ' . escapeshellarg( $target ), $code ); if ( $code !== 0 ) { @@ -342,9 +354,9 @@ class ExtensionInstaller { $s = $this->prompt( $msg . " [yes/no]: "); $s = strtolower( trim($s) ); - if ( $s == 'yes' || $s == 'y' ) return true; - else if ( $s == 'no' || $s == 'n' ) return false; - else print "bad response: $s\n"; + if ( $s == 'yes' || $s == 'y' ) { return true; } + else if ( $s == 'no' || $s == 'n' ) { return false; } + else { print "bad response: $s\n"; } } } @@ -566,6 +578,7 @@ if ( !$repos ) $repos = @$wgExtensionInstallerRepository; if ( !$repos && file_exists("$tgt/.svn") && is_dir("$tgt/.svn") ) { $svn = file_get_contents( "$tgt/.svn/entries" ); + $m = array(); if ( preg_match( '!url="(.*?)"!', $svn, $m ) ) { $repos = dirname( $m[1] ) . '/extensions'; } @@ -602,8 +615,8 @@ $src = isset( $args[1] ) ? $args[1] : $repository->getResource( $name ); #TODO: detect $source mismatching $name !! $mode = EXTINST_WRITEPATCH; -if ( isset( $options['nopatch'] ) || @$wgExtensionInstallerNoPatch ) $mode = EXTINST_NOPATCH; -else if ( isset( $options['hotpatch'] ) || @$wgExtensionInstallerHotPatch ) $mode = EXTINST_HOTPATCH; +if ( isset( $options['nopatch'] ) || @$wgExtensionInstallerNoPatch ) { $mode = EXTINST_NOPATCH; } +else if ( isset( $options['hotpatch'] ) || @$wgExtensionInstallerHotPatch ) { $mode = EXTINST_HOTPATCH; } if ( !file_exists( "$tgt/LocalSettings.php" ) ) { die("can't find $tgt/LocalSettings.php\n"); diff --git a/maintenance/interwiki.sql b/maintenance/interwiki.sql index b0df5557..0eae287a 100644 --- a/maintenance/interwiki.sql +++ b/maintenance/interwiki.sql @@ -91,6 +91,7 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('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), @@ -171,6 +172,7 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('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), diff --git a/maintenance/language/alltrans.php b/maintenance/language/alltrans.php index f8db9c0d..69b9a4ea 100644 --- a/maintenance/language/alltrans.php +++ b/maintenance/language/alltrans.php @@ -1,7 +1,6 @@ <?php /** - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * * Get all the translations messages, as defined in the English language file. */ diff --git a/maintenance/language/checkExtensioni18n.php b/maintenance/language/checkExtensioni18n.php new file mode 100644 index 00000000..7a131a08 --- /dev/null +++ b/maintenance/language/checkExtensioni18n.php @@ -0,0 +1,279 @@ +<?php +/** + * Copyright (C) 2007 Ashar Voultoiz <hashar@altern.org> + * + * 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 SpecialPage + */ + +# +# Lacking documentation. Examples: +# php checkExtensioni18n.php /opt/mw/extensions/CentralAuth/CentralAuth.i18n.php wgCentralAuthMessages +# php checkExtensioni18n.php --extdir /opt/mw/extensions/ +# +# BUGS: cant guess registered extensions :) +# TODO: let users set parameters to configure checklanguage.inc (it uses globals) + +// Filename for the extension i18n files database: +define( 'EXT_I18N_DB', 'i18n.db' ); + +// Global parameters for checkLanguage.inc +$wgDisplayLevel = 2; +$wgChecks = array( 'untranslated', 'obsolete', 'variables', 'empty', 'whitespace', 'xhtml', 'chars' ); + +$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 ) { + global $wgGeneralMessages, $wgRequiredMessagesNumber; + + $extLanguages = new extensionLanguages($filename, $arrayname); + + // Stuff needed by the checkLanguage routine (globals) + $wgGeneralMessages = $extLanguages->getGeneralMessages(); + $wgRequiredMessagesNumber = count( $wgGeneralMessages['required'] ); + + $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 checkExtensioni18n.php <filename> <arrayname> + php checkExtensioni18n.php --extdir <extension repository> + +Common option: + --lang <language code> : only check the given language. + + +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(); + } +} + +?> diff --git a/maintenance/language/checkLanguage.inc b/maintenance/language/checkLanguage.inc new file mode 100644 index 00000000..e859e39c --- /dev/null +++ b/maintenance/language/checkLanguage.inc @@ -0,0 +1,92 @@ +<?php +/** + * Check a language. + * + * @todo Stop with globals. + * @param $code The language code. + * @return Number of errors found. + */ +function checkLanguage( $wgLanguages, $code ) { + global $wgRequiredMessagesNumber, $wgDisplayLevel, $wgLinks, $wgWikiLanguage, $wgChecks; + + # Get messages + $messages = $wgLanguages->getMessages( $code ); + $messagesNumber = count( $messages['translated'] ); + + # Skip the checks if specified + if ( $wgDisplayLevel == 0 ) { + return; + } + + // Initialize counts + $untranslatedMessagesNumber = $duplicateMessagesNumber = $obsoleteMessagesNumber + = $messagesWithoutVariablesNumber = $messagesWithoutPluralNumber = $emptyMessagesNumber + = $messagesWithWhitespaceNumber = $nonXHTMLMessagesNumber = $messagesWithWrongCharsNumber + = 0; + + # Untranslated messages + if ( in_array( 'untranslated', $wgChecks ) ) { + $untranslatedMessages = $wgLanguages->getUntranslatedMessages( $code ); + $untranslatedMessagesNumber = count( $untranslatedMessages ); + $wgLanguages->outputMessagesList( $untranslatedMessages, $code, "\n$untranslatedMessagesNumber messages of $wgRequiredMessagesNumber are not translated to $code, but exist in en:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); + } + + # Duplicate messages + if ( in_array( 'duplicate', $wgChecks ) ) { + $duplicateMessages = $wgLanguages->getDuplicateMessages( $code ); + $duplicateMessagesNumber = count( $duplicateMessages ); + $wgLanguages->outputMessagesList( $duplicateMessages, $code, "\n$duplicateMessagesNumber messages of $messagesNumber are translated the same in en and $code:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); + } + + # Obsolete messages + if ( in_array( 'obsolete', $wgChecks ) ) { + $obsoleteMessages = $messages['obsolete']; + $obsoleteMessagesNumber = count( $obsoleteMessages ); + $wgLanguages->outputMessagesList( $obsoleteMessages, $code, "\n$obsoleteMessagesNumber messages of $messagesNumber are not exist in en (or are in the ignored list), but still exist in $code:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); + } + + # Messages without variables + if ( in_array( 'variables', $wgChecks ) ) { + $messagesWithoutVariables = $wgLanguages->getMessagesWithoutVariables( $code ); + $messagesWithoutVariablesNumber = count( $messagesWithoutVariables ); + $wgLanguages->outputMessagesList( $messagesWithoutVariables, $code, "\n$messagesWithoutVariablesNumber messages of $messagesNumber in $code don't use some variables while en uses them:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); + } + + # Messages without plural + if ( in_array( 'plural', $wgChecks ) ) { + $messagesWithoutPlural = $wgLanguages->getMessagesWithoutPlural( $code ); + $messagesWithoutPluralNumber = count( $messagesWithoutPlural ); + $wgLanguages->outputMessagesList( $messagesWithoutPlural, $code, "\n$messagesWithoutPluralNumber messages of $messagesNumber in $code don't use {{plural}} while en uses it:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); + } + + # Empty messages + if ( in_array( 'empty', $wgChecks ) ) { + $emptyMessages = $wgLanguages->getEmptyMessages( $code ); + $emptyMessagesNumber = count( $emptyMessages ); + $wgLanguages->outputMessagesList( $emptyMessages, $code, "\n$emptyMessagesNumber messages of $messagesNumber in $code are empty or -:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); + } + + # Messages with whitespace + if ( in_array( 'whitespace', $wgChecks ) ) { + $messagesWithWhitespace = $wgLanguages->getMessagesWithWhitespace( $code ); + $messagesWithWhitespaceNumber = count( $messagesWithWhitespace ); + $wgLanguages->outputMessagesList( $messagesWithWhitespace, $code, "\n$messagesWithWhitespaceNumber messages of $messagesNumber in $code have a trailing whitespace:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); + } + + # Non-XHTML messages + if ( in_array( 'xhtml', $wgChecks ) ) { + $nonXHTMLMessages = $wgLanguages->getNonXHTMLMessages( $code ); + $nonXHTMLMessagesNumber = count( $nonXHTMLMessages ); + $wgLanguages->outputMessagesList( $nonXHTMLMessages, $code, "\n$nonXHTMLMessagesNumber messages of $messagesNumber in $code are not well-formed XHTML:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); + } + + # Messages with wrong characters + if ( in_array( 'chars', $wgChecks ) ) { + $messagesWithWrongChars = $wgLanguages->getMessagesWithWrongChars( $code ); + $messagesWithWrongCharsNumber = count( $messagesWithWrongChars ); + $wgLanguages->outputMessagesList( $messagesWithWrongChars, $code, "\n$messagesWithWrongCharsNumber messages of $messagesNumber in $code include hidden chars which should not be used in the messages:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); + } + + return ($untranslatedMessagesNumber + $duplicateMessagesNumber + $obsoleteMessagesNumber + $messagesWithoutVariablesNumber + $messagesWithoutPluralNumber + $emptyMessagesNumber + $messagesWithWhitespaceNumber + $nonXHTMLMessagesNumber + $messagesWithWrongCharsNumber); +} +?> diff --git a/maintenance/language/checkLanguage.php b/maintenance/language/checkLanguage.php index 11c8ec92..4ce811c5 100644 --- a/maintenance/language/checkLanguage.php +++ b/maintenance/language/checkLanguage.php @@ -2,86 +2,12 @@ /** * Check a language file. * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ require_once( dirname(__FILE__).'/../commandLine.inc' ); require_once( 'languages.inc' ); - -/** - * Check a language. - * - * @param $code The language code. - */ -function checkLanguage( $code ) { - global $wgLanguages, $wgGeneralMessages, $wgRequiredMessagesNumber, $wgDisplayLevel, $wgLinks, $wgWikiLanguage, $wgChecks; - - # Get messages - $messages = $wgLanguages->getMessages( $code ); - $messagesNumber = count( $messages['translated'] ); - - # Skip the checks if specified - if ( $wgDisplayLevel == 0 ) { - return; - } - - # Untranslated messages - if ( in_array( 'untranslated', $wgChecks ) ) { - $untranslatedMessages = $wgLanguages->getUntranslatedMessages( $code ); - $untranslatedMessagesNumber = count( $untranslatedMessages ); - $wgLanguages->outputMessagesList( $untranslatedMessages, $code, "\n$untranslatedMessagesNumber messages of $wgRequiredMessagesNumber are not translated to $code, but exist in en:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); - } - - # Duplicate messages - if ( in_array( 'duplicate', $wgChecks ) ) { - $duplicateMessages = $wgLanguages->getDuplicateMessages( $code ); - $duplicateMessagesNumber = count( $duplicateMessages ); - $wgLanguages->outputMessagesList( $duplicateMessages, $code, "\n$duplicateMessagesNumber messages of $messagesNumber are translated the same in en and $code:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); - } - - # Obsolete messages - if ( in_array( 'obsolete', $wgChecks ) ) { - $obsoleteMessages = $messages['obsolete']; - $obsoleteMessagesNumber = count( $obsoleteMessages ); - $wgLanguages->outputMessagesList( $obsoleteMessages, $code, "\n$obsoleteMessagesNumber messages of $messagesNumber are not exist in en (or are in the ignored list), but still exist in $code:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); - } - - # Messages without variables - if ( in_array( 'variables', $wgChecks ) ) { - $messagesWithoutVariables = $wgLanguages->getMessagesWithoutVariables( $code ); - $messagesWithoutVariablesNumber = count( $messagesWithoutVariables ); - $wgLanguages->outputMessagesList( $messagesWithoutVariables, $code, "\n$messagesWithoutVariablesNumber messages of $messagesNumber in $code don't use some variables while en uses them:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); - } - - # Empty messages - if ( in_array( 'empty', $wgChecks ) ) { - $emptyMessages = $wgLanguages->getEmptyMessages( $code ); - $emptyMessagesNumber = count( $emptyMessages ); - $wgLanguages->outputMessagesList( $emptyMessages, $code, "\n$emptyMessagesNumber messages of $messagesNumber in $code are empty or -:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); - } - - # Messages with whitespace - if ( in_array( 'whitespace', $wgChecks ) ) { - $messagesWithWhitespace = $wgLanguages->getMessagesWithWhitespace( $code ); - $messagesWithWhitespaceNumber = count( $messagesWithWhitespace ); - $wgLanguages->outputMessagesList( $messagesWithWhitespace, $code, "\n$messagesWithWhitespaceNumber messages of $messagesNumber in $code have a trailing whitespace:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); - } - - # Non-XHTML messages - if ( in_array( 'xhtml', $wgChecks ) ) { - $nonXHTMLMessages = $wgLanguages->getNonXHTMLMessages( $code ); - $nonXHTMLMessagesNumber = count( $nonXHTMLMessages ); - $wgLanguages->outputMessagesList( $nonXHTMLMessages, $code, "\n$nonXHTMLMessagesNumber messages of $messagesNumber in $code are not well-formed XHTML:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); - } - - # Messages with wrong characters - if ( in_array( 'chars', $wgChecks ) ) { - $messagesWithWrongChars = $wgLanguages->getMessagesWithWrongChars( $code ); - $messagesWithWrongCharsNumber = count( $messagesWithWrongChars ); - $wgLanguages->outputMessagesList( $messagesWithWrongChars, $code, "\n$messagesWithWrongCharsNumber messages of $messagesNumber in $code include hidden chars which should not be used in the messages:", $wgDisplayLevel, $wgLinks, $wgWikiLanguage ); - } -} +require_once( 'checkLanguage.inc' ); # Show help if ( isset( $options['help'] ) ) { @@ -96,6 +22,7 @@ Parameters: * whitelist: Make only the following checks (form: code,code). * blacklist: Don't make the following checks (form: code,code). * duplicate: Additionally check for messages which are translated the same to English (default off). + * plural: Additionally check for messages that don't use plural while English does (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): * untranslated: Messages which are required to translate, but are not translated. @@ -141,10 +68,13 @@ if ( isset( $options['whitelist'] ) ) { $wgChecks = array_diff( $wgChecks, explode( ',', $options['blacklist'] ) ); } -# Add duplicate option if specified +# Add duplicate and plural options if specified if ( isset( $options['duplicate'] ) ) { $wgChecks[] = 'duplicate'; } +if ( isset( $options['plural'] ) ) { + $wgChecks[] = 'plural'; +} # Should check for EXIF? $wgCheckEXIF = !isset( $options['noexif'] ); @@ -160,7 +90,7 @@ $wgRequiredMessagesNumber = count( $wgGeneralMessages['required'] ); if ( $wgCode == 'all' ) { foreach ( $wgLanguages->getLanguages() as $language ) { if ( $language != 'en' && $language != 'enRTL' ) { - checkLanguage( $language ); + checkLanguage( $wgLanguages, $language ); } } } else { @@ -170,7 +100,7 @@ if ( $wgCode == 'all' ) { } else if ( $wgCode == 'enRTL' ) { echo "Current selected language is RTL English, which cannot be checked.\n"; } else { - checkLanguage( $wgCode ); + checkLanguage( $wgLanguages, $wgCode ); } } diff --git a/maintenance/language/date-formats.php b/maintenance/language/date-formats.php index 962c2f8c..a0d46f02 100644 --- a/maintenance/language/date-formats.php +++ b/maintenance/language/date-formats.php @@ -8,6 +8,7 @@ require_once( "$IP/maintenance/commandLine.inc" ); foreach ( glob( "$IP/languages/messages/Messages*.php" ) as $filename ) { $base = basename( $filename ); + $m = array(); if ( !preg_match( '/Messages(.*)\.php$/', $base, $m ) ) { continue; } diff --git a/maintenance/language/diffLanguage.php b/maintenance/language/diffLanguage.php index 2aaa5902..ada4db07 100644 --- a/maintenance/language/diffLanguage.php +++ b/maintenance/language/diffLanguage.php @@ -35,8 +35,7 @@ * percentage of messages correctly localised and the number of messages to be * translated. * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** This script run from the commandline */ @@ -75,7 +74,8 @@ function ucfirstlcrest($string) { function getMediawikiMessages($languageCode = 'En') { $foo = "wgAllMessages$languageCode"; - global $$foo, $wgSkinNamesEn; + global $$foo; + global $wgSkinNamesEn; // potentially unused global declaration? // it might already be loaded in LocalSettings.php if(!isset($$foo)) { @@ -83,7 +83,7 @@ function getMediawikiMessages($languageCode = 'En') { $langFile = $IP.'/languages/classes/Language'.$languageCode.'.php'; if (file_exists( $langFile ) ) { print "Including $langFile\n"; - global $wgNamespaceNamesEn; + global $wgNamespaceNamesEn; // potentially unused global declaration? include($langFile); } else wfDie("ERROR: The file $langFile does not exist !\n"); } diff --git a/maintenance/language/dumpMessages.php b/maintenance/language/dumpMessages.php index bd7e2aed..6b7fea68 100644 --- a/maintenance/language/dumpMessages.php +++ b/maintenance/language/dumpMessages.php @@ -1,8 +1,7 @@ <?php /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/language/lang2po.php b/maintenance/language/lang2po.php index 520d8d6e..9a542e94 100644 --- a/maintenance/language/lang2po.php +++ b/maintenance/language/lang2po.php @@ -69,7 +69,7 @@ msgstr "" * @param array &$messages Array containing the various messages. * @return string Filename where stuff got saved or false. */ -function generatePo($langcode, &$messages) { +function generatePo($langcode, $messages) { $data = poHeader(); // Generate .po entries @@ -135,20 +135,13 @@ echo "done.\n"; $langTool = new languages(); // Do all languages -foreach ( $langTool->getMessages() as $langcode) { - echo "Loading messages for $langcode:\t"; - require_once( Language::getClassFileName( $langcode ) ); - $arr = 'wgAllMessages'.$langcode; - if(!@is_array($$arr)) { - echo "NONE FOUND\n"; +foreach ( $langTool->getLanguages() as $langcode) { + echo "Loading messages for $langcode:\n"; + if( ! generatePo($langcode, $langTool->getMessages($langcode) ) ) { + echo "ERROR: Failed to wrote file.\n"; } else { - echo "ok\n"; - if( ! generatePo($langcode, $$arr) ) { - echo "ERROR: Failed to wrote file.\n"; - } else { - echo "Applying template:"; - applyPot($langcode); - } + echo "Applying template:"; + applyPot($langcode); } } ?> diff --git a/maintenance/language/languages.inc b/maintenance/language/languages.inc index 946c6cb2..a10cae9e 100644 --- a/maintenance/language/languages.inc +++ b/maintenance/language/languages.inc @@ -2,19 +2,18 @@ /** * Handle messages in the language files. * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ require_once( 'messageTypes.inc' ); class languages { - private $mLanguages; # List of languages - private $mRawMessages; # Raw list of the messages in each language - private $mMessages; # Messages in each language (except for English), divided to groups - private $mGeneralMessages; # General messages in English, divided to groups - private $mIgnoredMessages; # All the messages which should be exist only in the English file - private $mOptionalMessages; # All the messages which may be translated or not, depending on the language + protected $mLanguages; # List of languages + protected $mRawMessages; # Raw list of the messages in each language + protected $mMessages; # Messages in each language (except for English), divided to groups + protected $mGeneralMessages; # General messages in English, divided to groups + protected $mIgnoredMessages; # All the messages which should be exist only in the English file + protected $mOptionalMessages; # All the messages which may be translated or not, depending on the language /** * Load the list of languages: all the Messages*.php @@ -67,7 +66,7 @@ class languages { * * @param $code The langauge code. */ - private function loadRawMessages( $code ) { + protected function loadRawMessages( $code ) { if ( isset( $this->mRawMessages[$code] ) ) { return; } @@ -248,6 +247,25 @@ class languages { } /** + * Get the messages which do not use plural. + * + * @param $code The langauge code. + * + * @return The messages which do not use plural in this language. + */ + public function getMessagesWithoutPlural( $code ) { + $this->loadGeneralMessages(); + $this->loadMessages( $code ); + $messagesWithoutPlural = array(); + foreach ( $this->mMessages[$code]['translated'] as $key => $value ) { + if ( stripos( $this->mGeneralMessages['translatable'][$key], '{{plural:' ) !== false && stripos( $value, '{{plural:' ) === false ) { + $messagesWithoutPlural[$key] = $value; + } + } + return $messagesWithoutPlural; + } + + /** * Get the empty messages. * * @param $code The langauge code. diff --git a/maintenance/language/messageTypes.inc b/maintenance/language/messageTypes.inc index f7f1ffeb..59ddcd95 100644 --- a/maintenance/language/messageTypes.inc +++ b/maintenance/language/messageTypes.inc @@ -2,13 +2,66 @@ /** * Several types of messages. * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** Ignored messages, which should be exist only in the English messages file. */ $wgIgnoredMessages = array( 'sidebar', + 'accesskey-pt-userpage', + 'accesskey-pt-anonuserpage', + 'accesskey-pt-mytalk', + 'accesskey-pt-anontalk', + 'accesskey-pt-preferences', + 'accesskey-pt-watchlist', + 'accesskey-pt-mycontris', + 'accesskey-pt-login', + 'accesskey-pt-anonlogin', + 'accesskey-pt-logout', + 'accesskey-ca-talk', + 'accesskey-ca-edit', + 'accesskey-ca-addsection', + 'accesskey-ca-viewsource', + 'accesskey-ca-history', + 'accesskey-ca-protect', + 'accesskey-ca-delete', + 'accesskey-ca-undelete', + 'accesskey-ca-move', + 'accesskey-ca-watch', + 'accesskey-ca-unwatch', + 'accesskey-search', + 'accesskey-p-logo', + 'accesskey-n-mainpage', + 'accesskey-n-portal', + 'accesskey-n-currentevents', + 'accesskey-n-recentchanges', + 'accesskey-n-randompage', + 'accesskey-n-help', + 'accesskey-n-sitesupport', + 'accesskey-t-whatlinkshere', + 'accesskey-t-recentchangeslinked', + 'accesskey-feed-rss', + 'accesskey-feed-atom', + 'accesskey-t-contributions', + 'accesskey-t-emailuser', + 'accesskey-t-upload', + 'accesskey-t-specialpages', + 'accesskey-ca-nstab-main', + 'accesskey-ca-nstab-user', + 'accesskey-ca-nstab-media', + 'accesskey-ca-nstab-special', + 'accesskey-ca-nstab-project', + 'accesskey-ca-nstab-image', + 'accesskey-ca-nstab-mediawiki', + 'accesskey-ca-nstab-template', + 'accesskey-ca-nstab-help', + 'accesskey-ca-nstab-category', + 'accesskey-minoredit', + 'accesskey-save', + 'accesskey-preview', + 'accesskey-diff', + 'accesskey-compareselectedversions', + 'accesskey-watch', 'addsection', 'anonnotice', 'autoblock_whitelist', @@ -27,6 +80,7 @@ $wgIgnoredMessages = array( 'noarticletextanon', 'number_of_watching_users_RCview', 'pagecategorieslink', + 'patrol-log-header', 'pubmedurl', 'randompage-url', 'rc-change-size', @@ -38,6 +92,9 @@ $wgIgnoredMessages = array( 'sitenotice', 'sitesubtitle', 'sitetitle', + 'sp-contributions-footer', + 'sp-contributions-footer-anon', + 'statistics-footer', 'talkpagetext', 'trackback', 'trackbackexcerpt', @@ -50,6 +107,8 @@ $wgOptionalMessages = array( 'linkprefix', 'feed-atom', 'feed-rss', + 'sectionlink', + 'unit-pixel', 'allpages-summary', 'booksources-summary', 'ipblocklist-summary', @@ -60,7 +119,6 @@ $wgOptionalMessages = array( 'whatlinkshere-summary', 'whatlinkshere-barrow', 'imagelist-summary', - 'mimesearch-summary', 'listredirects-summary', 'uncategorizedpages-summary', 'uncategorizedcategories-summary', @@ -82,10 +140,14 @@ $wgOptionalMessages = array( 'userrights-summary', 'brokenredirects-summary', 'deadendpages-summary', + 'protectedpages-summary', 'disambiguations-summary', 'doubleredirects-summary', 'lonelypages-summary', 'unusedtemplates-summary', + 'recentchangeslinked-summary', + 'fewestrevisions-summary', + 'withoutinterwiki-summary', 'variantname-zh-cn', 'variantname-zh-tw', 'variantname-zh-hk', diff --git a/maintenance/language/messages.inc b/maintenance/language/messages.inc index 4fbe2ed1..c4e8ee89 100644 --- a/maintenance/language/messages.inc +++ b/maintenance/language/messages.inc @@ -1,13 +1,12 @@ <?php /** - * Define the messages structure in the messages file, for a future automated rewriting. + * Define the messages structure in the messages file, for an automated rewriting. * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** The structure of the messages, divided to blocks */ -$wgMessageStrucutre = array( +$wgMessageStructure = array( 'sidebar' => array( 'sidebar', ), @@ -50,6 +49,7 @@ $wgMessageStrucutre = array( 'tog-watchlisthideminor', 'tog-nolangconversion', 'tog-ccmeonemails', + 'tog-diffonly', ), 'underline' => array( 'underline-always', @@ -121,28 +121,13 @@ $wgMessageStrucutre = array( ), 'mainpage' => array( 'linkprefix', - 'mainpage', 'mainpagetext', 'mainpagedocfooter', ), 'miscellaneous1' => array( - 'portal', - 'portal-url', 'about', - 'aboutsite', - 'aboutpage', 'article', - 'help', - 'helppage', - 'bugreports', - 'bugreportspage', - 'sitesupport', - 'sitesupport-url', - 'faq', - 'faqpage', - 'edithelp', 'newwindow', - 'edithelppage', 'cancel', 'qbfind', 'qbbrowse', @@ -160,15 +145,7 @@ $wgMessageStrucutre = array( 'metadata_help' => array( 'metadata_help', ), - 'currentevents' => array( - 'currentevents', - 'currentevents-url', - ), 'miscellaneous2' => array( - 'disclaimers', - 'disclaimerpage', - 'privacy', - 'privacypage', 'errorpagetitle', 'returnto', 'tagline', @@ -190,11 +167,13 @@ $wgMessageStrucutre = array( 'deletethispage', 'undelete_short', 'protect', + 'protect_change', 'protectthispage', 'unprotect', 'unprotectthispage', 'newpage', 'talkpage', + 'talkpagelinktext', 'specialpage', 'personaltools', 'postcomment', @@ -216,12 +195,38 @@ $wgMessageStrucutre = array( 'redirectpagesub', 'lastmodifiedat', 'viewcount', - 'copyright', 'protectedpage', 'jumpto', 'jumptonavigation', 'jumptosearch', ), + 'links' => array( + 'aboutsite', + 'aboutpage', + 'bugreports', + 'bugreportspage', + 'copyright', + 'copyrightpagename', + 'copyrightpage', + 'currentevents', + 'currentevents-url', + 'disclaimers', + 'disclaimerpage', + 'edithelp', + 'edithelppage', + 'faq', + 'faqpage', + 'help', + 'helppage', + 'mainpage', + 'policy-url', + 'portal', + 'portal-url', + 'privacy', + 'privacypage', + 'sitesupport', + 'sitesupport-url', + ), 'badaccess' => array( 'badaccess', 'badaccess-group0', @@ -234,7 +239,6 @@ $wgMessageStrucutre = array( 'versionrequiredtext', ), 'miscellaneous3' => array( - 'widthheight', 'ok', 'sitetitle', 'pagetitle', @@ -315,6 +319,7 @@ $wgMessageStrucutre = array( 'protectedinterface', 'editinginterface', 'sqlhidden', + 'cascadeprotected', ), 'login' => array( 'logouttitle', @@ -447,6 +452,8 @@ $wgMessageStrucutre = array( 'whitelistacctext', 'confirmedittitle', 'confirmedittext', + 'nosuchsectiontitle', + 'nosuchsectiontext', 'loginreqtitle', 'loginreqlink', 'loginreqpagetext', @@ -489,6 +496,7 @@ $wgMessageStrucutre = array( 'readonlywarning', 'protectedpagewarning', 'semiprotectedpagewarning', + 'cascadeprotectedwarning', 'templatesused', 'templatesusedpreview', 'templatesusedsection', @@ -525,16 +533,15 @@ $wgMessageStrucutre = array( 'next', 'last', 'orig', + 'page_first', + 'page_last', 'histlegend', 'history_copyright', 'deletedrev', 'histfirst', 'histlast', - 'rev-deleted-comment', - 'rev-deleted-user', - 'rev-deleted-text-permission', - 'rev-deleted-text-view', - 'rev-delundel', + 'historysize', + 'historyempty', ), 'history-feed' => array( 'history-feed-title', @@ -543,19 +550,39 @@ $wgMessageStrucutre = array( 'history-feed-empty', ), 'revdelete' => array( + 'rev-deleted-comment', + 'rev-deleted-user', + 'rev-deleted-event', + 'rev-deleted-text-permission', + 'rev-deleted-text-view', + 'rev-delundel', 'revisiondelete', 'revdelete-nooldid-title', 'revdelete-nooldid-text', 'revdelete-selected', + 'logdelete-selected', 'revdelete-text', 'revdelete-legend', 'revdelete-hide-text', + 'revdelete-hide-name', 'revdelete-hide-comment', 'revdelete-hide-user', 'revdelete-hide-restricted', + 'revdelete-suppress', + 'revdelete-hide-image', + 'revdelete-unsuppress', 'revdelete-log', 'revdelete-submit', 'revdelete-logentry', + 'logdelete-logentry', + 'revdelete-logaction', + 'logdelete-logaction', + 'revdelete-success', + 'logdelete-success', + ), + 'oversightlog' => array( + 'oversightlog', + 'overlogpagetext', ), 'diffs' => array( 'difference', @@ -601,6 +628,11 @@ $wgMessageStrucutre = array( 'prefsnologintext', 'prefsreset', 'qbsettings', + 'qbsettings-none', + 'qbsettings-fixedleft', + 'qbsettings-fixedright', + 'qbsettings-floatingleft', + 'qbsettings-floatingright', 'changepassword', 'skin', 'math', @@ -635,6 +667,7 @@ $wgMessageStrucutre = array( 'contextlines', 'contextchars', 'stubthreshold', + 'recentchangesdays', 'recentchangescount', 'savedprefs', 'timezonelegend', @@ -657,6 +690,7 @@ $wgMessageStrucutre = array( 'userrights-groupsmember', 'userrights-groupsavailable', 'userrights-groupshelp', + 'userrights-reason', ), 'group' => array( 'group', @@ -675,8 +709,14 @@ $wgMessageStrucutre = array( 'grouppage-sysop', 'grouppage-bureaucrat', ), + 'rightslog' => array( + 'rightslog', + 'rightslogtext', + 'rightslogentry', + 'rightsnone', + ), 'recentchanges' => array( - 'changes', + 'nchanges', 'recentchanges', 'recentchanges-url', 'recentchangestext', @@ -705,6 +745,11 @@ $wgMessageStrucutre = array( 'rc_categories_any', 'rc-change-size', ), + 'recentchangeslinked' => array( + 'recentchangeslinked', + 'recentchangeslinked-noresult', + 'recentchangeslinked-summary', + ), 'upload' => array( 'upload', 'uploadbtn', @@ -723,19 +768,23 @@ $wgMessageStrucutre = array( 'fileuploadsummary', 'filestatus', 'filesource', - 'copyrightpage', - 'copyrightpagename', 'uploadedfiles', 'ignorewarning', 'ignorewarnings', 'minlength', 'illegalfilename', 'badfilename', - 'badfiletype', + 'filetype-badmime', + 'filetype-badtype', + 'filetype-missing', 'large-file', 'largefileserver', 'emptyfile', 'fileexists', + 'fileexists-extension', + 'fileexists-thumb', + 'fileexists-thumbnail-yes', + 'file-thumbnail-no', 'fileexists-forbidden', 'fileexists-shared-forbidden', 'successfulupload', @@ -833,6 +882,7 @@ $wgMessageStrucutre = array( ), 'randomredirect' => array( 'randomredirect', + 'randomredirect-nopages', ), 'statistics' => array( 'statistics', @@ -841,12 +891,13 @@ $wgMessageStrucutre = array( 'sitestatstext', 'userstatstext', 'statistics-mostpopular', + 'statistics-footer', ), 'disambiguations' => array( 'disambiguations', 'disambiguations-summary', 'disambiguationspage', - 'disambiguationstext', + 'disambiguations-text', ), 'doubleredirects' => array( 'doubleredirects', @@ -857,6 +908,17 @@ $wgMessageStrucutre = array( 'brokenredirects', 'brokenredirects-summary', 'brokenredirectstext', + 'brokenredirects-edit', + 'brokenredirects-delete', + ), + 'withoutinterwiki' => array( + 'withoutinterwiki', + 'withoutinterwiki-header', + 'withoutinterwiki-summary', + ), + 'fewestrevisions' => array( + 'fewestrevisions', + 'fewestrevisions-summary', ), 'specialpages' => array( 'nbytes', @@ -865,6 +927,8 @@ $wgMessageStrucutre = array( 'nmembers', 'nrevisions', 'nviews', + 'nchanges', + 'specialpage-empty', 'lonelypages', 'lonelypages-summary', 'lonelypagestext', @@ -897,6 +961,7 @@ $wgMessageStrucutre = array( 'prefixindex', 'prefixindex-summary', 'randompage', + 'randompage-nopages', 'randompage-url', 'shortpages', 'shortpages-summary', @@ -905,13 +970,16 @@ $wgMessageStrucutre = array( 'deadendpages', 'deadendpages-summary', 'deadendpagestext', + 'protectedpages', + 'protectedpages-summary', + 'protectedpagestext', + 'protectedpagesempty', 'listusers', 'listusers-summary', 'specialpages', 'specialpages-summary', 'spheading', 'restrictedpheading', - 'recentchangeslinked', 'rclsub', 'newpages', 'newpages-summary', @@ -943,9 +1011,16 @@ $wgMessageStrucutre = array( 'pubmedurl', 'alphaindexline', 'version', + ), + 'logpages' => array( + 'specialloguserlabel', + 'speciallogtitlelabel', 'log', + 'log-search-legend', + 'log-search-submit', 'alllogstext', 'logempty', + 'log-title-wildcard', ), 'allpages' => array( 'nextpage', @@ -962,6 +1037,8 @@ $wgMessageStrucutre = array( ), 'listusers' => array( 'listusersfrom', + 'listusers-submit', + 'listusers-noresult', ), 'emailuser' => array( 'mailnologin', @@ -985,6 +1062,7 @@ $wgMessageStrucutre = array( ), 'watchlist' => array( 'watchlist', + 'mywatchlist', 'watchlistfor', 'nowatchlist', 'watchlistanontext', @@ -1079,32 +1157,49 @@ $wgMessageStrucutre = array( 'confirmprotect', 'protectmoveonly', 'protectcomment', + 'protectexpiry', + 'protect_expiry_invalid', + 'protect_expiry_old', 'unprotectsub', 'confirmunprotecttext', 'confirmunprotect', 'unprotectcomment', 'protect-unchain', 'protect-text', - 'protect-viewtext', + 'protect-locked-blocked', + 'protect-locked-dblock', + 'protect-locked-access', + 'protect-cascadeon', 'protect-default', 'protect-level-autoconfirmed', 'protect-level-sysop', + 'protect-summary-cascade', + 'protect-expiring', + 'protect-cascade', + 'restriction-type', + 'restriction-level', + 'minimum-size', ), 'restrictions' => array( 'restriction-edit', 'restriction-move', ), + 'restriction-levels' => array( + 'restriction-level-sysop', + 'restriction-level-autoconfirmed', + 'restriction-level-all', + ), 'undelete' => array( 'undelete', 'undeletepage', 'viewdeletedpage', 'undeletepagetext', 'undeleteextrahelp', - 'undeletearticle', 'undeleterevisions', 'undeletehistory', + 'undeleterevdel', 'undeletehistorynoadmin', - 'undeleterevision', + 'undelete-revision', 'undeleterevision-missing', 'undeletebtn', 'undeletereset', @@ -1115,6 +1210,11 @@ $wgMessageStrucutre = array( 'undeletedfiles', 'cannotundelete', 'undeletedpage', + 'undelete-header', + 'undelete-search-box', + 'undelete-search-prefix', + 'undelete-search-submit', + 'undelete-no-results', ), 'nsform' => array( 'namespace', @@ -1123,20 +1223,25 @@ $wgMessageStrucutre = array( 'contributions' => array( 'contributions', 'mycontris', - 'contribsub', + 'contribsub2', 'nocontribs', 'ucnote', 'uclinks', 'uctop', - 'newbies', ), 'sp-contributions' => array( 'sp-contributions-newest', 'sp-contributions-oldest', 'sp-contributions-newer', 'sp-contributions-older', + 'sp-contributions-newbies', 'sp-contributions-newbies-sub', 'sp-contributions-blocklog', + 'sp-contributions-search', + 'sp-contributions-username', + 'sp-contributions-submit', + 'sp-contributions-footer', + 'sp-contributions-footer-anon', ), 'newimages-showfrom' => array( 'sp-newimages-showfrom', @@ -1150,8 +1255,11 @@ $wgMessageStrucutre = array( 'linklistsub', 'linkshere', 'nolinkshere', + 'nolinkshere-ns', 'isredirect', 'istemplate', + 'whatlinkshere-prev', + 'whatlinkshere-next', ), 'block' => array( 'blockip', @@ -1160,6 +1268,8 @@ $wgMessageStrucutre = array( 'ipadressorusername', 'ipbexpiry', 'ipbreason', + 'ipbreasonotherlist', + 'ipbreason-dropdown', 'ipbanononly', 'ipbcreateaccount', 'ipbenableautoblock', @@ -1167,15 +1277,23 @@ $wgMessageStrucutre = array( 'ipbother', 'ipboptions', 'ipbotheroption', + 'ipbotherreason', + 'ipbhidename', 'badipaddress', 'blockipsuccesssub', 'blockipsuccesstext', + 'ipb-edit-dropdown', + 'ipb-unblock-addr', + 'ipb-unblock', + 'ipb-blocklist-addr', + 'ipb-blocklist', 'unblockip', 'unblockiptext', 'ipusubmit', 'unblocked', 'ipblocklist', 'ipblocklist-summary', + 'ipblocklist-submit', 'blocklistline', 'infiniteblock', 'expiringblock', @@ -1191,6 +1309,9 @@ $wgMessageStrucutre = array( 'blocklogentry', 'blocklogtext', 'unblocklogentry', + 'block-log-flags-anononly', + 'block-log-flags-nocreate', + 'block-log-flags-noautoblock', 'range_block_disabled', 'ipb_expiry_invalid', 'ipb_already_blocked', @@ -1220,26 +1341,6 @@ $wgMessageStrucutre = array( 'lockfilenotwritable', 'databasenotlocked', ), - 'makesysop' => array( - 'makesysoptitle', - 'makesysoptext', - 'makesysopname', - 'makesysopsubmit', - 'makesysopok', - 'makesysopfail', - 'setbureaucratflag', - 'rightslog', - 'rightslogtext', - 'rightslogentry', - 'rights', - 'set_user_rights', - 'user_rights_set', - 'set_rights_fail', - 'makesysop', - 'already_sysop', - 'already_bureaucrat', - 'rightsnone', - ), 'movepage' => array( 'movepage', 'movepagetext', @@ -1277,6 +1378,8 @@ $wgMessageStrucutre = array( 'exportcuronly', 'exportnohistory', 'export-submit', + 'export-addcattext', + 'export-addcat', ), 'allmessages' => array( 'allmessages', @@ -1294,6 +1397,10 @@ $wgMessageStrucutre = array( 'missingimage', 'filemissing', 'thumbnail_error', + 'djvu_page_error', + 'djvu_no_xml', + 'thumbnail_invalid_params', + 'thumbnail_dest_directory', ), 'import' => array( 'import', @@ -1326,7 +1433,54 @@ $wgMessageStrucutre = array( 'import-logentry-interwiki-detail', ), 'accesskeys' => array( + 'accesskey-pt-userpage', + 'accesskey-pt-anonuserpage', + 'accesskey-pt-mytalk', + 'accesskey-pt-anontalk', + 'accesskey-pt-preferences', + 'accesskey-pt-watchlist', + 'accesskey-pt-mycontris', + 'accesskey-pt-login', + 'accesskey-pt-anonlogin', + 'accesskey-pt-logout', + 'accesskey-ca-talk', + 'accesskey-ca-edit', + 'accesskey-ca-addsection', + 'accesskey-ca-viewsource', + 'accesskey-ca-history', + 'accesskey-ca-protect', + 'accesskey-ca-delete', + 'accesskey-ca-undelete', + 'accesskey-ca-move', + 'accesskey-ca-watch', + 'accesskey-ca-unwatch', 'accesskey-search', + 'accesskey-p-logo', + 'accesskey-n-mainpage', + 'accesskey-n-portal', + 'accesskey-n-currentevents', + 'accesskey-n-recentchanges', + 'accesskey-n-randompage', + 'accesskey-n-help', + 'accesskey-n-sitesupport', + 'accesskey-t-whatlinkshere', + 'accesskey-t-recentchangeslinked', + 'accesskey-feed-rss', + 'accesskey-feed-atom', + 'accesskey-t-contributions', + 'accesskey-t-emailuser', + 'accesskey-t-upload', + 'accesskey-t-specialpages', + 'accesskey-ca-nstab-main', + 'accesskey-ca-nstab-user', + 'accesskey-ca-nstab-media', + 'accesskey-ca-nstab-special', + 'accesskey-ca-nstab-project', + 'accesskey-ca-nstab-image', + 'accesskey-ca-nstab-mediawiki', + 'accesskey-ca-nstab-template', + 'accesskey-ca-nstab-help', + 'accesskey-ca-nstab-category', 'accesskey-minoredit', 'accesskey-save', 'accesskey-preview', @@ -1335,18 +1489,70 @@ $wgMessageStrucutre = array( 'accesskey-watch', ), 'tooltips' => array( + 'tooltip-pt-userpage', + 'tooltip-pt-anonuserpage', + 'tooltip-pt-mytalk', + 'tooltip-pt-anontalk', + 'tooltip-pt-preferences', + 'tooltip-pt-watchlist', + 'tooltip-pt-mycontris', + 'tooltip-pt-login', + 'tooltip-pt-anonlogin', + 'tooltip-pt-logout', + 'tooltip-ca-talk', + 'tooltip-ca-edit', + 'tooltip-ca-addsection', + 'tooltip-ca-viewsource', + 'tooltip-ca-history', + 'tooltip-ca-protect', + 'tooltip-ca-delete', + 'tooltip-ca-undelete', + 'tooltip-ca-move', + 'tooltip-ca-watch', + 'tooltip-ca-unwatch', 'tooltip-search', + 'tooltip-p-logo', + 'tooltip-n-mainpage', + 'tooltip-n-portal', + 'tooltip-n-currentevents', + 'tooltip-n-recentchanges', + 'tooltip-n-randompage', + 'tooltip-n-help', + 'tooltip-n-sitesupport', + 'tooltip-t-whatlinkshere', + 'tooltip-t-recentchangeslinked', + 'tooltip-feed-rss', + 'tooltip-feed-atom', + 'tooltip-t-contributions', + 'tooltip-t-emailuser', + 'tooltip-t-upload', + 'tooltip-t-specialpages', + 'tooltip-ca-nstab-main', + 'tooltip-ca-nstab-user', + 'tooltip-ca-nstab-media', + 'tooltip-ca-nstab-special', + 'tooltip-ca-nstab-project', + 'tooltip-ca-nstab-image', + 'tooltip-ca-nstab-mediawiki', + 'tooltip-ca-nstab-template', + 'tooltip-ca-nstab-help', + 'tooltip-ca-nstab-category', 'tooltip-minoredit', 'tooltip-save', 'tooltip-preview', 'tooltip-diff', 'tooltip-compareselectedversions', 'tooltip-watch', + 'tooltip-recreate', ), 'stylesheets' => array( 'common.css', 'monobook.css', ), + 'scripts' => array( + 'common.js', + 'monobook.js', + ), 'metadata_cc' => array( 'nodublincore', 'nocreativecommons', @@ -1403,11 +1609,12 @@ $wgMessageStrucutre = array( 'markedaspatrollederrortext', 'markedaspatrollederror-noautopatrol', ), - 'monobook.js' => array( - 'monobook.js', - ), - 'common.js' => array( - 'common.js', + 'patrol-log' => array( + 'patrol-log-page', + 'patrol-log-header', + 'patrol-log-line', + 'patrol-log-auto', + 'patrol-log-diff', ), 'imagedeletion' => array( 'deletedrevision', @@ -1416,10 +1623,17 @@ $wgMessageStrucutre = array( 'previousdiff', 'nextdiff', ), - 'imagesize' => array( + 'media-info' => array( + 'mediawarning', 'imagemaxsize', 'thumbsize', - 'showbigimage', + 'widthheight', + 'file-info', + 'file-info-size', + 'file-nohires', + 'file-svg', + 'show-big-image', + 'show-big-image-thumb', ), 'newimages' => array( 'newimages', @@ -1447,19 +1661,9 @@ $wgMessageStrucutre = array( 'variantname-kk-cn', 'variantname-kk', ), - 'specialloglabels' => array( - 'specialloguserlabel', - 'speciallogtitlelabel', - ), 'passwordtooshort' => array( 'passwordtooshort', ), - 'mediawarning' => array( - 'mediawarning', - ), - 'fileinfo' => array( - 'fileinfo', - ), 'metadata' => array( 'metadata', 'metadata-help', @@ -1823,7 +2027,6 @@ $wgMessageStrucutre = array( 'deletedwhileediting', 'confirmrecreate', 'recreate', - 'tooltip-recreate', ), 'unit-pixel' => array( 'unit-pixel', @@ -1861,6 +2064,7 @@ $wgMessageStrucutre = array( 'imgmultigo', 'imgmultigotopre', 'imgmultigotopost', + 'imgmultiparseerror', ), 'tablepager' => array( 'ascending_abbrev', @@ -1888,6 +2092,12 @@ $wgMessageStrucutre = array( 'size-megabytes', 'size-gigabytes', ), + 'livepreview' => array( + 'livepreview-loading', + 'livepreview-ready', + 'livepreview-failed', + 'livepreview-error', + ), ); /** Comments for each block */ $wgBlockComments = array( @@ -1905,8 +2115,8 @@ XHTML id names.", 'mainpage' => '', 'miscellaneous1' => '', 'metadata_help' => 'Metadata in edit box', - 'currentevents' => '', 'miscellaneous2' => '', + 'links' => 'All link text and link target definitions of links into project namespace that get used by other message strings, with the exception of user group pages (see grouppage) and the disambiguation template definition (see disambiguations).', 'badaccess' => '', 'versionrequired' => '', 'miscellaneous3' => '', @@ -1920,8 +2130,9 @@ XHTML id names.", 'undo' => '"Undo" feature', 'cantcreateaccount' => 'Account creation failure', 'history' => 'History pages', - 'history-feed' => '', + 'history-feed' => 'Revision feed', 'revdelete' => 'Revision deletion', + 'oversightlog' => 'Oversight log', 'diffs' => 'Diffs', 'search' => 'Search results', 'preferences' => 'Preferences page', @@ -1929,7 +2140,9 @@ XHTML id names.", 'group' => 'Groups', 'group-member' => '', 'grouppage' => '', + 'rightslog' => 'User rights log', 'recentchanges' => 'Recent changes', + 'recentchangeslinked' => 'Recent changes linked', 'upload' => 'Upload', 'upload-errors' => '', 'upload-curl-errors' => 'Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>', @@ -1944,9 +2157,12 @@ XHTML id names.", 'disambiguations' => '', 'doubleredirects' => '', 'brokenredirects' => '', + 'withoutinterwiki' => '', + 'fewestrevisions' => '', 'specialpages' => 'Miscellaneous special pages', 'booksources' => 'Book sources', 'specialpages2' => '', + 'logpages' => 'Special:Log', 'allpages' => 'Special:Allpages', 'listusers' => 'Special:Listusers', 'emailuser' => 'E-mail user', @@ -1955,6 +2171,7 @@ XHTML id names.", 'enotif' => '', 'deleteprotectrev' => 'Delete/protect/revert', 'restrictions' => 'Restrictions (nouns)', + 'restriction-levels' => 'Restriction levels', 'undelete' => 'Undelete', 'nsform' => 'Namespace form on various pages', 'contributions' => 'Contributions', @@ -1963,7 +2180,6 @@ XHTML id names.", 'whatlinkshere' => 'What links here', 'block' => 'Block/unblock', 'developertools' => 'Developer tools', - 'makesysop' => 'Make sysop', 'movepage' => 'Move page', 'export' => 'Export', 'allmessages' => 'Namespace 8 related', @@ -1971,19 +2187,18 @@ XHTML id names.", 'import' => 'Special:Import', 'importlog' => 'Import log', 'accesskeys' => 'Keyboard access keys for power users', - 'tooltips' => 'Tooltip help for some actions, most are in Monobook.js', + 'tooltips' => 'Tooltip help for the actions', 'stylesheets' => 'Stylesheets', + 'scripts' => 'Scripts', 'metadata_cc' => 'Metadata', 'attribution' => 'Attribution', 'spamprotection' => 'Spam protection', 'info' => 'Info page', 'math' => 'Math options', 'patrolling' => 'Patrolling', - 'monobook.js' => 'Monobook.js: tooltips and access keys for monobook', - 'common.js' => 'Common.js: contains nothing but a placeholder comment', + 'patrol-log' => 'Patrol log', 'imagedeletion' => 'Image deletion', 'browsediffs' => 'Browsing diffs', - 'imagesize' => '', 'newimages' => '', 'variantname-zh' => "Short names for language variants used for language conversion links. To disable showing a particular link, set it to 'disable', e.g. @@ -1991,10 +2206,8 @@ To disable showing a particular link, set it to 'disable', e.g. Variants for Chinese language", 'variantname-sr' => 'Variants for Serbian language', 'variantname-kk' => 'Variants for Kazakh language', - 'specialloglabels' => 'Labels for User: and Title: on Special:Log pages', 'passwordtooshort' => '', - 'mediawarning' => 'Media Warning', - 'fileinfo' => '', + 'media-info' => 'Media information', 'metadata' => 'Metadata', 'exif' => 'EXIF tags', 'exif-values' => 'Make & model, can be wikified in order to link to the camera and model name', @@ -2049,6 +2262,7 @@ Variants for Chinese language", 'autosumm' => 'Auto-summaries', 'autoblock_whitelist' => 'Autoblock whitelist', 'sizeunits' => 'Size units', + 'livepreview' => 'Live preview', ); /** Short comments for standalone messages */ diff --git a/maintenance/language/rebuildLanguage.php b/maintenance/language/rebuildLanguage.php index 1643d30b..d4753c4a 100644 --- a/maintenance/language/rebuildLanguage.php +++ b/maintenance/language/rebuildLanguage.php @@ -2,8 +2,7 @@ /** * Rewrite the messages array in the files languages/messages/MessagesXX.php. * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ require_once( dirname(__FILE__).'/../commandLine.inc' ); @@ -15,32 +14,13 @@ require_once( 'writeMessagesArray.inc' ); * * @param $code The language code. * @param $write Write to the messages file? + * @param $listUnknown List the unknown messages? */ -function rebuildLanguage( $code, $write ) { - global $wgLanguages, $wg; - - # Get messages +function rebuildLanguage( $code, $write, $listUnknown ) { + global $wgLanguages; $messages = $wgLanguages->getMessages( $code ); $messages = $messages['all']; - - # Rewrite messages array - $messagesText = writeMessagesArray( $messages, $code == 'en' ); - - # Write to the file - if ( $write ) { - $filename = Language::getMessagesFileName( $code ); - $contents = file_get_contents( $filename ); - if ( strpos( $contents, '$messages' ) !== false ) { - $new = explode( '$messages', $contents ); - $new = $new[0]; - $new .= $messagesText; - $new .= "\n?>\n"; - file_put_contents( $filename, $new ); - echo "Generated and wrote messages in language $code.\n"; - } - } else { - echo "Generated messages in language $code.\n"; - } + writeMessagesToFile( $messages, $code, $write, $listUnknown ); } # Show help @@ -52,6 +32,7 @@ Parameters: * help: Show this help. Options: * dry-run: Don't write the array to the file. + * no-unknown: Don't list the unknown messages. END; exit(); @@ -64,8 +45,9 @@ if ( isset( $options['lang'] ) ) { $wgCode = $wgContLang->getCode(); } -# Get the write options +# Get the options $wgWriteToFile = !isset( $options['dry-run'] ); +$wgListUnknownMessages = !isset( $options['no-unknown'] ); # Get language objects $wgLanguages = new languages(); @@ -73,10 +55,10 @@ $wgLanguages = new languages(); # Write all the language if ( $wgCode == 'all' ) { foreach ( $wgLanguages->getLanguages() as $language ) { - rebuildLanguage( $language, $wgWriteToFile ); + rebuildLanguage( $language, $wgWriteToFile, $wgListUnknownMessages ); } } else { - rebuildLanguage( $wgCode, $wgWriteToFile ); + rebuildLanguage( $wgCode, $wgWriteToFile, $wgListUnknownMessages ); } ?> diff --git a/maintenance/language/transstat.php b/maintenance/language/transstat.php index e1b67274..36a78000 100644 --- a/maintenance/language/transstat.php +++ b/maintenance/language/transstat.php @@ -2,8 +2,7 @@ /** * Statistics about the localisation. * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> * @author Ashar Voultoiz <thoane@altern.org> @@ -67,7 +66,7 @@ class wikiStatsOutput extends statsOutput { echo "'''Statistics are based on:''' <code>" . $version . "</code>\n\n"; echo "'''Note:''' These statistics can be generated by running <code>php maintenance/language/transstat.php</code>.\n\n"; echo "For additional information on specific languages (the message names, the actual problems, etc.), run <code>php maintenance/language/checkLanguage.php --lang=foo</code>.\n\n"; - echo '{| class="sortable wikitable" border="2" cellpadding="4" cellspacing="0" style="background-color: #F9F9F9; border: 1px #AAAAAA solid; border-collapse: collapse;" width="100%"'."\n"; + echo '{| class="sortable wikitable" border="2" cellpadding="4" cellspacing="0" style="background-color: #F9F9F9; border: 1px #AAAAAA solid; border-collapse: collapse; clear:both;" width="100%"'."\n"; } function footer() { echo "|}\n"; diff --git a/maintenance/language/writeMessagesArray.inc b/maintenance/language/writeMessagesArray.inc index b0d17c59..01fc7762 100644 --- a/maintenance/language/writeMessagesArray.inc +++ b/maintenance/language/writeMessagesArray.inc @@ -2,27 +2,69 @@ /** * Write a messages array as a PHP text. * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ require_once( 'messages.inc' ); require_once( 'messageTypes.inc' ); /** + * Write a messages array as a PHP text and write it to the messages file. + * + * @param $messages The messages array. + * @param $code The language code. + * @param $write Write to the messages file? + * @param $listUnknown List the unknown messages? + */ +function writeMessagesToFile( $messages, $code, $write, $listUnknown ) { + # Rewrite the messages array + $messages = writeMessagesArray( $messages, $code == 'en' ); + $messagesText = $messages[0]; + $sortedMessages = $messages[1]; + + # Write to the file + $filename = Language::getMessagesFileName( $code ); + $contents = file_get_contents( $filename ); + if ( strpos( $contents, '$messages' ) !== false ) { + $contents = explode( '$messages', $contents ); + if ( $messagesText . "\n?>\n" == '$messages' . $contents[1] ) { + echo "Generated messages for language $code. Same to the current file.\n"; + } else { + if ( $write ) { + $new = $contents[0]; + $new .= $messagesText; + $new .= "\n?>\n"; + file_put_contents( $filename, $new ); + echo "Generated and wrote messages for language $code.\n"; + } else { + echo "Generated messages for language $code. Please run the script again (without the parameter \"dry-run\") to write the array to the file.\n"; + } + } + if ( $listUnknown && isset( $sortedMessages['unknown'] ) && !empty( $sortedMessages['unknown'] ) ) { + 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"; + } +} + +/** * Write a messages array as a PHP text. * * @param $messages The messages array. * @param $ignoredComments Show comments about ignored and optional messages? (For English.) * - * @return The PHP text. + * @return Array of the PHP text and the sorted messages array. */ function writeMessagesArray( $messages, $ignoredComments = false ) { - global $wgMessageStrucutre, $wgBlockComments, $wgMessageComments; + global $wgMessageStructure, $wgBlockComments; # Sort messages to blocks $sortedMessages['unknown'] = $messages; - foreach ( $wgMessageStrucutre as $blockName => $block ) { + foreach ( $wgMessageStructure as $blockName => $block ) { foreach ( $block as $key ) { if ( array_key_exists( $key, $sortedMessages['unknown'] ) ) { $sortedMessages[$blockName][$key] = $sortedMessages['unknown'][$key]; @@ -46,7 +88,7 @@ function writeMessagesArray( $messages, $ignoredComments = false ) { $messagesText .= writeMessagesBlock( 'unknown', 'Unknown messages', $sortedMessages['unknown'], $ignoredComments ); # Write the unknown messages, alphabetically sorted $messagesText .= ");\n"; - return $messagesText; + return array( $messagesText, $sortedMessages ); } /** @@ -79,12 +121,7 @@ function writeMessagesBlock( $name, $comment, $messages, $ignoredComments ) { } # Get max key length - $maxKeyLength = 0; - foreach( array_keys( $messages ) as $key ) { - if ( strlen( $key ) > $maxKeyLength ) { - $maxKeyLength = strlen( $key ); - } - } + $maxKeyLength = max( array_map( 'strlen', array_keys( $messages ) ) ); # Format the messages foreach( $messages as $key => $value ) { @@ -92,9 +129,7 @@ function writeMessagesBlock( $name, $comment, $messages, $ignoredComments ) { $blockText .= "'$key'"; # Add the appropriate block whitespace - for ( $i = 1; $i <= ( $maxKeyLength - strlen( $key ) ); $i++ ) { - $blockText .= ' '; - } + $blockText .= str_repeat( ' ', $maxKeyLength - strlen( $key ) ); # Refer to the value $blockText .= ' => '; @@ -105,7 +140,11 @@ function writeMessagesBlock( $name, $comment, $messages, $ignoredComments ) { } elseif ( strpos( $value, '"' ) === false && !in_array( $key, $wgMessagseWithDollarSigns ) ) { $blockText .= "\"$value\""; } else { - $blockText .= "'" . str_replace( "'", "\'", $value ) . "'"; + # Pick the less numerous one to escape + $quote = substr_count( $value, '"' ) + substr_count( $value, '$' ) >= substr_count( $value, "'" ) ? "'" : '"'; + if ('"' == $quote) { $extra = '$'; } + else { $extra = ''; } + $blockText .= $quote . addcslashes( $value, $quote.'\\'.$extra ) . $quote; } # Comma diff --git a/maintenance/mcc.php b/maintenance/mcc.php index 93b6ec18..b0302ab2 100644 --- a/maintenance/mcc.php +++ b/maintenance/mcc.php @@ -3,8 +3,7 @@ * memcached diagnostic tool * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -112,7 +111,11 @@ do { case 'server': $res = $mcc->get( $args[0] ); - print $mcc->_buckets[$mcc->_hashfunc( $args[0] ) % $mcc->_bucketcount] . "\n"; + $hv = $mcc->_hashfunc( $args[0] ); + for ( $i = 0; $i < 3; $i++ ) { + print $mcc->_buckets[$hv % $mcc->_bucketcount] . "\n"; + $hv += $mcc->_hashfunc( $i . $args[0] ); + } break; case 'set': diff --git a/maintenance/mctest.php b/maintenance/mctest.php index f8f4b965..dbf99f62 100644 --- a/maintenance/mctest.php +++ b/maintenance/mctest.php @@ -1,5 +1,5 @@ <?php -/* $Id: mctest.php 16738 2006-10-02 17:04:13Z brion $ */ +/* $Id: mctest.php 19364 2007-01-17 00:54:54Z brion $ */ $optionsWithArgs = array( 'i' ); @@ -16,8 +16,6 @@ function microtime_float() if ( isset( $args[0] ) ) { $wgMemCachedServers = array( $args[0] ); -} else { - $wgMemCachedServers[] = 'localhost'; } if ( isset( $options['i'] ) ) { $iterations = $options['i']; diff --git a/maintenance/moveBatch.php b/maintenance/moveBatch.php index 4b0abf7f..058652dc 100644 --- a/maintenance/moveBatch.php +++ b/maintenance/moveBatch.php @@ -3,8 +3,7 @@ /** * Maintenance script to move a batch of pages * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Tim Starling * * USAGE: php moveBatch.php [-u <user>] [-r <reason>] [-i <interval>] <listfile> @@ -56,7 +55,7 @@ if ( !$file ) { exit; } -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); for ( $linenum = 1; !feof( $file ); $linenum++ ) { $line = fgets( $file ); diff --git a/maintenance/mwdocgen.php b/maintenance/mwdocgen.php index de1a7d96..d66e6874 100644 --- a/maintenance/mwdocgen.php +++ b/maintenance/mwdocgen.php @@ -18,8 +18,7 @@ * * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * * @author Ashar Voultoiz <thoane@altern.org> * @version first release diff --git a/maintenance/mwdoxygen.cfg b/maintenance/mwdoxygen.cfg index 39fae228..b5ba8925 100644 --- a/maintenance/mwdoxygen.cfg +++ b/maintenance/mwdoxygen.cfg @@ -1,1136 +1,230 @@ -# Doxyfile 1.4.3-20050530 - -# -# NOTE: this configuration assume you are running doxygen from the -# mediawiki root directory. For example: -# ~/dev/mediawiki-HEAD/ -# The easiest way is to get in the maintenance directory and then: -# make doxydoc -# -# Paths visited are configured by the INPUT variable (around line 450) - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for the MediaWiki project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") +# Doxyfile 1.5.1 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- - PROJECT_NAME = MediaWiki -PROJECT_NUMBER = 1.6-cvs +PROJECT_NUMBER = MW_VERSION_PLACEHOLDER OUTPUT_DIRECTORY = docs - -# 2 levels directories, create 4096 of them! CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, -# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, -# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, -# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, -# Swedish, and Ukrainian. - OUTPUT_LANGUAGE = English - USE_WINDOWS_ENCODING = NO - BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. ALWAYS_DETAILED_SEC = YES - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explicit @brief command for a brief description. -JAVADOC_AUTOBRIEF = YES - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. +JAVADOC_AUTOBRIEF = YES MULTILINE_CPP_IS_BRIEF = NO - -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. DETAILS_AT_TOP = YES - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. INHERIT_DOCS = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -DISTRIBUTE_GROUP_DOC = NO - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. ALIASES = - - OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES - - - #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. EXTRACT_PRIVATE = YES - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. SORT_BRIEF_DOCS = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. SORT_BY_SCOPE_NAME = NO - GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. SHOW_DIRECTORIES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command <command> <input-file>, where <command> is the value of -# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file -# provided by doxygen. Whatever the progam writes to standard output -# is used as the file version. See the manual for examples. -FILE_VERSION_FILTER = - - - +FILE_VERSION_FILTER = bin/svnstat #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. WARN_LOGFILE = - #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -# should be run from maintenance -# FIXME : includes/normal includes/templates languages are missing -INPUT = config includes maintenance skins tests - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm - -FILE_PATTERNS = *.php *.inc - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - +INPUT = config \ + includes \ + maintenance \ + skins \ + tests +FILE_PATTERNS = *.php \ + *.inc RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - +EXCLUDE = EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. - EXCLUDE_PATTERNS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command <filter> <input-file>, where <filter> -# is the value of the INPUT_FILTER tag, and <input-file> is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - FILTER_SOURCE_FILES = NO - - - #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - REFERENCED_BY_RELATION = YES - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - REFERENCES_RELATION = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - +REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - VERBATIM_HEADERS = YES - - #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - IGNORE_PREFIX = - #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. - GENERATE_TREEVIEW = YES - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - TREEVIEW_WIDTH = 250 - #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - PDF_HYPERLINKS = NO - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - USE_PDFLATEX = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - LATEX_HIDE_INDICES = NO - #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - RTF_EXTENSIONS_FILE = - #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - MAN_LINKS = NO - #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - XML_PROGRAMLISTING = YES - #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - GENERATE_AUTOGEN_DEF = NO - #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - PERLMOD_MAKEVAR_PREFIX = - #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = NO - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - +ENABLE_PREPROCESSING = NO MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_PREDEFINED tags. - EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - SKIP_FUNCTION_MACROS = YES - #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - CLASS_DIAGRAMS = YES - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - +HAVE_DOT = YES CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - +COLLABORATION_GRAPH = NO GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. - CALL_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - +CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - MAX_DOT_GRAPH_WIDTH = 1024 - -# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - MAX_DOT_GRAPH_HEIGHT = 1024 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that a graph may be further truncated if the graph's -# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH -# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), -# the graph is not depth-constrained. - MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). - DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - DOT_CLEANUP = YES - #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO +SEARCHENGINE = YES diff --git a/maintenance/namespaceDupes.php b/maintenance/namespaceDupes.php index acd3a708..c5c1ec58 100644 --- a/maintenance/namespaceDupes.php +++ b/maintenance/namespaceDupes.php @@ -175,7 +175,7 @@ $fix = isset( $options['fix'] ); $suffix = isset( $options['suffix'] ) ? $options['suffix'] : ''; $prefix = isset( $options['prefix'] ) ? $options['prefix'] : ''; $key = isset( $options['key'] ) ? intval( $options['key'] ) : 0; -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); $duper = new NamespaceConflictChecker( $dbw ); if( $prefix ) { diff --git a/maintenance/nextJobDB.php b/maintenance/nextJobDB.php new file mode 100644 index 00000000..7aa05a27 --- /dev/null +++ b/maintenance/nextJobDB.php @@ -0,0 +1,48 @@ +<?php + +/* + * Pick a database that has pending jobs + */ + +require_once( 'commandLine.inc' ); + +$pendingDBs = $wgMemc->get( 'jobqueue:dbs' ); +if ( !$pendingDBs ) { + $pendingDBs = array(); + # Cross-reference DBs by master DB server + $dbsByMaster = array(); + $defaultMaster = $wgAlternateMaster['DEFAULT']; + foreach ( $wgLocalDatabases as $db ) { + if ( isset( $wgAlternateMaster[$db] ) ) { + $dbsByMaster[$wgAlternateMaster[$db]][] = $db; + } else { + $dbsByMaster[$defaultMaster][] = $db; + } + } + + foreach ( $dbsByMaster as $master => $dbs ) { + $dbConn = new Database( $master, $wgDBuser, $wgDBpassword ); + + # Padding row for MySQL bug + $sql = "(SELECT '-------------------------------------------')"; + foreach ( $dbs as $dbName ) { + if ( $sql != '' ) { + $sql .= ' UNION '; + } + $sql .= "(SELECT '$dbName' FROM `$dbName`.job LIMIT 1)"; + } + $res = $dbConn->query( $sql, 'nextJobDB.php' ); + $row = $dbConn->fetchRow( $res ); // discard padding row + while ( $row = $dbConn->fetchRow( $res ) ) { + $pendingDBs[] = $row[0]; + } + } + + $wgMemc->set( 'jobqueue:dbs', $pendingDBs, 300 ); +} + +if ( $pendingDBs ) { + echo $pendingDBs[mt_rand(0, count( $pendingDBs ) - 1)]; +} + +?> diff --git a/maintenance/nukeNS.php b/maintenance/nukeNS.php new file mode 100644 index 00000000..8e280b20 --- /dev/null +++ b/maintenance/nukeNS.php @@ -0,0 +1,108 @@ +<?php + +/** + * Remove pages with only 1 revision from the MediaWiki namespace, without + * flooding recent changes, delete logs, etc. + * Irreversible (can't use standard undelete) and does not update link tables + * + * This is mainly useful to run before maintenance/update.php when upgrading + * to 1.9, to prevent flooding recent changes/deletion logs. It's intended + * to be conservative, so it's possible that a few entries will be left for + * deletion by the upgrade script. It's also possible that it hasn't been + * tested thouroughly enough, and will delete something it shouldn't; so + * back up your DB if there's anything in the MediaWiki that is important to + * you. + * + * @addtogroup Maintenance + * @author Steve Sanbeg + * based on nukePage by Rob Church + */ + +require_once( 'commandLine.inc' ); +require_once( 'nukePage.inc' ); + +$ns = NS_MEDIAWIKI; +$delete = false; + +if (isset($options['ns'])) +{ + $ns = $options['ns']; +} + +if (isset( $options['delete'] ) and $options['delete']) +{ + $delete = true; +} + + +NukeNS( $ns, $delete); + +function NukeNS($ns_no, $delete) { + + $dbw = wfGetDB( DB_MASTER ); + $dbw->begin(); + + $tbl_pag = $dbw->tableName( 'page' ); + $tbl_rev = $dbw->tableName( 'revision' ); + $res = $dbw->query( "SELECT page_title FROM $tbl_pag WHERE page_namespace = $ns_no" ); + + $n_deleted = 0; + + while( $row = $dbw->fetchObject( $res ) ) { + //echo "$ns_name:".$row->page_title, "\n"; + $title = Title::newFromText($row->page_title, $ns_no); + $id = $title->getArticleID(); + + // Get corresponding revisions + $res2 = $dbw->query( "SELECT rev_id FROM $tbl_rev WHERE rev_page = $id" ); + $revs = array(); + + while( $row2 = $dbw->fetchObject( $res2 ) ) { + $revs[] = $row2->rev_id; + } + $count = count( $revs ); + + //skip anything that looks modified (i.e. multiple revs) + if (($count == 1)) { + #echo $title->getPrefixedText(), "\t", $count, "\n"; + echo "delete: ", $title->getPrefixedText(), "\n"; + + //as much as I hate to cut & paste this, it's a little different, and + //I already have the id & revs + + if( $delete ) { + $dbw->query( "DELETE FROM $tbl_pag WHERE page_id = $id" ); + $dbw->commit(); + // Delete revisions as appropriate + DeleteRevisions( $revs ); + PurgeRedundantText( true ); + $n_deleted ++; + } + } else { + echo "skip: ", $title->getPrefixedText(), "\n"; + } + + + } + $dbw->commit(); + + if ($n_deleted > 0) { + #update statistics - better to decrement existing count, or just count + #the page table? + $pages = $dbw->selectField('site_stats', 'ss_total_pages'); + $pages -= $n_deleted; + $dbw->update( 'site_stats', + array('ss_total_pages' => $pages ), + array( 'ss_row_id' => 1), + __METHOD__ ); + + } + + if (!$delete) { + echo( "To update the database, run the script with the --delete option.\n" ); + } + +} + + +?>
\ No newline at end of file diff --git a/maintenance/nukePage.inc b/maintenance/nukePage.inc index 921faba6..804651b1 100644 --- a/maintenance/nukePage.inc +++ b/maintenance/nukePage.inc @@ -3,8 +3,7 @@ /** * Support functions for the nukeArticle script * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -12,7 +11,7 @@ require_once( 'purgeOldText.inc' ); function NukePage( $name, $delete = false ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->begin(); $tbl_pag = $dbw->tableName( 'page' ); @@ -65,7 +64,7 @@ function NukePage( $name, $delete = false ) { function DeleteRevisions( $ids ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->begin(); $tbl_rev = $dbw->tableName( 'revision' ); @@ -74,6 +73,14 @@ function DeleteRevisions( $ids ) { $dbw->query( "DELETE FROM $tbl_rev WHERE rev_id IN ( $set )" ); $dbw->commit(); + + #TODO: see if this is a "good" page, to decrement that as well. + $pages = $dbw->selectField('site_stats', 'ss_total_pages'); + $pages--; + $dbw->update( 'site_stats', + array('ss_total_pages' => $pages ), + array( 'ss_row_id' => 1), + __METHOD__ ); } diff --git a/maintenance/nukePage.php b/maintenance/nukePage.php index b5c3f283..6ea9e18a 100644 --- a/maintenance/nukePage.php +++ b/maintenance/nukePage.php @@ -4,8 +4,7 @@ * Erase a page record from the database * Irreversible (can't use standard undelete) and does not update link tables * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/ora/tables.sql b/maintenance/ora/tables.sql new file mode 100644 index 00000000..d2436e1d --- /dev/null +++ b/maintenance/ora/tables.sql @@ -0,0 +1,437 @@ +-- SQL to create the initial tables for the MediaWiki database. +-- This is read and executed by the install script; you should +-- not have to run it by itself unless doing a manual install. +-- This is the Oracle version (based on PostgreSQL schema). +-- For information about each table, please see the notes in maintenance/tables.sql + +CREATE SEQUENCE user_user_id_seq MINVALUE 0 START WITH 0; + +CREATE TABLE mwuser ( -- replace reserved word 'user' + user_id INTEGER NOT NULL PRIMARY KEY, + user_name VARCHAR(255) NOT NULL UNIQUE, + user_real_name CLOB, + user_password CLOB, + user_newpassword CLOB, + user_newpass_time TIMESTAMP WITH TIME ZONE, + user_token CHAR(32), + user_email CLOB, + user_email_token CHAR(32), + user_email_token_expires TIMESTAMP WITH TIME ZONE, + user_email_authenticated TIMESTAMP WITH TIME ZONE, + user_options CLOB, + user_touched TIMESTAMP WITH TIME ZONE, + user_registration TIMESTAMP WITH TIME ZONE, + user_editcount INTEGER +); +CREATE INDEX user_email_token_idx ON mwuser (user_email_token); + +-- Create a dummy user to satisfy fk contraints especially with revisions +INSERT INTO mwuser + VALUES (user_user_id_seq.nextval,'Anonymous','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, '', current_timestamp, current_timestamp, 0); + +CREATE TABLE user_groups ( + ug_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE CASCADE, + ug_group CHAR(16) NOT NULL +); +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 VARCHAR(40) NULL +); +CREATE INDEX user_newtalk_id_idx ON user_newtalk (user_id); +CREATE INDEX user_newtalk_ip_idx ON user_newtalk (user_ip); + +CREATE SEQUENCE page_page_id_seq; +CREATE TABLE page ( + page_id INTEGER NOT NULL PRIMARY KEY, + page_namespace SMALLINT NOT NULL, + page_title VARCHAR(255) NOT NULL, + page_restrictions CLOB, + page_counter INTEGER DEFAULT 0 NOT NULL, + page_is_redirect CHAR DEFAULT 0 NOT NULL, + page_is_new CHAR DEFAULT 0 NOT NULL, + page_random NUMERIC(15,14) NOT NULL, + page_touched TIMESTAMP WITH TIME ZONE, + page_latest INTEGER NOT NULL, -- FK? + page_len INTEGER NOT NULL +); +CREATE UNIQUE INDEX page_unique_name ON page (page_namespace, page_title); +CREATE INDEX page_random_idx ON page (page_random); +CREATE INDEX page_len_idx ON page (page_len); + +CREATE TRIGGER page_set_random BEFORE INSERT ON page + FOR EACH ROW WHEN (new.page_random IS NULL) + BEGIN + SELECT dbms_random.value INTO :new.page_random FROM dual; + END; +/ + +CREATE SEQUENCE rev_rev_id_val; +CREATE TABLE revision ( + rev_id INTEGER NOT NULL PRIMARY KEY, + rev_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE, + rev_text_id INTEGER NULL, -- FK + rev_comment CLOB, + rev_user INTEGER NOT NULL REFERENCES mwuser(user_id), + rev_user_text VARCHAR(255) NOT NULL, + rev_timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + rev_minor_edit CHAR DEFAULT '0' NOT NULL, + rev_deleted CHAR DEFAULT '0' NOT NULL, + rev_len INTEGER NULL, + rev_parent_id INTEGER DEFAULT NULL +); +CREATE UNIQUE INDEX revision_unique ON revision (rev_page, rev_id); +CREATE INDEX rev_text_id_idx ON revision (rev_text_id); +CREATE INDEX rev_timestamp_idx ON revision (rev_timestamp); +CREATE INDEX rev_user_idx ON revision (rev_user); +CREATE INDEX rev_user_text_idx ON revision (rev_user_text); + + +CREATE SEQUENCE text_old_id_val; +CREATE TABLE pagecontent ( -- replaces reserved word 'text' + old_id INTEGER NOT NULL PRIMARY KEY, + old_text CLOB, + old_flags CLOB +); + + +CREATE SEQUENCE pr_id_val; +CREATE TABLE page_restrictions ( + pr_id INTEGER NOT NULL UNIQUE, + pr_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE, + pr_type VARCHAR(255) NOT NULL, + pr_level VARCHAR(255) NOT NULL, + pr_cascade SMALLINT NOT NULL, + pr_user INTEGER NULL, + pr_expiry TIMESTAMP WITH TIME ZONE NULL +); +ALTER TABLE page_restrictions ADD CONSTRAINT page_restrictions_pk PRIMARY KEY (pr_page,pr_type); + +CREATE TABLE archive ( + ar_namespace SMALLINT NOT NULL, + ar_title VARCHAR(255) NOT NULL, + ar_text CLOB, + ar_comment CLOB, + ar_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, + ar_user_text CLOB NOT NULL, + ar_timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + ar_minor_edit CHAR DEFAULT '0' NOT NULL, + ar_flags CLOB, + ar_rev_id INTEGER, + ar_text_id INTEGER, + ar_deleted INTEGER DEFAULT '0' NOT NULL +); +CREATE INDEX archive_name_title_timestamp ON archive (ar_namespace,ar_title,ar_timestamp); + +CREATE TABLE redirect ( + rd_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE, + rd_namespace SMALLINT NOT NULL, + rd_title VARCHAR(255) NOT NULL +); +CREATE INDEX redirect_ns_title ON redirect (rd_namespace,rd_title,rd_from); + + +CREATE TABLE pagelinks ( + pl_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE, + pl_namespace SMALLINT NOT NULL, + pl_title VARCHAR(255) NOT NULL +); +CREATE UNIQUE INDEX pagelink_unique ON pagelinks (pl_from,pl_namespace,pl_title); + +CREATE TABLE templatelinks ( + tl_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE, + tl_namespace INTEGER NOT NULL, + tl_title VARCHAR(255) NOT NULL +); +CREATE UNIQUE INDEX templatelinks_unique ON templatelinks (tl_namespace,tl_title,tl_from); + +CREATE TABLE imagelinks ( + il_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE, + il_to VARCHAR(255) NOT NULL +); +CREATE UNIQUE INDEX il_from ON imagelinks (il_to,il_from); + +CREATE TABLE categorylinks ( + cl_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE, + cl_to VARCHAR(255) NOT NULL, + cl_sortkey VARCHAR(86), + cl_timestamp TIMESTAMP WITH TIME ZONE NOT NULL +); +CREATE UNIQUE INDEX cl_from ON categorylinks (cl_from, cl_to); +CREATE INDEX cl_sortkey ON categorylinks (cl_to, cl_sortkey); + +CREATE TABLE externallinks ( + el_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE, + el_to VARCHAR(2048) NOT NULL, + el_index CLOB NOT NULL +); +-- XXX CREATE INDEX externallinks_from_to ON externallinks (el_from,el_to); +-- XXX CREATE INDEX externallinks_index ON externallinks (el_index); + +CREATE TABLE langlinks ( + ll_from INTEGER NOT NULL REFERENCES page (page_id) ON DELETE CASCADE, + ll_lang VARCHAR(10), + ll_title VARCHAR(255) +); +CREATE UNIQUE INDEX langlinks_unique ON langlinks (ll_from,ll_lang); +CREATE INDEX langlinks_lang_title ON langlinks (ll_lang,ll_title); + + +CREATE TABLE site_stats ( + ss_row_id INTEGER NOT NULL UNIQUE, + ss_total_views INTEGER DEFAULT 0, + ss_total_edits INTEGER DEFAULT 0, + ss_good_articles INTEGER DEFAULT 0, + ss_total_pages INTEGER DEFAULT -1, + ss_users INTEGER DEFAULT -1, + ss_admins INTEGER DEFAULT -1, + ss_images INTEGER DEFAULT 0 +); + +CREATE TABLE hitcounter ( + hc_id INTEGER NOT NULL +); + + +CREATE SEQUENCE ipblocks_ipb_id_val; +CREATE TABLE ipblocks ( + ipb_id INTEGER NOT NULL PRIMARY KEY, + ipb_address VARCHAR(255) 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_reason VARCHAR(255) NOT NULL, + ipb_timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + ipb_auto CHAR DEFAULT '0' NOT NULL, + ipb_anon_only CHAR DEFAULT '0' NOT NULL, + ipb_create_account CHAR DEFAULT '1' NOT NULL, + ipb_enable_autoblock CHAR DEFAULT '1' NOT NULL, + ipb_expiry TIMESTAMP WITH TIME ZONE NOT NULL, + ipb_range_start CHAR(8), + ipb_range_end CHAR(8), + ipb_deleted INTEGER DEFAULT '0' NOT NULL +); +CREATE INDEX ipb_address ON ipblocks (ipb_address); +CREATE INDEX ipb_user ON ipblocks (ipb_user); +CREATE INDEX ipb_range ON ipblocks (ipb_range_start,ipb_range_end); + + +CREATE TABLE image ( + img_name VARCHAR(255) NOT NULL PRIMARY KEY, + img_size INTEGER NOT NULL, + img_width INTEGER NOT NULL, + img_height INTEGER NOT NULL, + img_metadata CLOB, + img_bits SMALLINT, + img_media_type CLOB, + img_major_mime CLOB DEFAULT 'unknown', + img_minor_mime CLOB DEFAULT 'unknown', + img_description CLOB NOT NULL, + img_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, + img_user_text CLOB NOT NULL, + img_timestamp TIMESTAMP WITH TIME ZONE +); +CREATE INDEX img_size_idx ON image (img_size); +CREATE INDEX img_timestamp_idx ON image (img_timestamp); + +CREATE TABLE oldimage ( + oi_name VARCHAR(255) NOT NULL REFERENCES image(img_name), + oi_archive_name VARCHAR(255) NOT NULL, + oi_size INTEGER NOT NULL, + oi_width INTEGER NOT NULL, + oi_height INTEGER NOT NULL, + oi_bits SMALLINT NOT NULL, + oi_description CLOB, + oi_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, + oi_user_text CLOB NOT NULL, + oi_timestamp TIMESTAMP WITH TIME ZONE NOT NULL +); +CREATE INDEX oi_name ON oldimage (oi_name); + +CREATE SEQUENCE filearchive_fa_id_seq; +CREATE TABLE filearchive ( + fa_id INTEGER NOT NULL PRIMARY KEY, + fa_name VARCHAR(255) NOT NULL, + fa_archive_name VARCHAR(255), + fa_storage_group VARCHAR(16), + fa_storage_key CHAR(64), + fa_deleted_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, + fa_deleted_timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + fa_deleted_reason CLOB, + fa_size SMALLINT NOT NULL, + fa_width SMALLINT NOT NULL, + fa_height SMALLINT NOT NULL, + fa_metadata CLOB, + fa_bits SMALLINT, + fa_media_type CLOB, + fa_major_mime CLOB DEFAULT 'unknown', + fa_minor_mime CLOB DEFAULT 'unknown', + fa_description CLOB NOT NULL, + fa_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, + fa_user_text CLOB NOT NULL, + fa_timestamp TIMESTAMP WITH TIME ZONE, + fa_deleted INTEGER DEFAULT '0' NOT NULL +); +CREATE INDEX fa_name_time ON filearchive (fa_name, fa_timestamp); +CREATE INDEX fa_dupe ON filearchive (fa_storage_group, fa_storage_key); +CREATE INDEX fa_notime ON filearchive (fa_deleted_timestamp); +CREATE INDEX fa_nouser ON filearchive (fa_deleted_user); + + +CREATE SEQUENCE rc_rc_id_seq; +CREATE TABLE recentchanges ( + rc_id INTEGER NOT NULL PRIMARY KEY, + rc_timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + rc_cur_time TIMESTAMP WITH TIME ZONE NOT NULL, + rc_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, + rc_user_text CLOB NOT NULL, + rc_namespace SMALLINT NOT NULL, + rc_title VARCHAR(255) NOT NULL, + rc_comment VARCHAR(255), + rc_minor CHAR DEFAULT '0' NOT NULL, + rc_bot CHAR DEFAULT '0' NOT NULL, + rc_new CHAR DEFAULT '0' NOT NULL, + rc_cur_id INTEGER NULL REFERENCES page(page_id) ON DELETE SET NULL, + rc_this_oldid INTEGER NOT NULL, + rc_last_oldid INTEGER NOT NULL, + rc_type CHAR DEFAULT '0' NOT NULL, + rc_moved_to_ns SMALLINT, + rc_moved_to_title CLOB, + rc_patrolled CHAR DEFAULT '0' NOT NULL, + rc_ip VARCHAR(15), + rc_old_len INTEGER, + rc_new_len INTEGER, + rc_deleted INTEGER DEFAULT '0' NOT NULL, + rc_logid INTEGER DEFAULT '0' NOT NULL, + rc_log_type CLOB, + rc_log_action CLOB, + rc_params CLOB +); +CREATE INDEX rc_timestamp ON recentchanges (rc_timestamp); +CREATE INDEX rc_namespace_title ON recentchanges (rc_namespace, rc_title); +CREATE INDEX rc_cur_id ON recentchanges (rc_cur_id); +CREATE INDEX new_name_timestamp ON recentchanges (rc_new, rc_namespace, rc_timestamp); +CREATE INDEX rc_ip ON recentchanges (rc_ip); + + +CREATE TABLE watchlist ( + wl_user INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE CASCADE, + wl_namespace SMALLINT DEFAULT 0 NOT NULL, + wl_title VARCHAR(255) NOT NULL, + wl_notificationtimestamp TIMESTAMP WITH TIME ZONE +); +CREATE UNIQUE INDEX wl_user_namespace_title ON watchlist (wl_namespace, wl_title, wl_user); + + +CREATE TABLE math ( + math_inputhash VARCHAR(16) NOT NULL UNIQUE, + math_outputhash VARCHAR(16) NOT NULL, + math_html_conservativeness SMALLINT NOT NULL, + math_html CLOB, + math_mathml CLOB +); + + +CREATE TABLE interwiki ( + iw_prefix VARCHAR(32) NOT NULL UNIQUE, + iw_url VARCHAR(127) NOT NULL, + iw_local CHAR NOT NULL, + iw_trans CHAR DEFAULT '0' NOT NULL +); + +CREATE TABLE querycache ( + qc_type CHAR(32) NOT NULL, + qc_value SMALLINT NOT NULL, + qc_namespace SMALLINT NOT NULL, + qc_title CHAR(255) NOT NULL +); +CREATE INDEX querycache_type_value ON querycache (qc_type, qc_value); + +CREATE TABLE querycache_info ( + qci_type VARCHAR(32) UNIQUE, + qci_timestamp TIMESTAMP WITH TIME ZONE NULL +); + +CREATE TABLE querycachetwo ( + qcc_type CHAR(32) NOT NULL, + qcc_value SMALLINT DEFAULT 0 NOT NULL, + qcc_namespace INTEGER DEFAULT 0 NOT NULL, + qcc_title CHAR(255) DEFAULT '' NOT NULL, + qcc_namespacetwo INTEGER DEFAULT 0 NOT NULL, + qcc_titletwo CHAR(255) DEFAULT '' NOT NULL +); +CREATE INDEX querycachetwo_type_value ON querycachetwo (qcc_type, qcc_value); +CREATE INDEX querycachetwo_title ON querycachetwo (qcc_type,qcc_namespace,qcc_title); +CREATE INDEX querycachetwo_titletwo ON querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo); + + +CREATE TABLE objectcache ( + keyname CHAR(255) UNIQUE, + value BLOB, + exptime TIMESTAMP WITH TIME ZONE NOT NULL +); +CREATE INDEX objectcacache_exptime ON objectcache (exptime); + +CREATE TABLE transcache ( + tc_url VARCHAR(255) NOT NULL UNIQUE, + tc_contents CLOB NOT NULL, + tc_time TIMESTAMP WITH TIME ZONE NOT NULL +); + + +CREATE SEQUENCE log_log_id_seq; +CREATE TABLE logging ( + log_type VARCHAR(10) NOT NULL, + log_action VARCHAR(10) NOT NULL, + log_timestamp TIMESTAMP WITH TIME ZONE NOT NULL, + log_user INTEGER REFERENCES mwuser(user_id) ON DELETE SET NULL, + log_namespace SMALLINT NOT NULL, + log_title VARCHAR(255) NOT NULL, + log_comment VARCHAR(255), + log_params CLOB, + log_deleted INTEGER DEFAULT '0' NOT NULL, + log_id INTEGER NOT NULL PRIMARY KEY +); +CREATE INDEX logging_type_name ON logging (log_type, log_timestamp); +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 INTEGER NOT NULL PRIMARY KEY, + tb_page INTEGER REFERENCES page(page_id) ON DELETE CASCADE, + tb_title VARCHAR(255) NOT NULL, + tb_url VARCHAR(255) NOT NULL, + tb_ex CLOB, + tb_name VARCHAR(255) +); +CREATE INDEX trackback_page ON trackbacks (tb_page); + +CREATE SEQUENCE job_job_id_seq; +CREATE TABLE job ( + job_id INTEGER NOT NULL PRIMARY KEY, + job_cmd VARCHAR(255) NOT NULL, + job_namespace SMALLINT NOT NULL, + job_title VARCHAR(255) NOT NULL, + job_params CLOB NOT NULL +); +CREATE INDEX job_cmd_namespace_title ON job (job_cmd, job_namespace, job_title); + +-- This table is not used unless profiling is turned on +--CREATE TABLE profiling ( +-- pf_count INTEGER DEFAULT 0 NOT NULL, +-- pf_time NUMERIC(18,10) DEFAULT 0 NOT NULL, +-- pf_name CLOB NOT NULL, +-- pf_server CLOB NULL +--); +--CREATE UNIQUE INDEX pf_name_server ON profiling (pf_name, pf_server); + +CREATE TABLE searchindex ( + si_page INTEGER UNIQUE NOT NULL, + si_title VARCHAR(255) DEFAULT '' NOT NULL, + si_text CLOB NOT NULL +); + + +CREATE INDEX si_title_idx ON searchindex(si_title) INDEXTYPE IS ctxsys.context; +CREATE INDEX si_text_idx ON searchindex(si_text) INDEXTYPE IS ctxsys.context; diff --git a/maintenance/orphans.php b/maintenance/orphans.php index 3bfa79f5..0729a239 100644 --- a/maintenance/orphans.php +++ b/maintenance/orphans.php @@ -24,8 +24,7 @@ * Man this is depressing. * * @author <brion@pobox.com> - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ $options = array( 'fix' ); @@ -41,7 +40,7 @@ checkSeparation( isset( $options['fix'] ) ); # ------ function checkOrphans( $fix ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $page = $dbw->tableName( 'page' ); $revision = $dbw->tableName( 'revision' ); @@ -92,7 +91,7 @@ function checkOrphans( $fix ) { * but valid revisions do exist) */ function checkWidows( $fix ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $page = $dbw->tableName( 'page' ); $revision = $dbw->tableName( 'revision' ); @@ -135,7 +134,7 @@ function checkWidows( $fix ) { function checkSeparation( $fix ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $page = $dbw->tableName( 'page' ); $revision = $dbw->tableName( 'revision' ); $text = $dbw->tableName( 'text' ); diff --git a/maintenance/ourusers.php b/maintenance/ourusers.php index 9b7af605..cd5f8ff3 100644 --- a/maintenance/ourusers.php +++ b/maintenance/ourusers.php @@ -1,8 +1,7 @@ <?php /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/parserTests.inc b/maintenance/parserTests.inc index c85220d0..ddf8b89a 100644 --- a/maintenance/parserTests.inc +++ b/maintenance/parserTests.inc @@ -20,8 +20,7 @@ /** * @todo Make this more independent of the configuration (and if possible the database) * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -29,46 +28,32 @@ $options = array( 'quick', 'color', 'quiet', 'help', 'show-output', 'record' ); $optionsWithArgs = array( 'regex' ); require_once( 'commandLine.inc' ); -require_once( "$IP/includes/ObjectCache.php" ); -require_once( "$IP/includes/BagOStuff.php" ); -require_once( "$IP/includes/Hooks.php" ); require_once( "$IP/maintenance/parserTestsParserHook.php" ); require_once( "$IP/maintenance/parserTestsStaticParserHook.php" ); require_once( "$IP/maintenance/parserTestsParserTime.php" ); /** - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ class ParserTest { /** * boolean $color whereas output should be colorized - * @private */ - var $color; - - /** - * boolean $lightcolor whereas output should use light colors - * @private - */ - var $lightcolor; + private $color; /** * boolean $showOutput Show test output */ - var $showOutput; + private $showOutput; /** * Sets terminal colorization and diff/quick modes depending on OS and * command-line options (--color and --quick). - * - * @public */ - function ParserTest() { + public function ParserTest() { global $options; # Only colorize output if stdout is a terminal. - $this->lightcolor = false; $this->color = !wfIsWindows() && posix_isatty(1); if( isset( $options['color'] ) ) { @@ -76,9 +61,6 @@ class ParserTest { case 'no': $this->color = false; break; - case 'light': - $this->lightcolor = true; - # Fall through case 'yes': default: $this->color = true; @@ -86,11 +68,16 @@ class ParserTest { } } $this->term = $this->color - ? new AnsiTermColorer( $this->lightcolor ) + ? new AnsiTermColorer() : new DummyTermColorer(); $this->showDiffs = !isset( $options['quick'] ); - $this->quiet = isset( $options['quiet'] ); + $this->showProgress = !isset( $options['quiet'] ); + $this->showFailure = !( + isset( $options['quiet'] ) + && ( isset( $options['record'] ) + || isset( $options['compare'] ) ) ); // redundant output + $this->showOutput = isset( $options['show-output'] ); @@ -100,22 +87,23 @@ class ParserTest { # Matches anything $this->regex = ''; } - + if( isset( $options['record'] ) ) { $this->recorder = new DbTestRecorder( $this->term ); + } elseif( isset( $options['compare'] ) ) { + $this->recorder = new DbTestPreviewer( $this->term ); } else { $this->recorder = new TestRecorder( $this->term ); } - + $this->hooks = array(); $this->functionHooks = array(); } /** * Remove last character if it is a newline - * @private */ - function chomp($s) { + private function chomp($s) { if (substr($s, -1) === "\n") { return substr($s, 0, -1); } @@ -134,26 +122,27 @@ class ParserTest { * * @param array of strings $filenames * @return bool True if passed all tests, false if any tests failed. - * @public */ - function runTestsFromFiles( $filenames ) { + public function runTestsFromFiles( $filenames ) { $this->recorder->start(); $ok = true; foreach( $filenames as $filename ) { $ok = $this->runFile( $filename ) && $ok; } - $this->recorder->end(); $this->recorder->report(); + $this->recorder->end(); return $ok; } - + private function runFile( $filename ) { $infile = fopen( $filename, 'rt' ); if( !$infile ) { wfDie( "Couldn't open $filename\n" ); } else { + global $IP; + $relative = wfRelativePath( $filename, $IP ); print $this->term->color( 1 ) . - "Reading tests from \"$filename\"..." . + "Reading tests from \"$relative\"..." . $this->term->reset() . "\n"; } @@ -164,6 +153,7 @@ class ParserTest { $ok = true; while( false !== ($line = fgets( $infile ) ) ) { $n++; + $matches = array(); if( preg_match( '/^!!\s*(\w+)/', $line, $matches ) ) { $section = strtolower( $matches[1] ); if( $section == 'endarticle') { @@ -250,7 +240,9 @@ class ParserTest { $data[$section] .= $line; } } - print "\n"; + if ( $this->showProgress ) { + print "\n"; + } return $ok; } @@ -263,8 +255,8 @@ class ParserTest { * @param string $result Result to output * @return bool */ - function runTest( $desc, $input, $result, $opts ) { - if( !$this->quiet ) { + private function runTest( $desc, $input, $result, $opts ) { + if( $this->showProgress ) { $this->showTesting( $desc ); } @@ -278,6 +270,7 @@ class ParserTest { $options->setUseTex(true); } + $m = array(); if (preg_match('/title=\[\[(.*)\]\]/', $opts, $m)) { $titleText = $m[1]; } @@ -295,9 +288,10 @@ class ParserTest { $parser->setFunctionHook( $tag, $callback ); } wfRunHooks( 'ParserTestParser', array( &$parser ) ); - + $title =& Title::makeTitle( NS_MAIN, $titleText ); + $matches = array(); if (preg_match('/\\bpst\\b/i', $opts)) { $out = $parser->preSaveTransform( $input, $title, $user, $options ); } elseif (preg_match('/\\bmsg\\b/i', $opts)) { @@ -336,12 +330,10 @@ class ParserTest { /** * Set up the global variables for a consistent environment for each test. * Ideally this should replace the global configuration entirely. - * - * @private */ - function setupGlobals($opts = '') { + private function setupGlobals($opts = '') { # Save the prefixed / quoted table names for later use when we make the temporaries. - $db =& wfGetDB( DB_READ ); + $db = wfGetDB( DB_READ ); $this->oldTableNames = array(); foreach( $this->listTables() as $table ) { $this->oldTableNames[$table] = $db->tableName( $table ); @@ -349,17 +341,19 @@ class ParserTest { if( !isset( $this->uploadDir ) ) { $this->uploadDir = $this->setupUploadDir(); } - + + $m = array(); if( preg_match( '/language=([a-z]+(?:_[a-z]+)?)/', $opts, $m ) ) { $lang = $m[1]; } else { $lang = 'en'; } - if( preg_match( '/variant=([a-z]+(?:-[a-z]+)?)/', $opts, $m ) ) + if( preg_match( '/variant=([a-z]+(?:-[a-z]+)?)/', $opts, $m ) ) { $variant = $m[1]; - else + } else { $variant = false; + } $settings = array( @@ -408,10 +402,12 @@ class ParserTest { $wgUser = new User(); } - # List of temporary tables to create, without prefix - # Some of these probably aren't necessary - function listTables() { - $tables = array('user', 'page', 'revision', 'text', + /** + * List of temporary tables to create, without prefix. + * Some of these probably aren't necessary. + */ + private function listTables() { + $tables = array('user', 'page', 'page_restrictions', 'revision', 'text', 'pagelinks', 'imagelinks', 'categorylinks', 'templatelinks', 'externallinks', 'langlinks', 'site_stats', 'hitcounter', @@ -422,14 +418,11 @@ class ParserTest { 'objectcache', 'job', 'redirect', 'querycachetwo' ); - - // FIXME manually adding additional table for the tasks extension - // we probably need a better software wide system to register new - // tables. - global $wgExtensionFunctions; - if( in_array('wfTasksExtension' , $wgExtensionFunctions ) ) { - $tables[] = 'tasks'; - } + + // Allow extensions to add to the list of tables to duplicate; + // may be necessary if they hook into page save or other code + // which will require them while running tests. + wfRunHooks( 'ParserTestTables', array( &$tables ) ); return $tables; } @@ -438,10 +431,8 @@ class ParserTest { * Set up a temporary set of wiki tables to work with for the tests. * Currently this will only be done once per run, and any changes to * the db will be visible to later tests in the run. - * - * @private */ - function setupDatabase() { + private function setupDatabase() { static $setupDB = false; global $wgDBprefix; @@ -449,7 +440,7 @@ class ParserTest { if (!$setupDB && $wgDBprefix === 'parsertest_') { # oh teh horror $GLOBALS['wgLoadBalancer'] = LoadBalancer::newFromParams( $GLOBALS['wgDBservers'] ); - $db =& wfGetDB( DB_MASTER ); + $db = wfGetDB( DB_MASTER ); $tables = $this->listTables(); @@ -525,7 +516,7 @@ class ParserTest { '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 ) ); @@ -537,9 +528,8 @@ class ParserTest { * Create a dummy uploads directory which will contain a couple * of files in order to pass existence tests. * @return string The directory - * @private */ - function setupUploadDir() { + private function setupUploadDir() { global $IP; $dir = wfTempDir() . "/mwParser-" . mt_rand() . "-images"; @@ -561,10 +551,8 @@ class ParserTest { /** * Restore default values and perform any necessary clean-up * after each test runs. - * - * @private */ - function teardownGlobals() { + private function teardownGlobals() { foreach( $this->savedGlobals as $var => $val ) { $GLOBALS[$var] = $val; } @@ -576,11 +564,10 @@ class ParserTest { /** * Remove the dummy uploads directory - * @private */ - function teardownUploadDir( $dir ) { + private function teardownUploadDir( $dir ) { // delete the files first, then the dirs. - self::deleteFiles( + self::deleteFiles( array ( "$dir/3/3a/Foobar.jpg", "$dir/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg", @@ -589,9 +576,9 @@ class ParserTest { "$dir/thumb/3/3a/Foobar.jpg/120px-Foobar.jpg", ) ); - + self::deleteDirs( - array ( + array ( "$dir/3/3a", "$dir/3", "$dir/thumb/6/65", @@ -616,7 +603,7 @@ class ParserTest { } } } - + /** * @desc delete the specified directories, if they exist. Must be empty. * @param array $dirs full paths to directories to delete. @@ -628,12 +615,11 @@ class ParserTest { } } } - + /** * "Running test $desc..." - * @private */ - function showTesting( $desc ) { + private function showTesting( $desc ) { print "Running test $desc... "; } @@ -642,10 +628,9 @@ class ParserTest { * * @param string $desc The test name * @return bool - * @private */ - function showSuccess( $desc ) { - if( !$this->quiet ) { + private function showSuccess( $desc ) { + if( $this->showProgress ) { print $this->term->color( '1;32' ) . 'PASSED' . $this->term->reset() . "\n"; } return true; @@ -659,22 +644,23 @@ class ParserTest { * @param string $result Expected HTML output * @param string $html Actual HTML output * @return bool - * @private */ - function showFailure( $desc, $result, $html ) { - if( $this->quiet ) { - # In quiet mode we didn't show the 'Testing' message before the - # test, in case it succeeded. Show it now: - $this->showTesting( $desc ); - } - print $this->term->color( '1;31' ) . 'FAILED!' . $this->term->reset() . "\n"; - if ( $this->showOutput ) { - print "--- Expected ---\n$result\n--- Actual ---\n$html\n"; - } - if( $this->showDiffs ) { - print $this->quickDiff( $result, $html ); - if( !$this->wellFormed( $html ) ) { - print "XML error: $this->mXmlError\n"; + private function showFailure( $desc, $result, $html ) { + if( $this->showFailure ) { + if( !$this->showProgress ) { + # In quiet mode we didn't show the 'Testing' message before the + # test, in case it succeeded. Show it now: + $this->showTesting( $desc ); + } + print $this->term->color( '31' ) . 'FAILED!' . $this->term->reset() . "\n"; + if ( $this->showOutput ) { + print "--- Expected ---\n$result\n--- Actual ---\n$html\n"; + } + if( $this->showDiffs ) { + print $this->quickDiff( $result, $html ); + if( !$this->wellFormed( $html ) ) { + print "XML error: $this->mXmlError\n"; + } } } return false; @@ -689,9 +675,8 @@ class ParserTest { * @param string $inFileTail Tailing for the input file name * @param string $outFileTail Tailing for the output file name * @return string - * @private */ - function quickDiff( $input, $output, $inFileTail='expected', $outFileTail='actual' ) { + private function quickDiff( $input, $output, $inFileTail='expected', $outFileTail='actual' ) { $prefix = wfTempDir() . "/mwParser-" . mt_rand(); $infile = "$prefix-$inFileTail"; @@ -712,9 +697,8 @@ class ParserTest { * * @param string $data * @param string $filename - * @private */ - function dumpToFile( $data, $filename ) { + private function dumpToFile( $data, $filename ) { $file = fopen( $filename, "wt" ); fwrite( $file, $data . "\n" ); fclose( $file ); @@ -726,9 +710,8 @@ class ParserTest { * * @param string $text * @return string - * @private */ - function colorDiff( $text ) { + private function colorDiff( $text ) { return preg_replace( array( '/^(-.*)$/m', '/^(\+.*)$/m' ), array( $this->term->color( 34 ) . '$1' . $this->term->reset(), @@ -741,9 +724,8 @@ class ParserTest { * @param string $name the title, including any prefix * @param string $text the article text * @param int $line the input line number, for reporting errors - * @private */ - function addArticle($name, $text, $line) { + private function addArticle($name, $text, $line) { $this->setupGlobals(); $title = Title::newFromText( $name ); if ( is_null($title) ) { @@ -759,7 +741,7 @@ class ParserTest { $art->insertNewArticle($text, '', false, false ); $this->teardownGlobals(); } - + /** * Steal a callback function from the primary parser, save it for * application to our scary parser. If the hook is not installed, @@ -775,7 +757,6 @@ class ParserTest { } } - /** * Steal a callback function from the primary parser, save it for * application to our scary parser. If the hook is not installed, @@ -798,9 +779,8 @@ class ParserTest { * @param string $text the text to tidy * @return string * @static - * @private */ - function tidy( $text ) { + private function tidy( $text ) { global $wgUseTidy; if ($wgUseTidy) { $text = Parser::tidy($text); @@ -808,7 +788,7 @@ class ParserTest { return $text; } - function wellFormed( $text ) { + private function wellFormed( $text ) { $html = Sanitizer::hackDocType() . '<html>' . @@ -832,7 +812,7 @@ class ParserTest { return true; } - function extractFragment( $text, $position ) { + private function extractFragment( $text, $position ) { $start = max( 0, $position - 10 ); $before = $position - $start; $fragment = '...' . @@ -855,23 +835,21 @@ class ParserTest { $this->term->color( 0 ); return "$display\n$caret"; } - } class AnsiTermColorer { - function __construct( $light ) { - $this->light = $light; + function __construct() { } - + /** * Return ANSI terminal escape code for changing text attribs/color * * @param string $color Semicolon-separated list of attribute/color codes * @return string - * @private */ - function color( $color ) { - $light = $this->light ? "1;" : ""; + public function color( $color ) { + global $wgCommandLineDarkBg; + $light = $wgCommandLineDarkBg ? "1;" : "0;"; return "\x1b[{$light}{$color}m"; } @@ -879,20 +857,19 @@ class AnsiTermColorer { * Return ANSI terminal escape code for restoring default text attributes * * @return string - * @private */ - function reset() { - return "\x1b[0m"; + public function reset() { + return $this->color( 0 ); } } /* A colour-less terminal */ class DummyTermColorer { - function color( $color ) { + public function color( $color ) { return ''; } - - function reset() { + + public function reset() { return ''; } } @@ -901,21 +878,21 @@ class TestRecorder { function __construct( $term ) { $this->term = $term; } - + function start() { $this->total = 0; $this->success = 0; } - + function record( $test, $result ) { $this->total++; $this->success += ($result ? 1 : 0); } - + function end() { // dummy } - + function report() { if( $this->total > 0 ) { $this->reportPercentage( $this->success, $this->total ); @@ -923,14 +900,15 @@ class TestRecorder { wfDie( "No tests found.\n" ); } } - + function reportPercentage( $success, $total ) { $ratio = wfPercent( 100 * $success / $total ); print $this->term->color( 1 ) . "Passed $success of $total tests ($ratio)... "; if( $success == $total ) { - print $this->term->color( 32 ) . "PASSED!"; + print $this->term->color( 32 ) . "ALL TESTS PASSED!"; } else { - print $this->term->color( 31 ) . "FAILED!"; + $failed = $total - $success ; + print $this->term->color( 31 ) . "$failed tests failed!"; } print $this->term->reset() . "\n"; return ($success == $total); @@ -938,27 +916,33 @@ class TestRecorder { } class DbTestRecorder extends TestRecorder { - private $db; ///< Database connection to the main DB - private $curRun; ///< run ID number for the current run - private $prevRun; ///< run ID number for the previous run, if any - + 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 + function __construct( $term ) { parent::__construct( $term ); $this->db = wfGetDB( DB_MASTER ); } - + /** * Set up result recording; insert a record for the run with the date * and all that fun stuff */ function start() { 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"; + dbsource( 'testRunner.sql', $this->db ); + echo "OK, resuming.\n"; + } + // 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(), @@ -970,7 +954,7 @@ class DbTestRecorder extends TestRecorder { __METHOD__ ); $this->curRun = $this->db->insertId(); } - + /** * Record an individual test item's success or failure to the db * @param string $test @@ -986,7 +970,7 @@ class DbTestRecorder extends TestRecorder { ), __METHOD__ ); } - + /** * Commit transaction and clean up for result recording */ @@ -994,38 +978,40 @@ class DbTestRecorder extends TestRecorder { $this->db->commit(); parent::end(); } - + function report() { if( $this->prevRun ) { $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 ), ); foreach( $table as $criteria ) { list( $label, $before, $after ) = $criteria; $differences = $this->compareResult( $before, $after ); if( $differences ) { $count = count($differences); - printf( "%4d %s\n", $count, $label ); - foreach ($differences as $differing_test_name) { - print " * $differing_test_name\n"; + printf( "\n%4d %s\n", $count, $label ); + foreach ($differences as $differing_test_name => $statusInfo) { + print " * $differing_test_name [$statusInfo]\n"; } } } } else { print "No previous test runs to compare against.\n"; } + print "\n"; parent::report(); } - + /** - ** @desc: Returns an array of the test names with changed results, based on the specified - ** before/after criteria. + ** 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' ); @@ -1033,7 +1019,7 @@ class DbTestRecorder extends TestRecorder { $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 = " @@ -1055,14 +1041,77 @@ class DbTestRecorder extends TestRecorder { $result = $this->db->query( $sql, __METHOD__ ); $retval = array(); while ($row = $this->db->fetchObject( $result )) { - $retval[] = $row->t; + $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) { + + // If we're looking at a test that has just been removed, then say when it first appeared. + if ( is_null( $after ) ) { + $changedRun = $this->db->selectField ( 'testitem', + 'MIN(ti_run)', + array( 'ti_name' => $testname ), + __METHOD__ ); + $appear = $this->db->selectRow ( 'testrun', + array( 'tr_date', 'tr_mw_version' ), + array( 'tr_id' => $changedRun ), + __METHOD__ ); + return "First recorded appearance: " + . date( "d-M-Y H:i:s", strtotime ( $appear->tr_date ) ) + . ", " . $appear->tr_mw_version; + } + + // 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__ ); + + // If no record of ever having had a different result. + if ( is_null ( $changedRun ) ) { + if ($after == "0") { + return "Has never passed"; + } else { + return "Has never failed"; + } + } + + // Otherwise, we're looking at a test whose status has changed. + // (i.e. it used to work, but now doesn't; or used to fail, but is now fixed.) + // In this situation, give as much info as we can as to when it changed status. + $pre = $this->db->selectRow ( 'testrun', + array( 'tr_date', 'tr_mw_version' ), + array( 'tr_id' => $changedRun ), + __METHOD__ ); + $post = $this->db->selectRow ( 'testrun', + array( 'tr_date', 'tr_mw_version' ), + array( "tr_id > " . $this->db->addQuotes ( $changedRun) ), + __METHOD__, + array( "LIMIT" => 1, "ORDER BY" => 'tr_id' ) + ); + + return ( $after == "0" ? "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 ; + } + /** - ** @desc: Helper function for compareResult() database querying. + ** Helper function for compareResult() database querying. */ private function condition( $value ) { if( is_null( $value ) ) { @@ -1074,4 +1123,14 @@ class DbTestRecorder extends TestRecorder { } +class DbTestPreviewer extends DbTestRecorder { + /** + * Commit transaction and clean up for result recording + */ + function end() { + $this->db->rollback(); + TestRecorder::end(); + } +} + ?> diff --git a/maintenance/parserTests.php b/maintenance/parserTests.php index bd147788..540d6b08 100644 --- a/maintenance/parserTests.php +++ b/maintenance/parserTests.php @@ -18,8 +18,7 @@ # http://www.gnu.org/copyleft/gpl.html /** - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -29,17 +28,20 @@ if( isset( $options['help'] ) ) { echo <<<ENDS MediaWiki $wgVersion parser test suite Usage: php parserTests.php [--quick] [--quiet] [--show-output] - [--color[=(yes|no|light)]] + [--color[=(yes|no)]] [--regex=<expression>] [--file=<testfile>] + [--record] [--compare] [--help] Options: --quick Suppress diff output of failed tests --quiet Suppress notification of passed tests (shows only failed tests) --show-output Show expected and actual output --color Override terminal detection and force color output on or off - 'light' option is similar to 'yes' but with color for dark backgrounds + use wgCommandLineDarkBg = true; if your term is dark --regex Only run tests whose descriptions which match given regex --file Run test cases from a custom file instead of parserTests.txt + --record Record tests in database + --compare Compare with recorded results, without updating the database. --help Show this help message @@ -62,7 +64,7 @@ if( isset( $options['file'] ) ) { # Print out software version to assist with locating regressions $version = SpecialVersion::getVersion(); -echo( "This is MediaWiki version {$version}.\n" ); +echo( "This is MediaWiki version {$version}.\n\n" ); $ok = $tester->runTestsFromFiles( $files ); exit ($ok ? 0 : -1); diff --git a/maintenance/parserTests.txt b/maintenance/parserTests.txt index 3d748aef..72e01362 100644 --- a/maintenance/parserTests.txt +++ b/maintenance/parserTests.txt @@ -255,7 +255,7 @@ everything starting with < followed by !-- until the first -- and > we see, that wouldn't be valid XML however, since in XML -- has to terminate a comment -->--> !! result -<p>--> +<p>--> </p> !! end @@ -264,7 +264,7 @@ Comment semantics: nesting !! input <!--<!-- no, we're not going to do anything fancy here -->--> !! result -<p>--> +<p>--> </p> !! end @@ -983,7 +983,23 @@ External link containing double-single-quotes in text embedded in italics (bug 4 </p> !! end +!! test +URL-encoding in URL functions (single parameter) +!! input +{{localurl:Some page|amp=&}} +!! result +<p>/index.php?title=Some_page&amp=%26 +</p> +!! end +!! test +URL-encoding in URL functions (multiple parameters) +!! input +{{localurl:Some page|q=?&=&}} +!! result +<p>/index.php?title=Some_page&q=%3F&amp=%26 +</p> +!! end ### ### Quotes @@ -1211,7 +1227,7 @@ Invalid attributes in table cell (bug 1830) # FIXME: this one has incorrect tag nesting still. !! test -TODO: Table security: embedded pipes (http://mail.wikipedia.org/pipermail/wikitech-l/2006-April/034637.html) +Table security: embedded pipes (http://mail.wikipedia.org/pipermail/wikitech-l/2006-April/034637.html) !! input {| | |[ftp://|x||]" onmouseover="alert(document.cookie)">test @@ -1384,7 +1400,7 @@ Link containing "<#" and ">#" as a hex sequences !! end !! test -TODO: Link containing double-single-quotes '' (bug 4598) +Link containing double-single-quotes '' (bug 4598) !! input [[Lista d''e paise d''o munno]] !! result @@ -1470,6 +1486,34 @@ title=[[Main Page]] </p> !! end +!! article +00 +!! text +This is 00. +!! endarticle + +!!test +Self-link to numeric title +!!options +title=[[0]] +!!input +[[0]] +!!result +<p><strong class="selflink">0</strong> +</p> +!!end + +!!test +Link to numeric-equivalent title +!!options +title=[[0]] +!!input +[[00]] +!!result +<p><a href="/wiki/00" title="00">00</a> +</p> +!!end + !! test <nowiki> inside a link !! input @@ -1522,6 +1566,53 @@ Interwiki link with fragment (bug 2130) </p> !! end +!! test +Interlanguage link +!! input +Blah blah blah +[[zh:Chinese]] +!!result +<p>Blah blah blah +</p> +!! end + +!! test +Double interlanguage link +!! input +Blah blah blah +[[es:Spanish]] +[[zh:Chinese]] +!!result +<p>Blah blah blah +</p> +!! end + +!! test +Interlanguage link, with prefix links +!! options +language=ln +!! input +Blah blah blah +[[zh:Chinese]] +!!result +<p>Blah blah blah +</p> +!! end + +!! test +Double interlanguage link, with prefix links (bug 8897) +!! options +language=ln +!! input +Blah blah blah +[[es:Spanish]] +[[zh:Chinese]] +!!result +<p>Blah blah blah +</p> +!! end + + ## ## XHTML tidiness ### @@ -1963,7 +2054,7 @@ Magic links: RFC (bug 479) !! input RFC 822 !! result -<p><a href="http://www.ietf.org/rfc/rfc822.txt" class="external" title="http://www.ietf.org/rfc/rfc822.txt">RFC 822</a> +<p><a href="http://tools.ietf.org/html/rfc822" class="external" title="http://tools.ietf.org/html/rfc822">RFC 822</a> </p> !! end @@ -2808,7 +2899,7 @@ msg !! end !! test -TODO: message transform: <noinclude> in transcluded template (bug 4926) +message transform: <noinclude> in transcluded template (bug 4926) !! options msg !! input @@ -2818,7 +2909,7 @@ Foobar !! end !! test -TODO: message transform: <onlyinclude> in transcluded template (bug 4926) +message transform: <onlyinclude> in transcluded template (bug 4926) !! options msg !! input @@ -2855,7 +2946,7 @@ Simple image !! input [[Image:foobar.jpg]] !! result -<p><a href="/wiki/Image:Foobar.jpg" class="image" title="Image:foobar.jpg"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="Image:foobar.jpg" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="/wiki/Image:Foobar.jpg" class="image" title="Image:foobar.jpg"><img alt="Image:foobar.jpg" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! end @@ -2864,7 +2955,7 @@ Right-aligned image !! input [[Image:foobar.jpg|right]] !! result -<div class="floatright"><span><a href="/wiki/Image:Foobar.jpg" class="image" title=""><img src="http://example.com/images/3/3a/Foobar.jpg" alt="" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a></span></div> +<div class="floatright"><span><a href="/wiki/Image:Foobar.jpg" class="image" title=""><img alt="" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></span></div> !! end @@ -2873,7 +2964,7 @@ Image with caption !! input [[Image:foobar.jpg|right|Caption text]] !! result -<div class="floatright"><span><a href="/wiki/Image:Foobar.jpg" class="image" title="Caption text"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="Caption text" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a></span></div> +<div class="floatright"><span><a href="/wiki/Image:Foobar.jpg" class="image" title="Caption text"><img alt="Caption text" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></span></div> !! end @@ -2882,13 +2973,13 @@ Image with frame and link !! input [[Image:Foobar.jpg|frame|left|This is a test image [[Main Page]]]] !! result -<div class="thumb tleft"><div class="thumbinner" style="width:1943px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="This is a test image Main Page"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="This is a test image Main Page" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption">This is a test image <a href="/wiki/Main_Page" title="Main Page">Main Page</a></div></div></div> +<div class="thumb tleft"><div class="thumbinner" style="width:1943px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="This is a test image Main Page"><img alt="This is a test image Main Page" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> <div class="thumbcaption">This is a test image <a href="/wiki/Main_Page" title="Main Page">Main Page</a></div></div></div> !! end !! test Link to image page- image page normally doesn't exists, hence edit link -TODO: Add test with existing image page +Add test with existing image page #<p><a href="/wiki/Image:Test" title="Image:Test">Image:test</a> !! input [[:Image:test]] @@ -2902,7 +2993,7 @@ Frameless image caption with a free URL !! input [[Image:foobar.jpg|http://example.com]] !! result -<p><a href="/wiki/Image:Foobar.jpg" class="image" title="http://example.com"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="http://example.com" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="/wiki/Image:Foobar.jpg" class="image" title="http://example.com"><img alt="http://example.com" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! end @@ -2911,7 +3002,7 @@ Thumbnail image caption with a free URL !! input [[Image:foobar.jpg|thumb|http://example.com]] !! result -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="http://example.com"><img src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" alt="http://example.com" width="180" height="20" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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="http://example.com" class="external free" title="http://example.com" rel="nofollow">http://example.com</a></div></div></div> +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="http://example.com"><img alt="http://example.com" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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="http://example.com" class="external free" title="http://example.com" rel="nofollow">http://example.com</a></div></div></div> !! end @@ -2920,7 +3011,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="internal" title="ISBN 1235467890"><img src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" alt="ISBN 1235467890" width="180" height="20" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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="internal" title="ISBN 1235467890"><img alt="ISBN 1235467890" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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> !! end @@ -2929,7 +3020,7 @@ BUG 1887: A RFC with a thumbnail !! input [[Image:foobar.jpg|thumb|This is RFC 12354]] !! result -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="This is RFC 12354"><img src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" alt="This is RFC 12354" width="180" height="20" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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>This is <a href="http://www.ietf.org/rfc/rfc12354.txt" class="external" title="http://www.ietf.org/rfc/rfc12354.txt">RFC 12354</a></div></div></div> +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="This is RFC 12354"><img alt="This is RFC 12354" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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>This is <a href="http://tools.ietf.org/html/rfc12354" class="external" title="http://tools.ietf.org/html/rfc12354">RFC 12354</a></div></div></div> !! end @@ -2938,7 +3029,7 @@ BUG 1887: A mailto link with a thumbnail !! input [[Image:foobar.jpg|thumb|Please mailto:nobody@example.com]] !! result -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="Please mailto:nobody@example.com"><img src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" alt="Please mailto:nobody@example.com" width="180" height="20" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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>Please <a href="mailto:nobody@example.com" class="external free" title="mailto:nobody@example.com" rel="nofollow">mailto:nobody@example.com</a></div></div></div> +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="Please mailto:nobody@example.com"><img alt="Please mailto:nobody@example.com" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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>Please <a href="mailto:nobody@example.com" class="external free" title="mailto:nobody@example.com" rel="nofollow">mailto:nobody@example.com</a></div></div></div> !! end @@ -2948,7 +3039,7 @@ so math is not stripped and turns up as escaped <math> tags. !! input [[Image:foobar.jpg|thumb|<math>2+2</math>]] !! result -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="<math>2+2</math>"><img src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" alt="<math>2+2</math>" width="180" height="20" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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><math>2+2</math></div></div></div> +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="<math>2+2</math>"><img alt="<math>2+2</math>" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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><math>2+2</math></div></div></div> !! end @@ -2959,7 +3050,7 @@ math !! input [[Image:foobar.jpg|thumb|<math>2+2</math>]] !! result -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="2 + 2"><img src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" alt="2 + 2" width="180" height="20" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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><span class="texhtml">2 + 2</span></div></div></div> +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="2 + 2"><img alt="2 + 2" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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><span class="texhtml">2 + 2</span></div></div></div> !! end @@ -2969,7 +3060,7 @@ BUG 648: Frameless image caption with a link !! input [[Image:foobar.jpg|text with a [[link]] in it]] !! result -<p><a href="/wiki/Image:Foobar.jpg" class="image" title="text with a link in it"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="text with a link in it" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="/wiki/Image:Foobar.jpg" class="image" title="text with a link in it"><img alt="text with a link in it" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! end @@ -2978,7 +3069,7 @@ BUG 648: Frameless image caption with a link (suffix) !! input [[Image:foobar.jpg|text with a [[link]]foo in it]] !! result -<p><a href="/wiki/Image:Foobar.jpg" class="image" title="text with a linkfoo in it"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="text with a linkfoo in it" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="/wiki/Image:Foobar.jpg" class="image" title="text with a linkfoo in it"><img alt="text with a linkfoo in it" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! end @@ -2987,7 +3078,7 @@ BUG 648: Frameless image caption with an interwiki link !! input [[Image:foobar.jpg|text with a [[MeatBall:Link]] in it]] !! result -<p><a href="/wiki/Image:Foobar.jpg" class="image" title="text with a MeatBall:Link in it"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="text with a MeatBall:Link in it" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="/wiki/Image:Foobar.jpg" class="image" title="text with a MeatBall:Link in it"><img alt="text with a MeatBall:Link in it" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! end @@ -2996,7 +3087,7 @@ BUG 648: Frameless image caption with a piped interwiki link !! input [[Image:foobar.jpg|text with a [[MeatBall:Link|link]] in it]] !! result -<p><a href="/wiki/Image:Foobar.jpg" class="image" title="text with a link in it"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="text with a link in it" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="/wiki/Image:Foobar.jpg" class="image" title="text with a link in it"><img alt="text with a link in it" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! end @@ -3005,7 +3096,7 @@ Escape HTML special chars in image alt text !! input [[Image:foobar.jpg|& < > "]] !! result -<p><a href="/wiki/Image:Foobar.jpg" class="image" title="& < > ""><img src="http://example.com/images/3/3a/Foobar.jpg" alt="& < > "" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="/wiki/Image:Foobar.jpg" class="image" title="& < > ""><img alt="& < > "" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! end @@ -3014,7 +3105,7 @@ BUG 499: Alt text should have Ӓ, not &1234; !! input [[Image:foobar.jpg|♀]] !! result -<p><a href="/wiki/Image:Foobar.jpg" class="image" title="♀"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="♀" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="/wiki/Image:Foobar.jpg" class="image" title="♀"><img alt="♀" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !! end @@ -3032,7 +3123,7 @@ Image caption containing another image !! input [[Image:Foobar.jpg|thumb|This is a caption with another [[Image:icon.png|image]] inside it!]] !! result -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="This is a caption with another Image:Icon.png inside it!"><img src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" alt="This is a caption with another Image:Icon.png inside it!" width="180" height="20" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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>This is a caption with another <a href="/index.php?title=Special:Upload&wpDestFile=Icon.png" class="new" title="Image:Icon.png">Image:Icon.png</a> inside it!</div></div></div> +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="This is a caption with another Image:Icon.png inside it!"><img alt="This is a caption with another Image:Icon.png inside it!" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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>This is a caption with another <a href="/index.php?title=Special:Upload&wpDestFile=Icon.png" class="new" title="Image:Icon.png">Image:Icon.png</a> inside it!</div></div></div> !! end @@ -3042,7 +3133,7 @@ Image caption containing a newline [[Image:Foobar.jpg|This *is some text]] !! result -<p><a href="/wiki/Image:Foobar.jpg" class="image" title="This *is some text"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="This *is some text" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="/wiki/Image:Foobar.jpg" class="image" title="This *is some text"><img alt="This *is some text" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !!end @@ -3052,7 +3143,7 @@ Bug 3090: External links other than http: in image captions !! input [[Image:Foobar.jpg|thumb|200px|This caption has [irc://example.net irc] and [https://example.com Secure] ext links in it.]] !! result -<div class="thumb tright"><div class="thumbinner" style="width:202px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="This caption has irc and Secure ext links in it."><img src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" alt="This caption has irc and Secure ext links in it." width="200" height="23" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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>This caption has <a href="irc://example.net" class="external text" title="irc://example.net" rel="nofollow">irc</a> and <a href="https://example.com" class="external text" title="https://example.com" rel="nofollow">Secure</a> ext links in it.</div></div></div> +<div class="thumb tright"><div class="thumbinner" style="width:202px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="This caption has irc and Secure ext links in it."><img alt="This caption has irc and Secure ext links in it." longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/thumb/3/3a/Foobar.jpg/200px-Foobar.jpg" width="200" height="23" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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>This caption has <a href="irc://example.net" class="external text" title="irc://example.net" rel="nofollow">irc</a> and <a href="https://example.com" class="external text" title="https://example.com" rel="nofollow">Secure</a> ext links in it.</div></div></div> !! end @@ -3279,6 +3370,44 @@ Handling of sections up to level 6 and beyond !! end !! test +TOC regression (bug 9764) +!! input +== title 1 == +=== title 1.1 === +==== title 1.1.1 ==== +=== title 1.2 === +== title 2 == +=== title 2.1 === +!! 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> +<ul> +<li class="toclevel-3"><a href="#title_1.1.1"><span class="tocnumber">1.1.1</span> <span class="toctext">title 1.1.1</span></a></li> +</ul> +</li> +<li class="toclevel-2"><a href="#title_1.2"><span class="tocnumber">1.2</span> <span class="toctext">title 1.2</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> +<ul> +<li class="toclevel-2"><a href="#title_2.1"><span class="tocnumber">2.1</span> <span class="toctext">title 2.1</span></a></li> +</ul> +</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_1.1.1"></a><h4><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=3" title="Edit section: title 1.1.1">edit</a>]</span> <span class="mw-headline"> title 1.1.1 </span></h4> +<a name="title_1.2"></a><h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=4" title="Edit section: title 1.2">edit</a>]</span> <span class="mw-headline"> title 1.2 </span></h3> +<a name="title_2"></a><h2><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=5" title="Edit section: title 2">edit</a>]</span> <span class="mw-headline"> title 2 </span></h2> +<a name="title_2.1"></a><h3><span class="editsection">[<a href="/index.php?title=Parser_test&action=edit&section=6" title="Edit section: title 2.1">edit</a>]</span> <span class="mw-headline"> title 2.1 </span></h3> + +!! end + +!! test Resolving duplicate section names !! input == Foo bar == @@ -3338,7 +3467,7 @@ BUG 1219 URL next to image (good) !! input http://example.com [[Image:foobar.jpg]] !! result -<p><a href="http://example.com" class="external free" title="http://example.com" rel="nofollow">http://example.com</a> <a href="/wiki/Image:Foobar.jpg" class="image" title="Image:foobar.jpg"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="Image:foobar.jpg" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="http://example.com" class="external free" title="http://example.com" rel="nofollow">http://example.com</a> <a href="/wiki/Image:Foobar.jpg" class="image" title="Image:foobar.jpg"><img alt="Image:foobar.jpg" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !!end @@ -3347,7 +3476,7 @@ BUG 1219 URL next to image (broken) !! input http://example.com[[Image:foobar.jpg]] !! result -<p><a href="http://example.com" class="external free" title="http://example.com" rel="nofollow">http://example.com</a><a href="/wiki/Image:Foobar.jpg" class="image" title="Image:foobar.jpg"><img src="http://example.com/images/3/3a/Foobar.jpg" alt="Image:foobar.jpg" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="http://example.com" class="external free" title="http://example.com" rel="nofollow">http://example.com</a><a href="/wiki/Image:Foobar.jpg" class="image" title="Image:foobar.jpg"><img alt="Image:foobar.jpg" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a> </p> !!end @@ -4272,7 +4401,7 @@ HTML bullet list, closed tags (bug 5497) !! end !! test -TODO: HTML bullet list, unclosed tags (bug 5497) +HTML bullet list, unclosed tags (bug 5497) !! input <ul> <li>One @@ -4302,7 +4431,7 @@ HTML ordered list, closed tags (bug 5497) !! end !! test -TODO: HTML ordered list, unclosed tags (bug 5497) +HTML ordered list, unclosed tags (bug 5497) !! input <ol> <li>One @@ -4342,7 +4471,7 @@ HTML nested bullet list, closed tags (bug 5497) !! end !! test -TODO: HTML nested bullet list, open tags (bug 5497) +HTML nested bullet list, open tags (bug 5497) !! input <ul> <li>One @@ -4390,7 +4519,7 @@ HTML nested ordered list, closed tags (bug 5497) !! end !! test -TODO: HTML nested ordered list, open tags (bug 5497) +HTML nested ordered list, open tags (bug 5497) !! input <ol> <li>One @@ -4622,7 +4751,7 @@ Fuzz testing: image with bogus manual thumbnail !!input [[Image:foobar.jpg|thumbnail= ]] !!result -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title=""><img src="http://example.com/images/3/3a/Foobar.jpg" alt="" width="180" height="20" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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></div></div></div> +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title=""><img alt="" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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></div></div></div> !!end @@ -4636,7 +4765,7 @@ Fuzz testing: encoded newline in generated HTML replacements (bug 6577) !! end !! test -TODO: Parsing optional HTML elements (Bug 6171) +Parsing optional HTML elements (Bug 6171) !! options !! input <table> @@ -4702,7 +4831,7 @@ New wiki paragraph !! end !! test -TODO: Inline HTML vs wiki block nesting +Inline HTML vs wiki block nesting !! input <b>Bold paragraph @@ -4715,7 +4844,7 @@ New wiki paragraph !!test -TODO: Mixing markup for italics and bold +Mixing markup for italics and bold !! options !! input '''bold''''''bold''bolditalics''''' @@ -5679,7 +5808,7 @@ Handling of 
 in URLs !!end !! test -TODO: 5 quotes, code coverage +1 line +5 quotes, code coverage +1 line !! input ''''' !! result @@ -5751,19 +5880,47 @@ image4 |300px| centre * image6 </gallery> !! result -<table class="gallery" cellspacing="0" cellpadding="0"><tr><td><div class="gallerybox"><div style="height: 152px;">Image1.png</div><div class="gallerytext"> -</div></div></td> -<td><div class="gallerybox"><div style="height: 152px;">Image2.gif</div><div class="gallerytext"> -||||</div></div></td> -<td><div class="gallerybox"><div style="height: 152px;">Image3</div><div class="gallerytext"> -</div></div></td> -<td><div class="gallerybox"><div style="height: 152px;">Image4</div><div class="gallerytext"> -300px| centre</div></div></td> -</tr><tr><td><div class="gallerybox"><div style="height: 152px;">Image5.svg</div><div class="gallerytext"> - <a href="http://///////" class="external free" title="http://///////" rel="nofollow">http://///////</a></div></div></td> -<td><div class="gallerybox"><div style="height: 152px;">* image6</div><div class="gallerytext"> -</div></div></td> -</tr> +<table class="gallery" cellspacing="0" cellpadding="0"> + <tr> + <td><div class="gallerybox" style="width: 150px;"> + <div style="height: 152px;">Image1.png</div> + <div class="gallerytext"> + </div> + </div></td> + <td><div class="gallerybox" style="width: 150px;"> + <div style="height: 152px;">Image2.gif</div> + <div class="gallerytext"> +<p>|||| +</p> + </div> + </div></td> + <td><div class="gallerybox" style="width: 150px;"> + <div style="height: 152px;">Image3</div> + <div class="gallerytext"> + </div> + </div></td> + <td><div class="gallerybox" style="width: 150px;"> + <div style="height: 152px;">Image4</div> + <div class="gallerytext"> +<p>300px| centre +</p> + </div> + </div></td> + </tr> + <tr> + <td><div class="gallerybox" style="width: 150px;"> + <div style="height: 152px;">Image5.svg</div> + <div class="gallerytext"> +<pre><a href="http://///////" class="external free" title="http://///////" rel="nofollow">http://///////</a> +</pre> + </div> + </div></td> + <td><div class="gallerybox" style="width: 150px;"> + <div style="height: 152px;">* image6</div> + <div class="gallerytext"> + </div> + </div></td> + </tr> </table> !! end @@ -5819,7 +5976,7 @@ Double RFC !! input RFC RFC 1234 !! result -<p>RFC <a href="http://www.ietf.org/rfc/rfc1234.txt" class="external" title="http://www.ietf.org/rfc/rfc1234.txt">RFC 1234</a> +<p>RFC <a href="http://tools.ietf.org/html/rfc1234" class="external" title="http://tools.ietf.org/html/rfc1234">RFC 1234</a> </p> !! end @@ -5837,7 +5994,7 @@ RFC code coverage !! input RFC 983 987 !! result -<p><a href="http://www.ietf.org/rfc/rfc983.txt" class="external" title="http://www.ietf.org/rfc/rfc983.txt">RFC 983</a> 987 +<p><a href="http://tools.ietf.org/html/rfc983" class="external" title="http://tools.ietf.org/html/rfc983">RFC 983</a> 987 </p> !! end @@ -5846,7 +6003,7 @@ Centre-aligned image !! input [[Image:foobar.jpg|centre]] !! result -<div class="center"><div class="floatnone"><span><a href="/wiki/Image:Foobar.jpg" class="image" title=""><img src="http://example.com/images/3/3a/Foobar.jpg" alt="" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a></span></div></div> +<div class="center"><div class="floatnone"><span><a href="/wiki/Image:Foobar.jpg" class="image" title=""><img alt="" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></span></div></div> !!end @@ -5855,7 +6012,7 @@ None-aligned image !! input [[Image:foobar.jpg|none]] !! result -<div class="floatnone"><span><a href="/wiki/Image:Foobar.jpg" class="image" title=""><img src="http://example.com/images/3/3a/Foobar.jpg" alt="" width="1941" height="220" longdesc="/wiki/Image:Foobar.jpg" /></a></span></div> +<div class="floatnone"><span><a href="/wiki/Image:Foobar.jpg" class="image" title=""><img alt="" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/3/3a/Foobar.jpg" width="1941" height="220" /></a></span></div> !!end @@ -5864,7 +6021,7 @@ Width + Height sized image (using px) (height is ignored) !! input [[Image:foobar.jpg|640x480px]] !! result -<p><a href="/wiki/Image:Foobar.jpg" class="image" title=""><img src="http://example.com/images/thumb/3/3a/Foobar.jpg/640px-Foobar.jpg" alt="" width="640" height="73" longdesc="/wiki/Image:Foobar.jpg" /></a> +<p><a href="/wiki/Image:Foobar.jpg" class="image" title=""><img alt="" longdesc="/wiki/Image:Foobar.jpg" src="http://example.com/images/thumb/3/3a/Foobar.jpg/640px-Foobar.jpg" width="640" height="73" /></a> </p> !!end @@ -5881,16 +6038,16 @@ Another italics / bold test # XML error: Mismatched tag at byte 6120: # ...<dd> </dt></dl> </dd... !! test -TODO: dt/dd/dl test +dt/dd/dl test !! input :;;;:: !! result <dl><dd><dl><dt><dl><dt><dl><dt><dl><dd><dl><dd> -</dt></dl> -</dd></dl> -</dd></dl> </dd></dl> </dd></dl> +</dt></dl> +</dt></dl> +</dt></dl> </dd></dl> !!end @@ -5898,11 +6055,11 @@ TODO: dt/dd/dl test # Images with the "|" character in external URLs in comment tags; Eats half the comment, leaves unmatched "</a>" tag. !! test -TODO: Images with the "|" character in the comment +Images with the "|" character in the comment !! input [[image:Foobar.jpg|thumb|An [http://test/?param1=|left|¶m2=|x external] URL]] !! result -<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="An external URL"><img src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" alt="An external URL" width="180" height="20" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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>An <a href="http://test/?param1=|left|&param2=|x" class="external text" title="http://test/?param1=|left|&param2=|x" rel="nofollow">external</a> URL</div></div></div> +<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/Image:Foobar.jpg" class="internal" title="An external URL"><img alt="An external URL" longdesc="/wiki/Image:Foobar.jpg" class="thumbimage" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" /></a> <div class="thumbcaption"><div class="magnify" style="float:right"><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>An <a href="http://test/?param1=|left|&param2=|x" class="external text" title="http://test/?param1=|left|&param2=|x" rel="nofollow">external</a> URL</div></div></div> !!end @@ -5966,7 +6123,7 @@ subpage title=[[Subpage test/L1/L2/L3]] # Question: should result be "/index.php?title=Subpage_test/L1&action=edit" instead? !! test -TODO: Parents of subpages, two levels up, without trailing slash or name. +Parents of subpages, two levels up, without trailing slash or name. !! options subpage title=[[Subpage test/L1/L2/L3]] !! input @@ -5979,7 +6136,7 @@ subpage title=[[Subpage test/L1/L2/L3]] # Question: Why should the link text in the above test be "../..", yet in this test the "../.." part is silently dropped? # Current result: <p><a href="/index.php?title=Subpage_test/L1////&action=edit" class="new" title="Subpage test/L1////">/// !! test -TODO: Parents of subpages, two levels up, with lots of extra trailing slashes. +Parents of subpages, two levels up, with lots of extra trailing slashes. !! options subpage title=[[Subpage test/L1/L2/L3]] !! input @@ -6004,7 +6161,7 @@ Definition list code coverage !! end !! test -TODO: Don't fall for the self-closing div +Don't fall for the self-closing div !! input <div>hello world</div/> !! result @@ -6032,7 +6189,7 @@ RAW magic word # This isn't needed for XHTML conformance, but would be handy as a fallback security measure !! test -TODO: Always escape literal '>' in output, not just after '<' +Always escape literal '>' in output, not just after '<' !! input ><> !! result diff --git a/maintenance/parserTestsParserHook.php b/maintenance/parserTestsParserHook.php index 65e41aae..339cadab 100644 --- a/maintenance/parserTestsParserHook.php +++ b/maintenance/parserTestsParserHook.php @@ -5,8 +5,7 @@ if ( ! defined( 'MEDIAWIKI' ) ) * A basic extension that's used by the parser tests to test whether input and * arguments are passed to extensions properly. * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup 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 705f9ce7..68541cfb 100644 --- a/maintenance/parserTestsParserTime.php +++ b/maintenance/parserTestsParserTime.php @@ -8,8 +8,7 @@ if ( ! defined( 'MEDIAWIKI' ) ) * compensate with the passage of time and certainly less expensive than a * time-freezing device, get yours now! * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup 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 ac365aca..8f22101f 100644 --- a/maintenance/parserTestsStaticParserHook.php +++ b/maintenance/parserTestsStaticParserHook.php @@ -5,8 +5,7 @@ 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 * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com> * @copyright Copyright © 2005, 2006 Ævar Arnfjörð Bjarmason diff --git a/maintenance/postgres/archives/patch-archive-ar_deleted.sql b/maintenance/postgres/archives/patch-archive-ar_deleted.sql new file mode 100644 index 00000000..08bc1e37 --- /dev/null +++ b/maintenance/postgres/archives/patch-archive-ar_deleted.sql @@ -0,0 +1 @@ +ALTER TABLE archive ADD ar_deleted INTEGER NOT NULL DEFAULT '0'; diff --git a/maintenance/postgres/archives/patch-archive2.sql b/maintenance/postgres/archives/patch-archive2.sql new file mode 100644 index 00000000..fa900cbf --- /dev/null +++ b/maintenance/postgres/archives/patch-archive2.sql @@ -0,0 +1,15 @@ +ALTER TABLE archive RENAME to archive2; +CREATE VIEW archive AS +SELECT + ar_namespace, ar_title, ar_text, ar_comment, ar_user, ar_user_text, + ar_minor_edit, ar_flags, ar_rev_id, ar_text_id, + TO_CHAR(ar_timestamp, 'YYYYMMDDHH24MISS') AS ar_timestamp +FROM archive2; + +CREATE RULE archive_insert AS ON INSERT TO archive +DO INSTEAD INSERT INTO archive2 VALUES ( + NEW.ar_namespace, NEW.ar_title, NEW.ar_text, NEW.ar_comment, NEW.ar_user, NEW.ar_user_text, + TO_DATE(NEW.ar_timestamp, 'YYYYMMDDHH24MISS'), + NEW.ar_minor_edit, NEW.ar_flags, NEW.ar_rev_id, NEW.ar_text_id +); + diff --git a/maintenance/postgres/archives/patch-archive_delete.sql b/maintenance/postgres/archives/patch-archive_delete.sql new file mode 100644 index 00000000..4a864c3b --- /dev/null +++ b/maintenance/postgres/archives/patch-archive_delete.sql @@ -0,0 +1,5 @@ +CREATE RULE archive_delete AS ON DELETE TO archive +DO INSTEAD DELETE FROM archive2 WHERE + archive2.ar_title = OLD.ar_title AND + archive2.ar_namespace = OLD.ar_namespace AND + archive2.ar_rev_id = OLD.ar_rev_id; diff --git a/maintenance/postgres/archives/patch-archive_insert.sql b/maintenance/postgres/archives/patch-archive_insert.sql new file mode 100644 index 00000000..ca13d2a2 --- /dev/null +++ b/maintenance/postgres/archives/patch-archive_insert.sql @@ -0,0 +1,6 @@ +CREATE OR REPLACE RULE archive_insert AS ON INSERT TO archive +DO INSTEAD INSERT INTO archive2 VALUES ( + NEW.ar_namespace, NEW.ar_title, NEW.ar_text, NEW.ar_comment, NEW.ar_user, NEW.ar_user_text, + TO_TIMESTAMP(NEW.ar_timestamp, 'YYYYMMDDHH24MISS'), + NEW.ar_minor_edit, NEW.ar_flags, NEW.ar_rev_id, NEW.ar_text_id +); diff --git a/maintenance/postgres/archives/patch-mediawiki_version.sql b/maintenance/postgres/archives/patch-mediawiki_version.sql new file mode 100644 index 00000000..811b38a1 --- /dev/null +++ b/maintenance/postgres/archives/patch-mediawiki_version.sql @@ -0,0 +1,18 @@ +CREATE TABLE mediawiki_version ( + type TEXT NOT NULL, + mw_version TEXT NOT NULL, + notes TEXT NULL, + + pg_version TEXT NULL, + pg_dbname TEXT NULL, + pg_user TEXT NULL, + pg_port TEXT NULL, + mw_schema TEXT NULL, + ts2_schema TEXT NULL, + ctype TEXT NULL, + + sql_version TEXT NULL, + sql_date TEXT NULL, + cdate TIMESTAMPTZ NOT NULL DEFAULT now() +); + diff --git a/maintenance/postgres/archives/patch-mwuser.sql b/maintenance/postgres/archives/patch-mwuser.sql new file mode 100644 index 00000000..3984703a --- /dev/null +++ b/maintenance/postgres/archives/patch-mwuser.sql @@ -0,0 +1 @@ +ALTER TABLE "user" RENAME TO mwuser; diff --git a/maintenance/postgres/archives/patch-page_deleted.sql b/maintenance/postgres/archives/patch-page_deleted.sql new file mode 100644 index 00000000..5b0782cb --- /dev/null +++ b/maintenance/postgres/archives/patch-page_deleted.sql @@ -0,0 +1,11 @@ +CREATE FUNCTION page_deleted() RETURNS TRIGGER LANGUAGE plpgsql AS +$mw$ +BEGIN +DELETE FROM recentchanges WHERE rc_namespace = OLD.page_namespace AND rc_title = OLD.page_title; +RETURN NULL; +END; +$mw$; + +CREATE TRIGGER page_deleted AFTER DELETE ON page + FOR EACH ROW EXECUTE PROCEDURE page_deleted(); + diff --git a/maintenance/postgres/archives/patch-page_restrictions.sql b/maintenance/postgres/archives/patch-page_restrictions.sql new file mode 100644 index 00000000..1faa14a9 --- /dev/null +++ b/maintenance/postgres/archives/patch-page_restrictions.sql @@ -0,0 +1,10 @@ +CREATE TABLE page_restrictions ( + pr_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE, + pr_type TEXT NOT NULL, + pr_level TEXT NOT NULL, + pr_cascade SMALLINT NOT NULL, + pr_user INTEGER NULL, + pr_expiry TIMESTAMPTZ NULL +); +ALTER TABLE page_restrictions ADD CONSTRAINT page_restrictions_pk PRIMARY KEY (pr_page,pr_type); + diff --git a/maintenance/postgres/archives/patch-pagecontent.sql b/maintenance/postgres/archives/patch-pagecontent.sql new file mode 100644 index 00000000..c3651f92 --- /dev/null +++ b/maintenance/postgres/archives/patch-pagecontent.sql @@ -0,0 +1 @@ +ALTER TABLE "text" RENAME TO pagecontent; diff --git a/maintenance/postgres/archives/patch-profiling.sql b/maintenance/postgres/archives/patch-profiling.sql new file mode 100644 index 00000000..1c4dce4e --- /dev/null +++ b/maintenance/postgres/archives/patch-profiling.sql @@ -0,0 +1,7 @@ +CREATE TABLE profiling ( + pf_count INTEGER NOT NULL DEFAULT 0, + pf_time NUMERIC(18,10) NOT NULL DEFAULT 0, + pf_name TEXT NOT NULL, + pf_server TEXT NULL +); +CREATE UNIQUE INDEX pf_name_server ON profiling (pf_name, pf_server); diff --git a/maintenance/postgres/archives/patch-querycachetwo.sql b/maintenance/postgres/archives/patch-querycachetwo.sql new file mode 100644 index 00000000..cb70cd89 --- /dev/null +++ b/maintenance/postgres/archives/patch-querycachetwo.sql @@ -0,0 +1,12 @@ +CREATE TABLE querycachetwo ( + qcc_type TEXT NOT NULL, + qcc_value SMALLINT NOT NULL DEFAULT 0, + qcc_namespace INTEGER NOT NULL DEFAULT 0, + qcc_title TEXT NOT NULL DEFAULT '', + qcc_namespacetwo INTEGER NOT NULL DEFAULT 0, + qcc_titletwo TEXT NOT NULL DEFAULT '' +); +CREATE INDEX querycachetwo_type_value ON querycachetwo (qcc_type, qcc_value); +CREATE INDEX querycachetwo_title ON querycachetwo (qcc_type,qcc_namespace,qcc_title); +CREATE INDEX querycachetwo_titletwo ON querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo); + diff --git a/maintenance/postgres/archives/patch-rc_cur_id-not-null.sql b/maintenance/postgres/archives/patch-rc_cur_id-not-null.sql new file mode 100644 index 00000000..2ca7edbf --- /dev/null +++ b/maintenance/postgres/archives/patch-rc_cur_id-not-null.sql @@ -0,0 +1 @@ +ALTER TABLE recentchanges ALTER rc_cur_id DROP NOT NULL; diff --git a/maintenance/postgres/archives/patch-redirect.sql b/maintenance/postgres/archives/patch-redirect.sql new file mode 100644 index 00000000..d2922d3b --- /dev/null +++ b/maintenance/postgres/archives/patch-redirect.sql @@ -0,0 +1,7 @@ +CREATE TABLE redirect ( + rd_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE, + rd_namespace SMALLINT NOT NULL, + rd_title TEXT NOT NULL +); +CREATE INDEX redirect_ns_title ON redirect (rd_namespace,rd_title,rd_from); + diff --git a/maintenance/postgres/archives/patch-remove-archive2.sql b/maintenance/postgres/archives/patch-remove-archive2.sql new file mode 100644 index 00000000..20bac385 --- /dev/null +++ b/maintenance/postgres/archives/patch-remove-archive2.sql @@ -0,0 +1,3 @@ +DROP VIEW archive; +ALTER TABLE archive2 RENAME TO archive; +ALTER TABLE archive ADD ar_len INTEGER; diff --git a/maintenance/postgres/archives/patch-rev_text_id_idx.sql b/maintenance/postgres/archives/patch-rev_text_id_idx.sql new file mode 100644 index 00000000..036c0be3 --- /dev/null +++ b/maintenance/postgres/archives/patch-rev_text_id_idx.sql @@ -0,0 +1 @@ +CREATE INDEX rev_text_id_idx ON revision (rev_text_id); diff --git a/maintenance/postgres/archives/patch-revision_rev_user_fkey.sql b/maintenance/postgres/archives/patch-revision_rev_user_fkey.sql new file mode 100644 index 00000000..721aadd5 --- /dev/null +++ b/maintenance/postgres/archives/patch-revision_rev_user_fkey.sql @@ -0,0 +1,4 @@ +ALTER TABLE revision DROP CONSTRAINT revision_rev_user_fkey; +ALTER TABLE revision ADD CONSTRAINT revision_rev_user_fkey + FOREIGN KEY (rev_user) REFERENCES mwuser(user_id) ON DELETE RESTRICT; + diff --git a/maintenance/postgres/compare_schemas.pl b/maintenance/postgres/compare_schemas.pl index cdbbdf41..ce045fef 100644 --- a/maintenance/postgres/compare_schemas.pl +++ b/maintenance/postgres/compare_schemas.pl @@ -7,8 +7,8 @@ use strict; use warnings; use Data::Dumper; -my @old = ("../tables.sql", "../mysql5/tables.sql", "../mysql5/tables-binary.sql"); -my $new = "tables.sql"; +my @old = ('../tables.sql'); +my $new = 'tables.sql'; my @xfile; ## Read in exceptions and other metadata @@ -27,7 +27,7 @@ while (<DATA>) { push @xfile, $val; next; } - for (split(/\s+/ => $val)) { + for (split /\s+/ => $val) { $ok{$name}{$_} = 0; } } @@ -46,16 +46,16 @@ my $typeval = qr{(\(\d+\))?}; my $typeval2 = qr{ 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"; +my $indextype = join '|' => qw(INDEX KEY FULLTEXT), 'PRIMARY KEY', 'UNIQUE INDEX', 'UNIQUE KEY'; $indextype = qr{$indextype}; my $engine = qr{TYPE|ENGINE}; -my $tabletype = qr{InnoDB|MyISAM|HEAP|HEAP MAX_ROWS=\d+}; +my $tabletype = qr{InnoDB|MyISAM|HEAP|HEAP MAX_ROWS=\d+|InnoDB MAX_ROWS=\d+ AVG_ROW_LENGTH=\d+}; my $charset = qr{utf8|binary}; -open my $newfh, "<", $new or die qq{Could not open $new: $!\n}; +open my $newfh, '<', $new or die qq{Could not open $new: $!\n}; my ($table,%old); @@ -83,7 +83,7 @@ sub parse_sql { my $oldfile = shift; - open my $oldfh, "<", $oldfile or die qq{Could not open $oldfile: $!\n}; + open my $oldfh, '<', $oldfile or die qq{Could not open $oldfile: $!\n}; my %info; while (<$oldfh>) { @@ -97,6 +97,10 @@ sub parse_sql { $table = $1; $info{$table}{name}=$table; } + elsif (m#^\) /\*\$wgDBTableOptions\*/#) { + $info{$table}{engine} = 'TYPE'; + $info{$table}{type} = 'variable'; + } elsif (/^\) ($engine)=($tabletype);$/) { $info{$table}{engine}=$1; $info{$table}{type}=$2; @@ -110,8 +114,8 @@ sub parse_sql { $info{$table}{column}{$1} = $2; } elsif (/^ ($indextype)(?: (\w+))? \(([\w, \(\)]+)\),?$/) { - $info{$table}{lc $1."_name"} = $2 ? $2 : ""; - $info{$table}{lc $1."pk_target"} = $3; + $info{$table}{lc $1.'_name'} = $2 ? $2 : ''; + $info{$table}{lc $1.'pk_target'} = $3; } else { die "Cannot parse line $. of $oldfile:\n$_\n"; @@ -209,13 +213,13 @@ for my $t (sort keys %{$old{$oldfile}}) { my $newcol = $new{$newt}{column}; for my $c (keys %$oldcol) { if (!exists $newcol->{$c}) { - print "Column $t.$c not in new\n"; + print "Column $t.$c not in $new\n"; next; } } for my $c (keys %$newcol) { if (!exists $oldcol->{$c}) { - print "Column $t.$c not in old\n"; + print "Column $t.$c not in $oldfile\n"; next; } } @@ -223,7 +227,7 @@ for my $t (sort keys %{$old{$oldfile}}) { ## New but not old: for (sort keys %new) { if (!exists $old{$oldfile}{$_} and !exists $ok{NEW}{$_}) { - print "Not in old: $_\n"; + print "Not in $oldfile: $_\n"; next; } } @@ -235,9 +239,7 @@ for (sort keys %new) { __DATA__ ## Known exceptions OLD: searchindex ## We use tsearch2 directly on the page table instead -OLD: archive ## This is a view due to the char(14) timestamp hack RENAME: user mwuser ## Reserved word causing lots of problems RENAME: text pagecontent ## Reserved word -NEW: archive2 ## The real archive table NEW: mediawiki_version ## Just us, for now XFILE: ../archives/patch-profiling.sql diff --git a/maintenance/postgres/mediawiki_mysql2postgres.pl b/maintenance/postgres/mediawiki_mysql2postgres.pl new file mode 100644 index 00000000..733af08f --- /dev/null +++ b/maintenance/postgres/mediawiki_mysql2postgres.pl @@ -0,0 +1,444 @@ +#!/usr/bin/perl + +## Convert data from a MySQL mediawiki database into a Postgres mediawiki database +## svn: $Id: mediawiki_mysql2postgres.pl 21254 2007-04-14 02:10:03Z greg $ + +use strict; +use warnings; +use Data::Dumper; +use Getopt::Long; + +use vars qw(%table %tz %special @torder $COM); +my $VERSION = '1.2'; + +## The following options can be changed via command line arguments: +my $MYSQLDB = ''; +my $MYSQLUSER = ''; + +## If the following are zero-length, we omit their arguments entirely: +my $MYSQLHOST = ''; +my $MYSQLPASSWORD = ''; +my $MYSQLSOCKET = ''; + +## Name of the dump file created +my $MYSQLDUMPFILE = 'mediawiki_upgrade.pg'; + +## How verbose should this script be (0, 1, or 2) +my $verbose = 0; + +my $help = 0; + +my $USAGE = " +Usage: $0 --db=<dbname> --user=<user> [OPTION]... +Example: $0 --db=wikidb --user=wikiuser --pass=sushi + +Converts a MediaWiki schema from MySQL to Postgres +Options: + db Name of the MySQL database + user MySQL database username + pass MySQL database password + host MySQL database host + socket MySQL database socket + verbose Verbosity, increases with multiple uses +"; + +GetOptions + ( + 'db=s' => \$MYSQLDB, + 'user=s' => \$MYSQLUSER, + 'pass=s' => \$MYSQLPASSWORD, + 'host=s' => \$MYSQLHOST, + 'socket=s' => \$MYSQLSOCKET, + 'verbose+' => \$verbose, + 'help' => \$help, + ); + +die $USAGE + if ! length $MYSQLDB + or ! length $MYSQLUSER + or $help; + +## The Postgres schema file: should not be changed +my $PG_SCHEMA = 'tables.sql'; + +## What version we default to when we can't parse the old schema +my $MW_DEFAULT_VERSION = 110; + +## Try and find a working version of mysqldump +$verbose and warn "Locating the mysqldump executable\n"; +my @MYSQLDUMP = ('/usr/local/bin/mysqldump', '/usr/bin/mysqldump'); +my $MYSQLDUMP; +for my $mytry (@MYSQLDUMP) { + next if ! -e $mytry; + -x $mytry or die qq{Not an executable file: "$mytry"\n}; + my $version = qx{$mytry -V}; + $version =~ /^mysqldump\s+Ver\s+\d+/ or die qq{Program at "$mytry" does not act like mysqldump\n}; + $MYSQLDUMP = $mytry; +} +$MYSQLDUMP or die qq{Could not find the mysqldump program\n}; + +## Flags we use for mysqldump +my @MYSQLDUMPARGS = qw( +--skip-lock-tables +--complete-insert +--skip-extended-insert +--skip-add-drop-table +--skip-add-locks +--skip-disable-keys +--skip-set-charset +--skip-comments +--skip-quote-names +); + + +$verbose and warn "Checking that mysqldump can handle our flags\n"; +## Make sure this version can handle all the flags we want. +## Combine with user dump below +my $MYSQLDUMPARGS = join ' ' => @MYSQLDUMPARGS; +## Argh. Any way to make this work on Win32? +my $version = qx{$MYSQLDUMP $MYSQLDUMPARGS 2>&1}; +if ($version =~ /unknown option/) { + die qq{Sorry, you need to use a newer version of the mysqldump program than the one at "$MYSQLDUMP"\n}; +} + +push @MYSQLDUMPARGS, "--user=$MYSQLUSER"; +length $MYSQLPASSWORD and push @MYSQLDUMPARGS, "--password=$MYSQLPASSWORD"; +length $MYSQLHOST and push @MYSQLDUMPARGS, "--host=$MYSQLHOST"; + +## Open the dump file to hold the mysqldump output +open my $mdump, '+>', $MYSQLDUMPFILE or die qq{Could not open "$MYSQLDUMPFILE": $!\n}; +print qq{Writing file "$MYSQLDUMPFILE"\n}; + +open my $mfork2, '-|' or exec $MYSQLDUMP, @MYSQLDUMPARGS, '--no-data', $MYSQLDB; +my $oldselect = select $mdump; + +print while <$mfork2>; + +## Slurp in the current schema +my $current_schema; +seek $mdump, 0, 0; +{ + local $/; + $current_schema = <$mdump>; +} +seek $mdump, 0, 0; +truncate $mdump, 0; + +warn qq{Trying to determine database version...\n} if $verbose; + +my $current_version = 0; +if ($current_schema =~ /CREATE TABLE \S+cur /) { + $current_version = 103; +} +elsif ($current_schema =~ /CREATE TABLE \S+brokenlinks /) { + $current_version = 104; +} +elsif ($current_schema !~ /CREATE TABLE \S+templatelinks /) { + $current_version = 105; +} +elsif ($current_schema !~ /CREATE TABLE \S+validate /) { + $current_version = 106; +} +elsif ($current_schema !~ /ipb_auto tinyint/) { + $current_version = 107; +} +elsif ($current_schema !~ /CREATE TABLE \S+profiling /) { + $current_version = 108; +} +elsif ($current_schema !~ /CREATE TABLE \S+querycachetwo /) { + $current_version = 109; +} +else { + $current_version = $MW_DEFAULT_VERSION; +} + +if (!$current_version) { + warn qq{WARNING! Could not figure out the old version, assuming MediaWiki $MW_DEFAULT_VERSION\n}; + $current_version = $MW_DEFAULT_VERSION; +} + +## Check for a table prefix: +my $table_prefix = ''; +if ($current_schema =~ /CREATE TABLE (\S+)querycache /) { + $table_prefix = $1; +} + +warn qq{Old schema is from MediaWiki version $current_version\n} if $verbose; +warn qq{Table prefix is "$table_prefix"\n} if $verbose and length $table_prefix; + +$verbose and warn qq{Writing file "$MYSQLDUMPFILE"\n}; +my $now = scalar localtime; +my $conninfo = ''; +$MYSQLHOST and $conninfo .= "\n-- host $MYSQLHOST"; +$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: 21254 $}.qq{) +-- Author: Greg Sabino Mullane <greg\@turnstep.com> Comments welcome +-- +-- This file was created: $now +-- Executable used: $MYSQLDUMP +-- Connection information: +-- database: $MYSQLDB +-- user: $MYSQLUSER$conninfo + +-- This file can be imported manually with psql like so: +-- psql -p port# -h hostname -U username -f $MYSQLDUMPFILE databasename +-- This will overwrite any existing MediaWiki information, so be careful + +}; + +## psql specific stuff +print q{ +\\set ON_ERROR_STOP +BEGIN; +SET client_min_messages = 'WARNING'; +SET timezone = 'GMT'; +}; + +warn qq{Reading in the Postgres schema information\n} if $verbose; +open my $schema, '<', $PG_SCHEMA + or die qq{Could not open "$PG_SCHEMA": make sure this script is run from maintenance/postgres/\n}; +my $t; +while (<$schema>) { + if (/CREATE TABLE\s+(\S+)/) { + $t = $1; + $table{$t}={}; + $verbose > 1 and warn qq{ Found table $t\n}; + } + elsif (/^ +(\w+)\s+TIMESTAMP/) { + $tz{$t}{$1}++; + $verbose > 1 and warn qq{ Got a timestamp for column $1\n}; + } + elsif (/REFERENCES\s*([^( ]+)/) { + my $ref = $1; + exists $table{$ref} or die qq{No parent table $ref found for $t\n}; + $table{$t}{$ref}++; + } +} +close $schema or die qq{Could not close "$PG_SCHEMA": $!\n}; + +## Read in special cases and table/version information +$verbose and warn qq{Reading in schema exception information\n}; +my %version_tables; +while (<DATA>) { + if (/^VERSION\s+(\d+\.\d+):\s+(.+)/) { + my $list = join '|' => split /\s+/ => $2; + $version_tables{$1} = qr{\b$list\b}; + next; + } + next unless /^(\w+)\s*(.*)/; + $special{$1} = $2||''; + $special{$2} = $1 if length $2; +} + +## Determine the order of tables based on foreign key constraints +$verbose and warn qq{Figuring out order of tables to dump\n}; +my %dumped; +my $bail = 0; +{ + my $found=0; + T: for my $t (sort keys %table) { + next if exists $dumped{$t} and $dumped{$t} >= 1; + $found=1; + for my $dep (sort keys %{$table{$t}}) { + next T if ! exists $dumped{$dep} or $dumped{$dep} < 0; + } + $dumped{$t} = -1 if ! exists $dumped{$t}; + ## Skip certain tables that are not imported + next if exists $special{$t} and !$special{$t}; + push @torder, $special{$t} || $t; + } + last if !$found; + push @torder, '---'; + for (values %dumped) { $_+=2; } + die "Too many loops!\n" if $bail++ > 1000; + redo; +} + +## Prepare the Postgres database for the move +$verbose and warn qq{Writing Postgres transformation information\n}; + +print "\n-- Empty out all existing tables\n"; +$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"}; +} +print "\n\n"; + +print qq{-- Temporarily rename pagecontent to "text"\n}; +print qq{ALTER TABLE pagecontent RENAME TO "text";\n\n}; + +print qq{-- Allow rc_ip to contain empty string, will convert at end\n}; +print qq{ALTER TABLE recentchanges ALTER rc_ip TYPE text USING host(rc_ip);\n\n}; + +print "-- Changing all timestamp fields to handle raw integers\n"; +for my $t (sort keys %tz) { + next if $t eq 'archive2'; + for my $c (sort keys %{$tz{$t}}) { + printf "ALTER TABLE %-18s ALTER %-25s TYPE TEXT;\n", $t, $c; + } +} +print "\n"; + +print q{ +INSERT INTO page VALUES (0,-1,'Dummy Page','',0,0,0,default,now(),0,10); +}; + +## If we have a table _prefix, we need to temporarily rename all of our Postgres +## tables temporarily for the import. Perhaps consider making this an auto-schema +## thing in the future. +if (length $table_prefix) { + print qq{\n\n-- Temporarily renaming tables to accomodate the table_prefix "$table_prefix"\n\n}; + for my $t (@torder) { + next if $t eq '---'; + my $tname = $special{$t}||$t; + printf qq{ALTER TABLE %-18s RENAME TO "${table_prefix}$tname"\n}, qq{"$tname"}; + } +} + + +## Try and dump the ill-named "user" table: +## We do this table alone because "user" is a reserved word. +print q{ + +SET escape_string_warning TO 'off'; +\\o /dev/null + +-- Postgres uses a table name of "mwuser" instead of "user" + +-- Create a dummy user to satisfy fk contraints especially with revisions +SELECT setval('user_user_id_seq',0,'false'); +INSERT INTO mwuser + VALUES (DEFAULT,'Anonymous','',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,now(),now()); + +}; + +push @MYSQLDUMPARGS, '--no-create-info'; + +$verbose and warn qq{Dumping "user" table\n}; +$verbose > 2 and warn Dumper \@MYSQLDUMPARGS; +my $usertable = "${table_prefix}user"; +open my $mfork, '-|' or exec $MYSQLDUMP, @MYSQLDUMPARGS, $MYSQLDB, $usertable; +## Unfortunately, there is no easy way to catch errors +my $numusers = 0; +while (<$mfork>) { + ++$numusers and print if s/INSERT INTO $usertable/INSERT INTO mwuser/; +} +close $mfork; +if ($numusers < 1) { + warn qq{No users found, probably a connection error.\n}; + print qq{ERROR: No users found, connection failed, or table "$usertable" does not exist. Dump aborted.\n}; + close $mdump or die qq{Could not close "$MYSQLDUMPFILE": $!\n}; + exit; +} +print "\n-- Users loaded: $numusers\n\n-- Loading rest of the mediawiki schema:\n"; + +warn qq{Dumping all other tables from the MySQL schema\n} if $verbose; + +## Dump the rest of the tables, in chunks based on constraints +## We do not need the user table: +my @dumplist = grep { $_ ne 'user'} @torder; +my @alist; +{ + undef @alist; + PICKATABLE: { + my $tname = shift @dumplist; + ## XXX Make this dynamic below + for my $ver (sort {$b <=> $a } keys %version_tables) { + redo PICKATABLE if $tname =~ $version_tables{$ver}; + } + $tname = "${table_prefix}$tname" if length $table_prefix; + next if $tname !~ /^\w/; + push @alist, $tname; + $verbose and warn " $tname...\n"; + pop @alist and last if index($alist[-1],'---') >= 0; + redo if @dumplist; + } + + ## Dump everything else + open my $mfork2, '-|' or exec $MYSQLDUMP, @MYSQLDUMPARGS, $MYSQLDB, @alist; + print while <$mfork2>; + close $mfork2; + warn qq{Finished dumping from MySQL\n} if $verbose; + + redo if @dumplist; +} + +warn qq{Writing information to return Postgres database to normal\n} if $verbose; +print qq{ALTER TABLE "${table_prefix}text" RENAME TO pagecontent;\n}; +print qq{ALTER TABLE ${table_prefix}recentchanges ALTER rc_ip TYPE cidr USING\n}; +print qq{ CASE WHEN rc_ip = '' THEN NULL ELSE rc_ip::cidr END;\n}; + +## Return tables to their original names if a table prefix was used. +if (length $table_prefix) { + print qq{\n\n-- Renaming tables by removing table prefix "$table_prefix"\n\n}; + my $maxsize = 18; + for (@torder) { + $maxsize = length "$_$table_prefix" if length "$_$table_prefix" > $maxsize; + } + for my $t (@torder) { + next if $t eq '---' or $t eq 'text'; + my $tname = $special{$t}||$t; + printf qq{ALTER TABLE %*s RENAME TO "$tname"\n}, $maxsize+1, qq{"${table_prefix}$tname"}; + } +} + +print qq{\n\n--Returning timestamps to normal\n}; +for my $t (sort keys %tz) { + next if $t eq 'archive2'; + for my $c (sort keys %{$tz{$t}}) { + printf "ALTER TABLE %-18s ALTER %-25s TYPE timestamptz\n". + " USING TO_TIMESTAMP($c,'YYYYMMDDHHMISS');\n", $t, $c; + } +} + +## Reset sequences +print q{ +SELECT setval('filearchive_fa_id_seq', 1+coalesce(max(fa_id) ,0),false) FROM filearchive; +SELECT setval('ipblocks_ipb_id_val', 1+coalesce(max(ipb_id) ,0),false) FROM ipblocks; +SELECT setval('job_job_id_seq', 1+coalesce(max(job_id) ,0),false) FROM job; +SELECT setval('log_log_id_seq', 1+coalesce(max(log_id) ,0),false) FROM logging; +SELECT setval('page_page_id_seq', 1+coalesce(max(page_id),0),false) FROM page; +SELECT setval('pr_id_val', 1+coalesce(max(pr_id) ,0),false) FROM page_restrictions; +SELECT setval('rc_rc_id_seq', 1+coalesce(max(rc_id) ,0),false) FROM recentchanges; +SELECT setval('rev_rev_id_val', 1+coalesce(max(rev_id) ,0),false) FROM revision; +SELECT setval('text_old_id_val', 1+coalesce(max(old_id) ,0),false) FROM pagecontent; +SELECT setval('trackbacks_tb_id_seq', 1+coalesce(max(tb_id) ,0),false) FROM trackbacks; +SELECT setval('user_user_id_seq', 1+coalesce(max(user_id),0),false) FROM mwuser; +}; + +## Finally, make a record in the mediawiki_version table about this import +print qq{ +INSERT INTO mediawiki_version (type,mw_version,notes) VALUES ('MySQL import','??', +'Imported from file created on $now. Old version: $current_version'); +}; + +print "COMMIT;\n\\o\n\n-- End of dump\n\n"; +select $oldselect; +close $mdump or die qq{Could not close "$MYSQLDUMPFILE": $!\n}; +exit; + + +__DATA__ +## Known remappings: either indicate the MySQL name, +## or leave blank if it should be skipped +pagecontent text +mwuser user +mediawiki_version +archive2 +profiling +objectcache + +## Which tables to ignore depending on the version +VERSION 1.5: trackback +VERSION 1.6: externallinks job templatelinks transcache +VERSION 1.7: filearchive langlinks querycache_info +VERSION 1.9: querycachetwo page_restrictions redirect + diff --git a/maintenance/postgres/tables.sql b/maintenance/postgres/tables.sql index e6cbbe2a..e5dd129b 100644 --- a/maintenance/postgres/tables.sql +++ b/maintenance/postgres/tables.sql @@ -5,7 +5,7 @@ -- 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 to BOOL +-- TODO: Change CHAR to BOOL (still needed as CHAR due to some PHP code) BEGIN; SET client_min_messages = 'ERROR'; @@ -42,7 +42,7 @@ 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 CIDR NULL + user_ip TEXT NULL ); CREATE INDEX user_newtalk_id_idx ON user_newtalk (user_id); CREATE INDEX user_newtalk_ip_idx ON user_newtalk (user_ip); @@ -92,9 +92,12 @@ CREATE TABLE revision ( rev_user_text TEXT NOT NULL, rev_timestamp TIMESTAMPTZ NOT NULL, rev_minor_edit CHAR NOT NULL DEFAULT '0', - rev_deleted CHAR NOT NULL DEFAULT '0' + rev_deleted CHAR NOT NULL DEFAULT '0', + rev_len INTEGER NULL, + rev_parent_id INTEGER NULL ); CREATE UNIQUE INDEX revision_unique ON revision (rev_page, rev_id); +CREATE INDEX rev_text_id_idx ON revision (rev_text_id); CREATE INDEX rev_timestamp_idx ON revision (rev_timestamp); CREATE INDEX rev_user_idx ON revision (rev_user); CREATE INDEX rev_user_text_idx ON revision (rev_user_text); @@ -108,7 +111,20 @@ CREATE TABLE pagecontent ( -- replaces reserved word 'text' ); -CREATE TABLE archive2 ( +CREATE SEQUENCE pr_id_val; +CREATE TABLE page_restrictions ( + pr_id INTEGER NOT NULL UNIQUE DEFAULT nextval('pr_id_val'), + pr_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE, + pr_type TEXT NOT NULL, + pr_level TEXT NOT NULL, + pr_cascade SMALLINT NOT NULL, + pr_user INTEGER NULL, + pr_expiry TIMESTAMPTZ NULL +); +ALTER TABLE page_restrictions ADD CONSTRAINT page_restrictions_pk PRIMARY KEY (pr_page,pr_type); + + +CREATE TABLE archive ( ar_namespace SMALLINT NOT NULL, ar_title TEXT NOT NULL, ar_text TEXT, @@ -119,24 +135,11 @@ CREATE TABLE archive2 ( ar_minor_edit CHAR NOT NULL DEFAULT '0', ar_flags TEXT, ar_rev_id INTEGER, - ar_text_id INTEGER -); -CREATE INDEX archive_name_title_timestamp ON archive2 (ar_namespace,ar_title,ar_timestamp); - --- This is the easiest way to work around the char(15) timestamp hack without modifying PHP code -CREATE VIEW archive AS -SELECT - ar_namespace, ar_title, ar_text, ar_comment, ar_user, ar_user_text, - ar_minor_edit, ar_flags, ar_rev_id, ar_text_id, - TO_CHAR(ar_timestamp, 'YYYYMMDDHH24MISS') AS ar_timestamp -FROM archive2; - -CREATE RULE archive_insert AS ON INSERT TO archive -DO INSTEAD INSERT INTO archive2 VALUES ( - NEW.ar_namespace, NEW.ar_title, NEW.ar_text, NEW.ar_comment, NEW.ar_user, NEW.ar_user_text, - TO_DATE(NEW.ar_timestamp, 'YYYYMMDDHH24MISS'), - NEW.ar_minor_edit, NEW.ar_flags, NEW.ar_rev_id, NEW.ar_text_id + ar_text_id INTEGER, + ar_deleted INTEGER NOT NULL DEFAULT 0, + ar_len INTEGER NULL ); +CREATE INDEX archive_name_title_timestamp ON archive (ar_namespace,ar_title,ar_timestamp); CREATE TABLE redirect ( @@ -223,7 +226,8 @@ CREATE TABLE ipblocks ( ipb_enable_autoblock CHAR NOT NULL DEFAULT '1', ipb_expiry TIMESTAMPTZ NOT NULL, ipb_range_start TEXT, - ipb_range_end TEXT + ipb_range_end TEXT, + ipb_deleted INTEGER NOT NULL DEFAULT 0 ); CREATE INDEX ipb_address ON ipblocks (ipb_address); CREATE INDEX ipb_user ON ipblocks (ipb_user); @@ -283,7 +287,8 @@ CREATE TABLE filearchive ( fa_description TEXT NOT NULL, fa_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL, fa_user_text TEXT NOT NULL, - fa_timestamp TIMESTAMPTZ + fa_timestamp TIMESTAMPTZ, + fa_deleted INTEGER NOT NULL DEFAULT 0 ); CREATE INDEX fa_name_time ON filearchive (fa_name, fa_timestamp); CREATE INDEX fa_dupe ON filearchive (fa_storage_group, fa_storage_key); @@ -313,7 +318,12 @@ CREATE TABLE recentchanges ( rc_patrolled CHAR NOT NULL DEFAULT '0', rc_ip CIDR, rc_old_len INTEGER, - rc_new_len INTEGER + rc_new_len INTEGER, + rc_deleted INTEGER NOT NULL DEFAULT 0, + rc_logid INTEGER NOT NULL DEFAULT 0, + rc_log_type TEXT, + rc_log_action TEXT, + rc_params TEXT ); CREATE INDEX rc_timestamp ON recentchanges (rc_timestamp); CREATE INDEX rc_namespace_title ON recentchanges (rc_namespace, rc_title); @@ -332,8 +342,8 @@ CREATE UNIQUE INDEX wl_user_namespace_title ON watchlist (wl_namespace, wl_title CREATE TABLE math ( - math_inputhash TEXT NOT NULL UNIQUE, - math_outputhash TEXT NOT NULL, + math_inputhash BYTEA NOT NULL UNIQUE, + math_outputhash BYTEA NOT NULL, math_html_conservativeness SMALLINT NOT NULL, math_html TEXT, math_mathml TEXT @@ -373,7 +383,6 @@ CREATE INDEX querycachetwo_type_value ON querycachetwo (qcc_type, qcc_value); CREATE INDEX querycachetwo_title ON querycachetwo (qcc_type,qcc_namespace,qcc_title); CREATE INDEX querycachetwo_titletwo ON querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo); - CREATE TABLE objectcache ( keyname CHAR(255) UNIQUE, value BYTEA NOT NULL DEFAULT '', @@ -388,7 +397,9 @@ CREATE TABLE transcache ( ); +CREATE SEQUENCE log_log_id_seq; CREATE TABLE logging ( + log_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('log_log_id_seq'), log_type TEXT NOT NULL, log_action TEXT NOT NULL, log_timestamp TIMESTAMPTZ NOT NULL, @@ -396,7 +407,8 @@ CREATE TABLE logging ( log_namespace SMALLINT NOT NULL, log_title TEXT NOT NULL, log_comment TEXT, - log_params TEXT + log_params TEXT, + log_deleted INTEGER NOT NULL DEFAULT 0 ); CREATE INDEX logging_type_name ON logging (log_type, log_timestamp); CREATE INDEX logging_user_time ON logging (log_timestamp, log_user); @@ -427,7 +439,6 @@ 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 ALTER TABLE page ADD titlevector tsvector; -CREATE INDEX ts2_page_title ON page USING gist(titlevector); CREATE FUNCTION ts2_page_title() RETURNS TRIGGER LANGUAGE plpgsql AS $mw$ BEGIN @@ -445,7 +456,6 @@ CREATE TRIGGER ts2_page_title BEFORE INSERT OR UPDATE ON page ALTER TABLE pagecontent ADD textvector tsvector; -CREATE INDEX ts2_page_text ON pagecontent USING gist(textvector); CREATE FUNCTION ts2_page_text() RETURNS TRIGGER LANGUAGE plpgsql AS $mw$ BEGIN @@ -461,6 +471,11 @@ $mw$; CREATE TRIGGER ts2_page_text BEFORE INSERT OR UPDATE ON pagecontent FOR EACH ROW EXECUTE PROCEDURE ts2_page_text(); +-- These are added by the setup script due to version compatibility issues +-- If using 8.1, switch from "gin" to "gist" +-- CREATE INDEX ts2_page_title ON page USING gin(titlevector); +-- CREATE INDEX ts2_page_text ON pagecontent USING gin(textvector); + CREATE FUNCTION add_interwiki (TEXT,INT,CHAR) RETURNS INT LANGUAGE SQL AS $mw$ INSERT INTO interwiki (iw_prefix, iw_url, iw_local) VALUES ($1,$2,$3); @@ -496,7 +511,6 @@ CREATE TABLE mediawiki_version ( ); INSERT INTO mediawiki_version (type,mw_version,sql_version,sql_date) - VALUES ('Creation','??','$LastChangedRevision: 18326 $','$LastChangedDate: 2006-12-14 07:34:56 -0800 (Thu, 14 Dec 2006) $'); + VALUES ('Creation','??','$LastChangedRevision: 20687 $','$LastChangedDate: 2007-03-25 20:12:26 -0400 (Sun, 25 Mar 2007) $'); -COMMIT; diff --git a/maintenance/purgeList.php b/maintenance/purgeList.php index 9bf7c1bf..abe76683 100644 --- a/maintenance/purgeList.php +++ b/maintenance/purgeList.php @@ -19,6 +19,9 @@ while( !feof( $stdin ) ) { $url = $title->getFullUrl(); echo "$url\n"; $urls[] = $url; + if( isset( $options['purge'] ) ) { + $title->invalidateCache(); + } } else { echo "(Invalid title '$page')\n"; } diff --git a/maintenance/purgeOldText.inc b/maintenance/purgeOldText.inc index 0bf6225a..c4732e97 100644 --- a/maintenance/purgeOldText.inc +++ b/maintenance/purgeOldText.inc @@ -3,15 +3,14 @@ /** * Support functions for cleaning up redundant text records * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ function PurgeRedundantText( $delete = false ) { # Data should come off the master, wrapped in a transaction - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->begin(); $tbl_arc = $dbw->tableName( 'archive' ); @@ -38,6 +37,7 @@ function PurgeRedundantText( $delete = false ) { echo( "Searching for inactive text records..." ); $set = implode( ', ', $cur ); $res = $dbw->query( "SELECT old_id FROM $tbl_txt WHERE old_id NOT IN ( $set )" ); + $old = array(); while( $row = $dbw->fetchObject( $res ) ) { $old[] = $row->old_id; } @@ -60,4 +60,4 @@ function PurgeRedundantText( $delete = false ) { } -?>
\ No newline at end of file +?> diff --git a/maintenance/purgeOldText.php b/maintenance/purgeOldText.php index e8a738ad..2147ee37 100644 --- a/maintenance/purgeOldText.php +++ b/maintenance/purgeOldText.php @@ -3,8 +3,7 @@ /** * Purge old text records from the database * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ diff --git a/maintenance/reassignEdits.inc.php b/maintenance/reassignEdits.inc.php index 6e54aea1..9f5c9c02 100644 --- a/maintenance/reassignEdits.inc.php +++ b/maintenance/reassignEdits.inc.php @@ -3,8 +3,7 @@ /** * Support functions for the reassignEdits script * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> * @licence GNU General Public Licence 2.0 or later */ @@ -19,7 +18,7 @@ * @return integer Number of entries changed, or that would be changed */ function reassignEdits( &$from, &$to, $rc = false, $report = false ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->immediateBegin(); $fname = 'reassignEdits'; @@ -137,7 +136,7 @@ function initialiseUser( $username ) { } else { $user = User::newFromName( $username ); } - $user->loadFromDatabase(); + $user->load(); return $user; } diff --git a/maintenance/reassignEdits.php b/maintenance/reassignEdits.php index 4ac566af..691fefc1 100644 --- a/maintenance/reassignEdits.php +++ b/maintenance/reassignEdits.php @@ -3,8 +3,7 @@ /** * Reassign edits from a user or IP address to another user * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup 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 38b89a48..4c02dc9c 100644 --- a/maintenance/rebuildImages.php +++ b/maintenance/rebuildImages.php @@ -26,8 +26,7 @@ * http://www.gnu.org/copyleft/gpl.html * * @author Brion Vibber <brion at pobox.com> - * @package MediaWiki - * @subpackage maintenance + * @addtogroup maintenance */ $options = array( 'missing', 'dry-run' ); @@ -75,9 +74,9 @@ class ImageBuilder extends FiveUpgrade { $portion * 100.0, $this->table, wfTimestamp( TS_DB, intval( $eta ) ), - $completed, + $completed, // $completed does not appear to be defined. $this->count, - $rate, + $rate, // $rate does not appear to be defined. $updateRate * 100.0 ); flush(); } diff --git a/maintenance/rebuildInterwiki.inc b/maintenance/rebuildInterwiki.inc index d719fd40..d85612bd 100644 --- a/maintenance/rebuildInterwiki.inc +++ b/maintenance/rebuildInterwiki.inc @@ -4,16 +4,14 @@ * Wikimedia specific! * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ class Site { var $suffix, $lateral, $url; @@ -59,6 +57,7 @@ function getRebuildInterwikiSQL() { 'sep11wiki' => 'sep11.wikipedia.org', 'metawiki' => 'meta.wikimedia.org', 'commonswiki' => 'commons.wikimedia.org', + 'specieswiki' => 'species.wikimedia.org', ); # Extra interwiki links that can't be in the intermap for some reason @@ -108,6 +107,7 @@ function getRebuildInterwikiSQL() { $iwArray = array(); foreach ( $lines as $line ) { + $matches = array(); if ( preg_match( '/^\|\s*(.*?)\s*\|\|\s*(https?:\/\/.*?)\s*$/', $line, $matches ) ) { $prefix = strtolower( $matches[1] ); $url = $matches[2]; @@ -252,7 +252,7 @@ function makeLink( $entry, &$first, $source ) { } else { $sql .= ",\n"; } - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $sql .= "(" . $dbr->makeList( $entry ) . ")"; return $sql; } diff --git a/maintenance/rebuildInterwiki.php b/maintenance/rebuildInterwiki.php index 19e081ad..b3656bb1 100644 --- a/maintenance/rebuildInterwiki.php +++ b/maintenance/rebuildInterwiki.php @@ -3,8 +3,7 @@ * Rebuild interwiki table using the file on meta and the language list * Wikimedia specific! * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/rebuildall.php b/maintenance/rebuildall.php index 7c44e300..4ac91eed 100644 --- a/maintenance/rebuildall.php +++ b/maintenance/rebuildall.php @@ -3,8 +3,7 @@ * Rebuild link tracking tables from scratch. This takes several * hours, depending on the database size and server configuration. * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/rebuildrecentchanges.inc b/maintenance/rebuildrecentchanges.inc index e077da52..9f1abf1b 100644 --- a/maintenance/rebuildrecentchanges.inc +++ b/maintenance/rebuildrecentchanges.inc @@ -3,15 +3,14 @@ * Rebuild recent changes table. * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ function rebuildRecentChangesTablePass1() { $fname = 'rebuildRecentChangesTablePass1'; - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); extract( $dbw->tableNames( 'recentchanges', 'cur', 'old' ) ); $dbw->delete( 'recentchanges', '*' ); @@ -41,17 +40,14 @@ function rebuildRecentChangesTablePass1() 'rev_page=page_id' ), $fname, array(), // INSERT options - array( 'ORDER BY' => 'rev_timestamp', 'LIMIT' => 5000 ) // SELECT options + array( 'ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 5000 ) // SELECT options ); } function rebuildRecentChangesTablePass2() { - $dbw =& wfGetDB( DB_MASTER ); - extract( $dbw->tableNames( 'recentchanges', 'revision' ) ); - - $ns = $id = $count = 0; - $title = $ct = ""; + $dbw = wfGetDB( DB_MASTER ); + list ($recentchanges, $revision) = $dbw->tableNamesN( 'recentchanges', 'revision' ); print( "Updating links...\n" ); diff --git a/maintenance/rebuildrecentchanges.php b/maintenance/rebuildrecentchanges.php index 77816cf8..7fe91dd3 100644 --- a/maintenance/rebuildrecentchanges.php +++ b/maintenance/rebuildrecentchanges.php @@ -4,8 +4,7 @@ * hours, depending on the database size and server configuration. * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/rebuildtextindex.inc b/maintenance/rebuildtextindex.inc index 5035b564..ef65eeda 100644 --- a/maintenance/rebuildtextindex.inc +++ b/maintenance/rebuildtextindex.inc @@ -8,8 +8,7 @@ require_once 'counter.php'; * but that will prevent searches from working while it runs. * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -36,7 +35,7 @@ function createTextIndex( &$database ) function rebuildTextIndex( &$database ) { - extract( $database->tableNames( 'page', 'revision', 'text', 'searchindex' ) ); + list ($page, $revision, $text, $searchindex) = $database->tableNamesN( 'page', 'revision', 'text', 'searchindex' ); $sql = "SELECT MAX(page_id) AS count FROM $page"; $res = $database->query($sql, "rebuildTextIndex" ); diff --git a/maintenance/rebuildtextindex.php b/maintenance/rebuildtextindex.php index 54672d21..6f31cbb6 100644 --- a/maintenance/rebuildtextindex.php +++ b/maintenance/rebuildtextindex.php @@ -4,8 +4,7 @@ * hours, depending on the database size and server configuration. * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/refreshImageCount.php b/maintenance/refreshImageCount.php index 88ac3c52..91145bad 100644 --- a/maintenance/refreshImageCount.php +++ b/maintenance/refreshImageCount.php @@ -5,7 +5,7 @@ require_once( "commandLine.inc" ); -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); // Load the current value from the master $count = $dbw->selectField( 'site_stats', 'ss_images' ); diff --git a/maintenance/refreshLinks.inc b/maintenance/refreshLinks.inc index 34ea6294..7a560e97 100644 --- a/maintenance/refreshLinks.inc +++ b/maintenance/refreshLinks.inc @@ -1,8 +1,7 @@ <?php /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -13,7 +12,7 @@ function refreshLinks( $start, $newOnly = false, $maxLag = false, $end = 0 ) { global $wgUser, $wgParser, $wgUseImageResize, $wgUseTidy; $fname = 'refreshLinks'; - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $start = intval( $start ); # Don't generate TeX PNGs (lack of a sensible current directory causes errors anyway) @@ -69,7 +68,7 @@ function fixLinksFromArticle( $id ) { global $wgTitle, $wgParser; $wgTitle = Title::newFromID( $id ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $linkCache =& LinkCache::singleton(); $linkCache->clear(); @@ -96,7 +95,7 @@ function deleteLinksFromNonexistent( $maxLag = 0 ) { wfWaitForSlaves( $maxLag ); - $dbw =& wfGetDB( DB_WRITE ); + $dbw = wfGetDB( DB_WRITE ); $linksTables = array( 'pagelinks' => 'pl_from', diff --git a/maintenance/refreshLinks.php b/maintenance/refreshLinks.php index e59124aa..40e12115 100644 --- a/maintenance/refreshLinks.php +++ b/maintenance/refreshLinks.php @@ -1,8 +1,7 @@ <?php /** * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/removeUnusedAccounts.inc b/maintenance/removeUnusedAccounts.inc index ac15ebef..20791230 100644 --- a/maintenance/removeUnusedAccounts.inc +++ b/maintenance/removeUnusedAccounts.inc @@ -4,8 +4,7 @@ * Support functions for the removeUnusedAccounts maintenance script * * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -18,7 +17,7 @@ * @return bool */ function isInactiveAccount( $id, $master = false ) { - $dbo =& wfGetDB( $master ? DB_MASTER : DB_SLAVE ); + $dbo = wfGetDB( $master ? DB_MASTER : DB_SLAVE ); $fname = 'isInactiveAccount'; $checks = array( 'revision' => 'rev', 'archive' => 'ar', 'logging' => 'log', 'image' => 'img', 'oldimage' => 'oi' ); diff --git a/maintenance/removeUnusedAccounts.php b/maintenance/removeUnusedAccounts.php index 33b9a0c1..42c5f059 100644 --- a/maintenance/removeUnusedAccounts.php +++ b/maintenance/removeUnusedAccounts.php @@ -4,8 +4,7 @@ * Remove unused user accounts from the database * An unused account is one which has made no edits * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -27,7 +26,7 @@ if( isset( $options['help'] ) ) { # Do an initial scan for inactive accounts and report the result echo( "Checking for unused user accounts...\n" ); $del = array(); -$dbr =& wfGetDB( DB_SLAVE ); +$dbr = wfGetDB( DB_SLAVE ); $res = $dbr->select( 'user', array( 'user_id', 'user_name' ), '', $fname ); while( $row = $dbr->fetchObject( $res ) ) { # Check the account, but ignore it if it's the primary administrator @@ -43,7 +42,7 @@ echo( "...found {$count}.\n" ); # If required, go back and delete each marked account if( $count > 0 && isset( $options['delete'] ) ) { echo( "\nDeleting inactive accounts..." ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->delete( 'user', array( 'user_id' => $del ), $fname ); echo( "done.\n" ); # Update the site_stats.ss_users field diff --git a/maintenance/renamewiki.php b/maintenance/renamewiki.php new file mode 100644 index 00000000..ebfbaea9 --- /dev/null +++ b/maintenance/renamewiki.php @@ -0,0 +1,60 @@ +<?php +require_once( "commandLine.inc" ); + +/** + * Why yes, this *is* another special-purpose Wikimedia maintenance script! + * Should be fixed up and generalized. + */ + +if ( count( $args ) != 2 ) { + wfDie( "Rename external storage dbs and leave a new one...\n" . + "Usage: php renamewiki.php <olddb> <newdb>\n" ); +} + +list( $from, $to ) = $args; + +echo "Renaming blob tables in ES from $from to $to...\n"; +echo "Sleeping 5 seconds..."; +sleep(5); +echo "\n"; + +$maintenance = "$IP/maintenance"; + +# Initialise external storage +if ( is_array( $wgDefaultExternalStore ) ) { + $stores = $wgDefaultExternalStore; +} elseif ( $wgDefaultExternalStore ) { + $stores = array( $wgDefaultExternalStore ); +} else { + $stores = array(); +} +if ( count( $stores ) ) { + require_once( 'ExternalStoreDB.php' ); + print "Initialising external storage $store...\n"; + global $wgDBuser, $wgDBpassword, $wgExternalServers; + foreach ( $stores as $storeURL ) { + $m = array(); + if ( !preg_match( '!^DB://(.*)$!', $storeURL, $m ) ) { + continue; + } + + $cluster = $m[1]; + + # Hack + $wgExternalServers[$cluster][0]['user'] = $wgDBuser; + $wgExternalServers[$cluster][0]['password'] = $wgDBpassword; + + $store = new ExternalStoreDB; + $extdb =& $store->getMaster( $cluster ); + $extdb->query( "SET table_type=InnoDB" ); + $extdb->query( "CREATE DATABASE {$to}" ); + $extdb->query( "ALTER TABLE {$from}.blobs RENAME TO {$to}.blobs" ); + $extdb->selectDB( $from ); + dbsource( "$maintenance/storage/blobs.sql", $extdb ); + $extdb->immediateCommit(); + } +} + +echo "done.\n"; + +?>
\ No newline at end of file diff --git a/maintenance/renderDump.php b/maintenance/renderDump.php index 10986f2c..5cb79c53 100644 --- a/maintenance/renderDump.php +++ b/maintenance/renderDump.php @@ -24,8 +24,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ $optionsWithArgs = array( 'report' ); diff --git a/maintenance/runJobs.php b/maintenance/runJobs.php index 343cda8a..91168e59 100644 --- a/maintenance/runJobs.php +++ b/maintenance/runJobs.php @@ -12,15 +12,16 @@ if ( isset( $options['maxjobs'] ) ) { $maxJobs = 10000; } -// Trigger errors on inappropriate use of $wgTitle -$wgTitle = new FakeTitle; +$wgTitle = Title::newFromText( 'RunJobs.php' ); -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); $n = 0; while ( $dbw->selectField( 'job', 'count(*)', '', 'runJobs.php' ) ) { - while ( false != ($job = Job::pop()) ) { + $offset=0; + while ( false != ($job = Job::pop($offset)) ) { wfWaitForSlaves( 5 ); print $job->id . " " . $job->toString() . "\n"; + $offset=$job->id; if ( !$job->run() ) { print "Error: {$job->error}\n"; } diff --git a/maintenance/showJobs.php b/maintenance/showJobs.php index 98e47de2..14aff3d5 100644 --- a/maintenance/showJobs.php +++ b/maintenance/showJobs.php @@ -12,7 +12,7 @@ require_once( "$IP/includes/FakeTitle.php" ); // Trigger errors on inappropriate use of $wgTitle $wgTitle = new FakeTitle; -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); $count = $dbw->selectField( 'job', 'count(*)', '', 'runJobs.php' ); print $count."\n"; diff --git a/maintenance/showStats.php b/maintenance/showStats.php index 27f9be6b..abab26cb 100644 --- a/maintenance/showStats.php +++ b/maintenance/showStats.php @@ -28,7 +28,7 @@ $fields = array( ); // Get cached stats from slave database -$dbr =& wfGetDB( DB_SLAVE ); +$dbr = wfGetDB( DB_SLAVE ); $fname = 'showStats'; $stats = $dbr->selectRow( 'site_stats', '*', '' ); diff --git a/maintenance/sql.php b/maintenance/sql.php new file mode 100644 index 00000000..a536705e --- /dev/null +++ b/maintenance/sql.php @@ -0,0 +1,67 @@ +<?php + +/** + * Send SQL queries from the specified file to the database, performing + * variable replacement along the way. + */ + +require_once( dirname(__FILE__) . '/' . 'commandLine.inc' ); + +if ( isset( $options['help'] ) ) { + echo "Send SQL queries to a MediaWiki database.\nUsage: php sql.php [<file>]\n"; + exit( 1 ); +} + +if ( isset( $args[0] ) ) { + $fileName = $args[0]; + $file = fopen( $fileName, 'r' ); + $promptCallback = false; +} else { + $file = STDIN; + $promptObject = new SqlPromptPrinter( "> " ); + $promptCallback = $promptObject->cb(); +} + +if ( !$file ) { + echo "Unable to open input file\n"; + exit( 1 ); +} + +$dbw =& wfGetDB( DB_MASTER ); +$error = $dbw->sourceStream( $file, $promptCallback, 'sqlPrintResult' ); +if ( $error !== true ) { + echo $error; + exit( 1 ); +} else { + exit( 0 ); +} + +//----------------------------------------------------------------------------- +class SqlPromptPrinter { + function __construct( $prompt ) { + $this->prompt = $prompt; + } + + function cb() { + return array( $this, 'printPrompt' ); + } + + function printPrompt() { + echo $this->prompt; + } +} + +function sqlPrintResult( $res ) { + if ( !$res ) { + // Do nothing + } elseif ( $res->numRows() ) { + while ( $row = $res->fetchObject() ) { + print_r( $row ); + } + } else { + $affected = $res->db->affectedRows(); + echo "Query OK, $affected row(s) affected\n"; + } +} + +?> diff --git a/maintenance/storage/blobs.sql b/maintenance/storage/blobs.sql index 5782ac47..b50865c6 100644 --- a/maintenance/storage/blobs.sql +++ b/maintenance/storage/blobs.sql @@ -1,8 +1,8 @@ -- Blobs table for external storage CREATE TABLE /*$wgDBprefix*/blobs ( - blob_id int(8) NOT NULL AUTO_INCREMENT, - blob_text mediumtext, + blob_id integer UNSIGNED NOT NULL AUTO_INCREMENT, + blob_text longblob, PRIMARY KEY (blob_id) -) TYPE=InnoDB; +) TYPE=MyISAM MAX_ROWS=1000000 AVG_ROW_LENGTH=1000000; diff --git a/maintenance/storage/checkStorage.php b/maintenance/storage/checkStorage.php index 579954d5..46b938ef 100644 --- a/maintenance/storage/checkStorage.php +++ b/maintenance/storage/checkStorage.php @@ -40,9 +40,9 @@ class CheckStorage function check( $fix = false, $xml = '' ) { $fname = 'checkStorage'; - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); if ( $fix ) { - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); print "Checking, will fix errors if possible...\n"; } else { print "Checking...\n"; @@ -197,6 +197,7 @@ class CheckStorage array( 'old_id IN (' . implode( ',', $objectRevs ) . ')' ), $fname ); while ( $row = $dbr->fetchObject( $res ) ) { $oldId = $row->old_id; + $matches = array(); if ( !preg_match( '/^O:(\d+):"(\w+)"/', $row->header, $matches ) ) { $this->error( 'restore text', "Error: invalid object header", $oldId ); continue; @@ -410,8 +411,8 @@ class CheckStorage return; } - $dbr =& wfGetDB( DB_SLAVE ); - $dbw =& wfGetDB( DB_MASTER ); + $dbr = wfGetDB( DB_SLAVE ); + $dbw = wfGetDB( DB_MASTER ); $dbr->ping(); $dbw->ping(); @@ -443,7 +444,7 @@ class CheckStorage } // Find text row again - $dbr =& wfGetDB( DB_SLAVE ); + $dbr = wfGetDB( DB_SLAVE ); $oldId = $dbr->selectField( 'revision', 'rev_text_id', array( 'rev_id' => $id ), $fname ); if ( !$oldId ) { echo "Missing revision row for rev_id $id\n"; @@ -454,6 +455,7 @@ class CheckStorage $flags = Revision::compressRevisionText( $text ); // Update the text row + $dbw = wfGetDB( DB_MASTER ); $dbw->update( 'text', array( 'old_flags' => $flags, 'old_text' => $text ), array( 'old_id' => $oldId ), diff --git a/maintenance/storage/compressOld.inc b/maintenance/storage/compressOld.inc index d38bb741..2da015b0 100644 --- a/maintenance/storage/compressOld.inc +++ b/maintenance/storage/compressOld.inc @@ -1,7 +1,6 @@ <?php /** - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -14,9 +13,8 @@ function compressOldPages( $start = 0, $extdb = '' ) { $chunksize = 50; print "Starting from old_id $start...\n"; - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); do { - $end = $start + $chunksize; $res = $dbw->select( 'text', array( 'old_id','old_flags','old_namespace','old_title','old_text' ), "old_id>=$start", $fname, array( 'ORDER BY' => 'old_id', 'LIMIT' => $chunksize, 'FOR UPDATE' ) ); if( $dbw->numRows( $res ) == 0 ) { @@ -41,7 +39,7 @@ function compressPage( $row, $extdb ) { #print "Already compressed row {$row->old_id}\n"; return false; } - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $flags = $row->old_flags ? "{$row->old_flags},gzip" : "gzip"; $compress = gzdeflate( $row->old_text ); @@ -77,8 +75,8 @@ function compressWithConcat( $startId, $maxChunkSize, $maxChunkFactor, $factorTh $fname = 'compressWithConcat'; $loadStyle = LS_CHUNKED; - $dbr =& wfGetDB( DB_SLAVE ); - $dbw =& wfGetDB( DB_MASTER ); + $dbr = wfGetDB( DB_SLAVE ); + $dbw = wfGetDB( DB_MASTER ); # Set up external storage if ( $extdb != '' ) { @@ -112,9 +110,17 @@ function compressWithConcat( $startId, $maxChunkSize, $maxChunkFactor, $factorTh "old_flags NOT LIKE '%object%' AND old_flags NOT LIKE '%external%'"); if ( $beginDate ) { + if ( !preg_match( '/^\d{14}$/', $beginDate ) ) { + print "Invalid begin date \"$beginDate\"\n"; + return false; + } $conds[] = "rev_timestamp>'" . $beginDate . "'"; } if ( $endDate ) { + if ( !preg_match( '/^\d{14}$/', $endDate ) ) { + print "Invalid end date \"$endDate\"\n"; + return false; + } $conds[] = "rev_timestamp<'" . $endDate . "'"; } if ( $loadStyle == LS_CHUNKED ) { @@ -133,9 +139,6 @@ function compressWithConcat( $startId, $maxChunkSize, $maxChunkFactor, $factorTh #$tables[] = 'page'; #$conds[] = 'page_id=rev_page AND rev_id != page_latest'; - $oldReadsSinceLastSlaveWait = 0; #check slave lag periodically - $totalMatchingRevisions = 0; - $masterPos = false; for ( $pageId = $startId; $pageId <= $maxPageId; $pageId++ ) { wfWaitForSlaves( 5 ); @@ -155,26 +158,15 @@ function compressWithConcat( $startId, $maxChunkSize, $maxChunkFactor, $factorTh $titleObj = Title::makeTitle( $pageRow->page_namespace, $pageRow->page_title ); print "$pageId\t" . $titleObj->getPrefixedDBkey() . " "; - print_r( - array( - 'rev_page' => $pageRow->page_id, - # Don't operate on the current revision - # Use < instead of <> in case the current revision has changed - # since the page select, which wasn't locking - 'rev_id < ' . $pageRow->page_latest - ) + $conds - ); - exit; - # Load revisions $revRes = $dbw->select( $tables, $fields, - array( + array_merge( array( 'rev_page' => $pageRow->page_id, # Don't operate on the current revision # Use < instead of <> in case the current revision has changed # since the page select, which wasn't locking 'rev_id < ' . $pageRow->page_latest - ) + $conds, + ), $conds ), $fname, $revLoadOptions ); diff --git a/maintenance/storage/compressOld.php b/maintenance/storage/compressOld.php index d597f1df..87aebb78 100644 --- a/maintenance/storage/compressOld.php +++ b/maintenance/storage/compressOld.php @@ -2,8 +2,7 @@ /** * Compress the text of a wiki * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -31,8 +30,8 @@ * */ -$optionsWithArgs = array( 't', 'c', 's', 'f', 'h', 'extdb', 'endid' ); -require_once( "../commandLine.inc" ); +$optionsWithArgs = array( 't', 'c', 's', 'f', 'h', 'extdb', 'endid', 'e' ); +require_once( dirname(__FILE__) . '/../commandLine.inc' ); require_once( "compressOld.inc" ); if( !function_exists( "gzdeflate" ) ) { diff --git a/maintenance/storage/dumpRev.php b/maintenance/storage/dumpRev.php index 4d0ccb58..d35af384 100644 --- a/maintenance/storage/dumpRev.php +++ b/maintenance/storage/dumpRev.php @@ -1,8 +1,9 @@ <?php -require_once( 'commandLine.inc' ); -$dbr =& wfGetDB( DB_SLAVE ); -$row = $dbr->selectRow( 'old', array( 'old_flags', 'old_text' ), array( 'old_id' => $args[0] ) ); +require_once( dirname(__FILE__) . '/../commandLine.inc' ); + +$dbr = wfGetDB( DB_SLAVE ); +$row = $dbr->selectRow( 'text', array( 'old_flags', 'old_text' ), array( 'old_id' => $args[0] ) ); $obj = unserialize( $row->old_text ); if ( get_class( $obj ) == 'concatenatedgziphistoryblob' ) { @@ -11,4 +12,4 @@ if ( get_class( $obj ) == 'concatenatedgziphistoryblob' ) { var_dump( $obj ); } -?> +?>
\ No newline at end of file diff --git a/maintenance/storage/moveToExternal.php b/maintenance/storage/moveToExternal.php index 0b46f70b..6d3ebfcb 100644 --- a/maintenance/storage/moveToExternal.php +++ b/maintenance/storage/moveToExternal.php @@ -1,96 +1,112 @@ <?php -define( 'REPORTING_INTERVAL', 100 ); +define( 'REPORTING_INTERVAL', 1 ); if ( !defined( 'MEDIAWIKI' ) ) { - $optionsWithArgs = array( 'm' ); + $optionsWithArgs = array( 'm', 's' ); - require_once( '../commandLine.inc' ); + require_once( dirname(__FILE__) . '/../commandLine.inc' ); require_once( 'ExternalStoreDB.php' ); require_once( 'resolveStubs.php' ); $fname = 'moveToExternal'; if ( !isset( $args[0] ) ) { - print "Usage: php moveToExternal.php [-m <maxid>] <cluster>\n"; + print "Usage: php moveToExternal.php [-s <startid>] [-e <endid>] <cluster>\n"; exit; } $cluster = $args[0]; - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); - if ( isset( $options['m'] ) ) { - $maxID = $options['m']; + if ( isset( $options['e'] ) ) { + $maxID = $options['e']; } else { $maxID = $dbw->selectField( 'text', 'MAX(old_id)', false, $fname ); } + $minID = isset( $options['s'] ) ? $options['s'] : 1; - moveToExternal( $cluster, $maxID ); + moveToExternal( $cluster, $maxID, $minID ); } -function moveToExternal( $cluster, $maxID ) { +function moveToExternal( $cluster, $maxID, $minID = 1 ) { $fname = 'moveToExternal'; - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); + $dbr = wfGetDB( DB_SLAVE ); - print "Moving $maxID text rows to external storage\n"; + $count = $maxID - $minID + 1; + $blockSize = 1000; + $numBlocks = ceil( $count / $blockSize ); + print "Moving text rows from $minID to $maxID to external storage\n"; $ext = new ExternalStoreDB; - for ( $id = 1; $id <= $maxID; $id++ ) { - if ( !($id % REPORTING_INTERVAL) ) { - print "$id\n"; - wfWaitForSlaves( 5 ); + $numMoved = 0; + $numStubs = 0; + + for ( $block = 0; $block < $numBlocks; $block++ ) { + $blockStart = $block * $blockSize + $minID; + $blockEnd = $blockStart + $blockSize - 1; + + if ( !($block % REPORTING_INTERVAL) ) { + print "oldid=$blockStart, moved=$numMoved\n"; + wfWaitForSlaves( 2 ); } - $row = $dbw->selectRow( 'text', array( 'old_flags', 'old_text' ), + + $res = $dbr->select( 'text', array( 'old_id', 'old_flags', 'old_text' ), array( - 'old_id' => $id, + "old_id BETWEEN $blockStart AND $blockEnd", "old_flags NOT LIKE '%external%'", ), $fname ); - if ( !$row ) { - # Non-existent or already done - continue; - } - - # Resolve stubs - $text = $row->old_text; - if ( $row->old_flags === '' ) { - $flags = 'external'; - } else { - $flags = "{$row->old_flags},external"; - } - - if ( strpos( $flags, 'object' ) !== false ) { - $obj = unserialize( $text ); - $className = strtolower( get_class( $obj ) ); - if ( $className == 'historyblobstub' ) { - resolveStub( $id, $row->old_text, $row->old_flags ); - continue; - } elseif ( $className == 'historyblobcurstub' ) { - $text = gzdeflate( $obj->getText() ); - $flags = 'utf-8,gzip,external'; - } elseif ( $className == 'concatenatedgziphistoryblob' ) { - // Do nothing + while ( $row = $dbr->fetchObject( $res ) ) { + # Resolve stubs + $text = $row->old_text; + $id = $row->old_id; + if ( $row->old_flags === '' ) { + $flags = 'external'; } else { - print "Warning: unrecognised object class \"$className\"\n"; - continue; + $flags = "{$row->old_flags},external"; + } + + if ( strpos( $flags, 'object' ) !== false ) { + $obj = unserialize( $text ); + $className = strtolower( get_class( $obj ) ); + if ( $className == 'historyblobstub' ) { + #resolveStub( $id, $row->old_text, $row->old_flags ); + #$numStubs++; + continue; + } elseif ( $className == 'historyblobcurstub' ) { + $text = gzdeflate( $obj->getText() ); + $flags = 'utf-8,gzip,external'; + } elseif ( $className == 'concatenatedgziphistoryblob' ) { + // Do nothing + } else { + print "Warning: unrecognised object class \"$className\"\n"; + continue; + } + } else { + $className = false; } - } - if ( strlen( $text ) < 100 ) { - // Don't move tiny revisions - continue; - } + if ( strlen( $text ) < 100 && $className === false ) { + // Don't move tiny revisions + continue; + } - #print "Storing " . strlen( $text ) . " bytes to $url\n"; + #print "Storing " . strlen( $text ) . " bytes to $url\n"; + #print "old_id=$id\n"; - $url = $ext->store( $cluster, $text ); - if ( !$url ) { - print "Error writing to external storage\n"; - exit; + $url = $ext->store( $cluster, $text ); + if ( !$url ) { + print "Error writing to external storage\n"; + exit; + } + $dbw->update( 'text', + array( 'old_flags' => $flags, 'old_text' => $url ), + array( 'old_id' => $id ), $fname ); + $numMoved++; } - $dbw->update( 'text', - array( 'old_flags' => $flags, 'old_text' => $url ), - array( 'old_id' => $id ), $fname ); + $dbr->freeResult( $res ); } } diff --git a/maintenance/storage/resolveStubs.php b/maintenance/storage/resolveStubs.php index e93d5c97..6836ae60 100644 --- a/maintenance/storage/resolveStubs.php +++ b/maintenance/storage/resolveStubs.php @@ -5,7 +5,7 @@ define( 'REPORTING_INTERVAL', 100 ); if ( !defined( 'MEDIAWIKI' ) ) { $optionsWithArgs = array( 'm' ); - require_once( '../commandLine.inc' ); + require_once( dirname(__FILE__) . '/../commandLine.inc' ); require_once( 'includes/ExternalStoreDB.php' ); resolveStubs(); @@ -18,21 +18,17 @@ if ( !defined( 'MEDIAWIKI' ) ) { function resolveStubs() { $fname = 'resolveStubs'; - $dbr =& wfGetDB( DB_SLAVE ); - $dbw =& wfGetDB( DB_MASTER ); + $dbr = wfGetDB( DB_SLAVE ); $maxID = $dbr->selectField( 'text', 'MAX(old_id)', false, $fname ); $blockSize = 10000; $numBlocks = intval( $maxID / $blockSize ) + 1; for ( $b = 0; $b < $numBlocks; $b++ ) { - wfWaitForSlaves( 5 ); + wfWaitForSlaves( 2 ); printf( "%5.2f%%\n", $b / $numBlocks * 100 ); $start = intval($maxID / $numBlocks) * $b + 1; $end = intval($maxID / $numBlocks) * ($b + 1); - $stubs = array(); - $flagsArray = array(); - $res = $dbr->select( 'text', array( 'old_id', 'old_text', 'old_flags' ), "old_id>=$start AND old_id<=$end " . @@ -40,7 +36,7 @@ function resolveStubs() { #"AND old_flags LIKE '%object%' AND old_flags NOT LIKE '%external%' ". "AND old_flags='object' " . - "AND old_text LIKE 'O:15:\"historyblobstub\"%'", $fname ); + "AND LOWER(LEFT(old_text,22)) = 'O:15:\"historyblobstub\"'", $fname ); while ( $row = $dbr->fetchObject( $res ) ) { resolveStub( $row->old_id, $row->old_text, $row->old_flags ); } @@ -60,8 +56,8 @@ function resolveStub( $id, $stubText, $flags ) { $stub = unserialize( $stubText ); $flags = explode( ',', $flags ); - $dbr =& wfGetDB( DB_SLAVE ); - $dbw =& wfGetDB( DB_MASTER ); + $dbr = wfGetDB( DB_SLAVE ); + $dbw = wfGetDB( DB_MASTER ); if ( strtolower( get_class( $stub ) ) !== 'historyblobstub' ) { print "Error found object of class " . get_class( $stub ) . ", expecting historyblobstub\n"; @@ -87,6 +83,7 @@ function resolveStub( $id, $stubText, $flags ) { } # Update the row + #print "oldid=$id\n"; $dbw->update( 'text', array( /* SET */ 'old_flags' => $newFlags, diff --git a/maintenance/tables.sql b/maintenance/tables.sql index 188ca63e..5d8b5481 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -130,7 +130,7 @@ CREATE TABLE /*$wgDBprefix*/user ( UNIQUE INDEX user_name (user_name), INDEX (user_email_token) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- User permissions have been broken out to a separate table; @@ -156,20 +156,20 @@ CREATE TABLE /*$wgDBprefix*/user_groups ( PRIMARY KEY (ug_user,ug_group), KEY (ug_group) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- Stores notifications of user talk page changes, for the display -- of the "you have new messages" box CREATE TABLE /*$wgDBprefix*/user_newtalk ( -- Key to user.user_id user_id int(5) NOT NULL default '0', - -- If the user is an anonymous user hir IP address is stored here + -- If the user is an anonymous user their IP address is stored here -- since the user_id of 0 is ambiguous user_ip varchar(40) NOT NULL default '', INDEX user_id (user_id), INDEX user_ip (user_ip) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- @@ -229,7 +229,7 @@ CREATE TABLE /*$wgDBprefix*/page ( INDEX (page_random), INDEX (page_len) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Every edit of a page creates also a revision row. @@ -270,6 +270,13 @@ CREATE TABLE /*$wgDBprefix*/revision ( -- Not yet used; reserved for future changes to the deletion system. rev_deleted tinyint(1) unsigned NOT NULL default '0', + -- Length of this revision in bytes + rev_len int(8) unsigned, + + -- Key to revision.rev_id + -- This field is used to add support for a tree structure (The Adjacency List Model) + rev_parent_id int(8) unsigned default NULL, + PRIMARY KEY rev_page_id (rev_page, rev_id), UNIQUE INDEX rev_id (rev_id), INDEX rev_timestamp (rev_timestamp), @@ -277,8 +284,8 @@ CREATE TABLE /*$wgDBprefix*/revision ( INDEX user_timestamp (rev_user,rev_timestamp), INDEX usertext_timestamp (rev_user_text,rev_timestamp) -) TYPE=InnoDB; - +) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=1024; +-- In case tables are created as MyISAM, use row hints for MySQL <5.0 to avoid 4GB limit -- -- Holds text of individual page revisions. @@ -313,7 +320,8 @@ CREATE TABLE /*$wgDBprefix*/text ( PRIMARY KEY old_id (old_id) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=10240; +-- In case tables are created as MyISAM, use row hints for MySQL <5.0 to avoid 4GB limit -- -- Holding area for deleted articles, which may be viewed @@ -362,10 +370,16 @@ CREATE TABLE /*$wgDBprefix*/archive ( -- ar_text and ar_flags fields will be used to create a new text -- row upon undeletion. ar_text_id int(8) unsigned, + + -- rev_deleted for archives + ar_deleted tinyint(1) unsigned NOT NULL default '0', + + -- Length of this revision in bytes + ar_len int(8) unsigned, KEY name_title_timestamp (ar_namespace,ar_title,ar_timestamp) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- @@ -385,7 +399,7 @@ CREATE TABLE /*$wgDBprefix*/pagelinks ( UNIQUE KEY pl_from (pl_from,pl_namespace,pl_title), KEY (pl_namespace,pl_title,pl_from) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- @@ -405,7 +419,7 @@ CREATE TABLE /*$wgDBprefix*/templatelinks ( UNIQUE KEY tl_from (tl_from,tl_namespace,tl_title), KEY (tl_namespace,tl_title,tl_from) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Track links to images *used inline* @@ -424,7 +438,7 @@ CREATE TABLE /*$wgDBprefix*/imagelinks ( UNIQUE KEY il_from (il_from,il_to), KEY (il_to,il_from) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Track category inclusions *used inline* @@ -464,7 +478,7 @@ CREATE TABLE /*$wgDBprefix*/categorylinks ( -- Not really used? KEY cl_timestamp (cl_to,cl_timestamp) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Track links to external URLs @@ -492,7 +506,7 @@ CREATE TABLE /*$wgDBprefix*/externallinks ( KEY (el_from, el_to(40)), KEY (el_to(60), el_from), KEY (el_index(60)) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Track interlanguage links @@ -509,7 +523,7 @@ CREATE TABLE /*$wgDBprefix*/langlinks ( UNIQUE KEY (ll_from, ll_lang), KEY (ll_lang, ll_title) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Contains a single row with some aggregate info @@ -546,7 +560,7 @@ CREATE TABLE /*$wgDBprefix*/site_stats ( UNIQUE KEY ss_row_id (ss_row_id) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Stores an ID for every time any article is visited; @@ -605,6 +619,9 @@ CREATE TABLE /*$wgDBprefix*/ipblocks ( -- Size chosen to allow IPv6 ipb_range_start tinyblob NOT NULL, ipb_range_end tinyblob NOT NULL, + + -- Flag for entries hidden from users and Sysops + ipb_deleted bool NOT NULL default 0, PRIMARY KEY ipb_id (ipb_id), @@ -617,7 +634,7 @@ CREATE TABLE /*$wgDBprefix*/ipblocks ( INDEX ipb_timestamp (ipb_timestamp), INDEX ipb_expiry (ipb_expiry) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- @@ -674,7 +691,7 @@ CREATE TABLE /*$wgDBprefix*/image ( -- Used by Special:Newimages and Special:Imagelist INDEX img_timestamp (img_timestamp) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Previous revisions of uploaded files. @@ -701,7 +718,7 @@ CREATE TABLE /*$wgDBprefix*/oldimage ( INDEX oi_name (oi_name(10)) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Record of deleted file data @@ -746,6 +763,9 @@ CREATE TABLE /*$wgDBprefix*/filearchive ( fa_user int(5) unsigned default '0', fa_user_text varchar(255) binary, fa_timestamp char(14) binary default '', + + -- Visibility of deleted revisions, bitfield + fa_deleted tinyint(1) unsigned NOT NULL default '0', PRIMARY KEY (fa_id), INDEX (fa_name, fa_timestamp), -- pick out by image name @@ -753,7 +773,7 @@ CREATE TABLE /*$wgDBprefix*/filearchive ( INDEX (fa_deleted_timestamp), -- sort by deletion time INDEX (fa_deleted_user) -- sort by deleter -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Primarily a summary table for Special:Recentchanges, @@ -815,6 +835,18 @@ CREATE TABLE /*$wgDBprefix*/recentchanges ( rc_old_len int(10), rc_new_len int(10), + -- Visibility of deleted revisions, bitfield + rc_deleted tinyint(1) unsigned NOT NULL default '0', + + -- Value corresonding to log_id, specific log entries + rc_logid int(10) unsigned NOT NULL default '0', + -- Store log type info here, or null + rc_log_type varchar(255) binary NULL default NULL, + -- Store log action or null + rc_log_action varchar(255) binary NULL default NULL, + -- Log params + rc_params blob NOT NULL default '', + PRIMARY KEY rc_id (rc_id), INDEX rc_timestamp (rc_timestamp), INDEX rc_namespace_title (rc_namespace, rc_title), @@ -824,7 +856,7 @@ CREATE TABLE /*$wgDBprefix*/recentchanges ( INDEX rc_ns_usertext (rc_namespace, rc_user_text), INDEX rc_user_text (rc_user_text, rc_timestamp) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; CREATE TABLE /*$wgDBprefix*/watchlist ( -- Key to user.user_id @@ -843,7 +875,7 @@ CREATE TABLE /*$wgDBprefix*/watchlist ( UNIQUE KEY (wl_user, wl_namespace, wl_title), KEY namespace_title (wl_namespace, wl_title) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- @@ -869,7 +901,7 @@ CREATE TABLE /*$wgDBprefix*/math ( UNIQUE KEY math_inputhash (math_inputhash) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- When using the default MySQL search backend, page titles @@ -916,7 +948,7 @@ CREATE TABLE /*$wgDBprefix*/interwiki ( UNIQUE KEY iw_prefix (iw_prefix) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Used for caching expensive grouped queries @@ -934,7 +966,7 @@ CREATE TABLE /*$wgDBprefix*/querycache ( KEY (qc_type,qc_value) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- For a few generic cache operations if not using Memcached @@ -946,7 +978,7 @@ CREATE TABLE /*$wgDBprefix*/objectcache ( UNIQUE KEY (keyname), KEY (exptime) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- -- Cache of interwiki transclusion @@ -956,7 +988,7 @@ CREATE TABLE /*$wgDBprefix*/transcache ( tc_contents text, tc_time int NOT NULL, UNIQUE INDEX tc_url_idx (tc_url) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; CREATE TABLE /*$wgDBprefix*/logging ( -- Symbolic keys for the general log type and the action type @@ -982,12 +1014,19 @@ 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(1) 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) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; CREATE TABLE /*$wgDBprefix*/trackbacks ( tb_id int auto_increment, @@ -999,7 +1038,7 @@ CREATE TABLE /*$wgDBprefix*/trackbacks ( PRIMARY KEY (tb_id), INDEX (tb_page) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- Jobs performed by parallel apache threads or a command-line daemon @@ -1020,7 +1059,7 @@ CREATE TABLE /*$wgDBprefix*/job ( PRIMARY KEY job_id (job_id), KEY (job_cmd, job_namespace, job_title) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- Details of updates to cached special pages @@ -1035,7 +1074,7 @@ CREATE TABLE /*$wgDBprefix*/querycache_info ( UNIQUE KEY ( qci_type ) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- For each redirect, this table contains exactly one row defining its target CREATE TABLE /*$wgDBprefix*/redirect ( @@ -1051,7 +1090,7 @@ CREATE TABLE /*$wgDBprefix*/redirect ( PRIMARY KEY rd_from (rd_from), KEY rd_ns_title (rd_namespace,rd_title,rd_from) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; -- Used for caching expensive grouped queries that need two links (for example double-redirects) CREATE TABLE /*$wgDBprefix*/querycachetwo ( @@ -1073,6 +1112,32 @@ CREATE TABLE /*$wgDBprefix*/querycachetwo ( KEY qcc_title (qcc_type,qcc_namespace,qcc_title), KEY qcc_titletwo (qcc_type,qcc_namespacetwo,qcc_titletwo) -) TYPE=InnoDB; +) /*$wgDBTableOptions*/; + +--- Used for storing page restrictions (i.e. protection levels) +CREATE TABLE /*$wgDBprefix*/page_restrictions ( + -- Page to apply restrictions to (Foreign Key to page). + pr_page int(8) NOT NULL, + -- The protection type (edit, move, etc) + pr_type varchar(255) NOT NULL, + -- The protection level (Sysop, autoconfirmed, etc) + pr_level varchar(255) NOT NULL, + -- Whether or not to cascade the protection down to pages transcluded. + pr_cascade tinyint(4) NOT NULL, + -- Field for future support of per-user restriction. + pr_user int(8) NULL, + -- Field for time-limited protection. + pr_expiry char(14) binary NULL, + -- Field for an ID for this restrictions row (sort-key for Special:ProtectedPages) + pr_id int unsigned NOT NULL auto_increment, + + PRIMARY KEY pr_pagetype (pr_page,pr_type), + + UNIQUE KEY pr_id (pr_id), + KEY pr_page (pr_page), + KEY pr_typelevel (pr_type,pr_level), + KEY pr_level (pr_level), + KEY pr_cascade (pr_cascade) +) /*$wgDBTableOptions*/; -- vim: sw=2 sts=2 et diff --git a/maintenance/update.php b/maintenance/update.php index 490c3f63..cf380174 100644 --- a/maintenance/update.php +++ b/maintenance/update.php @@ -4,8 +4,7 @@ require_once 'counter.php'; * Run all updaters. * * @todo document - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/updateArticleCount.inc.php b/maintenance/updateArticleCount.inc.php index 7eaea749..d4e2a9e8 100644 --- a/maintenance/updateArticleCount.inc.php +++ b/maintenance/updateArticleCount.inc.php @@ -3,8 +3,7 @@ /** * Support class for the updateArticleCount.php maintenance script * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -16,7 +15,7 @@ class ArticleCounter { function ArticleCounter() { global $wgContentNamespaces; $this->namespaces = $wgContentNamespaces; - $this->dbr =& wfGetDB( DB_SLAVE ); + $this->dbr = wfGetDB( DB_SLAVE ); } /** @@ -37,7 +36,7 @@ class ArticleCounter { * @return string */ function makeSql() { - extract( $this->dbr->tableNames( 'page', 'pagelinks' ) ); + list( $page, $pagelinks ) = $this->dbr->tableNamesN( 'page', 'pagelinks' ); $nsset = $this->makeNsSet(); return "SELECT DISTINCT page_namespace,page_title FROM $page,$pagelinks " . "WHERE pl_from=page_id and page_namespace IN ( $nsset ) " . diff --git a/maintenance/updateArticleCount.php b/maintenance/updateArticleCount.php index 112274d2..03c7939c 100644 --- a/maintenance/updateArticleCount.php +++ b/maintenance/updateArticleCount.php @@ -4,8 +4,7 @@ * Maintenance script to provide a better count of the number of articles * and update the site statistics table, if desired * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance * @author Rob Church <robchur@gmail.com> */ @@ -28,7 +27,7 @@ if( $result !== false ) { echo( "found {$result}.\n" ); if( isset( $options['update'] ) && $options['update'] ) { echo( "Updating site statistics table... " ); - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $dbw->update( 'site_stats', array( 'ss_good_articles' => $result ), array( 'ss_row_id' => 1 ), __METHOD__ ); echo( "done.\n" ); } else { diff --git a/maintenance/updateRestrictions.php b/maintenance/updateRestrictions.php new file mode 100644 index 00000000..6c8ffb5e --- /dev/null +++ b/maintenance/updateRestrictions.php @@ -0,0 +1,67 @@ +<?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. + */ + +define( 'BATCH_SIZE', 100 ); + +require_once 'commandLine.inc'; + +$db =& wfGetDB( DB_MASTER ); +if ( !$db->tableExists( 'page_restrictions' ) ) { + echo "page_restrictions does not exist\n"; + exit( 1 ); +} + +migrate_page_restrictions( $db ); + +function migrate_page_restrictions( $db ) { + + $start = $db->selectField( 'page', 'MIN(page_id)', false, __FUNCTION__ ); + $end = $db->selectField( 'page', 'MAX(page_id)', false, __FUNCTION__ ); + $blockStart = $start; + $blockEnd = $start + BATCH_SIZE - 1; + $encodedExpiry = Block::decodeExpiry(''); + while ( $blockEnd <= $end ) { + $cond = "page_id BETWEEN $blockStart AND $blockEnd AND page_restrictions !=''"; + $res = $db->select( 'page', array('page_id', 'page_restrictions'), $cond, __FUNCTION__ ); + $batch = array(); + while ( $row = $db->fetchObject( $res ) ) { + $oldRestrictions = array(); + foreach( explode( ':', trim( $row->page_restrictions ) ) as $restrict ) { + $temp = explode( '=', trim( $restrict ) ); + if(count($temp) == 1) { + // old old format should be treated as edit/move restriction + $oldRestrictions["edit"] = trim( $temp[0] ); + $oldRestrictions["move"] = trim( $temp[0] ); + } else { + $oldRestrictions[$temp[0]] = trim( $temp[1] ); + } + } + # Update restrictions table + foreach( $oldRestrictions as $action => $restrictions ) { + $batch[] = array( + 'pr_page' => $row->page_id, + 'pr_type' => $action, + 'pr_level' => $restrictions, + 'pr_cascade' => 0, + 'pr_expiry' => $encodedExpiry + ); + } + } + # We use insert() and not replace() as Article.php replaces + # page_restrictions with '' when protected in the restrictions table + if ( count( $batch ) ) { + $db->insert( 'page_restrictions', $batch, __FUNCTION__ ); + } + $blockStart += BATCH_SIZE; + $blockEnd += BATCH_SIZE; + wfWaitForSlaves( 5 ); + } +} + +?> diff --git a/maintenance/updateSearchIndex.inc b/maintenance/updateSearchIndex.inc index ed01575c..bf2b8c37 100644 --- a/maintenance/updateSearchIndex.inc +++ b/maintenance/updateSearchIndex.inc @@ -1,7 +1,6 @@ <?php /** - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -14,7 +13,7 @@ function updateSearchIndex( $start, $end, $maxLockTime, $quiet ) { $wgQuiet = $quiet; $wgDisableSearchUpdate = false; - $dbw =& wfGetDB( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $recentchanges = $dbw->tableName( 'recentchanges' ); output( "Updating searchindex between $start and $end\n" ); @@ -74,7 +73,9 @@ function updateSearchIndex( $start, $end, $maxLockTime, $quiet ) { # Unlock searchindex if ( $maxLockTime ) { + output( " --- Unlocking --" ); unlockSearchindex( $dbw ); + output( "\n" ); } output( "Done\n" ); } @@ -91,11 +92,11 @@ function lockSearchindex( &$db ) { $items[] = $db->tableName( $table ) . ' READ'; } $sql = "LOCK TABLES " . implode( ',', $items ); - $db->query( $sql ); + $db->query( $sql, 'updateSearchIndex.inc ' . __METHOD__ ); } function unlockSearchindex( &$db ) { - $db->query( "UNLOCK TABLES" ); + $db->query( "UNLOCK TABLES", 'updateSearchIndex.inc ' . __METHOD__ ); } # Unlock and lock again diff --git a/maintenance/updateSearchIndex.php b/maintenance/updateSearchIndex.php index b03dc00d..9456be2a 100644 --- a/maintenance/updateSearchIndex.php +++ b/maintenance/updateSearchIndex.php @@ -9,8 +9,7 @@ * LOCKTIME is how long the searchindex and cur tables will be locked for * -q means quiet * - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ diff --git a/maintenance/updateSpecialPages.php b/maintenance/updateSpecialPages.php index 89b5aa94..c7f9749d 100644 --- a/maintenance/updateSpecialPages.php +++ b/maintenance/updateSpecialPages.php @@ -17,7 +17,7 @@ if(@$options['help']) { } $wgOut->disable(); -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); foreach ( $wgQueryPages as $page ) { @list( $class, $special, $limit ) = $page; @@ -28,11 +28,11 @@ foreach ( $wgQueryPages as $page ) { continue; } - if ( in_array( $special, $wgDisableQueryPageUpdate ) ) { + if ( $wgDisableQueryPageUpdate && in_array( $special, $wgDisableQueryPageUpdate ) ) { printf("%-30s disabled\n", $special); continue; } - + $specialObj = SpecialPage::getPage( $special ); if ( !$specialObj ) { print "No such special page: $special\n"; @@ -86,7 +86,7 @@ foreach ( $wgQueryPages as $page ) { # Wait for the slave to catch up /* - $slaveDB =& wfGetDB( DB_SLAVE, array('QueryPage::recache', 'vslow' ) ); + $slaveDB = wfGetDB( DB_SLAVE, array('QueryPage::recache', 'vslow' ) ); while( $slaveDB->getLag() > 600 ) { print "Slave lagged, waiting...\n"; sleep(30); diff --git a/maintenance/updaters.inc b/maintenance/updaters.inc index 9641d60d..b3fb16f4 100644 --- a/maintenance/updaters.inc +++ b/maintenance/updaters.inc @@ -1,7 +1,6 @@ <?php /** - * @package MediaWiki - * @subpackage Maintenance + * @addtogroup Maintenance */ /** */ @@ -64,9 +63,19 @@ $wgNewFields = array( array( 'ipblocks', 'ipb_range_start', 'patch-ipb_range_start.sql' ), array( 'site_stats', 'ss_images', 'patch-ss_images.sql' ), array( 'ipblocks', 'ipb_anon_only', 'patch-ipb_anon_only.sql' ), - array( 'ipblocks', 'ipb_enable_autoblock', 'patch-ipb_optional_autoblock.sql' ), + array( 'ipblocks', 'ipb_enable_autoblock', 'patch-ipb_optional_autoblock.sql' ), array( 'user', 'user_newpass_time','patch-user_newpass_time.sql' ), array( 'user', 'user_editcount', 'patch-user_editcount.sql' ), + array( 'recentchanges', 'rc_deleted', 'patch-rc_deleted.sql' ), + array( 'logging', 'log_id', 'patch-log_id.sql' ), + array( 'logging', 'log_deleted', 'patch-log_deleted.sql' ), + array( 'archive', 'ar_deleted', 'patch-ar_deleted.sql' ), + array( 'ipblocks', 'ipb_deleted', 'patch-ipb_deleted.sql' ), + array( 'filearchive', 'fa_deleted', 'patch-fa_deleted.sql' ), + array( 'revision', 'rev_len', 'patch-rev_len.sql' ), + array( 'archive', 'ar_len', 'patch-ar_len.sql' ), + array( 'revision', 'rev_parent_id', 'patch-rev_parent_id.sql' ), + array( 'page_restrictions', 'pr_id', 'patch-page_restrictions_sortkey.sql' ), ); function rename_table( $from, $to, $patch ) { @@ -164,7 +173,7 @@ function do_index_update() { # Check that proper indexes are in place global $wgDatabase; $meta = $wgDatabase->fieldInfo( "recentchanges", "rc_timestamp" ); - if( $meta->multiple_key == 0 ) { + if( !$meta->isMultipleKey() ) { echo "Updating indexes to 20031107: "; dbsource( archive("patch-indexes.sql") ); echo "ok\n"; @@ -178,7 +187,7 @@ function do_image_index_update() { global $wgDatabase; $meta = $wgDatabase->fieldInfo( "image", "img_major_mime" ); - if( $meta->multiple_key == 0 ) { + if( !$meta->isMultipleKey() ) { echo "Updating indexes to 20050912: "; dbsource( archive("patch-mimesearch-indexes.sql") ); echo "ok\n"; @@ -321,16 +330,16 @@ function do_schema_restructuring() { echo "...page table already exists.\n"; } else { echo "...converting from cur/old to page/revision/text DB structure.\n"; flush(); - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "......checking for duplicate entries.\n"; flush(); - extract( $wgDatabase->tableNames( 'cur', 'old', 'page', 'revision', 'text' ) ); + list ($cur, $old, $page, $revision, $text) = $wgDatabase->tableNamesN( 'cur', 'old', 'page', 'revision', 'text' ); $rows = $wgDatabase->query( "SELECT cur_title, cur_namespace, COUNT(cur_namespace) AS c FROM $cur GROUP BY cur_title, cur_namespace HAVING c>1", $fname ); if ( $wgDatabase->numRows( $rows ) > 0 ) { - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "......<b>Found duplicate entries</b>\n"; echo ( sprintf( "<b> %-60s %3s %5s</b>\n", 'Title', 'NS', 'Count' ) ); while ( $row = $wgDatabase->fetchObject( $rows ) ) { @@ -378,12 +387,12 @@ function do_schema_restructuring() { } $sql = "DELETE FROM $cur WHERE cur_id IN ( " . join( ',', $deleteId ) . ')'; $rows = $wgDatabase->query( $sql, $fname ); - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "......<b>Deleted</b> ".$wgDatabase->affectedRows()." records.\n"; } - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "......Creating tables.\n"; $wgDatabase->query("CREATE TABLE $page ( page_id int(8) unsigned NOT NULL auto_increment, @@ -412,7 +421,8 @@ function do_schema_restructuring() { rev_timestamp char(14) binary NOT NULL default '', rev_minor_edit tinyint(1) unsigned NOT NULL default '0', rev_deleted tinyint(1) unsigned NOT NULL default '0', - + rev_len int(8) unsigned, + rev_parent_id int(8) unsigned default NULL, PRIMARY KEY rev_page_id (rev_page, rev_id), UNIQUE INDEX rev_id (rev_id), INDEX rev_timestamp (rev_timestamp), @@ -421,15 +431,15 @@ function do_schema_restructuring() { INDEX usertext_timestamp (rev_user_text,rev_timestamp) ) TYPE=InnoDB", $fname ); - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "......Locking tables.\n"; $wgDatabase->query( "LOCK TABLES $page WRITE, $revision WRITE, $old WRITE, $cur WRITE", $fname ); $maxold = intval( $wgDatabase->selectField( 'old', 'max(old_id)', '', $fname ) ); - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "......maxold is {$maxold}\n"; - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); global $wgLegacySchemaConversion; if( $wgLegacySchemaConversion ) { // Create HistoryBlobCurStub entries. @@ -449,7 +459,7 @@ function do_schema_restructuring() { SELECT cur_namespace, cur_title, $cur_text, cur_comment, cur_user, cur_user_text, cur_timestamp, cur_minor_edit, $cur_flags FROM $cur", $fname ); - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "......Setting up revision table.\n"; $wgDatabase->query( "INSERT INTO $revision (rev_id, rev_page, rev_comment, rev_user, rev_user_text, rev_timestamp, rev_minor_edit) @@ -457,7 +467,7 @@ function do_schema_restructuring() { old_timestamp, old_minor_edit FROM $old,$cur WHERE old_namespace=cur_namespace AND old_title=cur_title", $fname ); - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "......Setting up page table.\n"; $wgDatabase->query( "INSERT INTO $page (page_id, page_namespace, page_title, page_restrictions, page_counter, page_is_redirect, page_is_new, page_random, page_touched, page_latest, page_len) @@ -466,22 +476,21 @@ function do_schema_restructuring() { FROM $cur,$revision WHERE cur_id=rev_page AND rev_timestamp=cur_timestamp AND rev_id > {$maxold}", $fname ); - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "......Unlocking tables.\n"; $wgDatabase->query( "UNLOCK TABLES", $fname ); - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "......Renaming old.\n"; $wgDatabase->query( "ALTER TABLE $old RENAME TO $text", $fname ); - echo wfTimestamp(); + echo wfTimestamp( TS_DB ); echo "...done.\n"; } } function do_inverse_timestamp() { global $wgDatabase; - $fname="do_schema_restructuring"; if( $wgDatabase->fieldExists( 'revision', 'inverse_timestamp' ) ) { echo "Removing revision.inverse_timestamp and fixing indexes... "; dbsource( archive( 'patch-inverse_timestamp.sql' ), $wgDatabase ); @@ -670,7 +679,7 @@ function do_user_groups_reformat() { global $wgDatabase; $info = $wgDatabase->fieldInfo( 'user_groups', 'ug_group' ); - if( $info->type == 'int' ) { + if( $info->type() == 'int' ) { $oldug = $wgDatabase->tableName( 'user_groups' ); $newug = $wgDatabase->tableName( 'user_groups_bogus' ); echo "user_groups is in bogus intermediate format. Renaming to $newug... "; @@ -697,7 +706,7 @@ function do_watchlist_null() { global $wgDatabase; $info = $wgDatabase->fieldInfo( 'watchlist', 'wl_notificationtimestamp' ); - if( $info->not_null ) { + if( !$info->nullable() ) { echo "Making wl_notificationtimestamp nullable... "; dbsource( archive( 'patch-watchlist-null.sql' ), $wgDatabase ); echo "ok\n"; @@ -827,6 +836,22 @@ function do_backlinking_indices_update() { } } +function do_stats_init() { + // Sometimes site_stats table is not properly populated. + global $wgDatabase; + echo "Checking site_stats row..."; + $row = $wgDatabase->selectRow( 'site_stats', '*', array( 'ss_row_id' => 1 ), __METHOD__ ); + if( $row === false ) { + echo "data is missing! rebuilding...\n"; + + global $IP; + require_once "$IP/maintenance/initStats.inc"; + wfInitStats(); + } else { + echo "ok.\n"; + } +} + function purge_cache() { global $wgDatabase; # We can't guarantee that the user will be able to use TRUNCATE, @@ -839,7 +864,7 @@ function purge_cache() { function do_all_updates( $shared = false, $purge = true ) { global $wgNewTables, $wgNewFields, $wgRenamedTables, $wgSharedDB, $wgDatabase, $wgDBtype, $IP; - $doUser = !$wgSharedDB || $doShared; + $doUser = !$wgSharedDB || $shared; if ($wgDBtype === 'postgres') { do_postgres_updates(); @@ -906,10 +931,14 @@ function do_all_updates( $shared = false, $purge = true ) { do_backlinking_indices_update(); flush(); - echo "Deleting old default messages..."; flush(); + do_restrictions_update(); flush (); + + echo "Deleting old default messages (this may take a long time!)..."; flush(); deleteDefaultMessages(); echo "Done\n"; flush(); + do_stats_init(); flush(); + if( $purge ) { purge_cache(); flush(); @@ -919,179 +948,406 @@ function do_all_updates( $shared = false, $purge = true ) { function archive($name) { global $wgDBtype, $IP; switch ($wgDBtype) { - case "oracle": - return "$IP/maintenance/oracle/archives/$name"; + case "postgres": + return "$IP/maintenance/postgres/archives/$name"; default: return "$IP/maintenance/archives/$name"; } } -function do_postgres_updates() { - global $wgDatabase, $wgVersion, $wgDBmwschema; +function do_restrictions_update() { + # Adding page_restrictions table, obsoleting page.page_restrictions. + # Migrating old restrictions to new table + # -- Andrew Garrett, January 2007. - # Just in case their LocalSetings.php does not have this: - if ( !isset( $wgDBmwschema )) - $wgDBmwschema = 'mediawiki'; + global $wgDatabase; + + $name = 'page_restrictions'; + $patch = 'patch-page_restrictions.sql'; + $patch2 = 'patch-page_restrictions_sortkey.sql'; + + if ( $wgDatabase->tableExists( $name ) ) { + echo "...$name table already exists.\n"; + } else { + echo "Creating $name table..."; + dbsource( archive($patch), $wgDatabase ); + dbsource( archive($patch2), $wgDatabase ); + echo "ok\n"; + + echo "Migrating old restrictions to new table..."; + + $res = $wgDatabase->select( 'page', array( 'page_id', 'page_restrictions' ), array("page_restrictions!=''", "page_restrictions!='edit=:move='"), __METHOD__ ); + + $count = 0; + + while ($row = $wgDatabase->fetchObject($res) ) { + $count = ($count + 1) % 100; + + if ($count == 0) { + if ( function_exists( 'wfWaitForSlaves' ) ) { + wfWaitForSlaves( 10 ); + } else { + sleep( 1 ); + } + } + + # Figure out what the restrictions are.. + $id = $row->page_id; + $flatrestrictions = explode( ':', $row->page_restrictions ); + + $restrictions = array (); + foreach( $flatrestrictions as $restriction ) { + $thisrestriction = explode( '=', $restriction, 2 ); + if( count( $thisrestriction ) == 1 ) { + // Compatibility with old protections from before + // separate move protection was added. + list( $level ) = $thisrestriction; + if( $level ) { + $restrictions['edit'] = $level; + $restrictions['move'] = $level; + } + } else { + list( $type, $level ) = $thisrestriction; + if( $level ) { + $restrictions[$type] = $level; + } + } + + $wgDatabase->update( 'page', array ( 'page_restrictions' => ''), array( 'page_id' => $id ), __METHOD__ ); + + } + + foreach( $restrictions as $type => $level ) { + $wgDatabase->insert( 'page_restrictions', array ( 'pr_page' => $id, + 'pr_type' => $type, + 'pr_level' => $level, + 'pr_cascade' => 0 ), + __METHOD__ ); + } + } + print "ok\n"; + } + +} + +function +pg_describe_table($table) +{ +global $wgDatabase, $wgDBmwschema; + $q = <<<END +SELECT attname, attnum FROM pg_namespace, pg_class, pg_attribute + WHERE pg_class.relnamespace = pg_namespace.oid + AND attrelid=pg_class.oid AND attnum > 0 + AND relname=%s AND nspname=%s +END; + $res = $wgDatabase->query(sprintf($q, + $wgDatabase->addQuotes($table), + $wgDatabase->addQuotes($wgDBmwschema))); + if (!$res) + return null; + + $cols = array(); + while ($r = $wgDatabase->fetchRow($res)) { + $cols[] = array( + "name" => $r[0], + "ord" => $r[1], + ); + } + return $cols; +} - ## Default to the oldest supported version - $version = 1.7; +function +pg_describe_index($idx) +{ +global $wgDatabase, $wgDBmwschema; + + // first fetch the key (which is a list of columns ords) and + // the table the index applies to (an oid) + $q = <<<END +SELECT indkey, indrelid FROM pg_namespace, pg_class, pg_index + WHERE nspname=%s + AND pg_class.relnamespace = pg_namespace.oid + AND relname=%s + AND indexrelid=pg_class.oid +END; + $res = $wgDatabase->query(sprintf($q, + $wgDatabase->addQuotes($wgDBmwschema), + $wgDatabase->addQuotes($idx))); + if (!$res) + return null; + if (!($r = $wgDatabase->fetchRow($res))) { + $wgDatabase->freeResult($res); + return null; + } - if ($wgDatabase->tableExists("mediawiki_version")) { - $version = "1.8"; - $sql = "SELECT mw_version FROM mediawiki_version ORDER BY cdate DESC LIMIT 1"; - $tempversion = pg_fetch_result($wgDatabase->doQuery($sql),0,0); - $thisver = array(); - if (preg_match('/(\d+\.\d+)/', $tempversion, $thisver)) { - $version = $thisver[1]; + $indkey = $r[0]; + $relid = intval($r[1]); + $indkeys = explode(" ", $indkey); + $wgDatabase->freeResult($res); + + $colnames = array(); + foreach ($indkeys as $rid) { + $query = <<<END +SELECT attname FROM pg_class, pg_attribute + WHERE attrelid=$relid + AND attnum=%d + AND attrelid=pg_class.oid +END; + $r2 = $wgDatabase->query(sprintf($query, $rid)); + if (!$r2) + return null; + if (!($row2 = $wgDatabase->fetchRow($r2))) { + $wgDatabase->freeResult($r2); + return null; } + $colnames[] = $row2[0]; + $wgDatabase->freeResult($r2); } - print " Detected version: $version "; - $upgrade = ''; + return $colnames; +} - if ($version <= 1.7) { - $upgrade = <<<PGEND +function +pg_index_exists($table, $index) +{ +global $wgDatabase, $wgDBmwschema; + $exists = $wgDatabase->selectField("pg_indexes", "indexname", + array( "indexname" => $index, + "tablename" => $table, + "schemaname" => $wgDBmwschema)); + return $exists === $index; +} --- Type tweaking: -ALTER TABLE oldimage ALTER oi_size TYPE INTEGER; -ALTER TABLE oldimage ALTER oi_width TYPE INTEGER; -ALTER TABLE oldimage ALTER oi_height TYPE INTEGER; +function +pg_fkey_deltype($fkey) +{ +global $wgDatabase, $wgDBmwschema; + $q = <<<END +SELECT confdeltype FROM pg_constraint, pg_namespace + WHERE connamespace=pg_namespace.oid + AND nspname=%s + AND conname=%s; +END; + $r = $wgDatabase->query(sprintf($q, + $wgDatabase->addQuotes($wgDBmwschema), + $wgDatabase->addQuotes($fkey))); + if (!($row = $wgDatabase->fetchRow($r))) + return null; + return $row[0]; +} -ALTER TABLE image ALTER img_size TYPE INTEGER; -ALTER TABLE image ALTER img_width TYPE INTEGER; -ALTER TABLE image ALTER img_height TYPE INTEGER; +function +pg_rule_def($table, $rule) +{ +global $wgDatabase, $wgDBmwschema; + $q = <<<END +SELECT definition FROM pg_rules + WHERE schemaname = %s + AND tablename = %s + AND rulename = %s +END; + $r = $wgDatabase->query(sprintf($q, + $wgDatabase->addQuotes($wgDBmwschema), + $wgDatabase->addQuotes($table), + $wgDatabase->addQuotes($rule))); + $row = $wgDatabase->fetchRow($r); + if (!$row) + return null; + $d = $row[0]; + $wgDatabase->freeResult($r); + return $d; +} --- Constraint tweaking: -ALTER TABLE recentchanges ALTER rc_cur_id DROP NOT NULL; +function do_postgres_updates() { + global $wgDatabase, $wgVersion, $wgDBmwschema, $wgShowExceptionDetails; --- New columns: -ALTER TABLE ipblocks ADD ipb_anon_only CHAR NOT NULL DEFAULT '0'; -ALTER TABLE ipblocks ADD ipb_create_account CHAR NOT NULL DEFAULT '1'; + $wgShowExceptionDetails = 1; --- Index order rearrangements: -DROP INDEX pagelink_unique; -CREATE UNIQUE INDEX pagelink_unique ON pagelinks (pl_from,pl_namespace,pl_title); + # Just in case their LocalSettings.php does not have this: + if ( !isset( $wgDBmwschema )) + $wgDBmwschema = 'mediawiki'; --- Rename tables -ALTER TABLE "user" RENAME TO mwuser; -ALTER TABLE "text" RENAME to pagecontent; + $newsequences = array( + "log_log_id_seq", + "pr_id_val", + ); --- New tables: -CREATE TABLE profiling ( - pf_count INTEGER NOT NULL DEFAULT 0, - pf_time NUMERIC(18,10) NOT NULL DEFAULT 0, - pf_name TEXT NOT NULL, - pf_server TEXT NULL -); -CREATE UNIQUE INDEX pf_name_server ON profiling (pf_name, pf_server); - -CREATE TABLE mediawiki_version ( - type TEXT NOT NULL, - mw_version TEXT NOT NULL, - notes TEXT NULL, - - pg_version TEXT NULL, - pg_dbname TEXT NULL, - pg_user TEXT NULL, - pg_port TEXT NULL, - mw_schema TEXT NULL, - ts2_schema TEXT NULL, - ctype TEXT NULL, - - sql_version TEXT NULL, - sql_date TEXT NULL, - cdate TIMESTAMPTZ NOT NULL DEFAULT now() -); + $newtables = array( + array("mediawiki_version", "patch-mediawiki_version.sql"), + array("mwuser", "patch-mwuser.sql"), + array("pagecontent", "patch-pagecontent.sql"), + array("querycachetwo", "patch-querycachetwo.sql"), + array("page_restrictions", "patch-page_restrictions.sql"), + array("profiling", "patch-profiling.sql"), + array("redirect", "patch-redirect.sql"), + ); --- Special modifications -ALTER TABLE archive RENAME to archive2; -CREATE VIEW archive AS -SELECT - ar_namespace, ar_title, ar_text, ar_comment, ar_user, ar_user_text, - ar_minor_edit, ar_flags, ar_rev_id, ar_text_id, - TO_CHAR(ar_timestamp, 'YYYYMMDDHH24MISS') AS ar_timestamp -FROM archive2; - -CREATE RULE archive_insert AS ON INSERT TO archive -DO INSTEAD INSERT INTO archive2 VALUES ( - NEW.ar_namespace, NEW.ar_title, NEW.ar_text, NEW.ar_comment, NEW.ar_user, NEW.ar_user_text, - TO_DATE(NEW.ar_timestamp, 'YYYYMMDDHH24MISS'), - NEW.ar_minor_edit, NEW.ar_flags, NEW.ar_rev_id, NEW.ar_text_id -); + $newcols = array( + array("archive", "ar_len", "INTEGER"), + array("ipblocks", "ipb_anon_only", "CHAR NOT NULL DEFAULT '0'"), + array("ipblocks", "ipb_create_account", "CHAR NOT NULL DEFAULT '1'"), + array("ipblocks", "ipb_deleted", "INTEGER NOT NULL DEFAULT 0"), + array("ipblocks", "ipb_enable_autoblock", "CHAR NOT NULL DEFAULT '1'"), + array("filearchive", "fa_deleted", "INTEGER NOT NULL DEFAULT 0"), + array("logging", "log_deleted", "INTEGER NOT NULL DEFAULT 0"), + array("logging", "log_id", "INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('log_log_id_seq')"), + array("logging", "log_params", "TEXT"), + array("mwuser", "user_editcount", "INTEGER"), + array("mwuser", "user_newpass_time", "TIMESTAMPTZ"), + array("page_restrictions", "pr_id", "INTEGER NOT NULL UNIQUE DEFAULT nextval('pr_id_val')"), + array("recentchanges", "rc_deleted", "INTEGER NOT NULL DEFAULT 0"), + array("recentchanges", "rc_log_action", "TEXT"), + array("recentchanges", "rc_log_type", "TEXT"), + array("recentchanges", "rc_logid", "INTEGER NOT NULL DEFAULT 0"), + array("recentchanges", "rc_new_len", "INTEGER"), + array("recentchanges", "rc_old_len", "INTEGER"), + array("recentchanges", "rc_params", "TEXT"), + array("revision", "rev_len", "INTEGER"), + ); -CREATE FUNCTION page_deleted() RETURNS TRIGGER LANGUAGE plpgsql AS -\$mw\$ -BEGIN -DELETE FROM recentchanges WHERE rc_namespace = OLD.page_namespace AND rc_title = OLD.page_title; -RETURN NULL; -END; -\$mw\$; -CREATE TRIGGER page_deleted AFTER DELETE ON page - FOR EACH ROW EXECUTE PROCEDURE page_deleted(); + # table, column, desired type, USING clause if needed + $typechanges = array( + array("image", "img_size", "int4", ""), + array("image", "img_width", "int4", ""), + array("image", "img_height", "int4", ""), + array("ipblocks", "ipb_address", "text", "ipb_address::text"), + array("math", "math_inputhash", "bytea", "decode(math_inputhash,'escape')"), + array("math", "math_outputhash", "bytea", "decode(math_outputhash,'escape')"), + array("oldimage", "oi_size", "int4", ""), + array("oldimage", "oi_width", "int4", ""), + array("oldimage", "oi_height", "int4", ""), + array("user_newtalk", "user_ip", "text", "host(user_ip)"), + ); + + $newindexes = array( + array("revision", "rev_text_id_idx", "patch-rev_text_id_idx.sql") + ); + + $newrules = array( + ); -PGEND; - } ## end version 1.7 + foreach ($newsequences as $ns) { + if ($wgDatabase->sequenceExists($ns)) { + echo "... sequence $ns already exists\n"; + continue; + } - else if ($version <= 1.8) { - $upgrade = <<<PGEND + echo "... create sequence $ns\n"; + $wgDatabase->query("CREATE SEQUENCE $ns"); + } --- Tighten up restrictions on the revision table so we don't lose data: -ALTER TABLE revision DROP CONSTRAINT revision_rev_user_fkey; -ALTER TABLE revision ADD CONSTRAINT revision_rev_user_fkey - FOREIGN KEY (rev_user) REFERENCES mwuser(user_id) ON DELETE RESTRICT; + foreach ($newtables as $nt) { + if ($wgDatabase->tableExists($nt[0])) { + echo "... table $nt[0] already exists\n"; + continue; + } --- New columns for better password tracking: -ALTER TABLE mwuser ADD user_newpass_time TIMESTAMPTZ; -ALTER TABLE mwuser ADD user_editcount INTEGER; + echo "... create table $nt[0]\n"; + dbsource(archive($nt[1])); + } --- New column for autoblocking problem users -ALTER TABLE ipblocks ADD ipb_enable_autoblock CHAR NOT NULL DEFAULT '1'; + ## Needed before newcols + if ($wgDatabase->tableExists("archive2")) { + echo "... convert archive2 back to normal archive table\n"; + if ($wgDatabase->ruleExists("archive", "archive_insert")) { + echo "... drop rule archive_insert\n"; + $wgDatabase->query("DROP RULE archive_insert ON archive"); + } + if ($wgDatabase->ruleExists("archive", "archive_delete")) { + echo "... drop rule archive_delete\n"; + $wgDatabase->query("DROP RULE archive_delete ON archive"); + } --- Despite it's name, ipb_address does not necessarily contain IP addresses :) -ALTER TABLE ipblocks ALTER ipb_address TYPE TEXT USING ipb_address::TEXT; + dbsource(archive("patch-remove-archive2.sql")); + } else + echo "... obsolete archive2 not present\n"; --- New tables: -CREATE TABLE redirect ( - rd_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE, - rd_namespace SMALLINT NOT NULL, - rd_title TEXT NOT NULL -); -CREATE INDEX redirect_ns_title ON redirect (rd_namespace,rd_title,rd_from); - -CREATE TABLE querycachetwo ( - qcc_type TEXT NOT NULL, - qcc_value SMALLINT NOT NULL DEFAULT 0, - qcc_namespace INTEGER NOT NULL DEFAULT 0, - qcc_title TEXT NOT NULL DEFAULT '', - qcc_namespacetwo INTEGER NOT NULL DEFAULT 0, - qcc_titletwo TEXT NOT NULL DEFAULT '' -); -CREATE INDEX querycachetwo_type_value ON querycachetwo (qcc_type, qcc_value); -CREATE INDEX querycachetwo_title ON querycachetwo (qcc_type,qcc_namespace,qcc_title); -CREATE INDEX querycachetwo_titletwo ON querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo); + foreach ($newcols as $nc) { + $fi = $wgDatabase->fieldInfo($nc[0], $nc[1]); + if (!is_null($fi)) { + echo "... column $nc[0].$nc[1] already exists\n"; + continue; + } --- New columns for fancy recentchanges display -ALTER TABLE recentchanges ADD rc_old_len INT; -ALTER TABLE recentchanges ADD rc_new_len INT; + echo "... add column $nc[0].$nc[1]\n"; + $wgDatabase->query("ALTER TABLE $nc[0] ADD $nc[1] $nc[2]"); + } --- Note this upgrade -INSERT INTO mediawiki_version (type,mw_version,notes) -VALUES ('Upgrade','MWVERSION','Upgrade from older version THISVERSION'); + foreach ($typechanges as $tc) { + $fi = $wgDatabase->fieldInfo($tc[0], $tc[1]); + if (is_null($fi)) { + echo "... error: expected column $tc[0].$tc[1] to exist\n"; + exit(1); + } -PGEND; + if ($fi->type() === $tc[2]) + echo "... $tc[0].$tc[1] is already $tc[2]\n"; + else { + echo "... change $tc[0].$tc[1] from {$fi->type()} to $tc[2]\n"; + $sql = "ALTER TABLE $tc[0] ALTER $tc[1] TYPE $tc[2]"; + if (strlen($tc[3])) { + $sql .= " USING $tc[3]"; + } + $sql .= ";\nCOMMIT;\n"; + $wgDatabase->query($sql); + } + } + foreach ($newindexes as $ni) { + if (pg_index_exists($ni[0], $ni[1])) { + echo "... index $ni[1] on $ni[0] already exists\n"; + continue; + } + dbsource(archive($ni[2])); } - if ( !strlen($upgrade)) { - print "No updates needed for version $version\n"; - return; + foreach ($newrules as $nr) { + if ($wgDatabase->ruleExists($nr[0], $nr[1])) { + echo "... rule $nr[1] on $nr[0] already exists\n"; + continue; + } + dbsource(archive($nr[2])); + } + + if (!$wgDatabase->triggerExists("page", "page_deleted")) { + echo "... create page_deleted trigger\n"; + dbsource(archive('patch-page_deleted.sql')); + } + + $fi = $wgDatabase->fieldInfo("recentchanges", "rc_cur_id"); + if (!$fi->nullable()) { + echo "... remove NOT NULL constraint on recentchanges.rc_cur_id\n"; + dbsource(archive('patch-rc_cur_id-not-null.sql')); + } + + $pu = pg_describe_index("pagelink_unique"); + if (!is_null($pu) && ($pu[0] != "pl_from" || $pu[1] != "pl_namespace" || $pu[2] != "pl_title")) { + echo "... dropping obsolete pagelink_unique index\n"; + $wgDatabase->query("DROP INDEX pagelink_unique"); + $pu = null; + } else + echo "... obsolete pagelink_unique index not present\n"; + + if (is_null($pu)) { + echo "... adding new pagelink_unique index\n"; + $wgDatabase->query("CREATE UNIQUE INDEX pagelink_unique ON pagelinks (pl_from,pl_namespace,pl_title)"); + } else + echo "... already have current pagelink_unique index\n"; + + if (pg_fkey_deltype("revision_rev_user_fkey") == 'r') { + echo "... revision_rev_user_fkey is already ON DELETE RESTRICT\n"; + } else { + echo "... change revision_rev_user_fkey to ON DELETE RESTRICT\n"; + dbsource(archive('patch-revision_rev_user_fkey.sql')); } - $upgrade = str_replace( 'MWVERSION', $wgVersion, $upgrade ); - $upgrade = str_replace( 'THISVERSION', $version, $upgrade ); - $res = $wgDatabase->query("BEGIN;\n\n $upgrade\n\nCOMMIT;\n"); + if (is_null($wgDatabase->fieldInfo("archive", "ar_deleted"))) { + echo "... add archive.ar_deleted\n"; + dbsource(archive("patch-archive-ar_deleted.sql")); + } else + echo "... archive.ar_deleted already exists\n"; return; } diff --git a/maintenance/userDupes.inc b/maintenance/userDupes.inc index 9af66f11..00c4e345 100644 --- a/maintenance/userDupes.inc +++ b/maintenance/userDupes.inc @@ -146,7 +146,7 @@ class UserDupes { $names = array_map( array( $this, 'lockTable' ), $set ); $tables = implode( ',', $names ); - $result = $this->db->query( "LOCK TABLES $tables", $fname ); + $this->db->query( "LOCK TABLES $tables", $fname ); } function lockTable( $table ) { @@ -166,7 +166,7 @@ class UserDupes { */ function unlock() { $fname = 'UserDupes::unlock'; - $result = $this->db->query( "UNLOCK TABLES", $fname ); + $this->db->query( "UNLOCK TABLES", $fname ); } /** @@ -301,7 +301,7 @@ class UserDupes { function reassignEditsOn( $table, $field, $from, $to ) { $fname = 'UserDupes::reassignEditsOn'; echo "reassigning on $table... "; - $result = $this->db->update( $table, + $this->db->update( $table, array( $field => $to ), array( $field => $from ), $fname ); diff --git a/maintenance/userDupes.php b/maintenance/userDupes.php index 2469c6eb..90de160d 100644 --- a/maintenance/userDupes.php +++ b/maintenance/userDupes.php @@ -26,7 +26,7 @@ require_once( 'maintenance/userDupes.inc' ); $wgTitle = Title::newFromText( 'Dupe user entry cleanup script' ); $fix = isset( $options['fix'] ); -$dbw =& wfGetDB( DB_MASTER ); +$dbw = wfGetDB( DB_MASTER ); $duper = new UserDupes( $dbw ); $retval = $duper->checkDupes( $fix ); diff --git a/maintenance/userOptions.inc b/maintenance/userOptions.inc new file mode 100644 index 00000000..702ab715 --- /dev/null +++ b/maintenance/userOptions.inc @@ -0,0 +1,237 @@ +<?php +// Options we will use +$options = array( 'list', 'nowarn', 'quiet', 'usage', 'dry' ); +$optionsWithArgs = array( 'old', 'new' ); + +require_once( 'commandLine.inc' ); + +class userOptions { + public $mQuick; + public $mQuiet; + public $mDry; + public $mAnOption; + public $mOldValue; + public $mNewValue; + + private $mMode, $mReady ; + + /** Constructor. Will show usage and exit if script options are not correct */ + function __construct( $opts, $args ) { + if( !$this->checkOpts( $opts, $args ) ) { + userOptions::showUsageAndExit(); + } else { + $this->mReady = $this->initializeOpts( $opts, $args ); + } + } + + + /** This is used to check options. Only needed on construction */ + private function checkOpts( $opts, $args ) { + // The three possible ways to run the script: + $list = isset( $opts['list'] ); + $usage = isset( $opts['usage'] ) && (count($args) <= 1); + $change = isset( $opts['old']) && isset($opts['new']) && (count($args) <= 1) ; + + // We want only one of them + $isValid = (($list + $usage + $change) == 1); + + return $isValid; + } + + /** load script options in the object */ + private function initializeOpts( $opts, $args ) { + + $this->mQuick = isset( $opts['nowarn'] ); + $this->mQuiet = isset( $opts['quiet'] ); + $this->mDry = isset( $opts['dry'] ); + + // Set object properties, specially 'mMode' used by run() + if( isset($opts['list']) ) { + $this->mMode = 'LISTER' ; + } elseif( isset($opts['usage']) ) { + $this->mMode = 'USAGER' ; + $this->mAnOption = isset($args[0]) ? $args[0] : false ; + } elseif( isset($opts['old']) && isset($opts['new']) ) { + $this->mMode = 'CHANGER' ; + $this->mOldValue = $opts['old'] ; + $this->mNewValue = $opts['new'] ; + $this->mAnOption = $args[0]; + } else { + die("There is a bug in the software, this should never happen\n"); + } + + return true; + } + + // Dumb stuff to run a mode. + public function run() { + if(!$this->mReady ) { + return false; + } + + $this->{$this->mMode}( ); + + } + + # + # Modes. + # + + /** List default options and their value */ + private function LISTER( ) { + $def = User::getDefaultOptions(); + ksort($def); + $maxOpt = 0; + foreach( $def as $opt => $value ) { + $maxOpt = max( $maxOpt, strlen($opt) ); + } + foreach( $def as $opt => $value ) { + printf( "%-{$maxOpt}s: %s\n", $opt, $value ); + } + } + + /** List options usage */ + private function USAGER( ) { + $ret = array(); + $defaultOptions = User::getDefaultOptions(); + + // We list user by user_id from one of the slave database + $dbr = wfGetDB( DB_SLAVE ); + $result = $dbr->select( 'user', + array( 'user_id' ), + array(), + __METHOD__ + ); + + while( $id = $dbr->fetchObject( $result ) ) { + + $user = User::newFromId( $id->user_id ); + + // Get the options and update stats + foreach( $defaultOptions as $name => $defaultValue ) { + $userValue = $user->getOption( $name ); + if( $userValue <> $defaultValue ) { + @$ret[$name][$userValue]++; + } + } + } + + foreach( $ret as $optionName => $usageStats ) { + print "Usage for <$optionName> (default: '{$defaultOptions[$optionName]}'):\n"; + foreach( $usageStats as $value => $count ) { + print " $count user(s): '$value'\n"; + } + print "\n"; + } + } + + + /** Change our users options */ + private function CHANGER( ) { + $this->warn(); + + // We list user by user_id from one of the slave database + $dbr = wfGetDB( DB_SLAVE ); + $result = $dbr->select( 'user', + array( 'user_id' ), + array(), + __METHOD__ + ); + + while( $id = $dbr->fetchObject( $result ) ) { + + $user = User::newFromId( $id->user_id ); + + $curValue = $user->getOption( $this->mAnOption ); + $username = $user->getName(); + + if( $curValue == $this->mOldValue ) { + + if(!$this->mQuiet) { + print "Setting {$this->mAnOption} for $username from '{$this->mOldValue}' to '{$this->mNewValue}'): "; + } + + // Change value + $user->setOption( $this->mAnOption, $this->mNewValue ); + + // Will not save the settings if run with --dry + if(!$this->mDry) { + $user->saveSettings(); + } + if( !$this->mQuiet) { print " OK\n"; } + + } elseif( !$this->mQuiet ) { + print "Not changing '$username' using <{$this->mAnOption}> = '$curValue'\n"; + } + } + } + + + /** Return an array of option names */ + public static function getDefaultOptionsNames() { + $def = User::getDefaultOptions(); + $ret = array(); + foreach( $def as $optname => $defaultValue) { + array_push( $ret, $optname ); + } + return $ret; + } + + + # + # Helper methods + # + + public static function showUsageAndExit() { +print <<<USAGE + +This script pass through all users and change one of their options. +The new option is NOT validated. + +Usage: + php userOptions.php --list + php userOptions.php <user option> --usage + php userOptions.php [options] <user option> --old <old value> --new <new value> + +Switchs: + --list : list available user options and their default value + + --usage <option name> : report statistics about an option + + --old <old value> : the value to look for + --new <new value> : new value to update users with + +Options: + --nowarn: hides the 5 seconds warning + --quiet : do not print what is happening + --dry : do not save user settings back to database + +USAGE; + exit(0); + } + + /** The warning message and countdown */ + public function warn() { + + if( $this->mQuick ) { + return true; + } + +print <<<WARN +The script is about to change the skin for ALL USERS in the database. +Users with option <$this->mAnOption> = '$this->mOldValue' will be made to use '$this->mNewValue'. + +Abort with control-c in the next five seconds.... +WARN; + require('counter.php'); + for ($i=6;$i>=1;) { + print_c($i, --$i); + sleep(1); + } + print "\n"; + + return true; + } + +} +?> diff --git a/maintenance/userOptions.php b/maintenance/userOptions.php new file mode 100644 index 00000000..f71d8e62 --- /dev/null +++ b/maintenance/userOptions.php @@ -0,0 +1,21 @@ +<?php +/** + * Script to change users skins on the fly. + * This is for at least MediaWiki 1.10alpha (r19611) and have not been + * tested with previous versions. It should probably work with 1.7+. + * + * Made on an original idea by Fooey (freenode) + * + * @author Ashar Voultoiz <hashar@altern.org> + */ + +// This is a command line script, load tools and parse args +require_once( 'userOptions.inc' ); + +// Load up our tool system, exit with usage() if options are not fine +$uo = new userOptions( $options, $args ); + +$uo->run(); + +print "Done.\n"; +?> diff --git a/maintenance/waitForSlave.php b/maintenance/waitForSlave.php new file mode 100644 index 00000000..f41bdfc2 --- /dev/null +++ b/maintenance/waitForSlave.php @@ -0,0 +1,16 @@ +<?php +require_once( "commandLine.inc" ); + +# Don't wait for benet +foreach ( $wgLoadBalancer->mServers as $i => $server ) { + if ( $server['host'] == '10.0.0.29' ) { + unset($wgLoadBalancer->mServers[$i]); + } +} +if ( isset( $args[0] ) ) { + wfWaitForSlaves($args[0]); +} else { + wfWaitForSlaves(10); +} + +?> diff --git a/maintenance/wikipedia-interwiki.sql b/maintenance/wikipedia-interwiki.sql index c6e4883f..38f33b9b 100644 --- a/maintenance/wikipedia-interwiki.sql +++ b/maintenance/wikipedia-interwiki.sql @@ -2,25 +2,31 @@ -- for Wikipedia. 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), ('n','http://en.wikinews.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: ('aa','http://aa.wikipedia.org/wiki/$1',1), ('ab','http://ab.wikipedia.org/wiki/$1',1), ('af','http://af.wikipedia.org/wiki/$1',1), ('ak','http://ak.wikipedia.org/wiki/$1',1), ('als','http://als.wikipedia.org/wiki/$1',1), ('am','http://am.wikipedia.org/wiki/$1',1), -('an','http://an.wikipedia.org/wiki/$1',1), ('ang','http://ang.wikipedia.org/wiki/$1',1), -('ar','http://ar.wikipedia.org/wiki/$1',1), +('an','http://an.wikipedia.org/wiki/$1',1), ('arc','http://arc.wikipedia.org/wiki/$1',1), +('ar','http://ar.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), ('ay','http://ay.wikipedia.org/wiki/$1',1), ('az','http://az.wikipedia.org/wiki/$1',1), ('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), ('be','http://be.wikipedia.org/wiki/$1',1), ('bg','http://bg.wikipedia.org/wiki/$1',1), ('bh','http://bh.wikipedia.org/wiki/$1',1), @@ -38,12 +44,14 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('chy','http://chy.wikipedia.org/wiki/$1',1), ('co','http://co.wikipedia.org/wiki/$1',1), ('cr','http://cr.wikipedia.org/wiki/$1',1), -('cs','http://cs.wikipedia.org/wiki/$1',1), ('csb','http://csb.wikipedia.org/wiki/$1',1), +('cs','http://cs.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), +('dk','http://da.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), @@ -59,8 +67,9 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('fj','http://fj.wikipedia.org/wiki/$1',1), ('fo','http://fo.wikipedia.org/wiki/$1',1), ('fr','http://fr.wikipedia.org/wiki/$1',1), -('fy','http://fy.wikipedia.org/wiki/$1',1), +('frp','http://frp.wikipedia.org/wiki/$1',1), ('fur','http://fur.wikipedia.org/wiki/$1',1), +('fy','http://fy.wikipedia.org/wiki/$1',1), ('ga','http://ga.wikipedia.org/wiki/$1',1), ('gd','http://gd.wikipedia.org/wiki/$1',1), ('gl','http://gl.wikipedia.org/wiki/$1',1), @@ -84,6 +93,7 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('ig','http://ig.wikipedia.org/wiki/$1',1), ('ii','http://ii.wikipedia.org/wiki/$1',1), ('ik','http://ik.wikipedia.org/wiki/$1',1), +('ilo','http://ilo.wikipedia.org/wiki/$1',1), ('io','http://io.wikipedia.org/wiki/$1',1), ('is','http://is.wikipedia.org/wiki/$1',1), ('it','http://it.wikipedia.org/wiki/$1',1), @@ -106,10 +116,12 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('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), ('lb','http://lb.wikipedia.org/wiki/$1',1), ('lg','http://lg.wikipedia.org/wiki/$1',1), ('li','http://li.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), @@ -117,6 +129,7 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('mg','http://mg.wikipedia.org/wiki/$1',1), ('mh','http://mh.wikipedia.org/wiki/$1',1), ('mi','http://mi.wikipedia.org/wiki/$1',1), +('minnan','http://zh-min-nan.wikipedia.org/wiki/$1',1), ('mk','http://mk.wikipedia.org/wiki/$1',1), ('ml','http://ml.wikipedia.org/wiki/$1',1), ('mn','http://mn.wikipedia.org/wiki/$1',1), @@ -126,37 +139,46 @@ 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), -('na','http://na.wikipedia.org/wiki/$1',1), ('nah','http://nah.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), +('nds-nl','http://nds-nl.wikipedia.org/wiki/$1',1), ('ne','http://ne.wikipedia.org/wiki/$1',1), ('ng','http://ng.wikipedia.org/wiki/$1',1), ('nl','http://nl.wikipedia.org/wiki/$1',1), ('nn','http://nn.wikipedia.org/wiki/$1',1), ('no','http://no.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), ('oc','http://oc.wikipedia.org/wiki/$1',1), ('om','http://om.wikipedia.org/wiki/$1',1), ('or','http://or.wikipedia.org/wiki/$1',1), +('os','http://os.wikipedia.org/wiki/$1',1), ('pa','http://pa.wikipedia.org/wiki/$1',1), +('pam','http://pam.wikipedia.org/wiki/$1',1), +('pdc','http://pdc.wikipedia.org/wiki/$1',1), ('pi','http://pi.wikipedia.org/wiki/$1',1), ('pl','http://pl.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), -('ro','http://ro.wikipedia.org/wiki/$1',1), ('roa-rup','http://roa-rup.wikipedia.org/wiki/$1',1), +('ro','http://ro.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), ('sc','http://sc.wikipedia.org/wiki/$1',1), ('scn','http://scn.wikipedia.org/wiki/$1',1), +('sco','http://sco.wikipedia.org/wiki/$1',1), ('sd','http://sd.wikipedia.org/wiki/$1',1), ('se','http://se.wikipedia.org/wiki/$1',1), +('sep11','http://sep11.wikipedia.org/wiki/$1',1), ('sg','http://sg.wikipedia.org/wiki/$1',1), ('sh','http://sh.wikipedia.org/wiki/$1',1), ('si','http://si.wikipedia.org/wiki/$1',1), @@ -179,8 +201,8 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('th','http://th.wikipedia.org/wiki/$1',1), ('ti','http://ti.wikipedia.org/wiki/$1',1), ('tk','http://tk.wikipedia.org/wiki/$1',1), -('tl','http://tl.wikipedia.org/wiki/$1',1), ('tlh','http://tlh.wikipedia.org/wiki/$1',1), +('tl','http://tl.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), @@ -199,22 +221,17 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('vi','http://vi.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), ('wo','http://wo.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), ('za','http://za.wikipedia.org/wiki/$1',1), +('zh-cfr','http://zh-min-nan.wikipedia.org/wiki/$1',1), +('zh-classical','http://pam.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), -('zu','http://zu.wikipedia.org/wiki/$1',1), -('zh-cn','http://zh.wikipedia.org/wiki/$1',1), ('zh-tw','http://zh.wikipedia.org/wiki/$1',1), -('minnan','http://zh-min-nan.wikipedia.org/wiki/$1',1), -('zh-cfr','http://zh-min-nan.wikipedia.org/wiki/$1',1), -('dk','http://da.wikipedia.org/wiki/$1',1), -('w','http://en.wikipedia.org/wiki/$1',1), -('m','http://meta.wikimedia.org/wiki/$1',1), -('meta','http://meta.wikimedia.org/wiki/$1',1), -('sep11','http://sep11.wikipedia.org/wiki/$1',1), -('os','http://os.wikipedia.org/wiki/$1',1); - +('zh-yue','http://zh-yue.wikipedia.org/wiki/$1',1), +('zu','http://zu.wikipedia.org/wiki/$1',1); |