summaryrefslogtreecommitdiff
path: root/maintenance
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2014-12-27 15:41:37 +0100
committerPierre Schmitz <pierre@archlinux.de>2014-12-31 11:43:28 +0100
commitc1f9b1f7b1b77776192048005dcc66dcf3df2bfb (patch)
tree2b38796e738dd74cb42ecd9bfd151803108386bc /maintenance
parentb88ab0086858470dd1f644e64cb4e4f62bb2be9b (diff)
Update to MediaWiki 1.24.1
Diffstat (limited to 'maintenance')
-rw-r--r--maintenance/7zip.inc4
-rw-r--r--maintenance/Maintenance.php275
-rw-r--r--maintenance/README5
-rw-r--r--maintenance/archives/patch-drop-rc_cur_time.sql2
-rw-r--r--maintenance/archives/patch-fa_major_mime-chemical.sql3
-rw-r--r--maintenance/archives/patch-hitcounter.sql2
-rw-r--r--maintenance/archives/patch-il_from_namespace.sql4
-rw-r--r--maintenance/archives/patch-img_major_mime-chemical.sql3
-rw-r--r--maintenance/archives/patch-logging_user_text_time_index.sql1
-rw-r--r--maintenance/archives/patch-logging_user_text_type_time_index.sql1
-rw-r--r--maintenance/archives/patch-mimesearch-indexes.sql2
-rw-r--r--maintenance/archives/patch-oi_major_mime-chemical.sql3
-rw-r--r--maintenance/archives/patch-page_lang.sql2
-rw-r--r--maintenance/archives/patch-page_links_updated.sql2
-rw-r--r--maintenance/archives/patch-pl_from_namespace.sql4
-rw-r--r--maintenance/archives/patch-pp_sortkey.sql8
-rw-r--r--maintenance/archives/patch-profiling.sql2
-rw-r--r--maintenance/archives/patch-rc_source.sql16
-rw-r--r--maintenance/archives/patch-restructure.sql146
-rw-r--r--maintenance/archives/patch-tl_from_namespace.sql4
-rw-r--r--maintenance/archives/patch-uploadstash.sql4
-rw-r--r--maintenance/archives/patch-user_password_expire.sql3
-rw-r--r--maintenance/archives/patch-val_ip.sql4
-rw-r--r--maintenance/archives/patch-validate.sql13
-rw-r--r--maintenance/archives/patch-watchlist-user-notificationtimestamp-index.sql4
-rw-r--r--maintenance/archives/upgradeLogging.php6
-rw-r--r--maintenance/attachLatest.php14
-rw-r--r--maintenance/backup.inc185
-rw-r--r--maintenance/backupPrefetch.inc74
-rw-r--r--maintenance/backupTextPass.inc210
-rw-r--r--maintenance/benchmarks/Benchmarker.php21
-rw-r--r--maintenance/benchmarks/bench_HTTP_HTTPS.php7
-rw-r--r--maintenance/benchmarks/bench_delete_truncate.php9
-rw-r--r--maintenance/benchmarks/bench_if_switch.php89
-rw-r--r--maintenance/benchmarks/bench_strtr_str_replace.php11
-rw-r--r--maintenance/benchmarks/bench_utf8_title_check.php29
-rw-r--r--maintenance/benchmarks/bench_wfBaseConvert.php12
-rw-r--r--maintenance/benchmarks/bench_wfIsWindows.php12
-rw-r--r--maintenance/benchmarks/benchmarkHooks.php8
-rw-r--r--maintenance/benchmarks/benchmarkParse.php174
-rw-r--r--maintenance/benchmarks/benchmarkPurge.php11
-rw-r--r--maintenance/cdb.php15
-rw-r--r--maintenance/checkBadRedirects.php2
-rw-r--r--maintenance/checkImages.php4
-rw-r--r--maintenance/checkLess.php48
-rw-r--r--maintenance/checkSyntax.php63
-rw-r--r--maintenance/checkUsernames.php2
-rw-r--r--maintenance/cleanupAncientTables.php9
-rw-r--r--maintenance/cleanupCaps.php5
-rw-r--r--maintenance/cleanupImages.php20
-rw-r--r--maintenance/cleanupRemovedModules.php10
-rw-r--r--maintenance/cleanupSpam.php32
-rw-r--r--maintenance/cleanupTitles.php10
-rw-r--r--maintenance/cleanupUploadStash.php52
-rw-r--r--maintenance/cleanupWatchlist.php14
-rw-r--r--maintenance/commandLine.inc7
-rw-r--r--maintenance/compareParserCache.php104
-rw-r--r--maintenance/compareParsers.php52
-rw-r--r--maintenance/convertLinks.php124
-rw-r--r--maintenance/convertUserOptions.php48
-rw-r--r--maintenance/copyFileBackend.php49
-rw-r--r--maintenance/copyJobQueue.php11
-rw-r--r--maintenance/createAndPromote.php14
-rw-r--r--maintenance/cssjanus/COPYING13
-rw-r--r--maintenance/cssjanus/LICENSE202
-rw-r--r--maintenance/cssjanus/README91
-rw-r--r--maintenance/cssjanus/cssjanus.py574
-rw-r--r--maintenance/cssjanus/csslex.py114
-rw-r--r--maintenance/deleteArchivedFiles.inc14
-rw-r--r--maintenance/deleteArchivedFiles.php1
-rw-r--r--maintenance/deleteArchivedRevisions.inc3
-rw-r--r--maintenance/deleteArchivedRevisions.php6
-rw-r--r--maintenance/deleteBatch.php14
-rw-r--r--maintenance/deleteDefaultMessages.php3
-rw-r--r--maintenance/deleteEqualMessages.php25
-rw-r--r--maintenance/deleteImageMemcached.php8
-rw-r--r--maintenance/deleteOrphanedRevisions.php7
-rw-r--r--maintenance/deleteRevision.php59
-rw-r--r--maintenance/dev/includes/php.sh2
-rw-r--r--maintenance/dev/includes/router.php4
-rw-r--r--maintenance/dictionary/mediawiki.dic160
-rw-r--r--maintenance/doMaintenance.php28
-rw-r--r--maintenance/dumpBackup.php4
-rw-r--r--maintenance/dumpIterator.php22
-rw-r--r--maintenance/dumpLinks.php6
-rw-r--r--maintenance/dumpSisterSites.php2
-rw-r--r--maintenance/dumpTextPass.php5
-rw-r--r--maintenance/dumpUploads.php6
-rw-r--r--maintenance/edit.php21
-rw-r--r--maintenance/eraseArchivedFile.php2
-rw-r--r--maintenance/eval.php22
-rw-r--r--maintenance/fetchText.php20
-rw-r--r--maintenance/findHooks.php133
-rw-r--r--maintenance/findMissingFiles.php115
-rw-r--r--maintenance/fixDoubleRedirects.php17
-rw-r--r--maintenance/fixExtLinksProtocolRelative.php15
-rw-r--r--maintenance/fixSlaveDesync.php46
-rw-r--r--maintenance/fixTimestamps.php9
-rw-r--r--maintenance/fixUserRegistration.php14
-rw-r--r--maintenance/fuzz-tester.php2692
-rw-r--r--maintenance/generateJsonI18n.php287
-rw-r--r--maintenance/generateSitemap.php120
-rw-r--r--maintenance/getConfiguration.php12
-rw-r--r--maintenance/getSlaveServer.php1
-rw-r--r--maintenance/getText.php5
-rw-r--r--maintenance/importDump.php37
-rw-r--r--maintenance/importImages.inc33
-rw-r--r--maintenance/importImages.php124
-rw-r--r--maintenance/importSiteScripts.php4
-rw-r--r--maintenance/importTextFile.php110
-rw-r--r--maintenance/initEditCount.php2
-rw-r--r--maintenance/initSiteStats.php23
-rw-r--r--maintenance/install.php99
-rw-r--r--maintenance/interwiki.list89
-rw-r--r--maintenance/interwiki.sql90
-rw-r--r--maintenance/jsduck/CustomTags.rb116
-rw-r--r--maintenance/jsduck/MetaTags.rb69
-rw-r--r--maintenance/jsduck/categories.json55
-rw-r--r--maintenance/jsduck/config.json47
-rw-r--r--maintenance/jsduck/eg-iframe.html154
-rw-r--r--maintenance/lag.php4
-rw-r--r--maintenance/language/StatOutputs.php47
-rw-r--r--maintenance/language/checkDupeMessages.php3
-rw-r--r--maintenance/language/checkLanguage.inc262
-rw-r--r--maintenance/language/countMessages.php72
-rw-r--r--maintenance/language/generateCollationData.php19
-rw-r--r--maintenance/language/generateNormalizerDataAr.php (renamed from maintenance/language/generateNormalizerData.php)72
-rw-r--r--maintenance/language/generateNormalizerDataMl.php69
-rw-r--r--maintenance/language/generateUtf8Case.php129
-rw-r--r--maintenance/language/langmemusage.php2
-rw-r--r--maintenance/language/languages.inc209
-rw-r--r--maintenance/language/listVariants.php73
-rw-r--r--maintenance/language/messageTypes.inc872
-rw-r--r--maintenance/language/messages.inc4239
-rw-r--r--maintenance/language/rebuildLanguage.php126
-rw-r--r--maintenance/language/transstat.php41
-rw-r--r--maintenance/language/validate.php64
-rw-r--r--maintenance/language/writeMessagesArray.inc283
-rw-r--r--maintenance/language/zhtable/Makefile.py70
-rw-r--r--maintenance/language/zhtable/trad2simp_supp_unset.manual0
-rw-r--r--maintenance/language/zhtable/tradphrases.manual1
-rw-r--r--maintenance/locking/LockServerDaemon.php640
-rw-r--r--maintenance/mctest.php19
-rw-r--r--maintenance/mergeMessageFileList.php23
-rw-r--r--maintenance/minify.php3
-rw-r--r--maintenance/moveBatch.php10
-rw-r--r--maintenance/mssql/archives/named_constraints.sql38
-rw-r--r--maintenance/mssql/archives/patch-fa_major_mime-chemical.sql4
-rw-r--r--maintenance/mssql/archives/patch-img_major_mime-chemical.sql4
-rw-r--r--maintenance/mssql/archives/patch-oi_major_mime-chemical.sql4
-rw-r--r--maintenance/mssql/archives/patch-page_page_lang.sql1
-rw-r--r--maintenance/mssql/archives/patch-user_password_expires.sql1
-rw-r--r--maintenance/mssql/tables.sql1592
-rw-r--r--maintenance/mssql/update-keys.sql31
-rw-r--r--maintenance/mwdocgen.php4
-rw-r--r--maintenance/mwjsduck-gen10
-rw-r--r--maintenance/namespaceDupes.php101
-rw-r--r--maintenance/nextJobDB.php119
-rw-r--r--maintenance/nukeNS.php2
-rw-r--r--maintenance/oracle/alterSharedConstraints.php38
-rw-r--r--maintenance/oracle/archives/patch-logging_user_text_time_index.sql4
-rw-r--r--maintenance/oracle/archives/patch-logging_user_text_type_time_index.sql4
-rw-r--r--maintenance/oracle/archives/patch-page-page_lang.sql3
-rw-r--r--maintenance/oracle/archives/patch-page_links_updated.sql4
-rw-r--r--maintenance/oracle/archives/patch-rc_source.sql3
-rw-r--r--maintenance/oracle/archives/patch-user_password_expire.sql3
-rw-r--r--maintenance/oracle/archives/patch_16_17_schema_changes.sql2
-rw-r--r--maintenance/oracle/tables.sql21
-rw-r--r--maintenance/oracle/update-keys.sql29
-rw-r--r--maintenance/orphans.php36
-rw-r--r--maintenance/pageExists.php54
-rw-r--r--maintenance/parse.php22
-rw-r--r--maintenance/patchSql.php5
-rw-r--r--maintenance/populateBacklinkNamespace.php97
-rw-r--r--maintenance/populateBloomCache.php78
-rw-r--r--maintenance/populateCategory.php39
-rw-r--r--maintenance/populateFilearchiveSha1.php1
-rw-r--r--maintenance/populateImageSha1.php25
-rw-r--r--maintenance/populateLogSearch.php12
-rw-r--r--maintenance/populateLogUsertext.php2
-rw-r--r--maintenance/populateParentId.php15
-rw-r--r--maintenance/populateRecentChangesSource.php107
-rw-r--r--maintenance/populateRevisionLength.php111
-rw-r--r--maintenance/populateRevisionSha1.php32
-rw-r--r--maintenance/postgres/mediawiki_mysql2postgres.pl3
-rw-r--r--maintenance/postgres/tables.sql29
-rw-r--r--maintenance/postgres/update-keys.sql29
-rw-r--r--maintenance/preprocessDump.php8
-rw-r--r--maintenance/preprocessorFuzzTest.php23
-rw-r--r--maintenance/pruneFileCache.php8
-rw-r--r--maintenance/purgeChangedFiles.php18
-rw-r--r--maintenance/purgeChangedPages.php4
-rw-r--r--maintenance/purgeList.php13
-rw-r--r--maintenance/purgeOldText.inc78
-rw-r--r--maintenance/purgeParserCache.php5
-rw-r--r--maintenance/reassignEdits.php53
-rw-r--r--maintenance/rebuildFileCache.php17
-rw-r--r--maintenance/rebuildImages.php20
-rw-r--r--maintenance/rebuildLocalisationCache.php10
-rw-r--r--maintenance/rebuildall.php6
-rw-r--r--maintenance/rebuildrecentchanges.php97
-rw-r--r--maintenance/rebuildtextindex.php10
-rw-r--r--maintenance/refreshImageMetadata.php65
-rw-r--r--maintenance/refreshLinks.php24
-rw-r--r--maintenance/removeUnusedAccounts.php16
-rw-r--r--maintenance/renderDump.php5
-rw-r--r--maintenance/resetUserTokens.php22
-rw-r--r--maintenance/resources/update-oojs-ui.sh95
-rw-r--r--maintenance/resources/update-oojs.sh53
-rw-r--r--maintenance/rollbackEdits.php14
-rw-r--r--maintenance/runBatchedQuery.php4
-rw-r--r--maintenance/runJobs.php122
-rw-r--r--maintenance/runScript.php64
-rw-r--r--maintenance/showCacheStats.php41
-rw-r--r--maintenance/showJobs.php11
-rw-r--r--maintenance/showSiteStats.php7
-rw-r--r--maintenance/sql.php35
-rw-r--r--maintenance/sqlite.inc8
-rw-r--r--maintenance/sqlite.php8
-rw-r--r--maintenance/sqlite/archives/initial-indexes.sql4
-rw-r--r--maintenance/sqlite/archives/patch-drop-rc_cur_time.sql45
-rw-r--r--maintenance/sqlite/archives/patch-page-page_lang.sql3
-rw-r--r--maintenance/storage/checkStorage.php68
-rw-r--r--maintenance/storage/compressOld.php99
-rw-r--r--maintenance/storage/fixBug20757.php18
-rw-r--r--maintenance/storage/orphanStats.php17
-rw-r--r--maintenance/storage/recompressTracked.php73
-rw-r--r--maintenance/storage/resolveStubs.php13
-rw-r--r--maintenance/storage/testCompression.php6
-rw-r--r--maintenance/storage/trackBlobs.php4
-rw-r--r--maintenance/syncFileBackend.php31
-rw-r--r--maintenance/tables.sql73
-rw-r--r--maintenance/term/MWTerm.php6
-rw-r--r--maintenance/undelete.php2
-rw-r--r--maintenance/update-keys.sql29
-rw-r--r--maintenance/update.php53
-rw-r--r--maintenance/updateArticleCount.php10
-rw-r--r--maintenance/updateCollation.php20
-rw-r--r--maintenance/updateDoubleWidthSearch.php8
-rw-r--r--maintenance/updateRestrictions.php15
-rw-r--r--maintenance/updateSearchIndex.php14
-rw-r--r--maintenance/updateSpecialPages.php76
-rw-r--r--maintenance/userDupes.inc38
-rw-r--r--maintenance/userOptions.inc45
-rw-r--r--maintenance/userOptions.php2
-rw-r--r--maintenance/waitForSlave.php1
-rw-r--r--maintenance/wrapOldPasswords.php126
247 files changed, 6716 insertions, 13258 deletions
diff --git a/maintenance/7zip.inc b/maintenance/7zip.inc
index 590cad23..751a1311 100644
--- a/maintenance/7zip.inc
+++ b/maintenance/7zip.inc
@@ -3,7 +3,7 @@
* 7z stream wrapper
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -36,6 +36,7 @@ class SevenZipStream {
private function stripPath( $path ) {
$prefix = 'mediawiki.compress.7z://';
+
return substr( $path, strlen( $prefix ) );
}
@@ -91,4 +92,5 @@ class SevenZipStream {
return fseek( $this->stream, $offset, $whence );
}
}
+
stream_wrapper_register( 'mediawiki.compress.7z', 'SevenZipStream' );
diff --git a/maintenance/Maintenance.php b/maintenance/Maintenance.php
index 30e93c90..8d30df4c 100644
--- a/maintenance/Maintenance.php
+++ b/maintenance/Maintenance.php
@@ -49,7 +49,6 @@ $maintClass = false;
* @ingroup Maintenance
*/
abstract class Maintenance {
-
/**
* Constants for DB access type
* @see Maintenance::getDbType()
@@ -115,11 +114,11 @@ abstract class Maintenance {
public $fileHandle;
/**
- * List of all the core maintenance scripts. This is added
- * to scripts added by extensions in $wgMaintenanceScripts
- * and returned by getMaintenanceScripts()
+ * Accessible via getConfig()
+ *
+ * @var Config
*/
- protected static $mCoreScripts = null;
+ private $config;
/**
* Default constructor. Children should call this *first* if implementing
@@ -141,9 +140,16 @@ abstract class Maintenance {
* as a standalone class? It checks that the call stack only includes this
* function and "requires" (meaning was called from the file scope)
*
- * @return Boolean
+ * @return bool
*/
public static function shouldExecute() {
+ global $wgCommandLineMode;
+
+ if ( !function_exists( 'debug_backtrace' ) ) {
+ // If someone has a better idea...
+ return $wgCommandLineMode;
+ }
+
$bt = debug_backtrace();
$count = count( $bt );
if ( $count < 2 ) {
@@ -158,6 +164,7 @@ abstract class Maintenance {
return false; // previous calls should all be "requires"
}
}
+
return true;
}
@@ -170,14 +177,22 @@ abstract class Maintenance {
* Add a parameter to the script. Will be displayed on --help
* with the associated description
*
- * @param $name String: the name of the param (help, version, etc)
- * @param $description String: the description of the param to show on --help
- * @param $required Boolean: is the param required?
- * @param $withArg Boolean: is an argument required with this option?
- * @param $shortName String: character to use as short name
+ * @param string $name The name of the param (help, version, etc)
+ * @param string $description The description of the param to show on --help
+ * @param bool $required Is the param required?
+ * @param bool $withArg Is an argument required with this option?
+ * @param string $shortName Character to use as short name
*/
- protected function addOption( $name, $description, $required = false, $withArg = false, $shortName = false ) {
- $this->mParams[$name] = array( 'desc' => $description, 'require' => $required, 'withArg' => $withArg, 'shortName' => $shortName );
+ protected function addOption( $name, $description, $required = false,
+ $withArg = false, $shortName = false
+ ) {
+ $this->mParams[$name] = array(
+ 'desc' => $description,
+ 'require' => $required,
+ 'withArg' => $withArg,
+ 'shortName' => $shortName
+ );
+
if ( $shortName !== false ) {
$this->mShortParamsMap[$shortName] = $name;
}
@@ -185,8 +200,8 @@ abstract class Maintenance {
/**
* Checks to see if a particular param exists.
- * @param $name String: the name of the param
- * @return Boolean
+ * @param string $name The name of the param
+ * @return bool
*/
protected function hasOption( $name ) {
return isset( $this->mOptions[$name] );
@@ -194,9 +209,9 @@ abstract class Maintenance {
/**
* Get an option, or return the default
- * @param $name String: the name of the param
- * @param $default Mixed: anything you want, default null
- * @return Mixed
+ * @param string $name The name of the param
+ * @param mixed $default Anything you want, default null
+ * @return mixed
*/
protected function getOption( $name, $default = null ) {
if ( $this->hasOption( $name ) ) {
@@ -204,15 +219,16 @@ abstract class Maintenance {
} else {
// Set it so we don't have to provide the default again
$this->mOptions[$name] = $default;
+
return $this->mOptions[$name];
}
}
/**
* Add some args that are needed
- * @param $arg String: name of the arg, like 'start'
- * @param $description String: short description of the arg
- * @param $required Boolean: is this required?
+ * @param string $arg Name of the arg, like 'start'
+ * @param string $description Short description of the arg
+ * @param bool $required Is this required?
*/
protected function addArg( $arg, $description, $required = true ) {
$this->mArgList[] = array(
@@ -224,7 +240,7 @@ abstract class Maintenance {
/**
* Remove an option. Useful for removing options that won't be used in your script.
- * @param $name String: the option to remove.
+ * @param string $name The option to remove.
*/
protected function deleteOption( $name ) {
unset( $this->mParams[$name] );
@@ -232,7 +248,7 @@ abstract class Maintenance {
/**
* Set the description text.
- * @param $text String: the text of the description
+ * @param string $text The text of the description
*/
protected function addDescription( $text ) {
$this->mDescription = $text;
@@ -240,8 +256,8 @@ abstract class Maintenance {
/**
* Does a given argument exist?
- * @param $argId Integer: the integer value (from zero) for the arg
- * @return Boolean
+ * @param int $argId The integer value (from zero) for the arg
+ * @return bool
*/
protected function hasArg( $argId = 0 ) {
return isset( $this->mArgs[$argId] );
@@ -249,8 +265,8 @@ abstract class Maintenance {
/**
* Get an argument.
- * @param $argId Integer: the integer value (from zero) for the arg
- * @param $default Mixed: the default if it doesn't exist
+ * @param int $argId The integer value (from zero) for the arg
+ * @param mixed $default The default if it doesn't exist
* @return mixed
*/
protected function getArg( $argId = 0, $default = null ) {
@@ -259,7 +275,7 @@ abstract class Maintenance {
/**
* Set the batch size.
- * @param $s Integer: the number of operations to do in a batch
+ * @param int $s The number of operations to do in a batch
*/
protected function setBatchSize( $s = 0 ) {
$this->mBatchSize = $s;
@@ -281,7 +297,7 @@ abstract class Maintenance {
/**
* Get the script's name
- * @return String
+ * @return string
*/
public function getName() {
return $this->mSelf;
@@ -289,10 +305,9 @@ abstract class Maintenance {
/**
* Return input from stdin.
- * @param $len Integer: the number of bytes to read. If null,
- * just return the handle. Maintenance::STDIN_ALL returns
- * the full length
- * @return Mixed
+ * @param int $len The number of bytes to read. If null, just return the handle.
+ * Maintenance::STDIN_ALL returns the full length
+ * @return mixed
*/
protected function getStdin( $len = null ) {
if ( $len == Maintenance::STDIN_ALL ) {
@@ -304,6 +319,7 @@ abstract class Maintenance {
}
$input = fgets( $f, $len );
fclose( $f );
+
return rtrim( $input );
}
@@ -317,9 +333,8 @@ abstract class Maintenance {
/**
* Throw some output to the user. Scripts can call this with no fears,
* as we handle all --quiet stuff here
- * @param $out String: the text to show to the user
- * @param $channel Mixed: unique identifier for the channel. See
- * function outputChanneled.
+ * @param string $out The text to show to the user
+ * @param mixed $channel Unique identifier for the channel. See function outputChanneled.
*/
protected function output( $out, $channel = null ) {
if ( $this->mQuiet ) {
@@ -337,8 +352,8 @@ abstract class Maintenance {
/**
* Throw an error to the user. Doesn't respect --quiet, so don't use
* this for non-error output
- * @param $err String: the error to display
- * @param $die Int: if > 0, go ahead and die out using this int as the code
+ * @param string $err The error to display
+ * @param int $die If > 0, go ahead and die out using this int as the code
*/
protected function error( $err, $die = 0 ) {
$this->outputChanneled( false );
@@ -370,13 +385,14 @@ abstract class Maintenance {
* Message outputter with channeled message support. Messages on the
* same channel are concatenated, but any intervening messages in another
* channel start a new line.
- * @param $msg String: the message without trailing newline
- * @param $channel string Channel identifier or null for no
+ * @param string $msg The message without trailing newline
+ * @param string $channel Channel identifier or null for no
* channel. Channel comparison uses ===.
*/
public function outputChanneled( $msg, $channel = null ) {
if ( $msg === false ) {
$this->cleanupChanneled();
+
return;
}
@@ -404,7 +420,7 @@ abstract class Maintenance {
* Maintenance::DB_NONE - For no DB access at all
* Maintenance::DB_STD - For normal DB access, default
* Maintenance::DB_ADMIN - For admin DB access
- * @return Integer
+ * @return int
*/
public function getDbType() {
return Maintenance::DB_STD;
@@ -422,10 +438,14 @@ abstract class Maintenance {
$this->addOption( 'conf', 'Location of LocalSettings.php, if not default', false, true );
$this->addOption( 'wiki', 'For specifying the wiki ID', false, true );
$this->addOption( 'globals', 'Output globals at the end of processing for debugging' );
- $this->addOption( 'memory-limit', 'Set a specific memory limit for the script, "max" for no limit or "default" to avoid changing it' );
+ $this->addOption(
+ 'memory-limit',
+ 'Set a specific memory limit for the script, '
+ . '"max" for no limit or "default" to avoid changing it'
+ );
$this->addOption( '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.", false, true );
+ "http://en.wikipedia.org. This is sometimes necessary because " .
+ "server name detection may fail in command line scripts.", false, true );
$this->addOption( 'profiler', 'Set to "text" or "trace" to show profiling output', false, true );
# Save generic options to display them separately in help
@@ -445,11 +465,31 @@ abstract class Maintenance {
}
/**
+ * @since 1.24
+ * @return Config
+ */
+ public function getConfig() {
+ if ( $this->config === null ) {
+ $this->config = ConfigFactory::getDefaultInstance()->makeConfig( 'main' );
+ }
+
+ return $this->config;
+ }
+
+ /**
+ * @since 1.24
+ * @param Config $config
+ */
+ public function setConfig( Config $config ) {
+ $this->config = $config;
+ }
+
+ /**
* Run a child maintenance script. Pass all of the current arguments
* to it.
- * @param $maintClass String: a name of a child maintenance class
- * @param $classFile String: full path of where the child is
- * @return Maintenance child
+ * @param string $maintClass A name of a child maintenance class
+ * @param string $classFile Full path of where the child is
+ * @return Maintenance
*/
public function runChild( $maintClass, $classFile = null ) {
// Make sure the class is loaded first
@@ -470,6 +510,7 @@ abstract class Maintenance {
if ( !is_null( $this->mDb ) ) {
$child->setDB( $this->mDb );
}
+
return $child;
}
@@ -570,9 +611,9 @@ abstract class Maintenance {
* $mOptions becomes an array with keys set to the option names
* $mArgs becomes a zero-based array containing the non-option arguments
*
- * @param $self String The name of the script, if any
- * @param $opts Array An array of options, in form of key=>value
- * @param $args Array An array of command line arguments
+ * @param string $self The name of the script, if any
+ * @param array $opts An array of options, in form of key=>value
+ * @param array $args An array of command line arguments
*/
public function loadParamsAndArgs( $self = null, $opts = null, $args = null ) {
# If we were given opts or args, set those and return early
@@ -594,6 +635,7 @@ abstract class Maintenance {
# it's run again and again
if ( $this->mInputLoaded ) {
$this->loadSpecialVars();
+
return;
}
@@ -639,8 +681,9 @@ abstract class Maintenance {
}
} elseif ( substr( $arg, 0, 1 ) == '-' ) {
# Short options
- for ( $p = 1; $p < strlen( $arg ); $p++ ) {
- $option = $arg { $p };
+ $argLength = strlen( $arg );
+ for ( $p = 1; $p < $argLength; $p++ ) {
+ $option = $arg[$p];
if ( !isset( $this->mParams[$option] ) && isset( $this->mShortParamsMap[$option] ) ) {
$option = $this->mShortParamsMap[$option];
}
@@ -715,14 +758,14 @@ abstract class Maintenance {
/**
* Maybe show the help.
- * @param $force boolean Whether to force the help to show, default false
+ * @param bool $force Whether to force the help to show, default false
*/
protected function maybeHelp( $force = false ) {
if ( !$force && !$this->hasOption( 'help' ) ) {
return;
}
- $screenWidth = 80; // TODO: Caculate this!
+ $screenWidth = 80; // TODO: Calculate this!
$tab = " ";
$descWidth = $screenWidth - ( 2 * strlen( $tab ) );
@@ -766,7 +809,7 @@ abstract class Maintenance {
}
$this->output(
wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
- "\n$tab$tab" ) . "\n"
+ "\n$tab$tab" ) . "\n"
);
}
$this->output( "\n" );
@@ -781,13 +824,12 @@ abstract class Maintenance {
}
$this->output(
wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
- "\n$tab$tab" ) . "\n"
+ "\n$tab$tab" ) . "\n"
);
}
$this->output( "\n" );
}
-
// Script specific parameters not defined on construction by
// Maintenance::addDefaultParams()
$scriptSpecificParams = array_diff_key(
@@ -806,7 +848,7 @@ abstract class Maintenance {
}
$this->output(
wordwrap( "$tab--$par: " . $info['desc'], $descWidth,
- "\n$tab$tab" ) . "\n"
+ "\n$tab$tab" ) . "\n"
);
}
$this->output( "\n" );
@@ -881,7 +923,12 @@ abstract class Maintenance {
$this->afterFinalSetup();
$wgShowSQLErrors = true;
+
+ // @codingStandardsIgnoreStart Allow error supppression. wfSuppressWarnings()
+ // is not avaiable.
@set_time_limit( 0 );
+ // @codingStandardsIgnoreStart
+
$this->adjustMemoryLimit();
// Per-script profiling; useful for debugging
@@ -916,7 +963,7 @@ abstract class Maintenance {
/**
* Generic setup for most installs. Returns the location of LocalSettings
- * @return String
+ * @return string
*/
public function loadSettings() {
global $wgCommandLineMode, $IP;
@@ -939,16 +986,17 @@ abstract class Maintenance {
if ( !is_readable( $settingsFile ) ) {
$this->error( "A copy of your installation's LocalSettings.php\n" .
- "must exist and be readable in the source directory.\n" .
- "Use --conf to specify it.", true );
+ "must exist and be readable in the source directory.\n" .
+ "Use --conf to specify it.", true );
}
$wgCommandLineMode = true;
+
return $settingsFile;
}
/**
* Support function for cleaning up redundant text records
- * @param $delete Boolean: whether or not to actually delete the records
+ * @param bool $delete Whether or not to actually delete the records
* @author Rob Church <robchur@gmail.com>
*/
public function purgeRedundantText( $delete = true ) {
@@ -1009,52 +1057,6 @@ abstract class Maintenance {
}
/**
- * Get the list of available maintenance scripts. Note
- * that if you call this _before_ calling doMaintenance
- * you won't have any extensions in it yet
- * @return Array
- */
- public static function getMaintenanceScripts() {
- global $wgMaintenanceScripts;
- return $wgMaintenanceScripts + self::getCoreScripts();
- }
-
- /**
- * Return all of the core maintenance scripts
- * @return array
- */
- protected static function getCoreScripts() {
- if ( !self::$mCoreScripts ) {
- $paths = array(
- __DIR__,
- __DIR__ . '/language',
- __DIR__ . '/storage',
- );
- self::$mCoreScripts = array();
- foreach ( $paths as $p ) {
- $handle = opendir( $p );
- while ( ( $file = readdir( $handle ) ) !== false ) {
- if ( $file == 'Maintenance.php' ) {
- continue;
- }
- $file = $p . '/' . $file;
- if ( is_dir( $file ) || !strpos( $file, '.php' ) ||
- ( strpos( file_get_contents( $file ), '$maintClass' ) === false ) ) {
- continue;
- }
- require $file;
- $vars = get_defined_vars();
- if ( array_key_exists( 'maintClass', $vars ) ) {
- self::$mCoreScripts[$vars['maintClass']] = $file;
- }
- }
- closedir( $handle );
- }
- }
- return self::$mCoreScripts;
- }
-
- /**
* Returns a database to be used by current maintenance script. It can be set by setDB().
* If not set, wfGetDB() will be used.
* This function has the same parameters as wfGetDB()
@@ -1072,7 +1074,7 @@ abstract class Maintenance {
/**
* Sets database object to be returned by getDB().
*
- * @param $db DatabaseBase: Database object to be used
+ * @param DatabaseBase $db Database object to be used
*/
public function setDB( &$db ) {
$this->mDb = $db;
@@ -1080,7 +1082,7 @@ abstract class Maintenance {
/**
* Lock the search index
- * @param &$db DatabaseBase object
+ * @param DatabaseBase &$db
*/
private function lockSearchindex( &$db ) {
$write = array( 'searchindex' );
@@ -1090,7 +1092,7 @@ abstract class Maintenance {
/**
* Unlock the tables
- * @param &$db DatabaseBase object
+ * @param DatabaseBase &$db
*/
private function unlockSearchindex( &$db ) {
$db->unlockTables( __CLASS__ . '::' . __METHOD__ );
@@ -1099,7 +1101,7 @@ abstract class Maintenance {
/**
* Unlock and lock again
* Since the lock is low-priority, queued reads will be able to complete
- * @param &$db DatabaseBase object
+ * @param DatabaseBase &$db
*/
private function relockSearchindex( &$db ) {
$this->unlockSearchindex( $db );
@@ -1108,10 +1110,10 @@ abstract class Maintenance {
/**
* Perform a search index update with locking
- * @param $maxLockTime Integer: the maximum time to keep the search index locked.
- * @param $callback callback String: the function that will update the function.
- * @param $dbw DatabaseBase object
- * @param $results
+ * @param int $maxLockTime The maximum time to keep the search index locked.
+ * @param string $callback The function that will update the function.
+ * @param DatabaseBase $dbw
+ * @param array $results
*/
public function updateSearchIndex( $maxLockTime, $callback, $dbw, $results ) {
$lockTime = time();
@@ -1142,13 +1144,12 @@ abstract class Maintenance {
$this->unlockSearchindex( $dbw );
$this->output( "\n" );
}
-
}
/**
* Update the searchindex table for a given pageid
- * @param $dbw DatabaseBase a database write handle
- * @param $pageId Integer: the page ID to update.
+ * @param DatabaseBase $dbw A database write handle
+ * @param int $pageId The page ID to update.
* @return null|string
*/
public function updateSearchIndexForPage( $dbw, $pageId ) {
@@ -1164,6 +1165,7 @@ abstract class Maintenance {
$u->doUpdate();
$this->output( "\n" );
}
+
return $title;
}
@@ -1172,7 +1174,7 @@ abstract class Maintenance {
* We default as considering stdin a tty (for nice readline methods)
* but treating stout as not a tty to avoid color codes
*
- * @param $fd int File descriptor
+ * @param int $fd File descriptor
* @return bool
*/
public static function posix_isatty( $fd ) {
@@ -1185,8 +1187,8 @@ abstract class Maintenance {
/**
* Prompt the console for input
- * @param $prompt String what to begin the line with, like '> '
- * @return String response
+ * @param string $prompt What to begin the line with, like '> '
+ * @return string Response
*/
public static function readconsole( $prompt = '> ' ) {
static $isatty = null;
@@ -1210,14 +1212,15 @@ abstract class Maintenance {
return false;
}
$resp = trim( $st );
+
return $resp;
}
}
/**
* Emulate readline()
- * @param $prompt String what to begin the line with, like '> '
- * @return String
+ * @param string $prompt What to begin the line with, like '> '
+ * @return string
*/
private static function readlineEmulation( $prompt ) {
$bash = Installer::locateExecutableInDefaultPaths( array( 'bash' ) );
@@ -1245,6 +1248,7 @@ abstract class Maintenance {
return false;
}
print $prompt;
+
return fgets( STDIN, 1024 );
}
}
@@ -1254,6 +1258,7 @@ abstract class Maintenance {
*/
class FakeMaintenance extends Maintenance {
protected $mSelf = "FakeMaintenanceScript";
+
public function execute() {
return;
}
@@ -1274,10 +1279,11 @@ abstract class LoggedUpdateMaintenance extends Maintenance {
$db = $this->getDB( DB_MASTER );
$key = $this->getUpdateKey();
- if ( !$this->hasOption( 'force' ) &&
- $db->selectRow( 'updatelog', '1', array( 'ul_key' => $key ), __METHOD__ ) )
- {
+ if ( !$this->hasOption( 'force' )
+ && $db->selectRow( 'updatelog', '1', array( 'ul_key' => $key ), __METHOD__ )
+ ) {
$this->output( "..." . $this->updateSkippedMessage() . "\n" );
+
return true;
}
@@ -1285,44 +1291,45 @@ abstract class LoggedUpdateMaintenance extends Maintenance {
return false;
}
- if (
- $db->insert( 'updatelog', array( 'ul_key' => $key ), __METHOD__, 'IGNORE' ) )
- {
+ if ( $db->insert( 'updatelog', array( 'ul_key' => $key ), __METHOD__, 'IGNORE' ) ) {
return true;
} else {
$this->output( $this->updatelogFailedMessage() . "\n" );
+
return false;
}
}
/**
* Message to show that the update was done already and was just skipped
- * @return String
+ * @return string
*/
protected function updateSkippedMessage() {
$key = $this->getUpdateKey();
+
return "Update '{$key}' already logged as completed.";
}
/**
* Message to show the the update log was unable to log the completion of this update
- * @return String
+ * @return string
*/
protected function updatelogFailedMessage() {
$key = $this->getUpdateKey();
+
return "Unable to log update '{$key}' as completed.";
}
/**
* Do the actual work. All child classes will need to implement this.
* Return true to log the update as done or false (usually on failure).
- * @return Bool
+ * @return bool
*/
abstract protected function doDBUpdates();
/**
* Get the update key name to go in the update log table
- * @return String
+ * @return string
*/
abstract protected function getUpdateKey();
}
diff --git a/maintenance/README b/maintenance/README
index 5cb6f5f5..30bb6adb 100644
--- a/maintenance/README
+++ b/maintenance/README
@@ -51,7 +51,7 @@ installations.
edit.php
Edit a page to change its content
- findhooks.php
+ findHooks.php
Find hooks that aren't documented in docs/hooks.txt
importDump.php
@@ -60,9 +60,6 @@ installations.
importImages.php
Import images into the wiki
- importTextFile.php
- Import the contents of a text file into a wiki page
-
moveBatch.php
Move a batch of pages
diff --git a/maintenance/archives/patch-drop-rc_cur_time.sql b/maintenance/archives/patch-drop-rc_cur_time.sql
new file mode 100644
index 00000000..f1bc9e8b
--- /dev/null
+++ b/maintenance/archives/patch-drop-rc_cur_time.sql
@@ -0,0 +1,2 @@
+-- rc_cur_time is no longer used, delete the field
+ALTER TABLE /*$wgDBprefix*/recentchanges DROP COLUMN rc_cur_time; \ No newline at end of file
diff --git a/maintenance/archives/patch-fa_major_mime-chemical.sql b/maintenance/archives/patch-fa_major_mime-chemical.sql
new file mode 100644
index 00000000..be9b0ff5
--- /dev/null
+++ b/maintenance/archives/patch-fa_major_mime-chemical.sql
@@ -0,0 +1,3 @@
+ALTER TABLE /*$wgDBprefix*/filearchive
+ CHANGE fa_major_mime fa_major_mime ENUM('unknown','application','audio','image','text','video','message','model','multipart','chemical');
+
diff --git a/maintenance/archives/patch-hitcounter.sql b/maintenance/archives/patch-hitcounter.sql
index c87c9592..2d698f68 100644
--- a/maintenance/archives/patch-hitcounter.sql
+++ b/maintenance/archives/patch-hitcounter.sql
@@ -6,4 +6,4 @@
CREATE TABLE /*$wgDBprefix*/hitcounter (
hc_id INTEGER UNSIGNED NOT NULL
-) ENGINE=HEAP MAX_ROWS=25000;
+) ENGINE=MEMORY MAX_ROWS=25000;
diff --git a/maintenance/archives/patch-il_from_namespace.sql b/maintenance/archives/patch-il_from_namespace.sql
new file mode 100644
index 00000000..4c858f44
--- /dev/null
+++ b/maintenance/archives/patch-il_from_namespace.sql
@@ -0,0 +1,4 @@
+ALTER TABLE /*_*/imagelinks
+ ADD COLUMN il_from_namespace int NOT NULL default 0;
+
+CREATE INDEX /*i*/il_backlinks_namespace ON /*_*/imagelinks (il_to,il_from_namespace,il_from); \ No newline at end of file
diff --git a/maintenance/archives/patch-img_major_mime-chemical.sql b/maintenance/archives/patch-img_major_mime-chemical.sql
new file mode 100644
index 00000000..4bde446e
--- /dev/null
+++ b/maintenance/archives/patch-img_major_mime-chemical.sql
@@ -0,0 +1,3 @@
+ALTER TABLE /*$wgDBprefix*/image
+ CHANGE img_major_mime img_major_mime ENUM('unknown','application','audio','image','text','video','message','model','multipart','chemical');
+
diff --git a/maintenance/archives/patch-logging_user_text_time_index.sql b/maintenance/archives/patch-logging_user_text_time_index.sql
new file mode 100644
index 00000000..06f29861
--- /dev/null
+++ b/maintenance/archives/patch-logging_user_text_time_index.sql
@@ -0,0 +1 @@
+CREATE INDEX /*i*/log_user_text_time ON /*_*/logging (log_user_text, log_timestamp);
diff --git a/maintenance/archives/patch-logging_user_text_type_time_index.sql b/maintenance/archives/patch-logging_user_text_type_time_index.sql
new file mode 100644
index 00000000..2801bc86
--- /dev/null
+++ b/maintenance/archives/patch-logging_user_text_type_time_index.sql
@@ -0,0 +1 @@
+CREATE INDEX /*i*/log_user_text_type_time ON /*_*/logging (log_user_text, log_type, log_timestamp);
diff --git a/maintenance/archives/patch-mimesearch-indexes.sql b/maintenance/archives/patch-mimesearch-indexes.sql
index bd348c46..8d9426ea 100644
--- a/maintenance/archives/patch-mimesearch-indexes.sql
+++ b/maintenance/archives/patch-mimesearch-indexes.sql
@@ -1,4 +1,4 @@
--- Add indexes to the mime types in image for use on Special:MIMEsearch,
+-- Add indexes to the MIME types in image for use on Special:MIMEsearch,
-- changes a query like
--
-- SELECT img_name FROM image WHERE img_major_mime = "image" AND img_minor_mime = "svg";
diff --git a/maintenance/archives/patch-oi_major_mime-chemical.sql b/maintenance/archives/patch-oi_major_mime-chemical.sql
new file mode 100644
index 00000000..e3b4552d
--- /dev/null
+++ b/maintenance/archives/patch-oi_major_mime-chemical.sql
@@ -0,0 +1,3 @@
+ALTER TABLE /*$wgDBprefix*/oldimage
+ CHANGE oi_major_mime oi_major_mime ENUM('unknown','application','audio','image','text','video','message','model','multipart','chemical');
+
diff --git a/maintenance/archives/patch-page_lang.sql b/maintenance/archives/patch-page_lang.sql
new file mode 100644
index 00000000..c792b4ad
--- /dev/null
+++ b/maintenance/archives/patch-page_lang.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*$wgDBprefix*/page
+ ADD page_lang varbinary(35) DEFAULT NULL;
diff --git a/maintenance/archives/patch-page_links_updated.sql b/maintenance/archives/patch-page_links_updated.sql
new file mode 100644
index 00000000..18d9e2d9
--- /dev/null
+++ b/maintenance/archives/patch-page_links_updated.sql
@@ -0,0 +1,2 @@
+ALTER TABLE /*$wgDBprefix*/page
+ ADD page_links_updated varbinary(14) NULL default NULL;
diff --git a/maintenance/archives/patch-pl_from_namespace.sql b/maintenance/archives/patch-pl_from_namespace.sql
new file mode 100644
index 00000000..2f7ff046
--- /dev/null
+++ b/maintenance/archives/patch-pl_from_namespace.sql
@@ -0,0 +1,4 @@
+ALTER TABLE /*_*/pagelinks
+ ADD COLUMN pl_from_namespace int NOT NULL default 0;
+
+CREATE INDEX /*i*/pl_backlinks_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from_namespace,pl_from);
diff --git a/maintenance/archives/patch-pp_sortkey.sql b/maintenance/archives/patch-pp_sortkey.sql
new file mode 100644
index 00000000..b13b6055
--- /dev/null
+++ b/maintenance/archives/patch-pp_sortkey.sql
@@ -0,0 +1,8 @@
+-- Add a 'sortkey' field to page_props so pages can be efficiently
+-- queried by the numeric value of a property.
+
+ALTER TABLE /*_*/page_props
+ ADD pp_sortkey float DEFAULT NULL;
+
+CREATE UNIQUE INDEX /*i*/pp_propname_sortkey_page
+ ON /*_*/page_props ( pp_propname, pp_sortkey, pp_page );
diff --git a/maintenance/archives/patch-profiling.sql b/maintenance/archives/patch-profiling.sql
index 0a0e4e1a..6ad16224 100644
--- a/maintenance/archives/patch-profiling.sql
+++ b/maintenance/archives/patch-profiling.sql
@@ -7,6 +7,6 @@ CREATE TABLE /*_*/profiling (
pf_memory float NOT NULL default 0,
pf_name varchar(255) NOT NULL default '',
pf_server varchar(30) NOT NULL default ''
-) ENGINE=HEAP;
+) ENGINE=MEMORY;
CREATE UNIQUE INDEX /*i*/pf_name_server ON /*_*/profiling (pf_name, pf_server); \ No newline at end of file
diff --git a/maintenance/archives/patch-rc_source.sql b/maintenance/archives/patch-rc_source.sql
new file mode 100644
index 00000000..7dedd745
--- /dev/null
+++ b/maintenance/archives/patch-rc_source.sql
@@ -0,0 +1,16 @@
+-- first step of migrating recentchanges rc_type to rc_source
+ALTER TABLE /*$wgDBprefix*/recentchanges
+ ADD rc_source varbinary(16) NOT NULL default '';
+
+-- Populate rc_source field with the data from rc_type
+-- Large wiki's might prefer the PopulateRecentChangeSource maintenance
+-- script to batch updates into groups rather than all at once.
+UPDATE /*$wgDBprefix*/recentchanges
+ SET rc_source = CASE
+ WHEN rc_type = 0 THEN 'mw.edit'
+ WHEN rc_type = 1 THEN 'mw.new'
+ WHEN rc_type = 3 THEN 'mw.log'
+ WHEN rc_type = 5 THEN 'mw.external'
+ ELSE ''
+ END
+WHERE rc_source = '';
diff --git a/maintenance/archives/patch-restructure.sql b/maintenance/archives/patch-restructure.sql
deleted file mode 100644
index a5bc3e52..00000000
--- a/maintenance/archives/patch-restructure.sql
+++ /dev/null
@@ -1,146 +0,0 @@
--- The Great Restructuring of October 2004
--- Creates 'page', 'revision' tables and transforms the classic
--- cur+old into a separate page+revision+text structure.
---
--- The pre-conversion 'old' table is renamed to 'text' and used
--- without internal restructuring to avoid rebuilding the entire
--- table. (This can be done separately if desired.)
---
--- The pre-conversion 'cur' table is now redundant and can be
--- discarded when done.
-
-CREATE TABLE /*$wgDBprefix*/page (
- page_id int unsigned NOT NULL auto_increment,
- page_namespace tinyint NOT NULL,
- page_title varchar(255) binary NOT NULL,
- page_restrictions tinyblob NOT NULL,
- page_counter bigint unsigned NOT NULL default '0',
- page_is_redirect tinyint unsigned NOT NULL default '0',
- page_is_new tinyint unsigned NOT NULL default '0',
- page_random real unsigned NOT NULL,
- page_touched binary(14) NOT NULL default '',
- page_latest int unsigned NOT NULL,
- page_len int unsigned NOT NULL,
-
- PRIMARY KEY page_id (page_id),
- UNIQUE INDEX name_title (page_namespace,page_title),
- INDEX (page_random),
- INDEX (page_len)
-);
-
-CREATE TABLE /*$wgDBprefix*/revision (
- rev_id int unsigned NOT NULL auto_increment,
- rev_page int unsigned NOT NULL,
- rev_comment tinyblob NOT NULL,
- rev_user int unsigned NOT NULL default '0',
- rev_user_text varchar(255) binary NOT NULL default '',
- rev_timestamp binary(14) NOT NULL default '',
- rev_minor_edit tinyint unsigned NOT NULL default '0',
- rev_deleted tinyint unsigned NOT NULL default '0',
-
- PRIMARY KEY rev_page_id (rev_page, rev_id),
- UNIQUE INDEX rev_id (rev_id),
- INDEX rev_timestamp (rev_timestamp),
- INDEX page_timestamp (rev_page,rev_timestamp),
- INDEX user_timestamp (rev_user,rev_timestamp),
- INDEX usertext_timestamp (rev_user_text,rev_timestamp)
-);
-
--- If creating new 'text' table it would look like this:
---
--- CREATE TABLE /*$wgDBprefix*/text (
--- old_id int(8) unsigned NOT NULL auto_increment,
--- old_text mediumtext NOT NULL,
--- old_flags tinyblob NOT NULL,
---
--- PRIMARY KEY old_id (old_id)
--- );
-
-
--- Lock!
-LOCK TABLES /*$wgDBprefix*/page WRITE, /*$wgDBprefix*/revision WRITE, /*$wgDBprefix*/old WRITE, /*$wgDBprefix*/cur WRITE;
-
--- Save the last old_id value for later
-SELECT (@maxold:=MAX(old_id)) FROM /*$wgDBprefix*/old;
-
--- First, copy all current entries into the old table.
-INSERT
- INTO /*$wgDBprefix*/old
- (old_namespace,
- old_title,
- old_text,
- old_comment,
- old_user,
- old_user_text,
- old_timestamp,
- old_minor_edit,
- old_flags)
- SELECT
- cur_namespace,
- cur_title,
- cur_text,
- cur_comment,
- cur_user,
- cur_user_text,
- cur_timestamp,
- cur_minor_edit,
- ''
- FROM /*$wgDBprefix*/cur;
-
--- Now, copy all old data except the text into revisions
-INSERT
- INTO /*$wgDBprefix*/revision
- (rev_id,
- rev_page,
- rev_comment,
- rev_user,
- rev_user_text,
- rev_timestamp,
- rev_minor_edit)
- SELECT
- old_id,
- cur_id,
- old_comment,
- old_user,
- old_user_text,
- old_timestamp,
- old_minor_edit
- FROM /*$wgDBprefix*/old,/*$wgDBprefix*/cur
- WHERE old_namespace=cur_namespace
- AND old_title=cur_title;
-
--- And, copy the cur data into page
-INSERT
- INTO /*$wgDBprefix*/page
- (page_id,
- page_namespace,
- page_title,
- page_restrictions,
- page_counter,
- page_is_redirect,
- page_is_new,
- page_random,
- page_touched,
- page_latest)
- SELECT
- cur_id,
- cur_namespace,
- cur_title,
- cur_restrictions,
- cur_counter,
- cur_is_redirect,
- cur_is_new,
- cur_random,
- cur_touched,
- rev_id
- FROM /*$wgDBprefix*/cur,/*$wgDBprefix*/revision
- WHERE cur_id=rev_page
- AND rev_timestamp=cur_timestamp
- AND rev_id > @maxold;
-
-UNLOCK TABLES;
-
--- Keep the old table around as the text store.
--- Its extra fields will be ignored, but trimming them is slow
--- so we won't bother doing it for now.
-ALTER TABLE /*$wgDBprefix*/old RENAME TO /*$wgDBprefix*/text;
diff --git a/maintenance/archives/patch-tl_from_namespace.sql b/maintenance/archives/patch-tl_from_namespace.sql
new file mode 100644
index 00000000..8d6c76b8
--- /dev/null
+++ b/maintenance/archives/patch-tl_from_namespace.sql
@@ -0,0 +1,4 @@
+ALTER TABLE /*_*/templatelinks
+ ADD COLUMN tl_from_namespace int NOT NULL default 0;
+
+CREATE INDEX /*i*/tl_backlinks_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from_namespace,tl_from);
diff --git a/maintenance/archives/patch-uploadstash.sql b/maintenance/archives/patch-uploadstash.sql
index 14eaeab0..c1d93ef3 100644
--- a/maintenance/archives/patch-uploadstash.sql
+++ b/maintenance/archives/patch-uploadstash.sql
@@ -26,10 +26,10 @@ CREATE TABLE /*_*/uploadstash (
us_status varchar(50) not null,
- -- file properties from File::getPropsFromPath. these may prove unnecessary.
+ -- file properties from FSFile::getProps(). these may prove unnecessary.
--
us_size int unsigned NOT NULL,
- -- this hash comes from File::sha1Base36(), and is 31 characters
+ -- this hash comes from FSFile::getSha1Base36(), and is 31 characters
us_sha1 varchar(31) NOT NULL,
us_mime varchar(255),
-- Media type as defined by the MEDIATYPE_xxx constants, should duplicate definition in the image table
diff --git a/maintenance/archives/patch-user_password_expire.sql b/maintenance/archives/patch-user_password_expire.sql
new file mode 100644
index 00000000..3e716d33
--- /dev/null
+++ b/maintenance/archives/patch-user_password_expire.sql
@@ -0,0 +1,3 @@
+-- For setting a password expiration date for users
+ALTER TABLE /*$wgDBprefix*/user
+ ADD COLUMN user_password_expires varbinary(14) DEFAULT NULL;
diff --git a/maintenance/archives/patch-val_ip.sql b/maintenance/archives/patch-val_ip.sql
deleted file mode 100644
index 9214218d..00000000
--- a/maintenance/archives/patch-val_ip.sql
+++ /dev/null
@@ -1,4 +0,0 @@
--- Column added 2005-05-24
-
-ALTER TABLE /*$wgDBprefix*/validate
- ADD COLUMN val_ip varchar(20) NOT NULL default '';
diff --git a/maintenance/archives/patch-validate.sql b/maintenance/archives/patch-validate.sql
deleted file mode 100644
index 9701083c..00000000
--- a/maintenance/archives/patch-validate.sql
+++ /dev/null
@@ -1,13 +0,0 @@
--- For article validation
-
-DROP TABLE IF EXISTS /*$wgDBprefix*/validate;
-CREATE TABLE /*$wgDBprefix*/validate (
- `val_user` int(11) NOT NULL default '0',
- `val_page` int(11) unsigned NOT NULL default '0',
- `val_revision` int(11) unsigned NOT NULL default '0',
- `val_type` int(11) unsigned NOT NULL default '0',
- `val_value` int(11) default '0',
- `val_comment` varchar(255) NOT NULL default '',
- `val_ip` varchar(20) NOT NULL default '',
- KEY `val_user` (`val_user`,`val_revision`)
-) /*$wgDBTableOptions*/;
diff --git a/maintenance/archives/patch-watchlist-user-notificationtimestamp-index.sql b/maintenance/archives/patch-watchlist-user-notificationtimestamp-index.sql
new file mode 100644
index 00000000..22ae44f1
--- /dev/null
+++ b/maintenance/archives/patch-watchlist-user-notificationtimestamp-index.sql
@@ -0,0 +1,4 @@
+--
+-- Creates the wl_user_notificationtimestamp index for the watchlist table
+--
+CREATE INDEX /*i*/wl_user_notificationtimestamp ON /*_*/watchlist (wl_user, wl_notificationtimestamp);
diff --git a/maintenance/archives/upgradeLogging.php b/maintenance/archives/upgradeLogging.php
index 0749bbf6..aeadc93d 100644
--- a/maintenance/archives/upgradeLogging.php
+++ b/maintenance/archives/upgradeLogging.php
@@ -52,6 +52,7 @@ class UpdateLogging {
if ( $this->dbw->tableExists( 'logging_pre_1_10' ) ) {
echo "This script has already been run to completion\n";
+
return;
}
@@ -124,6 +125,8 @@ EOT;
/**
* Copy all rows from $srcTable to $dstTable
+ * @param string $srcTable
+ * @param string $dstTable
*/
function sync( $srcTable, $dstTable ) {
$batchSize = 1000;
@@ -158,7 +161,7 @@ EOT;
$srcRes = $this->dbw->select( $srcTable, '*', $conds, __METHOD__,
array( 'LIMIT' => $batchSize, 'ORDER BY' => 'log_timestamp' ) );
- if ( ! $srcRes->numRows() ) {
+ if ( !$srcRes->numRows() ) {
# All done
break;
}
@@ -205,6 +208,7 @@ EOT;
}
}
}
+
return $numRowsCopied;
}
}
diff --git a/maintenance/attachLatest.php b/maintenance/attachLatest.php
index 2cf277fe..fba6b92d 100644
--- a/maintenance/attachLatest.php
+++ b/maintenance/attachLatest.php
@@ -3,7 +3,7 @@
* Corrects wrong values in the `page_latest` field in the database.
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -33,19 +33,24 @@ require_once __DIR__ . '/Maintenance.php';
* @ingroup Maintenance
*/
class AttachLatest extends Maintenance {
-
public function __construct() {
parent::__construct();
$this->addOption( "fix", "Actually fix the entries, will dry run otherwise" );
+ $this->addOption( "regenerate-all",
+ "Regenerate the page_latest field for all records in table page" );
$this->mDescription = "Fix page_latest entries in the page table";
}
public function execute() {
$this->output( "Looking for pages with page_latest set to 0...\n" );
$dbw = wfGetDB( DB_MASTER );
+ $conds = array( 'page_latest' => 0 );
+ if ( $this->hasOption( 'regenerate-all' ) ) {
+ $conds = '';
+ }
$result = $dbw->select( 'page',
array( 'page_id', 'page_namespace', 'page_title' ),
- array( 'page_latest' => 0 ),
+ $conds,
__METHOD__ );
$n = 0;
@@ -64,7 +69,8 @@ class AttachLatest extends Maintenance {
$revision = Revision::loadFromTimestamp( $dbw, $title, $latestTime );
if ( is_null( $revision ) ) {
- $this->output( wfWikiID() . " $pageId [[$name]] latest time $latestTime, can't find revision id\n" );
+ $this->output( wfWikiID()
+ . " $pageId [[$name]] latest time $latestTime, can't find revision id\n" );
continue;
}
$id = $revision->getId();
diff --git a/maintenance/backup.inc b/maintenance/backup.inc
index 3dc94c88..222c538b 100644
--- a/maintenance/backup.inc
+++ b/maintenance/backup.inc
@@ -3,7 +3,7 @@
* Base classes for database dumpers
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -37,28 +37,30 @@ class DumpDBZip2Output extends DumpPipeOutput {
* @ingroup Dump Maintenance
*/
class BackupDumper {
- var $reportingInterval = 100;
- var $reporting = true;
- var $pageCount = 0;
- var $revCount = 0;
- var $server = null; // use default
- var $pages = null; // all pages
- var $skipHeader = false; // don't output <mediawiki> and <siteinfo>
- var $skipFooter = false; // don't output </mediawiki>
- var $startId = 0;
- var $endId = 0;
- var $revStartId = 0;
- var $revEndId = 0;
- var $sink = null; // Output filters
- var $stubText = false; // include rev_text_id instead of text; for 2-pass dump
- var $dumpUploads = false;
- var $dumpUploadFileContents = false;
- var $lastTime = 0;
- var $pageCountLast = 0;
- var $revCountLast = 0;
- var $ID = 0;
-
- var $outputTypes = array(), $filterTypes = array();
+ public $reporting = true;
+ public $pages = null; // all pages
+ public $skipHeader = false; // don't output <mediawiki> and <siteinfo>
+ public $skipFooter = false; // don't output </mediawiki>
+ public $startId = 0;
+ public $endId = 0;
+ public $revStartId = 0;
+ public $revEndId = 0;
+ public $dumpUploads = false;
+ public $dumpUploadFileContents = false;
+
+ protected $reportingInterval = 100;
+ protected $pageCount = 0;
+ protected $revCount = 0;
+ protected $server = null; // use default
+ protected $sink = null; // Output filters
+ protected $lastTime = 0;
+ protected $pageCountLast = 0;
+ protected $revCountLast = 0;
+
+ protected $outputTypes = array();
+ protected $filterTypes = array();
+
+ protected $ID = 0;
/**
* The dependency-injected database to use.
@@ -69,11 +71,12 @@ class BackupDumper {
*/
protected $forcedDb = null;
- /**
- * @var LoadBalancer
- */
+ /** @var LoadBalancer */
protected $lb;
+ // @todo Unused?
+ private $stubText = false; // include rev_text_id instead of text; for 2-pass dump
+
function __construct( $args ) {
$this->stderr = fopen( "php://stderr", "wt" );
@@ -92,16 +95,16 @@ class BackupDumper {
}
/**
- * @param $name String
- * @param $class String: name of output filter plugin class
+ * @param string $name
+ * @param string $class Name of output filter plugin class
*/
function registerOutput( $name, $class ) {
$this->outputTypes[$name] = $class;
}
/**
- * @param $name String
- * @param $class String: name of filter plugin class
+ * @param string $name
+ * @param string $class Name of filter plugin class
*/
function registerFilter( $name, $class ) {
$this->filterTypes[$name] = $class;
@@ -110,9 +113,9 @@ class BackupDumper {
/**
* Load a plugin and register it
*
- * @param $class String: name of plugin class; must have a static 'register'
- * method that takes a BackupDumper as a parameter.
- * @param $file String: full or relative path to the PHP file to load, or empty
+ * @param string $class Name of plugin class; must have a static 'register'
+ * method that takes a BackupDumper as a parameter.
+ * @param string $file Full or relative path to the PHP file to load, or empty
*/
function loadPlugin( $class, $file ) {
if ( $file != '' ) {
@@ -123,8 +126,8 @@ class BackupDumper {
}
/**
- * @param $args Array
- * @return Array
+ * @param array $args
+ * @return array
*/
function processArgs( $args ) {
$sink = null;
@@ -132,50 +135,53 @@ class BackupDumper {
foreach ( $args as $arg ) {
$matches = array();
if ( preg_match( '/^--(.+?)(?:=(.+?)(?::(.+?))?)?$/', $arg, $matches ) ) {
- @list( /* $full */ , $opt, $val, $param ) = $matches;
+ wfSuppressWarnings();
+ list( /* $full */, $opt, $val, $param ) = $matches;
+ wfRestoreWarnings();
+
switch ( $opt ) {
- case "plugin":
- $this->loadPlugin( $val, $param );
- break;
- case "output":
- if ( !is_null( $sink ) ) {
- $sinks[] = $sink;
- }
- if ( !isset( $this->outputTypes[$val] ) ) {
- $this->fatalError( "Unrecognized output sink type '$val'" );
- }
- $type = $this->outputTypes[$val];
- $sink = new $type( $param );
- break;
- case "filter":
- if ( is_null( $sink ) ) {
- $sink = new DumpOutput();
- }
- if ( !isset( $this->filterTypes[$val] ) ) {
- $this->fatalError( "Unrecognized filter type '$val'" );
- }
- $type = $this->filterTypes[$val];
- $filter = new $type( $sink, $param );
-
- // references are lame in php...
- unset( $sink );
- $sink = $filter;
-
- break;
- case "report":
- $this->reportingInterval = intval( $val );
- break;
- case "server":
- $this->server = $val;
- break;
- case "force-normal":
- if ( !function_exists( 'utf8_normalize' ) ) {
- $this->fatalError( "UTF-8 normalization extension not loaded. " .
- "Install or remove --force-normal parameter to use slower code." );
- }
- break;
- default:
- $this->processOption( $opt, $val, $param );
+ case "plugin":
+ $this->loadPlugin( $val, $param );
+ break;
+ case "output":
+ if ( !is_null( $sink ) ) {
+ $sinks[] = $sink;
+ }
+ if ( !isset( $this->outputTypes[$val] ) ) {
+ $this->fatalError( "Unrecognized output sink type '$val'" );
+ }
+ $type = $this->outputTypes[$val];
+ $sink = new $type( $param );
+ break;
+ case "filter":
+ if ( is_null( $sink ) ) {
+ $sink = new DumpOutput();
+ }
+ if ( !isset( $this->filterTypes[$val] ) ) {
+ $this->fatalError( "Unrecognized filter type '$val'" );
+ }
+ $type = $this->filterTypes[$val];
+ $filter = new $type( $sink, $param );
+
+ // references are lame in php...
+ unset( $sink );
+ $sink = $filter;
+
+ break;
+ case "report":
+ $this->reportingInterval = intval( $val );
+ break;
+ case "server":
+ $this->server = $val;
+ break;
+ case "force-normal":
+ if ( !function_exists( 'utf8_normalize' ) ) {
+ $this->fatalError( "UTF-8 normalization extension not loaded. " .
+ "Install or remove --force-normal parameter to use slower code." );
+ }
+ break;
+ default:
+ $this->processOption( $opt, $val, $param );
}
}
}
@@ -223,8 +229,8 @@ class BackupDumper {
} else {
$exporter->allLogs();
}
- # Page dumps: all or by page ID range
} elseif ( is_null( $this->pages ) ) {
+ # Page dumps: all or by page ID range
if ( $this->startId || $this->endId ) {
$exporter->pagesByRange( $this->startId, $this->endId );
} elseif ( $this->revStartId || $this->revEndId ) {
@@ -232,8 +238,8 @@ class BackupDumper {
} else {
$exporter->allPages();
}
- # Dump of specific pages
} else {
+ # Dump of specific pages
$exporter->pagesByName( $this->pages );
}
@@ -248,7 +254,7 @@ class BackupDumper {
* Initialise starting time and maximum revision count.
* We'll make ETA calculations based an progress, assuming relatively
* constant per-revision rate.
- * @param $history Integer: WikiExporter::CURRENT or WikiExporter::FULL
+ * @param int $history WikiExporter::CURRENT or WikiExporter::FULL
*/
function initProgress( $history = WikiExporter::FULL ) {
$table = ( $history == WikiExporter::CURRENT ) ? 'page' : 'revision';
@@ -276,7 +282,7 @@ class BackupDumper {
}
$this->lb = wfGetLBFactory()->newMainLB();
- $db = $this->lb->getConnection( DB_SLAVE, 'backup' );
+ $db = $this->lb->getConnection( DB_SLAVE, 'dump' );
// Discourage the server from disconnecting us if it takes a long time
// to read out the big ol' batch query.
@@ -289,9 +295,8 @@ class BackupDumper {
* Force the dump to use the provided database connection for database
* operations, wherever possible.
*
- * @param $db DatabaseBase|null: (Optional) the database connection to
- * use. If null, resort to use the globally provided ways to
- * get database connections.
+ * @param DatabaseBase|null $db (Optional) the database connection to use. If null, resort to
+ * use the globally provided ways to get database connections.
*/
function setDb( DatabaseBase $db = null ) {
$this->forcedDb = $db;
@@ -305,6 +310,7 @@ class BackupDumper {
function backupServer() {
global $wgDBserver;
+
return $this->server
? $this->server
: $wgDBserver;
@@ -352,8 +358,13 @@ class BackupDumper {
$pageRatePart = '-';
$revRatePart = '-';
}
- $this->progress( sprintf( "%s: %s (ID %d) %d pages (%0.1f|%0.1f/sec all|curr), %d revs (%0.1f|%0.1f/sec all|curr), ETA %s [max %d]",
- $now, wfWikiID(), $this->ID, $this->pageCount, $pageRate, $pageRatePart, $this->revCount, $revRate, $revRatePart, $etats, $this->maxCount ) );
+ $this->progress( sprintf(
+ "%s: %s (ID %d) %d pages (%0.1f|%0.1f/sec all|curr), "
+ . "%d revs (%0.1f|%0.1f/sec all|curr), ETA %s [max %d]",
+ $now, wfWikiID(), $this->ID, $this->pageCount, $pageRate,
+ $pageRatePart, $this->revCount, $revRate, $revRatePart, $etats,
+ $this->maxCount
+ ) );
$this->lastTime = $nowts;
$this->revCountLast = $this->revCount;
}
diff --git a/maintenance/backupPrefetch.inc b/maintenance/backupPrefetch.inc
index 04352b9b..7bfb7345 100644
--- a/maintenance/backupPrefetch.inc
+++ b/maintenance/backupPrefetch.inc
@@ -3,7 +3,7 @@
* Helper class for the --prefetch option of dumpTextPass.php
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -40,21 +40,20 @@
* @ingroup Maintenance
*/
class BaseDump {
- var $reader = null;
- var $atEnd = false;
- var $atPageEnd = false;
- var $lastPage = 0;
- var $lastRev = 0;
- var $infiles = null;
-
- function BaseDump( $infile ) {
+ protected $reader = null;
+ protected $atEnd = false;
+ protected $atPageEnd = false;
+ protected $lastPage = 0;
+ protected $lastRev = 0;
+ protected $infiles = null;
+
+ public function __construct( $infile ) {
$this->infiles = explode( ';', $infile );
$this->reader = new XMLReader();
$infile = array_shift( $this->infiles );
if ( defined( 'LIBXML_PARSEHUGE' ) ) {
$this->reader->open( $infile, null, LIBXML_PARSEHUGE );
- }
- else {
+ } else {
$this->reader->open( $infile );
}
}
@@ -64,9 +63,9 @@ class BaseDump {
* from the dump stream. May return null if the page is
* unavailable.
*
- * @param $page Integer: ID number of page to read
- * @param $rev Integer: ID number of revision to read
- * @return string or null
+ * @param int $page ID number of page to read
+ * @param int $rev ID number of revision to read
+ * @return string|null
*/
function prefetch( $page, $rev ) {
$page = intval( $page );
@@ -76,18 +75,24 @@ class BaseDump {
$this->nextPage();
}
if ( $this->lastPage > $page || $this->atEnd ) {
- $this->debug( "BaseDump::prefetch already past page $page looking for rev $rev [$this->lastPage, $this->lastRev]" );
+ $this->debug( "BaseDump::prefetch already past page $page "
+ . "looking for rev $rev [$this->lastPage, $this->lastRev]" );
+
return null;
}
while ( $this->lastRev < $rev && !$this->atEnd && !$this->atPageEnd ) {
- $this->debug( "BaseDump::prefetch at page $this->lastPage, rev $this->lastRev, looking for $page, $rev" );
+ $this->debug( "BaseDump::prefetch at page $this->lastPage, rev $this->lastRev, "
+ . "looking for $page, $rev" );
$this->nextRev();
}
if ( $this->lastRev == $rev && !$this->atEnd ) {
$this->debug( "BaseDump::prefetch hit on $page, $rev [$this->lastPage, $this->lastRev]" );
+
return $this->nextText();
} else {
- $this->debug( "BaseDump::prefetch already past rev $rev on page $page [$this->lastPage, $this->lastRev]" );
+ $this->debug( "BaseDump::prefetch already past rev $rev on page $page "
+ . "[$this->lastPage, $this->lastRev]" );
+
return null;
}
}
@@ -137,13 +142,14 @@ class BaseDump {
*/
function nextText() {
$this->skipTo( 'text' );
+
return strval( $this->nodeContents() );
}
/**
* @access private
- * @param $name string
- * @param $parent string
+ * @param string $name
+ * @param string $parent
* @return bool|null
*/
function skipTo( $name, $parent = 'page' ) {
@@ -151,16 +157,20 @@ class BaseDump {
return false;
}
while ( $this->reader->read() ) {
- if ( $this->reader->nodeType == XMLReader::ELEMENT &&
- $this->reader->name == $name ) {
+ if ( $this->reader->nodeType == XMLReader::ELEMENT
+ && $this->reader->name == $name
+ ) {
return true;
}
- if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
- $this->reader->name == $parent ) {
+ if ( $this->reader->nodeType == XMLReader::END_ELEMENT
+ && $this->reader->name == $parent
+ ) {
$this->debug( "BaseDump::skipTo found </$parent> searching for <$name>" );
+
return false;
}
}
+
return $this->close();
}
@@ -169,7 +179,7 @@ class BaseDump {
* Fetches text contents of the current element, assuming
* no sub-elements or such scary things.
*
- * @return String
+ * @return string
* @access private
*/
function nodeContents() {
@@ -182,15 +192,16 @@ class BaseDump {
$buffer = "";
while ( $this->reader->read() ) {
switch ( $this->reader->nodeType ) {
- case XMLReader::TEXT:
-// case XMLReader::WHITESPACE:
- case XMLReader::SIGNIFICANT_WHITESPACE:
- $buffer .= $this->reader->value;
- break;
- case XMLReader::END_ELEMENT:
- return $buffer;
+ case XMLReader::TEXT:
+ //case XMLReader::WHITESPACE:
+ case XMLReader::SIGNIFICANT_WHITESPACE:
+ $buffer .= $this->reader->value;
+ break;
+ case XMLReader::END_ELEMENT:
+ return $buffer;
}
}
+
return $this->close();
}
@@ -201,6 +212,7 @@ class BaseDump {
function close() {
$this->reader->close();
$this->atEnd = true;
+
return null;
}
}
diff --git a/maintenance/backupTextPass.inc b/maintenance/backupTextPass.inc
index c515c6fe..5f776373 100644
--- a/maintenance/backupTextPass.inc
+++ b/maintenance/backupTextPass.inc
@@ -3,7 +3,7 @@
* BackupDumper that postprocesses XML dumps from dumpBackup.php to add page text
*
* Copyright (C) 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -30,59 +30,60 @@ require_once __DIR__ . '/backup.inc';
* @ingroup Maintenance
*/
class TextPassDumper extends BackupDumper {
- var $prefetch = null;
- var $input = "php://stdin";
- var $history = WikiExporter::FULL;
- var $fetchCount = 0;
- var $prefetchCount = 0;
- var $prefetchCountLast = 0;
- var $fetchCountLast = 0;
+ public $prefetch = null;
- var $maxFailures = 5;
- var $maxConsecutiveFailedTextRetrievals = 200;
- var $failureTimeout = 5; // Seconds to sleep after db failure
+ // when we spend more than maxTimeAllowed seconds on this run, we continue
+ // processing until we write out the next complete page, then save output file(s),
+ // rename it/them and open new one(s)
+ public $maxTimeAllowed = 0; // 0 = no limit
- var $php = "php";
- var $spawn = false;
+ protected $input = "php://stdin";
+ protected $history = WikiExporter::FULL;
+ protected $fetchCount = 0;
+ protected $prefetchCount = 0;
+ protected $prefetchCountLast = 0;
+ protected $fetchCountLast = 0;
+
+ protected $maxFailures = 5;
+ protected $maxConsecutiveFailedTextRetrievals = 200;
+ protected $failureTimeout = 5; // Seconds to sleep after db failure
+
+ protected $php = "php";
+ protected $spawn = false;
/**
* @var bool|resource
*/
- var $spawnProc = false;
+ protected $spawnProc = false;
/**
* @var bool|resource
*/
- var $spawnWrite = false;
+ protected $spawnWrite = false;
/**
* @var bool|resource
*/
- var $spawnRead = false;
+ protected $spawnRead = false;
/**
* @var bool|resource
*/
- var $spawnErr = false;
+ protected $spawnErr = false;
- var $xmlwriterobj = false;
+ protected $xmlwriterobj = false;
- // when we spend more than maxTimeAllowed seconds on this run, we continue
- // processing until we write out the next complete page, then save output file(s),
- // rename it/them and open new one(s)
- var $maxTimeAllowed = 0; // 0 = no limit
- var $timeExceeded = false;
- var $firstPageWritten = false;
- var $lastPageWritten = false;
- var $checkpointJustWritten = false;
- var $checkpointFiles = array();
+ protected $timeExceeded = false;
+ protected $firstPageWritten = false;
+ protected $lastPageWritten = false;
+ protected $checkpointJustWritten = false;
+ protected $checkpointFiles = array();
/**
* @var DatabaseBase
*/
protected $db;
-
/**
* Drop the database connection $this->db and try to get a new one.
*
@@ -103,6 +104,7 @@ class TextPassDumper extends BackupDumper {
if ( $this->forcedDb !== null ) {
$this->db = $this->forcedDb;
+
return;
}
@@ -120,19 +122,19 @@ class TextPassDumper extends BackupDumper {
try {
$this->lb = wfGetLBFactory()->newMainLB();
} catch ( Exception $e ) {
- throw new MWException( __METHOD__ . " rotating DB failed to obtain new load balancer (" . $e->getMessage() . ")" );
+ throw new MWException( __METHOD__
+ . " rotating DB failed to obtain new load balancer (" . $e->getMessage() . ")" );
}
-
// 2. The Connection, through the load balancer.
try {
- $this->db = $this->lb->getConnection( DB_SLAVE, 'backup' );
+ $this->db = $this->lb->getConnection( DB_SLAVE, 'dump' );
} catch ( Exception $e ) {
- throw new MWException( __METHOD__ . " rotating DB failed to obtain new database (" . $e->getMessage() . ")" );
+ throw new MWException( __METHOD__
+ . " rotating DB failed to obtain new database (" . $e->getMessage() . ")" );
}
}
-
function initProgress( $history = WikiExporter::FULL ) {
parent::initProgress();
$this->timeOfCheckpoint = $this->startTime;
@@ -184,31 +186,31 @@ class TextPassDumper extends BackupDumper {
$url = $this->processFileOpt( $val, $param );
switch ( $opt ) {
- case 'prefetch':
- require_once "$IP/maintenance/backupPrefetch.inc";
- $this->prefetch = new BaseDump( $url );
- break;
- case 'stub':
- $this->input = $url;
- break;
- case 'maxtime':
- $this->maxTimeAllowed = intval( $val ) * 60;
- break;
- case 'checkpointfile':
- $this->checkpointFiles[] = $val;
- break;
- case 'current':
- $this->history = WikiExporter::CURRENT;
- break;
- case 'full':
- $this->history = WikiExporter::FULL;
- break;
- case 'spawn':
- $this->spawn = true;
- if ( $val ) {
- $this->php = $val;
- }
- break;
+ case 'prefetch':
+ require_once "$IP/maintenance/backupPrefetch.inc";
+ $this->prefetch = new BaseDump( $url );
+ break;
+ case 'stub':
+ $this->input = $url;
+ break;
+ case 'maxtime':
+ $this->maxTimeAllowed = intval( $val ) * 60;
+ break;
+ case 'checkpointfile':
+ $this->checkpointFiles[] = $val;
+ break;
+ case 'current':
+ $this->history = WikiExporter::CURRENT;
+ break;
+ case 'full':
+ $this->history = WikiExporter::FULL;
+ break;
+ case 'spawn':
+ $this->spawn = true;
+ if ( $val ) {
+ $this->php = $val;
+ }
+ break;
}
}
@@ -234,6 +236,7 @@ class TextPassDumper extends BackupDumper {
$newFileURIs[] = $newURI;
}
$val = implode( ';', $newFileURIs );
+
return $val;
}
@@ -243,6 +246,7 @@ class TextPassDumper extends BackupDumper {
function showReport() {
if ( !$this->prefetch ) {
parent::showReport();
+
return;
}
@@ -279,14 +283,19 @@ class TextPassDumper extends BackupDumper {
}
$pageRatePart = $this->pageCountPart / $deltaPart;
$revRatePart = $this->revCountPart / $deltaPart;
-
} else {
$fetchRatePart = '-';
$pageRatePart = '-';
$revRatePart = '-';
}
- $this->progress( sprintf( "%s: %s (ID %d) %d pages (%0.1f|%0.1f/sec all|curr), %d revs (%0.1f|%0.1f/sec all|curr), %0.1f%%|%0.1f%% prefetched (all|curr), ETA %s [max %d]",
- $now, wfWikiID(), $this->ID, $this->pageCount, $pageRate, $pageRatePart, $this->revCount, $revRate, $revRatePart, $fetchRate, $fetchRatePart, $etats, $this->maxCount ) );
+ $this->progress( sprintf(
+ "%s: %s (ID %d) %d pages (%0.1f|%0.1f/sec all|curr), "
+ . "%d revs (%0.1f|%0.1f/sec all|curr), %0.1f%%|%0.1f%% "
+ . "prefetched (all|curr), ETA %s [max %d]",
+ $now, wfWikiID(), $this->ID, $this->pageCount, $pageRate,
+ $pageRatePart, $this->revCount, $revRate, $revRatePart,
+ $fetchRate, $fetchRatePart, $etats, $this->maxCount
+ ) );
$this->lastTime = $nowts;
$this->revCountLast = $this->revCount;
$this->prefetchCountLast = $this->prefetchCount;
@@ -299,35 +308,43 @@ class TextPassDumper extends BackupDumper {
}
function checkIfTimeExceeded() {
- if ( $this->maxTimeAllowed && ( $this->lastTime - $this->timeOfCheckpoint > $this->maxTimeAllowed ) ) {
+ if ( $this->maxTimeAllowed
+ && ( $this->lastTime - $this->timeOfCheckpoint > $this->maxTimeAllowed )
+ ) {
return true;
}
+
return false;
}
function finalOptionCheck() {
- if ( ( $this->checkpointFiles && ! $this->maxTimeAllowed ) ||
- ( $this->maxTimeAllowed && !$this->checkpointFiles ) ) {
+ if ( ( $this->checkpointFiles && !$this->maxTimeAllowed )
+ || ( $this->maxTimeAllowed && !$this->checkpointFiles )
+ ) {
throw new MWException( "Options checkpointfile and maxtime must be specified together.\n" );
}
foreach ( $this->checkpointFiles as $checkpointFile ) {
- $count = substr_count ( $checkpointFile, "%s" );
+ $count = substr_count( $checkpointFile, "%s" );
if ( $count != 2 ) {
- throw new MWException( "Option checkpointfile must contain two '%s' for substitution of first and last pageids, count is $count instead, file is $checkpointFile.\n" );
+ throw new MWException( "Option checkpointfile must contain two '%s' "
+ . "for substitution of first and last pageids, count is $count instead, "
+ . "file is $checkpointFile.\n" );
}
}
if ( $this->checkpointFiles ) {
$filenameList = (array)$this->egress->getFilenames();
if ( count( $filenameList ) != count( $this->checkpointFiles ) ) {
- throw new MWException( "One checkpointfile must be specified for each output option, if maxtime is used.\n" );
+ throw new MWException( "One checkpointfile must be specified "
+ . "for each output option, if maxtime is used.\n" );
}
}
}
/**
* @throws MWException Failure to parse XML input
- * @return true
+ * @param string $input
+ * @return bool
*/
function readDump( $input ) {
$this->buffer = "";
@@ -341,7 +358,11 @@ class TextPassDumper extends BackupDumper {
$parser = xml_parser_create( "UTF-8" );
xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );
- xml_set_element_handler( $parser, array( &$this, 'startElement' ), array( &$this, 'endElement' ) );
+ xml_set_element_handler(
+ $parser,
+ array( &$this, 'startElement' ),
+ array( &$this, 'endElement' )
+ );
xml_set_character_data_handler( $parser, array( &$this, 'characterData' ) );
$offset = 0; // for context extraction on error reporting
@@ -359,7 +380,7 @@ class TextPassDumper extends BackupDumper {
'XML import parse failure',
xml_get_current_line_number( $parser ),
xml_get_current_column_number( $parser ),
- $byte . ( is_null( $chunk ) ? null : ( '; "' . substr( $chunk, $byte -$offset, 16 ) . '"' ) ),
+ $byte . ( is_null( $chunk ) ? null : ( '; "' . substr( $chunk, $byte - $offset, 16 ) . '"' ) ),
xml_error_string( xml_get_error_code( $parser ) ) )->escaped();
xml_parser_free( $parser );
@@ -378,15 +399,16 @@ class TextPassDumper extends BackupDumper {
# there's no pageID 0 so we use that. the caller is responsible
# for deciding what to do with a file containing only the
# siteinfo information and the mw tags.
- if ( ! $this->firstPageWritten ) {
+ if ( !$this->firstPageWritten ) {
$firstPageID = str_pad( 0, 9, "0", STR_PAD_LEFT );
$lastPageID = str_pad( 0, 9, "0", STR_PAD_LEFT );
- }
- else {
+ } else {
$firstPageID = str_pad( $this->firstPageWritten, 9, "0", STR_PAD_LEFT );
$lastPageID = str_pad( $this->lastPageWritten, 9, "0", STR_PAD_LEFT );
}
- for ( $i = 0; $i < count( $filenameList ); $i++ ) {
+
+ $filenameCount = count( $filenameList );
+ for ( $i = 0; $i < $filenameCount; $i++ ) {
$checkpointNameFilledIn = sprintf( $this->checkpointFiles[$i], $firstPageID, $lastPageID );
$fileinfo = pathinfo( $filenameList[$i] );
$newFilenames[] = $fileinfo['dirname'] . '/' . $checkpointNameFilledIn;
@@ -408,7 +430,7 @@ class TextPassDumper extends BackupDumper {
* $this->maxConsecutiveFailedTextRetrievals consecutive calls to getText, MWException
* is thrown.
*
- * @param $id string The revision id to get the text for
+ * @param string $id The revision id to get the text for
*
* @return string The revision text for $id, or ""
* @throws MWException
@@ -420,8 +442,8 @@ class TextPassDumper extends BackupDumper {
$text = false; // The candidate for a good text. false if no proper value.
$failures = 0; // The number of times, this invocation of getText already failed.
- static $consecutiveFailedTextRetrievals = 0; // The number of times getText failed without
- // yielding a good text in between.
+ // The number of times getText failed without yielding a good text in between.
+ static $consecutiveFailedTextRetrievals = 0;
$this->fetchCount++;
@@ -478,7 +500,7 @@ class TextPassDumper extends BackupDumper {
// Step 2: Checking for plausibility and return the text if it is
// plausible
$revID = intval( $this->thisRev );
- if ( ! isset( $this->db ) ) {
+ if ( !isset( $this->db ) ) {
throw new MWException( "No database available" );
}
@@ -497,9 +519,7 @@ class TextPassDumper extends BackupDumper {
$revLength = $row->rev_len;
}
}
-
- }
- else {
+ } else {
$revLength = $this->db->selectField( 'revision', 'rev_len', array( 'rev_id' => $revID ) );
}
@@ -507,12 +527,12 @@ class TextPassDumper extends BackupDumper {
if ( $tryIsPrefetch ) {
$this->prefetchCount++;
}
+
return $text;
}
$text = false;
throw new MWException( "Received text is unplausible for id " . $id );
-
} catch ( Exception $e ) {
$msg = "getting/checking text " . $id . " failed (" . $e->getMessage() . ")";
if ( $failures + 1 < $this->maxFailures ) {
@@ -525,7 +545,7 @@ class TextPassDumper extends BackupDumper {
$failures++;
// A failure in a prefetch hit does not warrant resetting db connection etc.
- if ( ! $tryIsPrefetch ) {
+ if ( !$tryIsPrefetch ) {
// After backing off for some time, we try to reboot the whole process as
// much as possible to not carry over failures from one part to the other
// parts
@@ -556,16 +576,15 @@ class TextPassDumper extends BackupDumper {
return "";
}
-
/**
* May throw a database error if, say, the server dies during query.
- * @param $id
+ * @param int $id
* @return bool|string
* @throws MWException
*/
private function getTextDb( $id ) {
global $wgContLang;
- if ( ! isset( $this->db ) ) {
+ if ( !isset( $this->db ) ) {
throw new MWException( __METHOD__ . "No database available" );
}
$row = $this->db->selectRow( 'text',
@@ -578,6 +597,7 @@ class TextPassDumper extends BackupDumper {
}
$stripped = str_replace( "\r", "", $text );
$normalized = $wgContLang->normalize( $stripped );
+
return $normalized;
}
@@ -589,6 +609,7 @@ class TextPassDumper extends BackupDumper {
}
$text = $this->getTextSpawnedOnce( $id );
wfRestoreWarnings();
+
return $text;
}
@@ -603,8 +624,7 @@ class TextPassDumper extends BackupDumper {
"$IP/../multiversion/MWScript.php",
"fetchText.php",
'--wiki', wfWikiID() ) ) );
- }
- else {
+ } else {
$cmd = implode( " ",
array_map( 'wfEscapeShellArg',
array(
@@ -623,11 +643,12 @@ class TextPassDumper extends BackupDumper {
if ( !$this->spawnProc ) {
// shit
$this->progress( "Subprocess spawn failed." );
+
return false;
}
list(
$this->spawnWrite, // -> stdin
- $this->spawnRead, // <- stdout
+ $this->spawnRead, // <- stdout
) = $pipes;
return true;
@@ -705,12 +726,14 @@ class TextPassDumper extends BackupDumper {
$gotbytes = strlen( $text );
if ( $gotbytes != $nbytes ) {
$this->progress( "Expected $nbytes bytes from database subprocess, got $gotbytes " );
+
return false;
}
// Do normalization in the dump thread...
$stripped = str_replace( "\r", "", $text );
$normalized = $wgContLang->normalize( $stripped );
+
return $normalized;
}
@@ -758,7 +781,7 @@ class TextPassDumper extends BackupDumper {
$this->buffer = "";
$this->thisRev = "";
} elseif ( $name == 'page' ) {
- if ( ! $this->firstPageWritten ) {
+ if ( !$this->firstPageWritten ) {
$this->firstPageWritten = trim( $this->thisPage );
}
$this->lastPageWritten = trim( $this->thisPage );
@@ -779,7 +802,8 @@ class TextPassDumper extends BackupDumper {
$newFilenames = array();
$firstPageID = str_pad( $this->firstPageWritten, 9, "0", STR_PAD_LEFT );
$lastPageID = str_pad( $this->lastPageWritten, 9, "0", STR_PAD_LEFT );
- for ( $i = 0; $i < count( $filenameList ); $i++ ) {
+ $filenamesCount = count( $filenameList );
+ for ( $i = 0; $i < $filenamesCount; $i++ ) {
$checkpointNameFilledIn = sprintf( $this->checkpointFiles[$i], $firstPageID, $lastPageID );
$fileinfo = pathinfo( $filenameList[$i] );
$newFilenames[] = $fileinfo['dirname'] . '/' . $checkpointNameFilledIn;
@@ -790,13 +814,11 @@ class TextPassDumper extends BackupDumper {
$this->timeOfCheckpoint = $this->lastTime;
$this->firstPageWritten = false;
$this->checkpointJustWritten = true;
- }
- else {
+ } else {
$this->egress->writeClosePage( $this->buffer );
$this->buffer = "";
$this->thisPage = "";
}
-
} elseif ( $name == 'mediawiki' ) {
$this->egress->writeCloseStream( $this->buffer );
$this->buffer = "";
diff --git a/maintenance/benchmarks/Benchmarker.php b/maintenance/benchmarks/Benchmarker.php
index dd558f32..3f8a8990 100644
--- a/maintenance/benchmarks/Benchmarker.php
+++ b/maintenance/benchmarks/Benchmarker.php
@@ -46,38 +46,38 @@ abstract class Benchmarker extends Maintenance {
$bench_number = 0;
$count = $this->getOption( 'count', 100 );
- foreach( $benchs as $bench ) {
+ foreach ( $benchs as $bench ) {
// handle empty args
- if( !array_key_exists( 'args', $bench ) ) {
+ if ( !array_key_exists( 'args', $bench ) ) {
$bench['args'] = array();
}
$bench_number++;
$start = microtime( true );
- for( $i = 0; $i < $count; $i++ ) {
+ for ( $i = 0; $i < $count; $i++ ) {
call_user_func_array( $bench['function'], $bench['args'] );
}
$delta = microtime( true ) - $start;
// function passed as a callback
- if( is_array( $bench['function'] ) ) {
+ if ( is_array( $bench['function'] ) ) {
$ret = get_class( $bench['function'][0] ) . '->' . $bench['function'][1];
$bench['function'] = $ret;
}
$this->results[$bench_number] = array(
- 'function' => $bench['function'],
+ 'function' => $bench['function'],
'arguments' => $bench['args'],
- 'count' => $count,
- 'delta' => $delta,
- 'average' => $delta / $count,
- );
+ 'count' => $count,
+ 'delta' => $delta,
+ 'average' => $delta / $count,
+ );
}
}
public function getFormattedResults() {
$ret = '';
- foreach( $this->results as $res ) {
+ foreach ( $this->results as $res ) {
// show function with args
$ret .= sprintf( "%s times: function %s(%s) :\n",
$res['count'],
@@ -89,6 +89,7 @@ abstract class Benchmarker extends Maintenance {
$res['average'] * 1000
);
}
+
return $ret;
}
}
diff --git a/maintenance/benchmarks/bench_HTTP_HTTPS.php b/maintenance/benchmarks/bench_HTTP_HTTPS.php
index 6f800fb3..bb7499b7 100644
--- a/maintenance/benchmarks/bench_HTTP_HTTPS.php
+++ b/maintenance/benchmarks/bench_HTTP_HTTPS.php
@@ -31,8 +31,7 @@ require_once __DIR__ . '/Benchmarker.php';
*
* @ingroup Benchmark
*/
-class bench_HTTP_HTTPS extends Benchmarker {
-
+class BenchHttpHttps extends Benchmarker {
public function __construct() {
parent::__construct();
$this->mDescription = "Benchmark HTTP request vs HTTPS request.";
@@ -42,7 +41,7 @@ class bench_HTTP_HTTPS extends Benchmarker {
$this->bench( array(
array( 'function' => array( $this, 'getHTTP' ) ),
array( 'function' => array( $this, 'getHTTPS' ) ),
- ));
+ ) );
print $this->getFormattedResults();
}
@@ -61,5 +60,5 @@ class bench_HTTP_HTTPS extends Benchmarker {
}
}
-$maintClass = 'bench_HTTP_HTTPS';
+$maintClass = 'BenchHttpHttps';
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/benchmarks/bench_delete_truncate.php b/maintenance/benchmarks/bench_delete_truncate.php
index 3eff534b..8ae4f030 100644
--- a/maintenance/benchmarks/bench_delete_truncate.php
+++ b/maintenance/benchmarks/bench_delete_truncate.php
@@ -29,7 +29,6 @@ require_once __DIR__ . '/Benchmarker.php';
* @ingroup Benchmark
*/
class BenchmarkDeleteTruncate extends Benchmarker {
-
public function __construct() {
parent::__construct();
$this->mDescription = "Benchmarks SQL DELETE vs SQL TRUNCATE.";
@@ -70,20 +69,20 @@ class BenchmarkDeleteTruncate extends Benchmarker {
}
/**
- * @param $dbw DatabaseBase
+ * @param DatabaseBase $dbw
* @return void
*/
private function insertData( $dbw ) {
$range = range( 0, 1024 );
$data = array();
- foreach( $range as $r ) {
+ foreach ( $range as $r ) {
$data[] = array( 'text' => $r );
}
$dbw->insert( 'test', $data, __METHOD__ );
}
/**
- * @param $dbw DatabaseBase
+ * @param DatabaseBase $dbw
* @return void
*/
private function delete( $dbw ) {
@@ -91,7 +90,7 @@ class BenchmarkDeleteTruncate extends Benchmarker {
}
/**
- * @param $dbw DatabaseBase
+ * @param DatabaseBase $dbw
* @return void
*/
private function truncate( $dbw ) {
diff --git a/maintenance/benchmarks/bench_if_switch.php b/maintenance/benchmarks/bench_if_switch.php
index 80fd9623..698a0f0a 100644
--- a/maintenance/benchmarks/bench_if_switch.php
+++ b/maintenance/benchmarks/bench_if_switch.php
@@ -31,8 +31,7 @@ require_once __DIR__ . '/Benchmarker.php';
*
* @ingroup Maintenance
*/
-class bench_if_switch extends Benchmarker {
-
+class BenchIfSwitch extends Benchmarker {
public function __construct() {
parent::__construct();
$this->mDescription = "Benchmark if elseif... versus switch case.";
@@ -42,55 +41,71 @@ class bench_if_switch extends Benchmarker {
$this->bench( array(
array( 'function' => array( $this, 'doElseIf' ) ),
array( 'function' => array( $this, 'doSwitch' ) ),
- ));
+ ) );
print $this->getFormattedResults();
}
// bench function 1
function doElseIf() {
$a = 'z';
- if( $a == 'a') {}
- elseif( $a == 'b') {}
- elseif( $a == 'c') {}
- elseif( $a == 'd') {}
- elseif( $a == 'e') {}
- elseif( $a == 'f') {}
- elseif( $a == 'g') {}
- elseif( $a == 'h') {}
- elseif( $a == 'i') {}
- elseif( $a == 'j') {}
- elseif( $a == 'k') {}
- elseif( $a == 'l') {}
- elseif( $a == 'm') {}
- elseif( $a == 'n') {}
- elseif( $a == 'o') {}
- elseif( $a == 'p') {}
- else {}
+ if ( $a == 'a' ) {
+ } elseif ( $a == 'b' ) {
+ } elseif ( $a == 'c' ) {
+ } elseif ( $a == 'd' ) {
+ } elseif ( $a == 'e' ) {
+ } elseif ( $a == 'f' ) {
+ } elseif ( $a == 'g' ) {
+ } elseif ( $a == 'h' ) {
+ } elseif ( $a == 'i' ) {
+ } elseif ( $a == 'j' ) {
+ } elseif ( $a == 'k' ) {
+ } elseif ( $a == 'l' ) {
+ } elseif ( $a == 'm' ) {
+ } elseif ( $a == 'n' ) {
+ } elseif ( $a == 'o' ) {
+ } elseif ( $a == 'p' ) {
+ } else {
+ }
}
// bench function 2
function doSwitch() {
$a = 'z';
- switch( $a ) {
- case 'b': break;
- case 'c': break;
- case 'd': break;
- case 'e': break;
- case 'f': break;
- case 'g': break;
- case 'h': break;
- case 'i': break;
- case 'j': break;
- case 'k': break;
- case 'l': break;
- case 'm': break;
- case 'n': break;
- case 'o': break;
- case 'p': break;
+ switch ( $a ) {
+ case 'b':
+ break;
+ case 'c':
+ break;
+ case 'd':
+ break;
+ case 'e':
+ break;
+ case 'f':
+ break;
+ case 'g':
+ break;
+ case 'h':
+ break;
+ case 'i':
+ break;
+ case 'j':
+ break;
+ case 'k':
+ break;
+ case 'l':
+ break;
+ case 'm':
+ break;
+ case 'n':
+ break;
+ case 'o':
+ break;
+ case 'p':
+ break;
default:
}
}
}
-$maintClass = 'bench_if_switch';
+$maintClass = 'BenchIfSwitch';
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/benchmarks/bench_strtr_str_replace.php b/maintenance/benchmarks/bench_strtr_str_replace.php
index bd21b186..44c8e032 100644
--- a/maintenance/benchmarks/bench_strtr_str_replace.php
+++ b/maintenance/benchmarks/bench_strtr_str_replace.php
@@ -38,8 +38,7 @@ function bfNormalizeTitleStrReplace( $str ) {
*
* @ingroup Benchmark
*/
-class bench_strtr_str_replace extends Benchmarker {
-
+class BenchStrtrStrReplace extends Benchmarker {
public function __construct() {
parent::__construct();
$this->mDescription = "Benchmark for strtr() vs str_replace().";
@@ -51,7 +50,7 @@ class bench_strtr_str_replace extends Benchmarker {
array( 'function' => array( $this, 'benchstr_replace' ) ),
array( 'function' => array( $this, 'benchstrtr_indirect' ) ),
array( 'function' => array( $this, 'benchstr_replace_indirect' ) ),
- ));
+ ) );
print $this->getFormattedResults();
}
@@ -60,10 +59,9 @@ class bench_strtr_str_replace extends Benchmarker {
}
function benchstr_replace() {
- str_replace( "_", " ", "[[MediaWiki:Some_random_test_page]]");
+ str_replace( "_", " ", "[[MediaWiki:Some_random_test_page]]" );
}
-
function benchstrtr_indirect() {
bfNormalizeTitleStrTr( "[[MediaWiki:Some_random_test_page]]" );
}
@@ -71,8 +69,7 @@ class bench_strtr_str_replace extends Benchmarker {
function benchstr_replace_indirect() {
bfNormalizeTitleStrReplace( "[[MediaWiki:Some_random_test_page]]" );
}
-
}
-$maintClass = 'bench_strtr_str_replace';
+$maintClass = 'BenchStrtrStrReplace';
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/benchmarks/bench_utf8_title_check.php b/maintenance/benchmarks/bench_utf8_title_check.php
index 078293eb..b742f666 100644
--- a/maintenance/benchmarks/bench_utf8_title_check.php
+++ b/maintenance/benchmarks/bench_utf8_title_check.php
@@ -29,8 +29,7 @@ require_once __DIR__ . '/Benchmarker.php';
*
* @ingroup Benchmark
*/
-class bench_utf8_title_check extends Benchmarker {
-
+class BenchUtf8TitleCheck extends Benchmarker {
private $canRun;
private $data;
@@ -38,6 +37,7 @@ class bench_utf8_title_check extends Benchmarker {
public function __construct() {
parent::__construct();
+ // @codingStandardsIgnoreStart Ignore long line warnings.
$this->data = array(
"",
"United States of America", // 7bit ASCII
@@ -59,11 +59,13 @@ class bench_utf8_title_check extends Benchmarker {
. "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
. "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
);
+ // @codingStandardsIgnoreEnd
- $this->canRun = function_exists ( 'mb_check_encoding' );
+ $this->canRun = function_exists( 'mb_check_encoding' );
if ( $this->canRun ) {
- $this->mDescription = "Benchmark for using a regexp vs. mb_check_encoding to check for UTF-8 encoding.";
+ $this->mDescription = "Benchmark for using a regexp vs. mb_check_encoding " .
+ "to check for UTF-8 encoding.";
mb_internal_encoding( 'UTF-8' );
} else {
$this->mDescription = "CANNOT RUN benchmark using mb_check_encoding: function not available.";
@@ -75,22 +77,22 @@ class bench_utf8_title_check extends Benchmarker {
return;
}
$benchmarks = array();
- foreach ($this->data as $val) {
+ foreach ( $this->data as $val ) {
$benchmarks[] = array(
'function' => array( $this, 'use_regexp' ),
- 'args' => array( rawurldecode ( $val ) )
+ 'args' => array( rawurldecode( $val ) )
);
$benchmarks[] = array(
'function' => array( $this, 'use_regexp_non_capturing' ),
- 'args' => array( rawurldecode ( $val ) )
+ 'args' => array( rawurldecode( $val ) )
);
$benchmarks[] = array(
'function' => array( $this, 'use_regexp_once_only' ),
- 'args' => array( rawurldecode ( $val ) )
+ 'args' => array( rawurldecode( $val ) )
);
$benchmarks[] = array(
'function' => array( $this, 'use_mb_check_encoding' ),
- 'args' => array( rawurldecode ( $val ) )
+ 'args' => array( rawurldecode( $val ) )
);
}
$this->bench( $benchmarks );
@@ -101,26 +103,25 @@ class bench_utf8_title_check extends Benchmarker {
function use_regexp( $s ) {
$this->isutf8 = preg_match( '/^([\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
- '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
+ '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
}
function use_regexp_non_capturing( $s ) {
// Same as above with a non-capturing subgroup.
$this->isutf8 = preg_match( '/^(?:[\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
- '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
+ '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
}
function use_regexp_once_only( $s ) {
// Same as above with a once-only subgroup.
$this->isutf8 = preg_match( '/^(?>[\x00-\x7f]|[\xc0-\xdf][\x80-\xbf]|' .
- '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
+ '[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3})+$/', $s );
}
function use_mb_check_encoding( $s ) {
$this->isutf8 = mb_check_encoding( $s, 'UTF-8' );
}
-
}
-$maintClass = 'bench_utf8_title_check';
+$maintClass = 'BenchUtf8TitleCheck';
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/benchmarks/bench_wfBaseConvert.php b/maintenance/benchmarks/bench_wfBaseConvert.php
index f8a21562..b4be12bc 100644
--- a/maintenance/benchmarks/bench_wfBaseConvert.php
+++ b/maintenance/benchmarks/bench_wfBaseConvert.php
@@ -29,8 +29,7 @@ require_once __DIR__ . '/Benchmarker.php';
*
* @ingroup Benchmark
*/
-class bench_wfBaseConvert extends Benchmarker {
-
+class BenchWfBaseConvert extends Benchmarker {
public function __construct() {
parent::__construct();
$this->mDescription = "Benchmark for wfBaseConvert.";
@@ -58,7 +57,7 @@ class bench_wfBaseConvert extends Benchmarker {
'function' => 'wfBaseConvert',
'args' => array( $number, $inbase, $outbase, 0, true, 'gmp' )
),
- ));
+ ) );
$this->output( $this->getFormattedResults() );
}
@@ -66,12 +65,13 @@ class bench_wfBaseConvert extends Benchmarker {
protected static function makeRandomNumber( $base, $length ) {
$baseChars = "0123456789abcdefghijklmnopqrstuvwxyz";
$res = "";
- for( $i = 0; $i < $length; $i++ ) {
- $res .= $baseChars[mt_rand(0, $base - 1)];
+ for ( $i = 0; $i < $length; $i++ ) {
+ $res .= $baseChars[mt_rand( 0, $base - 1 )];
}
+
return $res;
}
}
-$maintClass = 'bench_wfBaseConvert';
+$maintClass = 'BenchWfBaseConvert';
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/benchmarks/bench_wfIsWindows.php b/maintenance/benchmarks/bench_wfIsWindows.php
index 1cd2016b..8446694b 100644
--- a/maintenance/benchmarks/bench_wfIsWindows.php
+++ b/maintenance/benchmarks/bench_wfIsWindows.php
@@ -31,8 +31,7 @@ require_once __DIR__ . '/Benchmarker.php';
*
* @ingroup Benchmark
*/
-class bench_wfIsWindows extends Benchmarker {
-
+class BenchWfIsWindows extends Benchmarker {
public function __construct() {
parent::__construct();
$this->mDescription = "Benchmark for wfIsWindows.";
@@ -42,12 +41,12 @@ class bench_wfIsWindows extends Benchmarker {
$this->bench( array(
array( 'function' => array( $this, 'wfIsWindows' ) ),
array( 'function' => array( $this, 'wfIsWindowsCached' ) ),
- ));
+ ) );
print $this->getFormattedResults();
}
static function is_win() {
- return substr( php_uname(), 0, 7 ) == 'Windows' ;
+ return substr( php_uname(), 0, 7 ) == 'Windows';
}
// bench function 1
@@ -58,12 +57,13 @@ class bench_wfIsWindows extends Benchmarker {
// bench function 2
function wfIsWindowsCached() {
static $isWindows = null;
- if( $isWindows == null ) {
+ if ( $isWindows == null ) {
$isWindows = self::is_win();
}
+
return $isWindows;
}
}
-$maintClass = 'bench_wfIsWindows';
+$maintClass = 'BenchWfIsWindows';
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/benchmarks/benchmarkHooks.php b/maintenance/benchmarks/benchmarkHooks.php
index 3f5d6db0..fb25b9d9 100644
--- a/maintenance/benchmarks/benchmarkHooks.php
+++ b/maintenance/benchmarks/benchmarkHooks.php
@@ -29,7 +29,6 @@ require_once __DIR__ . '/Benchmarker.php';
* @ingroup Benchmark
*/
class BenchmarkHooks extends Benchmarker {
-
public function __construct() {
parent::__construct();
$this->mDescription = 'Benchmark MediaWiki Hooks.';
@@ -46,13 +45,13 @@ class BenchmarkHooks extends Benchmarker {
$time = $this->benchHooks();
$this->output( 'Loaded (one) hook: ' . $time . "\n" );
- for( $i = 0; $i < 9; $i++ ) {
+ for ( $i = 0; $i < 9; $i++ ) {
$wgHooks['Test'][] = array( $this, 'test' );
}
$time = $this->benchHooks();
$this->output( 'Loaded (ten) hook: ' . $time . "\n" );
- for( $i = 0; $i < 90; $i++ ) {
+ for ( $i = 0; $i < 90; $i++ ) {
$wgHooks['Test'][] = array( $this, 'test' );
}
$time = $this->benchHooks();
@@ -61,7 +60,7 @@ class BenchmarkHooks extends Benchmarker {
}
/**
- * @param $trials int
+ * @param int $trials
* @return string
*/
private function benchHooks( $trials = 10 ) {
@@ -71,6 +70,7 @@ class BenchmarkHooks extends Benchmarker {
}
$delta = microtime( true ) - $start;
$pertrial = $delta / $trials;
+
return sprintf( "Took %6.3fms",
$pertrial * 1000 );
}
diff --git a/maintenance/benchmarks/benchmarkParse.php b/maintenance/benchmarks/benchmarkParse.php
new file mode 100644
index 00000000..ce38dad6
--- /dev/null
+++ b/maintenance/benchmarks/benchmarkParse.php
@@ -0,0 +1,174 @@
+<?php
+/**
+ * Benchmark script for parse operations
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author Tim Starling <tstarling@wikimedia.org>
+ * @ingroup Benchmark
+ */
+
+require __DIR__ . '/../Maintenance.php';
+
+/**
+ * Maintenance script to benchmark how long it takes to parse a given title at an optionally
+ * specified timestamp
+ *
+ * @since 1.23
+ */
+class BenchmarkParse extends Maintenance {
+ /** @var string MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS) */
+ private $templateTimestamp = null;
+
+ /** @var array Cache that maps a Title DB key to revision ID for the requested timestamp */
+ private $idCache = array();
+
+ function __construct() {
+ parent::__construct();
+ $this->addDescription( 'Benchmark parse operation' );
+ $this->addArg( 'title', 'The name of the page to parse' );
+ $this->addOption( 'warmup', 'Repeat the parse operation this number of times to warm the cache',
+ false, true );
+ $this->addOption( 'loops', 'Number of times to repeat parse operation post-warmup',
+ false, true );
+ $this->addOption( 'page-time',
+ 'Use the version of the page which was current at the given time',
+ false, true );
+ $this->addOption( 'tpl-time',
+ 'Use templates which were current at the given time (except that moves and ' .
+ 'deletes are not handled properly)',
+ false, true );
+ }
+
+ function execute() {
+ if ( $this->hasOption( 'tpl-time' ) ) {
+ $this->templateTimestamp = wfTimestamp( TS_MW, strtotime( $this->getOption( 'tpl-time' ) ) );
+ Hooks::register( 'BeforeParserFetchTemplateAndtitle', array( $this, 'onFetchTemplate' ) );
+ }
+
+ $title = Title::newFromText( $this->getArg() );
+ if ( !$title ) {
+ $this->error( "Invalid title" );
+ exit( 1 );
+ }
+
+ if ( $this->hasOption( 'page-time' ) ) {
+ $pageTimestamp = wfTimestamp( TS_MW, strtotime( $this->getOption( 'page-time' ) ) );
+ $id = $this->getRevIdForTime( $title, $pageTimestamp );
+ if ( !$id ) {
+ $this->error( "The page did not exist at that time" );
+ exit( 1 );
+ }
+
+ $revision = Revision::newFromId( $id );
+ } else {
+ $revision = Revision::newFromTitle( $title );
+ }
+
+ if ( !$revision ) {
+ $this->error( "Unable to load revision, incorrect title?" );
+ exit( 1 );
+ }
+
+ $warmup = $this->getOption( 'warmup', 1 );
+ for ( $i = 0; $i < $warmup; $i++ ) {
+ $this->runParser( $revision );
+ }
+
+ $loops = $this->getOption( 'loops', 1 );
+ if ( $loops < 1 ) {
+ $this->error( 'Invalid number of loops specified', true );
+ }
+ $startUsage = getrusage();
+ $startTime = microtime( true );
+ for ( $i = 0; $i < $loops; $i++ ) {
+ $this->runParser( $revision );
+ }
+ $endUsage = getrusage();
+ $endTime = microtime( true );
+
+ printf( "CPU time = %.3f s, wall clock time = %.3f s\n",
+ // CPU time
+ ( $endUsage['ru_utime.tv_sec'] + $endUsage['ru_utime.tv_usec'] * 1e-6
+ - $startUsage['ru_utime.tv_sec'] - $startUsage['ru_utime.tv_usec'] * 1e-6 ) / $loops,
+ // Wall clock time
+ ( $endTime - $startTime ) / $loops
+ );
+ }
+
+ /**
+ * Fetch the ID of the revision of a Title that occurred
+ *
+ * @param Title $title
+ * @param string $timestamp
+ * @return bool|string Revision ID, or false if not found or error
+ */
+ function getRevIdForTime( Title $title, $timestamp ) {
+ $dbr = wfGetDB( DB_SLAVE );
+
+ $id = $dbr->selectField(
+ array( 'revision', 'page' ),
+ 'rev_id',
+ array(
+ 'page_namespace' => $title->getNamespace(),
+ 'page_title' => $title->getDBkey(),
+ 'rev_timestamp <= ' . $dbr->addQuotes( $timestamp )
+ ),
+ __METHOD__,
+ array( 'ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 1 ),
+ array( 'revision' => array( 'INNER JOIN', 'rev_page=page_id' ) )
+ );
+
+ return $id;
+ }
+
+ /**
+ * Parse the text from a given Revision
+ *
+ * @param Revision $revision
+ */
+ function runParser( Revision $revision ) {
+ $content = $revision->getContent();
+ $content->getParserOutput( $revision->getTitle(), $revision->getId() );
+ }
+
+ /**
+ * Hook into the parser's revision ID fetcher. Make sure that the parser only
+ * uses revisions around the specified timestamp.
+ *
+ * @param Parser $parser
+ * @param Title $title
+ * @param bool &$skip
+ * @param string|bool &$id
+ * @return bool
+ */
+ function onFetchTemplate( Parser $parser, Title $title, &$skip, &$id ) {
+ $pdbk = $title->getPrefixedDBkey();
+ if ( !isset( $this->idCache[$pdbk] ) ) {
+ $proposedId = $this->getRevIdForTime( $title, $this->templateTimestamp );
+ $this->idCache[$pdbk] = $proposedId;
+ }
+ if ( $this->idCache[$pdbk] !== false ) {
+ $id = $this->idCache[$pdbk];
+ }
+
+ return true;
+ }
+}
+
+$maintClass = 'BenchmarkParse';
+require RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/benchmarks/benchmarkPurge.php b/maintenance/benchmarks/benchmarkPurge.php
index fd863d52..42c1eb78 100644
--- a/maintenance/benchmarks/benchmarkPurge.php
+++ b/maintenance/benchmarks/benchmarkPurge.php
@@ -29,7 +29,6 @@ require_once __DIR__ . '/Benchmarker.php';
* @ingroup Benchmark
*/
class BenchmarkPurge extends Benchmarker {
-
public function __construct() {
parent::__construct();
$this->mDescription = "Benchmark the Squid purge functions.";
@@ -57,8 +56,8 @@ class BenchmarkPurge extends Benchmarker {
/**
* Run a bunch of URLs through SquidUpdate::purge()
* to benchmark Squid response times.
- * @param $urls array A bunch of URLs to purge
- * @param $trials int How many times to run the test?
+ * @param array $urls A bunch of URLs to purge
+ * @param int $trials How many times to run the test?
* @return string
*/
private function benchSquid( $urls, $trials = 1 ) {
@@ -69,13 +68,14 @@ class BenchmarkPurge extends Benchmarker {
$delta = microtime( true ) - $start;
$pertrial = $delta / $trials;
$pertitle = $pertrial / count( $urls );
+
return sprintf( "%4d titles in %6.2fms (%6.2fms each)",
count( $urls ), $pertrial * 1000.0, $pertitle * 1000.0 );
}
/**
* Get an array of randomUrl()'s.
- * @param $length int How many urls to add to the array
+ * @param int $length How many urls to add to the array
* @return array
*/
private function randomUrlList( $length ) {
@@ -83,6 +83,7 @@ class BenchmarkPurge extends Benchmarker {
for ( $i = 0; $i < $length; $i++ ) {
$list[] = $this->randomUrl();
}
+
return $list;
}
@@ -93,6 +94,7 @@ class BenchmarkPurge extends Benchmarker {
*/
private function randomUrl() {
global $wgServer, $wgArticlePath;
+
return $wgServer . str_replace( '$1', $this->randomTitle(), $wgArticlePath );
}
@@ -107,6 +109,7 @@ class BenchmarkPurge extends Benchmarker {
for ( $i = 0; $i < $length; $i++ ) {
$str .= chr( mt_rand( ord( 'a' ), ord( 'z' ) ) );
}
+
return ucfirst( $str );
}
}
diff --git a/maintenance/cdb.php b/maintenance/cdb.php
index d42f9f7a..86c686b4 100644
--- a/maintenance/cdb.php
+++ b/maintenance/cdb.php
@@ -52,7 +52,7 @@ do {
$bad = false;
$showhelp = false;
$quit = false;
- static $fileHandle;
+ static $fileHandle = false;
$line = Maintenance::readconsole();
if ( $line === false ) {
@@ -75,7 +75,11 @@ do {
}
$file = $args[0];
print "Loading cdb file $file...";
- $fileHandle = CdbReader::open( $file );
+ try {
+ $fileHandle = CdbReader::open( $file );
+ } catch ( CdbException $e ) {
+ }
+
if ( !$fileHandle ) {
print "not a cdb file or unable to read it\n";
} else {
@@ -91,7 +95,12 @@ do {
print "Need to specify a key, Luke\n";
break;
}
- $res = $fileHandle->get( $args[0] );
+ try {
+ $res = $fileHandle->get( $args[0] );
+ } catch ( CdbException $e ) {
+ print "Unable to read key from file\n";
+ break;
+ }
if ( $res === false ) {
print "No such key/value pair\n";
} elseif ( is_string( $res ) ) {
diff --git a/maintenance/checkBadRedirects.php b/maintenance/checkBadRedirects.php
index a96e9b80..fec92910 100644
--- a/maintenance/checkBadRedirects.php
+++ b/maintenance/checkBadRedirects.php
@@ -44,7 +44,7 @@ class CheckBadRedirects extends Maintenance {
$count = $result->numRows();
$this->output( "Found $count redirects.\n" .
- "Checking for bad redirects:\n\n" );
+ "Checking for bad redirects:\n\n" );
foreach ( $result as $row ) {
$title = Title::makeTitle( $row->page_namespace, $row->page_title );
diff --git a/maintenance/checkImages.php b/maintenance/checkImages.php
index e6aea537..3921c079 100644
--- a/maintenance/checkImages.php
+++ b/maintenance/checkImages.php
@@ -73,13 +73,13 @@ class CheckImages extends Maintenance {
}
if ( $stat['size'] != $row->img_size ) {
- $this->output( "{$row->img_name}: size mismatch DB={$row->img_size}, actual={$stat['size']}\n" );
+ $this->output( "{$row->img_name}: size mismatch DB={$row->img_size}, "
+ . "actual={$stat['size']}\n" );
continue;
}
$numGood++;
}
-
} while ( $res->numRows() );
$this->output( "Good images: $numGood/$numImages\n" );
diff --git a/maintenance/checkLess.php b/maintenance/checkLess.php
index d02d8a7b..b97e1b0b 100644
--- a/maintenance/checkLess.php
+++ b/maintenance/checkLess.php
@@ -22,49 +22,33 @@
*/
require_once __DIR__ . '/Maintenance.php';
+require_once 'PHPUnit/Autoload.php';
/**
* @ingroup Maintenance
*/
class CheckLess extends Maintenance {
+
public function __construct() {
parent::__construct();
- $this->mDescription = 'Checks LESS files for errors';
+ $this->mDescription =
+ 'Checks LESS files for errors by running the LessTestSuite PHPUnit test suite';
}
public function execute() {
- $result = false;
- $resourceLoader = new ResourceLoader();
- foreach ( $resourceLoader->getModuleNames() as $name ) {
- /** @var ResourceLoaderFileModule $module */
- $module = $resourceLoader->getModule( $name );
- if ( !$module || !$module instanceof ResourceLoaderFileModule ) {
- continue;
- }
+ global $IP;
+
+ // NOTE (phuedx, 2014-03-26) wgAutoloadClasses isn't set up
+ // by either of the dependencies at the top of the file, so
+ // require it here.
+ require_once __DIR__ . '/../tests/TestsAutoLoader.php';
- $hadErrors = false;
- foreach ( $module->getAllStyleFiles() as $file ) {
- if ( $module->getStyleSheetLang( $file ) !== 'less' ) {
- continue;
- }
- try {
- $compiler = ResourceLoader::getLessCompiler();
- $compiler->compileFile( $file );
- } catch ( Exception $e ) {
- if ( !$hadErrors ) {
- $this->error( "Errors checking module $name:\n" );
- $hadErrors = true;
- }
- $this->error( $e->getMessage() . "\n" );
- $result = true;
- }
- }
- }
- if ( !$result ) {
- $this->output( "No errors found\n" );
- } else {
- die( 1 );
- }
+ $textUICommand = new PHPUnit_TextUI_Command();
+ $argv = array(
+ "$IP/tests/phpunit/phpunit.php",
+ "$IP/tests/phpunit/suites/LessTestSuite.php"
+ );
+ $textUICommand->run( $argv );
}
}
diff --git a/maintenance/checkSyntax.php b/maintenance/checkSyntax.php
index dc8626df..d1c2edd0 100644
--- a/maintenance/checkSyntax.php
+++ b/maintenance/checkSyntax.php
@@ -38,10 +38,23 @@ class CheckSyntax extends Maintenance {
parent::__construct();
$this->mDescription = "Check syntax for all PHP files in MediaWiki";
$this->addOption( 'with-extensions', 'Also recurse the extensions folder' );
- $this->addOption( 'path', 'Specific path (file or directory) to check, either with absolute path or relative to the root of this MediaWiki installation',
- false, true );
- $this->addOption( 'list-file', 'Text file containing list of files or directories to check', false, true );
- $this->addOption( 'modified', 'Check only files that were modified (requires Git command-line client)' );
+ $this->addOption(
+ 'path',
+ 'Specific path (file or directory) to check, either with absolute path or '
+ . 'relative to the root of this MediaWiki installation',
+ false,
+ true
+ );
+ $this->addOption(
+ 'list-file',
+ 'Text file containing list of files or directories to check',
+ false,
+ true
+ );
+ $this->addOption(
+ 'modified',
+ 'Check only files that were modified (requires Git command-line client)'
+ );
$this->addOption( 'syntax-only', 'Check for syntax validity only, skip code style warnings' );
}
@@ -53,7 +66,8 @@ class CheckSyntax extends Maintenance {
$this->buildFileList();
// ParseKit is broken on PHP 5.3+, disabled until this is fixed
- $useParseKit = function_exists( 'parsekit_compile_file' ) && version_compare( PHP_VERSION, '5.3', '<' );
+ $useParseKit = function_exists( 'parsekit_compile_file' )
+ && version_compare( PHP_VERSION, '5.3', '<' );
$str = 'Checking syntax (using ' . ( $useParseKit ?
'parsekit' : ' php -l, this can take a long time' ) . ")\n";
@@ -82,7 +96,7 @@ class CheckSyntax extends Maintenance {
$this->mIgnorePaths = array(
// Compat stuff, explodes on PHP 5.3
"includes/NamespaceCompat.php$",
- );
+ );
$this->mNoStyleCheckPaths = array(
// Third-party code we don't care about
@@ -96,13 +110,14 @@ class CheckSyntax extends Maintenance {
"QPoll/Excel/",
"/geshi/",
"/smarty/",
- );
+ );
if ( $this->hasOption( 'path' ) ) {
$path = $this->getOption( 'path' );
if ( !$this->addPath( $path ) ) {
$this->error( "Error: can't find file or directory $path\n", true );
}
+
return; // process only this path
} elseif ( $this->hasOption( 'list-file' ) ) {
$file = $this->getOption( 'list-file' );
@@ -117,6 +132,7 @@ class CheckSyntax extends Maintenance {
$this->addPath( $path );
}
fclose( $f );
+
return;
} elseif ( $this->hasOption( 'modified' ) ) {
$this->output( "Retrieving list from Git... " );
@@ -127,6 +143,7 @@ class CheckSyntax extends Maintenance {
$this->mFiles[] = $file;
}
}
+
return;
}
@@ -153,17 +170,14 @@ class CheckSyntax extends Maintenance {
if ( file_exists( "$IP/LocalSettings.php" ) ) {
$this->mFiles[] = "$IP/LocalSettings.php";
}
- if ( file_exists( "$IP/AdminSettings.php" ) ) {
- $this->mFiles[] = "$IP/AdminSettings.php";
- }
$this->output( 'done.', 'listfiles' );
}
/**
* Returns a list of tracked files in a Git work tree differing from the master branch.
- * @param $path string: Path to the repository
- * @return array: Resulting list of changed files
+ * @param string $path Path to the repository
+ * @return array Resulting list of changed files
*/
private function getGitModifiedFiles( $path ) {
@@ -215,7 +229,7 @@ class CheckSyntax extends Maintenance {
/**
* Returns true if $file is of a type we can check
- * @param $file string
+ * @param string $file
* @return bool
*/
private function isSuitableFile( $file ) {
@@ -230,22 +244,24 @@ class CheckSyntax extends Maintenance {
return false;
}
}
+
return true;
}
/**
* Add given path to file list, searching it in include path if needed
- * @param $path string
+ * @param string $path
* @return bool
*/
private function addPath( $path ) {
global $IP;
+
return $this->addFileOrDir( $path ) || $this->addFileOrDir( "$IP/$path" );
}
/**
* Add given file to file list, or, if it's a directory, add its content
- * @param $path string
+ * @param string $path
* @return bool
*/
private function addFileOrDir( $path ) {
@@ -256,13 +272,14 @@ class CheckSyntax extends Maintenance {
} else {
return false;
}
+
return true;
}
/**
* Add all suitable files in given directory or its subdirectories to the file list
*
- * @param $dir String: directory to process
+ * @param string $dir Directory to process
*/
private function addDirectoryContent( $dir ) {
$iterator = new RecursiveIteratorIterator(
@@ -279,8 +296,8 @@ class CheckSyntax extends Maintenance {
/**
* Check a file for syntax errors using Parsekit. Shamelessly stolen
* from tools/lint.php by TimStarling
- * @param $file String Path to a file to check for syntax errors
- * @return boolean
+ * @param string $file Path to a file to check for syntax errors
+ * @return bool
*/
private function checkFileWithParsekit( $file ) {
static $okErrors = array(
@@ -302,21 +319,24 @@ class CheckSyntax extends Maintenance {
$this->mFailures[$file] = $errors;
}
}
+
return $ret;
}
/**
* Check a file for syntax errors using php -l
- * @param $file String Path to a file to check for syntax errors
- * @return boolean
+ * @param string $file Path to a file to check for syntax errors
+ * @return bool
*/
private function checkFileWithCli( $file ) {
$res = exec( 'php -l ' . wfEscapeShellArg( $file ) );
if ( strpos( $res, 'No syntax errors detected' ) === false ) {
$this->mFailures[$file] = $res;
$this->output( $res . "\n" );
+
return false;
}
+
return true;
}
@@ -324,8 +344,7 @@ class CheckSyntax extends Maintenance {
* Check a file for non-fatal coding errors, such as byte-order marks in the beginning
* or pointless ?> closing tags at the end.
*
- * @param $file String String Path to a file to check for errors
- * @return boolean
+ * @param string $file String Path to a file to check for errors
*/
private function checkForMistakes( $file ) {
foreach ( $this->mNoStyleCheckPaths as $regex ) {
diff --git a/maintenance/checkUsernames.php b/maintenance/checkUsernames.php
index 6df189fc..777c8334 100644
--- a/maintenance/checkUsernames.php
+++ b/maintenance/checkUsernames.php
@@ -55,7 +55,7 @@ class CheckUsernames extends Maintenance {
);
foreach ( $res as $row ) {
- if ( ! User::isValidUserName( $row->user_name ) ) {
+ if ( !User::isValidUserName( $row->user_name ) ) {
$this->error( sprintf( "%s: %6d: '%s'\n", wfWikiID(), $row->user_id, $row->user_name ) );
wfDebugLog( 'checkUsernames', $row->user_name );
}
diff --git a/maintenance/cleanupAncientTables.php b/maintenance/cleanupAncientTables.php
index 694efaa6..2dbf8bc1 100644
--- a/maintenance/cleanupAncientTables.php
+++ b/maintenance/cleanupAncientTables.php
@@ -40,8 +40,9 @@ class CleanupAncientTables extends Maintenance {
public function execute() {
if ( !$this->hasOption( 'force' ) ) {
$this->error( "This maintenance script will remove old columns and indexes.\n"
- . "It is recommended to backup your database first, and ensure all your data has been migrated to newer tables\n"
- . "If you want to continue, run this script again with the --force \n"
+ . "It is recommended to backup your database first, and ensure all your data has\n"
+ . "been migrated to newer tables. If you want to continue, run this script again\n"
+ . "with --force.\n"
);
}
@@ -82,7 +83,7 @@ class CleanupAncientTables extends Maintenance {
if ( $db->indexExists( 'text', $index, __METHOD__ ) ) {
$this->output( "Dropping index $index from the text table..." );
$db->query( "DROP INDEX " . $db->addIdentifierQuotes( $index )
- . " ON " . $db->tableName( 'text' ) );
+ . " ON " . $db->tableName( 'text' ) );
$this->output( "done.\n" );
}
}
@@ -101,7 +102,7 @@ class CleanupAncientTables extends Maintenance {
if ( $db->fieldExists( 'text', $field, __METHOD__ ) ) {
$this->output( "Dropping the $field field from the text table..." );
$db->query( "ALTER TABLE " . $db->tableName( 'text' )
- . " DROP COLUMN " . $db->addIdentifierQuotes( $field ) );
+ . " DROP COLUMN " . $db->addIdentifierQuotes( $field ) );
$this->output( "done.\n" );
}
}
diff --git a/maintenance/cleanupCaps.php b/maintenance/cleanupCaps.php
index 1a47ac4e..9e88c135 100644
--- a/maintenance/cleanupCaps.php
+++ b/maintenance/cleanupCaps.php
@@ -7,7 +7,7 @@
* --dry-run don't actually try moving them
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -71,6 +71,7 @@ class CapsCleanup extends TableCleanup {
$lower = $wgContLang->lcfirst( $row->page_title );
if ( $upper == $lower ) {
$this->output( "\"$display\" already lowercase.\n" );
+
return $this->progress( 0 );
}
@@ -78,6 +79,7 @@ class CapsCleanup extends TableCleanup {
$targetDisplay = $target->getPrefixedText();
if ( $target->exists() ) {
$this->output( "\"$display\" skipped; \"$targetDisplay\" already exists\n" );
+
return $this->progress( 0 );
}
@@ -98,6 +100,7 @@ class CapsCleanup extends TableCleanup {
}
}
}
+
return $this->progress( 0 );
}
}
diff --git a/maintenance/cleanupImages.php b/maintenance/cleanupImages.php
index 0e0b6194..915a2c08 100644
--- a/maintenance/cleanupImages.php
+++ b/maintenance/cleanupImages.php
@@ -7,7 +7,7 @@
* --fix Actually clean up titles; otherwise just checks for them
*
* Copyright © 2005-2006 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -56,6 +56,7 @@ class ImageCleanup extends TableCleanup {
if ( $source == '' ) {
// Ye olde empty rows. Just kill them.
$this->killRow( $source );
+
return $this->progress( 1 );
}
@@ -82,6 +83,7 @@ class ImageCleanup extends TableCleanup {
return $this->progress( 0 );
}
$this->pokeFile( $source, $safe );
+
return $this->progress( 1 );
}
@@ -89,6 +91,7 @@ class ImageCleanup extends TableCleanup {
$munged = $title->getDBkey();
$this->output( "page $source ($munged) doesn't match self.\n" );
$this->pokeFile( $source, $munged );
+
return $this->progress( 1 );
}
@@ -96,7 +99,7 @@ class ImageCleanup extends TableCleanup {
}
/**
- * @param $name string
+ * @param string $name
*/
private function killRow( $name ) {
if ( $this->dryrun ) {
@@ -114,6 +117,7 @@ class ImageCleanup extends TableCleanup {
if ( !isset( $this->repo ) ) {
$this->repo = RepoGroup::singleton()->getLocalRepo();
}
+
return $this->repo->getRootDirectory() . '/' . $this->repo->getHashPath( $name ) . $name;
}
@@ -122,7 +126,12 @@ class ImageCleanup extends TableCleanup {
}
private function pageExists( $name, $db ) {
- return $db->selectField( 'page', '1', array( 'page_namespace' => NS_FILE, 'page_title' => $name ), __METHOD__ );
+ return $db->selectField(
+ 'page',
+ '1',
+ array( 'page_namespace' => NS_FILE, 'page_title' => $name ),
+ __METHOD__
+ );
}
private function pokeFile( $orig, $new ) {
@@ -130,6 +139,7 @@ class ImageCleanup extends TableCleanup {
if ( !file_exists( $path ) ) {
$this->output( "missing file: $path\n" );
$this->killRow( $orig );
+
return;
}
@@ -145,7 +155,7 @@ class ImageCleanup extends TableCleanup {
$version = 0;
$final = $new;
$conflict = ( $this->imageExists( $final, $db ) ||
- ( $this->pageExists( $orig, $db ) && $this->pageExists( $final, $db ) ) );
+ ( $this->pageExists( $orig, $db ) && $this->pageExists( $final, $db ) ) );
while ( $conflict ) {
$this->output( "Rename conflicts with '$final'...\n" );
@@ -179,6 +189,7 @@ class ImageCleanup extends TableCleanup {
if ( !wfMkdirParents( $dir, null, __METHOD__ ) ) {
$this->output( "RENAME FAILED, COULD NOT CREATE $dir" );
$db->rollback( __METHOD__ );
+
return;
}
}
@@ -205,6 +216,7 @@ class ImageCleanup extends TableCleanup {
$test = Title::makeTitleSafe( NS_FILE, $x );
if ( is_null( $test ) || $test->getDBkey() !== $x ) {
$this->error( "Unable to generate safe title from '$name', got '$x'" );
+
return false;
}
diff --git a/maintenance/cleanupRemovedModules.php b/maintenance/cleanupRemovedModules.php
index 84eec289..e1d0ed6e 100644
--- a/maintenance/cleanupRemovedModules.php
+++ b/maintenance/cleanupRemovedModules.php
@@ -36,12 +36,18 @@ class CleanupRemovedModules extends Maintenance {
parent::__construct();
$this->mDescription = 'Remove cache entries for removed ResourceLoader modules from the database';
$this->addOption( 'batchsize', 'Delete rows in batches of this size. Default: 500', false, true );
- $this->addOption( 'max-slave-lag', 'If the slave lag exceeds this many seconds, wait until it drops below this value. Default: 5', false, true );
+ $this->addOption(
+ 'max-slave-lag',
+ 'If the slave lag exceeds this many seconds, wait until it drops below this value. '
+ . 'Default: 5',
+ false,
+ true
+ );
}
public function execute() {
$dbw = wfGetDB( DB_MASTER );
- $rl = new ResourceLoader();
+ $rl = new ResourceLoader( ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) );
$moduleNames = $rl->getModuleNames();
$moduleList = implode( ', ', array_map( array( $dbw, 'addQuotes' ), $moduleNames ) );
$limit = max( 1, intval( $this->getOption( 'batchsize', 500 ) ) );
diff --git a/maintenance/cleanupSpam.php b/maintenance/cleanupSpam.php
index 4b8c9feb..f4a5147a 100644
--- a/maintenance/cleanupSpam.php
+++ b/maintenance/cleanupSpam.php
@@ -35,11 +35,14 @@ class CleanupSpam extends Maintenance {
$this->mDescription = "Cleanup all spam from a given hostname";
$this->addOption( 'all', 'Check all wikis in $wgLocalDatabases' );
$this->addOption( 'delete', 'Delete pages containing only spam instead of blanking them' );
- $this->addArg( 'hostname', 'Hostname that was spamming, single * wildcard in the beginning allowed' );
+ $this->addArg(
+ 'hostname',
+ 'Hostname that was spamming, single * wildcard in the beginning allowed'
+ );
}
public function execute() {
- global $wgLocalDatabases, $wgUser;
+ global $IP, $wgLocalDatabases, $wgUser;
$username = wfMessage( 'spambot_username' )->text();
$wgUser = User::newFromName( $username );
@@ -67,7 +70,9 @@ class CleanupSpam extends Maintenance {
array( 'el_index' . $dbr->buildLike( $like ) ), __METHOD__ );
if ( $count ) {
$found = true;
- passthru( "php cleanupSpam.php --wiki='$wikiID' $spec | sed 's/^/$wikiID: /'" );
+ $cmd = wfShellWikiCmd( "$IP/maintenance/cleanupSpam.php",
+ array( '--wiki', $wikiID, $spec ) );
+ passthru( "$cmd | sed 's/^/$wikiID: /'" );
}
}
if ( $found ) {
@@ -96,6 +101,7 @@ class CleanupSpam extends Maintenance {
$title = Title::newFromID( $id );
if ( !$title ) {
$this->error( "Internal error: no page for ID $id" );
+
return;
}
@@ -104,7 +110,8 @@ class CleanupSpam extends Maintenance {
$currentRevId = $rev->getId();
while ( $rev && ( $rev->isDeleted( Revision::DELETED_TEXT )
- || LinkFilter::matchEntry( $rev->getContent( Revision::RAW ), $domain ) ) ) {
+ || LinkFilter::matchEntry( $rev->getContent( Revision::RAW ), $domain ) )
+ ) {
$rev = $rev->getPrevious();
}
@@ -121,19 +128,28 @@ class CleanupSpam extends Maintenance {
$content = $rev->getContent( Revision::RAW );
$this->output( "reverting\n" );
- $page->doEditContent( $content, wfMessage( 'spam_reverting', $domain )->inContentLanguage()->text(),
- EDIT_UPDATE, $rev->getId() );
+ $page->doEditContent(
+ $content,
+ wfMessage( 'spam_reverting', $domain )->inContentLanguage()->text(),
+ EDIT_UPDATE,
+ $rev->getId()
+ );
} elseif ( $this->hasOption( 'delete' ) ) {
// Didn't find a non-spammy revision, blank the page
$this->output( "deleting\n" );
- $page->doDeleteArticle( wfMessage( 'spam_deleting', $domain )->inContentLanguage()->text() );
+ $page->doDeleteArticle(
+ wfMessage( 'spam_deleting', $domain )->inContentLanguage()->text()
+ );
} else {
// Didn't find a non-spammy revision, blank the page
$handler = ContentHandler::getForTitle( $title );
$content = $handler->makeEmptyContent();
$this->output( "blanking\n" );
- $page->doEditContent( $content, wfMessage( 'spam_blanking', $domain )->inContentLanguage()->text() );
+ $page->doEditContent(
+ $content,
+ wfMessage( 'spam_blanking', $domain )->inContentLanguage()->text()
+ );
}
$dbw->commit( __METHOD__ );
}
diff --git a/maintenance/cleanupTitles.php b/maintenance/cleanupTitles.php
index 5b5ef184..0df9e7fe 100644
--- a/maintenance/cleanupTitles.php
+++ b/maintenance/cleanupTitles.php
@@ -7,7 +7,7 @@
* --fix Actually clean up titles; otherwise just checks for them
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -148,9 +148,15 @@ class TitleCleanup extends TableCleanup {
$ns = 0;
}
+ # Namespace which no longer exists. Put the page in the main namespace
+ # since we don't have any idea of the old namespace name. See bug 68501.
+ if ( !MWNamespace::exists( $ns ) ) {
+ $ns = 0;
+ }
+
$clean = 'Broken/' . $prior;
$verified = Title::makeTitleSafe( $ns, $clean );
- if ( $verified->exists() ) {
+ if ( !$verified || $verified->exists() ) {
$blah = "Broken/id:" . $row->page_id;
$this->output( "Couldn't legalize; form '$clean' exists; using '$blah'\n" );
$verified = Title::makeTitleSafe( $ns, $blah );
diff --git a/maintenance/cleanupUploadStash.php b/maintenance/cleanupUploadStash.php
index c2ba5558..24b63a8b 100644
--- a/maintenance/cleanupUploadStash.php
+++ b/maintenance/cleanupUploadStash.php
@@ -38,6 +38,7 @@ class UploadStashCleanup extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Clean up abandoned files in temporary uploaded file stash";
+ $this->setBatchSize( 50 );
}
public function execute() {
@@ -81,10 +82,9 @@ class UploadStashCleanup extends Maintenance {
try {
$stash->getFile( $key, true );
$stash->removeFileNoAuth( $key );
- } catch ( UploadStashBadPathException $ex ) {
- $this->output( "Failed removing stashed upload with key: $key\n" );
- } catch ( UploadStashZeroLengthFileException $ex ) {
- $this->output( "Failed removing stashed upload with key: $key\n" );
+ } catch ( UploadStashException $ex ) {
+ $type = get_class( $ex );
+ $this->output( "Failed removing stashed upload with key: $key ($type)\n" );
}
if ( $i % 100 == 0 ) {
$this->output( "$i\n" );
@@ -95,20 +95,25 @@ class UploadStashCleanup extends Maintenance {
// Delete all the corresponding thumbnails...
$dir = $tempRepo->getZonePath( 'thumb' );
- $iterator = $tempRepo->getBackend()->getFileList( array( 'dir' => $dir ) );
+ $iterator = $tempRepo->getBackend()->getFileList( array( 'dir' => $dir, 'adviseStat' => 1 ) );
$this->output( "Deleting old thumbnails...\n" );
$i = 0;
+ $batch = array(); // operation batch
foreach ( $iterator as $file ) {
if ( wfTimestamp( TS_UNIX, $tempRepo->getFileTimestamp( "$dir/$file" ) ) < $cutoff ) {
- $status = $tempRepo->quickPurge( "$dir/$file" );
- if ( !$status->isOK() ) {
- $this->error( print_r( $status->getErrorsArray(), true ) );
- }
- if ( ( ++$i % 100 ) == 0 ) {
+ $batch[] = array( 'op' => 'delete', 'src' => "$dir/$file" );
+ if ( count( $batch ) >= $this->mBatchSize ) {
+ $this->doOperations( $tempRepo, $batch );
+ $i += count( $batch );
+ $batch = array();
$this->output( "$i\n" );
}
}
}
+ if ( count( $batch ) ) {
+ $this->doOperations( $tempRepo, $batch );
+ $i += count( $batch );
+ }
$this->output( "$i done\n" );
// Apparently lots of stash files are not registered in the DB...
@@ -119,24 +124,31 @@ class UploadStashCleanup extends Maintenance {
$this->error( "Temp repo is not using the temp container.", 1 ); // die
}
$i = 0;
+ $batch = array(); // operation batch
foreach ( $iterator as $file ) {
- // Absolute sanity check for stashed files and file segments
- if ( !preg_match( '#(^\d{14}!|\.\d+\.\w+\.\d+$)#', basename( $file ) ) ) {
- $this->output( "Skipped non-stash $file\n" );
- continue;
- }
if ( wfTimestamp( TS_UNIX, $tempRepo->getFileTimestamp( "$dir/$file" ) ) < $cutoff ) {
- $status = $tempRepo->quickPurge( "$dir/$file" );
- if ( !$status->isOK() ) {
- $this->error( print_r( $status->getErrorsArray(), true ) );
- }
- if ( ( ++$i % 100 ) == 0 ) {
+ $batch[] = array( 'op' => 'delete', 'src' => "$dir/$file" );
+ if ( count( $batch ) >= $this->mBatchSize ) {
+ $this->doOperations( $tempRepo, $batch );
+ $i += count( $batch );
+ $batch = array();
$this->output( "$i\n" );
}
}
}
+ if ( count( $batch ) ) {
+ $this->doOperations( $tempRepo, $batch );
+ $i += count( $batch );
+ }
$this->output( "$i done\n" );
}
+
+ protected function doOperations( FileRepo $tempRepo, array $ops ) {
+ $status = $tempRepo->getBackend()->doQuickOperations( $ops );
+ if ( !$status->isOK() ) {
+ $this->error( print_r( $status->getErrorsArray(), true ) );
+ }
+ }
}
$maintClass = "UploadStashCleanup";
diff --git a/maintenance/cleanupWatchlist.php b/maintenance/cleanupWatchlist.php
index f1a7b481..eb7d7b18 100644
--- a/maintenance/cleanupWatchlist.php
+++ b/maintenance/cleanupWatchlist.php
@@ -7,7 +7,7 @@
* --fix Actually remove entries; without will only report.
*
* Copyright © 2005,2006 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -65,9 +65,11 @@ class WatchlistCleanup extends TableCleanup {
$title = Title::newFromText( $verified );
if ( $row->wl_user == 0 || is_null( $title ) || !$title->equals( $current ) ) {
- $this->output( "invalid watch by {$row->wl_user} for ({$row->wl_namespace}, \"{$row->wl_title}\")\n" );
+ $this->output( "invalid watch by {$row->wl_user} for "
+ . "({$row->wl_namespace}, \"{$row->wl_title}\")\n" );
$updated = $this->removeWatch( $row );
$this->progress( $updated );
+
return;
}
$this->progress( 0 );
@@ -76,12 +78,16 @@ class WatchlistCleanup extends TableCleanup {
private function removeWatch( $row ) {
if ( !$this->dryrun && $this->hasOption( 'fix' ) ) {
$dbw = wfGetDB( DB_MASTER );
- $dbw->delete( 'watchlist', array(
+ $dbw->delete(
+ 'watchlist', array(
'wl_user' => $row->wl_user,
'wl_namespace' => $row->wl_namespace,
'wl_title' => $row->wl_title ),
- __METHOD__ );
+ __METHOD__
+ );
+
$this->output( "- removed\n" );
+
return 1;
} else {
return 0;
diff --git a/maintenance/commandLine.inc b/maintenance/commandLine.inc
index be071422..88776f4f 100644
--- a/maintenance/commandLine.inc
+++ b/maintenance/commandLine.inc
@@ -23,14 +23,18 @@
require_once __DIR__ . '/Maintenance.php';
+// @codingStandardsIgnoreStart MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
global $optionsWithArgs;
+// @codingStandardsIgnoreEnd
if ( !isset( $optionsWithArgs ) ) {
$optionsWithArgs = array();
}
class CommandLineInc extends Maintenance {
public function __construct() {
+ // @codingStandardsIgnoreStart MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
global $optionsWithArgs;
+ // @codingStandardsIgnoreEnd
parent::__construct();
foreach ( $optionsWithArgs as $name ) {
$this->addOption( $name, '', false, true );
@@ -39,6 +43,7 @@ class CommandLineInc extends Maintenance {
/**
* No help, it would just be misleading since it misses custom options
+ * @param bool $force
*/
protected function maybeHelp( $force = false ) {
if ( !$force ) {
@@ -48,7 +53,9 @@ class CommandLineInc extends Maintenance {
}
public function execute() {
+ // @codingStandardsIgnoreStart MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
global $args, $options;
+ // @codingStandardsIgnoreEnd
$args = $this->mArgs;
$options = $this->mOptions;
}
diff --git a/maintenance/compareParserCache.php b/maintenance/compareParserCache.php
new file mode 100644
index 00000000..98441b60
--- /dev/null
+++ b/maintenance/compareParserCache.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * @ingroup Maintenance
+ */
+class CompareParserCache extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Parse random pages and compare output to cache.";
+ $this->addOption( 'namespace', 'Page namespace number', true, true );
+ $this->addOption( 'maxpages', 'Number of pages to try', true, true );
+ }
+
+ public function execute() {
+ $pages = $this->getOption( 'maxpages' );
+
+ $dbr = $this->getDB( DB_SLAVE );
+
+ $totalsec = 0.0;
+ $scanned = 0;
+ $withcache = 0;
+ $withdiff = 0;
+ while ( $pages-- > 0 ) {
+ $row = $dbr->selectRow( 'page', '*',
+ array(
+ 'page_namespace' => $this->getOption( 'namespace' ),
+ 'page_is_redirect' => 0,
+ 'page_random >= ' . wfRandom()
+ ),
+ __METHOD__,
+ array(
+ 'ORDER BY' => 'page_random',
+ )
+ );
+
+ if ( !$row ) {
+ continue;
+ }
+ ++$scanned;
+
+ $title = Title::newFromRow( $row );
+ $page = WikiPage::factory( $title );
+ $revision = $page->getRevision();
+ $content = $revision->getContent( Revision::RAW );
+
+ $parserOptions = $page->makeParserOptions( 'canonical' );
+
+ $parserOutputOld = ParserCache::singleton()->get( $page, $parserOptions );
+
+ if ( $parserOutputOld ) {
+ $t1 = microtime( true );
+ $parserOutputNew = $content->getParserOutput(
+ $title, $revision->getId(), $parserOptions, false );
+ $sec = microtime( true ) - $t1;
+ $totalsec += $sec;
+
+ $this->output( "Parsed '{$title->getPrefixedText()}' in $sec seconds.\n" );
+
+ $this->output( "Found cache entry found for '{$title->getPrefixedText()}'..." );
+ $oldHtml = trim( preg_replace( '#<!-- .+-->#Us', '', $parserOutputOld->getText() ) );
+ $newHtml = trim( preg_replace( '#<!-- .+-->#Us', '', $parserOutputNew->getText() ) );
+ $diff = wfDiff( $oldHtml, $newHtml );
+ if ( strlen( $diff ) ) {
+ $this->output( "differences found:\n\n$diff\n\n" );
+ ++$withdiff;
+ } else {
+ $this->output( "No differences found.\n" );
+ }
+ ++$withcache;
+ } else {
+ $this->output( "No parser cache entry found for '{$title->getPrefixedText()}'.\n" );
+ }
+ }
+
+ $ave = $totalsec ? $totalsec / $scanned : 0;
+ $this->output( "Checked $scanned pages; $withcache had prior cache entries.\n" );
+ $this->output( "Pages with differences found: $withdiff\n" );
+ $this->output( "Average parse time: $ave sec\n" );
+ }
+}
+
+$maintClass = "CompareParserCache";
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/compareParsers.php b/maintenance/compareParsers.php
index fabc2571..e67c439b 100644
--- a/maintenance/compareParsers.php
+++ b/maintenance/compareParsers.php
@@ -7,7 +7,7 @@
* Templates etc are pulled from the local wiki database, not from the dump.
*
* Copyright © 2011 Platonides
- * http://www.mediawiki.org/
+ * https://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
@@ -47,11 +47,31 @@ class CompareParsers extends DumpIterator {
$this->addOption( 'parser1', 'The first parser to compare.', true, true );
$this->addOption( 'parser2', 'The second parser to compare.', true, true );
$this->addOption( 'tidy', 'Run tidy on the articles.', false, false );
- $this->addOption( 'save-failed', 'Folder in which articles which differ will be stored.', false, true );
+ $this->addOption(
+ 'save-failed',
+ 'Folder in which articles which differ will be stored.',
+ false,
+ true
+ );
$this->addOption( 'show-diff', 'Show a diff of the two renderings.', false, false );
- $this->addOption( 'diff-bin', 'Binary to use for diffing (can also be provided by DIFF env var).', false, false );
- $this->addOption( 'strip-parameters', 'Remove parameters of html tags to increase readability.', false, false );
- $this->addOption( 'show-parsed-output', 'Show the parsed html if both Parsers give the same output.', false, false );
+ $this->addOption(
+ 'diff-bin',
+ 'Binary to use for diffing (can also be provided by DIFF env var).',
+ false,
+ false
+ );
+ $this->addOption(
+ 'strip-parameters',
+ 'Remove parameters of html tags to increase readability.',
+ false,
+ false
+ );
+ $this->addOption(
+ 'show-parsed-output',
+ 'Show the parsed html if both Parsers give the same output.',
+ false,
+ false
+ );
}
public function checkOptions() {
@@ -96,12 +116,13 @@ class CompareParsers extends DumpIterator {
if ( !$this->stripParametersEnabled ) {
return $text;
}
+
return preg_replace( '/(<a) [^>]+>/', '$1>', $text );
}
/**
* Callback function for each revision, parse with both parsers and compare
- * @param $rev Revision
+ * @param Revision $rev
*/
public function processRevision( $rev ) {
$title = $rev->getTitle();
@@ -118,7 +139,9 @@ class CompareParsers extends DumpIterator {
$content = $rev->getContent();
if ( $content->getModel() !== CONTENT_MODEL_WIKITEXT ) {
- $this->error( "Page {$title->getPrefixedText()} does not contain wikitext but {$content->getModel()}\n" );
+ $this->error( "Page {$title->getPrefixedText()} does not contain wikitext "
+ . "but {$content->getModel()}\n" );
+
return;
}
@@ -132,13 +155,21 @@ class CompareParsers extends DumpIterator {
$this->error( "Parsing for {$title->getPrefixedText()} differs\n" );
if ( $this->saveFailed ) {
- file_put_contents( $this->saveFailed . '/' . rawurlencode( $title->getPrefixedText() ) . ".txt", $text );
+ file_put_contents(
+ $this->saveFailed . '/' . rawurlencode( $title->getPrefixedText() ) . ".txt",
+ $text
+ );
}
if ( $this->showDiff ) {
- $this->output( wfDiff( $this->stripParameters( $output1->getText() ), $this->stripParameters( $output2->getText() ), '' ) );
+ $this->output( wfDiff(
+ $this->stripParameters( $output1->getText() ),
+ $this->stripParameters( $output2->getText() ),
+ ''
+ ) );
}
} else {
$this->output( $title->getPrefixedText() . "\tOK\n" );
+
if ( $this->showParsedOutput ) {
$this->output( $this->stripParameters( $output1->getText() ) );
}
@@ -149,10 +180,9 @@ class CompareParsers extends DumpIterator {
/* Look for the parser in a file appropiately named in the current folder */
if ( !class_exists( $parserName ) && file_exists( "$parserName.php" ) ) {
global $wgAutoloadClasses;
- $wgAutoloadClasses[ $parserName ] = realpath( '.' ) . "/$parserName.php";
+ $wgAutoloadClasses[$parserName] = realpath( '.' ) . "/$parserName.php";
}
}
-
}
$maintClass = "CompareParsers";
diff --git a/maintenance/convertLinks.php b/maintenance/convertLinks.php
index 17b91110..221ebe37 100644
--- a/maintenance/convertLinks.php
+++ b/maintenance/convertLinks.php
@@ -36,14 +36,29 @@ class ConvertLinks extends Maintenance {
public function __construct() {
parent::__construct();
- $this->mDescription = "Convert from the old links schema (string->ID) to the new schema (ID->ID).
-The wiki should be put into read-only mode while this script executes";
+ $this->mDescription =
+ "Convert from the old links schema (string->ID) to the new schema (ID->ID)."
+ . "The wiki should be put into read-only mode while this script executes";
$this->addArg( 'logperformance', "Log performance to perfLogFilename.", false );
- $this->addArg( 'perfLogFilename', "Filename where performance is logged if --logperformance was set (defaults to 'convLinksPerf.txt').", false );
- $this->addArg( 'keep-links-table', "Don't overwrite the old links table with the new one, leave the new table at links_temp.", false );
- $this->addArg( 'nokeys', "Don't create keys, and so allow duplicates in the new links table.\n
-This gives a huge speed improvement for very large links tables which are MyISAM." /* (What about InnoDB?) */, false );
+ $this->addArg(
+ 'perfLogFilename',
+ "Filename where performance is logged if --logperformance was set "
+ . "(defaults to 'convLinksPerf.txt').",
+ false
+ );
+ $this->addArg(
+ 'keep-links-table',
+ "Don't overwrite the old links table with the new one, leave the new table at links_temp.",
+ false
+ );
+ $this->addArg(
+ 'nokeys',
+ /* (What about InnoDB?) */
+ "Don't create keys, and so allow duplicates in the new links table.\n"
+ . "This gives a huge speed improvement for very large links tables which are MyISAM.",
+ false
+ );
}
public function getDbType() {
@@ -56,22 +71,34 @@ This gives a huge speed improvement for very large links tables which are MyISAM
$type = $dbw->getType();
if ( $type != 'mysql' ) {
$this->output( "Link table conversion not necessary for $type\n" );
+
return;
}
global $wgContLang;
- $numBadLinks = $curRowsRead = 0; # counters etc
- $totalTuplesInserted = 0; # total tuples INSERTed into links_temp
+ # counters etc
+ $numBadLinks = $curRowsRead = 0;
+
+ # total tuples INSERTed into links_temp
+ $totalTuplesInserted = 0;
+
+ # whether or not to give progress reports while reading IDs from cur table
+ $reportCurReadProgress = true;
- $reportCurReadProgress = true; # whether or not to give progress reports while reading IDs from cur table
- $curReadReportInterval = 1000; # number of rows between progress reports
+ # number of rows between progress reports
+ $curReadReportInterval = 1000;
- $reportLinksConvProgress = true; # whether or not to give progress reports during conversion
- $linksConvInsertInterval = 1000; # number of rows per INSERT
+ # whether or not to give progress reports during conversion
+ $reportLinksConvProgress = true;
+
+ # number of rows per INSERT
+ $linksConvInsertInterval = 1000;
$initialRowOffset = 0;
- # $finalRowOffset = 0; # not used yet; highest row number from links table to process
+
+ # not used yet; highest row number from links table to process
+ # $finalRowOffset = 0;
$overwriteLinksTable = !$this->hasOption( 'keep-links-table' );
$noKeys = $this->hasOption( 'noKeys' );
@@ -80,16 +107,19 @@ This gives a huge speed improvement for very large links tables which are MyISAM
# --------------------------------------------------------------------
- list( $cur, $links, $links_temp, $links_backup ) = $dbw->tableNamesN( 'cur', 'links', 'links_temp', 'links_backup' );
+ list( $cur, $links, $links_temp, $links_backup ) =
+ $dbw->tableNamesN( 'cur', 'links', 'links_temp', 'links_backup' );
if ( $dbw->tableExists( 'pagelinks' ) ) {
$this->output( "...have pagelinks; skipping old links table updates\n" );
+
return;
}
$res = $dbw->query( "SELECT l_from FROM $links LIMIT 1" );
if ( $dbw->fieldType( $res, 0 ) == "int" ) {
$this->output( "Schema already converted\n" );
+
return;
}
@@ -104,17 +134,17 @@ This gives a huge speed improvement for very large links tables which are MyISAM
} else {
$fh = false;
if ( $this->logPerformance ) {
- $fh = fopen ( $perfLogFilename, "w" );
+ $fh = fopen( $perfLogFilename, "w" );
if ( !$fh ) {
$this->error( "Couldn't open $perfLogFilename" );
$this->logPerformance = false;
}
}
- $baseTime = $startTime = $this->getMicroTime();
+ $baseTime = $startTime = microtime( true );
# Create a title -> cur_id map
$this->output( "Loading IDs from $cur table...\n" );
- $this->performanceLog ( $fh, "Reading $numRows rows from cur table...\n" );
- $this->performanceLog ( $fh, "rows read vs seconds elapsed:\n" );
+ $this->performanceLog( $fh, "Reading $numRows rows from cur table...\n" );
+ $this->performanceLog( $fh, "rows read vs seconds elapsed:\n" );
$dbw->bufferResults( false );
$res = $dbw->query( "SELECT cur_namespace,cur_title,cur_id FROM $cur" );
@@ -129,7 +159,10 @@ This gives a huge speed improvement for very large links tables which are MyISAM
$curRowsRead++;
if ( $reportCurReadProgress ) {
if ( ( $curRowsRead % $curReadReportInterval ) == 0 ) {
- $this->performanceLog( $fh, $curRowsRead . " " . ( $this->getMicroTime() - $baseTime ) . "\n" );
+ $this->performanceLog(
+ $fh,
+ $curRowsRead . " " . ( microtime( true ) - $baseTime ) . "\n"
+ );
$this->output( "\t$curRowsRead rows of $cur table read.\n" );
}
}
@@ -137,7 +170,10 @@ This gives a huge speed improvement for very large links tables which are MyISAM
$dbw->freeResult( $res );
$dbw->bufferResults( true );
$this->output( "Finished loading IDs.\n\n" );
- $this->performanceLog( $fh, "Took " . ( $this->getMicroTime() - $baseTime ) . " seconds to load IDs.\n\n" );
+ $this->performanceLog(
+ $fh,
+ "Took " . ( microtime( true ) - $baseTime ) . " seconds to load IDs.\n\n"
+ );
# --------------------------------------------------------------------
@@ -145,12 +181,14 @@ This gives a huge speed improvement for very large links tables which are MyISAM
# convert, and write to the new table.
$this->createTempTable();
$this->performanceLog( $fh, "Resetting timer.\n\n" );
- $baseTime = $this->getMicroTime();
+ $baseTime = microtime( true );
$this->output( "Processing $numRows rows from $links table...\n" );
$this->performanceLog( $fh, "Processing $numRows rows from $links table...\n" );
$this->performanceLog( $fh, "rows inserted vs seconds elapsed:\n" );
- for ( $rowOffset = $initialRowOffset; $rowOffset < $numRows; $rowOffset += $linksConvInsertInterval ) {
+ for ( $rowOffset = $initialRowOffset; $rowOffset < $numRows;
+ $rowOffset += $linksConvInsertInterval
+ ) {
$sqlRead = "SELECT * FROM $links ";
$sqlRead = $dbw->limitResult( $sqlRead, $linksConvInsertInterval, $rowOffset );
$res = $dbw->query( $sqlRead );
@@ -176,7 +214,8 @@ This gives a huge speed improvement for very large links tables which are MyISAM
}
}
$dbw->freeResult( $res );
- # $this->output( "rowOffset: $rowOffset\ttuplesAdded: $tuplesAdded\tnumBadLinks: $numBadLinks\n" );
+ # $this->output( "rowOffset: $rowOffset\ttuplesAdded: "
+ # . "$tuplesAdded\tnumBadLinks: $numBadLinks\n" );
if ( $tuplesAdded != 0 ) {
if ( $reportLinksConvProgress ) {
$this->output( "Inserting $tuplesAdded tuples into $links_temp..." );
@@ -185,15 +224,25 @@ This gives a huge speed improvement for very large links tables which are MyISAM
$totalTuplesInserted += $tuplesAdded;
if ( $reportLinksConvProgress ) {
$this->output( " done. Total $totalTuplesInserted tuples inserted.\n" );
- $this->performanceLog( $fh, $totalTuplesInserted . " " . ( $this->getMicroTime() - $baseTime ) . "\n" );
+ $this->performanceLog(
+ $fh,
+ $totalTuplesInserted . " " . ( microtime( true ) - $baseTime ) . "\n"
+ );
}
}
}
- $this->output( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n\n" );
- $this->performanceLog( $fh, "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n" );
- $this->performanceLog( $fh, "Total execution time: " . ( $this->getMicroTime() - $startTime ) . " seconds.\n" );
+ $this->output( "$totalTuplesInserted valid titles and "
+ . "$numBadLinks invalid titles were processed.\n\n" );
+ $this->performanceLog(
+ $fh,
+ "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n"
+ );
+ $this->performanceLog(
+ $fh,
+ "Total execution time: " . ( microtime( true ) - $startTime ) . " seconds.\n"
+ );
if ( $this->logPerformance ) {
- fclose ( $fh );
+ fclose( $fh );
}
}
# --------------------------------------------------------------------
@@ -209,7 +258,6 @@ This gives a huge speed improvement for very large links tables which are MyISAM
$dbw->query( "RENAME TABLE links TO $links_backup, $links_temp TO $links", __METHOD__ );
$this->output( " done.\n\n" );
- $dbw->close();
$this->output( "Conversion complete. The old table remains at $links_backup;\n" );
$this->output( "delete at your leisure.\n" );
} else {
@@ -223,6 +271,7 @@ This gives a huge speed improvement for very large links tables which are MyISAM
if ( !( $dbConn->isOpen() ) ) {
$this->output( "Opening connection to database failed.\n" );
+
return;
}
$links_temp = $dbConn->tableName( 'links_temp' );
@@ -234,14 +283,14 @@ This gives a huge speed improvement for very large links tables which are MyISAM
$this->output( "Creating temporary links table..." );
if ( $this->hasOption( 'noKeys' ) ) {
$dbConn->query( "CREATE TABLE $links_temp ( " .
- "l_from int(8) unsigned NOT NULL default '0', " .
- "l_to int(8) unsigned NOT NULL default '0')" );
+ "l_from int(8) unsigned NOT NULL default '0', " .
+ "l_to int(8) unsigned NOT NULL default '0')" );
} else {
$dbConn->query( "CREATE TABLE $links_temp ( " .
- "l_from int(8) unsigned NOT NULL default '0', " .
- "l_to int(8) unsigned NOT NULL default '0', " .
- "UNIQUE KEY l_from(l_from,l_to), " .
- "KEY (l_to))" );
+ "l_from int(8) unsigned NOT NULL default '0', " .
+ "l_to int(8) unsigned NOT NULL default '0', " .
+ "UNIQUE KEY l_from(l_from,l_to), " .
+ "KEY (l_to))" );
}
$this->output( " done.\n\n" );
}
@@ -251,11 +300,6 @@ This gives a huge speed improvement for very large links tables which are MyISAM
fwrite( $fh, $text );
}
}
-
- private function getMicroTime() { # return time in seconds, with microsecond accuracy
- list( $usec, $sec ) = explode( " ", microtime() );
- return ( (float)$usec + (float)$sec );
- }
}
$maintClass = "ConvertLinks";
diff --git a/maintenance/convertUserOptions.php b/maintenance/convertUserOptions.php
index 34c643bb..1542a8c3 100644
--- a/maintenance/convertUserOptions.php
+++ b/maintenance/convertUserOptions.php
@@ -26,8 +26,6 @@ require_once __DIR__ . '/Maintenance.php';
/**
* Maintenance script to convert user options to the new `user_properties` table.
*
- * Do each user sequentially, since accounts can't be deleted
- *
* @ingroup Maintenance
*/
class ConvertUserOptions extends Maintenance {
@@ -37,6 +35,7 @@ class ConvertUserOptions extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Convert user options from old to new system";
+ $this->setBatchSize( 50 );
}
public function execute() {
@@ -46,17 +45,23 @@ class ConvertUserOptions extends Maintenance {
if ( !$dbw->fieldExists( 'user', 'user_options', __METHOD__ ) ) {
$this->output( "nothing to migrate. " );
+
return;
}
while ( $id !== null ) {
- $idCond = 'user_id > ' . $dbw->addQuotes( $id );
- $optCond = "user_options != " . $dbw->addQuotes( '' ); // For compatibility
- $res = $dbw->select( 'user', '*',
- array( $optCond, $idCond ), __METHOD__,
- array( 'LIMIT' => 50, 'FOR UPDATE' )
+ $res = $dbw->select( 'user',
+ array( 'user_id', 'user_options' ),
+ array(
+ 'user_id > ' . $dbw->addQuotes( $id ),
+ "user_options != " . $dbw->addQuotes( '' ),
+ ),
+ __METHOD__,
+ array(
+ 'ORDER BY' => 'user_id',
+ 'LIMIT' => $this->mBatchSize,
+ )
);
$id = $this->convertOptionBatch( $res, $dbw );
- $dbw->commit( __METHOD__ );
wfWaitForSlaves();
@@ -68,20 +73,37 @@ class ConvertUserOptions extends Maintenance {
}
/**
- * @param $res
- * @param $dbw DatabaseBase
+ * @param ResultWrapper $res
+ * @param DatabaseBase $dbw
* @return null|int
*/
function convertOptionBatch( $res, $dbw ) {
$id = null;
foreach ( $res as $row ) {
$this->mConversionCount++;
+ $insertRows = array();
+ foreach ( explode( "\n", $row->user_options ) as $s ) {
+ $m = array();
+ if ( !preg_match( "/^(.[^=]*)=(.*)$/", $s, $m ) ) {
+ continue;
+ }
- $u = User::newFromRow( $row );
+ // MW < 1.16 would save even default values. Filter them out
+ // here (as in User) to avoid adding many unnecessary rows.
+ $defaultOption = User::getDefaultOption( $m[1] );
+ if ( is_null( $defaultOption ) || $m[2] != $defaultOption ) {
+ $insertRows[] = array(
+ 'up_user' => $row->user_id,
+ 'up_property' => $m[1],
+ 'up_value' => $m[2],
+ );
+ }
+ }
- $u->saveSettings();
+ if ( count( $insertRows ) ) {
+ $dbw->insert( 'user_properties', $insertRows, __METHOD__, array( 'IGNORE' ) );
+ }
- // Do this here as saveSettings() doesn't set user_options to '' anymore!
$dbw->update(
'user',
array( 'user_options' => '' ),
diff --git a/maintenance/copyFileBackend.php b/maintenance/copyFileBackend.php
index 21ef4ffa..9ed63c3c 100644
--- a/maintenance/copyFileBackend.php
+++ b/maintenance/copyFileBackend.php
@@ -35,7 +35,8 @@ require_once __DIR__ . '/Maintenance.php';
* @ingroup Maintenance
*/
class CopyFileBackend extends Maintenance {
- protected $statCache = array();
+ /** @var array|null (path sha1 => stat) Pre-computed dst stat entries from listings */
+ protected $statCache = null;
public function __construct() {
parent::__construct();
@@ -98,7 +99,7 @@ class CopyFileBackend extends Maintenance {
if ( $dstPathsRel === null ) {
$this->error( "Could not list files in $container.", 1 ); // die
}
- $this->statCache = array(); // clear
+ $this->statCache = array();
foreach ( $dstPathsRel as $dstPathRel ) {
$path = $dst->getRootStoragePath() . "/$backendRel/$dstPathRel";
$this->statCache[sha1( $path )] = $dst->getFileStat( array( 'src' => $path ) );
@@ -238,8 +239,8 @@ class CopyFileBackend extends Maintenance {
$this->error( "$wikiId: Detected illegal (non-UTF8) path for $srcPath." );
continue;
} elseif ( !$this->hasOption( 'missingonly' )
- && $this->filesAreSame( $src, $dst, $srcPath, $dstPath ) )
- {
+ && $this->filesAreSame( $src, $dst, $srcPath, $dstPath )
+ ) {
$this->output( "\tAlready have $srcPathRel.\n" );
continue; // assume already copied...
}
@@ -338,18 +339,42 @@ class CopyFileBackend extends Maintenance {
$skipHash = $this->hasOption( 'skiphash' );
$srcStat = $src->getFileStat( array( 'src' => $sPath ) );
$dPathSha1 = sha1( $dPath );
- $dstStat = isset( $this->statCache[$dPathSha1] )
- ? $this->statCache[$dPathSha1]
- : $dst->getFileStat( array( 'src' => $dPath ) );
- return (
+ if ( $this->statCache !== null ) {
+ // All dst files are already in stat cache
+ $dstStat = isset( $this->statCache[$dPathSha1] )
+ ? $this->statCache[$dPathSha1]
+ : false;
+ } else {
+ $dstStat = $dst->getFileStat( array( 'src' => $dPath ) );
+ }
+ // Initial fast checks to see if files are obviously different
+ $sameFast = (
is_array( $srcStat ) // sanity check that source exists
&& is_array( $dstStat ) // dest exists
&& $srcStat['size'] === $dstStat['size']
- && ( !$skipHash || $srcStat['mtime'] <= $dstStat['mtime'] )
- && ( $skipHash || $src->getFileSha1Base36( array( 'src' => $sPath, 'latest' => 1 ) )
- === $dst->getFileSha1Base36( array( 'src' => $dPath, 'latest' => 1 ) )
- )
);
+ // More thorough checks against files
+ if ( !$sameFast ) {
+ $same = false; // no need to look farther
+ } elseif ( isset( $srcStat['md5'] ) && isset( $dstStat['md5'] ) ) {
+ // If MD5 was already in the stat info, just use it.
+ // This is useful as many objects stores can return this in object listing,
+ // so we can use it to avoid slow per-file HEADs.
+ $same = ( $srcStat['md5'] === $dstStat['md5'] );
+ } elseif ( $skipHash ) {
+ // This mode is good for copying to a backup location or resyncing clone
+ // backends in FileBackendMultiWrite (since they get writes second, they have
+ // higher timestamps). However, when copying the other way, this hits loads of
+ // false positives (possibly 100%) and wastes a bunch of time on GETs/PUTs.
+ $same = ( $srcStat['mtime'] <= $dstStat['mtime'] );
+ } else {
+ // This is the slowest method which does many per-file HEADs (unless an object
+ // store tracks SHA-1 in listings).
+ $same = ( $src->getFileSha1Base36( array( 'src' => $sPath, 'latest' => 1 ) )
+ === $dst->getFileSha1Base36( array( 'src' => $dPath, 'latest' => 1 ) ) );
+ }
+
+ return $same;
}
}
diff --git a/maintenance/copyJobQueue.php b/maintenance/copyJobQueue.php
index e833115b..a9c9547e 100644
--- a/maintenance/copyJobQueue.php
+++ b/maintenance/copyJobQueue.php
@@ -78,19 +78,18 @@ class CopyJobQueue extends Maintenance {
++$total;
$batch[] = $job;
if ( count( $batch ) >= $this->mBatchSize ) {
- if ( $dst->push( $batch ) ) {
- $totalOK += count( $batch );
- }
+ $dst->push( $batch );
+ $totalOK += count( $batch );
$batch = array();
$dst->waitForBackups();
}
}
if ( count( $batch ) ) {
- if ( $dst->push( $batch ) ) {
- $totalOK += count( $batch );
- }
+ $dst->push( $batch );
+ $totalOK += count( $batch );
$dst->waitForBackups();
}
+
return array( $total, $totalOK );
}
}
diff --git a/maintenance/createAndPromote.php b/maintenance/createAndPromote.php
index aa25ee60..79f72542 100644
--- a/maintenance/createAndPromote.php
+++ b/maintenance/createAndPromote.php
@@ -31,13 +31,15 @@ require_once __DIR__ . '/Maintenance.php';
* @ingroup Maintenance
*/
class CreateAndPromote extends Maintenance {
-
- static $permitRoles = array( 'sysop', 'bureaucrat', 'bot' );
+ private static $permitRoles = array( 'sysop', 'bureaucrat', 'bot' );
public function __construct() {
parent::__construct();
$this->mDescription = "Create a new user account and/or grant it additional rights";
- $this->addOption( "force", "If acccount exists already, just grant it rights or change password." );
+ $this->addOption(
+ 'force',
+ 'If acccount exists already, just grant it rights or change password.'
+ );
foreach ( self::$permitRoles as $role ) {
$this->addOption( $role, "Add the account to the {$role} group" );
}
@@ -67,10 +69,14 @@ class CreateAndPromote extends Maintenance {
$inGroups = $user->getGroups();
}
- $promotions = array_diff( array_filter( self::$permitRoles, array( $this, 'hasOption' ) ), $inGroups );
+ $promotions = array_diff(
+ array_filter( self::$permitRoles, array( $this, 'hasOption' ) ),
+ $inGroups
+ );
if ( $exists && !$password && count( $promotions ) === 0 ) {
$this->output( "Account exists and nothing to do.\n" );
+
return;
} elseif ( count( $promotions ) !== 0 ) {
$promoText = "User:{$username} into " . implode( ', ', $promotions ) . "...\n";
diff --git a/maintenance/cssjanus/COPYING b/maintenance/cssjanus/COPYING
deleted file mode 100644
index 3f2c8953..00000000
--- a/maintenance/cssjanus/COPYING
+++ /dev/null
@@ -1,13 +0,0 @@
- Copyright 2008 Google Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/maintenance/cssjanus/LICENSE b/maintenance/cssjanus/LICENSE
deleted file mode 100644
index d6456956..00000000
--- a/maintenance/cssjanus/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/maintenance/cssjanus/README b/maintenance/cssjanus/README
deleted file mode 100644
index 1b96d1a2..00000000
--- a/maintenance/cssjanus/README
+++ /dev/null
@@ -1,91 +0,0 @@
-=CSSJanus=
-
-_Flips CSS from LTR to an RTL orienation and vice-versa_
-
-Author: `Lindsey Simon <elsigh@google.com>`
-
-==Introduction==
-
-CSSJanus is CSS parser utility designed to aid the conversion of a website's
-layout from left-to-right(LTR) to right-to-left(RTL). The script was born out of
-a need to convert CSS for RTL languages when tables are not being used for layout (since tables will automatically reorder TD's in RTL).
-CSSJanus will change most of the obvious CSS property names and their values as
-well as some not-so-obvious ones (cursor, background-position %, etc...).
-The script is designed to offer flexibility to account for cases when you do
-not want to change certain rules which exist to account for bidirectional text
-display bugs, as well as situations where you may or may not want to flip annotations inside of the background url string.
-Note that you can disable CSSJanus from running on an entire class or any
-rule within a class by prepending a /* @noflip */ comment before the rule(s)
-you want CSSJanus to ignore.
-
-CSSJanus itself is not always enough to make a website that works in a LTR
-language context work in a RTL language all the way, but it is a start.
-
-==Getting the code==
-
-View the trunk at:
-
- http://cssjanus.googlecode.com/svn/trunk/
-
-Check out the latest development version anonymously with:
-
-{{{
- $ svn checkout http://cssjanus.googlecode.com/svn/trunk/ cssjanus
-}}}
-
-==Using==
-
-Usage:
- ./cssjanus.py < file.css > file-rtl.css
-Flags:
- --swap_left_right_in_url: Fixes "left"/"right" string within urls.
- Ex: ./cssjanus.py --swap_left_right_in_url < file.css > file_rtl.css
- --swap_ltr_rtl_in_url: Fixes "ltr"/"rtl" string within urls.
- Ex: ./cssjanus.py --swap_ltr_rtl_in_url < file.css > file_rtl.css
-
-If you'd like to make use of the webapp version of cssjanus, you'll need to
-download the Google App Engine SDK
- http://code.google.com/appengine/downloads.html
-and also drop a "django" directory into this directory, with the latest svn
-from django. You should be good to go with that setup. Please let me know
-otherwise.
-
-==Bugs, Patches==
-
-Patches and bug reports are welcome, just please keep the style
-consistent with the original source. If you find a bug, please include a diff
-of cssjanus_test.py with the bug included as a new unit test which fails. It
-will make understanding and fixing the bug easier.
-
-==Todo==
-
-* Include some helpers for some typical bidi text solutions?
-* Aural CSS (azimuth) swapping?
-
-==Contributors==
-
-Additional thanks to Mike Samuel for his work on csslex.py, Andy Perelson for
-his help coding and reviewing, Stephen Zabel for his help with i18n and my sanity,
-and to Eric Meyer for his thoughtful input.
-Thanks to Junyu Wang for the Chinese translation.
-Thanks to Masashi Kawashima for the Japanese translation.
-Thanks to Taaryk Taar and Tariq Al-Omaireeni for an updated Arabic translation.
-Thanks to Jens Meiert for the German translation.
-
-==License==
-
-{{{
- Copyright 2008 Google Inc. All Rights Reserved.
-
- Licensed under the Apache License, Version 2.0 (the 'License');
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an 'AS IS' BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-}}}
diff --git a/maintenance/cssjanus/cssjanus.py b/maintenance/cssjanus/cssjanus.py
deleted file mode 100644
index dd14bd58..00000000
--- a/maintenance/cssjanus/cssjanus.py
+++ /dev/null
@@ -1,574 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2008 Google Inc. All Rights Reserved.
-
-"""Converts a LeftToRight Cascading Style Sheet into a RightToLeft one.
-
- This is a utility script for replacing "left" oriented things in a CSS file
- like float, padding, margin with "right" oriented values.
- It also does the opposite.
- The goal is to be able to conditionally serve one large, cat'd, compiled CSS
- file appropriate for LeftToRight oriented languages and RightToLeft ones.
- This utility will hopefully help your structural layout done in CSS in
- terms of its RTL compatibility. It will not help with some of the more
- complicated bidirectional text issues.
-"""
-
-__author__ = 'elsigh@google.com (Lindsey Simon)'
-__version__ = '0.1'
-
-import logging
-import re
-import sys
-import getopt
-import os
-
-import csslex
-
-logging.getLogger().setLevel(logging.INFO)
-
-# Global for the command line flags.
-SWAP_LTR_RTL_IN_URL_DEFAULT = False
-SWAP_LEFT_RIGHT_IN_URL_DEFAULT = False
-FLAGS = {'swap_ltr_rtl_in_url': SWAP_LTR_RTL_IN_URL_DEFAULT,
- 'swap_left_right_in_url': SWAP_LEFT_RIGHT_IN_URL_DEFAULT}
-
-# Generic token delimiter character.
-TOKEN_DELIMITER = '~'
-
-# This is a temporary match token we use when swapping strings.
-TMP_TOKEN = '%sTMP%s' % (TOKEN_DELIMITER, TOKEN_DELIMITER)
-
-# Token to be used for joining lines.
-TOKEN_LINES = '%sJ%s' % (TOKEN_DELIMITER, TOKEN_DELIMITER)
-
-# Global constant text strings for CSS value matches.
-LTR = 'ltr'
-RTL = 'rtl'
-LEFT = 'left'
-RIGHT = 'right'
-
-# This is a lookbehind match to ensure that we don't replace instances
-# of our string token (left, rtl, etc...) if there's a letter in front of it.
-# Specifically, this prevents replacements like 'background: url(bright.png)'.
-LOOKBEHIND_NOT_LETTER = r'(?<![a-zA-Z])'
-
-# This is a lookahead match to make sure we don't replace left and right
-# in actual classnames, so that we don't break the HTML/CSS dependencies.
-# Read literally, it says ignore cases where the word left, for instance, is
-# directly followed by valid classname characters and a curly brace.
-# ex: .column-left {float: left} will become .column-left {float: right}
-LOOKAHEAD_NOT_OPEN_BRACE = (r'(?!(?:%s|%s|%s|#|\:|\.|\,|\+|>)*?{)' %
- (csslex.NMCHAR, TOKEN_LINES, csslex.SPACE))
-
-
-# These two lookaheads are to test whether or not we are within a
-# background: url(HERE) situation.
-# Ref: http://www.w3.org/TR/CSS21/syndata.html#uri
-VALID_AFTER_URI_CHARS = r'[\'\"]?%s' % csslex.WHITESPACE
-LOOKAHEAD_NOT_CLOSING_PAREN = r'(?!%s?%s\))' % (csslex.URL_CHARS,
- VALID_AFTER_URI_CHARS)
-LOOKAHEAD_FOR_CLOSING_PAREN = r'(?=%s?%s\))' % (csslex.URL_CHARS,
- VALID_AFTER_URI_CHARS)
-
-# Compile a regex to swap left and right values in 4 part notations.
-# We need to match negatives and decimal numeric values.
-# ex. 'margin: .25em -2px 3px 0' becomes 'margin: .25em 0 3px -2px'.
-POSSIBLY_NEGATIVE_QUANTITY = r'((?:-?%s)|(?:inherit|auto))' % csslex.QUANTITY
-POSSIBLY_NEGATIVE_QUANTITY_SPACE = r'%s%s%s' % (POSSIBLY_NEGATIVE_QUANTITY,
- csslex.SPACE,
- csslex.WHITESPACE)
-FOUR_NOTATION_QUANTITY_RE = re.compile(r'%s%s%s%s' %
- (POSSIBLY_NEGATIVE_QUANTITY_SPACE,
- POSSIBLY_NEGATIVE_QUANTITY_SPACE,
- POSSIBLY_NEGATIVE_QUANTITY_SPACE,
- POSSIBLY_NEGATIVE_QUANTITY),
- re.I)
-COLOR = r'(%s|%s)' % (csslex.NAME, csslex.HASH)
-COLOR_SPACE = r'%s%s' % (COLOR, csslex.SPACE)
-FOUR_NOTATION_COLOR_RE = re.compile(r'(-color%s:%s)%s%s%s(%s)' %
- (csslex.WHITESPACE,
- csslex.WHITESPACE,
- COLOR_SPACE,
- COLOR_SPACE,
- COLOR_SPACE,
- COLOR),
- re.I)
-
-# Compile the cursor resize regexes
-CURSOR_EAST_RE = re.compile(LOOKBEHIND_NOT_LETTER + '([ns]?)e-resize')
-CURSOR_WEST_RE = re.compile(LOOKBEHIND_NOT_LETTER + '([ns]?)w-resize')
-
-# Matches the condition where we need to replace the horizontal component
-# of a background-position value when expressed in horizontal percentage.
-# Had to make two regexes because in the case of position-x there is only
-# one quantity, and otherwise we don't want to match and change cases with only
-# one quantity.
-BG_HORIZONTAL_PERCENTAGE_RE = re.compile(r'background(-position)?(%s:%s)'
- '([^%%]*?)(%s)%%'
- '(%s(?:%s|%s))' % (csslex.WHITESPACE,
- csslex.WHITESPACE,
- csslex.NUM,
- csslex.WHITESPACE,
- csslex.QUANTITY,
- csslex.IDENT))
-
-BG_HORIZONTAL_PERCENTAGE_X_RE = re.compile(r'background-position-x(%s:%s)'
- '(%s)%%' % (csslex.WHITESPACE,
- csslex.WHITESPACE,
- csslex.NUM))
-
-# Matches the opening of a body selector.
-BODY_SELECTOR = r'body%s{%s' % (csslex.WHITESPACE, csslex.WHITESPACE)
-
-# Matches anything up until the closing of a selector.
-CHARS_WITHIN_SELECTOR = r'[^\}]*?'
-
-# Matches the direction property in a selector.
-DIRECTION_RE = r'direction%s:%s' % (csslex.WHITESPACE, csslex.WHITESPACE)
-
-# These allow us to swap "ltr" with "rtl" and vice versa ONLY within the
-# body selector and on the same line.
-BODY_DIRECTION_LTR_RE = re.compile(r'(%s)(%s)(%s)(ltr)' %
- (BODY_SELECTOR, CHARS_WITHIN_SELECTOR,
- DIRECTION_RE),
- re.I)
-BODY_DIRECTION_RTL_RE = re.compile(r'(%s)(%s)(%s)(rtl)' %
- (BODY_SELECTOR, CHARS_WITHIN_SELECTOR,
- DIRECTION_RE),
- re.I)
-
-
-# Allows us to swap "direction:ltr" with "direction:rtl" and
-# vice versa anywhere in a line.
-DIRECTION_LTR_RE = re.compile(r'%s(ltr)' % DIRECTION_RE)
-DIRECTION_RTL_RE = re.compile(r'%s(rtl)' % DIRECTION_RE)
-
-# We want to be able to switch left with right and vice versa anywhere
-# we encounter left/right strings, EXCEPT inside the background:url(). The next
-# two regexes are for that purpose. We have alternate IN_URL versions of the
-# regexes compiled in case the user passes the flag that they do
-# actually want to have left and right swapped inside of background:urls.
-LEFT_RE = re.compile('%s(%s)%s%s' % (LOOKBEHIND_NOT_LETTER,
- LEFT,
- LOOKAHEAD_NOT_CLOSING_PAREN,
- LOOKAHEAD_NOT_OPEN_BRACE),
- re.I)
-RIGHT_RE = re.compile('%s(%s)%s%s' % (LOOKBEHIND_NOT_LETTER,
- RIGHT,
- LOOKAHEAD_NOT_CLOSING_PAREN,
- LOOKAHEAD_NOT_OPEN_BRACE),
- re.I)
-LEFT_IN_URL_RE = re.compile('%s(%s)%s' % (LOOKBEHIND_NOT_LETTER,
- LEFT,
- LOOKAHEAD_FOR_CLOSING_PAREN),
- re.I)
-RIGHT_IN_URL_RE = re.compile('%s(%s)%s' % (LOOKBEHIND_NOT_LETTER,
- RIGHT,
- LOOKAHEAD_FOR_CLOSING_PAREN),
- re.I)
-LTR_IN_URL_RE = re.compile('%s(%s)%s' % (LOOKBEHIND_NOT_LETTER,
- LTR,
- LOOKAHEAD_FOR_CLOSING_PAREN),
- re.I)
-RTL_IN_URL_RE = re.compile('%s(%s)%s' % (LOOKBEHIND_NOT_LETTER,
- RTL,
- LOOKAHEAD_FOR_CLOSING_PAREN),
- re.I)
-
-COMMENT_RE = re.compile('(%s)' % csslex.COMMENT, re.I)
-
-NOFLIP_TOKEN = r'\@noflip'
-# The NOFLIP_TOKEN inside of a comment. For now, this requires that comments
-# be in the input, which means users of a css compiler would have to run
-# this script first if they want this functionality.
-NOFLIP_ANNOTATION = r'/\*%s%s%s\*/' % (csslex.WHITESPACE,
- NOFLIP_TOKEN,
- csslex. WHITESPACE)
-
-# After a NOFLIP_ANNOTATION, and within a class selector, we want to be able
-# to set aside a single rule not to be flipped. We can do this by matching
-# our NOFLIP annotation and then using a lookahead to make sure there is not
-# an opening brace before the match.
-NOFLIP_SINGLE_RE = re.compile(r'(%s%s[^;}]+;?)' % (NOFLIP_ANNOTATION,
- LOOKAHEAD_NOT_OPEN_BRACE),
- re.I)
-
-# After a NOFLIP_ANNOTATION, we want to grab anything up until the next } which
-# means the entire following class block. This will prevent all of its
-# declarations from being flipped.
-NOFLIP_CLASS_RE = re.compile(r'(%s%s})' % (NOFLIP_ANNOTATION,
- CHARS_WITHIN_SELECTOR),
- re.I)
-
-
-class Tokenizer:
- """Replaces any CSS comments with string tokens and vice versa."""
-
- def __init__(self, token_re, token_string):
- """Constructor for the Tokenizer.
-
- Args:
- token_re: A regex for the string to be replace by a token.
- token_string: The string to put between token delimiters when tokenizing.
- """
- logging.debug('Tokenizer::init token_string=%s' % token_string)
- self.token_re = token_re
- self.token_string = token_string
- self.originals = []
-
- def Tokenize(self, line):
- """Replaces any string matching token_re in line with string tokens.
-
- By passing a function as an argument to the re.sub line below, we bypass
- the usual rule where re.sub will only replace the left-most occurrence of
- a match by calling the passed in function for each occurrence.
-
- Args:
- line: A line to replace token_re matches in.
-
- Returns:
- line: A line with token_re matches tokenized.
- """
- line = self.token_re.sub(self.TokenizeMatches, line)
- logging.debug('Tokenizer::Tokenize returns: %s' % line)
- return line
-
- def DeTokenize(self, line):
- """Replaces tokens with the original string.
-
- Args:
- line: A line with tokens.
-
- Returns:
- line with any tokens replaced by the original string.
- """
-
- # Put all of the comments back in by their comment token.
- for i, original in enumerate(self.originals):
- token = '%s%s_%s%s' % (TOKEN_DELIMITER, self.token_string, i + 1,
- TOKEN_DELIMITER)
- line = line.replace(token, original)
- logging.debug('Tokenizer::DeTokenize i:%s w/%s' % (i, token))
- logging.debug('Tokenizer::DeTokenize returns: %s' % line)
- return line
-
- def TokenizeMatches(self, m):
- """Replaces matches with tokens and stores the originals.
-
- Args:
- m: A match object.
-
- Returns:
- A string token which replaces the CSS comment.
- """
- logging.debug('Tokenizer::TokenizeMatches %s' % m.group(1))
- self.originals.append(m.group(1))
- return '%s%s_%s%s' % (TOKEN_DELIMITER,
- self.token_string,
- len(self.originals),
- TOKEN_DELIMITER)
-
-
-def FixBodyDirectionLtrAndRtl(line):
- """Replaces ltr with rtl and vice versa ONLY in the body direction.
-
- Args:
- line: A string to replace instances of ltr with rtl.
- Returns:
- line with direction: ltr and direction: rtl swapped only in body selector.
- line = FixBodyDirectionLtrAndRtl('body { direction:ltr }')
- line will now be 'body { direction:rtl }'.
- """
-
- line = BODY_DIRECTION_LTR_RE.sub('\\1\\2\\3%s' % TMP_TOKEN, line)
- line = BODY_DIRECTION_RTL_RE.sub('\\1\\2\\3%s' % LTR, line)
- line = line.replace(TMP_TOKEN, RTL)
- logging.debug('FixBodyDirectionLtrAndRtl returns: %s' % line)
- return line
-
-
-def FixLeftAndRight(line):
- """Replaces left with right and vice versa in line.
-
- Args:
- line: A string in which to perform the replacement.
-
- Returns:
- line with left and right swapped. For example:
- line = FixLeftAndRight('padding-left: 2px; margin-right: 1px;')
- line will now be 'padding-right: 2px; margin-left: 1px;'.
- """
-
- line = LEFT_RE.sub(TMP_TOKEN, line)
- line = RIGHT_RE.sub(LEFT, line)
- line = line.replace(TMP_TOKEN, RIGHT)
- logging.debug('FixLeftAndRight returns: %s' % line)
- return line
-
-
-def FixLeftAndRightInUrl(line):
- """Replaces left with right and vice versa ONLY within background urls.
-
- Args:
- line: A string in which to replace left with right and vice versa.
-
- Returns:
- line with left and right swapped in the url string. For example:
- line = FixLeftAndRightInUrl('background:url(right.png)')
- line will now be 'background:url(left.png)'.
- """
-
- line = LEFT_IN_URL_RE.sub(TMP_TOKEN, line)
- line = RIGHT_IN_URL_RE.sub(LEFT, line)
- line = line.replace(TMP_TOKEN, RIGHT)
- logging.debug('FixLeftAndRightInUrl returns: %s' % line)
- return line
-
-
-def FixLtrAndRtlInUrl(line):
- """Replaces ltr with rtl and vice versa ONLY within background urls.
-
- Args:
- line: A string in which to replace ltr with rtl and vice versa.
-
- Returns:
- line with left and right swapped. For example:
- line = FixLtrAndRtlInUrl('background:url(rtl.png)')
- line will now be 'background:url(ltr.png)'.
- """
-
- line = LTR_IN_URL_RE.sub(TMP_TOKEN, line)
- line = RTL_IN_URL_RE.sub(LTR, line)
- line = line.replace(TMP_TOKEN, RTL)
- logging.debug('FixLtrAndRtlInUrl returns: %s' % line)
- return line
-
-
-def FixCursorProperties(line):
- """Fixes directional CSS cursor properties.
-
- Args:
- line: A string to fix CSS cursor properties in.
-
- Returns:
- line reformatted with the cursor properties substituted. For example:
- line = FixCursorProperties('cursor: ne-resize')
- line will now be 'cursor: nw-resize'.
- """
-
- line = CURSOR_EAST_RE.sub('\\1' + TMP_TOKEN, line)
- line = CURSOR_WEST_RE.sub('\\1e-resize', line)
- line = line.replace(TMP_TOKEN, 'w-resize')
- logging.debug('FixCursorProperties returns: %s' % line)
- return line
-
-
-def FixFourPartNotation(line):
- """Fixes the second and fourth positions in 4 part CSS notation.
-
- Args:
- line: A string to fix 4 part CSS notation in.
-
- Returns:
- line reformatted with the 4 part notations swapped. For example:
- line = FixFourPartNotation('padding: 1px 2px 3px 4px')
- line will now be 'padding: 1px 4px 3px 2px'.
- """
- line = FOUR_NOTATION_QUANTITY_RE.sub('\\1 \\4 \\3 \\2', line)
- line = FOUR_NOTATION_COLOR_RE.sub('\\1\\2 \\5 \\4 \\3', line)
- logging.debug('FixFourPartNotation returns: %s' % line)
- return line
-
-
-def FixBackgroundPosition(line):
- """Fixes horizontal background percentage values in line.
-
- Args:
- line: A string to fix horizontal background position values in.
-
- Returns:
- line reformatted with the 4 part notations swapped.
- """
- line = BG_HORIZONTAL_PERCENTAGE_RE.sub(CalculateNewBackgroundPosition, line)
- line = BG_HORIZONTAL_PERCENTAGE_X_RE.sub(CalculateNewBackgroundPositionX,
- line)
- logging.debug('FixBackgroundPosition returns: %s' % line)
- return line
-
-
-def CalculateNewBackgroundPosition(m):
- """Fixes horizontal background-position percentages.
-
- This function should be used as an argument to re.sub since it needs to
- perform replacement specific calculations.
-
- Args:
- m: A match object.
-
- Returns:
- A string with the horizontal background position percentage fixed.
- BG_HORIZONTAL_PERCENTAGE_RE.sub(FixBackgroundPosition,
- 'background-position: 75% 50%')
- will return 'background-position: 25% 50%'.
- """
-
- # The flipped value is the offset from 100%
- new_x = str(100-int(m.group(4)))
-
- # Since m.group(1) may very well be None type and we need a string..
- if m.group(1):
- position_string = m.group(1)
- else:
- position_string = ''
-
- return 'background%s%s%s%s%%%s' % (position_string, m.group(2), m.group(3),
- new_x, m.group(5))
-
-
-def CalculateNewBackgroundPositionX(m):
- """Fixes percent based background-position-x.
-
- This function should be used as an argument to re.sub since it needs to
- perform replacement specific calculations.
-
- Args:
- m: A match object.
-
- Returns:
- A string with the background-position-x percentage fixed.
- BG_HORIZONTAL_PERCENTAGE_X_RE.sub(CalculateNewBackgroundPosition,
- 'background-position-x: 75%')
- will return 'background-position-x: 25%'.
- """
-
- # The flipped value is the offset from 100%
- new_x = str(100-int(m.group(2)))
-
- return 'background-position-x%s%s%%' % (m.group(1), new_x)
-
-
-def ChangeLeftToRightToLeft(lines,
- swap_ltr_rtl_in_url=None,
- swap_left_right_in_url=None):
- """Turns lines into a stream and runs the fixing functions against it.
-
- Args:
- lines: An list of CSS lines.
- swap_ltr_rtl_in_url: Overrides this flag if param is set.
- swap_left_right_in_url: Overrides this flag if param is set.
-
- Returns:
- The same lines, but with left and right fixes.
- """
-
- global FLAGS
-
- # Possibly override flags with params.
- logging.debug('ChangeLeftToRightToLeft swap_ltr_rtl_in_url=%s, '
- 'swap_left_right_in_url=%s' % (swap_ltr_rtl_in_url,
- swap_left_right_in_url))
- if swap_ltr_rtl_in_url is None:
- swap_ltr_rtl_in_url = FLAGS['swap_ltr_rtl_in_url']
- if swap_left_right_in_url is None:
- swap_left_right_in_url = FLAGS['swap_left_right_in_url']
-
- # Turns the array of lines into a single line stream.
- logging.debug('LINES COUNT: %s' % len(lines))
- line = TOKEN_LINES.join(lines)
-
- # Tokenize any single line rules with the /* noflip */ annotation.
- noflip_single_tokenizer = Tokenizer(NOFLIP_SINGLE_RE, 'NOFLIP_SINGLE')
- line = noflip_single_tokenizer.Tokenize(line)
-
- # Tokenize any class rules with the /* noflip */ annotation.
- noflip_class_tokenizer = Tokenizer(NOFLIP_CLASS_RE, 'NOFLIP_CLASS')
- line = noflip_class_tokenizer.Tokenize(line)
-
- # Tokenize the comments so we can preserve them through the changes.
- comment_tokenizer = Tokenizer(COMMENT_RE, 'C')
- line = comment_tokenizer.Tokenize(line)
-
- # Here starteth the various left/right orientation fixes.
- line = FixBodyDirectionLtrAndRtl(line)
-
- if swap_left_right_in_url:
- line = FixLeftAndRightInUrl(line)
-
- if swap_ltr_rtl_in_url:
- line = FixLtrAndRtlInUrl(line)
-
- line = FixLeftAndRight(line)
- line = FixCursorProperties(line)
- line = FixFourPartNotation(line)
- line = FixBackgroundPosition(line)
-
- # DeTokenize the single line noflips.
- line = noflip_single_tokenizer.DeTokenize(line)
-
- # DeTokenize the class-level noflips.
- line = noflip_class_tokenizer.DeTokenize(line)
-
- # DeTokenize the comments.
- line = comment_tokenizer.DeTokenize(line)
-
- # Rejoin the lines back together.
- lines = line.split(TOKEN_LINES)
-
- return lines
-
-def usage():
- """Prints out usage information."""
-
- print 'Usage:'
- print ' ./cssjanus.py < file.css > file-rtl.css'
- print 'Flags:'
- print ' --swap_left_right_in_url: Fixes "left"/"right" string within urls.'
- print ' Ex: ./cssjanus.py --swap_left_right_in_url < file.css > file_rtl.css'
- print ' --swap_ltr_rtl_in_url: Fixes "ltr"/"rtl" string within urls.'
- print ' Ex: ./cssjanus --swap_ltr_rtl_in_url < file.css > file_rtl.css'
-
-def setflags(opts):
- """Parse the passed in command line arguments and set the FLAGS global.
-
- Args:
- opts: getopt iterable intercepted from argv.
- """
-
- global FLAGS
-
- # Parse the arguments.
- for opt, arg in opts:
- logging.debug('opt: %s, arg: %s' % (opt, arg))
- if opt in ("-h", "--help"):
- usage()
- sys.exit()
- elif opt in ("-d", "--debug"):
- logging.getLogger().setLevel(logging.DEBUG)
- elif opt == '--swap_ltr_rtl_in_url':
- FLAGS['swap_ltr_rtl_in_url'] = True
- elif opt == '--swap_left_right_in_url':
- FLAGS['swap_left_right_in_url'] = True
-
-
-def main(argv):
- """Sends stdin lines to ChangeLeftToRightToLeft and writes to stdout."""
-
- # Define the flags.
- try:
- opts, args = getopt.getopt(argv, 'hd', ['help', 'debug',
- 'swap_left_right_in_url',
- 'swap_ltr_rtl_in_url'])
- except getopt.GetoptError:
- usage()
- sys.exit(2)
-
- # Parse and set the flags.
- setflags(opts)
-
- # Call the main routine with all our functionality.
- fixed_lines = ChangeLeftToRightToLeft(sys.stdin.readlines())
- sys.stdout.write(''.join(fixed_lines))
-
-if __name__ == '__main__':
- main(sys.argv[1:])
diff --git a/maintenance/cssjanus/csslex.py b/maintenance/cssjanus/csslex.py
deleted file mode 100644
index 1fc7304e..00000000
--- a/maintenance/cssjanus/csslex.py
+++ /dev/null
@@ -1,114 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2007 Google Inc. All Rights Reserved.
-
-"""CSS Lexical Grammar rules.
-
-CSS lexical grammar from http://www.w3.org/TR/CSS21/grammar.html
-"""
-
-__author__ = ['elsigh@google.com (Lindsey Simon)',
- 'msamuel@google.com (Mike Samuel)']
-
-# public symbols
-__all__ = [ "NEWLINE", "HEX", "NON_ASCII", "UNICODE", "ESCAPE", "NMSTART", "NMCHAR", "STRING1", "STRING2", "IDENT", "NAME", "HASH", "NUM", "STRING", "URL", "SPACE", "WHITESPACE", "COMMENT", "QUANTITY", "PUNC" ]
-
-# The comments below are mostly copied verbatim from the grammar.
-
-# "@import" {return IMPORT_SYM;}
-# "@page" {return PAGE_SYM;}
-# "@media" {return MEDIA_SYM;}
-# "@charset" {return CHARSET_SYM;}
-KEYWORD = r'(?:\@(?:import|page|media|charset))'
-
-# nl \n|\r\n|\r|\f ; a newline
-NEWLINE = r'\n|\r\n|\r|\f'
-
-# h [0-9a-f] ; a hexadecimal digit
-HEX = r'[0-9a-f]'
-
-# nonascii [\200-\377]
-NON_ASCII = r'[\200-\377]'
-
-# unicode \\{h}{1,6}(\r\n|[ \t\r\n\f])?
-UNICODE = r'(?:(?:\\' + HEX + r'{1,6})(?:\r\n|[ \t\r\n\f])?)'
-
-# escape {unicode}|\\[^\r\n\f0-9a-f]
-ESCAPE = r'(?:' + UNICODE + r'|\\[^\r\n\f0-9a-f])'
-
-# nmstart [_a-z]|{nonascii}|{escape}
-NMSTART = r'(?:[_a-z]|' + NON_ASCII + r'|' + ESCAPE + r')'
-
-# nmchar [_a-z0-9-]|{nonascii}|{escape}
-NMCHAR = r'(?:[_a-z0-9-]|' + NON_ASCII + r'|' + ESCAPE + r')'
-
-# ident -?{nmstart}{nmchar}*
-IDENT = r'-?' + NMSTART + NMCHAR + '*'
-
-# name {nmchar}+
-NAME = NMCHAR + r'+'
-
-# hash
-HASH = r'#' + NAME
-
-# string1 \"([^\n\r\f\\"]|\\{nl}|{escape})*\" ; "string"
-STRING1 = r'"(?:[^\"\\]|\\.)*"'
-
-# string2 \'([^\n\r\f\\']|\\{nl}|{escape})*\' ; 'string'
-STRING2 = r"'(?:[^\'\\]|\\.)*'"
-
-# string {string1}|{string2}
-STRING = '(?:' + STRING1 + r'|' + STRING2 + ')'
-
-# num [0-9]+|[0-9]*"."[0-9]+
-NUM = r'(?:[0-9]*\.[0-9]+|[0-9]+)'
-
-# s [ \t\r\n\f]
-SPACE = r'[ \t\r\n\f]'
-
-# w {s}*
-WHITESPACE = '(?:' + SPACE + r'*)'
-
-# url special chars
-URL_SPECIAL_CHARS = r'[!#$%&*-~]'
-
-# url chars ({url_special_chars}|{nonascii}|{escape})*
-URL_CHARS = r'(?:%s|%s|%s)*' % (URL_SPECIAL_CHARS, NON_ASCII, ESCAPE)
-
-# url
-URL = r'url\(%s(%s|%s)%s\)' % (WHITESPACE, STRING, URL_CHARS, WHITESPACE)
-
-# comments
-# see http://www.w3.org/TR/CSS21/grammar.html
-COMMENT = r'/\*[^*]*\*+([^/*][^*]*\*+)*/'
-
-# {E}{M} {return EMS;}
-# {E}{X} {return EXS;}
-# {P}{X} {return LENGTH;}
-# {C}{M} {return LENGTH;}
-# {M}{M} {return LENGTH;}
-# {I}{N} {return LENGTH;}
-# {P}{T} {return LENGTH;}
-# {P}{C} {return LENGTH;}
-# {D}{E}{G} {return ANGLE;}
-# {R}{A}{D} {return ANGLE;}
-# {G}{R}{A}{D} {return ANGLE;}
-# {M}{S} {return TIME;}
-# {S} {return TIME;}
-# {H}{Z} {return FREQ;}
-# {K}{H}{Z} {return FREQ;}
-# % {return PERCENTAGE;}
-UNIT = r'(?:em|ex|px|cm|mm|in|pt|pc|deg|rad|grad|ms|s|hz|khz|%)'
-
-# {num}{UNIT|IDENT} {return NUMBER;}
-QUANTITY = '%s(?:%s%s|%s)?' % (NUM, WHITESPACE, UNIT, IDENT)
-
-# "<!--" {return CDO;}
-# "-->" {return CDC;}
-# "~=" {return INCLUDES;}
-# "|=" {return DASHMATCH;}
-# {w}"{" {return LBRACE;}
-# {w}"+" {return PLUS;}
-# {w}">" {return GREATER;}
-# {w}"," {return COMMA;}
-PUNC = r'<!--|-->|~=|\|=|[\{\+>,:;]'
diff --git a/maintenance/deleteArchivedFiles.inc b/maintenance/deleteArchivedFiles.inc
index d58e9a40..0c0b34a3 100644
--- a/maintenance/deleteArchivedFiles.inc
+++ b/maintenance/deleteArchivedFiles.inc
@@ -39,6 +39,10 @@ class DeleteArchivedFilesImplementation {
$count = 0;
foreach ( $res as $row ) {
$key = $row->fa_storage_key;
+ if ( !strlen( $key ) ) {
+ $output->handleOutput( "Entry with ID {$row->fa_id} has empty key, skipping\n" );
+ continue;
+ }
$group = $row->fa_storage_group;
$id = $row->fa_id;
$path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key;
@@ -49,9 +53,13 @@ class DeleteArchivedFilesImplementation {
$sha1 = LocalRepo::getHashFromKey( $key );
}
// Check if the file is used anywhere...
- $inuse = $dbw->selectField( 'oldimage', '1',
- array( 'oi_sha1' => $sha1,
- 'oi_deleted & ' . File::DELETED_FILE => File::DELETED_FILE ),
+ $inuse = $dbw->selectField(
+ 'oldimage',
+ '1',
+ array(
+ 'oi_sha1' => $sha1,
+ 'oi_deleted & ' . File::DELETED_FILE => File::DELETED_FILE
+ ),
__METHOD__,
array( 'FOR UPDATE' )
);
diff --git a/maintenance/deleteArchivedFiles.php b/maintenance/deleteArchivedFiles.php
index ad7b54d0..286b1f24 100644
--- a/maintenance/deleteArchivedFiles.php
+++ b/maintenance/deleteArchivedFiles.php
@@ -47,6 +47,7 @@ class DeleteArchivedFiles extends Maintenance {
public function execute() {
if ( !$this->hasOption( 'delete' ) ) {
$this->output( "Use --delete to actually confirm this script\n" );
+
return;
}
$force = $this->hasOption( 'force' );
diff --git a/maintenance/deleteArchivedRevisions.inc b/maintenance/deleteArchivedRevisions.inc
index dd8e3dd4..ed620ee3 100644
--- a/maintenance/deleteArchivedRevisions.inc
+++ b/maintenance/deleteArchivedRevisions.inc
@@ -30,8 +30,7 @@ class DeleteArchivedRevisionsImplementation {
/**
* Perform the delete on archived revisions.
-
- * @param $maint Object An object (typically of class Maintenance)
+ * @param object $maint An object (typically of class Maintenance)
* that implements two methods: handleOutput() and
* purgeRedundantText(). See Maintenance for a description of
* those methods.
diff --git a/maintenance/deleteArchivedRevisions.php b/maintenance/deleteArchivedRevisions.php
index ffd581c1..30883ba4 100644
--- a/maintenance/deleteArchivedRevisions.php
+++ b/maintenance/deleteArchivedRevisions.php
@@ -36,7 +36,8 @@ require_once __DIR__ . '/deleteArchivedRevisions.inc';
class DeleteArchivedRevisions extends Maintenance {
public function __construct() {
parent::__construct();
- $this->mDescription = "Deletes all archived revisions\nThese revisions will no longer be restorable";
+ $this->mDescription =
+ "Deletes all archived revisions\nThese revisions will no longer be restorable";
$this->addOption( 'delete', 'Performs the deletion' );
}
@@ -53,7 +54,8 @@ class DeleteArchivedRevisions extends Maintenance {
$dbw = wfGetDB( DB_MASTER );
$res = $dbw->selectRow( 'archive', 'COUNT(*) as count', array(), __FUNCTION__ );
$this->output( "Found {$res->count} revisions to delete.\n" );
- $this->output( "Please run the script again with the --delete option to really delete the revisions.\n" );
+ $this->output( "Please run the script again with the --delete option "
+ . "to really delete the revisions.\n" );
}
}
}
diff --git a/maintenance/deleteBatch.php b/maintenance/deleteBatch.php
index c1cc03cd..93507b34 100644
--- a/maintenance/deleteBatch.php
+++ b/maintenance/deleteBatch.php
@@ -3,11 +3,11 @@
* Deletes a batch of pages.
* Usage: php deleteBatch.php [-u <user>] [-r <reason>] [-i <interval>] [listfile]
* where
- * [listfile] is a file where each line contains the title of a page to be
- * deleted, standard input is used if listfile is not given.
- * <user> is the username
- * <reason> is the delete reason
- * <interval> is the number of seconds to sleep for after each delete
+ * [listfile] is a file where each line contains the title of a page to be
+ * deleted, standard input is used if listfile is not given.
+ * <user> is the username
+ * <reason> is the delete reason
+ * <interval> is the number of seconds to sleep for after each delete
*
* 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
@@ -79,7 +79,9 @@ class DeleteBatch extends Maintenance {
$dbw = wfGetDB( DB_MASTER );
# Handle each entry
+ // @codingStandardsIgnoreStart Ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
for ( $linenum = 1; !feof( $file ); $linenum++ ) {
+ // @codingStandardsIgnoreEnd
$line = trim( fgets( $file ) );
if ( $line == '' ) {
continue;
@@ -97,7 +99,7 @@ class DeleteBatch extends Maintenance {
$this->output( $title->getPrefixedText() );
$dbw->begin( __METHOD__ );
if ( $title->getNamespace() == NS_FILE ) {
- $img = wfFindFile( $title );
+ $img = wfFindFile( $title, array( 'ignoreRedirect' => true ) );
if ( $img && $img->isLocal() && !$img->delete( $reason ) ) {
$this->output( " FAILED to delete associated file... " );
}
diff --git a/maintenance/deleteDefaultMessages.php b/maintenance/deleteDefaultMessages.php
index 7d8c80e4..5aeeb8e1 100644
--- a/maintenance/deleteDefaultMessages.php
+++ b/maintenance/deleteDefaultMessages.php
@@ -34,7 +34,7 @@ class DeleteDefaultMessages extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Deletes all pages in the MediaWiki namespace" .
- " which were last edited by \"MediaWiki default\"";
+ " which were last edited by \"MediaWiki default\"";
}
public function execute() {
@@ -54,6 +54,7 @@ class DeleteDefaultMessages extends Maintenance {
if ( $dbr->numRows( $res ) == 0 ) {
# No more messages left
$this->output( "done.\n" );
+
return;
}
diff --git a/maintenance/deleteEqualMessages.php b/maintenance/deleteEqualMessages.php
index 81758913..dbe96982 100644
--- a/maintenance/deleteEqualMessages.php
+++ b/maintenance/deleteEqualMessages.php
@@ -30,15 +30,18 @@ require_once __DIR__ . '/Maintenance.php';
class DeleteEqualMessages extends Maintenance {
public function __construct() {
parent::__construct();
- $this->mDescription = "Deletes all pages in the MediaWiki namespace that are equal to the default message";
+ $this->mDescription = 'Deletes all pages in the MediaWiki namespace that are equal to '
+ . 'the default message';
$this->addOption( 'delete', 'Actually delete the pages (default: dry run)' );
$this->addOption( 'delete-talk', 'Don\'t leave orphaned talk pages behind during deletion' );
- $this->addOption( 'lang-code', 'Check for subpages of this language code (default: root page against content language). ' .
- 'Use value "*" to run for all mwfile language code subpages (including the base pages that override content language).', false, true );
+ $this->addOption( 'lang-code', 'Check for subpages of this language code (default: root '
+ . 'page against content language). Use value "*" to run for all mwfile language code '
+ . 'subpages (including the base pages that override content language).', false, true );
}
/**
* @param string|bool $langCode See --lang-code option.
+ * @param array &$messageInfo
*/
protected function fetchMessageInfo( $langCode, array &$messageInfo ) {
global $wgContLang;
@@ -59,7 +62,8 @@ class DeleteEqualMessages extends Maintenance {
// Normalise message names for NS_MEDIAWIKI page_title
$messageNames = array_map( array( $wgContLang, 'ucfirst' ), $messageNames );
- $statuses = AllmessagesTablePager::getCustomisedStatuses( $messageNames, $langCode, $nonContLang );
+ $statuses = AllMessagesTablePager::getCustomisedStatuses(
+ $messageNames, $langCode, $nonContLang );
// getCustomisedStatuses is stripping the sub page from the page titles, add it back
$titleSuffix = $nonContLang ? "/$langCode" : '';
@@ -130,11 +134,14 @@ class DeleteEqualMessages extends Maintenance {
if ( $messageInfo['equalPages'] === 0 ) {
// No more equal messages left
$this->output( "\ndone.\n" );
+
return;
}
- $this->output( "\n{$messageInfo['relevantPages']} pages in the MediaWiki namespace override messages." );
- $this->output( "\n{$messageInfo['equalPages']} pages are equal to the default message (+ {$messageInfo['equalPagesTalks']} talk pages).\n" );
+ $this->output( "\n{$messageInfo['relevantPages']} pages in the MediaWiki namespace "
+ . "override messages." );
+ $this->output( "\n{$messageInfo['equalPages']} pages are equal to the default message "
+ . "(+ {$messageInfo['equalPagesTalks']} talk pages).\n" );
if ( !$doDelete ) {
$list = '';
@@ -151,6 +158,7 @@ class DeleteEqualMessages extends Maintenance {
$this->output( " (include --delete-talk to also delete the talk pages)" );
}
$this->output( "\n" );
+
return;
}
@@ -170,7 +178,6 @@ class DeleteEqualMessages extends Maintenance {
foreach ( $messageInfo['results'] as $result ) {
wfWaitForSlaves();
$dbw->ping();
- $dbw->begin( __METHOD__ );
$title = Title::makeTitle( NS_MEDIAWIKI, $result['title'] );
$this->output( "\n* [[$title]]" );
$page = WikiPage::factory( $title );
@@ -181,9 +188,9 @@ class DeleteEqualMessages extends Maintenance {
$this->output( "\n* [[$title]]" );
$page = WikiPage::factory( $title );
$error = ''; // Passed by ref
- $page->doDeleteArticle( 'Orphaned talk page of no longer required message', false, 0, false, $error, $user );
+ $page->doDeleteArticle( 'Orphaned talk page of no longer required message',
+ false, 0, false, $error, $user );
}
- $dbw->commit( __METHOD__ );
}
$this->output( "\n\ndone!\n" );
}
diff --git a/maintenance/deleteImageMemcached.php b/maintenance/deleteImageMemcached.php
index 835de352..4799e5e0 100644
--- a/maintenance/deleteImageMemcached.php
+++ b/maintenance/deleteImageMemcached.php
@@ -60,7 +60,12 @@ class DeleteImageCache extends Maintenance {
foreach ( $res as $row ) {
if ( $i % $this->report == 0 ) {
- $this->output( sprintf( "%s: %13s done (%s)\n", wfWikiID(), "$i/$total", wfPercent( $i / $total * 100 ) ) );
+ $this->output( sprintf(
+ "%s: %13s done (%s)\n",
+ wfWikiID(),
+ "$i/$total",
+ wfPercent( $i / $total * 100 )
+ ) );
}
$md5 = md5( $row->img_name );
$wgMemc->delete( wfMemcKey( 'Image', $md5 ) );
@@ -75,6 +80,7 @@ class DeleteImageCache extends Maintenance {
private function getImageCount() {
$dbr = wfGetDB( DB_SLAVE );
+
return $dbr->selectField( 'image', 'COUNT(*)', array(), __METHOD__ );
}
}
diff --git a/maintenance/deleteOrphanedRevisions.php b/maintenance/deleteOrphanedRevisions.php
index f0a96928..7f1ffe41 100644
--- a/maintenance/deleteOrphanedRevisions.php
+++ b/maintenance/deleteOrphanedRevisions.php
@@ -49,7 +49,8 @@ class DeleteOrphanedRevisions extends Maintenance {
# Find all the orphaned revisions
$this->output( "Checking for orphaned revisions..." );
- $sql = "SELECT rev_id FROM {$revision} LEFT JOIN {$page} ON rev_page = page_id WHERE page_namespace IS NULL";
+ $sql = "SELECT rev_id FROM {$revision} LEFT JOIN {$page} ON rev_page = page_id "
+ . "WHERE page_namespace IS NULL";
$res = $dbw->query( $sql, 'deleteOrphanedRevisions' );
# Stash 'em all up for deletion (if needed)
@@ -80,8 +81,8 @@ class DeleteOrphanedRevisions extends Maintenance {
* Delete one or more revisions from the database
* Do this inside a transaction
*
- * @param $id Array of revision id values
- * @param $dbw DatabaseBase class (needs to be a master)
+ * @param array $id Array of revision id values
+ * @param DatabaseBase $dbw DatabaseBase class (needs to be a master)
*/
private function deleteRevs( $id, &$dbw ) {
if ( !is_array( $id ) ) {
diff --git a/maintenance/deleteRevision.php b/maintenance/deleteRevision.php
index 6bc0f7cd..818ee360 100644
--- a/maintenance/deleteRevision.php
+++ b/maintenance/deleteRevision.php
@@ -42,41 +42,64 @@ class DeleteRevision extends Maintenance {
}
$this->output( "Deleting revision(s) " . implode( ',', $this->mArgs ) .
- " from " . wfWikiID() . "...\n" );
+ " from " . wfWikiID() . "...\n" );
$dbw = wfGetDB( DB_MASTER );
$affected = 0;
foreach ( $this->mArgs as $revID ) {
$dbw->insertSelect( 'archive', array( 'page', 'revision' ),
array(
- 'ar_namespace' => 'page_namespace',
- 'ar_title' => 'page_title',
- 'ar_page_id' => 'page_id',
- 'ar_comment' => 'rev_comment',
- 'ar_user' => 'rev_user',
- 'ar_user_text' => 'rev_user_text',
- 'ar_timestamp' => 'rev_timestamp',
+ 'ar_namespace' => 'page_namespace',
+ 'ar_title' => 'page_title',
+ 'ar_page_id' => 'page_id',
+ 'ar_comment' => 'rev_comment',
+ 'ar_user' => 'rev_user',
+ 'ar_user_text' => 'rev_user_text',
+ 'ar_timestamp' => 'rev_timestamp',
'ar_minor_edit' => 'rev_minor_edit',
- 'ar_rev_id' => 'rev_id',
- 'ar_text_id' => 'rev_text_id',
- 'ar_deleted' => 'rev_deleted',
- 'ar_len' => 'rev_len',
- ), array(
+ 'ar_rev_id' => 'rev_id',
+ 'ar_text_id' => 'rev_text_id',
+ 'ar_deleted' => 'rev_deleted',
+ 'ar_len' => 'rev_len',
+ ),
+ array(
'rev_id' => $revID,
'page_id = rev_page'
- ), __METHOD__
+ ),
+ __METHOD__
);
if ( !$dbw->affectedRows() ) {
$this->output( "Revision $revID not found\n" );
} else {
$affected += $dbw->affectedRows();
- $pageID = $dbw->selectField( 'revision', 'rev_page', array( 'rev_id' => $revID ), __METHOD__ );
- $pageLatest = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), __METHOD__ );
+ $pageID = $dbw->selectField(
+ 'revision',
+ 'rev_page',
+ array( 'rev_id' => $revID ),
+ __METHOD__
+ );
+ $pageLatest = $dbw->selectField(
+ 'page',
+ 'page_latest',
+ array( 'page_id' => $pageID ),
+ __METHOD__
+ );
$dbw->delete( 'revision', array( 'rev_id' => $revID ) );
if ( $pageLatest == $revID ) {
// Database integrity
- $newLatest = $dbw->selectField( 'revision', 'rev_id', array( 'rev_page' => $pageID ), __METHOD__, array( 'ORDER BY' => 'rev_timestamp DESC' ) );
- $dbw->update( 'page', array( 'page_latest' => $newLatest ), array( 'page_id' => $pageID ), __METHOD__ );
+ $newLatest = $dbw->selectField(
+ 'revision',
+ 'rev_id',
+ array( 'rev_page' => $pageID ),
+ __METHOD__,
+ array( 'ORDER BY' => 'rev_timestamp DESC' )
+ );
+ $dbw->update(
+ 'page',
+ array( 'page_latest' => $newLatest ),
+ array( 'page_id' => $pageID ),
+ __METHOD__
+ );
}
}
}
diff --git a/maintenance/dev/includes/php.sh b/maintenance/dev/includes/php.sh
index 7ce87944..3c5bef0d 100644
--- a/maintenance/dev/includes/php.sh
+++ b/maintenance/dev/includes/php.sh
@@ -4,7 +4,7 @@
# and previous home directory location
# The binary path is returned in $PHP if any
-for binary in $PHP `which php || true` "$DEV/php/bin/php" "$HOME/.mediawiki/php/bin/php" "$HOME/.mwphp/bin/php" ]; do
+for binary in $PHP $(which php || true) "$DEV/php/bin/php" "$HOME/.mediawiki/php/bin/php" "$HOME/.mwphp/bin/php" ]; do
if [ -x "$binary" ]; then
if "$binary" -r 'exit((int)!version_compare(PHP_VERSION, "5.4", ">="));'; then
PHP="$binary"
diff --git a/maintenance/dev/includes/router.php b/maintenance/dev/includes/router.php
index a3cc0ba3..0a65e31e 100644
--- a/maintenance/dev/includes/router.php
+++ b/maintenance/dev/includes/router.php
@@ -59,6 +59,7 @@ if ( $ext == 'php' || $ext == 'php5' ) {
# the php webserver will discard post data and things like login
# will not function in the dev environment.
require $file;
+
return true;
}
$mime = false;
@@ -79,7 +80,7 @@ if ( !$mime ) {
}
}
if ( $mime ) {
- # Use custom handling to serve files with a known mime type
+ # Use custom handling to serve files with a known MIME type
# This way we can serve things like .svg files that the built-in
# PHP webserver doesn't understand.
# ;) Nicely enough we just happen to bundle a mime.types file
@@ -93,6 +94,7 @@ if ( $mime ) {
header( "Content-Length: " . filesize( $file ) );
// Stream that out to the browser
fpassthru( $f );
+
return true;
}
diff --git a/maintenance/dictionary/mediawiki.dic b/maintenance/dictionary/mediawiki.dic
index 164b5b05..df8a34ca 100644
--- a/maintenance/dictionary/mediawiki.dic
+++ b/maintenance/dictionary/mediawiki.dic
@@ -1,10 +1,10 @@
-ænglisc
-ævar
&add
&amp
&bar
+&img
&sim
&url
+&wap
ABNF
API
Aacute
@@ -90,7 +90,6 @@ Edit
Editor
Education
Egrave
-Ehcache
Elig
Email
Empty
@@ -367,6 +366,7 @@ abusive
ac
acad
accel
+acceptbilling
acceptlang
accessdenied
accesskey
@@ -431,6 +431,8 @@ ai
aifc
aiff
aiprop
+airtel
+aisort
ajaxwatch
al
alefsym
@@ -442,6 +444,7 @@ allcategories
alldata
alle
allexamples
+allfileusages
allhidden
allimages
allimit
@@ -459,6 +462,8 @@ allpagesbadtitle
allpagesprefix
allpagesredirect
allpagessubmit
+allpartners
+allredirects
allrev
alltitles
alltransclusions
@@ -471,15 +476,16 @@ alreadyexists
alreadyrolled
alunique
am
+analyticsconfig
anchor
anchorclose
anchorencode
and
andconvert
+andreescu
andtitle
anon
anoneditwarning
-anonlogin
anonnotice
anononly
anonpreviewwarning
@@ -656,6 +662,7 @@ badversion
balancer
balancers
banjar
+barebone
barstein
base
basefont
@@ -685,6 +692,7 @@ bgcolor
bgzip
bidi
bigdelete
+bingbot
binhex
bitdepth
bitfield
@@ -742,11 +750,13 @@ bmwschema
bmysql
bname
bodycontent
+bogo
boldening
bolding
booksources
bool
boolean
+bordercolor
borderhack
bot
botedit
@@ -831,12 +841,14 @@ capitalizeallnouns
captchaid
captchas
captchaword
+carriersnoips
cascade
cascadeable
cascadeon
cascadeprotected
cascadeprotectedwarning
cascading
+cascadinglevels
cascadingness
categories
categories's
@@ -850,6 +862,7 @@ categorypage
categoryviewer
catids
catlinks
+catmsg
catpage
catrope
cattitles
@@ -863,6 +876,7 @@ cedil
ceebc
cellpadding
cellspacing
+cellulant
central
centralauth
centralnotice
@@ -941,7 +955,6 @@ collapsable
collectionsaveascommunitypage
collectionsaveasuserpage
colname
-cologneblue
colonseparator
colorer
colspan
@@ -1070,6 +1083,7 @@ danga
danielc
darr
datalen
+datapath
dataset
datasets
datasize
@@ -1110,6 +1124,7 @@ defaultcontentmodel
defaultmessagetext
defaultmissing
defaultns
+defaultoptions
defaultsort
defaultval
deferr
@@ -1170,6 +1185,7 @@ devangari
devel
df
dflt
+dflts
dhtml
diams
didn
@@ -1197,7 +1213,6 @@ disabled
disabledtranscode
disablemail
disablepp
-disablesuggest
disclaimerpage
diskussion
displayname
@@ -1237,6 +1252,7 @@ domainpart
domainparts
domas
doms
+dont
dotdotcount
dotm
dotsc
@@ -1254,6 +1270,7 @@ dropdown
dump
dumpfm
dupfunc
+dupl
duplicatefiles
duplicatesoffile
dvips
@@ -1314,7 +1331,6 @@ editusercssjs
edituserjs
edoe
egrave
-ehcache
ei
eich
eiinvalidparammix
@@ -1322,7 +1338,9 @@ eimissingparam
eititle
el
elapsedreal
+elastica
elemname
+elems
elink
eltitle
email
@@ -1385,6 +1403,7 @@ epcampus
epcoordinator
epinstructor
eponline
+eqiad
erevoke
errno
error
@@ -1441,6 +1460,7 @@ externaldberror
externaldiff
externaledit
externaleditor
+externalimages
externallinks
externalstore
extet
@@ -1450,6 +1470,7 @@ extlinks
extracts
extradata
extrafields
+extralanglink
extraq
extratags
exturlusage
@@ -1520,6 +1541,7 @@ filepage
filepath
filerenameerror
filerepo
+filerepoinfo
filerevert
filerevisions
files
@@ -1558,6 +1580,7 @@ flagtype
flatlist
flds
float
+flrevs
fmttime
fname
fnof
@@ -1576,6 +1599,7 @@ forcebot
forceditsummary
forceeditsummary
forcelinkupdate
+forcerecursivelinkupdate
forcetoc
forcontent
formaction
@@ -1593,6 +1617,7 @@ found
founder
fr
frac
+frameborder
frameless
framesets
frasl
@@ -1629,12 +1654,15 @@ gadgetcategories
gadgets
gaid
gaifilterredir
+gaifrom
gallerybox
gallerycaption
gallerytext
gapdir
gapfilterredir
+gapfrom
gaplimit
+gapnamespace
gapprefix
garber
gblblock
@@ -1648,8 +1676,10 @@ general
generatexml
generator
geocoordinate
+geodata
geosearch
gerrit
+geshi
getcookie
getenv
getheader
@@ -1686,6 +1716,7 @@ globe
gmail
gmdate
goodtitle
+googlebot
gopher
graymap
grayscale
@@ -1782,8 +1813,8 @@ hit
hitcount
hitcounter
hits
+hlist
hmac
-hmtl
hobby
homelink
hookaborted
@@ -1847,9 +1878,11 @@ ilfrom
ilto
im
image
+imagecolorallocate
imagegetsize
imageinfo
imageinvalidfilename
+imagelimits
imagelinks
imagemagick
imagemaxsize
@@ -1862,6 +1895,7 @@ imagesize
imagetype
imagetypemismatch
imageusage
+imagewhitelistenabled
imagick
imgmultigo
imgmultigoto
@@ -1933,6 +1967,7 @@ interwiki
interwikimap
interwikipage
interwikis
+interwikisearchinfo
interwikisource
intnull
intoken
@@ -1980,6 +2015,8 @@ ipchain
ipedits
iphash
ipinrange
+ipset
+ipsets
ipusers
iquest
irc
@@ -1991,12 +2028,14 @@ isconnected
iscur
isin
isip
+islocal
ismap
isminor
ismodsince
ismulti
isnew
ispermalink
+isroot
isself
isset
istainted
@@ -2024,6 +2063,7 @@ iwltitle
iwprefix
iwtitle
iwurl
+ized
javascript
javascripttest
jbartsh
@@ -2042,6 +2082,7 @@ jslint
jsmimetype
jsminplus
json
+jsonconfig
jsonfm
jsparse
jstext
@@ -2060,6 +2101,7 @@ keyname
keynames
keytype
khash
+kikongo
kludgy
knownnamespace
konqueror
@@ -2075,11 +2117,13 @@ langcode
langcodes
langconversion
langlinks
+langname
langprop
langs
language
languagelinks
languages
+languageselection
languageshtml
laquo
large
@@ -2090,6 +2134,7 @@ lastdot
lastedit
lasteditor
lastedittime
+lastfile
lastlink
lastmod
lastmodifiedat
@@ -2140,6 +2185,8 @@ link
linkarr
linkcolour
linkprefix
+linkprefixcharset
+linkpurge
links
linkstoimage
linktbl
@@ -2175,6 +2222,7 @@ localdayname
localdow
locale
localhour
+localinterwiki
localmonth
localmonthabbrev
localmonthname
@@ -2205,6 +2253,7 @@ loginerror
loginfo
loginlanguagelinks
loginlink
+loginout
loginprompt
loginreqlink
loginreqpagetext
@@ -2241,7 +2290,6 @@ ltitle
ltrimmed
lurl
lysator
-möller
macr
magicarr
magicfile
@@ -2260,6 +2308,7 @@ mailtext
mailto
mainmodule
mainpage
+maint
maintainership
makesafe
male
@@ -2295,16 +2344,19 @@ maxwidth
mazeland
mbresponse
mbstring
+mccmnc
mckey
mcklmqw
mcrypt
mcvalue
md
mdash
+mdot
medialink
mediaqueries
mediatype
mediawarning
+mediawiki
mediawiki's
mediawikipage
megapixels
@@ -2385,6 +2437,7 @@ mkdir
mms
mobile
mobileformat
+mobilelanding
mobileview
modified
modifiedarticleprotection
@@ -2405,6 +2458,7 @@ moodbar
moredotdotdot
morelinkstoimage
morethan
+mouseup
move
movedarticleprotection
moveddeleted
@@ -2442,6 +2496,7 @@ msgsmall
msgtext
msie
msmetafile
+msnbot
mssql
msvideo
msword
@@ -2449,6 +2504,7 @@ mtime
mtype
mullane
multi
+multiactions
multibyte
multicast
multipage
@@ -2486,10 +2542,13 @@ mysqldump
mytalk
mytext
mywatchlist
+möller
nabla
name
namehidden
nameinlowercase
+namelookup
+namemsg
names
namespace
namespacealiases
@@ -2530,9 +2589,7 @@ newheader
newid
newimages
newlen
-newmessagesdifflink
newmessagesdifflinkplural
-newmessageslink
newmessageslinkplural
newname
newnames
@@ -2548,6 +2605,7 @@ newpos
newquery
newrevid
news
+newsectionheaderdefaultlevel
newsectionlink
newsectionsummary
newset
@@ -2574,6 +2632,7 @@ nextredirect
nextrevision
nextval
nfkc
+nfkd
nginx
nheight
niklas
@@ -2787,6 +2846,7 @@ noto
notoc
notoggle
notoken
+notpatrollable
notransform
notreviewable
notrustworthy
@@ -2888,6 +2948,7 @@ oldtitle
oldtitlemsg
oline
oname
+onerror
onkeyup
online
onload
@@ -2898,6 +2959,7 @@ onlyquery
onsubmit
onthisday
ontop
+onuser
openbasedir
opendoc
opendocument
@@ -2906,6 +2968,7 @@ opensearchdescription
openssl's
openxml
openxmlformats
+operamini
oplus
oppositedm
optgroup
@@ -2920,6 +2983,7 @@ ordertype
ordf
ordm
org
+orghttp
origcategory
ortime
oslash
@@ -2991,6 +3055,7 @@ pagetriagetagging
pagetriagetemplate
pageurl
pageview
+pango
param
parameters
paraminfo
@@ -3091,8 +3156,10 @@ pltitles
plusminus
plusmn
pname
+png'd
pnmtojpeg
pnmtopng
+pointsize
poolcounter
popts
popularpages
@@ -3117,17 +3184,18 @@ pptm
pptx
precaching
precompiled
+preemptively
preferences
preferencestoken
prefill
prefilled
prefix
prefixindex
+prefixsearch
prefixsearchdisabled
prefs
prefsection
-prefsnologin
-prefsnologintext
+prefsnologintext2
prefsubmit
preload
preloads
@@ -3139,6 +3207,7 @@ preprocessing
preprocessors
presentationml
presep
+pretransfer
prevchar
prevdiff
previd
@@ -3202,6 +3271,7 @@ protecttoken
proto
protocol
protocols
+protorel
protos
proxied
proxyblocker
@@ -3224,6 +3294,7 @@ purged
qabardjajəbza
qbar
qbsettings
+qlow
qmoicj
qp
quasit
@@ -3242,6 +3313,7 @@ querytype
question
queuefull
quickbar
+quicksorts
quicktemplate
quicktime
qunit
@@ -3337,6 +3409,7 @@ redirectable
redirectcreated
redirectedfrom
redirections
+redirector
redirectpagesub
redirectparams
redirects
@@ -3351,6 +3424,7 @@ redis
redlink
redlinks
redocument
+redux
reedyboy
reenables
reencode
@@ -3377,7 +3451,6 @@ relname
relnamespace
remarticle
remembermypassword
-rememberpassword
removablegroups
removal
remove
@@ -3389,6 +3462,8 @@ remstudent
renameuser
renaming
renderable
+renderesibanner
+renderwarning
renormalized
repeating
repl
@@ -3574,6 +3649,7 @@ selflink
selfmove
semiglobal
semiprotected
+semiprotectedlevels
semiprotectedpagewarning
sendemail
sendmail
@@ -3692,9 +3768,14 @@ slideshow
sm
smaxage
smil
+smpp
+sms's
+smscontent
+smslogs
smtp
snippet
sodipodi
+softredirect
softtabstop
solaris
somecontent
@@ -3748,6 +3829,7 @@ stabilize
stable
stablesettings
stansvik
+starcode
start
startid
startime
@@ -3755,6 +3837,7 @@ startsortkey
startsortkeyprefix
starttime
starttimestamp
+starttransfer
stash
stashfailed
stashimageinfo
@@ -3771,6 +3854,7 @@ stopwords
storedversion
strcasecmp
strcmp
+strftime
string
stripos
stripslashes
@@ -3887,6 +3971,7 @@ taglist
tags
tagset
tagstack
+tahoma
tailorings
talk
talkable
@@ -3904,8 +3989,8 @@ talkpagetext
talkspace
talkspacee
talkto
-taraškievica
tarask
+taraškievica
target
tb
tbase
@@ -3932,6 +4017,7 @@ test
testclean
testdata
testmailuser
+teston
testpass
testrunner
testswarm
@@ -3972,6 +4058,7 @@ thumbheight
thumbhtml
thumbimage
thumbinner
+thumblimits
thumbmime
thumbnail
thumbnailing
@@ -4045,6 +4132,7 @@ toparse
topbar
toplevel
toplinks
+topojson
toponly
torev
torevid
@@ -4076,7 +4164,9 @@ transwiki
troff
true
truespeed
+truncatedtext
trustworthy
+truteq
truthy
tsearch
tsquery
@@ -4099,6 +4189,7 @@ udpprofile
ufffd
ugrave
ui
+uids
uint
ulimit
ulink
@@ -4124,6 +4215,8 @@ undel
undelete
undeleted
undeletion
+undismissable
+undismissible
undo
undoafter
undofailure
@@ -4138,6 +4231,7 @@ unhelpful
unhidden
unhide
unidata
+unidecode
unindent
unindexed
uniq
@@ -4165,6 +4259,7 @@ unprotect
unprotectedarticle
unprotection
unprotectthispage
+unreadcount
unredacted
unrequest
unrequested
@@ -4177,6 +4272,7 @@ unseed
unserialization
unserialize
unserialized
+unserializes
unserializing
unsetting
unstub
@@ -4220,6 +4316,7 @@ uploadscripted
uploadsource
uploadstash
uploadvirus
+uploadwarning
uppercased
upsih
urandom
@@ -4303,6 +4400,9 @@ usertoollinks
useskin
useto
usort
+usrmonth
+ussd
+ussdcontent
ustar
ustoken
utfnormal
@@ -4347,6 +4447,7 @@ viewdeleted
viewhelppage
viewmyprivateinfo
viewmywatchlist
+viewport
viewprevnext
viewsource
viewsourcelink
@@ -4363,6 +4464,7 @@ vorbis
vpad
vrml
vslow
+vumi
vvcv
vxml
wais
@@ -4400,6 +4502,7 @@ wbxml
wddx
wddxfm
weblog
+weblogs
webm
webp
webrequest
@@ -4442,17 +4545,23 @@ wikilove
wikiloveimagelog
wikimedia
wikimediacommons
+wikimediafoundation
+wikinews
wikipage
wikipedia
wikipedian
wikipedias
+wikiquote
wikis
+wikisource
wikisyntax
wikitable
wikitables
wikitech
wikitext
wikiuser
+wikiversity
+wikivoyage
wiktionary
wincache
wininet
@@ -4477,6 +4586,7 @@ wmls
wmlsc
wmlscript
wmlscriptc
+wmnet
wordcount
wordprocessingml
wordwg
@@ -4491,6 +4601,7 @@ writerequired
writerights
wrongpassword
x
+xanalytics
xbitmap
xcache
xcancel
@@ -4512,8 +4623,8 @@ xml
xmldoublequote
xmlfm
xmlimport
+xmlmeta
xmlns
-xmlsafe
xmlselect
xor
xpinstall
@@ -4526,6 +4637,7 @@ xxxxx
yacute
yaml
yamlfm
+yandex
year
yes
youhavenewmessages
@@ -4547,10 +4659,26 @@ yourvariant
yourwiki
yuml
yyyymmddhhiiss
+zcmd
+zerobanner
+zerobar
+zerobutton
+zeroconfig
+zerodontask
+zerodot
+zeroinfo
+zeronet
+zeroportal
+zfile
zhdaemon
zhengzhu
zhtable
zijdel
+zlang
zlib
zoffset
+zrma
zwnj
+ænglisc
+ævar
+świerkosz
diff --git a/maintenance/doMaintenance.php b/maintenance/doMaintenance.php
index 3bd508cb..46844c9d 100644
--- a/maintenance/doMaintenance.php
+++ b/maintenance/doMaintenance.php
@@ -44,6 +44,7 @@ if ( !$maintClass || !class_exists( $maintClass ) ) {
}
// Get an object to start us off
+/** @var Maintenance $maintenance */
$maintenance = new $maintClass();
// Basic sanity checks and such
@@ -77,37 +78,24 @@ if ( defined( 'MW_CONFIG_CALLBACK' ) ) {
# Use a callback function to configure MediaWiki
call_user_func( MW_CONFIG_CALLBACK );
} else {
- if ( file_exists( "$IP/../wmf-config/wikimedia-mode" ) ) {
- // Load settings, using wikimedia-mode if needed
- // @todo FIXME: Replace this hack with general farm-friendly code
- # @todo FIXME: Wikimedia-specific stuff needs to go away to an ext
- # Maybe a hook?
- global $cluster;
- $cluster = 'pmtpa';
- require "$IP/../wmf-config/wgConf.php";
- }
// Require the configuration (probably LocalSettings.php)
require $maintenance->loadSettings();
}
-if ( $maintenance->getDbType() === Maintenance::DB_ADMIN &&
- is_readable( "$IP/AdminSettings.php" ) )
-{
- require "$IP/AdminSettings.php";
-}
-
if ( $maintenance->getDbType() === Maintenance::DB_NONE ) {
- if ( $wgLocalisationCacheConf['storeClass'] === false && ( $wgLocalisationCacheConf['store'] == 'db' || ( $wgLocalisationCacheConf['store'] == 'detect' && !$wgCacheDirectory ) ) ) {
- $wgLocalisationCacheConf['storeClass'] = 'LCStore_Null';
+ if ( $wgLocalisationCacheConf['storeClass'] === false
+ && ( $wgLocalisationCacheConf['store'] == 'db'
+ || ( $wgLocalisationCacheConf['store'] == 'detect' && !$wgCacheDirectory ) )
+ ) {
+ $wgLocalisationCacheConf['storeClass'] = 'LCStoreNull';
}
}
+
+$maintenance->setConfig( ConfigFactory::getDefaultInstance()->makeConfig( 'main' ) );
$maintenance->finalSetup();
// Some last includes
require_once "$IP/includes/Setup.php";
-// Much much faster startup than creating a title object
-$wgTitle = null;
-
// Do the work
try {
$maintenance->execute();
diff --git a/maintenance/dumpBackup.php b/maintenance/dumpBackup.php
index 25a777cd..18c78dcd 100644
--- a/maintenance/dumpBackup.php
+++ b/maintenance/dumpBackup.php
@@ -4,7 +4,7 @@
* wrapper format for export or backup
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -127,5 +127,5 @@ Fancy stuff: (Works? Add examples please.)
--filter=<type>[:<options>] Add a filter on an output branch
ENDS
-);
+ );
}
diff --git a/maintenance/dumpIterator.php b/maintenance/dumpIterator.php
index dd468a9f..4b2ff717 100644
--- a/maintenance/dumpIterator.php
+++ b/maintenance/dumpIterator.php
@@ -5,7 +5,7 @@
* We implement below the simple task of searching inside a dump.
*
* Copyright © 2011 Platonides
- * http://www.mediawiki.org/
+ * https://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
@@ -57,8 +57,11 @@ abstract class DumpIterator extends Maintenance {
$revision = new WikiRevision;
$revision->setText( file_get_contents( $this->getOption( 'file' ) ) );
- $revision->setTitle( Title::newFromText( rawurldecode( basename( $this->getOption( 'file' ), '.txt' ) ) ) );
+ $revision->setTitle( Title::newFromText(
+ rawurldecode( basename( $this->getOption( 'file' ), '.txt' ) )
+ ) );
$this->handleRevision( $revision );
+
return;
}
@@ -67,7 +70,8 @@ abstract class DumpIterator extends Maintenance {
if ( $this->getOption( 'dump' ) == '-' ) {
$source = new ImportStreamSource( $this->getStdin() );
} else {
- $this->error( "Sorry, I don't support dump filenames yet. Use - and provide it on stdin on the meantime.", true );
+ $this->error( "Sorry, I don't support dump filenames yet. "
+ . "Use - and provide it on stdin on the meantime.", true );
}
$importer = new WikiImporter( $source );
@@ -86,8 +90,9 @@ abstract class DumpIterator extends Maintenance {
$this->error( round( $this->count / $delta, 2 ) . " pages/sec" );
}
- # Perform the memory_get_peak_usage() when all the other data has been output so there's no damage if it dies.
- # It is only available since 5.2.0 (since 5.2.1 if you haven't compiled with --enable-memory-limit)
+ # Perform the memory_get_peak_usage() when all the other data has been
+ # output so there's no damage if it dies. It is only available since
+ # 5.2.0 (since 5.2.1 if you haven't compiled with --enable-memory-limit)
$this->error( "Memory peak usage of " . memory_get_peak_usage() . " bytes\n" );
}
@@ -97,7 +102,7 @@ abstract class DumpIterator extends Maintenance {
if ( $this->getDbType() == Maintenance::DB_NONE ) {
global $wgUseDatabaseMessages, $wgLocalisationCacheConf, $wgHooks;
$wgUseDatabaseMessages = false;
- $wgLocalisationCacheConf['storeClass'] = 'LCStore_Null';
+ $wgLocalisationCacheConf['storeClass'] = 'LCStoreNull';
$wgHooks['InterwikiLoadPrefix'][] = 'DumpIterator::disableInterwikis';
}
}
@@ -112,12 +117,13 @@ abstract class DumpIterator extends Maintenance {
/**
* Callback function for each revision, child classes should override
* processRevision instead.
- * @param $rev Revision
+ * @param DatabaseBase $rev
*/
public function handleRevision( $rev ) {
$title = $rev->getTitle();
if ( !$title ) {
$this->error( "Got bogus revision with null title!" );
+
return;
}
@@ -167,7 +173,7 @@ class SearchDump extends DumpIterator {
}
/**
- * @param $rev Revision
+ * @param Revision $rev
*/
public function processRevision( $rev ) {
if ( preg_match( $this->getOption( 'regex' ), $rev->getContent()->getTextForSearchIndex() ) ) {
diff --git a/maintenance/dumpLinks.php b/maintenance/dumpLinks.php
index be0b4633..888c2dc1 100644
--- a/maintenance/dumpLinks.php
+++ b/maintenance/dumpLinks.php
@@ -9,7 +9,7 @@
* Dumps ASCII text to stdout; command-line.
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -59,7 +59,7 @@ class DumpLinks extends Maintenance {
$lastPage = null;
foreach ( $result as $row ) {
if ( $lastPage != $row->page_id ) {
- if ( isset( $lastPage ) ) {
+ if ( $lastPage !== null ) {
$this->output( "\n" );
}
$page = Title::makeTitle( $row->page_namespace, $row->page_title );
@@ -69,7 +69,7 @@ class DumpLinks extends Maintenance {
$link = Title::makeTitle( $row->pl_namespace, $row->pl_title );
$this->output( " " . $link->getPrefixedURL() );
}
- if ( isset( $lastPage ) ) {
+ if ( $lastPage !== null ) {
$this->output( "\n" );
}
}
diff --git a/maintenance/dumpSisterSites.php b/maintenance/dumpSisterSites.php
index 5f0c5b7c..784dc7a8 100644
--- a/maintenance/dumpSisterSites.php
+++ b/maintenance/dumpSisterSites.php
@@ -4,7 +4,7 @@
* http://www.eekim.com/cgi-bin/wiki.pl?SisterSites
*
* Copyright © 2006 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
diff --git a/maintenance/dumpTextPass.php b/maintenance/dumpTextPass.php
index 5d783cb9..7c176071 100644
--- a/maintenance/dumpTextPass.php
+++ b/maintenance/dumpTextPass.php
@@ -3,7 +3,7 @@
* Script that postprocesses XML dumps from dumpBackup.php to add page text
*
* Copyright (C) 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -29,7 +29,6 @@ $originalDir = getcwd();
require_once __DIR__ . '/commandLine.inc';
require_once __DIR__ . '/backupTextPass.inc';
-
$dumper = new TextPassDumper( $argv );
if ( !isset( $options['help'] ) ) {
@@ -62,5 +61,5 @@ Options:
--spawn Spawn a subprocess for loading text records
--help Display this help message
ENDS
-);
+ );
}
diff --git a/maintenance/dumpUploads.php b/maintenance/dumpUploads.php
index 1a9293cb..9d53f07c 100644
--- a/maintenance/dumpUploads.php
+++ b/maintenance/dumpUploads.php
@@ -64,7 +64,7 @@ By default, outputs relative paths against the parent directory of \$wgUploadDir
$this->mSharedSupplement = true;
}
}
- $this-> { $this->mAction } ( $this->mShared );
+ $this->{$this->mAction} ( $this->mShared );
if ( $this->mSharedSupplement ) {
$this->fetchUsed( true );
}
@@ -73,7 +73,7 @@ By default, outputs relative paths against the parent directory of \$wgUploadDir
/**
* Fetch a list of used images from a particular image source.
*
- * @param $shared Boolean: true to pass shared-dir settings to hash func
+ * @param bool $shared True to pass shared-dir settings to hash func
*/
function fetchUsed( $shared ) {
$dbr = wfGetDB( DB_SLAVE );
@@ -94,7 +94,7 @@ By default, outputs relative paths against the parent directory of \$wgUploadDir
/**
* Fetch a list of all images from a particular image source.
*
- * @param $shared Boolean: true to pass shared-dir settings to hash func
+ * @param bool $shared True to pass shared-dir settings to hash func
*/
function fetchLocal( $shared ) {
$dbr = wfGetDB( DB_SLAVE );
diff --git a/maintenance/edit.php b/maintenance/edit.php
index 7c24f0fa..75ec12bf 100644
--- a/maintenance/edit.php
+++ b/maintenance/edit.php
@@ -38,11 +38,13 @@ class EditCLI extends Maintenance {
$this->addOption( 'bot', 'Bot edit', false, false, 'b' );
$this->addOption( 'autosummary', 'Enable autosummary', false, false, 'a' );
$this->addOption( 'no-rc', 'Do not show the change in recent changes', false, false, 'r' );
+ $this->addOption( 'nocreate', 'Don\'t create new pages', false, false );
+ $this->addOption( 'createonly', 'Only create new pages', false, false );
$this->addArg( 'title', 'Title of article to edit' );
}
public function execute() {
- global $wgUser, $wgTitle;
+ global $wgUser;
$userName = $this->getOption( 'user', 'Maintenance script' );
$summary = $this->getOption( 'summary', '' );
@@ -52,8 +54,6 @@ class EditCLI extends Maintenance {
$noRC = $this->hasOption( 'no-rc' );
$wgUser = User::newFromName( $userName );
- $context = RequestContext::getMain();
- $context->setUser( $wgUser );
if ( !$wgUser ) {
$this->error( "Invalid username", true );
}
@@ -61,17 +61,22 @@ class EditCLI extends Maintenance {
$wgUser->addToDatabase();
}
- $wgTitle = Title::newFromText( $this->getArg() );
- if ( !$wgTitle ) {
+ $title = Title::newFromText( $this->getArg() );
+ if ( !$title ) {
$this->error( "Invalid title", true );
}
- $context->setTitle( $wgTitle );
- $page = WikiPage::factory( $wgTitle );
+ if ( $this->hasOption( 'nocreate' ) && !$title->exists() ) {
+ $this->error( "Page does not exist", true );
+ } elseif ( $this->hasOption( 'createonly' ) && $title->exists() ) {
+ $this->error( "Page already exists", true );
+ }
+
+ $page = WikiPage::factory( $title );
# Read the text
$text = $this->getStdin( Maintenance::STDIN_ALL );
- $content = ContentHandler::makeContent( $text, $wgTitle );
+ $content = ContentHandler::makeContent( $text, $title );
# Do the edit
$this->output( "Saving... " );
diff --git a/maintenance/eraseArchivedFile.php b/maintenance/eraseArchivedFile.php
index 1c3f0376..94ca604d 100644
--- a/maintenance/eraseArchivedFile.php
+++ b/maintenance/eraseArchivedFile.php
@@ -27,7 +27,7 @@ require_once __DIR__ . '/Maintenance.php';
/**
* Maintenance script to delete archived (non-current) files from storage.
*
- * @TODO: Maybe add some simple logging
+ * @todo Maybe add some simple logging
*
* @ingroup Maintenance
* @since 1.22
diff --git a/maintenance/eval.php b/maintenance/eval.php
index abedc61a..51f2cace 100644
--- a/maintenance/eval.php
+++ b/maintenance/eval.php
@@ -1,6 +1,5 @@
<?php
/**
- * PHP lacks an interactive mode, but this can be very helpful when debugging.
* This script lets a command-line user start up the wiki engine and then poke
* about by issuing PHP commands directly.
*
@@ -56,7 +55,7 @@ if ( isset( $options['d'] ) ) {
}
$useReadline = function_exists( 'readline_add_history' )
- && Maintenance::posix_isatty( 0 /*STDIN*/ );
+ && Maintenance::posix_isatty( 0 /*STDIN*/ );
if ( $useReadline ) {
$historyFile = isset( $_ENV['HOME'] ) ?
@@ -64,13 +63,28 @@ if ( $useReadline ) {
readline_read_history( $historyFile );
}
+$e = null; // PHP exception
while ( ( $line = Maintenance::readconsole() ) !== false ) {
+ if ( $e && !preg_match( '/^(exit|die);?$/', $line ) ) {
+ // Internal state may be corrupted or fatals may occur later due
+ // to some object not being set. Don't drop out of eval in case
+ // lines were being pasted in (which would then get dumped to the shell).
+ // Instead, just absorb the remaning commands. Let "exit" through per DWIM.
+ echo "Exception was thrown before; please restart eval.php\n";
+ continue;
+ }
if ( $useReadline ) {
readline_add_history( $line );
readline_write_history( $historyFile );
}
- $val = eval( $line . ";" );
- if ( wfIsHipHop() || is_null( $val ) ) {
+ try {
+ $val = eval( $line . ";" );
+ } catch ( Exception $e ) {
+ echo "Caught exception " . get_class( $e ) .
+ ": {$e->getMessage()}\n" . $e->getTraceAsString() . "\n";
+ continue;
+ }
+ if ( wfIsHHVM() || is_null( $val ) ) {
echo "\n";
} elseif ( is_string( $val ) || is_numeric( $val ) ) {
echo "$val\n";
diff --git a/maintenance/fetchText.php b/maintenance/fetchText.php
index 05470d30..fc676b89 100644
--- a/maintenance/fetchText.php
+++ b/maintenance/fetchText.php
@@ -37,11 +37,11 @@ class FetchText extends Maintenance {
/**
* returns a string containing the following in order:
- * textid
- * \n
- * length of text (-1 on error = failure to retrieve/unserialize/gunzip/etc)
- * \n
- * text (may be empty)
+ * textid
+ * \n
+ * length of text (-1 on error = failure to retrieve/unserialize/gunzip/etc)
+ * \n
+ * text (may be empty)
*
* note that that the text string itself is *not* followed by newline
*/
@@ -59,8 +59,7 @@ class FetchText extends Maintenance {
if ( $text === false ) {
# actual error, not zero-length text
$textLen = "-1";
- }
- else {
+ } else {
$textLen = strlen( $text );
}
$this->output( $textId . "\n" . $textLen . "\n" . $text );
@@ -69,9 +68,9 @@ class FetchText extends Maintenance {
/**
* May throw a database error if, say, the server dies during query.
- * @param $db DatabaseBase object
- * @param $id int The old_id
- * @return String
+ * @param DatabaseBase $db
+ * @param int $id The old_id
+ * @return string
*/
private function doGetText( $db, $id ) {
$id = intval( $id );
@@ -83,6 +82,7 @@ class FetchText extends Maintenance {
if ( $text === false ) {
return false;
}
+
return $text;
}
}
diff --git a/maintenance/findHooks.php b/maintenance/findHooks.php
index 373170ff..36760d7e 100644
--- a/maintenance/findHooks.php
+++ b/maintenance/findHooks.php
@@ -42,6 +42,11 @@ require_once __DIR__ . '/Maintenance.php';
* @ingroup Maintenance
*/
class FindHooks extends Maintenance {
+ /*
+ * Hooks that are ignored
+ */
+ protected static $ignore = array( 'testRunLegacyHooks' );
+
public function __construct() {
parent::__construct();
$this->mDescription = 'Find hooks that are undocumented, missing, or just plain wrong';
@@ -58,34 +63,53 @@ class FindHooks extends Maintenance {
$documented = $this->getHooksFromDoc( $IP . '/docs/hooks.txt' );
$potential = array();
$bad = array();
+
+ // TODO: Don't hardcode the list of directories
$pathinc = array(
$IP . '/',
$IP . '/includes/',
$IP . '/includes/actions/',
$IP . '/includes/api/',
$IP . '/includes/cache/',
+ $IP . '/includes/changes/',
+ $IP . '/includes/clientpool/',
$IP . '/includes/content/',
$IP . '/includes/context/',
+ $IP . '/includes/dao/',
$IP . '/includes/db/',
+ $IP . '/includes/debug/',
+ $IP . '/includes/deferred/',
$IP . '/includes/diff/',
+ $IP . '/includes/externalstore/',
+ $IP . '/includes/filebackend/',
$IP . '/includes/filerepo/',
$IP . '/includes/filerepo/file/',
+ $IP . '/includes/gallery/',
+ $IP . '/includes/htmlform/',
$IP . '/includes/installer/',
$IP . '/includes/interwiki/',
+ $IP . '/includes/jobqueue/',
+ $IP . '/includes/json/',
$IP . '/includes/logging/',
$IP . '/includes/media/',
+ $IP . '/includes/page/',
$IP . '/includes/parser/',
+ $IP . '/includes/rcfeed/',
$IP . '/includes/resourceloader/',
$IP . '/includes/revisiondelete/',
$IP . '/includes/search/',
+ $IP . '/includes/site/',
+ $IP . '/includes/skins/',
+ $IP . '/includes/specialpage/',
$IP . '/includes/specials/',
$IP . '/includes/upload/',
+ $IP . '/includes/utils/',
$IP . '/languages/',
$IP . '/maintenance/',
+ $IP . '/maintenance/language/',
$IP . '/tests/',
$IP . '/tests/parser/',
$IP . '/tests/phpunit/suites/',
- $IP . '/skins/',
);
foreach ( $pathinc as $dir ) {
@@ -103,15 +127,15 @@ class FindHooks extends Maintenance {
$this->printArray( 'Documented and not found', $deprecated );
$this->printArray( 'Unclear hook calls', $bad );
- if ( count( $todo ) == 0 && count( $deprecated ) == 0 && count( $bad ) == 0 )
- {
+ if ( count( $todo ) == 0 && count( $deprecated ) == 0 && count( $bad ) == 0 ) {
$this->output( "Looks good!\n" );
}
}
/**
* Get the hook documentation, either locally or from MediaWiki.org
- * @return array of documented hooks
+ * @param string $doc
+ * @return array Array of documented hooks
*/
private function getHooksFromDoc( $doc ) {
if ( $this->hasOption( 'online' ) ) {
@@ -123,62 +147,75 @@ class FindHooks extends Maintenance {
/**
* Get hooks from a local file (for example docs/hooks.txt)
- * @param $doc string: filename to look in
- * @return array of documented hooks
+ * @param string $doc Filename to look in
+ * @return array Array of documented hooks
*/
private function getHooksFromLocalDoc( $doc ) {
- $m = array();
- $content = file_get_contents( $doc );
- preg_match_all( "/\n'(.*?)'/", $content, $m );
- return array_unique( $m[1] );
+ $m = array();
+ $content = file_get_contents( $doc );
+ preg_match_all( "/\n'(.*?)':/", $content, $m );
+
+ return array_unique( $m[1] );
}
/**
* Get hooks from www.mediawiki.org using the API
- * @return array of documented hooks
+ * @return array Array of documented hooks
*/
private function getHooksFromOnlineDoc() {
- // All hooks
- $allhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:MediaWiki_hooks&cmlimit=500&format=php' );
- $allhookdata = unserialize( $allhookdata );
- $allhooks = array();
- foreach ( $allhookdata['query']['categorymembers'] as $page ) {
- $found = preg_match( '/Manual\:Hooks\/([a-zA-Z0-9- :]+)/', $page['title'], $matches );
- if ( $found ) {
- $hook = str_replace( ' ', '_', $matches[1] );
- $allhooks[] = $hook;
- }
+ // All hooks
+ $allhookdata = Http::get(
+ 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&'
+ . 'cmtitle=Category:MediaWiki_hooks&cmlimit=500&format=php'
+ );
+ $allhookdata = unserialize( $allhookdata );
+ $allhooks = array();
+ foreach ( $allhookdata['query']['categorymembers'] as $page ) {
+ $found = preg_match( '/Manual\:Hooks\/([a-zA-Z0-9- :]+)/', $page['title'], $matches );
+ if ( $found ) {
+ $hook = str_replace( ' ', '_', $matches[1] );
+ $allhooks[] = $hook;
}
- // Removed hooks
- $oldhookdata = Http::get( 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Removed_hooks&cmlimit=500&format=php' );
- $oldhookdata = unserialize( $oldhookdata );
- $removed = array();
- foreach ( $oldhookdata['query']['categorymembers'] as $page ) {
- $found = preg_match( '/Manual\:Hooks\/([a-zA-Z0-9- :]+)/', $page['title'], $matches );
- if ( $found ) {
- $hook = str_replace( ' ', '_', $matches[1] );
- $removed[] = $hook;
- }
+ }
+ // Removed hooks
+ $oldhookdata = Http::get(
+ 'http://www.mediawiki.org/w/api.php?action=query&list=categorymembers&'
+ . 'cmtitle=Category:Removed_hooks&cmlimit=500&format=php'
+ );
+ $oldhookdata = unserialize( $oldhookdata );
+ $removed = array();
+ foreach ( $oldhookdata['query']['categorymembers'] as $page ) {
+ $found = preg_match( '/Manual\:Hooks\/([a-zA-Z0-9- :]+)/', $page['title'], $matches );
+ if ( $found ) {
+ $hook = str_replace( ' ', '_', $matches[1] );
+ $removed[] = $hook;
}
- return array_diff( $allhooks, $removed );
+ }
+
+ return array_diff( $allhooks, $removed );
}
/**
* Get hooks from a PHP file
- * @param $file string Full filename to the PHP file.
- * @return array of hooks found.
+ * @param string $file Full filename to the PHP file.
+ * @return array Array of hooks found
*/
private function getHooksFromFile( $file ) {
$content = file_get_contents( $file );
$m = array();
- preg_match_all( '/(?:wfRunHooks|Hooks\:\:run|ContentHandler\:\:runLegacyHooks)\(\s*([\'"])(.*?)\1/', $content, $m );
+ preg_match_all(
+ '/(?:wfRunHooks|Hooks\:\:run|ContentHandler\:\:runLegacyHooks)\(\s*([\'"])(.*?)\1/',
+ $content,
+ $m
+ );
+
return $m[2];
}
/**
* Get hooks from the source code.
- * @param $path Directory where the include files can be found
- * @return array of hooks found.
+ * @param string $path Directory where the include files can be found
+ * @return array Array of hooks found
*/
private function getHooksFromPath( $path ) {
$hooks = array();
@@ -191,13 +228,14 @@ class FindHooks extends Maintenance {
}
closedir( $dh );
}
+
return $hooks;
}
/**
* Get bad hooks (where the hook name could not be determined) from a PHP file
- * @param $file string Full filename to the PHP file.
- * @return array of bad wfRunHooks() lines
+ * @param string $file Full filename to the PHP file.
+ * @return array Array of bad wfRunHooks() lines
*/
private function getBadHooksFromFile( $file ) {
$content = file_get_contents( $file );
@@ -208,13 +246,14 @@ class FindHooks extends Maintenance {
foreach ( $m[0] as $match ) {
$list[] = $match . "(" . $file . ")";
}
+
return $list;
}
/**
* Get bad hooks from the source code.
- * @param $path Directory where the include files can be found
- * @return array of bad wfRunHooks() lines
+ * @param string $path Directory where the include files can be found
+ * @return array Array of bad wfRunHooks() lines
*/
private function getBadHooksFromPath( $path ) {
$hooks = array();
@@ -228,21 +267,25 @@ class FindHooks extends Maintenance {
}
closedir( $dh );
}
+
return $hooks;
}
/**
* Nicely output the array
- * @param $msg String: a message to show before the value
- * @param $arr Array: an array
- * @param $sort Boolean: whether to sort the array (Default: true)
+ * @param string $msg A message to show before the value
+ * @param array $arr
+ * @param bool $sort Whether to sort the array (Default: true)
*/
private function printArray( $msg, $arr, $sort = true ) {
if ( $sort ) {
asort( $arr );
}
+
foreach ( $arr as $v ) {
- $this->output( "$msg: $v\n" );
+ if ( !in_array( $v, self::$ignore ) ) {
+ $this->output( "$msg: $v\n" );
+ }
}
}
}
diff --git a/maintenance/findMissingFiles.php b/maintenance/findMissingFiles.php
new file mode 100644
index 00000000..5f9f643a
--- /dev/null
+++ b/maintenance/findMissingFiles.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author Aaron Schulz
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+class FindMissingFiles extends Maintenance {
+ function __construct() {
+ parent::__construct();
+
+ $this->mDescription = 'Find registered files with no corresponding file.';
+ $this->addOption( 'start', 'Starting file name', false, true );
+ $this->addOption( 'mtimeafter', 'Only include files changed since this time', false, true );
+ $this->addOption( 'mtimebefore', 'Only includes files changed before this time', false, true );
+ $this->setBatchSize( 300 );
+ }
+
+ function execute() {
+ $lastName = $this->getOption( 'start', '' );
+
+ $repo = RepoGroup::singleton()->getLocalRepo();
+ $dbr = $repo->getSlaveDB();
+ $be = $repo->getBackend();
+
+ $mtime1 = $dbr->timestampOrNull( $this->getOption( 'mtimeafter', null ) );
+ $mtime2 = $dbr->timestampOrNull( $this->getOption( 'mtimebefore', null ) );
+
+ $joinTables = array( 'image' );
+ $joinConds = array( 'image' => array( 'INNER JOIN', 'img_name = page_title' ) );
+ if ( $mtime1 || $mtime2 ) {
+ $joinTables[] = 'logging';
+ $on = array( 'log_page = page_id', 'log_type' => array( 'upload', 'move', 'delete' ) );
+ if ( $mtime1 ) {
+ $on[] = "log_timestamp > {$dbr->addQuotes($mtime1)}";
+ }
+ if ( $mtime2 ) {
+ $on[] = "log_timestamp < {$dbr->addQuotes($mtime2)}";
+ }
+ $joinConds['logging'] = array( 'INNER JOIN', $on );
+ }
+
+ do {
+ $res = $dbr->select(
+ array_merge( array( 'page' ), $joinTables ),
+ array( 'img_name' => 'DISTINCT(page_title)' ),
+ array( 'page_namespace' => NS_FILE,
+ "page_title >= " . $dbr->addQuotes( $lastName ) ),
+ __METHOD__,
+ array( 'ORDER BY' => 'page_title', 'LIMIT' => $this->mBatchSize ),
+ $joinConds
+ );
+
+ // Check if any of these files are missing...
+ $pathsByName = array();
+ foreach ( $res as $row ) {
+ $file = $repo->newFile( $row->img_name );
+ $pathsByName[$row->img_name] = $file->getPath();
+ $lastName = $row->img_name;
+ }
+ $be->preloadFileStat( array( 'srcs' => $pathsByName ) );
+ foreach ( $pathsByName as $path ) {
+ if ( $be->fileExists( array( 'src' => $path ) ) === false ) {
+ $this->output( "$path\n" );
+ }
+ }
+
+ // Find all missing old versions of any of the files in this batch...
+ if ( count( $pathsByName ) ) {
+ $ores = $dbr->select( 'oldimage',
+ array( 'oi_name', 'oi_archive_name' ),
+ array( 'oi_name' => array_keys( $pathsByName ) ),
+ __METHOD__
+ );
+
+ $checkPaths = array();
+ foreach ( $ores as $row ) {
+ if ( !strlen( $row->oi_archive_name ) ) {
+ continue; // broken row
+ }
+ $file = $repo->newFromArchiveName( $row->oi_name, $row->oi_archive_name );
+ $checkPaths[] = $file->getPath();
+ }
+
+ foreach ( array_chunk( $checkPaths, $this->mBatchSize ) as $paths ) {
+ $be->preloadFileStat( array( 'srcs' => $paths ) );
+ foreach ( $paths as $path ) {
+ if ( $be->fileExists( array( 'src' => $path ) ) === false ) {
+ $this->output( "$path\n" );
+ }
+ }
+ }
+ }
+ } while ( $res->numRows() >= $this->mBatchSize );
+ }
+}
+
+$maintClass = 'FindMissingFiles';
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/fixDoubleRedirects.php b/maintenance/fixDoubleRedirects.php
index 523be7ef..95682847 100644
--- a/maintenance/fixDoubleRedirects.php
+++ b/maintenance/fixDoubleRedirects.php
@@ -3,7 +3,7 @@
* Fix double redirects.
*
* Copyright © 2011 Ilmari Karonen <nospam@vyznev.net>
- * http://www.mediawiki.org/
+ * https://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
@@ -44,13 +44,14 @@ class FixDoubleRedirects extends Maintenance {
public function execute() {
$async = $this->getOption( 'async', false );
$dryrun = $this->getOption( 'dry-run', false );
- $title = $this->getOption( 'title' );
- if ( isset( $title ) ) {
- $title = Title::newFromText( $title );
+ if ( $this->hasOption( 'title' ) ) {
+ $title = Title::newFromText( $this->getOption( 'title' ) );
if ( !$title || !$title->isRedirect() ) {
$this->error( $title->getPrefixedText() . " is not a redirect!\n", true );
}
+ } else {
+ $title = null;
}
$dbr = wfGetDB( DB_SLAVE );
@@ -71,11 +72,11 @@ class FixDoubleRedirects extends Maintenance {
'rd_from = pa.page_id',
'rd_namespace = pb.page_namespace',
'rd_title = pb.page_title',
- '(rd_interwiki IS NULL OR rd_interwiki = "")', // bug 40352
+ 'rd_interwiki IS NULL OR rd_interwiki = ' . $dbr->addQuotes( '' ), // bug 40352
'pb.page_is_redirect' => 1,
);
- if ( isset( $title ) ) {
+ if ( $title != null ) {
$conds['pb.page_namespace'] = $title->getNamespace();
$conds['pb.page_title'] = $title->getDBkey();
}
@@ -85,6 +86,7 @@ class FixDoubleRedirects extends Maintenance {
if ( !$res->numRows() ) {
$this->output( "No double redirects found.\n" );
+
return;
}
@@ -105,7 +107,8 @@ class FixDoubleRedirects extends Maintenance {
if ( !$async ) {
$success = ( $dryrun ? true : $job->run() );
if ( !$success ) {
- $this->error( "Error fixing " . $titleA->getPrefixedText() . ": " . $job->getLastError() . "\n" );
+ $this->error( "Error fixing " . $titleA->getPrefixedText()
+ . ": " . $job->getLastError() . "\n" );
}
} else {
$jobs[] = $job;
diff --git a/maintenance/fixExtLinksProtocolRelative.php b/maintenance/fixExtLinksProtocolRelative.php
index 02d65ed1..0c60e62c 100644
--- a/maintenance/fixExtLinksProtocolRelative.php
+++ b/maintenance/fixExtLinksProtocolRelative.php
@@ -34,7 +34,8 @@ require_once __DIR__ . '/Maintenance.php';
class FixExtLinksProtocolRelative extends LoggedUpdateMaintenance {
public function __construct() {
parent::__construct();
- $this->mDescription = "Fixes any entries in the externallinks table containing protocol-relative URLs";
+ $this->mDescription =
+ "Fixes any entries in the externallinks table containing protocol-relative URLs";
}
protected function getUpdateKey() {
@@ -49,6 +50,7 @@ class FixExtLinksProtocolRelative extends LoggedUpdateMaintenance {
$db = wfGetDB( DB_MASTER );
if ( !$db->tableExists( 'externallinks' ) ) {
$this->error( "externallinks table does not exist" );
+
return false;
}
$this->output( "Fixing protocol-relative entries in the externallinks table...\n" );
@@ -79,9 +81,18 @@ class FixExtLinksProtocolRelative extends LoggedUpdateMaintenance {
)
), __METHOD__, array( 'IGNORE' )
);
- $db->delete( 'externallinks', array( 'el_index' => $row->el_index, 'el_from' => $row->el_from, 'el_to' => $row->el_to ), __METHOD__ );
+ $db->delete(
+ 'externallinks',
+ array(
+ 'el_index' => $row->el_index,
+ 'el_from' => $row->el_from,
+ 'el_to' => $row->el_to
+ ),
+ __METHOD__
+ );
}
$this->output( "Done, $count rows updated.\n" );
+
return true;
}
}
diff --git a/maintenance/fixSlaveDesync.php b/maintenance/fixSlaveDesync.php
index e4e557fe..a5418ced 100644
--- a/maintenance/fixSlaveDesync.php
+++ b/maintenance/fixSlaveDesync.php
@@ -30,6 +30,9 @@ require_once __DIR__ . '/Maintenance.php';
* @ingroup Maintenance
*/
class FixSlaveDesync extends Maintenance {
+ /** @var array */
+ private $slaveIndexes;
+
public function __construct() {
parent::__construct();
$this->mDescription = "";
@@ -41,7 +44,8 @@ class FixSlaveDesync extends Maintenance {
public function execute() {
$this->slaveIndexes = array();
- for ( $i = 1; $i < wfGetLB()->getServerCount(); $i++ ) {
+ $serverCount = wfGetLB()->getServerCount();
+ for ( $i = 1; $i < $serverCount; $i++ ) {
if ( wfGetLB()->isNonZeroLoad( $i ) ) {
$this->slaveIndexes[] = $i;
}
@@ -66,7 +70,12 @@ class FixSlaveDesync extends Maintenance {
$n = 0;
$dbw = wfGetDB( DB_MASTER );
$masterIDs = array();
- $res = $dbw->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
+ $res = $dbw->select(
+ 'page',
+ array( 'page_id', 'page_latest' ),
+ array( 'page_id<6054123' ),
+ __METHOD__
+ );
$this->output( "Number of pages: " . $res->numRows() . "\n" );
foreach ( $res as $row ) {
$masterIDs[$row->page_id] = $row->page_latest;
@@ -78,7 +87,12 @@ class FixSlaveDesync extends Maintenance {
foreach ( $this->slaveIndexes as $i ) {
$db = wfGetDB( $i );
- $res = $db->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
+ $res = $db->select(
+ 'page',
+ array( 'page_id', 'page_latest' ),
+ array( 'page_id<6054123' ),
+ __METHOD__
+ );
foreach ( $res as $row ) {
if ( isset( $masterIDs[$row->page_id] ) && $masterIDs[$row->page_id] != $row->page_latest ) {
$desync[$row->page_id] = true;
@@ -87,12 +101,13 @@ class FixSlaveDesync extends Maintenance {
}
}
$this->output( "\n" );
+
return $desync;
}
/**
* Fix a broken page entry
- * @param $pageID int The page_id to fix
+ * @param int $pageID The page_id to fix
*/
private function desyncFixPage( $pageID ) {
# Check for a corrupted page_latest
@@ -122,6 +137,7 @@ class FixSlaveDesync extends Maintenance {
if ( !$found ) {
$this->output( "page_id $pageID seems fine\n" );
$dbw->commit( __METHOD__ );
+
return;
}
@@ -141,7 +157,8 @@ class FixSlaveDesync extends Maintenance {
if ( count( $masterIDs ) < count( $slaveIDs ) ) {
$missingIDs = array_diff( $slaveIDs, $masterIDs );
if ( count( $missingIDs ) ) {
- $this->output( "Found " . count( $missingIDs ) . " lost in master, copying from slave... " );
+ $this->output( "Found " . count( $missingIDs )
+ . " lost in master, copying from slave... " );
$dbFrom = $dbw;
$found = true;
$toMaster = true;
@@ -151,7 +168,8 @@ class FixSlaveDesync extends Maintenance {
} else {
$missingIDs = array_diff( $masterIDs, $slaveIDs );
if ( count( $missingIDs ) ) {
- $this->output( "Found " . count( $missingIDs ) . " missing revision(s), copying from master... " );
+ $this->output( "Found " . count( $missingIDs )
+ . " missing revision(s), copying from master... " );
$dbFrom = $dbw;
$found = true;
$toMaster = false;
@@ -199,11 +217,23 @@ class FixSlaveDesync extends Maintenance {
if ( $found ) {
$this->output( "Fixing page_latest... " );
if ( $toMaster ) {
- # $dbw->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), __METHOD__ );
+ /*
+ $dbw->update(
+ 'page',
+ array( 'page_latest' => $realLatest ),
+ array( 'page_id' => $pageID ),
+ __METHOD__
+ );
+ */
} else {
foreach ( $this->slaveIndexes as $i ) {
$db = wfGetDB( $i );
- $db->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), __METHOD__ );
+ $db->update(
+ 'page',
+ array( 'page_latest' => $realLatest ),
+ array( 'page_id' => $pageID ),
+ __METHOD__
+ );
}
}
$this->output( "done\n" );
diff --git a/maintenance/fixTimestamps.php b/maintenance/fixTimestamps.php
index b0609d17..5431cf2c 100644
--- a/maintenance/fixTimestamps.php
+++ b/maintenance/fixTimestamps.php
@@ -85,11 +85,11 @@ class FixTimestamps extends Maintenance {
if ( $sign == 0 || $sign == $expectedSign ) {
// Monotonic change
$lastNormal = $timestamp;
- ++ $numGoodRevs;
+ ++$numGoodRevs;
continue;
} elseif ( abs( $delta ) <= $grace ) {
// Non-monotonic change within grace interval
- ++ $numGoodRevs;
+ ++$numGoodRevs;
continue;
} else {
// Non-monotonic change larger than grace interval
@@ -100,7 +100,7 @@ class FixTimestamps extends Maintenance {
$numBadRevs = count( $badRevs );
if ( $numBadRevs > $numGoodRevs ) {
$this->error(
- "The majority of revisions in the search interval are marked as bad.
+ "The majority of revisions in the search interval are marked as bad.
Are you sure the offset ($offset) has the right sign? Positive means the clock
was incorrectly set forward, negative means the clock was incorrectly set back.
@@ -117,7 +117,8 @@ class FixTimestamps extends Maintenance {
$fixup = -$offset;
$sql = "UPDATE $revisionTable " .
- "SET rev_timestamp=DATE_FORMAT(DATE_ADD(rev_timestamp, INTERVAL $fixup SECOND), '%Y%m%d%H%i%s') " .
+ "SET rev_timestamp="
+ . "DATE_FORMAT(DATE_ADD(rev_timestamp, INTERVAL $fixup SECOND), '%Y%m%d%H%i%s') " .
"WHERE rev_id IN (" . $dbw->makeList( $badRevs ) . ')';
$dbw->query( $sql, __METHOD__ );
$this->output( "Done\n" );
diff --git a/maintenance/fixUserRegistration.php b/maintenance/fixUserRegistration.php
index 097936c9..878593c7 100644
--- a/maintenance/fixUserRegistration.php
+++ b/maintenance/fixUserRegistration.php
@@ -44,10 +44,20 @@ class FixUserRegistration extends Maintenance {
foreach ( $res as $row ) {
$id = $row->user_id;
// Get first edit time
- $timestamp = $dbr->selectField( 'revision', 'MIN(rev_timestamp)', array( 'rev_user' => $id ), __METHOD__ );
+ $timestamp = $dbr->selectField(
+ 'revision',
+ 'MIN(rev_timestamp)',
+ array( 'rev_user' => $id ),
+ __METHOD__
+ );
// Update
if ( !empty( $timestamp ) ) {
- $dbw->update( 'user', array( 'user_registration' => $timestamp ), array( 'user_id' => $id ), __METHOD__ );
+ $dbw->update(
+ 'user',
+ array( 'user_registration' => $timestamp ),
+ array( 'user_id' => $id ),
+ __METHOD__
+ );
$this->output( "$id $timestamp\n" );
} else {
$this->output( "$id NULL\n" );
diff --git a/maintenance/fuzz-tester.php b/maintenance/fuzz-tester.php
deleted file mode 100644
index 548bb2f2..00000000
--- a/maintenance/fuzz-tester.php
+++ /dev/null
@@ -1,2692 +0,0 @@
-<?php
-/**
- * Performs fuzz-style testing of MediaWiki's parser and forms.
- *
- * Copyright © 2006 Nick Jenkins
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- * @author Nick Jenkins ( http://nickj.org/ ).
-
-
-Started: 18 May 2006.
-
-Description:
- Performs fuzz-style testing of MediaWiki's parser and forms.
-
-How:
- - Generate lots of nasty wiki text.
- - Ask the Parser to render that wiki text to HTML, or ask MediaWiki's forms
- to deal with that wiki text.
- - Check MediaWiki's output for problems.
- - Repeat.
-
-Why:
- - To help find bugs.
- - To help find security issues, or potential security issues.
-
-What type of problems are being checked for:
- - Unclosed tags.
- - Errors or interesting warnings from Tidy.
- - PHP errors / warnings / notices.
- - MediaWiki internal errors.
- - Very slow responses.
- - No response from apache.
- - Optionally checking for malformed HTML using the W3C validator.
-
-Background:
- Many of the wikiFuzz class methods are a modified PHP port,
- of a "shameless" Python port, of LCAMTUF'S MANGELME:
- - http://www.securiteam.com/tools/6Z00N1PBFK.html
- - http://www.securityfocus.com/archive/1/378632/2004-10-15/2004-10-21/0
-
-Video:
- There's an XviD video discussing this fuzz tester. You can get it from:
- http://files.nickj.org/MediaWiki/Fuzz-Testing-MediaWiki-xvid.avi
-
-Requirements:
- To run this, you will need:
- - Command-line PHP5, with PHP-curl enabled (not all installations have this
- enabled - try "apt-get install php5-curl" if you're on Debian to install).
- - the Tidy standalone executable. ("apt-get install tidy").
-
-Optional:
- - If you want to run the curl scripts, you'll need standalone curl installed
- ("apt-get install curl")
- - For viewing the W3C validator output on a command line, the "html2text"
- program may be useful ("apt-get install html2text")
-
-Saving tests and test results:
- Any of the fuzz tests which find problems are saved for later review.
- In order to help track down problems, tests are saved in a number of
- different formats. The default filename extensions and their meanings are:
- - ".test.php" : PHP script that reproduces just that one problem using PHP-Curl.
- - ".curl.sh" : Shell script that reproduces that problem using standalone curl.
- - ".data.bin" : The serialized PHP data so that this script can re-run the test.
- - ".info.txt" : A human-readable text file with details of the field contents.
-
-Wiki configuration for testing:
- You should make some additions to LocalSettings.php in order to catch the most
- errors. Note this configuration is for **TESTING PURPOSES ONLY**, and is IN NO
- WAY, SHAPE, OR FORM suitable for deployment on a hostile network. That said,
- personally I find these additions to be the most helpful for testing purposes:
-
- // --------- Start ---------
- // Everyone can do everything. Very useful for testing, yet useless for deployment.
- $wgGroupPermissions['*']['autoconfirmed'] = true;
- $wgGroupPermissions['*']['block'] = true;
- $wgGroupPermissions['*']['bot'] = true;
- $wgGroupPermissions['*']['delete'] = true;
- $wgGroupPermissions['*']['deletedhistory'] = true;
- $wgGroupPermissions['*']['deleterevision'] = true;
- $wgGroupPermissions['*']['editinterface'] = true;
- $wgGroupPermissions['*']['hiderevision'] = true;
- $wgGroupPermissions['*']['import'] = true;
- $wgGroupPermissions['*']['importupload'] = true;
- $wgGroupPermissions['*']['minoredit'] = true;
- $wgGroupPermissions['*']['move'] = true;
- $wgGroupPermissions['*']['patrol'] = true;
- $wgGroupPermissions['*']['protect'] = true;
- $wgGroupPermissions['*']['proxyunbannable'] = true;
- $wgGroupPermissions['*']['renameuser'] = true;
- $wgGroupPermissions['*']['reupload'] = true;
- $wgGroupPermissions['*']['reupload-shared'] = true;
- $wgGroupPermissions['*']['rollback'] = true;
- $wgGroupPermissions['*']['siteadmin'] = true;
- $wgGroupPermissions['*']['unwatchedpages'] = true;
- $wgGroupPermissions['*']['upload'] = true;
- $wgGroupPermissions['*']['userrights'] = true;
- $wgGroupPermissions['*']['renameuser'] = true;
- $wgGroupPermissions['*']['makebot'] = true;
- $wgGroupPermissions['*']['makesysop'] = true;
-
- // Enable weird and wonderful options:
- // Increase default error reporting level.
- error_reporting (E_ALL); // At a later date could be increased to E_ALL | E_STRICT
- $wgEnableUploads = true; // enable uploads.
- $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";
- require_once "extensions/Cite/Cite.php";
- require_once "extensions/inputbox/inputbox.php";
- require_once "extensions/Sort/Sort.php";
- require_once "extensions/wikihiero/wikihiero.php";
- require_once "extensions/CharInsert/CharInsert.php";
- require_once "extensions/FixedImage/FixedImage.php";
-
- // Install & enable Special Page extensions to increase code coverage. E.g.:
- require_once "extensions/Cite/SpecialCite.php";
- require_once "extensions/Renameuser/SpecialRenameuser.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 LocalSettings.php:
- // --------- Start ---------
- $wgEnableProfileInfo = true;
- $wgDBserver = "localhost"; // replace with DB server hostname
- // --------- End ---------
-
-Usage:
- Run with "php fuzz-tester.php".
- To see the various command-line options, run "php fuzz-tester.php --help".
- To stop the script, press Ctrl-C.
-
-Console output:
- - If requested, first any previously failed tests will be rerun.
- - Then new tests will be generated and run. Any tests that fail will be saved,
- and a brief message about why they failed will be printed on the console.
- - The console will show the number of tests run, time run, number of tests
- failed, number of tests being done per minute, and the name of the current test.
-
-TODO:
- Some known things that could improve this script:
- - Logging in with cookie jar storage needed for some tests (as there are some
- pages that cannot be tested without being logged in, and which are currently
- untested - e.g. Special:Emailuser, Special:Preferences, adding to Watchist).
- - Testing of Timeline extension (I cannot test as ploticus has/had issues on
- my architecture).
-
-*/
-
-// ///////////////////////// COMMAND LINE HELP ////////////////////////////////////
-
-// This is a command line script, load MediaWiki env (gives command line options);
-require_once __DIR__ . '/commandLine.inc';
-
-// if the user asked for an explanation of command line options.
-if ( isset( $options["help"] ) ) {
- print <<<ENDS
-MediaWiki $wgVersion fuzz tester
-Usage: php {$_SERVER["SCRIPT_NAME"]} [--quiet] [--base-url=<url-to-test-wiki>]
- [--directory=<failed-test-path>] [--include-binary]
- [--w3c-validate] [--delete-passed-retests] [--help]
- [--user=<username>] [--password=<password>]
- [--rerun-failed-tests] [--max-errors=<int>]
- [--max-runtime=<num-minutes>]
- [--specific-test=<test-name>]
-
-Options:
- --quiet : Hides passed tests, shows only failed tests.
- --base-url : URL to a wiki on which to run the tests.
- The "http://" is optional and can be omitted.
- --directory : Full path to directory for storing failed tests.
- Will be created if it does not exist.
- --include-binary : Includes non-alphanumeric characters in the tests.
- --w3c-validate : Validates pages using the W3C's web validator.
- Slow. Currently many pages fail validation.
- --user : Login name of a valid user on your test wiki.
- --password : Password for the valid user on your test wiki.
- --delete-passed-retests : Will delete retests that now pass.
- Requires --rerun-failed-tests to be meaningful.
- --rerun-failed-tests : Whether to rerun any previously failed tests.
- --max-errors : Maximum number of errors to report before exiting.
- Does not include errors from --rerun-failed-tests
- --max-runtime : Maximum runtime, in minutes, to run before exiting.
- 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:
- If you wanted to fuzz test a nightly MediaWiki checkout using cron for 1 hour,
- and only wanted to be informed of errors, and did not want to redo previously
- failed tests, and wanted a maximum of 100 errors, then you could do:
- php {$_SERVER["SCRIPT_NAME"]} --quiet --max-errors=100 --max-runtime=60
-
-
-ENDS;
-
- exit( 0 );
-}
-
-
-// if we got command line options, check they look valid.
-$validOptions = array ( "quiet", "base-url", "directory", "include-binary",
- "w3c-validate", "user", "password", "delete-passed-retests",
- "rerun-failed-tests", "max-errors",
- "max-runtime", "specific-test", "keep-passed-tests", "help" );
-if ( !empty( $options ) ) {
- $unknownArgs = array_diff ( array_keys( $options ), $validOptions );
- foreach ( $unknownArgs as $invalidArg ) {
- print "Ignoring invalid command-line option: --$invalidArg\n";
- }
-}
-
-
-// /////////////////////////// CONFIGURATION ////////////////////////////////////
-
-// URL to some wiki on which we can run our tests.
-if ( !empty( $options["base-url"] ) ) {
- define( "WIKI_BASE_URL", $options["base-url"] );
-} else {
- define( "WIKI_BASE_URL", $wgServer . $wgScriptPath . '/' );
-}
-
-// The directory name where we store the output.
-// Example for Windows: "c:\\temp\\wiki-fuzz"
-if ( !empty( $options["directory"] ) ) {
- define( "DIRECTORY", $options["directory"] );
-} else {
- define( "DIRECTORY", "{$wgUploadDirectory}/fuzz-tests" );
-}
-
-// Should our test fuzz data include binary strings?
-define( "INCLUDE_BINARY", isset( $options["include-binary"] ) );
-
-// Whether we want to validate HTML output on the web.
-// At the moment very few generated pages will validate, so not recommended.
-define( "VALIDATE_ON_WEB", isset( $options["w3c-validate"] ) );
-// URL to use to validate our output:
-define( "VALIDATOR_URL", "http://validator.w3.org/check" );
-
-// Location of Tidy standalone executable.
-define( "PATH_TO_TIDY", "/usr/bin/tidy" );
-
-// The name of a user who has edited on your wiki. Used
-// when testing the Special:Contributions and Special:Userlogin page.
-if ( !empty( $options["user"] ) ) {
- define( "USER_ON_WIKI", $options["user"] );
-} else {
- define( "USER_ON_WIKI", "nickj" );
-}
-
-// The password of the above user. Used when testing the login page,
-// and to do this we sometimes need to login successfully.
-if ( !empty( $options["password"] ) ) {
- define( "USER_PASSWORD", $options["password"] );
-} else {
- // And no, this is not a valid password on any public wiki.
- define( "USER_PASSWORD", "nickj" );
-}
-
-// If we have a test that failed, and then we run it again, and it passes,
-// do you want to delete it or keep it?
-define( "DELETE_PASSED_RETESTS", isset( $options["delete-passed-retests"] ) );
-
-// Do we want to rerun old saved tests at script startup?
-// Set to true to help catch regressions, or false if you only want new stuff.
-define( "RERUN_OLD_TESTS", isset( $options["rerun-failed-tests"] ) );
-
-// File where the database errors are logged. Should be defined in LocalSettings.php.
-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"] ) );
-}
-
-// The maximum number of problems to find, if specified. Excludes retest errors.
-if ( !empty( $options["max-errors"] ) && intval( $options["max-errors"] ) > 0 ) {
- define( "MAX_ERRORS", intval( $options["max-errors"] ) );
-}
-
-// if the user has requested a specific test (instead of all tests), and the test they asked for looks valid.
-if ( !empty( $options["specific-test"] ) ) {
- if ( class_exists( $options["specific-test"] ) && get_parent_class( $options["specific-test"] ) == "pageTest" ) {
- define( "SPECIFIC_TEST", $options["specific-test"] );
- }
- else {
- print "Ignoring invalid --specific-test\n";
- }
-}
-
-// Define the file extensions we'll use:
-define( "PHP_TEST" , ".test.php" );
-define( "CURL_TEST", ".curl.sh" );
-define( "DATA_FILE", ".data.bin" );
-define( "INFO_FILE", ".info.txt" );
-define( "HTML_FILE", ".wiki_preview.html" );
-
-// If it goes wrong, we want to know about it.
-error_reporting( E_ALL | E_STRICT );
-
-// ////////////// A CLASS THAT GENERATES RANDOM NASTY WIKI & HTML STRINGS //////////////////////
-
-class wikiFuzz {
-
- // Only some HTML tags are understood with params by MediaWiki, the rest are ignored.
- // List the tags that accept params below, as well as what those params are.
- public static $data = array(
- "B" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "CAPTION" => array( "CLASS", "ID", "STYLE", "align", "lang", "dir", "title" ),
- "CENTER" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title" ),
- "DIV" => array( "CLASS", "STYLE", "ID", "align", "lang", "dir", "title" ),
- "FONT" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title", "face", "size", "color" ),
- "H1" => array( "STYLE", "CLASS", "ID", "align", "lang", "dir", "title" ),
- "H2" => array( "STYLE", "CLASS", "ID", "align", "lang", "dir", "title" ),
- "HR" => array( "STYLE", "CLASS", "ID", "WIDTH", "lang", "dir", "title", "size", "noshade" ),
- "LI" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "type", "value" ),
- "TABLE" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "BORDER", "CELLPADDING",
- "CELLSPACING", "lang", "dir", "title", "summary", "frame", "rules" ),
- "TD" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "COLSPAN", "ROWSPAN",
- "VALIGN", "abbr", "axis", "headers", "scope", "nowrap", "height", "lang",
- "dir", "title", "char", "charoff" ),
- "TH" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "COLSPAN", "ROWSPAN",
- "VALIGN", "abbr", "axis", "headers", "scope", "nowrap", "height", "lang",
- "dir", "title", "char", "charoff" ),
- "TR" => array( "CLASS", "STYLE", "ID", "BGCOLOR", "ALIGN", "VALIGN", "lang", "dir", "title", "char", "charoff" ),
- "UL" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title", "type" ),
- "P" => array( "style", "class", "id", "align", "lang", "dir", "title" ),
- "blockquote" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "cite" ),
- "span" => array( "CLASS", "ID", "STYLE", "align", "lang", "dir", "title" ),
- "code" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "tt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "small" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "big" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "s" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "u" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "del" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "datetime", "cite" ),
- "ins" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "datetime", "cite" ),
- "sub" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "sup" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "ol" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "type", "start" ),
- "br" => array( "CLASS", "ID", "STYLE", "title", "clear" ),
- "cite" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "var" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "ruby" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "rt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "rp" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "dt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "dl" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "em" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "strong" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "i" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
- "thead" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ),
- "tfoot" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ),
- "tbody" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ),
- "colgroup" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign', 'span', 'width' ),
- "col" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign', 'span', 'width' ),
- "pre" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "width" ),
-
- // extension tags that accept parameters:
- "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
- // Note: this needs to be initialized later to be equal to: array_keys(wikiFuzz::$data);
- // as such, it also needs to also be publicly modifiable.
- public static $types;
-
-
- // Some attribute values.
- static private $other = array( "&", "=", ":", "?", "\"", "\n", "%n%n%n%n%n%n%n%n%n%n%n%n", "\\" );
- static private $ints = array(
- // various numbers
- "0", "-1", "127", "-7897", "89000", "808080", "90928345",
- "0xfffffff", "ffff",
-
- // Different ways of saying: '
- "&#0000039;", // Long UTF-8 Unicode encoding
- "&#39;", // dec version.
- "&#x27;", // hex version.
- "&#xA7;", // malformed hex variant, MSB not zero.
-
- // Different ways of saying: "
- "&#0000034;", // Long UTF-8 Unicode encoding
- "&#34;",
- "&#x22;", // hex version.
- "&#xA2;", // malformed hex variant, MSB not zero.
-
- // Different ways of saying: <
- "<",
- "&#0000060", // Long UTF-8 Unicode encoding without semicolon (Mediawiki wants the colon)
- "&#0000060;", // Long UTF-8 Unicode encoding with semicolon
- "&#60;",
- "&#x3C;", // hex version.
- "&#xBC;", // malformed hex variant, MSB not zero.
- "&#x0003C;", // mid-length hex version
- "&#X00003C;", // slightly longer hex version, with capital "X"
-
- // Different ways of saying: >
- ">",
- "&#0000062;", // Long UTF-8 Unicode encoding
- "&#62;",
- "&#x3E;", // hex version.
- "&#xBE;", // malformed variant, MSB not zero.
-
- // Different ways of saying: [
- "&#0000091;", // Long UTF-8 Unicode encoding
- "&#91;",
- "&#x5B;", // hex version.
-
- // Different ways of saying: {{
- "&#0000123;&#0000123;", // Long UTF-8 Unicode encoding
- "&#123;&#123;",
- "&#x7B;&#x7B;", // hex version.
-
- // Different ways of saying: |
- "&#0000124;", // Long UTF-8 Unicode encoding
- "&#124;",
- "&#x7C;", // hex version.
- "&#xFC;", // malformed hex variant, MSB not zero.
-
- // a "lignature" - http://www.robinlionheart.com/stds/html4/spchars#ligature
- // &#8204; == &zwnj;
- "&#8204;"
- );
-
- // Defines various wiki-related bits of syntax, that can potentially cause
- // MediaWiki to do something other than just print that literal text.
- static private $ext = array(
- // links, templates, parameters.
- "[[", "]]", "{{", "}}", "|", "[", "]", "{{{", "}}}", "|]]",
-
- // wiki tables.
- "\n{|", "\n|}",
- "!",
- "\n!",
- "!!",
- "||",
- "\n|-", "| ", "\n|",
-
- // section headings.
- "=", "==", "===", "====", "=====", "======",
-
- // lists (ordered and unordered) and indentation.
- "\n*", "*", "\n:", ":",
- "\n#", "#",
-
- // definition lists (dl, dt, dd), newline, and newline with pre, and a tab.
- "\n;", ";", "\n ",
-
- // Whitespace: newline, tab, space.
- "\n", "\t", " ",
-
- // Some XSS attack vectors from http://ha.ckers.org/xss.html
- "&#x09;", // tab
- "&#x0A;", // newline
- "&#x0D;", // carriage return
- "\0", // null character
- " &#14; ", // spaces and meta characters
- "'';!--\"<XSS>=&{()}", // compact injection of XSS & SQL tester
-
- // various NULL fields
- "%00",
- "&#00;",
- "\0",
-
- // horizontal rule.
- "-----", "\n-----",
-
- // signature, redirect, bold, italics.
- "~~~~", "#REDIRECT [[", "'''", "''",
-
- // comments.
- "<!--", "-->",
-
- // quotes.
- "\"", "'",
-
- // tag start and tag end.
- "<", ">",
-
- // implicit link creation on URIs.
- "http://",
- "https://",
- "ftp://",
- "irc://",
- "news:",
- 'gopher://',
- 'telnet://',
- 'nntp://',
- 'worldwind://',
- 'mailto:',
-
- // images.
- "[[image:",
- ".gif",
- ".png",
- ".jpg",
- ".jpeg",
- 'thumbnail=',
- 'thumbnail',
- 'thumb=',
- 'thumb',
- 'right',
- 'none',
- 'left',
- 'framed',
- 'frame',
- 'enframed',
- 'centre',
- 'center',
- "Image:",
- "[[:Image",
- 'px',
- 'upright=',
- 'border',
-
- // misc stuff to throw at the Parser.
- '%08X',
- '/',
- ":x{|",
- "\n|+",
- "<noinclude>",
- "</noinclude>",
- " \302\273",
- " :",
- " !",
- " ;",
- "\302\253",
- "[[category:",
- "?=",
- "(",
- ")",
- "]]]",
- "../",
- "{{{{",
- "}}}}",
- "[[Special:",
- "<includeonly>",
- "</includeonly>",
- "<!--MWTEMPLATESECTION=",
- '<!--MWTOC-->',
-
- // implicit link creation on booknum, RFC, and PubMed ID usage (both with and without IDs)
- "ISBN 2",
- "RFC 000",
- "PMID 000",
- "ISBN ",
- "RFC ",
- "PMID ",
-
- // magic words:
- '__NOTOC__',
- '__FORCETOC__',
- '__NOEDITSECTION__',
- '__START__',
- '__NOTITLECONVERT__',
- '__NOCONTENTCONVERT__',
- '__END__',
- '__TOC__',
- '__NOTC__',
- '__NOCC__',
- "__FORCETOC__",
- "__NEWSECTIONLINK__",
- "__NOGALLERY__",
-
- // more magic words / internal templates.
- '{{PAGENAME}}',
- '{{PAGENAMEE}}',
- '{{NAMESPACE}}',
- "{{MSG:",
- "}}",
- "{{MSGNW:",
- "}}",
- "{{INT:",
- "}}",
- '{{SITENAME}}',
- "{{NS:",
- "}}",
- "{{LOCALURL:",
- "}}",
- "{{LOCALURLE:",
- "}}",
- "{{SCRIPTPATH}}",
- "{{GRAMMAR:gentiv|",
- "}}",
- "{{REVISIONID}}",
- "{{SUBPAGENAME}}",
- "{{SUBPAGENAMEE}}",
- "{{ns:0}}",
- "{{fullurle:",
- "}}",
- "{{subst::",
- "}}",
- "{{UCFIRST:",
- "}}",
- "{{UC:",
- '{{SERVERNAME}}',
- '{{SERVER}}',
- "{{RAW:",
- "}}",
- "{{PLURAL:",
- "}}",
- "{{LCFIRST:",
- "}}",
- "{{LC:",
- "}}",
- '{{CURRENTWEEK}}',
- '{{CURRENTDOW}}',
- "{{INT:{{LC:contribs-showhideminor}}|",
- "}}",
- "{{INT:googlesearch|",
- "}}",
- "{{ROOTPAGENAME}}",
- "{{BASEPAGENAME}}",
- "{{CONTENTLANGUAGE}}",
- "{{PAGESINNAMESPACE:}}",
- "{{#language:",
- "}}",
- "{{#special:",
- "}}",
- "{{#special:emailuser",
- "}}",
-
- // Some raw link for magic words.
- "{{NUMBEROFPAGES:R",
- "}}",
- "{{NUMBEROFUSERS:R",
- "}}",
- "{{NUMBEROFARTICLES:R",
- "}}",
- "{{NUMBEROFFILES:R",
- "}}",
- "{{NUMBEROFADMINS:R",
- "}}",
- "{{padleft:",
- "}}",
- "{{padright:",
- "}}",
- "{{DEFAULTSORT:",
- "}}",
-
- // internal Math "extension":
- "<math>",
- "</math>",
-
- // Parser extension functions:
- "{{#expr:",
- "{{#if:",
- "{{#ifeq:",
- "{{#ifexist:",
- "{{#ifexpr:",
- "{{#switch:",
- "{{#time:",
- "}}",
-
- // references table for the Cite extension.
- "<references/>",
-
- // Internal Parser tokens - try inserting some of these.
- "UNIQ25f46b0524f13e67NOPARSE",
- "UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002",
- "\x07UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002-QINU",
-
- // Inputbox extension:
- "<inputbox>\ntype=search\nsearchbuttonlabel=\n",
- "</inputbox>",
-
- // charInsert extension:
- "<charInsert>",
- "</charInsert>",
-
- // wikiHiero extension:
- "<hiero>",
- "</hiero>",
-
- // Image gallery:
- "<gallery>",
- "</gallery>",
-
- // FixedImage extension.
- "<fundraising/>",
-
- // Timeline extension: currently untested.
-
- // Nowiki:
- "<nOwIkI>",
- "</nowiki>",
-
- // an external image to test the external image displaying code
- "http://debian.org/Pics/debian.png",
-
- // LabeledSectionTransclusion extension.
- "{{#lstx:",
- "}}",
- "{{#lst:",
- "}}",
- "{{#lst:Main Page|",
- "}}"
- );
-
- /**
- ** Randomly returns one element of the input array.
- */
- public static function chooseInput( array $input ) {
- $randindex = wikiFuzz::randnum( count( $input ) - 1 );
- return $input[$randindex];
- }
-
- // Max number of parameters for HTML attributes.
- static private $maxparams = 10;
-
- /**
- * Returns random number between finish and start.
- * @param $finish
- * @param $start int
- * @return int
- */
- public static function randnum( $finish, $start = 0 ) {
- return mt_rand( $start, $finish );
- }
-
- /**
- * Returns a mix of random text and random wiki syntax.
- * @return string
- */
- private static function randstring() {
- $thestring = "";
-
- for ( $i = 0; $i < 40; $i++ ) {
- $what = wikiFuzz::randnum( 1 );
-
- if ( $what == 0 ) { // include some random wiki syntax
- $which = wikiFuzz::randnum( count( wikiFuzz::$ext ) - 1 );
- $thestring .= wikiFuzz::$ext[$which];
- }
- else { // include some random text
- $char = INCLUDE_BINARY
- // Decimal version:
- // "&#" . 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 );
- $thestring .= str_repeat ( $char, $length );
- }
- }
- return $thestring;
- }
-
- /**
- * Returns either random text, or random wiki syntax, or random data from "ints",
- * or random data from "other".
- * @return string
- */
- private static function makestring() {
- $what = wikiFuzz::randnum( 2 );
- if ( $what == 0 ) {
- return wikiFuzz::randstring();
- } elseif ( $what == 1 ) {
- return wikiFuzz::$ints[wikiFuzz::randnum( count( wikiFuzz::$ints ) - 1 )];
- } else {
- return wikiFuzz::$other[wikiFuzz::randnum( count( wikiFuzz::$other ) - 1 )];
- }
- }
-
- /**
- * Returns the matched character slash-escaped as in a C string
- * Helper for makeTitleSafe callback
- * @param $matches
- * @return string
- */
- private static function stringEscape( $matches ) {
- return sprintf( "\\x%02x", ord( $matches[1] ) );
- }
-
- /**
- ** Strips out the stuff that Mediawiki balks at in a page's title.
- ** Implementation copied/pasted from cleanupTable.inc & cleanupImages.php
- * @param $str string
- * @return string
- */
- public static function makeTitleSafe( $str ) {
- $legalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF";
- return preg_replace_callback(
- "/([^$legalTitleChars])/", 'wikiFuzz::stringEscape',
- $str );
- }
-
- /**
- ** Returns a string of fuzz text.
- * @return string
- */
- private static function loop() {
- switch ( wikiFuzz::randnum( 3 ) ) {
- case 1: // an opening tag, with parameters.
- $string = "";
- $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 );
- $t = wikiFuzz::$types[$i];
- $arr = wikiFuzz::$data[$t];
- $string .= "<" . $t . " ";
- $num_params = min( wikiFuzz::$maxparams, count( $arr ) );
- for ( $z = 0; $z < $num_params; $z++ ) {
- $badparam = $arr[wikiFuzz::randnum( count( $arr ) - 1 )];
- $badstring = wikiFuzz::makestring();
- $string .= $badparam . "=" . wikiFuzz::getRandQuote() . $badstring . wikiFuzz::getRandQuote() . " ";
- }
- $string .= ">\n";
- return $string;
- case 2: // a closing tag.
- $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 );
- return "</" . wikiFuzz::$types[$i] . ">";
- case 3: // a random string, between tags.
- return wikiFuzz::makeString();
- }
- return ""; // catch-all, should never be called.
- }
-
- /**
- * Returns one of the three styles of random quote: ', ", and nothing.
- * @return string
- */
- private static function getRandQuote() {
- switch ( wikiFuzz::randnum( 3 ) ) {
- case 1 : return "'";
- case 2 : return "\"";
- default: return "";
- }
- }
-
- /**
- ** Returns fuzz text, with the parameter indicating approximately how many lines of text you want.
- * @param $maxtypes int
- * @return string
- */
- public static function makeFuzz( $maxtypes = 2 ) {
- $page = "";
- for ( $k = 0; $k < $maxtypes; $k++ ) {
- $page .= wikiFuzz::loop();
- }
- return $page;
- }
-}
-
-
-// ////// MEDIAWIKI PAGES TO TEST, AND HOW TO TEST THEM ///////
-
-/**
- ** A page test has just these things:
- ** 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.
- */
-abstract class pageTest {
- protected $params;
- protected $pagePath;
- protected $cookie = "";
- protected $tidyValidate = true;
-
- public function getParams() {
- return $this->params;
- }
-
- public function getPagePath() {
- return $this->pagePath;
- }
-
- public function getCookie() {
- return $this->cookie;
- }
-
- public function tidyValidate() {
- return $this->tidyValidate;
- }
-}
-
-
-/**
- ** a page test for the "Edit" page. Tests Parser.php and Sanitizer.php.
- */
-class editPageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=WIKIFUZZ";
-
- $this->params = array (
- "action" => "submit",
- "wpMinoredit" => wikiFuzz::makeFuzz( 2 ),
- "wpPreview" => wikiFuzz::makeFuzz( 2 ),
- "wpSection" => wikiFuzz::makeFuzz( 2 ),
- "wpEdittime" => wikiFuzz::makeFuzz( 2 ),
- "wpSummary" => wikiFuzz::makeFuzz( 2 ),
- "wpScrolltop" => wikiFuzz::makeFuzz( 2 ),
- "wpStarttime" => wikiFuzz::makeFuzz( 2 ),
- "wpAutoSummary" => wikiFuzz::makeFuzz( 2 ),
- "wpTextbox1" => wikiFuzz::makeFuzz( 40 ) // the main wiki text, need lots of this.
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSection"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEdittime"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSummary"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpScrolltop"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpStarttime"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpAutoSummary"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpTextbox1"] );
- }
-}
-
-
-/**
- ** a page test for "Special:Listusers".
- */
-class listusersTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Listusers";
-
- $this->params = array (
- "title" => wikiFuzz::makeFuzz( 2 ),
- "group" => wikiFuzz::makeFuzz( 2 ),
- "username" => wikiFuzz::makeFuzz( 2 ),
- "Go" => wikiFuzz::makeFuzz( 2 ),
- "limit" => wikiFuzz::chooseInput( array( "0", "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- "offset" => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) )
- );
- }
-}
-
-
-/**
- ** a page test for "Special:Search".
- */
-class searchTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Search";
-
- $this->params = array (
- "action" => "index.php?title=Special:Search",
- "ns0" => wikiFuzz::makeFuzz( 2 ),
- "ns1" => wikiFuzz::makeFuzz( 2 ),
- "ns2" => wikiFuzz::makeFuzz( 2 ),
- "ns3" => wikiFuzz::makeFuzz( 2 ),
- "ns4" => wikiFuzz::makeFuzz( 2 ),
- "ns5" => wikiFuzz::makeFuzz( 2 ),
- "ns6" => wikiFuzz::makeFuzz( 2 ),
- "ns7" => wikiFuzz::makeFuzz( 2 ),
- "ns8" => wikiFuzz::makeFuzz( 2 ),
- "ns9" => wikiFuzz::makeFuzz( 2 ),
- "ns10" => wikiFuzz::makeFuzz( 2 ),
- "ns11" => wikiFuzz::makeFuzz( 2 ),
- "ns12" => wikiFuzz::makeFuzz( 2 ),
- "ns13" => wikiFuzz::makeFuzz( 2 ),
- "ns14" => wikiFuzz::makeFuzz( 2 ),
- "ns15" => wikiFuzz::makeFuzz( 2 ),
- "redirs" => wikiFuzz::makeFuzz( 2 ),
- "search" => wikiFuzz::makeFuzz( 2 ),
- "offset" => wikiFuzz::chooseInput( array( "", "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) ),
- "fulltext" => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) ),
- "searchx" => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) )
- );
- }
-}
-
-
-/**
- ** a page test for "Special:Recentchanges".
- */
-class recentchangesTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Recentchanges";
-
- $this->params = array (
- "action" => wikiFuzz::makeFuzz( 2 ),
- "title" => wikiFuzz::makeFuzz( 2 ),
- "namespace" => wikiFuzz::chooseInput( range( -1, 15 ) ),
- "Go" => wikiFuzz::makeFuzz( 2 ),
- "invert" => wikiFuzz::chooseInput( array( "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- "hideanons" => wikiFuzz::chooseInput( array( "-1", "------'-------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "---------'----0", "+1", "81340909772349234", wikiFuzz::makeFuzz( 2 ) ) ),
- "days" => wikiFuzz::chooseInput( array( "-1", "----------'---0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- "hideminor" => wikiFuzz::chooseInput( array( "-1", "-----------'--0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- "hidebots" => wikiFuzz::chooseInput( array( "-1", "---------'----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- "hideliu" => wikiFuzz::chooseInput( array( "-1", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- "hidepatrolled" => wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- "hidemyself" => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- 'categories_any' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- 'categories' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- 'feed' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) )
- );
- }
-}
-
-
-/**
- ** a page test for "Special:Prefixindex".
- */
-class prefixindexTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Prefixindex";
-
- $this->params = array (
- "title" => "Special:Prefixindex",
- "namespace" => wikiFuzz::randnum( 101, -10 ),
- "Go" => wikiFuzz::makeFuzz( 2 )
- );
-
- // sometimes we want 'prefix', sometimes we want 'from', and sometimes we want nothing.
- if ( wikiFuzz::randnum( 3 ) == 0 ) {
- $this->params["prefix"] = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1",
- wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) );
- }
- if ( wikiFuzz::randnum( 3 ) == 0 ) {
- $this->params["from"] = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1",
- wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) );
- }
- }
-}
-
-
-/**
- ** a page test for "Special:MIMEsearch".
- */
-class mimeSearchTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:MIMEsearch";
-
- $this->params = array (
- "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 ) ) )
- );
- }
-}
-
-
-/**
- ** a page test for "Special:Log".
- */
-class specialLogTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Log";
-
- $this->params = array (
- "type" => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
- "par" => wikiFuzz::makeFuzz( 2 ),
- "user" => wikiFuzz::makeFuzz( 2 ),
- "page" => wikiFuzz::makeFuzz( 2 ),
- "from" => wikiFuzz::makeFuzz( 2 ),
- "until" => wikiFuzz::makeFuzz( 2 ),
- "title" => wikiFuzz::makeFuzz( 2 )
- );
- }
-}
-
-
-/**
- ** a page test for "Special:Userlogin", with a successful login.
- */
-class successfulUserLoginTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Userlogin&action=submitlogin&type=login&returnto=" . wikiFuzz::makeFuzz( 2 );
-
- $this->params = array (
- "wpName" => USER_ON_WIKI,
- // sometimes real password, sometimes not:
- 'wpPassword' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), USER_PASSWORD ) ),
- 'wpRemember' => wikiFuzz::makeFuzz( 2 )
- );
-
- $this->cookie = "wikidb_session=" . wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) );
- }
-}
-
-
-/**
- ** a page test for "Special:Userlogin".
- */
-class userLoginTest extends pageTest {
- function __construct() {
-
- $this->pagePath = "index.php?title=Special:Userlogin";
-
- $this->params = array (
- 'wpRetype' => wikiFuzz::makeFuzz( 2 ),
- 'wpRemember' => wikiFuzz::makeFuzz( 2 ),
- 'wpRealName' => wikiFuzz::makeFuzz( 2 ),
- 'wpPassword' => wikiFuzz::makeFuzz( 2 ),
- 'wpName' => wikiFuzz::makeFuzz( 2 ),
- 'wpMailmypassword' => wikiFuzz::makeFuzz( 2 ),
- 'wpLoginattempt' => wikiFuzz::makeFuzz( 2 ),
- 'wpEmail' => wikiFuzz::makeFuzz( 2 ),
- 'wpDomain' => wikiFuzz::chooseInput( array( "", "local", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpCreateaccountMail' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpCreateaccount' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpCookieCheck' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'type' => wikiFuzz::chooseInput( array( "signup", "login", "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'returnto' => wikiFuzz::makeFuzz( 2 ),
- 'action' => wikiFuzz::chooseInput( array( "", "submitlogin", wikiFuzz::makeFuzz( 2 ) ) )
- );
-
- $this->cookie = "wikidb_session=" . wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) );
- }
-}
-
-
-/**
- ** a page test for "Special:Ipblocklist" (also includes unblocking)
- */
-class ipblocklistTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Ipblocklist";
-
- $this->params = array (
- 'wpUnblockAddress' => wikiFuzz::makeFuzz( 2 ),
- 'ip' => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
- // something like an IP address, sometimes invalid:
- ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
- . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
- 'id' => wikiFuzz::makeFuzz( 2 ),
- 'wpUnblockReason' => wikiFuzz::makeFuzz( 2 ),
- 'action' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "success", "submit", "unblock" ) ),
- 'wpEditToken' => wikiFuzz::makeFuzz( 2 ),
- 'wpBlock' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "" ) ),
- 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1",
- "09700982312351132098234", wikiFuzz::makeFuzz( 2 ) ) ),
- 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1",
- "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) )
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["ip"] );
- if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["id"] );
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpUnblockAddress"] );
- }
-}
-
-
-/**
- ** a page test for "Special:Newimages".
- */
-class newImagesTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Newimages";
-
- $this->params = array (
- 'hidebots' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "1", "", "-1" ) ),
- 'wpIlMatch' => wikiFuzz::makeFuzz( 2 ),
- 'until' => wikiFuzz::makeFuzz( 2 ),
- 'from' => wikiFuzz::makeFuzz( 2 )
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["until"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["from"] );
- }
-}
-
-
-/**
- ** a page test for the "Special:Imagelist" page.
- */
-class imagelistTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Imagelist";
-
- $this->params = array (
- 'sort' => wikiFuzz::chooseInput( array( "bysize", "byname" , "bydate", wikiFuzz::makeFuzz( 2 ) ) ),
- 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "09700982312351132098234", wikiFuzz::makeFuzz( 2 ) ) ),
- 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpIlMatch' => wikiFuzz::makeFuzz( 2 )
- );
- }
-}
-
-
-/**
- ** a page test for "Special:Export".
- */
-class specialExportTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Export";
-
- $this->params = array (
- 'action' => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'pages' => wikiFuzz::makeFuzz( 2 ),
- 'curonly' => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ),
- 'listauthors' => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ),
- 'history' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ),
-
- );
-
- // For the time being, need to disable "submit" action as Tidy barfs on MediaWiki's XML export.
- if ( $this->params['action'] == 'submit' ) $this->params['action'] = '';
-
- // Sometimes remove the history field.
- if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["history"] );
-
- // page does not produce HTML.
- $this->tidyValidate = false;
- }
-}
-
-
-/**
- ** a page test for "Special:Booksources".
- */
-class specialBooksourcesTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Booksources";
-
- $this->params = array (
- 'go' => wikiFuzz::makeFuzz( 2 ),
- // ISBN codes have to contain some semi-numeric stuff or will be ignored:
- 'isbn' => "0X0" . wikiFuzz::makeFuzz( 2 )
- );
- }
-}
-
-
-/**
- ** a page test for "Special:Allpages".
- */
-class specialAllpagesTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special%3AAllpages";
-
- $this->params = array (
- 'from' => wikiFuzz::makeFuzz( 2 ),
- 'namespace' => wikiFuzz::chooseInput( range( -1, 15 ) ),
- 'go' => wikiFuzz::makeFuzz( 2 )
- );
- }
-}
-
-
-/**
- ** a page test for the page History.
- */
-class pageHistoryTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Main_Page&action=history";
-
- $this->params = array (
- 'limit' => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- 'offset' => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ),
- "go" => wikiFuzz::chooseInput( array( "first", "last", wikiFuzz::makeFuzz( 2 ) ) ),
- "dir" => wikiFuzz::chooseInput( array( "prev", "next", wikiFuzz::makeFuzz( 2 ) ) ),
- "diff" => wikiFuzz::chooseInput( array( "-1", "--------'-----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- "oldid" => wikiFuzz::chooseInput( array( "prev", "-1", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- "feed" => wikiFuzz::makeFuzz( 2 )
- );
- }
-}
-
-
-/**
- ** a page test for the Special:Contributions".
- */
-class contributionsTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Contributions/" . USER_ON_WIKI;
-
- $this->params = array (
- '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 ) ) ),
- 'go' => wikiFuzz::chooseInput( array( "-1", 'prev', 'next', wikiFuzz::makeFuzz( 2 ) ) )
- );
- }
-}
-
-
-/**
- ** a page test for viewing a normal page, whilst posting various params.
- */
-class viewPageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Main_Page";
-
- $this->params = array (
- "useskin" => wikiFuzz::chooseInput( array( "chick", "cologneblue", "myskin",
- "nostalgia", "simple", "standard", wikiFuzz::makeFuzz( 2 ) ) ),
- "uselang" => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ),
- "ab", "af", "an", "ar", "arc", "as", "ast", "av", "ay", "az", "ba",
- "bat-smg", "be", "bg", "bm", "bn", "bo", "bpy", "br", "bs", "ca",
- "ce", "cs", "csb", "cv", "cy", "da", "de", "dv", "dz", "el", "en",
- "eo", "es", "et", "eu", "fa", "fi", "fo", "fr", "fur", "fy", "ga",
- "gn", "gsw", "gu", "he", "hi", "hr", "hu", "ia", "id", "ii", "is",
- "it", "ja", "jv", "ka", "km", "kn", "ko", "ks", "ku", "kv", "la",
- "li", "lo", "lt", "lv", "mk", "ml", "ms", "nah", "nap", "nds",
- "nds-nl", "nl", "nn", "no", "non", "nv", "oc", "or", "os", "pa",
- "pl", "pms", "ps", "pt", "pt-br", "qu", "rmy", "ro", "ru", "sc",
- "sd", "sk", "sl", "sq", "sr", "sr-ec", "sr-el",
- "su", "sv", "ta", "te", "th", "tr", "tt", "ty", "tyv", "udm",
- "ug", "uk", "ur", "utf8", "vec", "vi", "wa", "xal", "yi", "za",
- "zh", "zh-cn", "zh-hk", "zh-sg", "zh-tw", "zh-tw" ) ),
- "returnto" => wikiFuzz::makeFuzz( 2 ),
- "feed" => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ),
- "rcid" => wikiFuzz::makeFuzz( 2 ),
- "action" => wikiFuzz::chooseInput( array( "view", "raw", "render", wikiFuzz::makeFuzz( 2 ), "markpatrolled" ) ),
- "printable" => wikiFuzz::makeFuzz( 2 ),
- "oldid" => wikiFuzz::makeFuzz( 2 ),
- "redirect" => wikiFuzz::makeFuzz( 2 ),
- "diff" => wikiFuzz::makeFuzz( 2 ),
- "search" => wikiFuzz::makeFuzz( 2 ),
- "rdfrom" => wikiFuzz::makeFuzz( 2 ), // things from Article.php from here on:
- "token" => wikiFuzz::makeFuzz( 2 ),
- "tbid" => wikiFuzz::makeFuzz( 2 ),
- // @todo FIXME: Duplicate array key.
- "action" => wikiFuzz::chooseInput( array( "purge", wikiFuzz::makeFuzz( 2 ) ) ),
- "wpReason" => wikiFuzz::makeFuzz( 2 ),
- "wpEditToken" => wikiFuzz::makeFuzz( 2 ),
- "from" => wikiFuzz::makeFuzz( 2 ),
- "bot" => wikiFuzz::makeFuzz( 2 ),
- "summary" => wikiFuzz::makeFuzz( 2 ),
- "direction" => wikiFuzz::chooseInput( array( "next", "prev", wikiFuzz::makeFuzz( 2 ) ) ),
- "section" => wikiFuzz::makeFuzz( 2 ),
- "preload" => wikiFuzz::makeFuzz( 2 ),
-
- );
-
- // 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"] ); }
- elseif ( $this->params["feed"] == "rss" ) { unset( $this->params["feed"] ); }
-
- // Raw pages cannot really be validated
- if ( $this->params["action"] == "raw" ) unset( $this->params["action"] );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["rcid"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["diff"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["rdfrom"] );
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["oldid"] );
-
- // usually don't want action == purge.
- if ( wikiFuzz::randnum( 6 ) > 1 ) unset( $this->params["action"] );
- }
-}
-
-
-/**
- ** a page test for "Special:Allmessages".
- */
-class specialAllmessagesTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Allmessages";
-
- // only really has one parameter
- $this->params = array (
- "ot" => wikiFuzz::chooseInput( array( "php", "html", wikiFuzz::makeFuzz( 2 ) ) )
- );
- }
-}
-
-/**
- ** a page test for "Special:Newpages".
- */
-class specialNewpagesPageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Newpages";
-
- $this->params = array (
- "namespace" => wikiFuzz::chooseInput( range( -1, 15 ) ),
- "feed" => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ),
- 'limit' => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
- 'offset' => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) )
- );
-
- // 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"] ); }
- elseif ( $this->params["feed"] == "rss" ) { unset( $this->params["feed"] ); }
- }
-}
-
-/**
- ** a page test for "redirect.php"
- */
-class redirectTest extends pageTest {
- function __construct() {
- $this->pagePath = "redirect.php";
-
- $this->params = array (
- "wpDropdown" => wikiFuzz::makeFuzz( 2 )
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpDropdown"] );
- }
-}
-
-
-/**
- ** a page test for "Special:Confirmemail"
- */
-class confirmEmail extends pageTest {
- function __construct() {
- // sometimes we send a bogus confirmation code, and sometimes we don't.
- $this->pagePath = "index.php?title=Special:Confirmemail" . wikiFuzz::chooseInput( array( "", "/" . wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 1 ) ) ) );
-
- $this->params = array (
- "token" => wikiFuzz::makeFuzz( 2 )
- );
- }
-}
-
-
-/**
- ** a page test for "Special:Watchlist"
- ** Note: this test would be better if we were logged in.
- */
-class watchlistTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Watchlist";
-
- $this->params = array (
- "remove" => wikiFuzz::chooseInput( array( "Remove checked items from watchlist", wikiFuzz::makeFuzz( 2 ) ) ),
- 'days' => wikiFuzz::chooseInput( array( 0, -1, -230, "--", 3, 9, wikiFuzz::makeFuzz( 2 ) ) ),
- 'hideOwn' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
- 'hideBots' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
- 'namespace' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
- 'action' => wikiFuzz::chooseInput( array( "submit", "clear", wikiFuzz::makeFuzz( 2 ) ) ),
- 'id[]' => wikiFuzz::makeFuzz( 2 ),
- 'edit' => wikiFuzz::makeFuzz( 2 ),
- 'token' => wikiFuzz::chooseInput( array( "", "1243213", wikiFuzz::makeFuzz( 2 ) ) )
- );
-
- // sometimes we specifiy "reset", and sometimes we don't.
- if ( wikiFuzz::randnum( 3 ) == 0 ) $this->params["reset"] = wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) );
- }
-}
-
-/**
- ** a page test for "Special:Movepage"
- */
-class specialMovePage extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Movepage";
-
- $this->params = array (
- "action" => wikiFuzz::chooseInput( array( "success", "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpEditToken' => wikiFuzz::chooseInput( array( '', 0, 34987987, wikiFuzz::makeFuzz( 2 ) ) ),
- 'target' => wikiFuzz::chooseInput( array( "x", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ) ) ),
- 'wpOldTitle' => wikiFuzz::chooseInput( array( "z", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ), wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpNewTitle' => wikiFuzz::chooseInput( array( "y", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ), wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpReason' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpMovetalk' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpDeleteAndMove' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpConfirm' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- 'talkmoved' => wikiFuzz::chooseInput( array( "1", wikiFuzz::makeFuzz( 2 ), "articleexists", 'notalkpage' ) ),
- 'oldtitle' => wikiFuzz::makeFuzz( 2 ),
- 'newtitle' => wikiFuzz::makeFuzz( 2 ),
- 'wpMovetalk' => wikiFuzz::chooseInput( array( "1", "0", wikiFuzz::makeFuzz( 2 ) ) )
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["wpEditToken"] );
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["target"] );
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpNewTitle"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpReason"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpOldTitle"] );
- }
-}
-
-
-/**
- ** a page test for "Special:Undelete"
- */
-class specialUndeletePageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Undelete";
-
- $this->params = array (
- "action" => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpEditToken' => wikiFuzz::chooseInput( array( '', 0, 34987987, wikiFuzz::makeFuzz( 2 ) ) ),
- 'target' => wikiFuzz::chooseInput( array( "x", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ) ) ),
- 'timestamp' => wikiFuzz::chooseInput( array( "125223", wikiFuzz::makeFuzz( 2 ) ) ),
- 'file' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- 'restore' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
- 'preview' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpComment' => wikiFuzz::makeFuzz( 2 )
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["wpEditToken"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["target"] );
- if ( wikiFuzz::randnum( 1 ) == 0 ) unset( $this->params["restore"] );
- if ( wikiFuzz::randnum( 1 ) == 0 ) unset( $this->params["preview"] );
- }
-}
-
-
-/**
- ** a page test for "Special:Unlockdb"
- */
-class specialUnlockdbPageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Unlockdb";
-
- $this->params = array (
- "action" => wikiFuzz::chooseInput( array( "submit", "success", "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpLockConfirm' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) )
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpEditToken"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpLockConfirm"] );
- }
-}
-
-
-/**
- ** a page test for "Special:Lockdb"
- */
-class specialLockdbPageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Lockdb";
-
- $this->params = array (
- "action" => wikiFuzz::chooseInput( array( "submit", "success", "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpLockReason' => wikiFuzz::makeFuzz( 2 ),
- 'wpLockConfirm' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpEditToken"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpLockConfirm"] );
- }
-}
-
-
-/**
- ** a page test for "Special:Userrights"
- */
-class specialUserrights extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Userrights";
-
- $this->params = array (
- 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'user-editname' => wikiFuzz::chooseInput( array( "Nickj2", "Nickj2\n<xyz>", wikiFuzz::makeFuzz( 2 ) ) ),
- 'ssearchuser' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- 'saveusergroups' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ), "Save User Groups" ),
- 'member[]' => wikiFuzz::chooseInput( array( "0", "bot", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- "available[]" => wikiFuzz::chooseInput( array( "0", "sysop", "bureaucrat", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['ssearchuser'] );
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['saveusergroups'] );
- }
-}
-
-
-/**
- ** a test for page protection and unprotection.
- */
-class pageProtectionForm extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Main_Page";
-
- $this->params = array (
- "action" => "protect",
- 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
- "mwProtect-level-edit" => wikiFuzz::chooseInput( array( '', 'autoconfirmed', 'sysop', wikiFuzz::makeFuzz( 2 ) ) ),
- "mwProtect-level-move" => wikiFuzz::chooseInput( array( '', 'autoconfirmed', 'sysop', wikiFuzz::makeFuzz( 2 ) ) ),
- "mwProtectUnchained" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- 'mwProtect-reason' => wikiFuzz::chooseInput( array( "because it was there", wikiFuzz::makeFuzz( 2 ) ) )
- );
-
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["mwProtectUnchained"] );
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['mwProtect-reason'] );
- }
-}
-
-
-/**
- ** a page test for "Special:Blockip".
- */
-class specialBlockip extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Blockip";
-
- $this->params = array (
- "action" => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
- 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
- "wpBlockAddress" => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
- // something like an IP address, sometimes invalid:
- ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
- . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
- "ip" => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
- // something like an IP address, sometimes invalid:
- ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
- . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
- "wpBlockOther" => wikiFuzz::chooseInput( array( '', 'Nickj2', wikiFuzz::makeFuzz( 2 ) ) ),
- "wpBlockExpiry" => wikiFuzz::chooseInput( array( "other", "2 hours", "1 day", "3 days", "1 week", "2 weeks",
- "1 month", "3 months", "6 months", "1 year", "infinite", wikiFuzz::makeFuzz( 2 ) ) ),
- "wpBlockReason" => wikiFuzz::chooseInput( array( "because it was there", wikiFuzz::makeFuzz( 2 ) ) ),
- "wpAnonOnly" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- "wpCreateAccount" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- "wpBlock" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockOther"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockExpiry"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockReason"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpAnonOnly"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpCreateAccount"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockAddress"] );
- if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["ip"] );
- }
-}
-
-
-/**
- ** a test for the imagepage.
- */
-class imagepageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Image:Small-email.png";
-
- $this->params = array (
- "image" => wikiFuzz::chooseInput( array( "Small-email.png", wikiFuzz::makeFuzz( 2 ) ) ),
- "wpReason" => wikiFuzz::makeFuzz( 2 ),
- "oldimage" => wikiFuzz::chooseInput( array( "Small-email.png", wikiFuzz::makeFuzz( 2 ) ) ),
- "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["image"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpReason"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldimage"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEditToken"] );
- }
-}
-
-
-/**
- ** a test for page deletion form.
- */
-class pageDeletion extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Main_Page&action=delete";
-
- $this->params = array (
- "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
- "wpReason" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- "wpConfirm" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpReason"] );
- if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpEditToken"] );
- if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpConfirm"] );
- }
-}
-
-
-
-/**
- ** a test for Revision Deletion.
- */
-class specialRevisionDeletePageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Revisiondelete";
-
- $this->params = array (
- "target" => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
- "oldid" => wikiFuzz::makeFuzz( 2 ),
- "oldid[]" => wikiFuzz::makeFuzz( 2 ),
- "wpReason" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- "revdelete-hide-text" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- "revdelete-hide-comment" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- "revdelete-hide-user" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- "revdelete-hide-restricted" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["target"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldid"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldid[]"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpReason"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-text"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-comment"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-user"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-restricted"] );
- }
-}
-
-
-/**
- ** a test for Special:Import.
- */
-class specialImportPageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Import";
-
- $this->params = array (
- "action" => "submit",
- "source" => wikiFuzz::chooseInput( array( "upload", "interwiki", wikiFuzz::makeFuzz( 2 ) ) ),
- "MAX_FILE_SIZE" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- "xmlimport" => wikiFuzz::chooseInput( array( "/var/www/hosts/mediawiki/wiki/AdminSettings.php", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
- "namespace" => wikiFuzz::chooseInput( array( wikiFuzz::randnum( 30, -6 ), wikiFuzz::makeFuzz( 2 ) ) ),
- "interwiki" => wikiFuzz::makeFuzz( 2 ),
- "interwikiHistory" => wikiFuzz::makeFuzz( 2 ),
- "frompage" => wikiFuzz::makeFuzz( 2 ),
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["action"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["source"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["MAX_FILE_SIZE"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["xmlimport"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["interwiki"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["interwikiHistory"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["frompage"] );
-
- // Note: Need to do a file upload to fully test this Special page.
- }
-}
-
-
-/**
- ** a test for thumb.php
- */
-class thumbTest extends pageTest {
- function __construct() {
- $this->pagePath = "thumb.php";
-
- $this->params = array (
- "f" => wikiFuzz::chooseInput( array( "..", "\\", "small-email.png", wikiFuzz::makeFuzz( 2 ) ) ),
- "w" => wikiFuzz::chooseInput( array( "80", wikiFuzz::randnum( 6000, -200 ), wikiFuzz::makeFuzz( 2 ) ) ),
- "r" => wikiFuzz::chooseInput( array( "0", wikiFuzz::makeFuzz( 2 ) ) ),
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["f"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["w"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["r"] );
- }
-}
-
-/**
- ** a test for profileinfo.php
- */
-class profileInfo extends pageTest {
- function __construct() {
- $this->pagePath = "profileinfo.php";
-
- $this->params = array (
- "expand" => wikiFuzz::makeFuzz( 2 ),
- "sort" => wikiFuzz::chooseInput( array( "time", "count", "name", wikiFuzz::makeFuzz( 2 ) ) ),
- "filter" => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["sort"] );
- if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["filter"] );
- }
-}
-
-
-/**
- ** a test for Special:Cite (extension Special page).
- */
-class specialCitePageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Cite";
-
- $this->params = array (
- "page" => wikiFuzz::chooseInput( array( "\" onmouseover=\"alert(1);\"", "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
- "id" => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "-9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ),
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["page"] );
- if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["id"] );
- }
-}
-
-
-/**
- ** a test for Special:Filepath (extension Special page).
- */
-class specialFilepathPageTest extends pageTest {
- function __construct() {
- $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 ) ) ),
- );
- }
-}
-
-
-/**
- ** a test for Special:Renameuser (extension Special page).
- */
-class specialRenameuserPageTest extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:Renameuser";
-
- $this->params = array (
- "oldusername" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ),
- "newusername" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ),
- "token" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
- );
- }
-}
-
-
-/**
- ** a test for Special:Linksearch (extension Special page).
- */
-class specialLinksearch extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special%3ALinksearch";
-
- $this->params = array (
- "target" => wikiFuzz::makeFuzz( 2 ),
- );
-
- // sometimes we don't want to specify certain parameters.
- if ( wikiFuzz::randnum( 10 ) == 0 ) unset( $this->params["target"] );
- }
-}
-
-
-/**
- ** a test for Special:CategoryTree (extension Special page).
- */
-class specialCategoryTree extends pageTest {
- function __construct() {
- $this->pagePath = "index.php?title=Special:CategoryTree";
-
- $this->params = array (
- "target" => wikiFuzz::makeFuzz( 2 ),
- "from" => wikiFuzz::makeFuzz( 2 ),
- "until" => wikiFuzz::makeFuzz( 2 ),
- "showas" => wikiFuzz::makeFuzz( 2 ),
- "mode" => wikiFuzz::chooseInput( array( "pages", "categories", "all", wikiFuzz::makeFuzz( 2 ) ) ),
- );
-
- // sometimes we do want to specify certain parameters.
- if ( wikiFuzz::randnum( 5 ) == 0 ) $this->params["notree"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
- }
-}
-
-
-/**
- ** 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() {
- // @todo FIXME: Add "wikiFuzz::makeFuzz(2)" as possible value below?
- return array ( "feedformat" => wikiFuzz::chooseInput( array( "rss", "atom" ) ) );
- }
-
- // API query mode.
- private static function queryMode() {
- // @todo 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 (
- // @todo FIXME: More titles.
- "titles" => wikiFuzz::chooseInput( array( "Main Page" ) ),
- // @todo 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:
- // @todo 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.
- * @param $count
- * @return \api|\confirmEmail|\contributionsTest|\editPageTest|\imagelistTest|\imagepageTest|\ipblocklistTest|\listusersTest|\mimeSearchTest|\newImagesTest|\pageDeletion|\pageHistoryTest|\pageProtectionForm|\prefixindexTest|\profileInfo|\recentchangesTest|\redirectTest|\searchTest|\specialAllmessagesTest|\specialAllpagesTest|\specialBlockip|\specialBooksourcesTest|\specialCategoryTree|\specialChemicalsourcesTest|\specialCitePageTest|\specialExportTest|\specialFilepathPageTest|\specialImportPageTest|\specialLinksearch|\specialLockdbPageTest|\specialLogTest|\specialMovePage|\specialNewpagesPageTest|\specialRenameuserPageTest|\specialRevisionDeletePageTest|\specialUndeletePageTest|\specialUnlockdbPageTest|\specialUserrights|\successfulUserLoginTest|\thumbTest|\userLoginTest|\viewPageTest|\watchlistTest
- */
-function selectPageTest( $count ) {
-
- // if the user only wants a specific test, then only ever give them that.
- if ( defined( "SPECIFIC_TEST" ) ) {
- $testType = SPECIFIC_TEST;
- return new $testType ();
- }
-
- // Some of the time we test Special pages, the remaining
- // time we test using the standard edit page.
- switch ( $count % 100 ) {
- case 0 : return new successfulUserLoginTest();
- case 1 : return new listusersTest();
- case 2 : return new searchTest();
- case 3 : return new recentchangesTest();
- case 4 : return new prefixindexTest();
- case 5 : return new mimeSearchTest();
- case 6 : return new specialLogTest();
- case 7 : return new userLoginTest();
- case 8 : return new ipblocklistTest();
- case 9 : return new newImagesTest();
- case 10: return new imagelistTest();
- case 11: return new specialExportTest();
- case 12: return new specialBooksourcesTest();
- case 13: return new specialAllpagesTest();
- case 14: return new pageHistoryTest();
- case 15: return new contributionsTest();
- case 16: return new viewPageTest();
- case 17: return new specialAllmessagesTest();
- case 18: return new specialNewpagesPageTest();
- case 19: return new searchTest();
- case 20: return new redirectTest();
- case 21: return new confirmEmail();
- case 22: return new watchlistTest();
- case 24: return new specialUndeletePageTest();
- case 25: return new specialMovePage();
- case 26: return new specialUnlockdbPageTest();
- case 27: return new specialLockdbPageTest();
- case 28: return new specialUserrights();
- case 29: return new pageProtectionForm();
- case 30: return new specialBlockip();
- case 31: return new imagepageTest();
- case 32: return new pageDeletion();
- case 33: return new specialRevisionDeletePageTest();
- case 34: return new specialImportPageTest();
- case 35: return new thumbTest();
- case 37: return new profileInfo();
- case 38: return new specialCitePageTest();
- case 39: return new specialFilepathPageTest();
- case 40: return new specialRenameuserPageTest();
- case 41: return new specialLinksearch();
- case 42: return new specialCategoryTree();
- case 43: return new api();
- case 44: return new specialChemicalsourcesTest();
- default: return new editPageTest();
- }
-}
-
-
-// ///////////////////// SAVING OUTPUT /////////////////////////
-
-/**
- ** Utility function for saving a file. Currently has no error checking.
- */
-function saveFile( $data, $name ) {
- file_put_contents( $name, $data );
-}
-
-/**
- ** Returns a test as an experimental GET-to-POST URL.
- ** This doesn't seem to always work though, and sometimes the output is too long
- ** to be a valid GET URL, so we also save in other formats.
- * @param $test pageTest
- * @return string
- */
-function getAsURL( pageTest $test ) {
- $used_question_mark = ( strpos( $test->getPagePath(), "?" ) !== false );
- $retval = "http://get-to-post.nickj.org/?" . WIKI_BASE_URL . $test->getPagePath();
- foreach ( $test->getParams() as $param => $value ) {
- if ( !$used_question_mark ) {
- $retval .= "?";
- $used_question_mark = true;
- }
- else {
- $retval .= "&";
- }
- $retval .= $param . "=" . urlencode( $value );
- }
- return $retval;
-}
-
-
-/**
- ** Saves a plain-text human-readable version of a test.
- */
-function saveTestAsText( pageTest $test, $filename ) {
- $str = "Test: " . $test->getPagePath();
- foreach ( $test->getParams() as $param => $value ) {
- $str .= "\n$param: $value";
- }
- $str .= "\nGet-to-post URL: " . getAsURL( $test ) . "\n";
- saveFile( $str, $filename );
-}
-
-
-/**
- ** Saves a test as a standalone basic PHP script that shows this one problem.
- ** Resulting script requires PHP-Curl be installed in order to work.
- */
-function saveTestAsPHP( pageTest $test, $filename ) {
- $str = "<?php\n"
- . "\$params = " . var_export( escapeForCurl( $test->getParams() ), true ) . ";\n"
- . "\$ch = curl_init();\n"
- . "curl_setopt(\$ch, CURLOPT_POST, 1);\n"
- . "curl_setopt(\$ch, CURLOPT_POSTFIELDS, \$params );\n"
- . "curl_setopt(\$ch, CURLOPT_URL, " . var_export( WIKI_BASE_URL . $test->getPagePath(), true ) . ");\n"
- . "curl_setopt(\$ch, CURLOPT_RETURNTRANSFER,1);\n"
- . ( $test->getCookie() ? "curl_setopt(\$ch, CURLOPT_COOKIE, " . var_export( $test->getCookie(), true ) . ");\n" : "" )
- . "\$result=curl_exec(\$ch);\n"
- . "curl_close (\$ch);\n"
- . "print \$result;\n"
- . "\n";
- saveFile( $str, $filename );
-}
-
-/**
- * Escapes a value so that it can be used on the command line by Curl.
- * Specifically, "<" and "@" need to be escaped if they are the first character,
- * otherwise curl interprets these as meaning that we want to insert a file.
- * @param $input_params array
- * @return array
- */
-function escapeForCurl( array $input_params ) {
- $output_params = array();
- foreach ( $input_params as $param => $value ) {
- if ( strlen( $value ) > 0 && ( $value[0] == "@" || $value[0] == "<" ) ) {
- $value = "\\" . $value;
- }
- $output_params[$param] = $value;
- }
- return $output_params;
-}
-
-
-/**
- ** Saves a test as a standalone CURL shell script that shows this one problem.
- ** Resulting script requires standalone Curl be installed in order to work.
- */
-function saveTestAsCurl( pageTest $test, $filename ) {
- $str = "#!/bin/bash\n"
- . "curl --silent --include --globoff \\\n"
- . ( $test->getCookie() ? " --cookie " . escapeshellarg( $test->getCookie() ) . " \\\n" : "" );
- foreach ( escapeForCurl( $test->getParams() ) as $param => $value ) {
- $str .= " -F " . escapeshellarg( $param ) . "=" . escapeshellarg( $value ) . " \\\n";
- }
- $str .= " " . escapeshellarg( WIKI_BASE_URL . $test->getPagePath() ); // beginning space matters.
- $str .= "\n";
- saveFile( $str, $filename );
- chmod( $filename, 0755 ); // make executable
-}
-
-
-/**
- ** Saves the internal data structure to file.
- */
-function saveTestData ( pageTest $test, $filename ) {
- saveFile( serialize( $test ), $filename );
-}
-
-
-/**
- ** saves a test in the various formats.
- */
-function saveTest( pageTest $test, $testname ) {
- $base_name = DIRECTORY . "/" . $testname;
- saveTestAsText( $test, $base_name . INFO_FILE );
- saveTestAsPHP ( $test, $base_name . PHP_TEST );
- saveTestAsCurl( $test, $base_name . CURL_TEST );
- saveTestData ( $test, $base_name . DATA_FILE );
-}
-
-// ////////////////// MEDIAWIKI OUTPUT /////////////////////////
-
-/**
- * Asks MediaWiki for the HTML output of a test.
- * @param $test pageTest
- * @return string
- */
-function wikiTestOutput( pageTest $test ) {
-
- $ch = curl_init();
-
- // specify the cookie, if required.
- if ( $test->getCookie() ) {
- curl_setopt( $ch, CURLOPT_COOKIE, $test->getCookie() );
- }
- curl_setopt( $ch, CURLOPT_POST, 1 ); // save form using a POST
-
- $params = escapeForCurl( $test->getParams() );
- curl_setopt( $ch, CURLOPT_POSTFIELDS, $params ); // load the POST variables
-
- curl_setopt( $ch, CURLOPT_URL, WIKI_BASE_URL . $test->getPagePath() ); // set url to post to
- curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); // return into a variable
-
- $result = curl_exec ( $ch );
-
- // if we encountered an error, then say so, and return an empty string.
- if ( curl_error( $ch ) ) {
- print "\nCurl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch );
- $result = "";
- }
-
- curl_close ( $ch );
-
- return $result;
-}
-
-
-// ////////////////// HTML VALIDATION /////////////////////////
-
-/**
- * Asks the validator whether this is valid HTML, or not.
- * @param $text string
- * @return array
- */
-function validateHTML( $text ) {
-
- $params = array ( "fragment" => $text );
-
- $ch = curl_init();
-
- curl_setopt( $ch, CURLOPT_POST, 1 ); // save form using a POST
- curl_setopt( $ch, CURLOPT_POSTFIELDS, $params ); // load the POST variables
- curl_setopt( $ch, CURLOPT_URL, VALIDATOR_URL ); // set url to post to
- curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); // return into a variable
-
- $result = curl_exec ( $ch );
-
- // if we encountered an error, then log it, and exit.
- if ( curl_error( $ch ) ) {
- trigger_error( "Curl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ) );
- print "Curl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ) . " - exiting.\n";
- exit( 1 );
- }
-
- curl_close ( $ch );
-
- $valid = ( strpos( $result, "Failed validation" ) === false );
-
- return array( $valid, $result );
-}
-
-/**
- * Get tidy to check for no HTML errors in the output file (e.g. unescaped strings).
- * @param $name
- * @return bool
- */
-function tidyCheckFile( $name ) {
- $file = DIRECTORY . "/" . $name;
- $command = PATH_TO_TIDY . " -output /tmp/out.html -quiet $file 2>&1";
- $x = `$command`;
-
- // Look for the most interesting Tidy errors and warnings.
- if ( strpos( $x, "end of file while parsing attributes" ) !== false
- || strpos( $x, "attribute with missing trailing quote mark" ) !== false
- || strpos( $x, "missing '>' for end of tag" ) !== false
- || strpos( $x, "Error:" ) !== false ) {
- print "\nTidy found something - view details with: $command";
- return false;
- } else {
- return true;
- }
-}
-
-/**
- ** Returns whether or not an database error log file has changed in size since
- ** the last time this was run. This is used to tell if a test caused a DB error.
- * @return bool
- */
-function dbErrorLogged() {
- static $filesize;
-
- // first time running this function
- if ( !isset( $filesize ) ) {
- // create log if it does not exist
- if ( DB_ERROR_LOG_FILE && !file_exists( DB_ERROR_LOG_FILE ) ) {
- saveFile( '', DB_ERROR_LOG_FILE );
- }
- $filesize = filesize( DB_ERROR_LOG_FILE );
- return false;
- }
-
- $newsize = filesize( DB_ERROR_LOG_FILE );
- // if the log has grown, then assume the current test caused it.
- if ( $newsize != $filesize ) {
- $filesize = $newsize;
- return true;
- }
-
- return false;
-}
-
-// //////////////// TOP-LEVEL PROBLEM-FINDING FUNCTION ////////////////////////
-
-/**
- * takes a page test, and runs it and tests it for problems in the output.
- * Returns: False on finding a problem, or True on no problems being found.
- * @param $test pageTest
- * @param $testname
- * @param $can_overwrite bool
- * @return bool
- */
-function runWikiTest( pageTest $test, &$testname, $can_overwrite = false ) {
-
- // by default don't overwrite a previous test of the same name.
- while ( ! $can_overwrite && file_exists( DIRECTORY . "/" . $testname . DATA_FILE ) ) {
- $testname .= "-" . mt_rand( 0, 9 );
- }
-
- $filename = DIRECTORY . "/" . $testname . DATA_FILE;
-
- // Store the time before and after, to find slow pages.
- $before = microtime( true );
-
- // Get MediaWiki to give us the output of this test.
- $wiki_preview = wikiTestOutput( $test );
-
- $after = microtime( true );
-
- // if we received no response, then that's interesting.
- if ( $wiki_preview == "" ) {
- print "\nNo response received for: $filename";
- return false;
- }
-
- // save output HTML to file.
- $html_file = DIRECTORY . "/" . $testname . HTML_FILE;
- 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
- || 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" ) {
- print "\nPHP error/warning/notice in HTML output: $html_file ; $error";
- return false;
- }
- }
-
- // if there was a MediaWiki Backtrace message in the output, then that's also interesting.
- 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 ) {
- print "\nParser Error comment in HTML output: $html_file";
- return false;
- }
-
- // if a database error was logged, then that's definitely interesting.
- if ( dbErrorLogged() ) {
- print "\nDatabase Error logged for: $filename";
- return false;
- }
-
- // validate result
- $valid = true;
- 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 we already know it produces non-(X)HTML output.
- if ( $test->tidyValidate() ) {
- $valid = tidyCheckFile( $testname . HTML_FILE ) && $valid;
- }
-
- // if it took more than 2 seconds to render, then it may be interesting too. (Possible DoS attack?)
- if ( ( $after - $before ) >= 2 ) {
- print "\nParticularly slow to render (" . round( $after - $before, 2 ) . " seconds): $filename";
- return false;
- }
-
- if ( $valid ) {
- // Remove temp HTML file if test was valid:
- unlink( $html_file );
- } elseif ( VALIDATE_ON_WEB ) {
- saveFile( $validator_output, DIRECTORY . "/" . $testname . ".validator_output.html" );
- }
-
- return $valid;
-}
-
-
-// ///////////////// RERUNNING OLD TESTS ///////////////////
-
-/**
- ** We keep our failed tests so that they can be rerun.
- ** This function does that retesting.
- */
-function rerunPreviousTests() {
- print "Retesting previously found problems.\n";
-
- $dir_contents = scandir ( DIRECTORY );
-
- // sort file into the order a normal person would use.
- natsort ( $dir_contents );
-
- foreach ( $dir_contents as $file ) {
-
- // if file is not a test, then skip it.
- // Note we need to escape any periods or will be treated as "any character".
- $matches = array();
- if ( !preg_match( "/(.*)" . str_replace( ".", "\.", DATA_FILE ) . "$/", $file, $matches ) ) continue;
-
- // reload the test.
- $full_path = DIRECTORY . "/" . $file;
- $test = unserialize( file_get_contents( $full_path ) );
-
- // if this is not a valid test, then skip it.
- if ( ! $test instanceof pageTest ) {
- print "\nSkipping invalid test - $full_path";
- continue;
- }
-
- // The date format is in Apache log format, which makes it easier to locate
- // which retest caused which error in the Apache logs (only happens usually if
- // apache segfaults).
- if ( !QUIET ) print "[" . date ( "D M d H:i:s Y" ) . "] Retesting $file (" . get_class( $test ) . ")";
-
- // run test
- $testname = $matches[1];
- $valid = runWikiTest( $test, $testname, true );
-
- if ( !$valid ) {
- saveTest( $test, $testname );
- if ( QUIET ) {
- print "\nTest: " . get_class( $test ) . " ; Testname: $testname\n------";
- } else {
- print "\n";
- }
- }
- else {
- if ( !QUIET ) print "\r";
- if ( DELETE_PASSED_RETESTS ) {
- $prefix = DIRECTORY . "/" . $testname;
- if ( is_file( $prefix . DATA_FILE ) ) unlink( $prefix . DATA_FILE );
- if ( is_file( $prefix . PHP_TEST ) ) unlink( $prefix . PHP_TEST );
- if ( is_file( $prefix . CURL_TEST ) ) unlink( $prefix . CURL_TEST );
- if ( is_file( $prefix . INFO_FILE ) ) unlink( $prefix . INFO_FILE );
- }
- }
- }
-
- print "\nDone retesting.\n";
-}
-
-
-// //////////////////// MAIN LOOP ////////////////////////
-
-
-// first check whether CURL is installed, because sometimes it's not.
-if ( ! function_exists( 'curl_init' ) ) {
- die( "Could not find 'curl_init' function. Is the curl extension compiled into PHP?\n" );
-}
-
-// Initialization of types. wikiFuzz doesn't have a constructor because we want to
-// access it staticly and not have any globals.
-wikiFuzz::$types = array_keys( wikiFuzz::$data );
-
-// Make directory if doesn't exist
-if ( !is_dir( DIRECTORY ) ) {
- mkdir ( DIRECTORY, 0700 );
-}
-// otherwise, we first retest the things that we have found in previous runs
-elseif ( RERUN_OLD_TESTS ) {
- rerunPreviousTests();
-}
-
-// main loop.
-$start_time = date( "U" );
-$num_errors = 0;
-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 ) {
- // spinning progress indicator.
- switch( $count % 4 ) {
- case '0': print "\r/"; break;
- case '1': print "\r-"; break;
- case '2': print "\r\\"; break;
- case '3': print "\r|"; break;
- }
- print " $count";
- }
-
- // generate a page test to run.
- $test = selectPageTest( $count );
-
- $mins = ( date( "U" ) - $start_time ) / 60;
- if ( !QUIET && $mins > 0 ) {
- print ". $num_errors poss errors. "
- . floor( $mins ) . " mins. "
- . round ( $count / $mins, 0 ) . " tests/min. "
- . get_class( $test ); // includes the current test name.
- }
-
- // run this test against MediaWiki, and see if the output was valid.
- $testname = $count;
- $valid = runWikiTest( $test, $testname, false );
-
- // save the failed test
- if ( ! $valid ) {
- if ( QUIET ) {
- print "\nTest: " . get_class( $test ) . " ; Testname: $testname\n------";
- } else {
- print "\n";
- }
- saveTest( $test, $testname );
- $num_errors += 1;
- } elseif ( 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.
- if ( defined( "MAX_ERRORS" ) && $num_errors >= MAX_ERRORS ) {
- break;
- }
-
- // stop if we have reached max number of mins runtime.
- if ( defined( "MAX_RUNTIME" ) && $mins >= MAX_RUNTIME ) {
- break;
- }
-}
diff --git a/maintenance/generateJsonI18n.php b/maintenance/generateJsonI18n.php
new file mode 100644
index 00000000..22d99405
--- /dev/null
+++ b/maintenance/generateJsonI18n.php
@@ -0,0 +1,287 @@
+<?php
+
+/**
+ * Convert a PHP messages file to a set of JSON messages files.
+ *
+ * Usage:
+ * php generateJsonI18n.php ExtensionName.i18n.php i18n/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script to generate JSON i18n files from a PHP i18n file.
+ *
+ * @ingroup Maintenance
+ */
+class GenerateJsonI18n extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Build JSON messages files from a PHP messages file";
+
+ $this->addArg( 'phpfile', 'PHP file defining a $messages array', false );
+ $this->addArg( 'jsondir', 'Directory to write JSON files to', false );
+ $this->addOption( 'langcode', 'Language code; only needed for converting core i18n files',
+ false, true );
+ $this->addOption( 'extension', 'Perform default conversion on an extension',
+ false, true );
+ $this->addOption( 'shim-only', 'Only create or update the backward-compatibility shim' );
+ $this->addOption( 'supplementary', 'Find supplementary i18n files in subdirs and convert those',
+ false, false );
+ }
+
+ public function execute() {
+ global $IP;
+
+ $phpfile = $this->getArg( 0 );
+ $jsondir = $this->getArg( 1 );
+ $extension = $this->getOption( 'extension' );
+ $convertSupplementaryI18nFiles = $this->hasOption( 'supplementary' );
+
+ if ( $extension ) {
+ if ( $phpfile ) {
+ $this->error( "The phpfile is already specified, conflicts with --extension.\n", 1 );
+ }
+ $phpfile = "$IP/extensions/$extension/$extension.i18n.php";
+ }
+
+ if ( !$phpfile ) {
+ $this->error( "I'm here for an argument!\n" );
+ $this->maybeHelp( true );
+ // dies.
+ }
+
+ if ( $convertSupplementaryI18nFiles ) {
+ if ( is_readable( $phpfile ) ) {
+ $this->transformI18nFile( $phpfile, $jsondir );
+ } else {
+ // This is non-fatal because we might want to continue searching for
+ // i18n files in subdirs even if the extension does not include a
+ // primary i18n.php.
+ $this->error( "Warning: no primary i18n file was found." );
+ }
+ $this->output( "Searching for supplementary i18n files...\n" );
+ $dir_iterator = new RecursiveDirectoryIterator( dirname( $phpfile ) );
+ $iterator = new RecursiveIteratorIterator(
+ $dir_iterator, RecursiveIteratorIterator::LEAVES_ONLY );
+ foreach ( $iterator as $path => $fileObject ) {
+ if ( fnmatch( "*.i18n.php", $fileObject->getFilename() ) ) {
+ $this->output( "Converting $path.\n" );
+ $this->transformI18nFile( $path );
+ }
+ }
+ } else {
+ // Just convert the primary i18n file.
+ $this->transformI18nFile( $phpfile, $jsondir );
+ }
+ }
+
+ public function transformI18nFile( $phpfile, $jsondir = null ) {
+ if ( !$jsondir ) {
+ // Assume the json directory should be in the same directory as the
+ // .i18n.php file.
+ $jsondir = dirname( $phpfile ) . "/i18n";
+ }
+ if ( !is_dir( $jsondir ) ) {
+ $this->output( "Creating directory $jsondir.\n" );
+ $success = mkdir( $jsondir );
+ if ( !$success ) {
+ $this->error( "Could not create directory $jsondir\n", 1 );
+ }
+ }
+
+ if ( $this->hasOption( 'shim-only' ) ) {
+ $this->shimOnly( $phpfile, $jsondir );
+
+ return;
+ }
+
+ if ( $jsondir === null ) {
+ $this->error( 'Argument [jsondir] is required unless --shim-only is specified.' );
+ $this->maybeHelp( true );
+ }
+
+ if ( !is_readable( $phpfile ) ) {
+ $this->error( "Error reading $phpfile\n", 1 );
+ }
+ include $phpfile;
+ $phpfileContents = file_get_contents( $phpfile );
+
+ if ( !isset( $messages ) ) {
+ $this->error( "PHP file $phpfile does not define \$messages array\n", 1 );
+ }
+
+ $extensionStyle = true;
+ if ( !isset( $messages['en'] ) || !is_array( $messages['en'] ) ) {
+ if ( !$this->hasOption( 'langcode' ) ) {
+ $this->error( "PHP file $phpfile does not set language codes, --langcode " .
+ "is required.\n", 1 );
+ }
+ $extensionStyle = false;
+ $langcode = $this->getOption( 'langcode' );
+ $messages = array( $langcode => $messages );
+ } elseif ( $this->hasOption( 'langcode' ) ) {
+ $this->output( "Warning: --langcode option set but will not be used.\n" );
+ }
+
+ foreach ( $messages as $langcode => $langmsgs ) {
+ $authors = $this->getAuthorsFromComment( $this->findCommentBefore(
+ $extensionStyle ? "\$messages['$langcode'] =" : '$messages =',
+ $phpfileContents
+ ) );
+ // Make sure the @metadata key is the first key in the output
+ $langmsgs = array_merge(
+ array( '@metadata' => array( 'authors' => $authors ) ),
+ $langmsgs
+ );
+
+ $jsonfile = "$jsondir/$langcode.json";
+ $success = file_put_contents(
+ $jsonfile,
+ FormatJson::encode( $langmsgs, "\t", FormatJson::ALL_OK ) . "\n"
+ );
+ if ( $success === false ) {
+ $this->error( "FAILED to write $jsonfile", 1 );
+ }
+ $this->output( "$jsonfile\n" );
+ }
+
+ if ( !$this->hasOption( 'langcode' ) ) {
+ $shim = $this->doShim( $jsondir );
+ file_put_contents( $phpfile, $shim );
+ }
+
+ $this->output( "All done.\n" );
+ $this->output( "Also add \$wgMessagesDirs['YourExtension'] = __DIR__ . '/i18n';\n" );
+ }
+
+ protected function shimOnly( $phpfile, $jsondir ) {
+ if ( file_exists( $phpfile ) ) {
+ if ( !is_readable( $phpfile ) ) {
+ $this->error( "Error reading $phpfile\n", 1 );
+ }
+
+ $phpfileContents = file_get_contents( $phpfile );
+ $m = array();
+ if ( !preg_match( '!"/([^"$]+)/\$csCode.json";!', $phpfileContents, $m ) ) {
+ $this->error( "Cannot recognize $phpfile as a shim.\n", 1 );
+ }
+
+ if ( $jsondir === null ) {
+ $jsondir = $m[1];
+ }
+
+ $this->output( "Updating existing shim $phpfile\n" );
+ } elseif ( $jsondir === null ) {
+ $this->error( "$phpfile does not exist.\n" .
+ "Argument [jsondir] is required in order to create a new shim.\n", 1 );
+ } else {
+ $this->output( "Creating new shim $phpfile\n" );
+ }
+
+ $shim = $this->doShim( $jsondir );
+ file_put_contents( $phpfile, $shim );
+ $this->output( "All done.\n" );
+ }
+
+ protected function doShim( $jsondir ) {
+ $shim = <<<'PHP'
+<?php
+/**
+ * This is a backwards-compatibility shim, generated by:
+ * https://git.wikimedia.org/blob/mediawiki%2Fcore.git/HEAD/maintenance%2FgenerateJsonI18n.php
+ *
+ * Beginning with MediaWiki 1.23, translation strings are stored in json files,
+ * and the EXTENSION.i18n.php file only exists to provide compatibility with
+ * older releases of MediaWiki. For more information about this migration, see:
+ * https://www.mediawiki.org/wiki/Requests_for_comment/Localisation_format
+ *
+ * This shim maintains compatibility back to MediaWiki 1.17.
+ */
+$messages = array();
+if ( !function_exists( '{{FUNC}}' ) ) {
+ function {{FUNC}}( $cache, $code, &$cachedData ) {
+ $codeSequence = array_merge( array( $code ), $cachedData['fallbackSequence'] );
+ foreach ( $codeSequence as $csCode ) {
+ $fileName = dirname( __FILE__ ) . "/{{OUT}}/$csCode.json";
+ if ( is_readable( $fileName ) ) {
+ $data = FormatJson::decode( file_get_contents( $fileName ), true );
+ foreach ( array_keys( $data ) as $key ) {
+ if ( $key === '' || $key[0] === '@' ) {
+ unset( $data[$key] );
+ }
+ }
+ $cachedData['messages'] = array_merge( $data, $cachedData['messages'] );
+ }
+
+ $cachedData['deps'][] = new FileDependency( $fileName );
+ }
+ return true;
+ }
+
+ $GLOBALS['wgHooks']['LocalisationCacheRecache'][] = '{{FUNC}}';
+}
+
+PHP;
+
+ $jsondir = str_replace( '\\', '/', $jsondir );
+ $shim = str_replace( '{{OUT}}', $jsondir, $shim );
+ $shim = str_replace( '{{FUNC}}', 'wfJsonI18nShim' . wfRandomString( 16 ), $shim );
+
+ return $shim;
+ }
+
+ /**
+ * Find the documentation comment immediately before a given search string
+ * @param string $needle String to search for
+ * @param string $haystack String to search in
+ * @return string Substring of $haystack starting at '/**' ending right before $needle, or empty
+ */
+ protected function findCommentBefore( $needle, $haystack ) {
+ $needlePos = strpos( $haystack, $needle );
+ if ( $needlePos === false ) {
+ return '';
+ }
+ // Need to pass a negative offset to strrpos() so it'll search backwards from the
+ // offset
+ $startPos = strrpos( $haystack, '/**', $needlePos - strlen( $haystack ) );
+ if ( $startPos === false ) {
+ return '';
+ }
+
+ return substr( $haystack, $startPos, $needlePos - $startPos );
+ }
+
+ /**
+ * Get an array of author names from a documentation comment containing @author declarations.
+ * @param string $comment Documentation comment
+ * @return array Array of author names (strings)
+ */
+ protected function getAuthorsFromComment( $comment ) {
+ $matches = null;
+ preg_match_all( '/@author (.*?)$/m', $comment, $matches );
+
+ return $matches && $matches[1] ? $matches[1] : array();
+ }
+}
+
+$maintClass = "GenerateJsonI18n";
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/generateSitemap.php b/maintenance/generateSitemap.php
index 0b21a1fe..1930a22a 100644
--- a/maintenance/generateSitemap.php
+++ b/maintenance/generateSitemap.php
@@ -63,7 +63,8 @@ class GenerateSitemap extends Maintenance {
public $fspath;
/**
- * The URL path to prepend to filenames in the index; should resolve to the same directory as $fspath
+ * The URL path to prepend to filenames in the index;
+ * should resolve to the same directory as $fspath.
*
* @var string
*/
@@ -125,7 +126,6 @@ class GenerateSitemap extends Maintenance {
*/
public $findex;
-
/**
* A resource pointing to a sitemap file
*
@@ -146,11 +146,32 @@ class GenerateSitemap extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Creates a sitemap for the site";
- $this->addOption( 'fspath', 'The file system path to save to, e.g. /tmp/sitemap; defaults to current directory', false, true );
- $this->addOption( 'urlpath', 'The URL path corresponding to --fspath, prepended to filenames in the index; defaults to an empty string', false, true );
- $this->addOption( 'compress', 'Compress the sitemap files, can take value yes|no, default yes', false, true );
+ $this->addOption(
+ 'fspath',
+ 'The file system path to save to, e.g. /tmp/sitemap; defaults to current directory',
+ false,
+ true
+ );
+ $this->addOption(
+ 'urlpath',
+ 'The URL path corresponding to --fspath, prepended to filenames in the index; '
+ . 'defaults to an empty string',
+ false,
+ true
+ );
+ $this->addOption(
+ 'compress',
+ 'Compress the sitemap files, can take value yes|no, default yes',
+ false,
+ true
+ );
$this->addOption( 'skip-redirects', 'Do not include redirecting articles in the sitemap' );
- $this->addOption( 'identifier', 'What site identifier to use for the wiki, defaults to $wgDBname', false, true );
+ $this->addOption(
+ 'identifier',
+ 'What site identifier to use for the wiki, defaults to $wgDBname',
+ false,
+ true
+ );
}
/**
@@ -219,13 +240,10 @@ class GenerateSitemap extends Maintenance {
/**
* Create directory if it does not exist and return pathname with a trailing slash
- * @param $fspath string
+ * @param string $fspath
* @return null|string
*/
private static function init_path( $fspath ) {
- if ( !isset( $fspath ) ) {
- return null;
- }
# Create directory if needed
if ( $fspath && !is_dir( $fspath ) ) {
wfMkdirParents( $fspath, null, __METHOD__ ) or die( "Can not create directory $fspath.\n" );
@@ -242,6 +260,7 @@ class GenerateSitemap extends Maintenance {
global $wgSitemapNamespaces;
if ( is_array( $wgSitemapNamespaces ) ) {
$this->namespaces = $wgSitemapNamespaces;
+
return;
}
@@ -263,11 +282,13 @@ class GenerateSitemap extends Maintenance {
/**
* Get the priority of a given namespace
*
- * @param $namespace Integer: the namespace to get the priority for
- * @return String
+ * @param int $namespace The namespace to get the priority for
+ * @return string
*/
function priority( $namespace ) {
- return isset( $this->priorities[$namespace] ) ? $this->priorities[$namespace] : $this->guessPriority( $namespace );
+ return isset( $this->priorities[$namespace] )
+ ? $this->priorities[$namespace]
+ : $this->guessPriority( $namespace );
}
/**
@@ -275,17 +296,19 @@ class GenerateSitemap extends Maintenance {
* default priority for the namespace, varies depending on whether it's
* a talkpage or not.
*
- * @param $namespace Integer: the namespace to get the priority for
- * @return String
+ * @param int $namespace The namespace to get the priority for
+ * @return string
*/
function guessPriority( $namespace ) {
- return MWNamespace::isSubject( $namespace ) ? $this->priorities[self::GS_MAIN] : $this->priorities[self::GS_TALK];
+ return MWNamespace::isSubject( $namespace )
+ ? $this->priorities[self::GS_MAIN]
+ : $this->priorities[self::GS_TALK];
}
/**
* Return a database resolution of all the pages in a given namespace
*
- * @param $namespace Integer: limit the query to this namespace
+ * @param int $namespace Limit the query to this namespace
* @return Resource
*/
function getPageRes( $namespace ) {
@@ -318,14 +341,17 @@ class GenerateSitemap extends Maintenance {
$fns = $wgContLang->getFormattedNsText( $namespace );
$this->output( "$namespace ($fns)\n" );
- $skippedRedirects = 0; // Number of redirects skipped for that namespace
+ $skippedRedirects = 0; // Number of redirects skipped for that namespace
foreach ( $res as $row ) {
if ( $this->skipRedirects && $row->page_is_redirect ) {
$skippedRedirects++;
continue;
}
- if ( $i++ === 0 || $i === $this->url_limit + 1 || $length + $this->limit[1] + $this->limit[2] > $this->size_limit ) {
+ if ( $i++ === 0
+ || $i === $this->url_limit + 1
+ || $length + $this->limit[1] + $this->limit[2] > $this->size_limit
+ ) {
if ( $this->file !== false ) {
$this->write( $this->file, $this->closeFile() );
$this->close( $this->file );
@@ -350,7 +376,11 @@ class GenerateSitemap extends Maintenance {
if ( $vCode == $wgContLang->getCode() ) {
continue; // we don't want default variant
}
- $entry = $this->fileEntry( $title->getCanonicalURL( '', $vCode ), $date, $this->priority( $namespace ) );
+ $entry = $this->fileEntry(
+ $title->getCanonicalURL( '', $vCode ),
+ $date,
+ $this->priority( $namespace )
+ );
$length += strlen( $entry );
$this->write( $this->file, $entry );
}
@@ -373,18 +403,25 @@ class GenerateSitemap extends Maintenance {
/**
* gzopen() / fopen() wrapper
*
- * @return Resource
+ * @param string $file
+ * @param string $flags
+ * @return resource
*/
function open( $file, $flags ) {
$resource = $this->compress ? gzopen( $file, $flags ) : fopen( $file, $flags );
if ( $resource === false ) {
- throw new MWException( __METHOD__ . " error opening file $file with flags $flags. Check permissions?" );
+ throw new MWException( __METHOD__
+ . " error opening file $file with flags $flags. Check permissions?" );
}
+
return $resource;
}
/**
* gzwrite() / fwrite() wrapper
+ *
+ * @param resource $handle
+ * @param string $str
*/
function write( &$handle, $str ) {
if ( $handle === true || $handle === false ) {
@@ -399,6 +436,8 @@ class GenerateSitemap extends Maintenance {
/**
* gzclose() / fclose() wrapper
+ *
+ * @param resource $handle
*/
function close( &$handle ) {
if ( $this->compress ) {
@@ -411,12 +450,13 @@ class GenerateSitemap extends Maintenance {
/**
* Get a sitemap filename
*
- * @param $namespace Integer: the namespace
- * @param $count Integer: the count
- * @return String
+ * @param int $namespace The namespace
+ * @param int $count The count
+ * @return string
*/
function sitemapFilename( $namespace, $count ) {
$ext = $this->compress ? '.gz' : '';
+
return "sitemap-{$this->identifier}-NS_$namespace-$count.xml$ext";
}
@@ -432,7 +472,7 @@ class GenerateSitemap extends Maintenance {
/**
* Return the XML schema being used
*
- * @return String
+ * @return string
*/
function xmlSchema() {
return 'http://www.sitemaps.org/schemas/sitemap/0.9';
@@ -441,7 +481,7 @@ class GenerateSitemap extends Maintenance {
/**
* Return the XML required to open a sitemap index file
*
- * @return String
+ * @return string
*/
function openIndex() {
return $this->xmlHead() . '<sitemapindex xmlns="' . $this->xmlSchema() . '">' . "\n";
@@ -450,8 +490,8 @@ class GenerateSitemap extends Maintenance {
/**
* Return the XML for a single sitemap indexfile entry
*
- * @param $filename String: the filename of the sitemap file
- * @return String
+ * @param string $filename The filename of the sitemap file
+ * @return string
*/
function indexEntry( $filename ) {
return
@@ -464,7 +504,7 @@ class GenerateSitemap extends Maintenance {
/**
* Return the XML required to close a sitemap index file
*
- * @return String
+ * @return string
*/
function closeIndex() {
return "</sitemapindex>\n";
@@ -473,7 +513,7 @@ class GenerateSitemap extends Maintenance {
/**
* Return the XML required to open a sitemap file
*
- * @return String
+ * @return string
*/
function openFile() {
return $this->xmlHead() . '<urlset xmlns="' . $this->xmlSchema() . '">' . "\n";
@@ -482,10 +522,10 @@ class GenerateSitemap extends Maintenance {
/**
* Return the XML for a single sitemap entry
*
- * @param $url String: an RFC 2396 compliant URL
- * @param $date String: a ISO 8601 date
- * @param $priority String: a priority indicator, 0.0 - 1.0 inclusive with a 0.1 stepsize
- * @return String
+ * @param string $url An RFC 2396 compliant URL
+ * @param string $date A ISO 8601 date
+ * @param string $priority A priority indicator, 0.0 - 1.0 inclusive with a 0.1 stepsize
+ * @return string
*/
function fileEntry( $url, $date, $priority ) {
return
@@ -500,7 +540,7 @@ class GenerateSitemap extends Maintenance {
/**
* Return the XML required to close sitemap file
*
- * @return String
+ * @return string
*/
function closeFile() {
return "</urlset>\n";
@@ -508,6 +548,8 @@ class GenerateSitemap extends Maintenance {
/**
* Populate $this->limit
+ *
+ * @param int $namespace
*/
function generateLimit( $namespace ) {
// bug 17961: make a title with the longest possible URL in this namespace
@@ -515,7 +557,11 @@ class GenerateSitemap extends Maintenance {
$this->limit = array(
strlen( $this->openFile() ),
- strlen( $this->fileEntry( $title->getCanonicalURL(), wfTimestamp( TS_ISO_8601, wfTimestamp() ), $this->priority( $namespace ) ) ),
+ strlen( $this->fileEntry(
+ $title->getCanonicalURL(),
+ wfTimestamp( TS_ISO_8601, wfTimestamp() ),
+ $this->priority( $namespace )
+ ) ),
strlen( $this->closeFile() )
);
}
diff --git a/maintenance/getConfiguration.php b/maintenance/getConfiguration.php
index 5a5eb587..d5f68346 100644
--- a/maintenance/getConfiguration.php
+++ b/maintenance/getConfiguration.php
@@ -63,7 +63,7 @@ class GetConfiguration extends Maintenance {
$format = strtolower( $this->getOption( 'format', 'PHP' ) );
$validFormat = in_array( $format, self::$outFormats );
- if ( ! $validFormat ) {
+ if ( !$validFormat ) {
$this->error( "--format set to an unrecognized format", 0 );
$error_out = true;
}
@@ -87,11 +87,11 @@ class GetConfiguration extends Maintenance {
public function finalSetup() {
parent::finalSetup();
- $this->regex = $this->getOption( 'regex' ) ? : $this->getOption( 'iregex' );
+ $this->regex = $this->getOption( 'regex' ) ?: $this->getOption( 'iregex' );
if ( $this->regex ) {
$this->regex = '/' . $this->regex . '/';
if ( $this->hasOption( 'iregex' ) ) {
- $this->regex .= 'i'; # case insensitive regex
+ $this->regex .= 'i'; # case insensitive regex
}
}
@@ -115,7 +115,7 @@ class GetConfiguration extends Maintenance {
$res = array();
# Sane default: dump any wg / wmg variable
- if ( ! $this->regex && ! $this->getOption( 'settings' ) ) {
+ if ( !$this->regex && !$this->getOption( 'settings' ) ) {
$this->regex = '/^wm?g/';
}
@@ -165,7 +165,7 @@ class GetConfiguration extends Maintenance {
protected function formatVarDump( $res ) {
$ret = '';
foreach ( $res as $key => $value ) {
- ob_start(); # intercept var_dump() output
+ ob_start(); # intercept var_dump() output
print "\${$key} = ";
var_dump( $value );
# grab var_dump() output and discard it from the output buffer
@@ -182,10 +182,12 @@ class GetConfiguration extends Maintenance {
return false;
}
}
+
return true;
} elseif ( is_scalar( $value ) ) {
return true;
}
+
return false;
}
}
diff --git a/maintenance/getSlaveServer.php b/maintenance/getSlaveServer.php
index d618825f..68c19439 100644
--- a/maintenance/getSlaveServer.php
+++ b/maintenance/getSlaveServer.php
@@ -34,6 +34,7 @@ class GetSlaveServer extends Maintenance {
$this->addOption( "group", "Query group to check specifically" );
$this->mDescription = "Report the hostname of a slave server";
}
+
public function execute() {
global $wgAllDBsAreLocalhost;
if ( $wgAllDBsAreLocalhost ) {
diff --git a/maintenance/getText.php b/maintenance/getText.php
index 9c4bdfb8..7d7c1cc4 100644
--- a/maintenance/getText.php
+++ b/maintenance/getText.php
@@ -52,7 +52,10 @@ class GetTextMaint extends Maintenance {
$titleText = $title->getPrefixedText();
$this->error( "Page $titleText does not exist.\n", true );
}
- $content = $rev->getContent( $this->hasOption( 'show-private' ) ? Revision::RAW : Revision::FOR_PUBLIC );
+ $content = $rev->getContent( $this->hasOption( 'show-private' )
+ ? Revision::RAW
+ : Revision::FOR_PUBLIC );
+
if ( $content === false ) {
$titleText = $title->getPrefixedText();
$this->error( "Couldn't extract the text from $titleText.\n", true );
diff --git a/maintenance/importDump.php b/maintenance/importDump.php
index 1f47cf12..1f75bccf 100644
--- a/maintenance/importDump.php
+++ b/maintenance/importDump.php
@@ -3,7 +3,7 @@
* Import XML dump files into the current wiki.
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -42,8 +42,12 @@ class BackupReader extends Maintenance {
function __construct() {
parent::__construct();
- $gz = in_array( 'compress.zlib', stream_get_wrappers() ) ? 'ok' : '(disabled; requires PHP zlib module)';
- $bz2 = in_array( 'compress.bzip2', stream_get_wrappers() ) ? 'ok' : '(disabled; requires PHP bzip2 module)';
+ $gz = in_array( 'compress.zlib', stream_get_wrappers() )
+ ? 'ok'
+ : '(disabled; requires PHP zlib module)';
+ $bz2 = in_array( 'compress.bzip2', stream_get_wrappers() )
+ ? 'ok'
+ : '(disabled; requires PHP bzip2 module)';
$this->mDescription = <<<TEXT
This script reads pages from an XML file as produced from Special:Export or
@@ -56,7 +60,7 @@ Compressed XML files may be read directly:
Note that for very large data sets, importDump.php may be slow; there are
alternate methods which can be much faster for full site restoration:
-<http://www.mediawiki.org/wiki/Manual:Importing_XML_dumps>
+<https://www.mediawiki.org/wiki/Manual:Importing_XML_dumps>
TEXT;
$this->stderr = fopen( "php://stderr", "wt" );
$this->addOption( 'report',
@@ -67,7 +71,10 @@ TEXT;
$this->addOption( 'dry-run', 'Parse dump without actually importing pages' );
$this->addOption( 'debug', 'Output extra verbose debug information' );
$this->addOption( 'uploads', 'Process file upload data if included (experimental)' );
- $this->addOption( 'no-updates', 'Disable link table updates. Is faster but leaves the wiki in an inconsistent state' );
+ $this->addOption(
+ 'no-updates',
+ 'Disable link table updates. Is faster but leaves the wiki in an inconsistent state'
+ );
$this->addOption( 'image-base-path', 'Import files from a specified path', false, true );
$this->addArg( 'file', 'Dump file to import [else use stdin]', false );
}
@@ -104,6 +111,7 @@ TEXT;
function setNsfilter( array $namespaces ) {
if ( count( $namespaces ) == 0 ) {
$this->nsFilter = false;
+
return;
}
$this->nsFilter = array_unique( array_map( array( $this, 'getNsIndex' ), $namespaces ) );
@@ -122,7 +130,7 @@ TEXT;
}
/**
- * @param $obj Title|Revision
+ * @param Title|Revision $obj
* @return bool
*/
private function skippedNamespace( $obj ) {
@@ -133,9 +141,9 @@ TEXT;
} elseif ( $obj instanceof WikiRevision ) {
$ns = $obj->title->getNamespace();
} else {
- echo wfBacktrace();
- $this->error( "Cannot get namespace of object in " . __METHOD__, true );
+ throw new MWException( "Cannot get namespace of object in " . __METHOD__ );
}
+
return is_array( $this->nsFilter ) && !in_array( $ns, $this->nsFilter );
}
@@ -144,13 +152,13 @@ TEXT;
}
/**
- * @param $rev Revision
- * @return mixed
+ * @param Revision $rev
*/
function handleRevision( $rev ) {
$title = $rev->getTitle();
if ( !$title ) {
$this->progress( "Got bogus revision with null title!" );
+
return;
}
@@ -167,13 +175,13 @@ TEXT;
}
/**
- * @param $revision Revision
+ * @param Revision $revision
* @return bool
*/
function handleUpload( $revision ) {
if ( $this->uploads ) {
if ( $this->skippedNamespace( $revision ) ) {
- return;
+ return false;
}
$this->uploadCount++;
// $this->report();
@@ -183,9 +191,12 @@ TEXT;
// bluuuh hack
// call_user_func( $this->uploadCallback, $revision );
$dbw = wfGetDB( DB_MASTER );
+
return $dbw->deadlockLoop( array( $revision, 'importUpload' ) );
}
}
+
+ return false;
}
function handleLogItem( $rev ) {
@@ -242,6 +253,7 @@ TEXT;
}
$file = fopen( $filename, 'rt' );
+
return $this->importFromHandle( $file );
}
@@ -250,6 +262,7 @@ TEXT;
if ( self::posix_isatty( $file ) ) {
$this->maybeHelp( true );
}
+
return $this->importFromHandle( $file );
}
diff --git a/maintenance/importImages.inc b/maintenance/importImages.inc
index 5ae6d6be..b803e3da 100644
--- a/maintenance/importImages.inc
+++ b/maintenance/importImages.inc
@@ -26,10 +26,10 @@
/**
* Search a directory for files with one of a set of extensions
*
- * @param $dir string Path to directory to search
- * @param $exts Array of extensions to search for
- * @param $recurse Bool Search subdirectories recursively
- * @return mixed Array of filenames on success, or false on failure
+ * @param string $dir Path to directory to search
+ * @param array $exts Array of extensions to search for
+ * @param bool $recurse Search subdirectories recursively
+ * @return array|bool Array of filenames on success, or false on failure
*/
function findFiles( $dir, $exts, $recurse = false ) {
if ( is_dir( $dir ) ) {
@@ -46,6 +46,7 @@ function findFiles( $dir, $exts, $recurse = false ) {
$files = array_merge( $files, findFiles( $dir . '/' . $file, $exts, true ) );
}
}
+
return $files;
} else {
return array();
@@ -58,14 +59,15 @@ function findFiles( $dir, $exts, $recurse = false ) {
/**
* Split a filename into filename and extension
*
- * @param $filename string Filename
+ * @param string $filename Filename
* @return array
*/
function splitFilename( $filename ) {
$parts = explode( '.', $filename );
- $ext = $parts[ count( $parts ) - 1 ];
- unset( $parts[ count( $parts ) - 1 ] );
+ $ext = $parts[count( $parts ) - 1];
+ unset( $parts[count( $parts ) - 1] );
$fname = implode( '.', $parts );
+
return array( $fname, $ext );
}
@@ -78,10 +80,10 @@ function splitFilename( $filename ) {
* files for acme.foo.bar and the extension ".txt". With $maxStrip = 2,
* acme.txt would also be acceptable.
*
- * @param $file string base path
- * @param $auxExtension string the extension to be appended to the base path
- * @param $maxStrip int the maximum number of extensions to strip from the base path (default: 1)
- * @return string or false
+ * @param string $file Base path
+ * @param string $auxExtension The extension to be appended to the base path
+ * @param int $maxStrip The maximum number of extensions to strip from the base path (default: 1)
+ * @return string|bool
*/
function findAuxFile( $file, $auxExtension, $maxStrip = 1 ) {
if ( strpos( $auxExtension, '.' ) !== 0 ) {
@@ -110,9 +112,11 @@ function findAuxFile( $file, $auxExtension, $maxStrip = 1 ) {
return false;
}
-# FIXME: Access the api in a saner way and performing just one query (preferably batching files too).
+# @todo FIXME: Access the api in a saner way and performing just one query
+# (preferably batching files too).
function getFileCommentFromSourceWiki( $wiki_host, $file ) {
- $url = $wiki_host . '/api.php?action=query&format=xml&titles=File:' . rawurlencode( $file ) . '&prop=imageinfo&&iiprop=comment';
+ $url = $wiki_host . '/api.php?action=query&format=xml&titles=File:'
+ . rawurlencode( $file ) . '&prop=imageinfo&&iiprop=comment';
$body = Http::get( $url );
if ( preg_match( '#<ii comment="([^"]*)" />#', $body, $matches ) == 0 ) {
return false;
@@ -122,7 +126,8 @@ function getFileCommentFromSourceWiki( $wiki_host, $file ) {
}
function getFileUserFromSourceWiki( $wiki_host, $file ) {
- $url = $wiki_host . '/api.php?action=query&format=xml&titles=File:' . rawurlencode( $file ) . '&prop=imageinfo&&iiprop=user';
+ $url = $wiki_host . '/api.php?action=query&format=xml&titles=File:'
+ . rawurlencode( $file ) . '&prop=imageinfo&&iiprop=user';
$body = Http::get( $url );
if ( preg_match( '#<ii user="([^"]*)" />#', $body, $matches ) == 0 ) {
return false;
diff --git a/maintenance/importImages.php b/maintenance/importImages.php
index 54fd4e2d..ae70441f 100644
--- a/maintenance/importImages.php
+++ b/maintenance/importImages.php
@@ -4,7 +4,8 @@
* using the web-based interface.
*
* "Smart import" additions:
- * - aim: preserve the essential metadata (user, description) when importing medias from an existing wiki
+ * - aim: preserve the essential metadata (user, description) when importing media
+ * files from an existing wiki.
* - process:
* - interface with the source wiki, don't use bare files only (see --source-wiki-url).
* - fetch metadata from source wiki for each file to import.
@@ -87,16 +88,24 @@ if ( isset( $options['check-userblock'] ) ) {
}
# Get --from
-$from = @$options['from'];
+wfSuppressWarnings();
+$from = $options['from'];
+wfRestoreWarnings();
# Get sleep time.
-$sleep = @$options['sleep'];
+wfSuppressWarnings();
+$sleep = $options['sleep'];
+wfRestoreWarnings();
+
if ( $sleep ) {
$sleep = (int)$sleep;
}
# Get limit number
-$limit = @$options['limit'];
+wfSuppressWarnings();
+$limit = $options['limit'];
+wfRestoreWarnings();
+
if ( $limit ) {
$limit = (int)$limit;
}
@@ -167,7 +176,8 @@ if ( $count > 0 ) {
} else {
if ( isset( $options['skip-dupes'] ) ) {
$repo = $image->getRepo();
- $sha1 = File::sha1Base36( $file ); # XXX: we end up calculating this again when actually uploading. that sucks.
+ # XXX: we end up calculating this again when actually uploading. that sucks.
+ $sha1 = FSFile::getSha1Base36FromPath( $file );
$dupes = $repo->findBySha1( $sha1 );
@@ -210,7 +220,8 @@ if ( $count > 0 ) {
if ( $commentExt ) {
$f = findAuxFile( $file, $commentExt );
if ( !$f ) {
- echo " No comment file with extension {$commentExt} found for {$file}, using default comment. ";
+ echo " No comment file with extension {$commentExt} found "
+ . "for {$file}, using default comment. ";
} else {
$commentText = file_get_contents( $f );
if ( !$commentText ) {
@@ -254,7 +265,13 @@ if ( $count > 0 ) {
if ( isset( $options['dry'] ) ) {
echo "done.\n";
- } elseif ( $image->recordUpload2( $archive->value, $summary, $commentText, $props, $timestamp ) ) {
+ } elseif ( $image->recordUpload2(
+ $archive->value,
+ $summary,
+ $commentText,
+ $props,
+ $timestamp
+ ) ) {
# We're done!
echo "done.\n";
@@ -273,25 +290,24 @@ if ( $count > 0 ) {
}
if ( $doProtect ) {
- # Protect the file
- echo "\nWaiting for slaves...\n";
- // Wait for slaves.
- sleep( 2.0 ); # Why this sleep?
- wfWaitForSlaves();
-
- echo "\nSetting image restrictions ... ";
-
- $cascade = false;
- $restrictions = array();
- foreach ( $title->getRestrictionTypes() as $type ) {
- $restrictions[$type] = $protectLevel;
- }
+ # Protect the file
+ echo "\nWaiting for slaves...\n";
+ // Wait for slaves.
+ sleep( 2.0 ); # Why this sleep?
+ wfWaitForSlaves();
+
+ echo "\nSetting image restrictions ... ";
+
+ $cascade = false;
+ $restrictions = array();
+ foreach ( $title->getRestrictionTypes() as $type ) {
+ $restrictions[$type] = $protectLevel;
+ }
- $page = WikiPage::factory( $title );
- $status = $page->doUpdateRestrictions( $restrictions, array(), $cascade, '', $user );
- echo ( $status->isOK() ? 'done' : 'failed' ) . "\n";
+ $page = WikiPage::factory( $title );
+ $status = $page->doUpdateRestrictions( $restrictions, array(), $cascade, '', $user );
+ echo ( $status->isOK() ? 'done' : 'failed' ) . "\n";
}
-
} else {
echo "failed. (at recordUpload stage)\n";
$svar = 'failed';
@@ -311,14 +327,21 @@ if ( $count > 0 ) {
# Print out some statistics
echo "\n";
- foreach ( array( 'count' => 'Found', 'limit' => 'Limit', 'ignored' => 'Ignored',
- 'added' => 'Added', 'skipped' => 'Skipped', 'overwritten' => 'Overwritten',
- 'failed' => 'Failed' ) as $var => $desc ) {
+ foreach (
+ array(
+ 'count' => 'Found',
+ 'limit' => 'Limit',
+ 'ignored' => 'Ignored',
+ 'added' => 'Added',
+ 'skipped' => 'Skipped',
+ 'overwritten' => 'Overwritten',
+ 'failed' => 'Failed'
+ ) as $var => $desc
+ ) {
if ( $$var > 0 ) {
echo "{$desc}: {$$var}\n";
}
}
-
} else {
echo "No suitable files could be found for import.\n";
}
@@ -337,28 +360,37 @@ USAGE: php importImages.php [options] <dir>
<dir> : Path to the directory containing images to be imported
Options:
---extensions=<exts> Comma-separated list of allowable extensions, defaults to \$wgFileExtensions
---overwrite Overwrite existing images with the same name (default is to skip them)
---limit=<num> Limit the number of images to process. Ignored or skipped images are not counted.
---from=<name> Ignore all files until the one with the given name. Useful for resuming
- aborted imports. <name> should be the file's canonical database form.
---skip-dupes Skip images that were already uploaded under a different name (check SHA1)
---search-recursively Search recursively for files in subdirectories
+--extensions=<exts> Comma-separated list of allowable extensions, defaults
+ to \$wgFileExtensions.
+--overwrite Overwrite existing images with the same name (default
+ is to skip them).
+--limit=<num> Limit the number of images to process. Ignored or
+ skipped images are not counted.
+--from=<name> Ignore all files until the one with the given name.
+ Useful for resuming aborted imports. <name> should be
+ the file's canonical database form.
+--skip-dupes Skip images that were already uploaded under a different
+ name (check SHA1).
+--search-recursively Search recursively for files in subdirectories.
--sleep=<sec> Sleep between files. Useful mostly for debugging.
---user=<username> Set username of uploader, default 'Maintenance script'
+--user=<username> Set username of uploader, default 'Maintenance script'.
--check-userblock Check if the user got blocked during import.
--comment=<text> Set file description, default 'Importing file'.
--comment-file=<file> Set description to the content of <file>.
---comment-ext=<ext> Causes the description for each file to be loaded from a file with the same name
- but the extension <ext>. If a global description is also given, it is appended.
---license=<code> Use an optional license template
---dry Dry run, don't import anything
---protect=<protect> Specify the protect value (autoconfirmed,sysop)
---summary=<summary> Upload summary, description will be used if not provided
---timestamp=<timestamp> Override upload time/date, all MediaWiki timestamp formats are accepted
---unprotect Unprotects all uploaded images
---source-wiki-url If specified, take User and Comment data for each imported file from this URL.
- For example, --source-wiki-url="http://en.wikipedia.org/"
+--comment-ext=<ext> Causes the description for each file to be loaded from a
+ file with the same name, but the extension <ext>. If a
+ global description is also given, it is appended.
+--license=<code> Use an optional license template.
+--dry Dry run, don't import anything.
+--protect=<protect> Specify the protect value (autoconfirmed,sysop).
+--summary=<summary> Upload summary, description will be used if not
+ provided.
+--timestamp=<timestamp> Override upload time/date, all MediaWiki timestamp
+ formats are accepted.
+--unprotect Unprotects all uploaded images.
+--source-wiki-url If specified, take User and Comment data for each
+ imported file from this URL. For example,
+ --source-wiki-url="http://en.wikipedia.org/."
TEXT;
exit( 1 );
diff --git a/maintenance/importSiteScripts.php b/maintenance/importSiteScripts.php
index fd768b34..7705ec9c 100644
--- a/maintenance/importSiteScripts.php
+++ b/maintenance/importSiteScripts.php
@@ -65,13 +65,12 @@ class ImportSiteScripts extends Maintenance {
$content = ContentHandler::makeContent( $text, $wikiPage->getTitle() );
$wikiPage->doEditContent( $content, "Importing from $url", 0, false, $user );
}
-
}
protected function fetchScriptList() {
$data = array(
'action' => 'query',
- 'format' => 'php',//'json',
+ 'format' => 'php', //'json',
'list' => 'allpages',
'apnamespace' => '8',
'aplimit' => '500',
@@ -100,7 +99,6 @@ class ImportSiteScripts extends Maintenance {
} while ( isset( $result['query-continue'] ) );
return $pages;
-
}
}
diff --git a/maintenance/importTextFile.php b/maintenance/importTextFile.php
deleted file mode 100644
index 4a07f2c7..00000000
--- a/maintenance/importTextFile.php
+++ /dev/null
@@ -1,110 +0,0 @@
-<?php
-/**
- * Create or edit pages using the contents of a text file.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- * @author Rob Church <robchur@gmail.com>
- */
-
-$options = array( 'help', 'nooverwrite', 'norc' );
-$optionsWithArgs = array( 'title', 'user', 'comment' );
-require_once __DIR__ . '/commandLine.inc';
-echo "Import Text File\n\n";
-
-if ( count( $args ) < 1 || isset( $options['help'] ) ) {
- showHelp();
-} else {
-
- $filename = $args[0];
- echo "Using {$filename}...";
- if ( is_file( $filename ) ) {
-
- $title = isset( $options['title'] ) ? $options['title'] : titleFromFilename( $filename );
- $title = Title::newFromURL( $title );
-
- if ( is_object( $title ) ) {
-
- echo "\nUsing title '" . $title->getPrefixedText() . "'...";
- if ( !$title->exists() || !isset( $options['nooverwrite'] ) ) {
- RequestContext::getMain()->setTitle( $title );
-
- $text = file_get_contents( $filename );
- $user = isset( $options['user'] ) ? $options['user'] : 'Maintenance script';
- $user = User::newFromName( $user );
-
- if ( is_object( $user ) ) {
-
- echo "\nUsing username '" . $user->getName() . "'...";
- $wgUser =& $user;
- $comment = isset( $options['comment'] ) ? $options['comment'] : 'Importing text file';
- $flags = 0 | ( isset( $options['norc'] ) ? EDIT_SUPPRESS_RC : 0 );
-
- echo "\nPerforming edit...";
- $page = WikiPage::factory( $title );
- $content = ContentHandler::makeContent( $text, $title );
- $page->doEditContent( $content, $comment, $flags, false, $user );
- echo "done.\n";
-
- } else {
- echo "invalid username.\n";
- }
-
- } else {
- echo "page exists.\n";
- }
-
- } else {
- echo "invalid title.\n";
- }
-
- } else {
- echo "does not exist.\n";
- }
-
-}
-
-function titleFromFilename( $filename ) {
- $parts = explode( '/', $filename );
- $parts = explode( '.', $parts[ count( $parts ) - 1 ] );
- return $parts[0];
-}
-
-function showHelp() {
-print <<<EOF
-USAGE: php importTextFile.php <options> <filename>
-
-<filename> : Path to the file containing page content to import
-
-Options:
-
---title <title>
- Title for the new page; default is to use the filename as a base
---user <user>
- User to be associated with the edit
---comment <comment>
- Edit summary
---nooverwrite
- Don't overwrite existing content
---norc
- Don't update recent changes
---help
- Show this information
-
-EOF;
-}
diff --git a/maintenance/initEditCount.php b/maintenance/initEditCount.php
index 4b046835..7c6e7d4f 100644
--- a/maintenance/initEditCount.php
+++ b/maintenance/initEditCount.php
@@ -47,7 +47,7 @@ in the load balancer, usually indicating a replication environment.' );
// Autodetect mode...
$backgroundMode = wfGetLB()->getServerCount() > 1 ||
- ( $dbw instanceof DatabaseMysql && version_compare( $dbver, '4.1' ) < 0 );
+ ( $dbw instanceof DatabaseMysql );
if ( $this->hasOption( 'background' ) ) {
$backgroundMode = true;
diff --git a/maintenance/initSiteStats.php b/maintenance/initSiteStats.php
index 92268b3e..49e0e9d7 100644
--- a/maintenance/initSiteStats.php
+++ b/maintenance/initSiteStats.php
@@ -34,7 +34,10 @@ class InitSiteStats extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Re-initialise the site statistics tables";
- $this->addOption( 'update', 'Update the existing statistics (preserves the ss_total_views field)' );
+ $this->addOption(
+ 'update',
+ 'Update the existing statistics (preserves the ss_total_views field)'
+ );
$this->addOption( 'noviews', "Don't update the page view counter" );
$this->addOption( 'active', 'Also update active users count' );
$this->addOption( 'use-master', 'Count using the master database' );
@@ -66,21 +69,19 @@ class InitSiteStats extends Maintenance {
$this->output( "{$views}\n" );
}
+ if ( $this->hasOption( 'update' ) ) {
+ $this->output( "\nUpdating site statistics..." );
+ $counter->refresh();
+ $this->output( "done.\n" );
+ }
+
if ( $this->hasOption( 'active' ) ) {
- $this->output( "Counting active users..." );
+ $this->output( "\nCounting and updating active users..." );
$active = SiteStatsUpdate::cacheUpdate( wfGetDB( DB_MASTER ) );
$this->output( "{$active}\n" );
}
- $this->output( "\nUpdating site statistics..." );
-
- if ( $this->hasOption( 'update' ) ) {
- $counter->update();
- } else {
- $counter->refresh();
- }
-
- $this->output( "done.\n" );
+ $this->output( "\nDone.\n" );
}
}
diff --git a/maintenance/install.php b/maintenance/install.php
index d118747a..b948b674 100644
--- a/maintenance/install.php
+++ b/maintenance/install.php
@@ -21,19 +21,20 @@
* @ingroup Maintenance
*/
-if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.3.2' ) < 0 ) ) {
- require_once dirname( __FILE__ ) . '/../includes/PHPVersionError.php';
- wfPHPVersionError( 'cli' );
-}
+// Checking for old versions of PHP is done in Maintenance.php
+// We need to use dirname( __FILE__ ) here cause __DIR__ is PHP5.3+
+require_once dirname( __FILE__ ) . '/Maintenance.php';
define( 'MW_CONFIG_CALLBACK', 'Installer::overrideConfig' );
define( 'MEDIAWIKI_INSTALL', true );
-require_once dirname( __DIR__ ) . "/maintenance/Maintenance.php";
-
/**
* Maintenance script to install and configure MediaWiki
*
+ * Default values for the options are defined in DefaultSettings.php
+ * (see the mapping in CliInstaller.php)
+ * Default for --dbpath (SQLite-specific) is defined in SqliteInstaller::getGlobalDefaults
+ *
* @ingroup Maintenance
*/
class CommandLineInstaller extends Maintenance {
@@ -41,13 +42,26 @@ class CommandLineInstaller extends Maintenance {
parent::__construct();
global $IP;
- $this->addArg( 'name', 'The name of the wiki', true );
+ $this->addDescription( "CLI-based MediaWiki installation and configuration.\n" .
+ "Defaut options are indicated in parenthesis." );
+
+ $this->addArg( 'name', 'The name of the wiki (MediaWiki)', false );
- $this->addArg( 'admin', 'The username of the wiki administrator (WikiSysop)', true );
+ $this->addArg( 'admin', 'The username of the wiki administrator.' );
$this->addOption( 'pass', 'The password for the wiki administrator.', false, true );
- $this->addOption( 'passfile', 'An alternative way to provide pass option, as the contents of this file', false, true );
+ $this->addOption(
+ 'passfile',
+ 'An alternative way to provide pass option, as the contents of this file',
+ false,
+ true
+ );
/* $this->addOption( 'email', 'The email for the wiki administrator', false, true ); */
- $this->addOption( 'scriptpath', 'The relative path of the wiki in the web server (/wiki)', false, true );
+ $this->addOption(
+ 'scriptpath',
+ 'The relative path of the wiki in the web server (/wiki)',
+ false,
+ true
+ );
$this->addOption( 'lang', 'The language to use (en)', false, true );
/* $this->addOption( 'cont-lang', 'The content language (en)', false, true ); */
@@ -56,32 +70,42 @@ class CommandLineInstaller extends Maintenance {
$this->addOption( 'dbserver', 'The database host (localhost)', false, true );
$this->addOption( 'dbport', 'The database port; only for PostgreSQL (5432)', false, true );
$this->addOption( 'dbname', 'The database name (my_wiki)', false, true );
- $this->addOption( 'dbpath', 'The path for the SQLite DB (/var/data)', false, true );
+ $this->addOption( 'dbpath', 'The path for the SQLite DB ($IP/data)', false, true );
$this->addOption( 'dbprefix', 'Optional database table name prefix', false, true );
$this->addOption( 'installdbuser', 'The user to use for installing (root)', false, true );
- $this->addOption( 'installdbpass', 'The pasword for the DB user to install as.', false, true );
+ $this->addOption( 'installdbpass', 'The password for the DB user to install as.', false, true );
$this->addOption( 'dbuser', 'The user to use for normal operations (wikiuser)', false, true );
- $this->addOption( 'dbpass', 'The pasword for the DB user for normal operations', false, true );
- $this->addOption( 'dbpassfile', 'An alternative way to provide dbpass option, as the contents of this file', false, true );
- $this->addOption( 'confpath', "Path to write LocalSettings.php to, default $IP", false, true );
- /* $this->addOption( 'dbschema', 'The schema for the MediaWiki DB in pg (mediawiki)', false, true ); */
- /* $this->addOption( 'namespace', 'The project namespace (same as the name)', false, true ); */
+ $this->addOption( 'dbpass', 'The password for the DB user for normal operations', false, true );
+ $this->addOption(
+ 'dbpassfile',
+ 'An alternative way to provide dbpass option, as the contents of this file',
+ false,
+ true
+ );
+ $this->addOption( 'confpath', "Path to write LocalSettings.php to ($IP)", false, true );
+ $this->addOption( 'dbschema', 'The schema for the MediaWiki DB in '
+ . 'PostgreSQL/Microsoft SQL Server (mediawiki)', false, true );
+ /*
+ $this->addOption( 'namespace', 'The project namespace (same as the "name" argument)',
+ false, true );
+ */
$this->addOption( 'env-checks', "Run environment checks only, don't change anything" );
}
function execute() {
- global $IP, $wgTitle;
- $siteName = isset( $this->mArgs[0] ) ? $this->mArgs[0] : "Don't care"; // Will not be set if used with --env-checks
- $adminName = isset( $this->mArgs[1] ) ? $this->mArgs[1] : null;
- $wgTitle = Title::newFromText( 'Installer script' );
-
- $dbpassfile = $this->getOption( 'dbpassfile', false );
- if ( $dbpassfile !== false ) {
- if ( $this->getOption( 'dbpass', false ) !== false ) {
- $this->error( 'WARNING: You provide the options "dbpass" and "dbpassfile". The content of "dbpassfile" overwrites "dbpass".' );
+ global $IP;
+
+ $siteName = $this->getArg( 0, 'MediaWiki' ); // Will not be set if used with --env-checks
+ $adminName = $this->getArg( 1 );
+
+ $dbpassfile = $this->getOption( 'dbpassfile' );
+ if ( $dbpassfile !== null ) {
+ if ( $this->getOption( 'dbpass' ) !== null ) {
+ $this->error( 'WARNING: You have provided the options "dbpass" and "dbpassfile". '
+ . 'The content of "dbpassfile" overrides "dbpass".' );
}
wfSuppressWarnings();
- $dbpass = file_get_contents( $dbpassfile );
+ $dbpass = file_get_contents( $dbpassfile ); // returns false on failure
wfRestoreWarnings();
if ( $dbpass === false ) {
$this->error( "Couldn't open $dbpassfile", true );
@@ -89,30 +113,31 @@ class CommandLineInstaller extends Maintenance {
$this->mOptions['dbpass'] = trim( $dbpass, "\r\n" );
}
- $passfile = $this->getOption( 'passfile', false );
- if ( $passfile !== false ) {
- if ( $this->getOption( 'pass', false ) !== false ) {
- $this->error( 'WARNING: You provide the options "pass" and "passfile". The content of "passfile" overwrites "pass".' );
+ $passfile = $this->getOption( 'passfile' );
+ if ( $passfile !== null ) {
+ if ( $this->getOption( 'pass' ) !== null ) {
+ $this->error( 'WARNING: You have provided the options "pass" and "passfile". '
+ . 'The content of "passfile" overrides "pass".' );
}
wfSuppressWarnings();
- $pass = file_get_contents( $passfile );
+ $pass = file_get_contents( $passfile ); // returns false on failure
wfRestoreWarnings();
if ( $pass === false ) {
$this->error( "Couldn't open $passfile", true );
}
- $this->mOptions['pass'] = str_replace( array( "\n", "\r" ), "", $pass );
- } elseif ( $this->getOption( 'pass', false ) === false ) {
+ $this->mOptions['pass'] = trim( $pass, "\r\n" );
+ } elseif ( $this->getOption( 'pass' ) === null ) {
$this->error( 'You need to provide the option "pass" or "passfile"', true );
}
- $installer =
- InstallerOverrides::getCliInstaller( $siteName, $adminName, $this->mOptions );
+ $installer = InstallerOverrides::getCliInstaller( $siteName, $adminName, $this->mOptions );
$status = $installer->doEnvironmentChecks();
if ( $status->isGood() ) {
$installer->showMessage( 'config-env-good' );
} else {
$installer->showStatusMessage( $status );
+
return;
}
if ( !$this->hasOption( 'env-checks' ) ) {
@@ -128,6 +153,6 @@ class CommandLineInstaller extends Maintenance {
}
}
-$maintClass = "CommandLineInstaller";
+$maintClass = 'CommandLineInstaller';
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/interwiki.list b/maintenance/interwiki.list
index 179fa5c6..0660e55f 100644
--- a/maintenance/interwiki.list
+++ b/maintenance/interwiki.list
@@ -1,98 +1,77 @@
# Based more or less on the public interwiki map from MeatballWiki
# Default interwiki prefixes...
-acronym|http://www.acronymfinder.com/af-query.asp?String=exact&Acronym=$1|0
+acronym|http://www.acronymfinder.com/~/search/af.aspx?string=exact&Acronym=$1|0
advogato|http://www.advogato.org/$1|0
-annotationwiki|http://www.seedwiki.com/page.cfm?wikiid=368&doc=$1|0
arxiv|http://www.arxiv.org/abs/$1|0
c2find|http://c2.com/cgi/wiki?FindPage&value=$1|0
cache|http://www.google.com/search?q=cache:$1|0
-commons|http://commons.wikimedia.org/wiki/$1|0
-corpknowpedia|http://corpknowpedia.org/wiki/index.php/$1|0
+commons|https://commons.wikimedia.org/wiki/$1|0
dictionary|http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=$1|0
-disinfopedia|http://www.disinfopedia.org/wiki.phtml?title=$1|0
-docbook|http://wiki.docbook.org/topic/$1|0
+docbook|http://wiki.docbook.org/$1|0
doi|http://dx.doi.org/$1|0
-drumcorpswiki|http://www.drumcorpswiki.com/index.php/$1|0
+drumcorpswiki|http://www.drumcorpswiki.com/$1|0
dwjwiki|http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1|0
elibre|http://enciclopedia.us.es/index.php/$1|0
emacswiki|http://www.emacswiki.org/cgi-bin/wiki.pl?$1|0
foldoc|http://foldoc.org/?$1|0
foxwiki|http://fox.wikis.com/wc.dll?Wiki~$1|0
freebsdman|http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1|0
-gej|http://www.esperanto.de/cgi-bin/aktivikio/wiki.pl?$1|0
+gej|http://www.esperanto.de/dej.malnova/aktivikio.pl?$1|0
gentoo-wiki|http://gentoo-wiki.com/$1|0
google|http://www.google.com/search?q=$1|0
googlegroups|http://groups.google.com/groups?q=$1|0
hammondwiki|http://www.dairiki.org/HammondWiki/$1|0
-hewikisource|http://he.wikisource.org/wiki/$1|1
-hrwiki|http://www.hrwiki.org/index.php/$1|0
-imdb|http://us.imdb.com/Title?$1|0
+hrwiki|http://www.hrwiki.org/wiki/$1|0
+imdb|http://www.imdb.com/find?q=$1&tt=on|0
jargonfile|http://sunir.org/apps/meta.pl?wiki=JargonFile&redirect=$1|0
-jspwiki|http://www.jspwiki.org/wiki/$1|0
-keiki|http://kei.ki/en/$1|0
kmwiki|http://kmwiki.wikispaces.com/$1|0
linuxwiki|http://linuxwiki.de/$1|0
lojban|http://www.lojban.org/tiki/tiki-index.php?page=$1|0
lqwiki|http://wiki.linuxquestions.org/wiki/$1|0
-lugkr|http://lug-kr.sourceforge.net/cgi-bin/lugwiki.pl?$1|0
-mathsongswiki|http://SeedWiki.com/page.cfm?wikiid=237&doc=$1|0
+lugkr|http://www.lug-kr.de/wiki/$1|0
meatball|http://www.usemod.com/cgi-bin/mb.pl?$1|0
-mediawikiwiki|http://www.mediawiki.org/wiki/$1|0
-mediazilla|https://bugzilla.wikimedia.org/$1|1
-memoryalpha|http://www.memory-alpha.org/en/index.php/$1|0
+mediawikiwiki|https://www.mediawiki.org/wiki/$1|0
+mediazilla|https://bugzilla.wikimedia.org/$1|0
+memoryalpha|http://en.memory-alpha.org/wiki/$1|0
metawiki|http://sunir.org/apps/meta.pl?$1|0
-metawikimedia|http://meta.wikimedia.org/wiki/$1|0
-moinmoin|http://purl.net/wiki/moin/$1|0
-mozillawiki|http://wiki.mozilla.org/index.php/$1|0
+metawikimedia|https://meta.wikimedia.org/wiki/$1|0
+mozillawiki|http://wiki.mozilla.org/$1|0
mw|http://www.mediawiki.org/wiki/$1|0
-oeis|http://www.research.att.com/cgi-bin/access.cgi/as/njas/sequences/eisA.cgi?Anum=$1|0
-openfacts|http://openfacts.berlios.de/index.phtml?title=$1|0
-openwiki|http://openwiki.com/?$1|0
-# patwiki|http://gauss.ffii.org/$1|0 # 2008-02-27: lots of spambots
-pmeg|http://www.bertilow.com/pmeg/$1.php|0
+oeis|http://oeis.org/$1|0
+openwiki|http://openwiki.com/ow.asp?$1|0
ppr|http://c2.com/cgi/wiki?$1|0
pythoninfo|http://wiki.python.org/moin/$1|0
rfc|http://www.rfc-editor.org/rfc/rfc$1.txt|0
-s23wiki|http://is-root.de/wiki/index.php/$1|0
-seattlewiki|http://seattle.wikia.com/wiki/$1|0
-seattlewireless|http://seattlewireless.net/?$1|0
+s23wiki|http://s23.org/wiki/$1|0
+seattlewireless|http://seattlewireless.net/$1|0
senseislibrary|http://senseis.xmp.net/?$1|0
-# slashdot|http://slashdot.org/article.pl?sid=$1|0 # 2008-02-27: update me
+shoutwiki|http://www.shoutwiki.com/wiki/$1|0
sourceforge|http://sourceforge.net/$1|0
+sourcewatch|http://www.sourcewatch.org/index.php?title=$1|0
squeak|http://wiki.squeak.org/squeak/$1|0
-susning|http://www.susning.nu/$1|0
-svgwiki|http://wiki.svg.org/$1|0
-tavi|http://tavi.sourceforge.net/$1|0
tejo|http://www.tejo.org/vikio/$1|0
tmbw|http://www.tmbw.net/wiki/$1|0
tmnet|http://www.technomanifestos.net/?$1|0
-tmwiki|http://www.EasyTopicMaps.com/?page=$1|0
theopedia|http://www.theopedia.com/$1|0
twiki|http://twiki.org/cgi-bin/view/$1|0
-uea|http://www.tejo.org/uea/$1|0
-unreal|http://wiki.beyondunreal.com/wiki/$1|0
+uea|http://uea.org/vikio/index.php/$1|0
+uncyclopedia|http://en.uncyclopedia.co/wiki/$1|0
+unreal|http://wiki.beyondunreal.com/$1|0
usemod|http://www.usemod.com/cgi-bin/wiki.pl?$1|0
-vinismo|http://vinismo.com/en/$1|0
webseitzwiki|http://webseitz.fluxent.com/wiki/$1|0
-why|http://clublet.com/c/c/why?$1|0
wiki|http://c2.com/cgi/wiki?$1|0
wikia|http://www.wikia.com/wiki/$1|0
-wikibooks|http://en.wikibooks.org/wiki/$1|1
-wikicities|http://www.wikia.com/wiki/$1|0
+wikibooks|https://en.wikibooks.org/wiki/$1|0
wikif1|http://www.wikif1.org/$1|0
wikihow|http://www.wikihow.com/$1|0
-wikinfo|http://www.wikinfo.org/index.php/$1|0
-# The following wik[it]* interwikis but wikitravel belong to the Wikimedia Family:
-wikimedia|http://wikimediafoundation.org/wiki/$1|0
-wikinews|http://en.wikinews.org/wiki/$1|1
-wikipedia|http://en.wikipedia.org/wiki/$1|1
-wikiquote|http://en.wikiquote.org/wiki/$1|1
-wikisource|http://wikisource.org/wiki/$1|1
-wikispecies|http://species.wikimedia.org/wiki/$1|1
-wikitravel|http://wikitravel.org/en/$1|0
-wikiversity|http://en.wikiversity.org/wiki/$1|1
-wikt|http://en.wiktionary.org/wiki/$1|1
-wiktionary|http://en.wiktionary.org/wiki/$1|1
-wlug|http://www.wlug.org.nz/$1|0
-zwiki|http://zwiki.org/$1|0
-zzz wiki|http://wiki.zzz.ee/index.php/$1|0
+wikinfo|http://wikinfo.co/English/index.php/$1|0
+wikimedia|https://wikimediafoundation.org/wiki/$1|0
+wikinews|https://en.wikinews.org/wiki/$1|0
+wikipedia|https://en.wikipedia.org/wiki/$1|0
+wikiquote|https://en.wikiquote.org/wiki/$1|0
+wikisource|https://wikisource.org/wiki/$1|0
+wikispecies|https://species.wikimedia.org/wiki/$1|0
+wikiversity|https://en.wikiversity.org/wiki/$1|0
+wikivoyage|https://en.wikivoyage.org/wiki/$1|0
+wikt|https://en.wiktionary.org/wiki/$1|0
+wiktionary|https://en.wiktionary.org/wiki/$1|0
diff --git a/maintenance/interwiki.sql b/maintenance/interwiki.sql
index 370460af..aad0cc3b 100644
--- a/maintenance/interwiki.sql
+++ b/maintenance/interwiki.sql
@@ -2,99 +2,79 @@
-- Default interwiki prefixes...
REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES
-('acronym','http://www.acronymfinder.com/af-query.asp?String=exact&Acronym=$1',0),
+('acronym','http://www.acronymfinder.com/~/search/af.aspx?string=exact&Acronym=$1',0),
('advogato','http://www.advogato.org/$1',0),
-('annotationwiki','http://www.seedwiki.com/page.cfm?wikiid=368&doc=$1',0),
('arxiv','http://www.arxiv.org/abs/$1',0),
('c2find','http://c2.com/cgi/wiki?FindPage&value=$1',0),
('cache','http://www.google.com/search?q=cache:$1',0),
-('commons','http://commons.wikimedia.org/wiki/$1',0),
-('corpknowpedia','http://corpknowpedia.org/wiki/index.php/$1',0),
+('commons','https://commons.wikimedia.org/wiki/$1',0),
('dictionary','http://www.dict.org/bin/Dict?Database=*&Form=Dict1&Strategy=*&Query=$1',0),
-('disinfopedia','http://www.disinfopedia.org/wiki.phtml?title=$1',0),
-('docbook','http://wiki.docbook.org/topic/$1',0),
+('docbook','http://wiki.docbook.org/$1',0),
('doi','http://dx.doi.org/$1',0),
-('drumcorpswiki','http://www.drumcorpswiki.com/index.php/$1',0),
+('drumcorpswiki','http://www.drumcorpswiki.com/$1',0),
('dwjwiki','http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1',0),
('elibre','http://enciclopedia.us.es/index.php/$1',0),
('emacswiki','http://www.emacswiki.org/cgi-bin/wiki.pl?$1',0),
('foldoc','http://foldoc.org/?$1',0),
('foxwiki','http://fox.wikis.com/wc.dll?Wiki~$1',0),
('freebsdman','http://www.FreeBSD.org/cgi/man.cgi?apropos=1&query=$1',0),
-('gej','http://www.esperanto.de/cgi-bin/aktivikio/wiki.pl?$1',0),
+('gej','http://www.esperanto.de/dej.malnova/aktivikio.pl?$1',0),
('gentoo-wiki','http://gentoo-wiki.com/$1',0),
('google','http://www.google.com/search?q=$1',0),
('googlegroups','http://groups.google.com/groups?q=$1',0),
('hammondwiki','http://www.dairiki.org/HammondWiki/$1',0),
-('hewikisource','http://he.wikisource.org/wiki/$1',1),
-('hrwiki','http://www.hrwiki.org/index.php/$1',0),
-('imdb','http://us.imdb.com/Title?$1',0),
+('hrwiki','http://www.hrwiki.org/wiki/$1',0),
+('imdb','http://www.imdb.com/find?q=$1&tt=on',0),
('jargonfile','http://sunir.org/apps/meta.pl?wiki=JargonFile&redirect=$1',0),
-('jspwiki','http://www.jspwiki.org/wiki/$1',0),
-('keiki','http://kei.ki/en/$1',0),
('kmwiki','http://kmwiki.wikispaces.com/$1',0),
('linuxwiki','http://linuxwiki.de/$1',0),
('lojban','http://www.lojban.org/tiki/tiki-index.php?page=$1',0),
('lqwiki','http://wiki.linuxquestions.org/wiki/$1',0),
-('lugkr','http://lug-kr.sourceforge.net/cgi-bin/lugwiki.pl?$1',0),
-('mathsongswiki','http://SeedWiki.com/page.cfm?wikiid=237&doc=$1',0),
+('lugkr','http://www.lug-kr.de/wiki/$1',0),
('meatball','http://www.usemod.com/cgi-bin/mb.pl?$1',0),
-('mediawikiwiki','http://www.mediawiki.org/wiki/$1',0),
-('mediazilla','https://bugzilla.wikimedia.org/$1',1),
-('memoryalpha','http://www.memory-alpha.org/en/index.php/$1',0),
+('mediawikiwiki','https://www.mediawiki.org/wiki/$1',0),
+('mediazilla','https://bugzilla.wikimedia.org/$1',0),
+('memoryalpha','http://en.memory-alpha.org/wiki/$1',0),
('metawiki','http://sunir.org/apps/meta.pl?$1',0),
-('metawikimedia','http://meta.wikimedia.org/wiki/$1',0),
-('moinmoin','http://purl.net/wiki/moin/$1',0),
-('mozillawiki','http://wiki.mozilla.org/index.php/$1',0),
+('metawikimedia','https://meta.wikimedia.org/wiki/$1',0),
+('mozillawiki','http://wiki.mozilla.org/$1',0),
('mw','http://www.mediawiki.org/wiki/$1',0),
-('oeis','http://www.research.att.com/cgi-bin/access.cgi/as/njas/sequences/eisA.cgi?Anum=$1',0),
-('openfacts','http://openfacts.berlios.de/index.phtml?title=$1',0),
-('openwiki','http://openwiki.com/?$1',0),
-('patwiki','http://gauss.ffii.org/$1',0), # 2008-02-27: lots of spambots
-('pmeg','http://www.bertilow.com/pmeg/$1.php',0),
+('oeis','http://oeis.org/$1',0),
+('openwiki','http://openwiki.com/ow.asp?$1',0),
('ppr','http://c2.com/cgi/wiki?$1',0),
('pythoninfo','http://wiki.python.org/moin/$1',0),
('rfc','http://www.rfc-editor.org/rfc/rfc$1.txt',0),
-('s23wiki','http://is-root.de/wiki/index.php/$1',0),
-('seattlewiki','http://seattle.wikia.com/wiki/$1',0),
-('seattlewireless','http://seattlewireless.net/?$1',0),
+('s23wiki','http://s23.org/wiki/$1',0),
+('seattlewireless','http://seattlewireless.net/$1',0),
('senseislibrary','http://senseis.xmp.net/?$1',0),
-('slashdot','http://slashdot.org/article.pl?sid=$1',0), # 2008-02-27: update me
+('shoutwiki','http://www.shoutwiki.com/wiki/$1',0),
('sourceforge','http://sourceforge.net/$1',0),
+('sourcewatch','http://www.sourcewatch.org/index.php?title=$1',0),
('squeak','http://wiki.squeak.org/squeak/$1',0),
-('susning','http://www.susning.nu/$1',0),
-('svgwiki','http://wiki.svg.org/$1',0),
-('tavi','http://tavi.sourceforge.net/$1',0),
('tejo','http://www.tejo.org/vikio/$1',0),
('tmbw','http://www.tmbw.net/wiki/$1',0),
('tmnet','http://www.technomanifestos.net/?$1',0),
-('tmwiki','http://www.EasyTopicMaps.com/?page=$1',0),
('theopedia','http://www.theopedia.com/$1',0),
('twiki','http://twiki.org/cgi-bin/view/$1',0),
-('uea','http://www.tejo.org/uea/$1',0),
-('unreal','http://wiki.beyondunreal.com/wiki/$1',0),
+('uea','http://uea.org/vikio/index.php/$1',0),
+('uncyclopedia','http://en.uncyclopedia.co/wiki/$1',0),
+('unreal','http://wiki.beyondunreal.com/$1',0),
('usemod','http://www.usemod.com/cgi-bin/wiki.pl?$1',0),
-('vinismo','http://vinismo.com/en/$1',0),
('webseitzwiki','http://webseitz.fluxent.com/wiki/$1',0),
-('why','http://clublet.com/c/c/why?$1',0),
('wiki','http://c2.com/cgi/wiki?$1',0),
('wikia','http://www.wikia.com/wiki/$1',0),
-('wikibooks','http://en.wikibooks.org/wiki/$1',1),
-('wikicities','http://www.wikia.com/wiki/$1',0),
+('wikibooks','https://en.wikibooks.org/wiki/$1',0),
('wikif1','http://www.wikif1.org/$1',0),
('wikihow','http://www.wikihow.com/$1',0),
-('wikinfo','http://www.wikinfo.org/index.php/$1',0),
-# The following wik[it]* interwikis but wikitravel belong to the Wikimedia Family:
-('wikimedia','http://wikimediafoundation.org/wiki/$1',0),
-('wikinews','http://en.wikinews.org/wiki/$1',1),
-('wikipedia','http://en.wikipedia.org/wiki/$1',1),
-('wikiquote','http://en.wikiquote.org/wiki/$1',1),
-('wikisource','http://wikisource.org/wiki/$1',1),
-('wikispecies','http://species.wikimedia.org/wiki/$1',1),
-('wikitravel','http://wikitravel.org/en/$1',0),
-('wikiversity','http://en.wikiversity.org/wiki/$1',1),
-('wikt','http://en.wiktionary.org/wiki/$1',1),
-('wiktionary','http://en.wiktionary.org/wiki/$1',1),
-('wlug','http://www.wlug.org.nz/$1',0),
-('zwiki','http://zwiki.org/$1',0),
-('zzz wiki','http://wiki.zzz.ee/index.php/$1',0);
+('wikinfo','http://wikinfo.co/English/index.php/$1',0),
+('wikimedia','https://wikimediafoundation.org/wiki/$1',0),
+('wikinews','https://en.wikinews.org/wiki/$1',0),
+('wikipedia','https://en.wikipedia.org/wiki/$1',0),
+('wikiquote','https://en.wikiquote.org/wiki/$1',0),
+('wikisource','https://wikisource.org/wiki/$1',0),
+('wikispecies','https://species.wikimedia.org/wiki/$1',0),
+('wikiversity','https://en.wikiversity.org/wiki/$1',0),
+('wikivoyage','https://en.wikivoyage.org/wiki/$1',0),
+('wikt','https://en.wiktionary.org/wiki/$1',0),
+('wiktionary','https://en.wiktionary.org/wiki/$1',0)
+;
diff --git a/maintenance/jsduck/CustomTags.rb b/maintenance/jsduck/CustomTags.rb
new file mode 100644
index 00000000..2aff9881
--- /dev/null
+++ b/maintenance/jsduck/CustomTags.rb
@@ -0,0 +1,116 @@
+# Custom tags for JSDuck 5.x
+# See also:
+# - https://github.com/senchalabs/jsduck/wiki/Tags
+# - https://github.com/senchalabs/jsduck/wiki/Custom-tags
+# - https://github.com/senchalabs/jsduck/wiki/Custom-tags/7f5c32e568eab9edc8e3365e935bcb836cb11f1d
+require 'jsduck/tag/tag'
+
+class CommonTag < JsDuck::Tag::Tag
+ def initialize
+ @html_position = POS_DOC + 0.1
+ @repeatable = true
+ end
+
+ def parse_doc(scanner, position)
+ if @multiline
+ return { :tagname => @tagname, :doc => :multiline }
+ else
+ text = scanner.match(/.*$/)
+ return { :tagname => @tagname, :doc => text }
+ end
+ end
+
+ def process_doc(context, tags, position)
+ context[@tagname] = tags
+ end
+
+ def format(context, formatter)
+ context[@tagname].each do |tag|
+ tag[:doc] = formatter.format(tag[:doc])
+ end
+ end
+end
+
+class SourceTag < CommonTag
+ def initialize
+ @tagname = :source
+ @pattern = "source"
+ super
+ end
+
+ def to_html(context)
+ context[@tagname].map do |source|
+ <<-EOHTML
+ <h3 class='pa'>Source</h3>
+ #{source[:doc]}
+ EOHTML
+ end.join
+ end
+end
+
+class SeeTag < CommonTag
+ def initialize
+ @tagname = :see
+ @pattern = "see"
+ super
+ end
+
+ def format(context, formatter)
+ position = context[:files][0]
+ context[@tagname].each do |tag|
+ tag[:doc] = '<li>' + render_long_see(tag[:doc], formatter, position) + '</li>'
+ end
+ end
+
+ def to_html(context)
+ <<-EOHTML
+ <h3 class="pa">Related</h3>
+ <ul>
+ #{ context[@tagname].map {|tag| tag[:doc] }.join("\n") }
+ </ul>
+ EOHTML
+ end
+
+ def render_long_see(tag, formatter, position)
+ if tag =~ /\A([^\s]+)( .*)?\Z/m
+ name = $1
+ doc = $2 ? ': ' + $2 : ''
+ return formatter.format("{@link #{name}} #{doc}")
+ else
+ JsDuck::Logger.warn(nil, 'Unexpected @see argument: "'+tag+'"', position)
+ return tag
+ end
+ end
+end
+
+class ContextTag < CommonTag
+ def initialize
+ @tagname = :context
+ @pattern = 'context'
+ super
+ end
+
+ def format(context, formatter)
+ position = context[:files][0]
+ context[@tagname].each do |tag|
+ tag[:doc] = render_long_context(tag[:doc], formatter, position)
+ end
+ end
+
+ def to_html(context)
+ <<-EOHTML
+ <h3 class="pa">Context</h3>
+ #{ context[@tagname].last[:doc] }
+ EOHTML
+ end
+
+ def render_long_context(tag, formatter, position)
+ if tag =~ /\A([^\s]+)/m
+ name = $1
+ return formatter.format("`context` : {@link #{name}}")
+ else
+ JsDuck::Logger.warn(nil, 'Unexpected @context argument: "'+tag+'"', position)
+ return tag
+ end
+ end
+end
diff --git a/maintenance/jsduck/MetaTags.rb b/maintenance/jsduck/MetaTags.rb
deleted file mode 100644
index 83cc0884..00000000
--- a/maintenance/jsduck/MetaTags.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-# See also:
-# - https://github.com/senchalabs/jsduck/wiki/Tags
-# - https://github.com/senchalabs/jsduck/wiki/Custom-tags
-require 'jsduck/meta_tag'
-
-class SourceTag < JsDuck::MetaTag
- def initialize
- # This defines the name of the @tag
- @name = 'source'
- end
-
- # Generate HTML output for this tag.
- # One can make use of the #format method to easily support
- # Markdown and {@link} tags inside the contents of the tag.
- #
- # @param tags All matches of this tag on one class.
- def to_html(tags)
- '<h3 class="pa">Source</h3>' + tags.map {|tag| format(tag) }.join("\n")
- end
-end
-
-class ContextTag < JsDuck::MetaTag
- def initialize
- @name = 'context'
- end
-
- # @param tags All matches of this tag on one class.
- def to_html(tags)
- return '<h3 class="pa">Context</h3>' + render_long_context(tags.last)
- end
-
- def render_long_context(tag)
- if tag =~ /\A([^\s]+)/m
- name = $1
- return format("`this` : {@link #{name}}")
- end
- end
-end
-
-class SeeTag < JsDuck::MetaTag
- def initialize
- @name = 'see'
- @multiline = true
- end
-
- # @param tags All matches of this tag on one class.
- def to_html(tags)
- doc = []
- doc << '<h3 class="pa">Related</h3>'
- doc << [
- '<ul>',
- tags.map {|tag| render_long_see(tag) },
- '</ul>',
- ]
- doc
- end
-
- def render_long_see(tag)
- if tag =~ /\A([^\s]+)( .*)?\Z/m
- name = $1
- doc = $2 ? ': ' + $2 : ''
- return [
- '<li>',
- format("{@link #{name}} #{doc}"),
- '</li>'
- ]
- end
- end
-end
diff --git a/maintenance/jsduck/categories.json b/maintenance/jsduck/categories.json
index f96902d8..d6163bde 100644
--- a/maintenance/jsduck/categories.json
+++ b/maintenance/jsduck/categories.json
@@ -9,7 +9,7 @@
"mw.Map",
"mw.Message",
"mw.loader",
- "mw.log",
+ "mw.loader.store",
"mw.html",
"mw.html.Cdata",
"mw.html.Raw",
@@ -20,12 +20,13 @@
"name": "General",
"classes": [
"mw.Title",
- "mw.inspect",
- "mw.inspect.reports",
+ "mw.Uri",
"mw.notification",
+ "mw.Notification_",
"mw.user",
"mw.util",
- "mw.plugin.*"
+ "mw.plugin.*",
+ "mw.cookie"
]
},
{
@@ -35,6 +36,42 @@
{
"name": "API",
"classes": ["mw.Api*"]
+ },
+ {
+ "name": "Language",
+ "classes": [
+ "mw.language*",
+ "mw.cldr",
+ "mw.jqueryMsg"
+ ]
+ },
+ {
+ "name": "Page",
+ "classes": [
+ "mw.page*"
+ ]
+ },
+ {
+ "name": "Interfaces",
+ "classes": [
+ "mw.Feedback"
+ ]
+ },
+ {
+ "name": "Special",
+ "classes": [
+ "mw.special*"
+ ]
+ },
+ {
+ "name": "Development",
+ "classes": [
+ "mw.log",
+ "mw.inspect",
+ "mw.inspect.reports",
+ "mw.Debug",
+ "mw.Debug.profile"
+ ]
}
]
},
@@ -43,7 +80,11 @@
"groups": [
{
"name": "Plugins",
- "classes": ["jQuery.plugin.*"]
+ "classes": [
+ "jQuery.client",
+ "jQuery.colorUtil",
+ "jQuery.plugin.*"
+ ]
}
]
},
@@ -51,6 +92,10 @@
"name": "Upstream",
"groups": [
{
+ "name": "OOJS",
+ "classes": ["OO", "OO.*"]
+ },
+ {
"name": "jQuery",
"classes": ["jQuery", "jQuery.Event", "jQuery.Callbacks", "jQuery.Promise", "jQuery.Deferred", "jQuery.jqXHR", "QUnit"]
},
diff --git a/maintenance/jsduck/config.json b/maintenance/jsduck/config.json
index e6e0f658..e97f2923 100644
--- a/maintenance/jsduck/config.json
+++ b/maintenance/jsduck/config.json
@@ -1,27 +1,40 @@
{
"--title": "MediaWiki core - Documentation",
- "--footer": "Documentation for MediaWiki core. Generated on {DATE} by {JSDUCK} {VERSION}.",
"--categories": "./categories.json",
- "--meta-tags": "./MetaTags.rb",
"--eg-iframe": "./eg-iframe.html",
- "--warnings": ["-no_doc"],
+ "--tags": "./CustomTags.rb",
+ "--warnings": ["-nodoc(class,public)"],
"--builtin-classes": true,
+ "--warnings-exit-nonzero": true,
+ "--external": "HTMLElement,HTMLDocument,Window,File",
+ "--footer": "Documentation for MediaWiki core. Generated on {DATE} by {JSDUCK} {VERSION}.",
"--output": "../../docs/js",
"--": [
"./external.js",
- "../../resources/mediawiki/mediawiki.js",
- "../../resources/mediawiki/mediawiki.log.js",
- "../../resources/mediawiki/mediawiki.util.js",
- "../../resources/mediawiki/mediawiki.Title.js",
- "../../resources/mediawiki/mediawiki.inspect.js",
- "../../resources/mediawiki/mediawiki.notify.js",
- "../../resources/mediawiki/mediawiki.notification.js",
- "../../resources/mediawiki/mediawiki.user.js",
- "../../resources/mediawiki.action/mediawiki.action.edit.js",
- "../../resources/mediawiki.action/mediawiki.action.view.postEdit.js",
- "../../resources/mediawiki.page/mediawiki.page.startup.js",
- "../../resources/mediawiki.api",
- "../../resources/jquery/jquery.localize.js",
- "../../resources/jquery/jquery.spinner.js"
+ "../../resources/src/mediawiki",
+ "../../resources/src/mediawiki.action",
+ "../../resources/src/mediawiki.api",
+ "../../resources/src/mediawiki.language",
+ "../../resources/src/mediawiki.page",
+ "../../resources/src/mediawiki.special",
+ "../../resources/src/jquery/jquery.accessKeyLabel.js",
+ "../../resources/src/jquery/jquery.arrowSteps.js",
+ "../../resources/src/jquery/jquery.autoEllipsis.js",
+ "../../resources/src/jquery/jquery.badge.js",
+ "../../resources/src/jquery/jquery.byteLength.js",
+ "../../resources/src/jquery/jquery.byteLimit.js",
+ "../../resources/src/jquery/jquery.checkboxShiftClick.js",
+ "../../resources/src/jquery/jquery.client.js",
+ "../../resources/src/jquery/jquery.colorUtil.js",
+ "../../resources/src/jquery/jquery.confirmable.js",
+ "../../resources/src/jquery/jquery.footHovzer.js",
+ "../../resources/src/jquery/jquery.getAttrs.js",
+ "../../resources/src/jquery/jquery.hidpi.js",
+ "../../resources/src/jquery/jquery.localize.js",
+ "../../resources/src/jquery/jquery.makeCollapsible.js",
+ "../../resources/src/jquery/jquery.spinner.js",
+ "../../resources/src/jquery/jquery.tabIndex.js",
+ "../../resources/lib/oojs",
+ "../../resources/lib/oojs-ui"
]
}
diff --git a/maintenance/jsduck/eg-iframe.html b/maintenance/jsduck/eg-iframe.html
index 86eae4b6..7dc4afa8 100644
--- a/maintenance/jsduck/eg-iframe.html
+++ b/maintenance/jsduck/eg-iframe.html
@@ -1,88 +1,88 @@
<!DOCTYPE html>
<html>
<head>
- <meta charset="utf-8">
- <title>MediaWiki Code Example</title>
- <script src="modules/startup.js"></script>
- <script>
- function startUp() {
- mw.config = new mw.Map();
- }
- </script>
- <script src="modules/jquery/jquery.js"></script>
- <script src="modules/mediawiki/mediawiki.js"></script>
- <style>
- .mw-jsduck-log {
- position: relative;
- min-height: 3em;
- margin-top: 2em;
- background: #f7f7f7;
- border: 1px solid #e4e4e4;
- }
+ <meta charset="utf-8">
+ <title>MediaWiki Code Example</title>
+ <script src="modules/startup.js"></script>
+ <script>
+ function startUp() {
+ mw.config = new mw.Map();
+ }
+ </script>
+ <script src="modules/jquery/jquery.js"></script>
+ <script src="modules/mediawiki/mediawiki.js"></script>
+ <style>
+ .mw-jsduck-log {
+ position: relative;
+ min-height: 3em;
+ margin-top: 2em;
+ background: #f7f7f7;
+ border: 1px solid #e4e4e4;
+ }
- .mw-jsduck-log::after {
- position: absolute;
- bottom: 100%;
- right: -1px;
- padding: 0.5em;
- background: #fff;
- border: 1px solid #e4e4e4;
- border-bottom: 0;
- border-radius: 0.5em 0.5em 0 0;
- font: normal 0.5em sans-serif;
- content: 'console';
- }
+ .mw-jsduck-log::after {
+ position: absolute;
+ bottom: 100%;
+ right: -1px;
+ padding: 0.5em;
+ background: #fff;
+ border: 1px solid #e4e4e4;
+ border-bottom: 0;
+ border-radius: 0.5em 0.5em 0 0;
+ font: normal 0.5em sans-serif;
+ content: 'console';
+ }
- .mw-jsduck-log-line {
- padding: 0.2em 0.5em;
- white-space: pre-wrap;
- }
+ .mw-jsduck-log-line {
+ padding: 0.2em 0.5em;
+ white-space: pre-wrap;
+ }
- .mw-jsduck-log-line:nth-child(odd) {
- background: #fff;
- }
- </style>
+ .mw-jsduck-log-line:nth-child(odd) {
+ background: #fff;
+ }
+ </style>
</head>
<body>
- <script>
- /**
- * Basic log console for the example iframe in documentation pages.
- */
- ( function () {
- var pre;
- mw.log = function () {
- var str, i, len, line;
- if ( !pre ) {
- pre = document.createElement( 'pre' );
- pre.className = 'mw-jsduck-log';
- document.body.appendChild( pre );
- }
- str = [];
- for ( i = 0, len = arguments.length; i < len; i++ ) {
- str.push( String( arguments[ i ] ) );
- }
- line = document.createElement( 'div' );
- line.className = 'mw-jsduck-log-line';
- line.appendChild(
- document.createTextNode( str.join( ' , ' ) + '\n' )
- );
- pre.appendChild( line );
- };
- }() );
+<script>
+ /**
+ * Basic log console for the example iframe in documentation pages.
+ */
+ ( function () {
+ var pre;
+ mw.log = function () {
+ var str, i, len, line;
+ if ( !pre ) {
+ pre = document.createElement( 'pre' );
+ pre.className = 'mw-jsduck-log';
+ document.body.appendChild( pre );
+ }
+ str = [];
+ for ( i = 0, len = arguments.length; i < len; i++ ) {
+ str.push( String( arguments[ i ] ) );
+ }
+ line = document.createElement( 'div' );
+ line.className = 'mw-jsduck-log-line';
+ line.appendChild(
+ document.createTextNode( str.join( ' , ' ) + '\n' )
+ );
+ pre.appendChild( line );
+ };
+ }() );
- /**
- * Method called by jsduck to execute the example code.
- */
- function loadInlineExample( code, options, callback ) {
- try {
- eval( code );
- callback && callback( true );
- } catch (e) {
- mw.log( 'Uncaught exception: ' + e );
- callback && callback( false, e );
- throw e;
- }
- }
- </script>
+ /**
+ * Method called by jsduck to execute the example code.
+ */
+ function loadInlineExample( code, options, callback ) {
+ try {
+ eval( code );
+ callback && callback( true );
+ } catch ( e ) {
+ mw.log( 'Uncaught exception: ' + e );
+ callback && callback( false, e );
+ throw e;
+ }
+ }
+</script>
</body>
</html>
diff --git a/maintenance/lag.php b/maintenance/lag.php
index 410bf756..52f8201a 100644
--- a/maintenance/lag.php
+++ b/maintenance/lag.php
@@ -39,7 +39,9 @@ class DatabaseLag extends Maintenance {
if ( $this->hasOption( 'r' ) ) {
$lb = wfGetLB();
echo 'time ';
- for ( $i = 1; $i < $lb->getServerCount(); $i++ ) {
+
+ $serverCount = $lb->getServerCount();
+ for ( $i = 1; $i < $serverCount; $i++ ) {
$hostname = $lb->getServerName( $i );
printf( "%-12s ", $hostname );
}
diff --git a/maintenance/language/StatOutputs.php b/maintenance/language/StatOutputs.php
index e9d8c86d..31ce7024 100644
--- a/maintenance/language/StatOutputs.php
+++ b/maintenance/language/StatOutputs.php
@@ -1,7 +1,4 @@
<?php
-if ( !defined( 'MEDIAWIKI' ) ) {
- die();
-}
/**
* Statistic output classes.
*
@@ -27,57 +24,78 @@ if ( !defined( 'MEDIAWIKI' ) ) {
*/
/** A general output object. Need to be overriden */
-class statsOutput {
+class StatsOutput {
function formatPercent( $subset, $total, $revert = false, $accuracy = 2 ) {
- return @sprintf( '%.' . $accuracy . 'f%%', 100 * $subset / $total );
+ wfSuppressWarnings();
+ $return = sprintf( '%.' . $accuracy . 'f%%', 100 * $subset / $total );
+ wfRestoreWarnings();
+
+ return $return;
}
# Override the following methods
function heading() {
}
+
function footer() {
}
+
function blockstart() {
}
+
function blockend() {
}
+
function element( $in, $heading = false ) {
}
}
/** Outputs WikiText */
-class wikiStatsOutput extends statsOutput {
+class WikiStatsOutput extends StatsOutput {
function heading() {
global $wgDummyLanguageCodes;
$version = SpecialVersion::getVersion( 'nodb' );
echo "'''Statistics are based on:''' <code>" . $version . "</code>\n\n";
- echo "'''Note:''' These statistics can be generated by running <code>php maintenance/language/transstat.php</code>.\n\n";
- 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 "'''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 'English (en) is excluded because it is the default localization';
if ( is_array( $wgDummyLanguageCodes ) ) {
$dummyCodes = array();
foreach ( $wgDummyLanguageCodes as $dummyCode => $correctCode ) {
$dummyCodes[] = Language::fetchLanguageName( $dummyCode ) . ' (' . $dummyCode . ')';
}
- echo ', as well as the following languages that are not intended for system message translations, usually because they redirect to other language codes: ' . implode( ', ', $dummyCodes );
+ echo ', as well as the following languages that are not intended for ' .
+ 'system message translations, usually because they redirect to other ' .
+ 'language codes: ' . implode( ', ', $dummyCodes );
}
echo ".\n\n"; # dot to end sentence
- echo '{| class="sortable wikitable" border="2" style="background-color: #F9F9F9; border: 1px #AAAAAA solid; border-collapse: collapse; clear:both; width:100%;"' . "\n";
+ echo '{| class="sortable wikitable" border="2" style="background-color: #F9F9F9; ' .
+ 'border: 1px #AAAAAA solid; border-collapse: collapse; clear:both; width:100%;"' . "\n";
}
+
function footer() {
echo "|}\n";
}
+
function blockstart() {
echo "|-\n";
}
+
function blockend() {
echo '';
}
+
function element( $in, $heading = false ) {
echo ( $heading ? '!' : '|' ) . "$in\n";
}
+
function formatPercent( $subset, $total, $revert = false, $accuracy = 2 ) {
- $v = @round( 255 * $subset / $total );
+ wfSuppressWarnings();
+ $v = round( 255 * $subset / $total );
+ wfRestoreWarnings();
+
if ( $revert ) {
# Weigh reverse with factor 20 so coloring takes effect more quickly as
# this option is used solely for reporting 'bad' percentages.
@@ -100,25 +118,28 @@ class wikiStatsOutput extends statsOutput {
$color = $red . $green . $blue;
$percent = parent::formatPercent( $subset, $total, $revert, $accuracy );
+
return 'style="background-color:#' . $color . ';"|' . $percent;
}
}
/** Output text. To be used on a terminal for example. */
-class textStatsOutput extends statsOutput {
+class TextStatsOutput extends StatsOutput {
function element( $in, $heading = false ) {
echo $in . "\t";
}
+
function blockend() {
echo "\n";
}
}
/** csv output. Some people love excel */
-class csvStatsOutput extends statsOutput {
+class CsvStatsOutput extends StatsOutput {
function element( $in, $heading = false ) {
echo $in . ";";
}
+
function blockend() {
echo "\n";
}
diff --git a/maintenance/language/checkDupeMessages.php b/maintenance/language/checkDupeMessages.php
index 381ddae1..5d482442 100644
--- a/maintenance/language/checkDupeMessages.php
+++ b/maintenance/language/checkDupeMessages.php
@@ -67,8 +67,7 @@ if ( $runTest ) {
$messagesFileC = $messagesDir . 'Messages' . $langCodeFC . '.php';
if ( file_exists( $messagesFile ) && file_exists( $messagesFileC ) ) {
$run = true;
- }
- else {
+ } else {
echo "Messages file(s) could not be found.\nMake sure both files are exists.\n";
}
}
diff --git a/maintenance/language/checkLanguage.inc b/maintenance/language/checkLanguage.inc
index 4b49ada3..990f2585 100644
--- a/maintenance/language/checkLanguage.inc
+++ b/maintenance/language/checkLanguage.inc
@@ -41,7 +41,7 @@ class CheckLanguageCLI {
/**
* Constructor.
- * @param $options array Options for script.
+ * @param array $options Options for script.
*/
public function __construct( array $options ) {
if ( isset( $options['help'] ) ) {
@@ -89,7 +89,7 @@ class CheckLanguageCLI {
$this->output = $options['output'];
}
- $this->L = new languages( $this->includeExif );
+ $this->L = new Languages( $this->includeExif );
}
/**
@@ -118,7 +118,7 @@ class CheckLanguageCLI {
/**
* Get the checks that can easily be treated by non-speakers of the language.
- * @return Array A list of the easy checks.
+ * @return array A list of the easy checks.
*/
protected function easyChecks() {
return array(
@@ -182,21 +182,25 @@ class CheckLanguageCLI {
return array(
'untranslated' => '$1 message(s) of $2 are not translated to $3, but exist in en:',
'duplicate' => '$1 message(s) of $2 are translated the same in en and $3:',
- 'obsolete' => '$1 message(s) of $2 do not exist in en or are in the ignore list, but exist in $3:',
+ 'obsolete' =>
+ '$1 message(s) of $2 do not exist in en or are in the ignore list, but exist in $3:',
'variables' => '$1 message(s) of $2 in $3 don\'t match the variables used in en:',
'plural' => '$1 message(s) of $2 in $3 don\'t use {{plural}} while en uses:',
'empty' => '$1 message(s) of $2 in $3 are empty or -:',
'whitespace' => '$1 message(s) of $2 in $3 have trailing whitespace:',
'xhtml' => '$1 message(s) of $2 in $3 contain illegal XHTML:',
- 'chars' => '$1 message(s) of $2 in $3 include hidden chars which should not be used in the messages:',
+ 'chars' =>
+ '$1 message(s) of $2 in $3 include hidden chars which should not be used in the messages:',
'links' => '$1 message(s) of $2 in $3 have problematic link(s):',
'unbalanced' => '$1 message(s) of $2 in $3 have unbalanced {[]}:',
'namespace' => '$1 namespace name(s) of $2 are not translated to $3, but exist in en:',
- 'projecttalk' => '$1 namespace name(s) and alias(es) in $3 are project talk namespaces without the parameter:',
+ 'projecttalk' =>
+ '$1 namespace name(s) and alias(es) in $3 are project talk namespaces without the parameter:',
'magic' => '$1 magic word(s) of $2 are not translated to $3, but exist in en:',
'magic-old' => '$1 magic word(s) of $2 do not exist in en, but exist in $3:',
'magic-over' => '$1 magic word(s) of $2 in $3 do not contain the original en word(s):',
- 'magic-case' => '$1 magic word(s) of $2 in $3 change the case-sensitivity of the original en word:',
+ 'magic-case' =>
+ '$1 magic word(s) of $2 in $3 change the case-sensitivity of the original en word:',
'special' => '$1 special page alias(es) of $2 are not translated to $3, but exist in en:',
'special-old' => '$1 special page alias(es) of $2 do not exist in en, but exist in $3:',
);
@@ -216,35 +220,49 @@ Parameters:
--all: Check all customized languages.
--level: Show the following display level (default: 2):
* 0: Skip the checks (useful for checking syntax).
- * 1: Show only the stub headers and number of wrong messages, without list of messages.
- * 2: Show only the headers and the message keys, without the message values.
- * 3: Show both the headers and the complete messages, with both keys and values.
+ * 1: Show only the stub headers and number of wrong messages, without
+ list of messages.
+ * 2: Show only the headers and the message keys, without the message
+ values.
+ * 3: Show both the headers and the complete messages, with both keys and
+ values.
--links: Link the message values (default off).
--prefix: prefix to add to links.
- --wikilang: For the links, what is the content language of the wiki to display the output in (default en).
- --noexif: Do not check for Exif messages (a bit hard and boring to translate), if you know
- that they are currently not translated and want to focus on other problems (default off).
+ --wikilang: For the links, what is the content language of the wiki to
+ display the output in (default en).
+ --noexif: Do not check for Exif messages (a bit hard and boring to
+ translate), if you know what they are currently not translated and want
+ to focus on other problems (default off).
--whitelist: Do only the following checks (form: code,code).
--blacklist: Do not do the following checks (form: code,code).
- --easy: Do only the easy checks, which can be treated by non-speakers of the language.
-
-Check codes (ideally, all of them should result 0; all the checks are executed by default (except language-specific check blacklists in checkLanguage.inc):
- * untranslated: Messages which are required to translate, but are not translated.
- * duplicate: Messages which translation equal to fallback
- * obsolete: Messages which are untranslatable or do not exist, but are translated.
- * variables: Messages without variables which should be used, or with variables which should not be used.
+ --easy: Do only the easy checks, which can be treated by non-speakers of
+ the language.
+
+Check codes (ideally, all of them should result 0; all the checks are executed
+by default (except language-specific check blacklists in checkLanguage.inc):
+ * untranslated: Messages which are required to translate, but are not
+ translated.
+ * duplicate: Messages which translation equal to fallback.
+ * obsolete: Messages which are untranslatable or do not exist, but are
+ translated.
+ * variables: Messages without variables which should be used, or with
+ variables which should not be used.
* empty: Empty messages and messages that contain only -.
* whitespace: Messages which have trailing whitespace.
- * xhtml: Messages which are not well-formed XHTML (checks only few common errors).
+ * xhtml: Messages which are not well-formed XHTML (checks only few common
+ errors).
* chars: Messages with hidden characters.
* links: Messages which contains broken links to pages (does not find all).
- * unbalanced: Messages which contains unequal numbers of opening {[ and closing ]}.
+ * unbalanced: Messages which contains unequal numbers of opening {[ and
+ closing ]}.
* namespace: Namespace names that were not translated.
- * projecttalk: Namespace names and aliases where the project talk does not contain $1.
+ * projecttalk: Namespace names and aliases where the project talk does not
+ contain $1.
* magic: Magic words that were not translated.
* magic-old: Magic words which do not exist.
* magic-over: Magic words that override the original English word.
- * magic-case: Magic words whose translation changes the case-sensitivity of the original English word.
+ * magic-case: Magic words whose translation changes the case-sensitivity of
+ the original English word.
* special: Special page names that were not translated.
* special-old: Special page names which do not exist.
@@ -291,6 +309,17 @@ ENDS;
$this->results[$this->code] = $this->checkLanguage( $this->code );
}
}
+
+ $results = $this->results;
+ foreach ( $results as $code => $checks ) {
+ foreach ( $checks as $check => $messages ) {
+ foreach ( $messages as $key => $details ) {
+ if ( $this->isCheckBlacklisted( $check, $code, $key ) ) {
+ unset( $this->results[$code][$check][$key] );
+ }
+ }
+ }
+ }
}
/**
@@ -298,14 +327,58 @@ ENDS;
* @return array The list of checks which should not be executed.
*/
protected function getCheckBlacklist() {
+ static $blacklist = null;
+
+ if ( $blacklist !== null ) {
+ return $blacklist;
+ }
+
+ // @codingStandardsIgnoreStart Ignore that globals should have a "wg" prefix.
global $checkBlacklist;
+ // @codingStandardsIgnoreEnd
+
+ $blacklist = $checkBlacklist;
+
+ wfRunHooks( 'LocalisationChecksBlacklist', array( &$blacklist ) );
+
+ return $blacklist;
+ }
+
+ /**
+ * Verify whether a check is blacklisted.
+ *
+ * @param string $check Check name
+ * @param string $code Language code
+ * @param string|bool $message Message name, or False for a whole language
+ * @return bool Whether the check is blacklisted
+ */
+ protected function isCheckBlacklisted( $check, $code, $message ) {
+ $blacklist = $this->getCheckBlacklist();
+
+ foreach ( $blacklist as $item ) {
+ if ( isset( $item['check'] ) && $check !== $item['check'] ) {
+ continue;
+ }
- return $checkBlacklist;
+ if ( isset( $item['code'] ) && !in_array( $code, $item['code'] ) ) {
+ continue;
+ }
+
+ if ( isset( $item['message'] ) &&
+ ( $message === false || !in_array( $message, $item['message'] ) )
+ ) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
}
/**
* Check a language.
- * @param $code string The language code.
+ * @param string $code The language code.
* @throws MWException
* @return array The results.
*/
@@ -319,11 +392,8 @@ ENDS;
}
$checkFunctions = $this->getChecks();
- $checkBlacklist = $this->getCheckBlacklist();
foreach ( $this->checks as $check ) {
- if ( isset( $checkBlacklist[$code] ) &&
- in_array( $check, $checkBlacklist[$code] )
- ) {
+ if ( $this->isCheckBlacklisted( $check, $code, false ) ) {
$results[$check] = array();
continue;
}
@@ -340,8 +410,8 @@ ENDS;
/**
* Format a message key.
- * @param $key string The message key.
- * @param $code string The language code.
+ * @param string $key The message key.
+ * @param string $code The language code.
* @return string The formatted message key.
*/
protected function formatKey( $key, $code ) {
@@ -407,7 +477,8 @@ ENDS;
*/
function outputWiki() {
$detailText = '';
- $rows[] = '! Language !! Code !! Total !! ' . implode( ' !! ', array_diff( $this->checks, $this->nonMessageChecks() ) );
+ $rows[] = '! Language !! Code !! Total !! ' .
+ implode( ' !! ', array_diff( $this->checks, $this->nonMessageChecks() ) );
foreach ( $this->results as $code => $results ) {
$detailTextForLang = "==$code==\n";
$numbers = array();
@@ -447,6 +518,7 @@ ENDS;
$tableRows = implode( "\n|-\n", $rows );
$version = SpecialVersion::getVersion( 'nodb' );
+ // @codingStandardsIgnoreStart Long line.
echo <<<EOL
'''Check results are for:''' <code>$version</code>
@@ -458,6 +530,7 @@ $tableRows
$detailText
EOL;
+ // @codingStandardsIgnoreEnd
}
/**
@@ -485,8 +558,8 @@ class CheckExtensionsCLI extends CheckLanguageCLI {
/**
* Constructor.
- * @param $options array Options for script.
- * @param $extension string The extension name (or names).
+ * @param array $options Options for script.
+ * @param string $extension The extension name (or names).
*/
public function __construct( array $options, $extension ) {
if ( isset( $options['help'] ) ) {
@@ -539,19 +612,19 @@ class CheckExtensionsCLI extends CheckLanguageCLI {
if ( $extension == 'all' ) {
foreach ( MessageGroups::singleton()->getGroups() as $group ) {
if ( strpos( $group->getId(), 'ext-' ) === 0 && !$group->isMeta() ) {
- $this->extensions[] = new extensionLanguages( $group );
+ $this->extensions[] = new ExtensionLanguages( $group );
}
}
} elseif ( $extension == 'wikimedia' ) {
$wikimedia = MessageGroups::getGroup( 'ext-0-wikimedia' );
foreach ( $wikimedia->wmfextensions() as $extension ) {
$group = MessageGroups::getGroup( $extension );
- $this->extensions[] = new extensionLanguages( $group );
+ $this->extensions[] = new ExtensionLanguages( $group );
}
} elseif ( $extension == 'flaggedrevs' ) {
foreach ( MessageGroups::singleton()->getGroups() as $group ) {
if ( strpos( $group->getId(), 'ext-flaggedrevs-' ) === 0 && !$group->isMeta() ) {
- $this->extensions[] = new extensionLanguages( $group );
+ $this->extensions[] = new ExtensionLanguages( $group );
}
}
} else {
@@ -559,7 +632,7 @@ class CheckExtensionsCLI extends CheckLanguageCLI {
foreach ( $extensions as $extension ) {
$group = MessageGroups::getGroup( 'ext-' . $extension );
if ( $group ) {
- $extension = new extensionLanguages( $group );
+ $extension = new ExtensionLanguages( $group );
$this->extensions[] = $extension;
} else {
print "No such extension $extension.\n";
@@ -589,7 +662,7 @@ class CheckExtensionsCLI extends CheckLanguageCLI {
/**
* Get the checks that can easily be treated by non-speakers of the language.
- * @return arrayA list of the easy checks.
+ * @return array A list of the easy checks.
*/
protected function easyChecks() {
return array(
@@ -603,34 +676,50 @@ class CheckExtensionsCLI extends CheckLanguageCLI {
*/
protected function help() {
return <<<ENDS
-Run this script to check the status of a specific language in extensions, or all of them.
-Command line settings are in form --parameter[=value], except for the first one.
+Run this script to check the status of a specific language in extensions, or
+all of them. Command line settings are in form --parameter[=value], except for
+the first one.
Parameters:
- * First parameter (mandatory): Extension name, multiple extension names (separated by commas), "all" for all the extensions, "wikimedia" for extensions used by Wikimedia or "flaggedrevs" for all FLaggedRevs extension messages.
+ * First parameter (mandatory): Extension name, multiple extension names
+ (separated by commas), "all" for all the extensions, "wikimedia" for
+ extensions used by Wikimedia or "flaggedrevs" for all FLaggedRevs
+ extension messages.
* lang: Language code (default: the installation default language).
* help: Show this help.
* level: Show the following display level (default: 2).
* links: Link the message values (default off).
- * wikilang: For the links, what is the content language of the wiki to display the output in (default en).
+ * wikilang: For the links, what is the content language of the wiki to
+ display the output in (default en).
* whitelist: Do only the following checks (form: code,code).
* blacklist: Do not perform the following checks (form: code,code).
- * easy: Do only the easy checks, which can be treated by non-speakers of the language.
-Check codes (ideally, all of them should result 0; all the checks are executed by default (except language-specific check blacklists in checkLanguage.inc):
- * untranslated: Messages which are required to translate, but are not translated.
- * duplicate: Messages which translation equal to fallback
+ * easy: Do only the easy checks, which can be treated by non-speakers of
+ the language.
+
+Check codes (ideally, all of them should result 0; all the checks are executed
+by default (except language-specific check blacklists in checkLanguage.inc):
+ * untranslated: Messages which are required to translate, but are not
+ translated.
+ * duplicate: Messages which translation equal to fallback.
* obsolete: Messages which are untranslatable, but translated.
- * variables: Messages without variables which should be used, or with variables which should not be used.
+ * variables: Messages without variables which should be used, or with
+ variables which should not be used.
* empty: Empty messages.
* whitespace: Messages which have trailing whitespace.
- * xhtml: Messages which are not well-formed XHTML (checks only few common errors).
+ * xhtml: Messages which are not well-formed XHTML (checks only few common
+ errors).
* chars: Messages with hidden characters.
* links: Messages which contains broken links to pages (does not find all).
- * unbalanced: Messages which contains unequal numbers of opening {[ and closing ]}.
+ * unbalanced: Messages which contains unequal numbers of opening {[ and
+ closing ]}.
+
Display levels (default: 2):
* 0: Skip the checks (useful for checking syntax).
- * 1: Show only the stub headers and number of wrong messages, without list of messages.
- * 2: Show only the headers and the message keys, without the message values.
- * 3: Show both the headers and the complete messages, with both keys and values.
+ * 1: Show only the stub headers and number of wrong messages, without list
+ of messages.
+ * 2: Show only the headers and the message keys, without the message
+ values.
+ * 3: Show both the headers and the complete messages, with both keys and
+ values.
ENDS;
}
@@ -644,7 +733,7 @@ ENDS;
/**
* Check a language and show the results.
- * @param $code string The language code.
+ * @param string $code The language code.
* @throws MWException
*/
protected function checkLanguage( $code ) {
@@ -675,52 +764,21 @@ ENDS;
}
}
-# Blacklist some checks for some languages
+// Blacklist some checks for some languages or some messages
+// Possible keys of the sub arrays are: 'check', 'code' and 'message'.
$checkBlacklist = array(
-#'code' => array( 'check1', 'check2' ... )
- 'az' => array( 'plural' ),
- 'bo' => array( 'plural' ),
- 'cdo' => array( 'plural' ),
- 'dz' => array( 'plural' ),
- 'id' => array( 'plural' ),
- 'fa' => array( 'plural' ),
- 'gan' => array( 'plural' ),
- 'gan-hans' => array( 'plural' ),
- 'gan-hant' => array( 'plural' ),
- 'gn' => array( 'plural' ),
- 'hak' => array( 'plural' ),
- 'hu' => array( 'plural' ),
- 'ja' => array( 'plural' ), // Does not use plural
- 'jv' => array( 'plural' ),
- 'ka' => array( 'plural' ),
- 'kk-arab' => array( 'plural' ),
- 'kk-cyrl' => array( 'plural' ),
- 'kk-latn' => array( 'plural' ),
- 'km' => array( 'plural' ),
- 'kn' => array( 'plural' ),
- 'ko' => array( 'plural' ),
- 'lzh' => array( 'plural' ),
- 'mn' => array( 'plural' ),
- 'ms' => array( 'plural' ),
- 'my' => array( 'plural', 'chars' ), // Uses a lot zwnj
- 'sah' => array( 'plural' ),
- 'sq' => array( 'plural' ),
- 'tet' => array( 'plural' ),
- 'th' => array( 'plural' ),
- 'to' => array( 'plural' ),
- 'tr' => array( 'plural' ),
- 'vi' => array( 'plural' ),
- 'wuu' => array( 'plural' ),
- 'xmf' => array( 'plural' ),
- 'yo' => array( 'plural' ),
- 'yue' => array( 'plural' ),
- 'zh' => array( 'plural' ),
- 'zh-classical' => array( 'plural' ),
- 'zh-cn' => array( 'plural' ),
- 'zh-hans' => array( 'plural' ),
- 'zh-hant' => array( 'plural' ),
- 'zh-hk' => array( 'plural' ),
- 'zh-sg' => array( 'plural' ),
- 'zh-tw' => array( 'plural' ),
- 'zh-yue' => array( 'plural' ),
+ array(
+ 'check' => 'plural',
+ 'code' => array( 'az', 'bo', 'cdo', 'dz', 'id', 'fa', 'gan', 'gan-hans',
+ 'gan-hant', 'gn', 'hak', 'hu', 'ja', 'jv', 'ka', 'kk-arab',
+ 'kk-cyrl', 'kk-latn', 'km', 'kn', 'ko', 'lzh', 'mn', 'ms',
+ 'my', 'sah', 'sq', 'tet', 'th', 'to', 'tr', 'vi', 'wuu', 'xmf',
+ 'yo', 'yue', 'zh', 'zh-classical', 'zh-cn', 'zh-hans',
+ 'zh-hant', 'zh-hk', 'zh-sg', 'zh-tw', 'zh-yue'
+ ),
+ ),
+ array(
+ 'check' => 'chars',
+ 'code' => array( 'my' ),
+ ),
);
diff --git a/maintenance/language/countMessages.php b/maintenance/language/countMessages.php
deleted file mode 100644
index 95a7154b..00000000
--- a/maintenance/language/countMessages.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-/**
- * Count how many messages we have defined for each language.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup MaintenanceLanguage
- */
-
-require_once __DIR__ . '/../Maintenance.php';
-
-/**
- * Maintenance script that counts how many messages we have defined
- * for each language.
- *
- * @ingroup MaintenanceLanguage
- */
-class CountMessages extends Maintenance {
- public function __construct() {
- parent::__construct();
- $this->mDescription = "Count how many messages we have defined for each language";
- }
-
- public function execute() {
- global $IP;
- $dir = $this->getArg( 0, "$IP/languages/messages" );
- $total = 0;
- $nonZero = 0;
- foreach ( glob( "$dir/*.php" ) as $file ) {
- $baseName = basename( $file );
- if ( !preg_match( '/Messages([A-Z][a-z_]+)\.php$/', $baseName, $m ) ) {
- continue;
- }
-
- $numMessages = $this->getNumMessages( $file );
- // print "$code: $numMessages\n";
- $total += $numMessages;
- if ( $numMessages > 0 ) {
- $nonZero ++;
- }
- }
- $this->output( "\nTotal: $total\n" );
- $this->output( "Languages: $nonZero\n" );
- }
-
- private function getNumMessages( $file ) {
- // Separate function to limit scope
- require $file;
- if ( isset( $messages ) ) {
- return count( $messages );
- } else {
- return 0;
- }
- }
-}
-
-$maintClass = "CountMessages";
-require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/language/generateCollationData.php b/maintenance/language/generateCollationData.php
index fcf2c960..973cf7bc 100644
--- a/maintenance/language/generateCollationData.php
+++ b/maintenance/language/generateCollationData.php
@@ -48,7 +48,7 @@ class GenerateCollationData extends Maintenance {
* Important tertiary weights from UTS #10 section 7.2
*/
const NORMAL_UPPERCASE = 0x08;
- const NORMAL_HIRAGANA = 0X0E;
+ const NORMAL_HIRAGANA = 0x0E;
public function __construct() {
parent::__construct();
@@ -158,7 +158,8 @@ class GenerateCollationData extends Maintenance {
// people like to use that as a fake no header symbol.
$category = substr( $data['gc'], 0, 1 );
if ( strpos( 'LNPS', $category ) === false
- && $data['cp'] !== '0020' ) {
+ && $data['cp'] !== '0020'
+ ) {
return;
}
$cp = hexdec( $data['cp'] );
@@ -178,8 +179,8 @@ class GenerateCollationData extends Maintenance {
// Calculate implicit weight per UTS #10 v6.0.0, sec 7.1.3
if ( $data['UIdeo'] === 'Y' ) {
if ( $data['block'] == 'CJK Unified Ideographs'
- || $data['block'] == 'CJK Compatibility Ideographs' )
- {
+ || $data['block'] == 'CJK Compatibility Ideographs'
+ ) {
$base = 0xFB40;
} else {
$base = 0xFB80;
@@ -248,8 +249,8 @@ class GenerateCollationData extends Maintenance {
}
$this->weights[$cp] = $primary;
if ( $tertiary === '.0008'
- || $tertiary === '.000E' )
- {
+ || $tertiary === '.000E'
+ ) {
$goodTertiaryChars[$cp] = true;
}
}
@@ -325,7 +326,7 @@ class GenerateCollationData extends Maintenance {
$char = codepointToUtf8( $cp );
$headerChars[] = $char;
if ( $primaryCollator->compare( $char, $prevChar ) <= 0 ) {
- $numOutOfOrder ++;
+ $numOutOfOrder++;
/*
printf( "Out of order: U+%05X > U+%05X\n",
utf8ToCodepoint( $prevChar ),
@@ -390,6 +391,7 @@ class UcdXmlReader {
}
while ( $this->xml->name !== 'ucd' && $this->xml->read() );
$this->xml->read();
+
return $this->xml;
}
@@ -403,6 +405,7 @@ class UcdXmlReader {
while ( $this->xml->moveToNextAttribute() ) {
$attrs[$this->xml->name] = $this->xml->value;
}
+
return $attrs;
}
@@ -460,9 +463,9 @@ class UcdXmlReader {
}
}
$xml->close();
+
return $this->blocks;
}
-
}
$maintClass = 'GenerateCollationData';
diff --git a/maintenance/language/generateNormalizerData.php b/maintenance/language/generateNormalizerDataAr.php
index 216445e4..ece0450f 100644
--- a/maintenance/language/generateNormalizerData.php
+++ b/maintenance/language/generateNormalizerDataAr.php
@@ -1,6 +1,6 @@
<?php
/**
- * Generates normalizer data files for Arabic and Malayalam.
+ * Generates the normalizer data file for Arabic.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,46 +21,43 @@
* @ingroup MaintenanceLanguage
*/
-require_once __DIR__ . '/../../includes/normal/UtfNormalUtil.php';
-
require_once __DIR__ . '/../Maintenance.php';
/**
- * Generates normalizer data files for Arabic and Malayalam.
+ * Generates the normalizer data file for Arabic.
* For NFC see includes/normal.
*
* @ingroup MaintenanceLanguage
*/
-class GenerateNormalizerData extends Maintenance {
- public $dataFile;
-
+class GenerateNormalizerDataAr extends Maintenance {
public function __construct() {
parent::__construct();
+ $this->mDescription = 'Generate the normalizer data file for Arabic';
$this->addOption( 'unicode-data-file', 'The local location of the data file ' .
'from http://unicode.org/Public/UNIDATA/UnicodeData.txt', false, true );
}
+ public function getDbType() {
+ return Maintenance::DB_NONE;
+ }
+
public function execute() {
if ( !$this->hasOption( 'unicode-data-file' ) ) {
- $this->dataFile = 'UnicodeData.txt';
- if ( !file_exists( $this->dataFile ) ) {
- $this->error( "Unable to find UnicodeData.txt. Please specify its location with --unicode-data-file=<FILE>" );
+ $dataFile = 'UnicodeData.txt';
+ if ( !file_exists( $dataFile ) ) {
+ $this->error( "Unable to find UnicodeData.txt. Please specify " .
+ "its location with --unicode-data-file=<FILE>" );
exit( 1 );
}
} else {
- $this->dataFile = $this->getOption( 'unicode-data-file' );
- if ( !file_exists( $this->dataFile ) ) {
+ $dataFile = $this->getOption( 'unicode-data-file' );
+ if ( !file_exists( $dataFile ) ) {
$this->error( 'Unable to find the specified data file.' );
exit( 1 );
}
}
- $this->generateArabic();
- $this->generateMalayalam();
- }
-
- function generateArabic() {
- $file = fopen( $this->dataFile, 'r' );
+ $file = fopen( $dataFile, 'r' );
if ( !$file ) {
$this->error( 'Unable to open the data file.' );
exit( 1 );
@@ -74,7 +71,9 @@ class GenerateNormalizerData extends Maintenance {
'Canonical_Combining_Class',
'Bidi_Class',
'Decomposition_Type_Mapping',
- 'Numeric_Type_Value',
+ 'Numeric_Type_Value_6',
+ 'Numeric_Type_Value_7',
+ 'Numeric_Type_Value_8',
'Bidi_Mirrored',
'Unicode_1_Name',
'ISO_Comment',
@@ -104,15 +103,15 @@ class GenerateNormalizerData extends Maintenance {
$code = base_convert( $data['Code'], 16, 10 );
if ( ( $code >= 0xFB50 && $code <= 0xFDFF ) # Arabic presentation forms A
- || ( $code >= 0xFE70 && $code <= 0xFEFF ) ) # Arabic presentation forms B
- {
+ || ( $code >= 0xFE70 && $code <= 0xFEFF ) # Arabic presentation forms B
+ ) {
if ( $data['Decomposition_Type_Mapping'] === '' ) {
// No decomposition
continue;
}
if ( !preg_match( '/^ *(<\w*>) +([0-9A-F ]*)$/',
- $data['Decomposition_Type_Mapping'], $m ) )
- {
+ $data['Decomposition_Type_Mapping'], $m )
+ ) {
$this->error( "Can't parse Decomposition_Type/Mapping on line $lineNum" );
$this->error( $line );
continue;
@@ -128,32 +127,7 @@ class GenerateNormalizerData extends Maintenance {
file_put_contents( "$IP/serialized/normalize-ar.ser", serialize( $pairs ) );
echo "ar: " . count( $pairs ) . " pairs written.\n";
}
-
- function generateMalayalam() {
- $hexPairs = array(
- # From http://unicode.org/versions/Unicode5.1.0/#Malayalam_Chillu_Characters
- '0D23 0D4D 200D' => '0D7A',
- '0D28 0D4D 200D' => '0D7B',
- '0D30 0D4D 200D' => '0D7C',
- '0D32 0D4D 200D' => '0D7D',
- '0D33 0D4D 200D' => '0D7E',
-
- # From http://permalink.gmane.org/gmane.science.linguistics.wikipedia.technical/46413
- '0D15 0D4D 200D' => '0D7F',
- );
-
- $pairs = array();
- foreach ( $hexPairs as $hexSource => $hexDest ) {
- $source = hexSequenceToUtf8( $hexSource );
- $dest = hexSequenceToUtf8( $hexDest );
- $pairs[$source] = $dest;
- }
-
- global $IP;
- file_put_contents( "$IP/serialized/normalize-ml.ser", serialize( $pairs ) );
- echo "ml: " . count( $pairs ) . " pairs written.\n";
- }
}
-$maintClass = 'GenerateNormalizerData';
+$maintClass = 'GenerateNormalizerDataAr';
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/language/generateNormalizerDataMl.php b/maintenance/language/generateNormalizerDataMl.php
new file mode 100644
index 00000000..c7237cfe
--- /dev/null
+++ b/maintenance/language/generateNormalizerDataMl.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Generates the normalizer data file for Malayalam.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup MaintenanceLanguage
+ */
+
+require_once __DIR__ . '/../Maintenance.php';
+
+/**
+ * Generates the normalizer data file for Malayalam.
+ * For NFC see includes/normal.
+ *
+ * @ingroup MaintenanceLanguage
+ */
+class GenerateNormalizerDataMl extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = 'Generate the normalizer data file for Malayalam';
+ }
+
+ public function getDbType() {
+ return Maintenance::DB_NONE;
+ }
+
+ public function execute() {
+ $hexPairs = array(
+ # From http://unicode.org/versions/Unicode5.1.0/#Malayalam_Chillu_Characters
+ '0D23 0D4D 200D' => '0D7A',
+ '0D28 0D4D 200D' => '0D7B',
+ '0D30 0D4D 200D' => '0D7C',
+ '0D32 0D4D 200D' => '0D7D',
+ '0D33 0D4D 200D' => '0D7E',
+
+ # From http://permalink.gmane.org/gmane.science.linguistics.wikipedia.technical/46413
+ '0D15 0D4D 200D' => '0D7F',
+ );
+
+ $pairs = array();
+ foreach ( $hexPairs as $hexSource => $hexDest ) {
+ $source = hexSequenceToUtf8( $hexSource );
+ $dest = hexSequenceToUtf8( $hexDest );
+ $pairs[$source] = $dest;
+ }
+
+ global $IP;
+ file_put_contents( "$IP/serialized/normalize-ml.ser", serialize( $pairs ) );
+ echo "ml: " . count( $pairs ) . " pairs written.\n";
+ }
+}
+
+$maintClass = 'GenerateNormalizerDataMl';
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/language/generateUtf8Case.php b/maintenance/language/generateUtf8Case.php
new file mode 100644
index 00000000..0fd32427
--- /dev/null
+++ b/maintenance/language/generateUtf8Case.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * Generates Utf8Case.ser from the Unicode Character Database and
+ * supplementary files.
+ *
+ * Copyright © 2004, 2008 Brion Vibber <brion@pobox.com>
+ * https://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup MaintenanceLanguage
+ */
+
+require_once __DIR__ . '/../Maintenance.php';
+
+/**
+ * Generates Utf8Case.ser from the Unicode Character Database and
+ * supplementary files.
+ *
+ * @ingroup MaintenanceLanguage
+ */
+class GenerateUtf8Case extends Maintenance {
+
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = 'Generate Utf8Case.ser from the Unicode Character Database ' .
+ 'and supplementary files';
+ $this->addOption( 'unicode-data-file', 'The local location of the data file ' .
+ 'from http://unicode.org/Public/UNIDATA/UnicodeData.txt', false, true );
+ }
+
+ public function getDbType() {
+ return Maintenance::DB_NONE;
+ }
+
+ public function execute() {
+ if ( !$this->hasOption( 'unicode-data-file' ) ) {
+ $dataFile = 'UnicodeData.txt';
+ if ( !file_exists( $dataFile ) ) {
+ $this->error( "Unable to find UnicodeData.txt. Please specify " .
+ "its location with --unicode-data-file=<FILE>" );
+ exit( 1 );
+ }
+ } else {
+ $dataFile = $this->getOption( 'unicode-data-file' );
+ if ( !file_exists( $dataFile ) ) {
+ $this->error( 'Unable to find the specified data file.' );
+ exit( 1 );
+ }
+ }
+
+ $file = fopen( $dataFile, 'r' );
+ if ( !$file ) {
+ $this->error( 'Unable to open the data file.' );
+ exit( 1 );
+ }
+
+ // For the file format, see http://www.unicode.org/reports/tr44/
+ $fieldNames = array(
+ 'Code',
+ 'Name',
+ 'General_Category',
+ 'Canonical_Combining_Class',
+ 'Bidi_Class',
+ 'Decomposition_Type_Mapping',
+ 'Numeric_Type_Value_6',
+ 'Numeric_Type_Value_7',
+ 'Numeric_Type_Value_8',
+ 'Bidi_Mirrored',
+ 'Unicode_1_Name',
+ 'ISO_Comment',
+ 'Simple_Uppercase_Mapping',
+ 'Simple_Lowercase_Mapping',
+ 'Simple_Titlecase_Mapping'
+ );
+
+ $upper = array();
+ $lower = array();
+
+ $lineNum = 0;
+ while ( false !== ( $line = fgets( $file ) ) ) {
+ ++$lineNum;
+
+ # Strip comments
+ $line = trim( substr( $line, 0, strcspn( $line, '#' ) ) );
+ if ( $line === '' ) {
+ continue;
+ }
+
+ # Split fields
+ $numberedData = explode( ';', $line );
+ $data = array();
+ foreach ( $fieldNames as $number => $name ) {
+ $data[$name] = $numberedData[$number];
+ }
+
+ $source = hexSequenceToUtf8( $data['Code'] );
+ if ( $data['Simple_Uppercase_Mapping'] ) {
+ $upper[$source] = hexSequenceToUtf8( $data['Simple_Uppercase_Mapping'] );
+ }
+ if ( $data['Simple_Lowercase_Mapping'] ) {
+ $lower[$source] = hexSequenceToUtf8( $data['Simple_Lowercase_Mapping'] );
+ }
+ }
+
+ global $IP;
+ file_put_contents( "$IP/serialized/Utf8Case.ser", serialize( array(
+ 'wikiUpperChars' => $upper,
+ 'wikiLowerChars' => $lower,
+ ) ) );
+ }
+}
+
+$maintClass = 'GenerateUtf8Case';
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/language/langmemusage.php b/maintenance/language/langmemusage.php
index 14485f98..32cfcd7d 100644
--- a/maintenance/language/langmemusage.php
+++ b/maintenance/language/langmemusage.php
@@ -43,7 +43,7 @@ class LangMemUsage extends Maintenance {
$this->error( "You must compile PHP with --enable-memory-limit", true );
}
- $langtool = new languages();
+ $langtool = new Languages();
$memlast = $memstart = memory_get_usage();
$this->output( "Base memory usage: $memstart\n" );
diff --git a/maintenance/language/languages.inc b/maintenance/language/languages.inc
index 6070f4ab..fb496cbc 100644
--- a/maintenance/language/languages.inc
+++ b/maintenance/language/languages.inc
@@ -24,35 +24,47 @@
/**
* @ingroup MaintenanceLanguage
*/
-class languages {
- protected $mLanguages; # List of languages
+class Languages {
+ /** @var array List of languages */
+ protected $mLanguages;
- protected $mRawMessages; # Raw list of the messages in each language
- protected $mMessages; # Messages in each language (except for English), divided to groups
- protected $mFallback; # Fallback language in each language
- 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
+ /** @var array Raw list of the messages in each language */
+ protected $mRawMessages;
- protected $mNamespaceNames; # Namespace names
- protected $mNamespaceAliases; # Namespace aliases
- protected $mMagicWords; # Magic words
- protected $mSpecialPageAliases; # Special page aliases
+ /** @var array Messages in each language (except for English), divided to groups */
+ protected $mMessages;
+
+ /** @var array Fallback language in each language */
+ protected $mFallback;
+
+ /** @var array General messages in English, divided to groups */
+ protected $mGeneralMessages;
+
+ /** @var array All the messages which should be exist only in the English file */
+ protected $mIgnoredMessages;
+
+ /** @var array All the messages which may be translated or not, depending on the language */
+ protected $mOptionalMessages;
+
+ /** @var array Namespace names */
+ protected $mNamespaceNames;
+
+ /** @var array Namespace aliases */
+ protected $mNamespaceAliases;
+
+ /** @var array Magic words */
+ protected $mMagicWords;
+
+ /** @var array Special page aliases */
+ protected $mSpecialPageAliases;
/**
* Load the list of languages: all the Messages*.php
* files in the languages directory.
- *
- * @param $exif bool Treat the Exif messages?
*/
- function __construct( $exif = true ) {
- require __DIR__ . '/messageTypes.inc';
- $this->mIgnoredMessages = $wgIgnoredMessages;
- if ( $exif ) {
- $this->mOptionalMessages = array_merge( $wgOptionalMessages );
- } else {
- $this->mOptionalMessages = array_merge( $wgOptionalMessages, $wgEXIFMessages );
- }
+ function __construct() {
+ wfRunHooks( 'LocalisationIgnoredOptionalMessages',
+ array( &$this->mIgnoredMessages, &$this->mOptionalMessages ) );
$this->mLanguages = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) );
sort( $this->mLanguages );
@@ -88,7 +100,7 @@ class languages {
/**
* Load the language file.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*/
protected function loadFile( $code ) {
if ( isset( $this->mRawMessages[$code] ) &&
@@ -96,7 +108,8 @@ class languages {
isset( $this->mNamespaceNames[$code] ) &&
isset( $this->mNamespaceAliases[$code] ) &&
isset( $this->mMagicWords[$code] ) &&
- isset( $this->mSpecialPageAliases[$code] ) ) {
+ isset( $this->mSpecialPageAliases[$code] )
+ ) {
return;
}
$this->mRawMessages[$code] = array();
@@ -105,12 +118,16 @@ class languages {
$this->mNamespaceAliases[$code] = array();
$this->mMagicWords[$code] = array();
$this->mSpecialPageAliases[$code] = array();
+
+ $jsonfilename = Language::getJsonMessagesFileName( $code );
+ if ( file_exists( $jsonfilename ) ) {
+ $json = Language::getLocalisationCache()->readJSONFile( $jsonfilename );
+ $this->mRawMessages[$code] = $json['messages'];
+ }
+
$filename = Language::getMessagesFileName( $code );
if ( file_exists( $filename ) ) {
require $filename;
- if ( isset( $messages ) ) {
- $this->mRawMessages[$code] = $messages;
- }
if ( isset( $fallback ) ) {
$this->mFallback[$code] = $fallback;
}
@@ -130,14 +147,18 @@ class languages {
}
/**
- * Load the messages for a specific language (which is not English) and divide them to groups:
+ * Load the messages for a specific language (which is not English) and divide them to
+ * groups:
* all - all the messages.
* required - messages which should be translated in order to get a complete translation.
- * optional - messages which can be translated, the fallback translation is used if not translated.
- * obsolete - messages which should not be translated, either because they do not exist, or they are ignored messages.
- * translated - messages which are either required or optional, but translated from English and needed.
+ * optional - messages which can be translated, the fallback translation is used if not
+ * translated.
+ * obsolete - messages which should not be translated, either because they do not exist,
+ * or they are ignored messages.
+ * translated - messages which are either required or optional, but translated from
+ * English and needed.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*/
private function loadMessages( $code ) {
if ( isset( $this->mMessages[$code] ) ) {
@@ -166,10 +187,13 @@ class languages {
/**
* Load the messages for English and divide them to groups:
* all - all the messages.
- * required - messages which should be translated to other languages in order to get a complete translation.
- * optional - messages which can be translated to other languages, but it's not required for a complete translation.
+ * required - messages which should be translated to other languages in order to get a
+ * complete translation.
+ * optional - messages which can be translated to other languages, but it's not required
+ * for a complete translation.
* ignored - messages which should not be translated to other languages.
- * translatable - messages which are either required or optional, but can be translated from English.
+ * translatable - messages which are either required or optional, but can be translated
+ * from English.
*/
private function loadGeneralMessages() {
if ( isset( $this->mGeneralMessages ) ) {
@@ -199,111 +223,125 @@ class languages {
* fallback language messages, divided to groups:
* all - all the messages.
* required - messages which should be translated in order to get a complete translation.
- * optional - messages which can be translated, the fallback translation is used if not translated.
- * obsolete - messages which should not be translated, either because they do not exist, or they are ignored messages.
- * translated - messages which are either required or optional, but translated from English and needed.
+ * optional - messages which can be translated, the fallback translation is used if not
+ * translated.
+ * obsolete - messages which should not be translated, either because they do not exist,
+ * or they are ignored messages.
+ * translated - messages which are either required or optional, but translated from
+ * English and needed.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return string The messages in this language.
*/
public function getMessages( $code ) {
$this->loadMessages( $code );
+
return $this->mMessages[$code];
}
/**
* Get all the general English messages, divided to groups:
* all - all the messages.
- * required - messages which should be translated to other languages in order to get a complete translation.
- * optional - messages which can be translated to other languages, but it's not required for a complete translation.
+ * required - messages which should be translated to other languages in
+ * order to get a complete translation.
+ * optional - messages which can be translated to other languages, but it's
+ * not required for a complete translation.
* ignored - messages which should not be translated to other languages.
- * translatable - messages which are either required or optional, but can be translated from English.
+ * translatable - messages which are either required or optional, but can be
+ * translated from English.
*
* @return array The general English messages.
*/
public function getGeneralMessages() {
$this->loadGeneralMessages();
+
return $this->mGeneralMessages;
}
/**
* Get fallback language code for a specific language.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return string Fallback code.
*/
public function getFallback( $code ) {
$this->loadFile( $code );
+
return $this->mFallback[$code];
}
/**
* Get namespace names for a specific language.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array Namespace names.
*/
public function getNamespaceNames( $code ) {
$this->loadFile( $code );
+
return $this->mNamespaceNames[$code];
}
/**
* Get namespace aliases for a specific language.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array Namespace aliases.
*/
public function getNamespaceAliases( $code ) {
$this->loadFile( $code );
+
return $this->mNamespaceAliases[$code];
}
/**
* Get magic words for a specific language.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array Magic words.
*/
public function getMagicWords( $code ) {
$this->loadFile( $code );
+
return $this->mMagicWords[$code];
}
/**
* Get special page aliases for a specific language.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array Special page aliases.
*/
public function getSpecialPageAliases( $code ) {
$this->loadFile( $code );
+
return $this->mSpecialPageAliases[$code];
}
/**
* Get the untranslated messages for a specific language.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The untranslated messages for this language.
*/
public function getUntranslatedMessages( $code ) {
$this->loadGeneralMessages();
$this->loadMessages( $code );
+
return array_diff_key( $this->mGeneralMessages['required'], $this->mMessages[$code]['required'] );
}
/**
* Get the duplicate messages for a specific language.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The duplicate messages for this language.
*/
@@ -316,26 +354,28 @@ class languages {
$duplicateMessages[$key] = $value;
}
}
+
return $duplicateMessages;
}
/**
* Get the obsolete messages for a specific language.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The obsolete messages for this language.
*/
public function getObsoleteMessages( $code ) {
$this->loadGeneralMessages();
$this->loadMessages( $code );
+
return $this->mMessages[$code]['obsolete'];
}
/**
* Get the messages whose variables do not match the original ones.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The messages whose variables do not match the original ones.
*/
@@ -348,11 +388,13 @@ class languages {
$missing = false;
foreach ( $variables as $var ) {
if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
- !preg_match( "/$var/sU", $value ) ) {
+ !preg_match( "/$var/sU", $value )
+ ) {
$missing = true;
}
if ( !preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
- preg_match( "/$var/sU", $value ) ) {
+ preg_match( "/$var/sU", $value )
+ ) {
$missing = true;
}
}
@@ -360,13 +402,14 @@ class languages {
$mismatchMessages[$key] = $value;
}
}
+
return $mismatchMessages;
}
/**
* Get the messages which do not use plural.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The messages which do not use plural in this language.
*/
@@ -375,17 +418,20 @@ class languages {
$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 ) {
+ if ( stripos( $this->mGeneralMessages['translatable'][$key], '{{plural:' ) !== false &&
+ stripos( $value, '{{plural:' ) === false
+ ) {
$messagesWithoutPlural[$key] = $value;
}
}
+
return $messagesWithoutPlural;
}
/**
* Get the empty messages.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The empty messages for this language.
*/
@@ -398,13 +444,14 @@ class languages {
$emptyMessages[$key] = $value;
}
}
+
return $emptyMessages;
}
/**
* Get the messages with trailing whitespace.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The messages with trailing whitespace in this language.
*/
@@ -417,13 +464,14 @@ class languages {
$messagesWithWhitespace[$key] = $value;
}
}
+
return $messagesWithWhitespace;
}
/**
* Get the non-XHTML messages.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The non-XHTML messages for this language.
*/
@@ -445,13 +493,14 @@ class languages {
$nonXHTMLMessages[$key] = $value;
}
}
+
return $nonXHTMLMessages;
}
/**
* Get the messages which include wrong characters.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The messages which include wrong characters in this language.
*/
@@ -482,13 +531,14 @@ class languages {
$wrongCharsMessages[$key] = $value;
}
}
+
return $wrongCharsMessages;
}
/**
* Get the messages which include dubious links.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The messages which include dubious links in this language.
*/
@@ -500,24 +550,25 @@ class languages {
foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
$matches = array();
preg_match_all( "/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu", $value, $matches );
- for ( $i = 0; $i < count( $matches[0] ); $i++ ) {
+ $numMatches = count( $matches[0] );
+ for ( $i = 0; $i < $numMatches; $i++ ) {
if ( preg_match( "/.*project.*/isDu", $matches[1][$i] ) ) {
$messages[$key][] = $matches[0][$i];
}
}
-
if ( isset( $messages[$key] ) ) {
$messages[$key] = implode( $messages[$key], ", " );
}
}
+
return $messages;
}
/**
* Get the messages which include unbalanced brackets.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The messages which include unbalanced brackets in this language.
*/
@@ -547,15 +598,15 @@ class languages {
if ( $a !== $b || $c !== $d ) {
$messages[$key] = "$a, $b, $c, $d";
}
-
}
+
return $messages;
}
/**
* Get the untranslated namespace names.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The untranslated namespace names in this language.
*/
@@ -566,13 +617,14 @@ class languages {
if ( isset( $namespacesDiff[NS_MAIN] ) ) {
unset( $namespacesDiff[NS_MAIN] );
}
+
return $namespacesDiff;
}
/**
* Get the project talk namespace names with no $1.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The problematic project talk namespaces in this language.
*/
@@ -601,7 +653,7 @@ class languages {
/**
* Get the untranslated magic words.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The untranslated magic words in this language.
*/
@@ -614,13 +666,14 @@ class languages {
$magicWords[$key] = $value[1];
}
}
+
return $magicWords;
}
/**
* Get the obsolete magic words.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The obsolete magic words in this language.
*/
@@ -633,13 +686,14 @@ class languages {
$magicWords[$key] = $value[1];
}
}
+
return $magicWords;
}
/**
* Get the magic words that override the original English magic word.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The overriding magic words in this language.
*/
@@ -662,13 +716,14 @@ class languages {
}
}
}
+
return $magicWords;
}
/**
* Get the magic words which do not match the case-sensitivity of the original words.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The magic words whose case does not match in this language.
*/
@@ -685,13 +740,14 @@ class languages {
$magicWords[$key] = $local[0];
}
}
+
return $magicWords;
}
/**
* Get the untranslated special page names.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The untranslated special page names in this language.
*/
@@ -704,13 +760,14 @@ class languages {
$specialPageAliases[$key] = $value[0];
}
}
+
return $specialPageAliases;
}
/**
* Get the obsolete special page names.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*
* @return array The obsolete special page names in this language.
*/
@@ -723,12 +780,12 @@ class languages {
$specialPageAliases[$key] = $value[0];
}
}
+
return $specialPageAliases;
}
}
-class extensionLanguages extends languages {
-
+class ExtensionLanguages extends Languages {
/**
* @var MessageGroup
*/
@@ -736,7 +793,7 @@ class extensionLanguages extends languages {
/**
* Load the messages group.
- * @param $group MessageGroup The messages group.
+ * @param MessageGroup $group The messages group.
*/
function __construct( MessageGroup $group ) {
$this->mMessageGroup = $group;
@@ -757,7 +814,7 @@ class extensionLanguages extends languages {
/**
* Load the language file.
*
- * @param $code string The language code.
+ * @param string $code The language code.
*/
protected function loadFile( $code ) {
if ( !isset( $this->mRawMessages[$code] ) ) {
diff --git a/maintenance/language/listVariants.php b/maintenance/language/listVariants.php
new file mode 100644
index 00000000..4bff8916
--- /dev/null
+++ b/maintenance/language/listVariants.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Lists all language variants
+ *
+ * Copyright © 2014 MediaWiki developers
+ * https://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+require_once dirname( __DIR__ ) . '/Maintenance.php';
+
+/**
+ * @since 1.24
+ */
+class ListVariants extends Maintenance {
+
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = 'Outputs a list of language variants';
+ $this->addOption( 'flat', 'Output variants in a flat list' );
+ $this->addOption( 'json', 'Output variants as JSON' );
+ }
+
+ public function execute() {
+ $variantLangs = array();
+ $variants = array();
+ foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
+ $lang = Language::factory( $langCode );
+ if ( count( $lang->getVariants() ) > 1 ) {
+ $variants += array_flip( $lang->getVariants() );
+ $variantLangs[$langCode] = $lang->getVariants();
+ }
+ }
+ $variants = array_keys( $variants );
+ sort( $variants );
+ $result = $this->hasOption( 'flat' ) ? $variants : $variantLangs;
+
+ // Not using $this->output() because muting makes no sense here
+ if ( $this->hasOption( 'json' ) ) {
+ echo FormatJson::encode( $result, true ) . "\n";
+ } else {
+ foreach ( $result as $key => $value ) {
+ if ( is_array( $value ) ) {
+ echo "$key\n";
+ foreach ( $value as $variant ) {
+ echo " $variant\n";
+ }
+ } else {
+ echo "$value\n";
+ }
+ }
+ }
+ }
+}
+
+$maintClass = 'ListVariants';
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/language/messageTypes.inc b/maintenance/language/messageTypes.inc
deleted file mode 100644
index f9239b1c..00000000
--- a/maintenance/language/messageTypes.inc
+++ /dev/null
@@ -1,872 +0,0 @@
-<?php
-/**
- * Several types of messages.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup MaintenanceLanguage
- */
-
-/** Ignored messages, which should 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-unprotect',
- 'accesskey-ca-delete',
- 'accesskey-ca-undelete',
- 'accesskey-ca-move',
- 'accesskey-ca-watch',
- 'accesskey-ca-unwatch',
- 'accesskey-search',
- 'accesskey-search-go',
- 'accesskey-search-fulltext',
- 'accesskey-p-logo',
- 'accesskey-n-mainpage',
- 'accesskey-n-mainpage-description',
- 'accesskey-n-portal',
- 'accesskey-n-currentevents',
- 'accesskey-n-recentchanges',
- 'accesskey-n-randompage',
- 'accesskey-n-help',
- 'accesskey-t-whatlinkshere',
- 'accesskey-t-recentchangeslinked',
- 'accesskey-feed-rss',
- 'accesskey-feed-atom',
- 'accesskey-t-contributions',
- 'accesskey-t-emailuser',
- 'accesskey-t-permalink',
- 'accesskey-t-print',
- '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',
- 'accesskey-upload',
- 'accesskey-preferences-save',
- 'accesskey-summary',
- 'accesskey-userrights-set',
- 'accesskey-blockip-block',
- 'accesskey-export',
- 'accesskey-import',
- 'accesskey-watchlistedit-normal-submit',
- 'accesskey-watchlistedit-raw-submit',
- 'addsection',
- 'talkpageheader',
- 'anonnotice',
- 'autoblock_whitelist',
- 'searchmenu-new-nocreate',
- 'googlesearch',
- 'opensearch-desc',
- 'exif-make-value',
- 'exif-model-value',
- 'exif-software-value',
- 'exif-software-version-value',
- 'history_copyright',
- 'licenses',
- 'loginstart',
- 'loginend-https',
- 'loginend',
- 'loginlanguagelinks',
- 'pear-mail-error',
- 'php-mail-error',
- 'markaspatrolledlink',
- 'newarticletextanon',
- 'newsectionheaderdefaultlevel',
- 'mainpage-nstab',
- 'newtalkseparator',
- 'noarticletextanon',
- 'number_of_watching_users_RCview',
- 'pagecategorieslink',
- 'pubmedurl',
- 'randompage-url',
- 'recentchanges-url',
- 'recentchangestext',
- 'revision-info-current',
- 'revision-nav',
- 'rfcurl',
- 'shareddescriptionfollows',
- 'signature-anon',
- 'signupstart',
- 'signupend',
- 'signupend-https',
- 'sitenotice',
- 'sitesubtitle',
- 'sitetitle',
- 'sp-contributions-footer',
- 'sp-contributions-footer-anon',
- 'sp-contributions-footer-newbies',
- 'statistics-summary',
- 'statistics-footer',
- 'talkpagetext',
- 'uploadfooter',
- 'upload-default-description',
- 'listgrouprights-link',
- 'search-interwiki-custom',
- 'allpages-summary',
- 'booksources-summary',
- 'categories-summary',
- 'blocklist-summary',
- 'protectedtitles-summary',
- 'listusers-summary',
- 'longpages-summary',
- 'preferences-summary',
- 'specialpages-summary',
- 'whatlinkshere-summary',
- 'listredirects-summary',
- 'uncategorizedpages-summary',
- 'uncategorizedcategories-summary',
- 'uncategorizedimages-summary',
- 'uncategorizedtemplates-summary',
- 'popularpages-summary',
- 'wantedcategories-summary',
- 'wantedfiles-summary',
- 'wantedpages-summary',
- 'watchlist-summary',
- 'mostlinked-summary',
- 'mostlinkedcategories-summary',
- 'mostlinkedtemplates-summary',
- 'mostcategories-summary',
- 'mostimages-summary',
- 'mostinterwikis-summary',
- 'mostrevisions-summary',
- 'prefixindex-summary',
- 'shortpages-summary',
- 'newpages-summary',
- 'ancientpages-summary',
- 'unwatchedpages-summary',
- 'userrights-summary',
- 'brokenredirects-summary',
- 'deadendpages-summary',
- 'protectedpages-summary',
- 'disambiguations-summary',
- 'pageswithprop-summary',
- 'doubleredirects-summary',
- 'lonelypages-summary',
- 'unusedtemplates-summary',
- 'fewestrevisions-summary',
- 'upload-summary',
- 'wantedtemplates-summary',
- 'activeusers-summary',
- 'search-summary',
- 'editpage-head-copy-warn',
- 'editpage-tos-summary',
- 'addsection-preload',
- 'addsection-editintro',
- 'longpage-hint',
- 'javascripttest-backlink',
- 'javascripttest-qunit-name',
- 'revdelete-logentry',
- 'logdelete-logentry',
- 'revdelete-content',
- 'revdelete-summary',
- 'revdelete-uname',
- 'revdelete-hid',
- 'revdelete-unhid',
- 'revdelete-log-message',
- 'logdelete-log-message',
- 'deletedarticle',
- 'suppressedarticle',
- 'undeletedarticle',
- 'patrol-log-line',
- 'patrol-log-auto',
- 'patrol-log-diff',
- '1movedto2',
- '1movedto2_redir',
- 'move-redirect-suppressed',
- 'newuserlog-create-entry',
- 'newuserlog-create2-entry',
- 'newuserlog-autocreate-entry',
- 'rightslogentry',
- 'rightslogentry-autopromote',
- 'suppressedarticle',
- 'deletedarticle',
- // 'uploadedimage',
- // 'overwroteimage',
- 'createacct-helpusername',
- 'createacct-imgcaptcha-help',
- 'userlogout-summary',
- 'changeemail-summary',
- 'changepassword-summary',
- 'unusedcategories-summary',
- 'unusedimages-summary',
- 'deletedcontributions-summary',
- 'linksearch-summary',
- 'emailuser-summary',
- 'undelete-summary',
- 'contributions-summary',
- 'unblock-summary',
- 'movepage-summary',
- 'export-summary',
- 'import-summary',
- 'editwatchlist-summary',
- 'version-summary',
- 'tags-summary',
- 'comparepages-summary',
- 'resettokens-summary',
- 'version-db-mysql-url',
- 'version-db-mariadb-url',
- 'version-db-percona-url',
- 'version-db-postgres-url',
- 'version-db-oracle-url',
- 'version-db-sqlite-url',
- 'version-db-mssql-url',
- 'version-entrypoints-index-php',
- 'version-entrypoints-api-php',
- 'version-entrypoints-load-php',
- 'ipb-default-expiry',
- 'pageinfo-header',
- 'pageinfo-footer',
- 'createacct-benefit-head1',
- 'createacct-benefit-icon1',
- 'createacct-benefit-head2',
- 'createacct-benefit-icon2',
- 'createacct-benefit-head3',
- 'createacct-benefit-icon3',
- 'today-at',
- 'redirect-text',
- 'helppage',
- 'edithelppage',
- 'helplogin-url',
- 'autocomment-prefix',
- 'move-redirect-text',
-);
-
-/** Optional messages, which may be translated only if changed in the target language. */
-$wgOptionalMessages = array(
- 'linkprefix',
- 'feed-atom',
- 'feed-rss',
- 'unit-pixel',
- 'userrights-irreversible-marker',
- 'tog-noconvertlink',
- 'variantname-zh-hans',
- 'variantname-zh-hant',
- 'variantname-zh-cn',
- 'variantname-zh-tw',
- 'variantname-zh-hk',
- 'variantname-zh-mo',
- 'variantname-zh-my',
- 'variantname-zh-sg',
- 'variantname-zh',
- 'variantname-gan-hans',
- 'variantname-gan-hant',
- 'variantname-gan',
- 'variantname-sr-ec',
- 'variantname-sr-el',
- 'variantname-sr',
- 'variantname-kk-arab',
- 'variantname-kk-cyrl',
- 'variantname-kk-latn',
- 'variantname-kk-tr',
- 'variantname-kk-kz',
- 'variantname-kk-cn',
- 'variantname-kk',
- 'variantname-ku-latn',
- 'variantname-ku-arab',
- 'variantname-ku',
- 'variantname-tg-cyrl',
- 'variantname-tg-latn',
- 'variantname-tg',
- 'variantname-ike-cans',
- 'variantname-ike-latn',
- 'variantname-iu',
- 'variantname-shi-tfng',
- 'variantname-shi-latn',
- 'variantname-shi',
- 'rc-change-size',
- 'resetpass_text',
- 'image_sample',
- 'media_sample',
- 'skinname-cologneblue',
- 'skinname-monobook',
- 'skinname-modern',
- 'skinname-vector',
- 'common.css',
- 'cologneblue.css',
- 'monobook.css',
- 'modern.css',
- 'vector.css',
- 'print.css',
- 'noscript.css',
- 'group-autoconfirmed.css',
- 'group-bot.css',
- 'group-sysop.css',
- 'group-bureaucrat.css',
- 'common.js',
- 'cologneblue.js',
- 'monobook.js',
- 'modern.js',
- 'vector.js',
- 'group-autoconfirmed.js',
- 'group-bot.js',
- 'group-sysop.js',
- 'group-bureaucrat.js',
- 'widthheight',
- 'exif-fnumber-format',
- 'exif-focallength-format',
- 'exif-compression-5',
- 'exif-compression-6',
- 'exif-compression-7',
- 'exif-compression-8',
- 'exif-compression-32773',
- 'exif-compression-32946',
- 'exif-compression-34712',
- 'exif-photometricinterpretation-2',
- 'exif-photometricinterpretation-6',
- 'exif-xyresolution-i',
- 'exif-xyresolution-c',
- 'exif-colorspace-1',
- 'exif-componentsconfiguration-1',
- 'exif-componentsconfiguration-2',
- 'exif-componentsconfiguration-3',
- 'exif-componentsconfiguration-4',
- 'exif-componentsconfiguration-5',
- 'exif-componentsconfiguration-6',
- 'exif-contact-value',
- 'exif-coordinate-format',
- 'exif-lightsource-20',
- 'exif-lightsource-21',
- 'exif-lightsource-22',
- 'exif-lightsource-23',
- 'exif-maxaperturevalue-value',
- 'exif-subjectnewscode-value',
- 'booksources-isbn',
- 'protect-summary-desc',
- 'sp-contributions-explain',
- 'sorbs',
- 'video-dims',
- 'seconds-abbrev',
- 'minutes-abbrev',
- 'hours-abbrev',
- 'days-abbrev',
- 'pagetitle',
- 'filename-prefix-blacklist',
- 'edittools',
- 'edittools-upload',
- 'size-bytes',
- 'size-kilobytes',
- 'size-megabytes',
- 'size-gigabytes',
- 'size-terabytes',
- 'size-petabytes',
- 'size-exabytes',
- 'size-zetabytes',
- 'size-yottabytes',
- 'bitrate-bits',
- 'bitrate-kilobits',
- 'bitrate-megabits',
- 'bitrate-gigabits',
- 'bitrate-terabits',
- 'bitrate-petabits',
- 'bitrate-exabits',
- 'bitrate-zetabits',
- 'bitrate-yottabits',
- 'iranian-calendar-m1',
- 'iranian-calendar-m2',
- 'iranian-calendar-m3',
- 'iranian-calendar-m4',
- 'iranian-calendar-m5',
- 'iranian-calendar-m6',
- 'iranian-calendar-m7',
- 'iranian-calendar-m8',
- 'iranian-calendar-m9',
- 'iranian-calendar-m10',
- 'iranian-calendar-m11',
- 'iranian-calendar-m12',
- 'hijri-calendar-m1',
- 'hijri-calendar-m2',
- 'hijri-calendar-m3',
- 'hijri-calendar-m4',
- 'hijri-calendar-m5',
- 'hijri-calendar-m6',
- 'hijri-calendar-m7',
- 'hijri-calendar-m8',
- 'hijri-calendar-m9',
- 'hijri-calendar-m10',
- 'hijri-calendar-m11',
- 'hijri-calendar-m12',
- 'hebrew-calendar-m1',
- 'hebrew-calendar-m2',
- 'hebrew-calendar-m3',
- 'hebrew-calendar-m4',
- 'hebrew-calendar-m5',
- 'hebrew-calendar-m6',
- 'hebrew-calendar-m6a',
- 'hebrew-calendar-m6b',
- 'hebrew-calendar-m7',
- 'hebrew-calendar-m8',
- 'hebrew-calendar-m9',
- 'hebrew-calendar-m10',
- 'hebrew-calendar-m11',
- 'hebrew-calendar-m12',
- 'hebrew-calendar-m1-gen',
- 'hebrew-calendar-m2-gen',
- 'hebrew-calendar-m3-gen',
- 'hebrew-calendar-m4-gen',
- 'hebrew-calendar-m5-gen',
- 'hebrew-calendar-m6-gen',
- 'hebrew-calendar-m6a-gen',
- 'hebrew-calendar-m6b-gen',
- 'hebrew-calendar-m7-gen',
- 'hebrew-calendar-m8-gen',
- 'hebrew-calendar-m9-gen',
- 'hebrew-calendar-m10-gen',
- 'hebrew-calendar-m11-gen',
- 'hebrew-calendar-m12-gen',
- 'version-api',
- 'version-svn-revision',
- 'semicolon-separator',
- 'comma-separator',
- 'colon-separator',
- 'pipe-separator',
- 'word-separator',
- 'ellipsis',
- 'percent',
- 'parentheses',
- 'brackets',
- 'listgrouprights-right-display',
- 'listgrouprights-right-revoked',
- 'timezone-utc',
- 'unpatrolledletter',
- 'diff-with-additional',
- 'pagetitle-view-mainpage',
- 'backlinksubtitle',
- 'prefs-registration-date-time',
- 'prefs-memberingroups-type',
- 'userrights-groupsmember-type',
- 'shared-repo-name-wikimediacommons',
- 'usermessage-template',
- 'filepage.css',
- 'metadata-langitem',
- 'metadata-langitem-default',
- 'nocookiesforlogin',
- 'version-entrypoints-articlepath',
- 'version-entrypoints-scriptpath',
- 'mergehistory-revisionrow',
- 'categoryviewer-pagedlinks',
- 'undelete-revisionrow',
- 'pageinfo-redirects-value',
- 'created', // @deprecated. Remove in MediaWiki 1.23.
- 'changed', // @deprecated. Remove in MediaWiki 1.23.
- 'limitreport-ppvisitednodes-value',
- 'limitreport-ppgeneratednodes-value',
- 'limitreport-expansiondepth-value',
- 'limitreport-expensivefunctioncount-value',
- 'tooltip-iwiki',
-);
-
-/** Exif messages, which may be set as optional in several checks, but are generally mandatory */
-$wgEXIFMessages = array(
- 'exif-imagewidth',
- 'exif-imagelength',
- 'exif-bitspersample',
- 'exif-compression',
- 'exif-photometricinterpretation',
- 'exif-orientation',
- 'exif-samplesperpixel',
- 'exif-planarconfiguration',
- 'exif-ycbcrsubsampling',
- 'exif-ycbcrpositioning',
- 'exif-xresolution',
- 'exif-yresolution',
- 'exif-stripoffsets',
- 'exif-rowsperstrip',
- 'exif-stripbytecounts',
- 'exif-jpeginterchangeformat',
- 'exif-jpeginterchangeformatlength',
- 'exif-whitepoint',
- 'exif-primarychromaticities',
- 'exif-ycbcrcoefficients',
- 'exif-referenceblackwhite',
- 'exif-datetime',
- 'exif-imagedescription',
- 'exif-make',
- 'exif-model',
- 'exif-software',
- 'exif-artist',
- 'exif-copyright',
- 'exif-exifversion',
- 'exif-flashpixversion',
- 'exif-colorspace',
- 'exif-componentsconfiguration',
- 'exif-compressedbitsperpixel',
- 'exif-pixelydimension',
- 'exif-pixelxdimension',
- 'exif-usercomment',
- 'exif-relatedsoundfile',
- 'exif-datetimeoriginal',
- 'exif-datetimedigitized',
- 'exif-subsectime',
- 'exif-subsectimeoriginal',
- 'exif-subsectimedigitized',
- 'exif-exposuretime',
- 'exif-exposuretime-format',
- 'exif-fnumber',
- 'exif-fnumber-format',
- 'exif-exposureprogram',
- 'exif-spectralsensitivity',
- 'exif-isospeedratings',
- 'exif-shutterspeedvalue',
- 'exif-aperturevalue',
- 'exif-brightnessvalue',
- 'exif-exposurebiasvalue',
- 'exif-maxaperturevalue',
- 'exif-subjectdistance',
- 'exif-meteringmode',
- 'exif-lightsource',
- 'exif-flash',
- 'exif-focallength',
- 'exif-focallength-format',
- 'exif-subjectarea',
- 'exif-flashenergy',
- 'exif-focalplanexresolution',
- 'exif-focalplaneyresolution',
- 'exif-focalplaneresolutionunit',
- 'exif-subjectlocation',
- 'exif-exposureindex',
- 'exif-sensingmethod',
- 'exif-filesource',
- 'exif-scenetype',
- 'exif-customrendered',
- 'exif-exposuremode',
- 'exif-whitebalance',
- 'exif-digitalzoomratio',
- 'exif-focallengthin35mmfilm',
- 'exif-scenecapturetype',
- 'exif-gaincontrol',
- 'exif-contrast',
- 'exif-saturation',
- 'exif-sharpness',
- 'exif-devicesettingdescription',
- 'exif-subjectdistancerange',
- 'exif-imageuniqueid',
- 'exif-gpsversionid',
- 'exif-gpslatituderef',
- 'exif-gpslatitude',
- 'exif-gpslongituderef',
- 'exif-gpslongitude',
- 'exif-gpsaltituderef',
- 'exif-gpsaltitude',
- 'exif-gpstimestamp',
- 'exif-gpssatellites',
- 'exif-gpsstatus',
- 'exif-gpsmeasuremode',
- 'exif-gpsdop',
- 'exif-gpsspeedref',
- 'exif-gpsspeed',
- 'exif-gpstrackref',
- 'exif-gpstrack',
- 'exif-gpsimgdirectionref',
- 'exif-gpsimgdirection',
- 'exif-gpsmapdatum',
- 'exif-gpsdestlatituderef',
- 'exif-gpsdestlatitude',
- 'exif-gpsdestlongituderef',
- 'exif-gpsdestlongitude',
- 'exif-gpsdestbearingref',
- 'exif-gpsdestbearing',
- 'exif-gpsdestdistanceref',
- 'exif-gpsdestdistance',
- 'exif-gpsprocessingmethod',
- 'exif-gpsareainformation',
- 'exif-gpsdatestamp',
- 'exif-gpsdifferential',
- 'exif-coordinate-format',
- 'exif-jpegfilecomment',
- 'exif-keywords',
- 'exif-worldregioncreated',
- 'exif-countrycreated',
- 'exif-countrycodecreated',
- 'exif-provinceorstatecreated',
- 'exif-citycreated',
- 'exif-sublocationcreated',
- 'exif-worldregiondest',
- 'exif-countrydest',
- 'exif-countrycodedest',
- 'exif-provinceorstatedest',
- 'exif-citydest',
- 'exif-sublocationdest',
- 'exif-objectname',
- 'exif-specialinstructions',
- 'exif-headline',
- 'exif-credit',
- 'exif-source',
- 'exif-editstatus',
- 'exif-urgency',
- 'exif-fixtureidentifier',
- 'exif-locationdest',
- 'exif-locationdestcode',
- 'exif-objectcycle',
- 'exif-contact',
- 'exif-writer',
- 'exif-languagecode',
- 'exif-iimversion',
- 'exif-iimcategory',
- 'exif-iimsupplementalcategory',
- 'exif-datetimeexpires',
- 'exif-datetimereleased',
- 'exif-originaltransmissionref',
- 'exif-identifier',
- 'exif-lens',
- 'exif-serialnumber',
- 'exif-cameraownername',
- 'exif-label',
- 'exif-datetimemetadata',
- 'exif-nickname',
- 'exif-rating',
- 'exif-rightscertificate',
- 'exif-copyrighted',
- 'exif-copyrightowner',
- 'exif-usageterms',
- 'exif-webstatement',
- 'exif-originaldocumentid',
- 'exif-licenseurl',
- 'exif-morepermissionsurl',
- 'exif-attributionurl',
- 'exif-preferredattributionname',
- 'exif-pngfilecomment',
- 'exif-disclaimer',
- 'exif-contentwarning',
- 'exif-giffilecomment',
- 'exif-intellectualgenre',
- 'exif-subjectnewscode',
- 'exif-scenecode',
- 'exif-event',
- 'exif-organisationinimage',
- 'exif-personinimage',
- 'exif-originalimageheight',
- 'exif-originalimagewidth',
- 'exif-make-value',
- 'exif-model-value',
- 'exif-software-value',
- 'exif-software-version-value',
- 'exif-contact-value',
- 'exif-subjectnewscode-value',
- 'exif-compression-1',
- 'exif-compression-2',
- 'exif-compression-3',
- 'exif-compression-4',
- 'exif-compression-5',
- 'exif-compression-6',
- 'exif-compression-7',
- 'exif-compression-8',
- 'exif-compression-32773',
- 'exif-compression-32946',
- 'exif-compression-34712',
- 'exif-copyrighted-true',
- 'exif-copyrighted-false',
- 'exif-photometricinterpretation-2',
- 'exif-photometricinterpretation-6',
- 'exif-unknowndate',
- 'exif-orientation-1',
- 'exif-orientation-2',
- 'exif-orientation-3',
- 'exif-orientation-4',
- 'exif-orientation-5',
- 'exif-orientation-6',
- 'exif-orientation-7',
- 'exif-orientation-8',
- 'exif-planarconfiguration-1',
- 'exif-planarconfiguration-2',
- 'exif-xyresolution-i',
- 'exif-xyresolution-c',
- 'exif-colorspace-1',
- 'exif-colorspace-65535',
- 'exif-componentsconfiguration-0',
- 'exif-componentsconfiguration-1',
- 'exif-componentsconfiguration-2',
- 'exif-componentsconfiguration-3',
- 'exif-componentsconfiguration-4',
- 'exif-componentsconfiguration-5',
- 'exif-componentsconfiguration-6',
- 'exif-exposureprogram-0',
- 'exif-exposureprogram-1',
- 'exif-exposureprogram-2',
- 'exif-exposureprogram-3',
- 'exif-exposureprogram-4',
- 'exif-exposureprogram-5',
- 'exif-exposureprogram-6',
- 'exif-exposureprogram-7',
- 'exif-exposureprogram-8',
- 'exif-subjectdistance-value',
- 'exif-meteringmode-0',
- 'exif-meteringmode-1',
- 'exif-meteringmode-2',
- 'exif-meteringmode-3',
- 'exif-meteringmode-4',
- 'exif-meteringmode-5',
- 'exif-meteringmode-6',
- 'exif-meteringmode-255',
- 'exif-lightsource-0',
- 'exif-lightsource-1',
- 'exif-lightsource-2',
- 'exif-lightsource-3',
- 'exif-lightsource-4',
- 'exif-lightsource-9',
- 'exif-lightsource-10',
- 'exif-lightsource-11',
- 'exif-lightsource-12',
- 'exif-lightsource-13',
- 'exif-lightsource-14',
- 'exif-lightsource-15',
- 'exif-lightsource-17',
- 'exif-lightsource-18',
- 'exif-lightsource-19',
- 'exif-lightsource-20',
- 'exif-lightsource-21',
- 'exif-lightsource-22',
- 'exif-lightsource-23',
- 'exif-lightsource-24',
- 'exif-lightsource-255',
- 'exif-flash-fired-0',
- 'exif-flash-fired-1',
- 'exif-flash-return-0',
- 'exif-flash-return-2',
- 'exif-flash-return-3',
- 'exif-flash-mode-1',
- 'exif-flash-mode-2',
- 'exif-flash-mode-3',
- 'exif-flash-function-1',
- 'exif-flash-redeye-1',
- 'exif-focalplaneresolutionunit-2',
- 'exif-sensingmethod-1',
- 'exif-sensingmethod-2',
- 'exif-sensingmethod-3',
- 'exif-sensingmethod-4',
- 'exif-sensingmethod-5',
- 'exif-sensingmethod-7',
- 'exif-sensingmethod-8',
- 'exif-filesource-3',
- 'exif-scenetype-1',
- 'exif-customrendered-0',
- 'exif-customrendered-1',
- 'exif-exposuremode-0',
- 'exif-exposuremode-1',
- 'exif-exposuremode-2',
- 'exif-whitebalance-0',
- 'exif-whitebalance-1',
- 'exif-scenecapturetype-0',
- 'exif-scenecapturetype-1',
- 'exif-scenecapturetype-2',
- 'exif-scenecapturetype-3',
- 'exif-gaincontrol-0',
- 'exif-gaincontrol-1',
- 'exif-gaincontrol-2',
- 'exif-gaincontrol-3',
- 'exif-gaincontrol-4',
- 'exif-contrast-0',
- 'exif-contrast-1',
- 'exif-contrast-2',
- 'exif-saturation-0',
- 'exif-saturation-1',
- 'exif-saturation-2',
- 'exif-sharpness-0',
- 'exif-sharpness-1',
- 'exif-sharpness-2',
- 'exif-subjectdistancerange-0',
- 'exif-subjectdistancerange-1',
- 'exif-subjectdistancerange-2',
- 'exif-subjectdistancerange-3',
- 'exif-gpslatitude-n',
- 'exif-gpslatitude-s',
- 'exif-gpslongitude-e',
- 'exif-gpslongitude-w',
- 'exif-gpsaltitude-above-sealevel',
- 'exif-gpsaltitude-below-sealevel',
- 'exif-gpsstatus-a',
- 'exif-gpsstatus-v',
- 'exif-gpsmeasuremode-2',
- 'exif-gpsmeasuremode-3',
- 'exif-gpsspeed-k',
- 'exif-gpsspeed-m',
- 'exif-gpsspeed-n',
- 'exif-gpsdestdistance-k',
- 'exif-gpsdestdistance-m',
- 'exif-gpsdestdistance-n',
- 'exif-gpsdop-excellent',
- 'exif-gpsdop-good',
- 'exif-gpsdop-moderate',
- 'exif-gpsdop-fair',
- 'exif-gpsdop-poor',
- 'exif-objectcycle-a',
- 'exif-objectcycle-p',
- 'exif-objectcycle-b',
- 'exif-gpsdirection-t',
- 'exif-gpsdirection-m',
- 'exif-ycbcrpositioning-1',
- 'exif-ycbcrpositioning-2',
- 'exif-dc-contributor',
- 'exif-dc-coverage',
- 'exif-dc-date',
- 'exif-dc-publisher',
- 'exif-dc-relation',
- 'exif-dc-rights',
- 'exif-dc-source',
- 'exif-dc-type',
- 'exif-rating-rejected',
- 'exif-isospeedratings-overflow',
- 'exif-maxaperturevalue-value',
- 'exif-iimcategory-ace',
- 'exif-iimcategory-clj',
- 'exif-iimcategory-dis',
- 'exif-iimcategory-fin',
- 'exif-iimcategory-edu',
- 'exif-iimcategory-evn',
- 'exif-iimcategory-hth',
- 'exif-iimcategory-hum',
- 'exif-iimcategory-lab',
- 'exif-iimcategory-lif',
- 'exif-iimcategory-pol',
- 'exif-iimcategory-rel',
- 'exif-iimcategory-sci',
- 'exif-iimcategory-soi',
- 'exif-iimcategory-spo',
- 'exif-iimcategory-war',
- 'exif-iimcategory-wea',
- 'exif-urgency-normal',
- 'exif-urgency-low',
- 'exif-urgency-high',
- 'exif-urgency-other',
-);
diff --git a/maintenance/language/messages.inc b/maintenance/language/messages.inc
deleted file mode 100644
index e351549b..00000000
--- a/maintenance/language/messages.inc
+++ /dev/null
@@ -1,4239 +0,0 @@
-<?php
-/**
- * Define the messages structure in the messages file, for an automated rewriting.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup MaintenanceLanguage
- */
-
-/** The structure of the messages, divided to blocks */
-$wgMessageStructure = array(
- 'sidebar' => array(
- 'sidebar',
- ),
- 'toggles' => array(
- 'tog-underline',
- 'tog-justify',
- 'tog-hideminor',
- 'tog-hidepatrolled',
- 'tog-newpageshidepatrolled',
- 'tog-extendwatchlist',
- 'tog-usenewrc',
- 'tog-numberheadings',
- 'tog-showtoolbar',
- 'tog-editondblclick',
- 'tog-editsection',
- 'tog-editsectiononrightclick',
- 'tog-showtoc',
- 'tog-rememberpassword',
- 'tog-watchcreations',
- 'tog-watchdefault',
- 'tog-watchmoves',
- 'tog-watchdeletion',
- 'tog-minordefault',
- 'tog-previewontop',
- 'tog-previewonfirst',
- 'tog-nocache',
- 'tog-enotifwatchlistpages',
- 'tog-enotifusertalkpages',
- 'tog-enotifminoredits',
- 'tog-enotifrevealaddr',
- 'tog-shownumberswatching',
- 'tog-oldsig',
- 'tog-fancysig',
- 'tog-uselivepreview',
- 'tog-forceeditsummary',
- 'tog-watchlisthideown',
- 'tog-watchlisthidebots',
- 'tog-watchlisthideminor',
- 'tog-watchlisthideliu',
- 'tog-watchlisthideanons',
- 'tog-watchlisthidepatrolled',
- 'tog-ccmeonemails',
- 'tog-diffonly',
- 'tog-showhiddencats',
- 'tog-noconvertlink',
- 'tog-norollbackdiff',
- 'tog-useeditwarning',
- 'tog-prefershttps'
- ),
- 'underline' => array(
- 'underline-always',
- 'underline-never',
- 'underline-default',
- ),
- 'editfont' => array(
- 'editfont-style',
- 'editfont-default',
- 'editfont-monospace',
- 'editfont-sansserif',
- 'editfont-serif',
- ),
- 'dates' => array(
- 'sunday',
- 'monday',
- 'tuesday',
- 'wednesday',
- 'thursday',
- 'friday',
- 'saturday',
- 'sun',
- 'mon',
- 'tue',
- 'wed',
- 'thu',
- 'fri',
- 'sat',
- 'january',
- 'february',
- 'march',
- 'april',
- 'may_long',
- 'june',
- 'july',
- 'august',
- 'september',
- 'october',
- 'november',
- 'december',
- 'january-gen',
- 'february-gen',
- 'march-gen',
- 'april-gen',
- 'may-gen',
- 'june-gen',
- 'july-gen',
- 'august-gen',
- 'september-gen',
- 'october-gen',
- 'november-gen',
- 'december-gen',
- 'jan',
- 'feb',
- 'mar',
- 'apr',
- 'may',
- 'jun',
- 'jul',
- 'aug',
- 'sep',
- 'oct',
- 'nov',
- 'dec',
- 'january-date',
- 'february-date',
- 'march-date',
- 'april-date',
- 'may-date',
- 'june-date',
- 'july-date',
- 'august-date',
- 'september-date',
- 'october-date',
- 'november-date',
- 'december-date',
- ),
- 'categorypages' => array(
- 'pagecategories',
- 'pagecategorieslink',
- 'category_header',
- 'subcategories',
- 'category-media-header',
- 'category-empty',
- 'hidden-categories',
- 'hidden-category-category',
- 'category-subcat-count',
- 'category-subcat-count-limited',
- 'category-article-count',
- 'category-article-count-limited',
- 'category-file-count',
- 'category-file-count-limited',
- 'listingcontinuesabbrev',
- 'index-category',
- 'noindex-category',
- 'broken-file-category',
- 'categoryviewer-pagedlinks',
- ),
- 'mainpage' => array(
- 'linkprefix',
- ),
- 'miscellaneous1' => array(
- 'about',
- 'article',
- 'newwindow',
- 'cancel',
- 'moredotdotdot',
- 'morenotlisted',
- 'mypage',
- 'mytalk',
- 'anontalk',
- 'navigation',
- 'and',
- ),
- 'cologneblue' => array(
- 'qbfind',
- 'qbbrowse',
- 'qbedit',
- 'qbpageoptions',
- 'qbmyoptions',
- 'qbspecialpages',
- 'faq',
- 'faqpage',
- 'sitetitle',
- 'sitesubtitle',
- ),
- 'vector' => array(
- 'vector-action-addsection',
- 'vector-action-delete',
- 'vector-action-move',
- 'vector-action-protect',
- 'vector-action-undelete',
- 'vector-action-unprotect',
- 'vector-simplesearch-preference',
- 'vector-view-create',
- 'vector-view-edit',
- 'vector-view-history',
- 'vector-view-view',
- 'vector-view-viewsource',
- 'actions',
- 'namespaces',
- 'variants',
- ),
- 'miscellaneous2' => array(
- 'navigation-heading',
- 'errorpagetitle',
- 'returnto',
- 'tagline',
- 'help',
- 'search',
- 'searchbutton',
- 'go',
- 'searcharticle',
- 'history',
- 'history_short',
- 'updatedmarker',
- 'printableversion',
- 'permalink',
- 'print',
- 'view',
- 'edit',
- 'create',
- 'editthispage',
- 'create-this-page',
- 'delete',
- 'deletethispage',
- 'undeletethispage',
- 'undelete_short',
- 'viewdeleted_short',
- 'protect',
- 'protect_change',
- 'protectthispage',
- 'unprotect',
- 'unprotectthispage',
- 'newpage',
- 'talkpage',
- 'talkpagelinktext',
- 'specialpage',
- 'personaltools',
- 'postcomment',
- 'addsection',
- 'articlepage',
- 'talk',
- 'views',
- 'toolbox',
- 'userpage',
- 'projectpage',
- 'imagepage',
- 'mediawikipage',
- 'templatepage',
- 'viewhelppage',
- 'categorypage',
- 'viewtalkpage',
- 'otherlanguages',
- 'redirectedfrom',
- 'redirectpagesub',
- 'talkpageheader',
- 'lastmodifiedat',
- 'viewcount',
- 'protectedpage',
- 'jumpto',
- 'jumptonavigation',
- 'jumptosearch',
- 'view-pool-error',
- 'pool-timeout',
- 'pool-queuefull',
- 'pool-errorunknown',
- ),
- 'links' => array(
- 'aboutsite',
- 'aboutpage',
- 'copyright',
- 'copyrightpage',
- 'currentevents',
- 'currentevents-url',
- 'disclaimers',
- 'disclaimerpage',
- 'edithelp',
- 'edithelppage',
- 'help',
- 'helppage',
- 'mainpage',
- 'mainpage-description',
- 'policy-url',
- 'portal',
- 'portal-url',
- 'privacy',
- 'privacypage',
- ),
- 'badaccess' => array(
- 'badaccess',
- 'badaccess-group0',
- 'badaccess-groups',
- ),
- 'versionrequired' => array(
- 'versionrequired',
- 'versionrequiredtext',
- ),
- 'miscellaneous3' => array(
- 'ok',
- 'pagetitle',
- 'pagetitle-view-mainpage',
- 'backlinksubtitle',
- 'retrievedfrom',
- 'youhavenewmessages',
- 'newmessageslink',
- 'newmessagesdifflink',
- 'youhavenewmessagesfromusers',
- 'youhavenewmessagesmanyusers',
- 'newmessageslinkplural',
- 'newmessagesdifflinkplural',
- 'youhavenewmessagesmulti',
- 'newtalkseparator',
- 'editsection',
- 'editold',
- 'viewsourceold',
- 'editlink',
- 'viewsourcelink',
- 'editsectionhint',
- 'toc',
- 'showtoc',
- 'hidetoc',
- 'collapsible-collapse',
- 'collapsible-expand',
- 'thisisdeleted',
- 'viewdeleted',
- 'restorelink',
- 'feedlinks',
- 'feed-invalid',
- 'feed-unavailable',
- 'site-rss-feed',
- 'site-atom-feed',
- 'page-rss-feed',
- 'page-atom-feed',
- 'feed-atom',
- 'feed-rss',
- 'sitenotice',
- 'anonnotice',
- 'newsectionheaderdefaultlevel',
- 'red-link-title',
- 'sort-descending',
- 'sort-ascending',
-
- ),
- 'nstab' => array(
- 'nstab-main',
- 'nstab-user',
- 'nstab-media',
- 'nstab-special',
- 'nstab-project',
- 'nstab-image',
- 'nstab-mediawiki',
- 'nstab-template',
- 'nstab-help',
- 'nstab-category',
- 'mainpage-nstab',
- ),
- 'main' => array(
- 'nosuchaction',
- 'nosuchactiontext',
- 'nosuchspecialpage',
- 'nospecialpagetext',
- ),
- 'errors' => array(
- 'error',
- 'databaseerror',
- 'databaseerror-text',
- 'databaseerror-textcl',
- 'databaseerror-query',
- 'databaseerror-function',
- 'databaseerror-error',
- 'laggedslavemode',
- 'readonly',
- 'enterlockreason',
- 'readonlytext',
- 'missing-article', // not used anymore in core, but kept for extensions
- 'missingarticle-rev', // not used anymore in core, but kept for extensions
- 'missingarticle-diff', // not used anymore in core, but kept for extensions
- 'readonly_lag',
- 'internalerror',
- 'internalerror_info',
- 'fileappenderrorread',
- 'fileappenderror',
- 'filecopyerror',
- 'filerenameerror',
- 'filedeleteerror',
- 'directorycreateerror',
- 'filenotfound',
- 'fileexistserror',
- 'unexpected',
- 'formerror',
- 'badarticleerror',
- 'cannotdelete',
- 'cannotdelete-title',
- 'delete-hook-aborted',
- 'no-null-revision',
- 'badtitle',
- 'badtitletext',
- 'perfcached',
- 'perfcachedts',
- 'querypage-no-updates',
- 'wrong_wfQuery_params',
- 'viewsource',
- 'viewsource-title',
- 'actionthrottled',
- 'actionthrottledtext',
- 'protectedpagetext',
- 'viewsourcetext',
- 'viewyourtext',
- 'protectedinterface',
- 'editinginterface',
- 'cascadeprotected',
- 'namespaceprotected',
- 'customcssprotected',
- 'customjsprotected',
- 'mycustomcssprotected',
- 'mycustomjsprotected',
- 'myprivateinfoprotected',
- 'mypreferencesprotected',
- 'ns-specialprotected',
- 'titleprotected',
- 'filereadonlyerror',
- 'invalidtitle-knownnamespace',
- 'invalidtitle-unknownnamespace',
- 'exception-nologin',
- 'exception-nologin-text',
- ),
- 'virus' => array(
- 'virus-badscanner',
- 'virus-scanfailed',
- 'virus-unknownscanner',
- ),
- 'login' => array(
- 'logouttext',
- 'welcomeuser',
- 'welcomecreation-msg',
- 'yourname',
- 'userlogin-yourname',
- 'userlogin-yourname-ph',
- 'createacct-another-username-ph',
- 'createacct-helpusername',
- 'yourpassword',
- 'userlogin-yourpassword',
- 'userlogin-yourpassword-ph',
- 'createacct-yourpassword-ph',
- 'yourpasswordagain',
- 'createacct-yourpasswordagain',
- 'createacct-yourpasswordagain-ph',
- 'remembermypassword',
- 'userlogin-remembermypassword',
- 'userlogin-signwithsecure',
- 'yourdomainname',
- 'password-change-forbidden',
- 'externaldberror',
- 'login',
- 'nav-login-createaccount',
- 'loginprompt',
- 'userlogin',
- 'userloginnocreate',
- 'logout',
- 'userlogout',
- 'userlogout-summary',
- 'notloggedin',
- 'userlogin-noaccount',
- 'userlogin-joinproject',
- 'nologin',
- 'nologinlink',
- 'createaccount',
- 'gotaccount',
- 'gotaccountlink',
- 'userlogin-resetlink',
- 'userlogin-resetpassword-link',
- 'helplogin-url',
- 'userlogin-helplink2',
- 'userlogin-loggedin',
- 'userlogin-createanother',
- 'createacct-join',
- 'createacct-another-join',
- 'createacct-emailrequired',
- 'createacct-emailoptional',
- 'createacct-email-ph',
- 'createacct-another-email-ph',
- 'createaccountmail',
- 'createacct-realname',
- 'createaccountreason',
- 'createacct-reason',
- 'createacct-reason-ph',
- 'createacct-captcha',
- 'createacct-imgcaptcha-help',
- 'createacct-imgcaptcha-ph',
- 'createacct-submit',
- 'createacct-another-submit',
- 'createacct-benefit-heading',
- 'createacct-benefit-icon1',
- 'createacct-benefit-head1',
- 'createacct-benefit-body1',
- 'createacct-benefit-icon2',
- 'createacct-benefit-head2',
- 'createacct-benefit-body2',
- 'createacct-benefit-icon3',
- 'createacct-benefit-head3',
- 'createacct-benefit-body3',
- 'badretype',
- 'userexists',
- 'loginerror',
- 'createacct-error',
- 'createaccounterror',
- 'nocookiesnew',
- 'nocookieslogin',
- 'nocookiesfornew',
- 'nocookiesforlogin',
- 'noname',
- 'loginsuccesstitle',
- 'loginsuccess',
- 'nosuchuser',
- 'nosuchusershort',
- 'nouserspecified',
- 'login-userblocked',
- 'wrongpassword',
- 'wrongpasswordempty',
- 'passwordtooshort',
- 'password-name-match',
- 'password-login-forbidden',
- 'mailmypassword',
- 'passwordremindertitle',
- 'passwordremindertext',
- 'noemail',
- 'noemailcreate',
- 'passwordsent',
- 'blocked-mailpassword',
- 'eauthentsent',
- 'throttled-mailpassword',
- 'loginstart',
- 'loginend',
- 'loginend-https',
- 'signupstart',
- 'signupend',
- 'signupend-https',
- 'mailerror',
- 'acct_creation_throttle_hit',
- 'emailauthenticated',
- 'emailnotauthenticated',
- 'noemailprefs',
- 'emailconfirmlink',
- 'invalidemailaddress',
- 'cannotchangeemail',
- 'emaildisabled',
- 'accountcreated',
- 'accountcreatedtext',
- 'createaccount-title',
- 'createaccount-text',
- 'usernamehasherror',
- 'login-throttled',
- 'login-abort-generic',
- 'loginlanguagelabel',
- 'loginlanguagelinks',
- 'suspicious-userlogout',
- 'createacct-another-realname-tip',
- ),
- 'mail' => array(
- 'pear-mail-error',
- 'php-mail-error',
- 'php-mail-error-unknown',
- 'user-mail-no-addy',
- 'user-mail-no-body',
- ),
- 'resetpass' => array(
- 'resetpass',
- 'resetpass_announce',
- 'resetpass_text',
- 'resetpass_header',
- 'oldpassword',
- 'newpassword',
- 'retypenew',
- 'resetpass_submit',
- 'changepassword-success',
- 'resetpass_forbidden',
- 'resetpass-no-info',
- 'resetpass-submit-loggedin',
- 'resetpass-submit-cancel',
- 'resetpass-wrong-oldpass',
- 'resetpass-temp-password',
- 'resetpass-abort-generic',
- ),
- 'passwordreset' => array(
- 'passwordreset',
- 'passwordreset-text-one',
- 'passwordreset-text-many',
- 'passwordreset-legend',
- 'passwordreset-disabled',
- 'passwordreset-emaildisabled',
- 'passwordreset-username',
- 'passwordreset-domain',
- 'passwordreset-capture',
- 'passwordreset-capture-help',
- 'passwordreset-email',
- 'passwordreset-emailtitle',
- 'passwordreset-emailtext-ip',
- 'passwordreset-emailtext-user',
- 'passwordreset-emailelement',
- 'passwordreset-emailsent',
- 'passwordreset-emailsent-capture',
- 'passwordreset-emailerror-capture',
- ),
- 'changeemail' => array(
- 'changeemail',
- 'changeemail-summary',
- 'changeemail-header',
- 'changeemail-text',
- 'changeemail-no-info',
- 'changeemail-oldemail',
- 'changeemail-newemail',
- 'changeemail-none',
- 'changeemail-password',
- 'changeemail-submit',
- 'changeemail-cancel',
- ),
- 'resettokens' => array(
- 'resettokens',
- 'resettokens-summary',
- 'resettokens-text',
- 'resettokens-no-tokens',
- 'resettokens-legend',
- 'resettokens-tokens',
- 'resettokens-token-label',
- 'resettokens-watchlist-token',
- 'resettokens-done',
- 'resettokens-resetbutton',
- ),
- 'toolbar' => array(
- 'bold_sample',
- 'bold_tip',
- 'italic_sample',
- 'italic_tip',
- 'link_sample',
- 'link_tip',
- 'extlink_sample',
- 'extlink_tip',
- 'headline_sample',
- 'headline_tip',
- 'nowiki_sample',
- 'nowiki_tip',
- 'image_sample',
- 'image_tip',
- 'media_sample',
- 'media_tip',
- 'sig_tip',
- 'hr_tip',
- ),
- 'edit' => array(
- 'summary',
- 'subject',
- 'minoredit',
- 'watchthis',
- 'savearticle',
- 'preview',
- 'showpreview',
- 'showlivepreview',
- 'showdiff',
- 'anoneditwarning',
- 'anonpreviewwarning',
- 'missingsummary',
- 'missingcommenttext',
- 'missingcommentheader',
- 'summary-preview',
- 'subject-preview',
- 'blockedtitle',
- 'blockedtext',
- 'autoblockedtext',
- 'blockednoreason',
- 'whitelistedittext',
- 'confirmedittext',
- 'nosuchsectiontitle',
- 'nosuchsectiontext',
- 'loginreqtitle',
- 'loginreqlink',
- 'loginreqpagetext',
- 'accmailtitle',
- 'accmailtext',
- 'newarticle',
- 'newarticletext',
- 'newarticletextanon',
- 'talkpagetext',
- 'anontalkpagetext',
- 'noarticletext',
- 'noarticletext-nopermission',
- 'noarticletextanon',
- 'missing-revision',
- 'userpage-userdoesnotexist',
- 'userpage-userdoesnotexist-view',
- 'blocked-notice-logextract',
- 'clearyourcache',
- 'usercssyoucanpreview',
- 'userjsyoucanpreview',
- 'usercsspreview',
- 'userjspreview',
- 'sitecsspreview',
- 'sitejspreview',
- 'userinvalidcssjstitle',
- 'updated',
- 'note',
- 'previewnote',
- 'continue-editing',
- 'previewconflict',
- 'session_fail_preview',
- 'session_fail_preview_html',
- 'token_suffix_mismatch',
- 'edit_form_incomplete',
- 'editing',
- 'creating',
- 'editingsection',
- 'editingcomment',
- 'editconflict',
- 'explainconflict',
- 'yourtext',
- 'storedversion',
- 'nonunicodebrowser',
- 'editingold',
- 'yourdiff',
- 'copyrightwarning',
- 'copyrightwarning2',
- 'editpage-head-copy-warn',
- 'editpage-tos-summary',
- 'longpage-hint',
- 'longpageerror',
- 'readonlywarning',
- 'protectedpagewarning',
- 'semiprotectedpagewarning',
- 'cascadeprotectedwarning',
- 'titleprotectedwarning',
- 'templatesused',
- 'templatesusedpreview',
- 'templatesusedsection',
- 'template-protected',
- 'template-semiprotected',
- 'hiddencategories',
- 'edittools',
- 'edittools-upload',
- 'nocreatetext',
- 'nocreate-loggedin',
- 'sectioneditnotsupported-title',
- 'sectioneditnotsupported-text',
- 'permissionserrors',
- 'permissionserrorstext',
- 'permissionserrorstext-withaction',
- 'recreate-moveddeleted-warn',
- 'moveddeleted-notice',
- 'log-fulllog',
- 'edit-hook-aborted',
- 'edit-gone-missing',
- 'edit-conflict',
- 'edit-no-change',
- 'postedit-confirmation',
- 'edit-already-exists',
- 'addsection-preload',
- 'addsection-editintro',
- 'defaultmessagetext',
- 'content-failed-to-parse',
- 'invalid-content-data',
- 'content-not-allowed-here',
- 'editwarning-warning',
- ),
- 'contentmodels' => array(
- 'content-model-wikitext',
- 'content-model-text',
- 'content-model-javascript',
- 'content-model-css',
- ),
- 'parserwarnings' => array(
- 'expensive-parserfunction-warning',
- 'expensive-parserfunction-category',
- 'post-expand-template-inclusion-warning',
- 'post-expand-template-inclusion-category',
- 'post-expand-template-argument-warning',
- 'post-expand-template-argument-category',
- 'parser-template-loop-warning',
- 'parser-template-recursion-depth-warning',
- 'language-converter-depth-warning',
- 'node-count-exceeded-category',
- 'node-count-exceeded-warning',
- 'expansion-depth-exceeded-category',
- 'expansion-depth-exceeded-warning',
- 'parser-unstrip-loop-warning',
- 'parser-unstrip-recursion-limit',
- 'converter-manual-rule-error',
- ),
- 'undo' => array(
- 'undo-success',
- 'undo-failure',
- 'undo-norev',
- 'undo-summary',
- 'undo-summary-username-hidden',
- ),
- 'cantcreateaccount' => array(
- 'cantcreateaccounttitle',
- 'cantcreateaccount-text',
- ),
- 'history' => array(
- 'viewpagelogs',
- 'nohistory',
- 'currentrev',
- 'currentrev-asof',
- 'revisionasof',
- 'revision-info',
- 'revision-info-current',
- 'revision-nav',
- 'previousrevision',
- 'nextrevision',
- 'currentrevisionlink',
- 'cur',
- 'next',
- 'last',
- 'page_first',
- 'page_last',
- 'histlegend',
- 'history-fieldset-title',
- 'history-show-deleted',
- 'history_copyright',
- 'histfirst',
- 'histlast',
- 'historysize',
- 'historyempty',
- ),
- 'history-feed' => array(
- 'history-feed-title',
- 'history-feed-description',
- 'history-feed-item-nocomment',
- 'history-feed-empty',
- ),
- 'revdelete' => array(
- 'rev-deleted-comment',
- 'rev-deleted-user',
- 'rev-deleted-event',
- 'rev-deleted-user-contribs',
- 'rev-deleted-text-permission',
- 'rev-deleted-text-unhide',
- 'rev-suppressed-text-unhide',
- 'rev-deleted-text-view',
- 'rev-suppressed-text-view',
- 'rev-deleted-no-diff',
- 'rev-suppressed-no-diff',
- 'rev-deleted-unhide-diff',
- 'rev-suppressed-unhide-diff',
- 'rev-deleted-diff-view',
- 'rev-suppressed-diff-view',
- 'rev-delundel',
- 'rev-showdeleted',
- 'revisiondelete',
- 'revdelete-nooldid-title',
- 'revdelete-nooldid-text',
- 'revdelete-nologtype-title',
- 'revdelete-nologtype-text',
- 'revdelete-nologid-title',
- 'revdelete-nologid-text',
- 'revdelete-no-file',
- 'revdelete-show-file-confirm',
- 'revdelete-show-file-submit',
- 'revdelete-selected',
- 'logdelete-selected',
- 'revdelete-text',
- 'revdelete-confirm',
- 'revdelete-suppress-text',
- 'revdelete-legend',
- 'revdelete-hide-text',
- 'revdelete-hide-image',
- 'revdelete-hide-name',
- 'revdelete-hide-comment',
- 'revdelete-hide-user',
- 'revdelete-hide-restricted',
- 'revdelete-radio-same',
- 'revdelete-radio-set',
- 'revdelete-radio-unset',
- 'revdelete-suppress',
- 'revdelete-unsuppress',
- 'revdelete-log',
- 'revdelete-submit',
- 'revdelete-success',
- 'revdelete-failure',
- 'logdelete-success',
- 'logdelete-failure',
- 'revdel-restore',
- 'revdel-restore-deleted',
- 'revdel-restore-visible',
- 'pagehist',
- 'deletedhist',
- 'revdelete-hide-current',
- 'revdelete-show-no-access',
- 'revdelete-modify-no-access',
- 'revdelete-modify-missing',
- 'revdelete-no-change',
- 'revdelete-concurrent-change',
- 'revdelete-only-restricted',
- 'revdelete-reason-dropdown',
- 'revdelete-otherreason',
- 'revdelete-reasonotherlist',
- 'revdelete-edit-reasonlist',
- 'revdelete-offender',
- ),
- 'suppression' => array(
- 'suppressionlog',
- 'suppressionlogtext',
- ),
- 'mergehistory' => array(
- 'mergehistory',
- 'mergehistory-header',
- 'mergehistory-box',
- 'mergehistory-from',
- 'mergehistory-into',
- 'mergehistory-list',
- 'mergehistory-merge',
- 'mergehistory-go',
- 'mergehistory-submit',
- 'mergehistory-empty',
- 'mergehistory-success',
- 'mergehistory-fail',
- 'mergehistory-no-source',
- 'mergehistory-no-destination',
- 'mergehistory-invalid-source',
- 'mergehistory-invalid-destination',
- 'mergehistory-autocomment',
- 'mergehistory-comment',
- 'mergehistory-same-destination',
- 'mergehistory-reason',
- 'mergehistory-revisionrow'
- ),
- 'mergelog' => array(
- 'mergelog',
- 'pagemerge-logentry',
- 'revertmerge',
- 'mergelogpagetext',
- ),
- 'diffs' => array(
- 'history-title',
- 'difference-title',
- 'difference-title-multipage',
- 'difference-multipage',
- 'lineno',
- 'compareselectedversions',
- 'showhideselectedversions',
- 'editundo',
- 'diff-empty',
- 'diff-multi',
- 'diff-multi-manyusers',
- 'difference-missing-revision',
- ),
- 'search' => array(
- 'search-summary',
- 'searchresults',
- 'searchresults-title',
- 'searchresulttext',
- 'searchsubtitle',
- 'searchsubtitleinvalid',
- 'toomanymatches',
- 'titlematches',
- 'notitlematches',
- 'textmatches',
- 'notextmatches',
- 'prevn',
- 'nextn',
- 'prevn-title',
- 'nextn-title',
- 'shown-title',
- 'viewprevnext',
- 'searchmenu-legend',
- 'searchmenu-exists',
- 'searchmenu-new',
- 'searchmenu-new-nocreate',
- 'searchmenu-prefix',
- 'searchprofile-articles',
- 'searchprofile-project',
- 'searchprofile-images',
- 'searchprofile-everything',
- 'searchprofile-advanced',
- 'searchprofile-articles-tooltip',
- 'searchprofile-project-tooltip',
- 'searchprofile-images-tooltip',
- 'searchprofile-everything-tooltip',
- 'searchprofile-advanced-tooltip',
- 'search-result-size',
- 'search-result-category-size',
- 'search-result-score',
- 'search-redirect',
- 'search-section',
- 'search-suggest',
- 'search-interwiki-caption',
- 'search-interwiki-default',
- 'search-interwiki-custom',
- 'search-interwiki-more',
- 'search-relatedarticle',
- 'mwsuggest-disable',
- 'searcheverything-enable',
- 'searchrelated',
- 'searchall',
- 'showingresults',
- 'showingresultsnum',
- 'showingresultsheader',
- 'nonefound',
- 'search-nonefound',
- 'powersearch',
- 'powersearch-legend',
- 'powersearch-ns',
- 'powersearch-redir',
- 'powersearch-field',
- 'powersearch-togglelabel',
- 'powersearch-toggleall',
- 'powersearch-togglenone',
- 'search-external',
- 'searchdisabled',
- 'googlesearch',
- 'search-error',
- ),
- 'opensearch' => array(
- 'opensearch-desc',
- ),
- 'preferences' => array(
- 'preferences',
- 'preferences-summary',
- 'mypreferences',
- 'prefs-edits',
- 'prefsnologin',
- 'prefsnologintext',
- 'changepassword',
- 'changepassword-summary',
- 'prefs-skin',
- 'skin-preview',
- 'datedefault',
- 'prefs-beta',
- 'prefs-datetime',
- 'prefs-labs',
- 'prefs-user-pages',
- 'prefs-personal',
- 'prefs-rc',
- 'prefs-watchlist',
- 'prefs-watchlist-days',
- 'prefs-watchlist-days-max',
- 'prefs-watchlist-edits',
- 'prefs-watchlist-edits-max',
- 'prefs-watchlist-token',
- 'prefs-misc', // continue checking if used from here on (r49916)
- 'prefs-resetpass',
- 'prefs-changeemail',
- 'prefs-setemail',
- 'prefs-email',
- 'prefs-rendering',
- 'saveprefs',
- 'resetprefs',
- 'restoreprefs',
- 'prefs-editing',
- 'rows',
- 'columns',
- 'searchresultshead',
- 'resultsperpage',
- 'stub-threshold',
- 'stub-threshold-disabled',
- 'recentchangesdays',
- 'recentchangesdays-max',
- 'recentchangescount',
- 'prefs-help-recentchangescount',
- 'prefs-help-watchlist-token2',
- 'savedprefs',
- 'timezonelegend',
- 'localtime',
- 'timezoneuseserverdefault',
- 'timezoneuseoffset',
- 'timezoneoffset',
- 'servertime',
- 'guesstimezone',
- 'timezoneregion-africa',
- 'timezoneregion-america',
- 'timezoneregion-antarctica',
- 'timezoneregion-arctic',
- 'timezoneregion-asia',
- 'timezoneregion-atlantic',
- 'timezoneregion-australia',
- 'timezoneregion-europe',
- 'timezoneregion-indian',
- 'timezoneregion-pacific',
- 'allowemail',
- 'prefs-searchoptions',
- 'prefs-namespaces',
- 'defaultns',
- 'default',
- 'defaultns',
- 'prefs-files',
- 'prefs-custom-css',
- 'prefs-custom-js',
- 'prefs-common-css-js',
- 'prefs-reset-intro',
- 'prefs-emailconfirm-label',
- 'youremail',
- 'username',
- 'uid',
- 'prefs-memberingroups',
- 'prefs-memberingroups-type',
- 'prefs-registration',
- 'prefs-registration-date-time',
- 'yourrealname',
- 'yourlanguage',
- 'yourvariant',
- 'prefs-help-variant',
- 'yournick',
- 'prefs-help-signature',
- 'badsig',
- 'badsiglength',
- 'yourgender',
- 'gender-unknown',
- 'gender-male',
- 'gender-female',
- 'prefs-help-gender',
- 'email',
- 'prefs-help-realname',
-
- # 3 messages depending upon $wgEmailConfirmToEdit and $wgEnableUserEmail
- 'prefs-help-email',
- 'prefs-help-email-others',
- 'prefs-help-email-required',
-
- 'prefs-info',
- 'prefs-i18n',
- 'prefs-signature',
- 'prefs-dateformat',
- 'prefs-timeoffset',
- 'prefs-advancedediting',
- 'prefs-editor',
- 'prefs-preview',
- 'prefs-advancedrc',
- 'prefs-advancedrendering',
- 'prefs-advancedsearchoptions',
- 'prefs-advancedwatchlist',
- 'prefs-displayrc',
- 'prefs-displaysearchoptions',
- 'prefs-displaywatchlist',
- 'prefs-tokenwatchlist',
- 'prefs-diffs',
- 'prefs-help-prefershttps',
- ),
- 'preferences-email' => array(
- 'email-address-validity-valid',
- 'email-address-validity-invalid',
- ),
- 'userrights' => array(
- 'userrights',
- 'userrights-summary',
- 'userrights-lookup-user',
- 'userrights-user-editname',
- 'editusergroup',
- 'editinguser',
- 'userrights-editusergroup',
- 'saveusergroups',
- 'userrights-groupsmember',
- 'userrights-groupsmember-auto',
- 'userrights-groupsmember-type',
- 'userrights-groups-help',
- 'userrights-reason',
- 'userrights-no-interwiki',
- 'userrights-nodatabase',
- 'userrights-nologin',
- 'userrights-notallowed',
- 'userrights-changeable-col',
- 'userrights-unchangeable-col',
- 'userrights-irreversible-marker',
- 'userrights-conflict',
- 'userrights-removed-self',
- ),
- 'group' => array(
- 'group',
- 'group-user',
- 'group-autoconfirmed',
- 'group-bot',
- 'group-sysop',
- 'group-bureaucrat',
- 'group-suppress',
- 'group-all',
- ),
- 'group-member' => array(
- 'group-user-member',
- 'group-autoconfirmed-member',
- 'group-bot-member',
- 'group-sysop-member',
- 'group-bureaucrat-member',
- 'group-suppress-member',
- ),
- 'grouppage' => array(
- 'grouppage-user',
- 'grouppage-autoconfirmed',
- 'grouppage-bot',
- 'grouppage-sysop',
- 'grouppage-bureaucrat',
- 'grouppage-suppress',
- ),
- 'right' => array(
- 'right-read',
- 'right-edit',
- 'right-createpage',
- 'right-createtalk',
- 'right-createaccount',
- 'right-minoredit',
- 'right-move',
- 'right-move-subpages',
- 'right-move-rootuserpages',
- 'right-movefile',
- 'right-suppressredirect',
- 'right-upload',
- 'right-reupload',
- 'right-reupload-own',
- 'right-reupload-shared',
- 'right-upload_by_url',
- 'right-purge',
- 'right-autoconfirmed',
- 'right-bot',
- 'right-nominornewtalk',
- 'right-apihighlimits',
- 'right-writeapi',
- 'right-delete',
- 'right-bigdelete',
- 'right-deletelogentry',
- 'right-deleterevision',
- 'right-deletedhistory',
- 'right-deletedtext',
- 'right-browsearchive',
- 'right-undelete',
- 'right-suppressrevision',
- 'right-suppressionlog',
- 'right-block',
- 'right-blockemail',
- 'right-hideuser',
- 'right-ipblock-exempt',
- 'right-proxyunbannable',
- 'right-unblockself',
- 'right-protect',
- 'right-editprotected',
- 'right-editsemiprotected',
- 'right-editinterface',
- 'right-editusercssjs',
- 'right-editusercss',
- 'right-edituserjs',
- 'right-editmyusercss',
- 'right-editmyuserjs',
- 'right-viewmywatchlist',
- 'right-editmywatchlist',
- 'right-viewmyprivateinfo',
- 'right-editmyprivateinfo',
- 'right-editmyoptions',
- 'right-rollback',
- 'right-markbotedits',
- 'right-noratelimit',
- 'right-import',
- 'right-importupload',
- 'right-patrol',
- 'right-autopatrol',
- 'right-patrolmarks',
- 'right-unwatchedpages',
- 'right-mergehistory',
- 'right-userrights',
- 'right-userrights-interwiki',
- 'right-siteadmin',
- 'right-override-export-depth',
- 'right-sendemail',
- 'right-passwordreset',
- ),
- 'newuserlog' => array(
- 'newuserlogpage',
- 'newuserlogpagetext',
- ),
- 'rightslog' => array(
- 'rightslog',
- 'rightslogtext',
- ),
- 'action' => array(
- 'action-read',
- 'action-edit',
- 'action-createpage',
- 'action-createtalk',
- 'action-createaccount',
- 'action-minoredit',
- 'action-move',
- 'action-move-subpages',
- 'action-move-rootuserpages',
- 'action-movefile',
- 'action-upload',
- 'action-reupload',
- 'action-reupload-shared',
- 'action-upload_by_url',
- 'action-writeapi',
- 'action-delete',
- 'action-deleterevision',
- 'action-deletedhistory',
- 'action-browsearchive',
- 'action-undelete',
- 'action-suppressrevision',
- 'action-suppressionlog',
- 'action-block',
- 'action-protect',
- 'action-rollback',
- 'action-import',
- 'action-importupload',
- 'action-patrol',
- 'action-autopatrol',
- 'action-unwatchedpages',
- 'action-mergehistory',
- 'action-userrights',
- 'action-userrights-interwiki',
- 'action-siteadmin',
- 'action-sendemail',
- 'action-editmywatchlist',
- 'action-viewmywatchlist',
- 'action-viewmyprivateinfo',
- 'action-editmyprivateinfo',
- ),
- 'recentchanges' => array(
- 'nchanges',
- 'enhancedrc-since-last-visit',
- 'enhancedrc-history',
- 'recentchanges',
- 'recentchanges-url',
- 'recentchanges-legend',
- 'recentchanges-summary',
- 'recentchangestext',
- 'recentchanges-noresult',
- 'recentchanges-feed-description',
- 'recentchanges-label-newpage',
- 'recentchanges-label-minor',
- 'recentchanges-label-bot',
- 'recentchanges-label-unpatrolled',
- 'rcnote',
- 'rcnotefrom',
- 'rclistfrom',
- 'rcshowhideminor',
- 'rcshowhidebots',
- 'rcshowhideliu',
- 'rcshowhideanons',
- 'rcshowhidepatr',
- 'rcshowhidemine',
- 'rclinks',
- 'diff',
- 'hist',
- 'hide',
- 'show',
- 'minoreditletter',
- 'newpageletter',
- 'boteditletter',
- 'unpatrolledletter',
- 'number_of_watching_users_RCview',
- 'number_of_watching_users_pageview',
- 'rc_categories',
- 'rc_categories_any',
- 'rc-change-size',
- 'rc-change-size-new',
- 'newsectionsummary',
- 'rc-enhanced-expand',
- 'rc-enhanced-hide',
- 'rc-old-title',
- ),
- 'recentchangeslinked' => array(
- 'recentchangeslinked',
- 'recentchangeslinked-feed',
- 'recentchangeslinked-toolbox',
- 'recentchangeslinked-title',
- 'recentchangeslinked-summary',
- 'recentchangeslinked-page',
- 'recentchangeslinked-to',
- ),
- 'upload' => array(
- 'upload',
- 'uploadbtn',
- 'reuploaddesc',
- 'upload-tryagain',
- 'uploadnologin',
- 'uploadnologintext',
- 'upload_directory_missing',
- 'upload_directory_read_only',
- 'uploaderror',
- 'upload-summary',
- 'upload-recreate-warning',
- 'uploadtext',
- 'upload-permitted',
- 'upload-preferred',
- 'upload-prohibited',
- 'uploadfooter',
- 'upload-default-description',
- 'uploadlog',
- 'uploadlogpage',
- 'uploadlogpagetext',
- 'filename',
- 'filedesc',
- 'fileuploadsummary',
- 'filereuploadsummary',
- 'filestatus',
- 'filesource',
- 'uploadedfiles',
- 'ignorewarning',
- 'ignorewarnings',
- 'minlength1',
- 'illegalfilename',
- 'filename-toolong',
- 'badfilename',
- 'filetype-mime-mismatch',
- 'filetype-badmime',
- 'filetype-bad-ie-mime',
- 'filetype-unwanted-type',
- 'filetype-banned-type',
- 'filetype-missing',
- 'empty-file',
- 'file-too-large',
- 'filename-tooshort',
- 'filetype-banned',
- 'verification-error',
- 'hookaborted',
- 'illegal-filename',
- 'overwrite',
- 'unknown-error',
- 'tmp-create-error',
- 'tmp-write-error',
- 'large-file',
- 'largefileserver',
- 'emptyfile',
- 'windows-nonascii-filename',
- 'fileexists',
- 'filepageexists',
- 'fileexists-extension',
- 'fileexists-thumbnail-yes',
- 'file-thumbnail-no',
- 'fileexists-forbidden',
- 'fileexists-shared-forbidden',
- 'file-exists-duplicate',
- 'file-deleted-duplicate',
- 'uploadwarning',
- 'uploadwarning-text',
- 'savefile',
- 'uploadedimage',
- 'overwroteimage',
- 'uploaddisabled',
- 'copyuploaddisabled',
- 'uploadfromurl-queued',
- 'uploaddisabledtext',
- 'php-uploaddisabledtext',
- 'uploadscripted',
- 'uploadvirus',
- 'uploadjava',
- 'upload-source',
- 'sourcefilename',
- 'sourceurl',
- 'destfilename',
- 'upload-maxfilesize',
- 'upload-description',
- 'upload-options',
- 'watchthisupload',
- 'filewasdeleted',
- 'filename-bad-prefix',
- 'filename-prefix-blacklist',
- 'upload-success-subj',
- 'upload-success-msg',
- 'upload-failure-subj',
- 'upload-failure-msg',
- 'upload-warning-subj',
- 'upload-warning-msg',
- ),
- 'upload-errors' => array(
- 'upload-proto-error',
- 'upload-proto-error-text',
- 'upload-file-error',
- 'upload-file-error-text',
- 'upload-misc-error',
- 'upload-misc-error-text',
- 'upload-too-many-redirects',
- 'upload-unknown-size',
- 'upload-http-error',
- 'upload-copy-upload-invalid-domain',
- ),
-
- 'filebackend-errors' => array(
- 'backend-fail-stream',
- 'backend-fail-backup',
- 'backend-fail-notexists',
- 'backend-fail-hashes',
- 'backend-fail-notsame',
- 'backend-fail-invalidpath',
- 'backend-fail-delete',
- 'backend-fail-describe',
- 'backend-fail-alreadyexists',
- 'backend-fail-store',
- 'backend-fail-copy',
- 'backend-fail-move',
- 'backend-fail-opentemp',
- 'backend-fail-writetemp',
- 'backend-fail-closetemp',
- 'backend-fail-read',
- 'backend-fail-create',
- 'backend-fail-maxsize',
- 'backend-fail-readonly',
- 'backend-fail-synced',
- 'backend-fail-connect',
- 'backend-fail-internal',
- 'backend-fail-contenttype',
- 'backend-fail-batchsize',
- 'backend-fail-usable'
- ),
-
- 'filejournal-errors' => array(
- 'filejournal-fail-dbconnect',
- 'filejournal-fail-dbquery'
- ),
-
- 'lockmanager-errors' => array(
- 'lockmanager-notlocked',
- 'lockmanager-fail-closelock',
- 'lockmanager-fail-deletelock',
- 'lockmanager-fail-acquirelock',
- 'lockmanager-fail-openlock',
- 'lockmanager-fail-acquirelock',
- 'lockmanager-fail-releaselock',
- 'lockmanager-fail-db-bucket',
- 'lockmanager-fail-db-release',
- 'lockmanager-fail-svr-acquire',
- 'lockmanager-fail-svr-release'
- ),
-
- 'zip' => array(
- 'zip-file-open-error',
- 'zip-wrong-format',
- 'zip-bad',
- 'zip-unsupported'
- ),
-
- 'uploadstash' => array(
- 'uploadstash',
- 'uploadstash-summary',
- 'uploadstash-clear',
- 'uploadstash-nofiles',
- 'uploadstash-badtoken',
- 'uploadstash-errclear',
- 'uploadstash-refresh',
- 'invalid-chunk-offset',
- ),
-
- 'img-auth' => array(
- 'img-auth-accessdenied',
- 'img-auth-desc',
- 'img-auth-nopathinfo',
- 'img-auth-notindir',
- 'img-auth-badtitle',
- 'img-auth-nologinnWL',
- 'img-auth-nofile',
- 'img-auth-isdir',
- 'img-auth-streaming',
- 'img-auth-public',
- 'img-auth-noread',
- 'img-auth-bad-query-string',
- ),
-
- 'http-errors' => array(
- 'http-invalid-url',
- 'http-invalid-scheme',
- 'http-request-error',
- 'http-read-error',
- 'http-timed-out',
- 'http-curl-error',
- 'http-bad-status',
- ),
-
- 'upload-curl-errors' => array(
- 'upload-curl-error6',
- 'upload-curl-error6-text',
- 'upload-curl-error28',
- 'upload-curl-error28-text',
- ),
- 'licenses' => array(
- 'license',
- 'license-header',
- 'nolicense',
- 'licenses',
- 'license-nopreview',
- 'upload_source_url',
- 'upload_source_file',
- ),
- 'filelist' => array(
- 'listfiles-summary',
- 'listfiles_search_for',
- 'imgfile',
- 'listfiles',
- 'listfiles_thumb',
- 'listfiles_date',
- 'listfiles_name',
- 'listfiles_user',
- 'listfiles_size',
- 'listfiles_description',
- 'listfiles_count',
- 'listfiles-show-all',
- 'listfiles-latestversion',
- 'listfiles-latestversion-yes',
- 'listfiles-latestversion-no',
- ),
- 'filedescription' => array(
- 'file-anchor-link',
- 'filehist',
- 'filehist-help',
- 'filehist-deleteall',
- 'filehist-deleteone',
- 'filehist-revert',
- 'filehist-current',
- 'filehist-datetime',
- 'filehist-thumb',
- 'filehist-thumbtext',
- 'filehist-nothumb',
- 'filehist-user',
- 'filehist-dimensions',
- 'filehist-filesize',
- 'filehist-comment',
- 'filehist-missing',
- 'imagelinks',
- 'linkstoimage',
- 'linkstoimage-more',
- 'nolinkstoimage',
- 'morelinkstoimage',
- 'linkstoimage-redirect',
- 'duplicatesoffile',
- 'sharedupload',
- 'sharedupload-desc-there',
- 'sharedupload-desc-here',
- 'sharedupload-desc-edit',
- 'sharedupload-desc-create',
- 'shareddescriptionfollows',
- 'filepage-nofile',
- 'filepage-nofile-link',
- 'uploadnewversion-linktext',
- 'shared-repo-from',
- 'shared-repo',
- 'shared-repo-name-wikimediacommons',
- 'filepage.css',
- 'upload-disallowed-here',
- ),
- 'filerevert' => array(
- 'filerevert',
- 'filerevert-legend',
- 'filerevert-intro',
- 'filerevert-comment',
- 'filerevert-defaultcomment',
- 'filerevert-submit',
- 'filerevert-success',
- 'filerevert-badversion',
- ),
- 'filedelete' => array(
- 'filedelete',
- 'filedelete-legend',
- 'filedelete-intro',
- 'filedelete-intro-old',
- 'filedelete-comment',
- 'filedelete-submit',
- 'filedelete-success',
- 'filedelete-success-old',
- 'filedelete-nofile',
- 'filedelete-nofile-old',
- 'filedelete-otherreason',
- 'filedelete-reason-otherlist',
- 'filedelete-reason-dropdown',
- 'filedelete-edit-reasonlist',
- 'filedelete-maintenance',
- 'filedelete-maintenance-title',
- ),
- 'mimesearch' => array(
- 'mimesearch',
- 'mimesearch-summary',
- 'mimetype',
- 'download',
- ),
- 'unwatchedpages' => array(
- 'unwatchedpages',
- 'unwatchedpages-summary',
- ),
- 'listredirects' => array(
- 'listredirects',
- 'listredirects-summary',
- ),
- 'unusedtemplates' => array(
- 'unusedtemplates',
- 'unusedtemplates-summary',
- 'unusedtemplatestext',
- 'unusedtemplateswlh',
- ),
- 'randompage' => array(
- 'randompage',
- 'randompage-nopages',
- 'randompage-url',
- ),
- 'randomincategory' => array(
- 'randomincategory',
- 'randomincategory-invalidcategory',
- 'randomincategory-nopages',
- 'randomincategory-selectcategory',
- 'randomincategory-selectcategory-submit',
- ),
- 'randomredirect' => array(
- 'randomredirect',
- 'randomredirect-nopages',
- ),
- 'statistics' => array(
- 'statistics',
- 'statistics-summary',
- 'statistics-header-pages',
- 'statistics-header-edits',
- 'statistics-header-views',
- 'statistics-header-users',
- 'statistics-header-hooks',
- 'statistics-articles',
- 'statistics-pages',
- 'statistics-pages-desc',
- 'statistics-files',
- 'statistics-edits',
- 'statistics-edits-average',
- 'statistics-views-total',
- 'statistics-views-total-desc',
- 'statistics-views-peredit',
- 'statistics-users',
- 'statistics-users-active',
- 'statistics-users-active-desc',
- 'statistics-mostpopular',
- 'statistics-footer',
- ),
- 'pageswithprop' => array(
- 'pageswithprop',
- 'pageswithprop-summary',
- 'pageswithprop-legend',
- 'pageswithprop-text',
- 'pageswithprop-prop',
- 'pageswithprop-submit',
- 'pageswithprop-prophidden-long',
- 'pageswithprop-prophidden-binary',
- ),
- 'doubleredirects' => array(
- 'doubleredirects',
- 'doubleredirects-summary',
- 'doubleredirectstext',
- 'double-redirect-fixed-move',
- 'double-redirect-fixed-maintenance',
- 'double-redirect-fixer',
- ),
- 'brokenredirects' => array(
- 'brokenredirects',
- 'brokenredirects-summary',
- 'brokenredirectstext',
- 'brokenredirects-edit',
- 'brokenredirects-delete',
- ),
- 'withoutinterwiki' => array(
- 'withoutinterwiki',
- 'withoutinterwiki-summary',
- 'withoutinterwiki-legend',
- 'withoutinterwiki-submit',
- ),
- 'fewestrevisions' => array(
- 'fewestrevisions',
- 'fewestrevisions-summary',
- ),
- 'specialpages' => array(
- 'nbytes',
- 'ncategories',
- 'ninterwikis',
- 'nlinks',
- 'nmembers',
- 'nrevisions',
- 'nviews',
- 'nchanges',
- 'nimagelinks',
- 'ntransclusions',
- 'specialpage-empty',
- 'lonelypages',
- 'lonelypages-summary',
- 'lonelypagestext',
- 'uncategorizedpages',
- 'uncategorizedpages-summary',
- 'uncategorizedcategories',
- 'uncategorizedcategories-summary',
- 'uncategorizedimages',
- 'uncategorizedimages-summary',
- 'uncategorizedtemplates',
- 'uncategorizedtemplates-summary',
- 'unusedcategories',
- 'unusedcategories-summary',
- 'unusedimages',
- 'unusedimages-summary',
- 'popularpages',
- 'popularpages-summary',
- 'wantedcategories',
- 'wantedcategories-summary',
- 'wantedpages',
- 'wantedpages-summary',
- 'wantedpages-badtitle',
- 'wantedfiles',
- 'wantedfiles-summary',
- 'wantedfiletext-cat',
- 'wantedfiletext-nocat',
- 'wantedtemplates',
- 'wantedtemplates-summary',
- 'mostlinked',
- 'mostlinked-summary',
- 'mostlinkedcategories',
- 'mostlinkedcategories-summary',
- 'mostlinkedtemplates',
- 'mostlinkedtemplates-summary',
- 'mostcategories',
- 'mostcategories-summary',
- 'mostimages',
- 'mostimages-summary',
- 'mostinterwikis',
- 'mostinterwikis-summary',
- 'mostrevisions',
- 'mostrevisions-summary',
- 'prefixindex',
- 'prefixindex-namespace',
- 'prefixindex-summary',
- 'prefixindex-strip',
- 'shortpages',
- 'shortpages-summary',
- 'longpages',
- 'longpages-summary',
- 'deadendpages',
- 'deadendpages-summary',
- 'deadendpagestext',
- 'protectedpages',
- 'protectedpages-indef',
- 'protectedpages-summary',
- 'protectedpages-cascade',
- 'protectedpagestext',
- 'protectedpagesempty',
- 'protectedtitles',
- 'protectedtitles-summary',
- 'protectedtitlestext',
- 'protectedtitlesempty',
- 'listusers',
- 'listusers-summary',
- 'listusers-editsonly',
- 'listusers-creationsort',
- 'listusers-desc',
- 'usereditcount',
- 'usercreated',
- 'newpages',
- 'newpages-summary',
- 'newpages-username',
- 'ancientpages',
- 'ancientpages-summary',
- 'move',
- 'movethispage',
- 'unusedimagestext',
- 'unusedcategoriestext',
- 'notargettitle',
- 'notargettext',
- 'nopagetitle',
- 'nopagetext',
- 'pager-newer-n',
- 'pager-older-n',
- 'suppress',
- 'querypage-disabled',
- ),
- 'booksources' => array(
- 'booksources',
- 'booksources-summary',
- 'booksources-search-legend',
- 'booksources-isbn',
- 'booksources-go',
- 'booksources-text',
- 'booksources-invalid-isbn',
- ),
- 'magicwords' => array(
- 'rfcurl',
- 'pubmedurl',
- ),
- 'logpages' => array(
- 'specialloguserlabel',
- 'speciallogtitlelabel',
- 'log',
- 'all-logs-page',
- 'alllogstext',
- 'logempty',
- 'log-title-wildcard',
- 'showhideselectedlogentries',
- ),
- 'allpages' => array(
- 'allpages',
- 'allpages-summary',
- 'alphaindexline',
- 'nextpage',
- 'prevpage',
- 'allpagesfrom',
- 'allpagesto',
- 'allarticles',
- 'allinnamespace',
- 'allnotinnamespace',
- 'allpagesprev',
- 'allpagesnext',
- 'allpagessubmit',
- 'allpagesprefix',
- 'allpagesbadtitle',
- 'allpages-bad-ns',
- 'allpages-hide-redirects',
- ),
- 'cachedspecial' => array(
- 'cachedspecial-viewing-cached-ttl',
- 'cachedspecial-viewing-cached-ts',
- 'cachedspecial-refresh-now',
- ),
- 'categories' => array(
- 'categories',
- 'categories-summary',
- 'categoriespagetext',
- 'categoriesfrom',
- 'special-categories-sort-count',
- 'special-categories-sort-abc',
- ),
- 'deletedcontribs' => array(
- 'deletedcontributions',
- 'deletedcontributions-summary',
- 'deletedcontributions-title',
- 'sp-deletedcontributions-contribs',
- ),
- 'linksearch' => array(
- 'linksearch',
- 'linksearch-summary',
- 'linksearch-pat',
- 'linksearch-ns',
- 'linksearch-ok',
- 'linksearch-text',
- 'linksearch-line',
- 'linksearch-error',
- ),
- 'listusers' => array(
- 'listusersfrom',
- 'listusers-submit',
- 'listusers-noresult',
- 'listusers-blocked',
- ),
- 'activeusers' => array(
- 'activeusers',
- 'activeusers-summary',
- 'activeusers-intro',
- 'activeusers-count',
- 'activeusers-from',
- 'activeusers-hidebots',
- 'activeusers-hidesysops',
- 'activeusers-submit',
- 'activeusers-noresult',
- ),
- 'listgrouprights' => array(
- 'listgrouprights',
- 'listgrouprights-summary',
- 'listgrouprights-key',
- 'listgrouprights-group',
- 'listgrouprights-rights',
- 'listgrouprights-helppage',
- 'listgrouprights-members',
- 'listgrouprights-right-display',
- 'listgrouprights-right-revoked',
- 'listgrouprights-addgroup',
- 'listgrouprights-removegroup',
- 'listgrouprights-addgroup-all',
- 'listgrouprights-removegroup-all',
- 'listgrouprights-addgroup-self',
- 'listgrouprights-removegroup-self',
- 'listgrouprights-addgroup-self-all',
- 'listgrouprights-removegroup-self-all',
-
- ),
- 'emailuser' => array(
- 'mailnologin',
- 'mailnologintext',
- 'emailuser',
- 'emailuser-title-target',
- 'emailuser-title-notarget',
- 'emailuser-summary',
- 'emailpage',
- 'emailpagetext',
- 'usermailererror',
- 'defemailsubject',
- 'usermaildisabled',
- 'usermaildisabledtext',
- 'noemailtitle',
- 'noemailtext',
- 'nowikiemailtitle',
- 'nowikiemailtext',
- 'emailnotarget',
- 'emailtarget',
- 'emailusername',
- 'emailusernamesubmit',
- 'email-legend',
- 'emailfrom',
- 'emailto',
- 'emailsubject',
- 'emailmessage',
- 'emailsend',
- 'emailccme',
- 'emailccsubject',
- 'emailsent',
- 'emailsenttext',
- 'emailuserfooter',
- ),
- 'usermessage' => array(
- 'usermessage-summary',
- 'usermessage-editor',
- 'usermessage-template',
- ),
- 'watchlist' => array(
- 'watchlist',
- 'watchlist-summary',
- 'mywatchlist',
- 'watchlistfor2',
- 'nowatchlist',
- 'watchlistanontext',
- 'watchnologin',
- 'watchnologintext',
- 'addwatch',
- 'addedwatchtext',
- 'removewatch',
- 'removedwatchtext',
- 'watch',
- 'watchthispage',
- 'unwatch',
- 'unwatchthispage',
- 'notanarticle',
- 'notvisiblerev',
- 'watchlist-details',
- 'wlheader-enotif',
- 'wlheader-showupdated',
- 'watchmethod-recent',
- 'watchmethod-list',
- 'watchlistcontains',
- 'iteminvalidname',
- 'wlnote',
- 'wlshowlast',
- 'watchlist-options',
- ),
- 'watching' => array(
- 'watching',
- 'unwatching',
- 'watcherrortext',
- ),
- 'enotif' => array(
- 'enotif_mailer',
- 'enotif_reset',
- 'enotif_impersonal_salutation',
- 'enotif_subject_deleted',
- 'enotif_subject_created',
- 'enotif_subject_moved',
- 'enotif_subject_restored',
- 'enotif_subject_changed',
- 'enotif_body_intro_deleted',
- 'enotif_body_intro_created',
- 'enotif_body_intro_moved',
- 'enotif_body_intro_restored',
- 'enotif_body_intro_changed',
- 'enotif_lastvisited',
- 'enotif_lastdiff',
- 'enotif_anon_editor',
- 'enotif_body',
- 'created',
- 'changed',
- ),
- 'delete' => array(
- 'deletepage',
- 'confirm',
- 'excontent',
- 'excontentauthor',
- 'exbeforeblank',
- 'exblank',
- 'delete-confirm',
- 'delete-legend',
- 'historywarning',
- 'confirmdeletetext',
- 'actioncomplete',
- 'actionfailed',
- 'deletedtext',
- 'dellogpage',
- 'dellogpagetext',
- 'deletionlog',
- 'reverted',
- 'deletecomment',
- 'deleteotherreason',
- 'deletereasonotherlist',
- 'deletereason-dropdown',
- 'delete-edit-reasonlist',
- 'delete-toobig',
- 'delete-warning-toobig',
- ),
- 'rollback' => array(
- 'rollback',
- 'rollback_short',
- 'rollbacklink',
- 'rollbacklinkcount',
- 'rollbacklinkcount-morethan',
- 'rollbackfailed',
- 'cantrollback',
- 'alreadyrolled',
- 'editcomment',
- 'revertpage',
- 'revertpage-nouser',
- 'rollback-success',
- ),
- 'edittokens' => array(
- 'sessionfailure-title',
- 'sessionfailure',
- ),
- 'protect' => array(
- 'protectlogpage',
- 'protectlogtext',
- 'protectedarticle',
- 'modifiedarticleprotection',
- 'unprotectedarticle',
- 'movedarticleprotection',
- 'protect-title',
- 'protect-title-notallowed',
- 'prot_1movedto2',
- 'protect-badnamespace-title',
- 'protect-badnamespace-text',
- 'protect-norestrictiontypes-text',
- 'protect-norestrictiontypes-title',
- 'protect-legend',
- 'protectcomment',
- 'protectexpiry',
- 'protect_expiry_invalid',
- 'protect_expiry_old',
- 'protect-unchain-permissions',
- 'protect-text',
- 'protect-locked-blocked',
- 'protect-locked-dblock',
- 'protect-locked-access',
- 'protect-cascadeon',
- 'protect-default',
- 'protect-fallback',
- 'protect-level-autoconfirmed',
- 'protect-level-sysop',
- 'protect-summary-desc',
- 'protect-summary-cascade',
- 'protect-expiring',
- 'protect-expiring-local',
- 'protect-expiry-indefinite',
- 'protect-cascade',
- 'protect-cantedit',
- 'protect-othertime',
- 'protect-othertime-op',
- 'protect-existing-expiry',
- 'protect-otherreason',
- 'protect-otherreason-op',
- 'protect-dropdown',
- 'protect-edit-reasonlist',
- 'protect-expiry-options',
- 'restriction-type',
- 'restriction-level',
- 'minimum-size',
- 'maximum-size',
- 'pagesize',
- ),
- 'restrictions' => array(
- 'restriction-edit',
- 'restriction-move',
- 'restriction-create',
- 'restriction-upload',
- ),
- 'restriction-levels' => array(
- 'restriction-level-sysop',
- 'restriction-level-autoconfirmed',
- 'restriction-level-all',
- ),
- 'undelete' => array(
- 'undelete',
- 'undelete-summary',
- 'undeletepage',
- 'undeletepagetitle',
- 'viewdeletedpage',
- 'undeletepagetext',
- 'undelete-fieldset-title',
- 'undeleteextrahelp',
- 'undeleterevisions',
- 'undeletehistory',
- 'undeleterevdel',
- 'undeletehistorynoadmin',
- 'undelete-revision',
- 'undeleterevision-missing',
- 'undelete-nodiff',
- 'undeletebtn',
- 'undeletelink',
- 'undeleteviewlink',
- 'undeletereset',
- 'undeleteinvert',
- 'undeletecomment',
- 'undeletedrevisions',
- 'undeletedrevisions-files',
- 'undeletedfiles',
- 'cannotundelete',
- 'undeletedpage',
- 'undelete-header',
- 'undelete-search-title',
- 'undelete-search-box',
- 'undelete-search-prefix',
- 'undelete-search-submit',
- 'undelete-no-results',
- 'undelete-filename-mismatch',
- 'undelete-bad-store-key',
- 'undelete-cleanup-error',
- 'undelete-missing-filearchive',
- 'undelete-error',
- 'undelete-error-short',
- 'undelete-error-long',
- 'undelete-show-file-confirm',
- 'undelete-show-file-submit',
- 'undelete-revisionrow',
- ),
- 'nsform' => array(
- 'namespace',
- 'invert',
- 'tooltip-invert',
- 'namespace_association',
- 'tooltip-namespace_association',
- 'blanknamespace',
- ),
- 'contributions' => array(
- 'contributions',
- 'contributions-summary',
- 'contributions-title',
- 'mycontris',
- 'contribsub2',
- 'nocontribs',
- 'uctop',
- 'month',
- 'year',
- ),
- 'sp-contributions' => array(
- 'sp-contributions-newbies',
- 'sp-contributions-newbies-sub',
- 'sp-contributions-newbies-title',
- 'sp-contributions-blocklog',
- 'sp-contributions-deleted',
- 'sp-contributions-uploads',
- 'sp-contributions-logs',
- 'sp-contributions-talk',
- 'sp-contributions-userrights',
- 'sp-contributions-blocked-notice',
- 'sp-contributions-blocked-notice-anon',
- 'sp-contributions-search',
- 'sp-contributions-username',
- 'sp-contributions-toponly',
- 'sp-contributions-submit',
- 'sp-contributions-explain',
- 'sp-contributions-footer',
- 'sp-contributions-footer-anon',
- 'sp-contributions-footer-newbies',
- ),
- 'whatlinkshere' => array(
- 'whatlinkshere',
- 'whatlinkshere-title',
- 'whatlinkshere-summary',
- 'whatlinkshere-page',
- 'linkshere',
- 'nolinkshere',
- 'nolinkshere-ns',
- 'isredirect',
- 'istemplate',
- 'isimage',
- 'whatlinkshere-prev',
- 'whatlinkshere-next',
- 'whatlinkshere-links',
- 'whatlinkshere-hideredirs',
- 'whatlinkshere-hidetrans',
- 'whatlinkshere-hidelinks',
- 'whatlinkshere-hideimages',
- 'whatlinkshere-filters',
- ),
- 'block' => array(
- 'autoblockid',
- 'block',
- 'unblock',
- 'unblock-summary',
- 'blockip',
- 'blockip-title',
- 'blockip-legend',
- 'blockiptext',
- 'ipadressorusername',
- 'ipbexpiry',
- 'ipbreason',
- 'ipbreasonotherlist',
- 'ipbreason-dropdown',
- 'ipb-hardblock',
- 'ipbcreateaccount',
- 'ipbemailban',
- 'ipbenableautoblock',
- 'ipbsubmit',
- 'ipbother',
- 'ipboptions',
- 'ipbotheroption',
- 'ipbotherreason',
- 'ipbhidename',
- 'ipbwatchuser',
- 'ipb-disableusertalk',
- 'ipb-change-block',
- 'ipb-confirm',
- 'badipaddress',
- 'blockipsuccesssub',
- 'blockipsuccesstext',
- 'ipb-blockingself',
- 'ipb-confirmhideuser',
- 'ipb-edit-dropdown',
- 'ipb-unblock-addr',
- 'ipb-unblock',
- 'ipb-blocklist',
- 'ipb-blocklist-contribs',
- 'unblockip',
- 'unblockiptext',
- 'ipusubmit',
- 'unblocked',
- 'unblocked-range',
- 'unblocked-id',
- 'blocklist',
- 'ipblocklist',
- 'ipblocklist-legend',
- 'blocklist-userblocks',
- 'blocklist-tempblocks',
- 'blocklist-addressblocks',
- 'blocklist-rangeblocks',
- 'blocklist-timestamp',
- 'blocklist-target',
- 'blocklist-expiry',
- 'blocklist-by',
- 'blocklist-params',
- 'blocklist-reason',
- 'blocklist-summary',
- 'ipblocklist-submit',
- 'ipblocklist-localblock',
- 'ipblocklist-otherblocks',
-
- 'infiniteblock',
- 'expiringblock',
- 'anononlyblock',
- 'noautoblockblock',
- 'createaccountblock',
- 'emailblock',
- 'blocklist-nousertalk',
- 'ipblocklist-empty',
- 'ipblocklist-no-results',
- 'blocklink',
- 'unblocklink',
- 'change-blocklink',
- 'contribslink',
- 'emaillink',
- 'autoblocker',
- 'blocklogpage',
- 'blocklog-showlog',
- 'blocklog-showsuppresslog',
- 'blocklogentry',
- 'reblock-logentry',
- 'blocklogtext',
- 'unblocklogentry',
- 'block-log-flags-anononly',
- 'block-log-flags-nocreate',
- 'block-log-flags-noautoblock',
- 'block-log-flags-noemail',
- 'block-log-flags-nousertalk',
- 'block-log-flags-angry-autoblock',
- 'block-log-flags-hiddenname',
- 'range_block_disabled',
- 'ipb_expiry_invalid',
- 'ipb_expiry_temp',
- 'ipb_hide_invalid',
- 'ipb_already_blocked',
- 'ipb-needreblock',
- 'ipb-otherblocks-header',
- 'unblock-hideuser',
- 'ipb_cant_unblock',
- 'ipb_blocked_as_range',
- 'ip_range_invalid',
- 'ip_range_toolarge',
- 'proxyblocker',
- 'proxyblockreason',
- 'sorbs',
- 'sorbsreason',
- 'sorbs_create_account_reason',
- 'xffblockreason',
- 'cant-block-while-blocked',
- 'cant-see-hidden-user',
- 'ipbblocked',
- 'ipbnounblockself',
- 'ipb-default-expiry',
- ),
- 'developertools' => array(
- 'lockdb',
- 'unlockdb',
- 'lockdbtext',
- 'unlockdbtext',
- 'lockconfirm',
- 'unlockconfirm',
- 'lockbtn',
- 'unlockbtn',
- 'locknoconfirm',
- 'lockdbsuccesssub',
- 'unlockdbsuccesssub',
- 'lockdbsuccesstext',
- 'unlockdbsuccesstext',
- 'lockfilenotwritable',
- 'databasenotlocked',
- 'lockedbyandtime',
- ),
- 'movepage' => array(
- 'move-page',
- 'movepage-summary',
- 'move-page-legend',
- 'movepagetext',
- 'movepagetext-noredirectfixer',
- 'movepagetalktext',
- 'movearticle',
- 'moveuserpage-warning',
- 'movenologin',
- 'movenologintext',
- 'movenotallowed',
- 'movenotallowedfile',
- 'cant-move-user-page',
- 'cant-move-to-user-page',
- 'newtitle',
- 'move-watch',
- 'movepagebtn',
- 'pagemovedsub',
- 'movepage-moved',
- 'movepage-moved-redirect',
- 'movepage-moved-noredirect',
- 'articleexists',
- 'cantmove-titleprotected',
- 'talkexists',
- 'movedto',
- 'movetalk',
- 'move-subpages',
- 'move-talk-subpages',
- 'movepage-page-exists',
- 'movepage-page-moved',
- 'movepage-page-unmoved',
- 'movepage-max-pages',
- 'movelogpage',
- 'movelogpagetext',
- 'movesubpage',
- 'movesubpagetext',
- 'movenosubpage',
- 'movereason',
- 'move-redirect-text',
- 'revertmove',
- 'delete_and_move',
- 'delete_and_move_text',
- 'delete_and_move_confirm',
- 'delete_and_move_reason',
- 'selfmove',
- 'immobile-source-namespace',
- 'immobile-target-namespace',
- 'immobile-target-namespace-iw',
- 'immobile-source-page',
- 'immobile-target-page',
- 'bad-target-model',
- 'immobile_namespace',
- 'imagenocrossnamespace',
- 'nonfile-cannot-move-to-file',
- 'imagetypemismatch',
- 'imageinvalidfilename',
- 'fix-double-redirects',
- 'move-leave-redirect',
- 'protectedpagemovewarning',
- 'semiprotectedpagemovewarning',
- 'move-over-sharedrepo',
- 'file-exists-sharedrepo',
- ),
- 'export' => array(
- 'export',
- 'export-summary',
- 'exporttext',
- 'exportall',
- 'exportcuronly',
- 'exportnohistory',
- 'exportlistauthors',
- 'export-submit',
- 'export-addcattext',
- 'export-addcat',
- 'export-addnstext',
- 'export-addns',
- 'export-download',
- 'export-templates',
- 'export-pagelinks',
- ),
- 'allmessages' => array(
- 'allmessages',
- 'allmessagesname',
- 'allmessagesdefault',
- 'allmessagescurrent',
- 'allmessagestext',
- 'allmessagesnotsupportedDB',
- 'allmessages-filter-legend',
- 'allmessages-filter',
- 'allmessages-filter-unmodified',
- 'allmessages-filter-all',
- 'allmessages-filter-modified',
- 'allmessages-prefix',
- 'allmessages-language',
- 'allmessages-filter-submit',
- ),
- 'thumbnails' => array(
- 'thumbnail-more',
- 'filemissing',
- 'thumbnail_error',
- 'thumbnail_error_remote',
- 'djvu_page_error',
- 'djvu_no_xml',
- 'thumbnail-temp-create',
- 'thumbnail-dest-create',
- 'thumbnail_invalid_params',
- 'thumbnail_dest_directory',
- 'thumbnail_image-type',
- 'thumbnail_gd-library',
- 'thumbnail_image-missing',
- ),
- 'import' => array(
- 'import',
- 'import-summary',
- 'importinterwiki',
- 'import-interwiki-text',
- 'import-interwiki-source',
- 'import-interwiki-history',
- 'import-interwiki-templates',
- 'import-interwiki-submit',
- 'import-interwiki-namespace',
- 'import-interwiki-rootpage',
- 'import-upload-filename',
- 'import-comment',
- 'importtext',
- 'importstart',
- 'import-revision-count',
- 'importnopages',
- 'imported-log-entries',
- 'importfailed',
- 'importunknownsource',
- 'importcantopen',
- 'importbadinterwiki',
- 'importnotext',
- 'importsuccess',
- 'importhistoryconflict',
- 'importnosources',
- 'importnofile',
- 'importuploaderrorsize',
- 'importuploaderrorpartial',
- 'importuploaderrortemp',
- 'import-parse-failure',
- 'import-noarticle',
- 'import-nonewrevisions',
- 'xml-error-string',
- 'import-upload',
- 'import-token-mismatch',
- 'import-invalid-interwiki',
- 'import-error-edit',
- 'import-error-create',
- 'import-error-interwiki',
- 'import-error-special',
- 'import-error-invalid',
- 'import-error-unserialize',
- 'import-options-wrong',
- 'import-rootpage-invalid',
- 'import-rootpage-nosubpage',
- ),
- 'importlog' => array(
- 'importlogpage',
- 'importlogpagetext',
- 'import-logentry-upload',
- 'import-logentry-upload-detail',
- 'import-logentry-interwiki',
- 'import-logentry-interwiki-detail',
- ),
- 'javaccripttest' => array(
- 'javascripttest',
- 'javascripttest-backlink',
- 'javascripttest-title',
- 'javascripttest-pagetext-noframework',
- 'javascripttest-pagetext-unknownframework',
- 'javascripttest-pagetext-frameworks',
- 'javascripttest-pagetext-skins',
- 'javascripttest-qunit-name',
- 'javascripttest-qunit-intro',
- 'javascripttest-qunit-heading',
- ),
- '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-unprotect',
- 'accesskey-ca-delete',
- 'accesskey-ca-undelete',
- 'accesskey-ca-move',
- 'accesskey-ca-watch',
- 'accesskey-ca-unwatch',
- 'accesskey-search',
- 'accesskey-search-go',
- 'accesskey-search-fulltext',
- 'accesskey-p-logo',
- 'accesskey-n-mainpage',
- 'accesskey-n-mainpage-description',
- 'accesskey-n-portal',
- 'accesskey-n-currentevents',
- 'accesskey-n-recentchanges',
- 'accesskey-n-randompage',
- 'accesskey-n-help',
- 'accesskey-t-whatlinkshere',
- 'accesskey-t-recentchangeslinked',
- 'accesskey-t-random',
- 'accesskey-feed-rss',
- 'accesskey-feed-atom',
- 'accesskey-t-contributions',
- 'accesskey-t-emailuser',
- 'accesskey-t-permalink',
- 'accesskey-t-print',
- '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',
- 'accesskey-upload',
- 'accesskey-preferences-save',
- 'accesskey-summary',
- 'accesskey-userrights-set',
- 'accesskey-blockip-block',
- 'accesskey-export',
- 'accesskey-import',
- 'accesskey-watchlistedit-normal-submit',
- 'accesskey-watchlistedit-raw-submit',
- ),
- '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-unprotect',
- 'tooltip-ca-delete',
- 'tooltip-ca-undelete',
- 'tooltip-ca-move',
- 'tooltip-ca-watch',
- 'tooltip-ca-unwatch',
- 'tooltip-search',
- 'tooltip-search-go',
- 'tooltip-search-fulltext',
- 'tooltip-p-logo',
- 'tooltip-n-mainpage',
- 'tooltip-n-mainpage-description',
- 'tooltip-n-portal',
- 'tooltip-n-currentevents',
- 'tooltip-n-recentchanges',
- 'tooltip-n-randompage',
- 'tooltip-n-help',
- 'tooltip-t-whatlinkshere',
- 'tooltip-t-recentchangeslinked',
- 'tooltip-t-random',
- 'tooltip-feed-rss',
- 'tooltip-feed-atom',
- 'tooltip-t-contributions',
- 'tooltip-t-emailuser',
- 'tooltip-t-upload',
- 'tooltip-t-specialpages',
- 'tooltip-t-print',
- 'tooltip-t-permalink',
- '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-watchlistedit-normal-submit',
- 'tooltip-watchlistedit-raw-submit',
- 'tooltip-recreate',
- 'tooltip-upload',
- 'tooltip-rollback',
- 'tooltip-undo',
- 'tooltip-preferences-save',
- 'tooltip-summary',
- 'interlanguage-link-title',
- ),
- 'stylesheets' => array(
- 'common.css',
- 'cologneblue.css',
- 'monobook.css',
- 'modern.css',
- 'vector.css',
- 'print.css',
- 'noscript.css',
- 'group-autoconfirmed.css',
- 'group-bot.css',
- 'group-sysop.css',
- 'group-bureaucrat.css',
- ),
- 'scripts' => array(
- 'common.js',
- 'cologneblue.js',
- 'monobook.js',
- 'modern.js',
- 'vector.js',
- 'group-autoconfirmed.js',
- 'group-bot.js',
- 'group-sysop.js',
- 'group-bureaucrat.js',
- ),
- 'metadata_cc' => array(
- 'notacceptable',
- ),
- 'attribution' => array(
- 'anonymous',
- 'siteuser',
- 'anonuser',
- 'lastmodifiedatby',
- 'othercontribs',
- 'others',
- 'siteusers',
- 'anonusers',
- 'creditspage',
- 'nocredits',
- ),
- 'spamprotection' => array(
- 'spamprotectiontitle',
- 'spamprotectiontext',
- 'spamprotectionmatch',
- 'spambot_username',
- 'spam_reverting',
- 'spam_blanking',
- 'spam_deleting',
- 'simpleantispam-label',
- ),
- 'info' => array(
- 'pageinfo-header',
- 'pageinfo-title',
- 'pageinfo-not-current',
- 'pageinfo-header-basic',
- 'pageinfo-header-edits',
- 'pageinfo-header-restrictions',
- 'pageinfo-header-properties',
- 'pageinfo-display-title',
- 'pageinfo-default-sort',
- 'pageinfo-length',
- 'pageinfo-article-id',
- 'pageinfo-language',
- 'pageinfo-robot-policy',
- 'pageinfo-robot-index',
- 'pageinfo-robot-noindex',
- 'pageinfo-views',
- 'pageinfo-watchers',
- 'pageinfo-few-watchers',
- 'pageinfo-redirects-name',
- 'pageinfo-redirects-value',
- 'pageinfo-subpages-name',
- 'pageinfo-subpages-value',
- 'pageinfo-firstuser',
- 'pageinfo-firsttime',
- 'pageinfo-lastuser',
- 'pageinfo-lasttime',
- 'pageinfo-edits',
- 'pageinfo-authors',
- 'pageinfo-recent-edits',
- 'pageinfo-recent-authors',
- 'pageinfo-magic-words',
- 'pageinfo-hidden-categories',
- 'pageinfo-templates',
- 'pageinfo-transclusions',
- 'pageinfo-footer',
- 'pageinfo-toolboxlink',
- 'pageinfo-redirectsto',
- 'pageinfo-redirectsto-info',
- 'pageinfo-contentpage',
- 'pageinfo-contentpage-yes',
- 'pageinfo-protect-cascading',
- 'pageinfo-protect-cascading-yes',
- 'pageinfo-protect-cascading-from',
- 'pageinfo-category-info',
- 'pageinfo-category-pages',
- 'pageinfo-category-subcats',
- 'pageinfo-category-files'
- ),
- 'skin' => array(
- 'skinname-cologneblue',
- 'skinname-monobook',
- 'skinname-modern',
- 'skinname-vector',
- ),
- 'patrolling' => array(
- 'markaspatrolleddiff',
- 'markaspatrolledlink',
- 'markaspatrolledtext',
- 'markedaspatrolled',
- 'markedaspatrolledtext',
- 'rcpatroldisabled',
- 'rcpatroldisabledtext',
- 'markedaspatrollederror',
- 'markedaspatrollederrortext',
- 'markedaspatrollederror-noautopatrol',
- 'markedaspatrollednotify',
- 'markedaspatrollederrornotify',
- ),
- 'patrol-log' => array(
- 'patrol-log-page',
- 'patrol-log-header',
- 'log-show-hide-patrol',
- ),
- 'imagedeletion' => array(
- 'deletedrevision',
- 'filedeleteerror-short',
- 'filedeleteerror-long',
- 'filedelete-missing',
- 'filedelete-old-unregistered',
- 'filedelete-current-unregistered',
- 'filedelete-archive-read-only',
- ),
- 'browsediffs' => array(
- 'previousdiff',
- 'nextdiff',
- ),
- 'media-info' => array(
- 'mediawarning',
- 'imagemaxsize',
- 'thumbsize',
- 'widthheight',
- 'widthheightpage',
- 'file-info',
- 'file-info-size',
- 'file-info-size-pages',
- 'file-nohires',
- 'svg-long-desc',
- 'svg-long-desc-animated',
- 'svg-long-error',
- 'show-big-image',
- 'show-big-image-preview',
- 'show-big-image-other',
- 'show-big-image-size',
- 'file-info-gif-looped',
- 'file-info-gif-frames',
- 'file-info-png-looped',
- 'file-info-png-repeat',
- 'file-info-png-frames',
- 'file-no-thumb-animation',
- 'file-no-thumb-animation-gif',
- ),
- 'newfiles' => array(
- 'newimages',
- 'imagelisttext',
- 'newimages-summary',
- 'newimages-legend',
- 'newimages-label',
- 'showhidebots',
- 'noimages',
- 'ilsubmit',
- 'bydate',
- 'sp-newimages-showfrom',
- ),
- 'video-info' => array(
- 'video-dims',
- 'seconds-abbrev',
- 'minutes-abbrev',
- 'hours-abbrev',
- 'days-abbrev',
- 'seconds',
- 'minutes',
- 'hours',
- 'days',
- 'weeks',
- 'months',
- 'years',
- 'ago',
- 'just-now',
- ),
- 'human-timestamps' => array(
- 'hours-ago',
- 'minutes-ago',
- 'seconds-ago',
- 'monday-at',
- 'tuesday-at',
- 'wednesday-at',
- 'thursday-at',
- 'friday-at',
- 'saturday-at',
- 'sunday-at',
- 'today-at',
- 'yesterday-at',
- ),
- 'badimagelist' => array(
- 'bad_image_list',
- ),
- 'variantname-zh' => array(
- 'variantname-zh-hans',
- 'variantname-zh-hant',
- 'variantname-zh-cn',
- 'variantname-zh-tw',
- 'variantname-zh-hk',
- 'variantname-zh-mo',
- 'variantname-zh-sg',
- 'variantname-zh-my',
- 'variantname-zh',
- ),
- 'variantname-gan' => array(
- 'variantname-gan-hans',
- 'variantname-gan-hant',
- 'variantname-gan',
- ),
- 'variantname-sr' => array(
- 'variantname-sr-ec',
- 'variantname-sr-el',
- 'variantname-sr',
- ),
- 'variantname-kk' => array(
- 'variantname-kk-kz',
- 'variantname-kk-tr',
- 'variantname-kk-cn',
- 'variantname-kk-cyrl',
- 'variantname-kk-latn',
- 'variantname-kk-arab',
- 'variantname-kk',
- ),
- 'variantname-ku' => array(
- 'variantname-ku-arab',
- 'variantname-ku-latn',
- 'variantname-ku',
- ),
- 'variantname-tg' => array(
- 'variantname-tg-cyrl',
- 'variantname-tg-latn',
- 'variantname-tg',
- ),
- 'variantname-iu' => array(
- 'variantname-ike-cans',
- 'variantname-ike-latn',
- 'variantname-iu',
- ),
- 'variantname-shi' => array(
- 'variantname-shi-tfng',
- 'variantname-shi-latn',
- 'variantname-shi',
- ),
- 'metadata' => array(
- 'metadata',
- 'metadata-help',
- 'metadata-expand',
- 'metadata-collapse',
- 'metadata-fields',
- 'metadata-langitem',
- 'metadata-langitem-default',
- ),
- 'exif' => array(
- 'exif-imagewidth',
- 'exif-imagelength',
- 'exif-bitspersample',
- 'exif-compression',
- 'exif-photometricinterpretation',
- 'exif-orientation',
- 'exif-samplesperpixel',
- 'exif-planarconfiguration',
- 'exif-ycbcrsubsampling',
- 'exif-ycbcrpositioning',
- 'exif-xresolution',
- 'exif-yresolution',
- 'exif-resolutionunit',
- 'exif-stripoffsets',
- 'exif-rowsperstrip',
- 'exif-stripbytecounts',
- 'exif-jpeginterchangeformat',
- 'exif-jpeginterchangeformatlength',
- 'exif-whitepoint',
- 'exif-primarychromaticities',
- 'exif-ycbcrcoefficients',
- 'exif-referenceblackwhite',
- 'exif-datetime',
- 'exif-imagedescription',
- 'exif-make',
- 'exif-model',
- 'exif-software',
- 'exif-artist',
- 'exif-copyright',
- 'exif-exifversion',
- 'exif-flashpixversion',
- 'exif-colorspace',
- 'exif-componentsconfiguration',
- 'exif-compressedbitsperpixel',
- 'exif-pixelydimension',
- 'exif-pixelxdimension',
- 'exif-usercomment',
- 'exif-relatedsoundfile',
- 'exif-datetimeoriginal',
- 'exif-datetimedigitized',
- 'exif-subsectime',
- 'exif-subsectimeoriginal',
- 'exif-subsectimedigitized',
- 'exif-exposuretime',
- 'exif-exposuretime-format',
- 'exif-fnumber',
- 'exif-fnumber-format',
- 'exif-exposureprogram',
- 'exif-spectralsensitivity',
- 'exif-isospeedratings',
- 'exif-shutterspeedvalue',
- 'exif-aperturevalue',
- 'exif-brightnessvalue',
- 'exif-exposurebiasvalue',
- 'exif-maxaperturevalue',
- 'exif-subjectdistance',
- 'exif-meteringmode',
- 'exif-lightsource',
- 'exif-flash',
- 'exif-focallength',
- 'exif-focallength-format',
- 'exif-subjectarea',
- 'exif-flashenergy',
- 'exif-focalplanexresolution',
- 'exif-focalplaneyresolution',
- 'exif-focalplaneresolutionunit',
- 'exif-subjectlocation',
- 'exif-exposureindex',
- 'exif-sensingmethod',
- 'exif-filesource',
- 'exif-scenetype',
- 'exif-customrendered',
- 'exif-exposuremode',
- 'exif-whitebalance',
- 'exif-digitalzoomratio',
- 'exif-focallengthin35mmfilm',
- 'exif-scenecapturetype',
- 'exif-gaincontrol',
- 'exif-contrast',
- 'exif-saturation',
- 'exif-sharpness',
- 'exif-devicesettingdescription',
- 'exif-subjectdistancerange',
- 'exif-imageuniqueid',
- 'exif-gpsversionid',
- 'exif-gpslatituderef',
- 'exif-gpslatitude',
- 'exif-gpslongituderef',
- 'exif-gpslongitude',
- 'exif-gpsaltituderef',
- 'exif-gpsaltitude',
- 'exif-gpstimestamp',
- 'exif-gpssatellites',
- 'exif-gpsstatus',
- 'exif-gpsmeasuremode',
- 'exif-gpsdop',
- 'exif-gpsspeedref',
- 'exif-gpsspeed',
- 'exif-gpstrackref',
- 'exif-gpstrack',
- 'exif-gpsimgdirectionref',
- 'exif-gpsimgdirection',
- 'exif-gpsmapdatum',
- 'exif-gpsdestlatituderef',
- 'exif-gpsdestlatitude',
- 'exif-gpsdestlongituderef',
- 'exif-gpsdestlongitude',
- 'exif-gpsdestbearingref',
- 'exif-gpsdestbearing',
- 'exif-gpsdestdistanceref',
- 'exif-gpsdestdistance',
- 'exif-gpsprocessingmethod',
- 'exif-gpsareainformation',
- 'exif-gpsdatestamp',
- 'exif-gpsdifferential',
- 'exif-coordinate-format',
- 'exif-jpegfilecomment',
- 'exif-keywords',
- 'exif-worldregioncreated',
- 'exif-countrycreated',
- 'exif-countrycodecreated',
- 'exif-provinceorstatecreated',
- 'exif-citycreated',
- 'exif-sublocationcreated',
- 'exif-worldregiondest',
- 'exif-countrydest',
- 'exif-countrycodedest',
- 'exif-provinceorstatedest',
- 'exif-citydest',
- 'exif-sublocationdest',
- 'exif-objectname',
- 'exif-specialinstructions',
- 'exif-headline',
- 'exif-credit',
- 'exif-source',
- 'exif-editstatus',
- 'exif-urgency',
- 'exif-fixtureidentifier',
- 'exif-locationdest',
- 'exif-locationdestcode',
- 'exif-objectcycle',
- 'exif-contact',
- 'exif-writer',
- 'exif-languagecode',
- 'exif-iimversion',
- 'exif-iimcategory',
- 'exif-iimsupplementalcategory',
- 'exif-datetimeexpires',
- 'exif-datetimereleased',
- 'exif-originaltransmissionref',
- 'exif-identifier',
- 'exif-lens',
- 'exif-serialnumber',
- 'exif-cameraownername',
- 'exif-label',
- 'exif-datetimemetadata',
- 'exif-nickname',
- 'exif-rating',
- 'exif-rightscertificate',
- 'exif-copyrighted',
- 'exif-copyrightowner',
- 'exif-usageterms',
- 'exif-webstatement',
- 'exif-originaldocumentid',
- 'exif-licenseurl',
- 'exif-morepermissionsurl',
- 'exif-attributionurl',
- 'exif-preferredattributionname',
- 'exif-pngfilecomment',
- 'exif-disclaimer',
- 'exif-contentwarning',
- 'exif-giffilecomment',
- 'exif-intellectualgenre',
- 'exif-subjectnewscode',
- 'exif-scenecode',
- 'exif-event',
- 'exif-organisationinimage',
- 'exif-personinimage',
- 'exif-originalimageheight',
- 'exif-originalimagewidth',
- ),
- 'exif-values' => array(
- 'exif-make-value',
- 'exif-model-value',
- 'exif-software-value',
- 'exif-software-version-value',
- 'exif-contact-value',
- 'exif-subjectnewscode-value',
- ),
- 'exif-compression' => array(
- 'exif-compression-1',
- 'exif-compression-2',
- 'exif-compression-3',
- 'exif-compression-4',
- 'exif-compression-5',
- 'exif-compression-6',
- 'exif-compression-7',
- 'exif-compression-8',
- 'exif-compression-32773',
- 'exif-compression-32946',
- 'exif-compression-34712',
- ),
- 'exif-copyrighted' => array(
- 'exif-copyrighted-true',
- 'exif-copyrighted-false',
- ),
- 'exif-photometricinterpretation' => array(
- 'exif-photometricinterpretation-2',
- 'exif-photometricinterpretation-6',
- ),
- 'exif-unknowndate' => array(
- 'exif-unknowndate',
- ),
- 'exif-orientation' => array(
- 'exif-orientation-1',
- 'exif-orientation-2',
- 'exif-orientation-3',
- 'exif-orientation-4',
- 'exif-orientation-5',
- 'exif-orientation-6',
- 'exif-orientation-7',
- 'exif-orientation-8',
- ),
- 'exif-planarconfiguration' => array(
- 'exif-planarconfiguration-1',
- 'exif-planarconfiguration-2',
- ),
- 'exif-xyresolution' => array(
- 'exif-xyresolution-i',
- 'exif-xyresolution-c',
- ),
- 'exif-colorspace' => array(
- 'exif-colorspace-1',
- 'exif-colorspace-65535',
- ),
- 'exif-componentsconfiguration' => array(
- 'exif-componentsconfiguration-0',
- 'exif-componentsconfiguration-1',
- 'exif-componentsconfiguration-2',
- 'exif-componentsconfiguration-3',
- 'exif-componentsconfiguration-4',
- 'exif-componentsconfiguration-5',
- 'exif-componentsconfiguration-6',
- ),
- 'exif-exposureprogram' => array(
- 'exif-exposureprogram-0',
- 'exif-exposureprogram-1',
- 'exif-exposureprogram-2',
- 'exif-exposureprogram-3',
- 'exif-exposureprogram-4',
- 'exif-exposureprogram-5',
- 'exif-exposureprogram-6',
- 'exif-exposureprogram-7',
- 'exif-exposureprogram-8',
- ),
- 'exif-subjectdistance-value' => array(
- 'exif-subjectdistance-value',
- ),
- 'exif-meteringmode' => array(
- 'exif-meteringmode-0',
- 'exif-meteringmode-1',
- 'exif-meteringmode-2',
- 'exif-meteringmode-3',
- 'exif-meteringmode-4',
- 'exif-meteringmode-5',
- 'exif-meteringmode-6',
- 'exif-meteringmode-255',
- ),
- 'exif-lightsource' => array(
- 'exif-lightsource-0',
- 'exif-lightsource-1',
- 'exif-lightsource-2',
- 'exif-lightsource-3',
- 'exif-lightsource-4',
- 'exif-lightsource-9',
- 'exif-lightsource-10',
- 'exif-lightsource-11',
- 'exif-lightsource-12',
- 'exif-lightsource-13',
- 'exif-lightsource-14',
- 'exif-lightsource-15',
- 'exif-lightsource-17',
- 'exif-lightsource-18',
- 'exif-lightsource-19',
- 'exif-lightsource-20',
- 'exif-lightsource-21',
- 'exif-lightsource-22',
- 'exif-lightsource-23',
- 'exif-lightsource-24',
- 'exif-lightsource-255',
- ),
- 'exif-flash' => array(
- 'exif-flash-fired-0',
- 'exif-flash-fired-1',
- 'exif-flash-return-0',
- 'exif-flash-return-2',
- 'exif-flash-return-3',
- 'exif-flash-mode-1',
- 'exif-flash-mode-2',
- 'exif-flash-mode-3',
- 'exif-flash-function-1',
- 'exif-flash-redeye-1',
- ),
- 'exif-focalplaneresolutionunit' => array(
- 'exif-focalplaneresolutionunit-2',
- ),
- 'exif-sensingmethod' => array(
- 'exif-sensingmethod-1',
- 'exif-sensingmethod-2',
- 'exif-sensingmethod-3',
- 'exif-sensingmethod-4',
- 'exif-sensingmethod-5',
- 'exif-sensingmethod-7',
- 'exif-sensingmethod-8',
- ),
- 'exif-filesource' => array(
- 'exif-filesource-3',
- ),
- 'exif-scenetype' => array(
- 'exif-scenetype-1',
- ),
- 'exif-customrendered' => array(
- 'exif-customrendered-0',
- 'exif-customrendered-1',
- ),
- 'exif-exposuremode' => array(
- 'exif-exposuremode-0',
- 'exif-exposuremode-1',
- 'exif-exposuremode-2',
- ),
- 'exif-whitebalance' => array(
- 'exif-whitebalance-0',
- 'exif-whitebalance-1',
- ),
- 'exif-scenecapturetype' => array(
- 'exif-scenecapturetype-0',
- 'exif-scenecapturetype-1',
- 'exif-scenecapturetype-2',
- 'exif-scenecapturetype-3',
- ),
- 'exif-gaincontrol' => array(
- 'exif-gaincontrol-0',
- 'exif-gaincontrol-1',
- 'exif-gaincontrol-2',
- 'exif-gaincontrol-3',
- 'exif-gaincontrol-4',
- ),
- 'exif-contrast' => array(
- 'exif-contrast-0',
- 'exif-contrast-1',
- 'exif-contrast-2',
- ),
- 'exif-saturation' => array(
- 'exif-saturation-0',
- 'exif-saturation-1',
- 'exif-saturation-2',
- ),
- 'exif-sharpness' => array(
- 'exif-sharpness-0',
- 'exif-sharpness-1',
- 'exif-sharpness-2',
- ),
- 'exif-subjectdistancerange' => array(
- 'exif-subjectdistancerange-0',
- 'exif-subjectdistancerange-1',
- 'exif-subjectdistancerange-2',
- 'exif-subjectdistancerange-3',
- ),
- 'exif-gpslatitude' => array(
- 'exif-gpslatitude-n',
- 'exif-gpslatitude-s',
- ),
- 'exif-gpslongitude' => array(
- 'exif-gpslongitude-e',
- 'exif-gpslongitude-w',
- ),
- 'exif-altituderef' => array(
- 'exif-gpsaltitude-above-sealevel',
- 'exif-gpsaltitude-below-sealevel',
- ),
- 'exif-gpsstatus' => array(
- 'exif-gpsstatus-a',
- 'exif-gpsstatus-v',
- ),
- 'exif-gpsmeasuremode' => array(
- 'exif-gpsmeasuremode-2',
- 'exif-gpsmeasuremode-3',
- ),
- 'exif-gpsspeed' => array(
- 'exif-gpsspeed-k',
- 'exif-gpsspeed-m',
- 'exif-gpsspeed-n',
- ),
- 'exif-gpsdestdistanceref' => array(
- 'exif-gpsdestdistance-k',
- 'exif-gpsdestdistance-m',
- 'exif-gpsdestdistance-n',
- ),
- 'exif-gdop' => array(
- 'exif-gpsdop-excellent',
- 'exif-gpsdop-good',
- 'exif-gpsdop-moderate',
- 'exif-gpsdop-fair',
- 'exif-gpsdop-poor',
- ),
- 'exif-objectcycle' => array(
- 'exif-objectcycle-a',
- 'exif-objectcycle-p',
- 'exif-objectcycle-b',
- ),
- 'exif-gpsdirection' => array(
- 'exif-gpsdirection-t',
- 'exif-gpsdirection-m',
- ),
- 'exif-ycbcrpositioning' => array(
- 'exif-ycbcrpositioning-1',
- 'exif-ycbcrpositioning-2',
- ),
- 'exif-dc' => array(
- 'exif-dc-contributor',
- 'exif-dc-coverage',
- 'exif-dc-date',
- 'exif-dc-publisher',
- 'exif-dc-relation',
- 'exif-dc-rights',
- 'exif-dc-source',
- 'exif-dc-type',
- ),
- 'exif-rating' => array(
- 'exif-rating-rejected',
- ),
- 'exif-isospeedratings' => array(
- 'exif-isospeedratings-overflow',
- ),
- 'exif-maxaperturevalue' => array(
- 'exif-maxaperturevalue-value',
- ),
- 'exif-iimcategory' => array(
- 'exif-iimcategory-ace',
- 'exif-iimcategory-clj',
- 'exif-iimcategory-dis',
- 'exif-iimcategory-fin',
- 'exif-iimcategory-edu',
- 'exif-iimcategory-evn',
- 'exif-iimcategory-hth',
- 'exif-iimcategory-hum',
- 'exif-iimcategory-lab',
- 'exif-iimcategory-lif',
- 'exif-iimcategory-pol',
- 'exif-iimcategory-rel',
- 'exif-iimcategory-sci',
- 'exif-iimcategory-soi',
- 'exif-iimcategory-spo',
- 'exif-iimcategory-war',
- 'exif-iimcategory-wea',
- ),
- 'exif-urgency' => array(
- 'exif-urgency-normal',
- 'exif-urgency-low',
- 'exif-urgency-high',
- 'exif-urgency-other',
- ),
- 'edit-externally' => array(
- 'edit-externally',
- 'edit-externally-help',
- ),
- 'all' => array(
- 'watchlistall2',
- 'namespacesall',
- 'monthsall',
- 'limitall',
- ),
- 'confirmemail' => array(
- 'confirmemail',
- 'confirmemail_noemail',
- 'confirmemail_text',
- 'confirmemail_pending',
- 'confirmemail_send',
- 'confirmemail_sent',
- 'confirmemail_oncreate',
- 'confirmemail_sendfailed',
- 'confirmemail_invalid',
- 'confirmemail_needlogin',
- 'confirmemail_success',
- 'confirmemail_loggedin',
- 'confirmemail_error',
- 'confirmemail_subject',
- 'confirmemail_body',
- 'confirmemail_body_changed',
- 'confirmemail_body_set',
- 'confirmemail_invalidated',
- 'invalidateemail',
- ),
- 'scarytransclusion' => array(
- 'scarytranscludedisabled',
- 'scarytranscludefailed',
- 'scarytranscludefailed-httpstatus',
- 'scarytranscludetoolong',
- ),
- 'deleteconflict' => array(
- 'deletedwhileediting',
- 'confirmrecreate',
- 'confirmrecreate-noreason',
- 'recreate',
- ),
- 'unit-pixel' => array(
- 'unit-pixel',
- ),
- 'purge' => array(
- 'confirm_purge_button',
- 'confirm-purge-top',
- 'confirm-purge-bottom',
- ),
- 'watch-unwatch' => array(
- 'confirm-watch-button',
- 'confirm-watch-top',
- 'confirm-unwatch-button',
- 'confirm-unwatch-top',
- ),
- 'separators' => array(
- 'semicolon-separator',
- 'comma-separator',
- 'colon-separator',
- 'autocomment-prefix',
- 'pipe-separator',
- 'word-separator',
- 'ellipsis',
- 'percent',
- 'parentheses',
- 'brackets',
- ),
- 'imgmulti' => array(
- 'imgmultipageprev',
- 'imgmultipagenext',
- 'imgmultigo',
- 'imgmultigoto',
- ),
- 'tablepager' => array(
- 'ascending_abbrev',
- 'descending_abbrev',
- 'table_pager_next',
- 'table_pager_prev',
- 'table_pager_first',
- 'table_pager_last',
- 'table_pager_limit',
- 'table_pager_limit_label',
- 'table_pager_limit_submit',
- 'table_pager_empty',
- ),
- 'autosumm' => array(
- 'autosumm-blank',
- 'autosumm-replace',
- 'autoredircomment',
- 'autosumm-new',
- ),
- 'autoblock_whitelist' => array(
- 'autoblock_whitelist',
- ),
- 'sizeunits' => array(
- 'size-bytes',
- 'size-kilobytes',
- 'size-megabytes',
- 'size-gigabytes',
- 'size-terabytes',
- 'size-petabytes',
- 'size-exabytes',
- 'size-zetabytes',
- 'size-yottabytes',
- ),
- 'bitrateunits' => array(
- 'bitrate-bits',
- 'bitrate-kilobits',
- 'bitrate-megabits',
- 'bitrate-gigabits',
- 'bitrate-terabits',
- 'bitrate-petabits',
- 'bitrate-exabits',
- 'bitrate-zetabits',
- 'bitrate-yottabits',
- ),
- 'livepreview' => array(
- 'livepreview-loading',
- 'livepreview-ready',
- 'livepreview-failed',
- 'livepreview-error',
- ),
- 'lagwarning' => array(
- 'lag-warn-normal',
- 'lag-warn-high',
- ),
- 'watch' => array(
- 'confirm-watch-button',
- ),
- 'watchlisteditor' => array(
- 'editwatchlist-summary',
- 'watchlistedit-numitems',
- 'watchlistedit-noitems',
- 'watchlistedit-normal-title',
- 'watchlistedit-normal-legend',
- 'watchlistedit-normal-explain',
- 'watchlistedit-normal-submit',
- 'watchlistedit-normal-done',
- 'watchlistedit-raw-title',
- 'watchlistedit-raw-legend',
- 'watchlistedit-raw-explain',
- 'watchlistedit-raw-titles',
- 'watchlistedit-raw-submit',
- 'watchlistedit-raw-done',
- 'watchlistedit-raw-added',
- 'watchlistedit-raw-removed',
- ),
- 'watchlisttools' => array(
- 'watchlisttools-view',
- 'watchlisttools-edit',
- 'watchlisttools-raw',
- ),
- 'iranian-dates' => array(
- 'iranian-calendar-m1',
- 'iranian-calendar-m2',
- 'iranian-calendar-m3',
- 'iranian-calendar-m4',
- 'iranian-calendar-m5',
- 'iranian-calendar-m6',
- 'iranian-calendar-m7',
- 'iranian-calendar-m8',
- 'iranian-calendar-m9',
- 'iranian-calendar-m10',
- 'iranian-calendar-m11',
- 'iranian-calendar-m12',
- ),
- 'hijri-dates' => array(
- 'hijri-calendar-m1',
- 'hijri-calendar-m2',
- 'hijri-calendar-m3',
- 'hijri-calendar-m4',
- 'hijri-calendar-m5',
- 'hijri-calendar-m6',
- 'hijri-calendar-m7',
- 'hijri-calendar-m8',
- 'hijri-calendar-m9',
- 'hijri-calendar-m10',
- 'hijri-calendar-m11',
- 'hijri-calendar-m12',
- ),
- 'hebrew-dates' => array(
- 'hebrew-calendar-m1',
- 'hebrew-calendar-m2',
- 'hebrew-calendar-m3',
- 'hebrew-calendar-m4',
- 'hebrew-calendar-m5',
- 'hebrew-calendar-m6',
- 'hebrew-calendar-m6a',
- 'hebrew-calendar-m6b',
- 'hebrew-calendar-m7',
- 'hebrew-calendar-m8',
- 'hebrew-calendar-m9',
- 'hebrew-calendar-m10',
- 'hebrew-calendar-m11',
- 'hebrew-calendar-m12',
- 'hebrew-calendar-m1-gen',
- 'hebrew-calendar-m2-gen',
- 'hebrew-calendar-m3-gen',
- 'hebrew-calendar-m4-gen',
- 'hebrew-calendar-m5-gen',
- 'hebrew-calendar-m6-gen',
- 'hebrew-calendar-m6a-gen',
- 'hebrew-calendar-m6b-gen',
- 'hebrew-calendar-m7-gen',
- 'hebrew-calendar-m8-gen',
- 'hebrew-calendar-m9-gen',
- 'hebrew-calendar-m10-gen',
- 'hebrew-calendar-m11-gen',
- 'hebrew-calendar-m12-gen',
- ),
- 'signatures' => array(
- 'signature',
- 'signature-anon',
- 'timezone-utc',
- ),
- 'CoreParserFunctions' => array(
- 'unknown_extension_tag',
- 'duplicate-defaultsort',
- ),
- 'version' => array(
- 'version',
- 'version-summary',
- 'version-extensions',
- 'version-specialpages',
- 'version-parserhooks',
- 'version-variables',
- 'version-antispam',
- 'version-skins',
- 'version-api',
- 'version-other',
- 'version-mediahandlers',
- 'version-hooks',
- 'version-parser-extensiontags',
- 'version-parser-function-hooks',
- 'version-hook-name',
- 'version-hook-subscribedby',
- 'version-version',
- 'version-svn-revision',
- 'version-license',
- 'version-poweredby-credits',
- 'version-poweredby-others',
- 'version-poweredby-translators',
- 'version-credits-summary',
- 'version-license-info',
- 'version-software',
- 'version-software-product',
- 'version-software-version',
- 'version-db-mysql-url',
- 'version-db-mariadb-url',
- 'version-db-percona-url',
- 'version-db-postgres-url',
- 'version-db-oracle-url',
- 'version-db-sqlite-url',
- 'version-db-mssql-url',
- 'version-entrypoints',
- 'version-entrypoints-header-entrypoint',
- 'version-entrypoints-header-url',
- 'version-entrypoints-articlepath',
- 'version-entrypoints-scriptpath',
- 'version-entrypoints-index-php',
- 'version-entrypoints-api-php',
- 'version-entrypoints-load-php',
- ),
- 'redirect' => array(
- 'redirect',
- 'redirect-legend',
- 'redirect-text',
- 'redirect-summary',
- 'redirect-submit',
- 'redirect-lookup',
- 'redirect-value',
- 'redirect-user',
- 'redirect-revision',
- 'redirect-file',
- 'redirect-not-exists',
- ),
- 'fileduplicatesearch' => array(
- 'fileduplicatesearch',
- 'fileduplicatesearch-summary',
- 'fileduplicatesearch-legend',
- 'fileduplicatesearch-filename',
- 'fileduplicatesearch-submit',
- 'fileduplicatesearch-info',
- 'fileduplicatesearch-result-1',
- 'fileduplicatesearch-result-n',
- 'fileduplicatesearch-noresults',
- ),
- 'special-specialpages' => array(
- 'specialpages',
- 'specialpages-summary',
- 'specialpages-note',
- 'specialpages-group-maintenance',
- 'specialpages-group-other',
- 'specialpages-group-login',
- 'specialpages-group-changes',
- 'specialpages-group-media',
- 'specialpages-group-users',
- 'specialpages-group-highuse',
- 'specialpages-group-pages',
- 'specialpages-group-pagetools',
- 'specialpages-group-wiki',
- 'specialpages-group-redirects',
- 'specialpages-group-spam',
- ),
- 'special-blank' => array(
- 'blankpage',
- 'intentionallyblankpage',
- ),
- 'external_images' => array(
- 'external_image_whitelist',
- ),
- 'special-tags' => array(
- 'tags',
- 'tags-summary',
- 'tag-filter',
- 'tag-filter-submit',
- 'tag-list-wrapper',
- 'tags-title',
- 'tags-intro',
- 'tags-tag',
- 'tags-display-header',
- 'tags-description-header',
- 'tags-active-header',
- 'tags-hitcount-header',
- 'tags-active-yes',
- 'tags-active-no',
- 'tags-edit',
- 'tags-hitcount',
- ),
- 'comparepages' => array(
- 'comparepages',
- 'comparepages-summary',
- 'compare-selector',
- 'compare-page1',
- 'compare-page2',
- 'compare-rev1',
- 'compare-rev2',
- 'compare-submit',
- 'compare-invalid-title',
- 'compare-title-not-exists',
- 'compare-revision-not-exists',
- ),
- 'db-error-messages' => array(
- 'dberr-header',
- 'dberr-problems',
- 'dberr-again',
- 'dberr-info',
- 'dberr-info-hidden',
- 'dberr-usegoogle',
- 'dberr-outofdate',
- 'dberr-cachederror',
- ),
- 'html-forms' => array(
- 'htmlform-invalid-input',
- 'htmlform-select-badoption',
- 'htmlform-int-invalid',
- 'htmlform-float-invalid',
- 'htmlform-int-toolow',
- 'htmlform-int-toohigh',
- 'htmlform-required',
- 'htmlform-submit',
- 'htmlform-reset',
- 'htmlform-selectorother-other',
- 'htmlform-no',
- 'htmlform-yes',
- 'htmlform-chosen-placeholder',
- ),
- 'sqlite' => array(
- 'sqlite-has-fts',
- 'sqlite-no-fts',
- ),
- 'unwatch' => array(
- 'confirm-unwatch-button',
- ),
- 'logging' => array(
- 'logentry-delete-delete',
- 'logentry-delete-restore',
- 'logentry-delete-event',
- 'logentry-delete-revision',
- 'logentry-delete-event-legacy',
- 'logentry-delete-revision-legacy',
- 'logentry-suppress-delete',
- 'logentry-suppress-event',
- 'logentry-suppress-revision',
- 'logentry-suppress-event-legacy',
- 'logentry-suppress-revision-legacy',
- 'revdelete-content-hid',
- 'revdelete-summary-hid',
- 'revdelete-uname-hid',
- 'revdelete-content-unhid',
- 'revdelete-summary-unhid',
- 'revdelete-uname-unhid',
- 'revdelete-restricted',
- 'revdelete-unrestricted',
- 'logentry-move-move',
- 'logentry-move-move-noredirect',
- 'logentry-move-move_redir',
- 'logentry-move-move_redir-noredirect',
- 'logentry-patrol-patrol',
- 'logentry-patrol-patrol-auto',
- 'logentry-newusers-newusers',
- 'logentry-newusers-create',
- 'logentry-newusers-create2',
- 'logentry-newusers-byemail',
- 'logentry-newusers-autocreate',
- 'logentry-rights-rights',
- 'logentry-rights-rights-legacy',
- 'logentry-rights-autopromote',
- 'rightsnone',
- ),
- 'logging-irc' => array(
- 'revdelete-logentry',
- 'logdelete-logentry',
- 'revdelete-content',
- 'revdelete-summary',
- 'revdelete-uname',
- 'revdelete-hid',
- 'revdelete-unhid',
- 'revdelete-log-message',
- 'logdelete-log-message',
- 'deletedarticle',
- 'suppressedarticle',
- 'undeletedarticle',
- 'patrol-log-line',
- 'patrol-log-auto',
- 'patrol-log-diff',
- '1movedto2',
- '1movedto2_redir',
- 'move-redirect-suppressed',
- 'newuserlog-create-entry',
- 'newuserlog-create2-entry',
- 'newuserlog-autocreate-entry',
- 'suppressedarticle',
- 'deletedarticle',
- // 'uploadedimage',
- // 'overwroteimage',
- 'rightslogentry',
- 'rightslogentry-autopromote',
- ),
- 'feedback' => array(
- 'feedback-bugornote',
- 'feedback-subject',
- 'feedback-message',
- 'feedback-cancel',
- 'feedback-submit',
- 'feedback-adding',
- 'feedback-error1',
- 'feedback-error2',
- 'feedback-error3',
- 'feedback-thanks',
- 'feedback-close',
- 'feedback-bugcheck',
- 'feedback-bugnew',
- ),
- 'searchsuggestions' => array(
- 'searchsuggest-search',
- 'searchsuggest-containing',
- ),
- 'apierrors' => array(
- 'api-error-badaccess-groups',
- 'api-error-badtoken',
- 'api-error-copyuploaddisabled',
- 'api-error-duplicate',
- 'api-error-duplicate-archive',
- 'api-error-duplicate-archive-popup-title',
- 'api-error-duplicate-popup-title',
- 'api-error-empty-file',
- 'api-error-emptypage',
- 'api-error-fetchfileerror',
- 'api-error-fileexists-forbidden',
- 'api-error-fileexists-shared-forbidden',
- 'api-error-file-too-large',
- 'api-error-filename-tooshort',
- 'api-error-filetype-banned',
- 'api-error-filetype-banned-type',
- 'api-error-filetype-missing',
- 'api-error-hookaborted',
- 'api-error-http',
- 'api-error-illegal-filename',
- 'api-error-internal-error',
- 'api-error-invalid-file-key',
- 'api-error-missingparam',
- 'api-error-missingresult',
- 'api-error-mustbeloggedin',
- 'api-error-mustbeposted',
- 'api-error-noimageinfo',
- 'api-error-nomodule',
- 'api-error-ok-but-empty',
- 'api-error-overwrite',
- 'api-error-stashfailed',
- 'api-error-publishfailed',
- 'api-error-timeout',
- 'api-error-unclassified',
- 'api-error-unknown-code',
- 'api-error-unknown-error',
- 'api-error-unknown-warning',
- 'api-error-unknownerror',
- 'api-error-uploaddisabled',
- 'api-error-verification-error',
- ),
- 'duration' => array(
- 'duration-seconds',
- 'duration-minutes',
- 'duration-hours',
- 'duration-days',
- 'duration-weeks',
- 'duration-years',
- 'duration-decades',
- 'duration-centuries',
- 'duration-millennia'
- ),
- 'rotation' => array(
- 'rotate-comment',
- ),
- 'limitreport' => array(
- 'limitreport-title',
- 'limitreport-cputime',
- 'limitreport-cputime-value',
- 'limitreport-walltime',
- 'limitreport-walltime-value',
- 'limitreport-ppvisitednodes',
- 'limitreport-ppvisitednodes-value',
- 'limitreport-ppgeneratednodes',
- 'limitreport-ppgeneratednodes-value',
- 'limitreport-postexpandincludesize',
- 'limitreport-postexpandincludesize-value',
- 'limitreport-templateargumentsize',
- 'limitreport-templateargumentsize-value',
- 'limitreport-expansiondepth',
- 'limitreport-expansiondepth-value',
- 'limitreport-expensivefunctioncount',
- 'limitreport-expensivefunctioncount-value',
- ),
-);
-
-/** Comments for each block */
-$wgBlockComments = array(
- 'sidebar' => "The sidebar for MonoBook is generated from this message, lines that do not
-begin with * or ** are discarded, furthermore lines that do begin with ** and
-do not contain | are also discarded, but do not depend on this behavior for
-future releases. Also note that since each list value is wrapped in a unique
-(X)HTML id it should only appear once and include characters that are legal
-(X)HTML id names.",
- 'toggles' => 'User preference toggles',
- 'underline' => '',
- 'editfont' => 'Font style option in Special:Preferences',
- 'dates' => 'Dates',
- 'categorypages' => 'Categories related messages',
- 'mainpage' => '',
- 'miscellaneous1' => '',
- 'cologneblue' => 'Cologne Blue skin',
- 'vector' => 'Vector skin',
- '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).',
- 'badaccess' => '',
- 'versionrequired' => '',
- 'miscellaneous3' => '',
- 'nstab' => "Short words for each namespace, by default used in the namespace tab in monobook",
- 'main' => 'Main script and global functions',
- 'errors' => 'General errors',
- 'virus' => 'Virus scanner',
- 'login' => 'Login and logout pages',
- 'mail' => 'Email sending',
- 'passwordstrength' => 'JavaScript password checks',
- 'resetpass' => 'Change password dialog',
- 'passwordreset' => 'Special:PasswordReset',
- 'changeemail' => 'Special:ChangeEmail',
- 'resettokens' => 'Special:ResetTokens',
- 'toolbar' => 'Edit page toolbar',
- 'edit' => 'Edit pages',
- 'parserwarnings' => 'Parser/template warnings',
- 'contentmodels' => 'Content models',
- 'undo' => '"Undo" feature',
- 'cantcreateaccount' => 'Account creation failure',
- 'history' => 'History pages',
- 'history-feed' => 'Revision feed',
- 'revdelete' => 'Revision deletion',
- 'suppression' => 'Suppression log',
- 'mergehistory' => 'History merging',
- 'mergelog' => 'Merge log',
- 'diffs' => 'Diffs',
- 'search' => 'Search results',
- 'opensearch' => 'OpenSearch description',
- 'preferences' => 'Preferences page',
- 'preferences-email' => 'User preference: email validation using jQuery',
- 'userrights' => 'User rights',
- 'group' => 'Groups',
- 'group-member' => '',
- 'grouppage' => '',
- 'right' => 'Rights',
- 'action' => 'Associated actions - in the sentence "You do not have permission to X"',
- 'rightslog' => 'User rights log',
- 'recentchanges' => 'Recent changes',
- 'recentchangeslinked' => 'Recent changes linked',
- 'upload' => 'Upload',
- 'zip' => 'ZipDirectoryReader',
- 'upload-errors' => '',
- 'filebackend-errors' => 'File backend',
- 'filejournal-errors' => 'File journal errors',
- 'lockmanager-errors' => 'Lock manager',
- 'uploadstash' => 'Special:UploadStash',
- 'img-auth' => 'img_auth script messages',
- 'http-errors' => 'HTTP errors',
- 'upload-curl-errors' => 'Some likely curl errors. More could be added from <http://curl.haxx.se/libcurl/c/libcurl-errors.html>',
- 'licenses' => '',
- 'filelist' => 'Special:ListFiles',
- 'filedescription' => 'File description page',
- 'filerevert' => 'File reversion',
- 'filedelete' => 'File deletion',
- 'mimesearch' => 'MIME search',
- 'unwatchedpages' => 'Unwatched pages',
- 'listredirects' => 'List redirects',
- 'unusedtemplates' => 'Unused templates',
- 'randompage' => 'Random page',
- 'randomincategory' => 'Random page in category',
- 'randomredirect' => 'Random redirect',
- 'statistics' => 'Statistics',
- 'pageswithprop' => '',
- 'doubleredirects' => '',
- 'brokenredirects' => '',
- 'withoutinterwiki' => '',
- 'fewestrevisions' => '',
- 'specialpages' => 'Miscellaneous special pages',
- 'booksources' => 'Book sources',
- 'magicwords' => 'Magic words',
- 'logpages' => 'Special:Log',
- 'allpages' => 'Special:AllPages',
- 'categories' => 'Special:Categories',
- 'deletedcontribs' => 'Special:DeletedContributions',
- 'linksearch' => 'Special:LinkSearch',
- 'listusers' => 'Special:ListUsers',
- 'activeusers' => 'Special:ActiveUsers',
- 'newuserlog' => 'Special:Log/newusers',
- 'listgrouprights' => 'Special:ListGroupRights',
- 'emailuser' => 'Email user',
- 'usermessage' => 'User Messenger',
- 'watchlist' => 'Watchlist',
- 'watching' => 'Displayed when you click the "watch" button and it is in the process of watching',
- 'enotif' => '',
- 'delete' => 'Delete',
- 'rollback' => 'Rollback',
- 'edittokens' => 'Edit tokens',
- 'protect' => 'Protect',
- 'restrictions' => 'Restrictions (nouns)',
- 'restriction-levels' => 'Restriction levels',
- 'undelete' => 'Undelete',
- 'nsform' => 'Namespace form on various pages',
- 'contributions' => 'Contributions',
- 'sp-contributions' => '',
- 'whatlinkshere' => 'What links here',
- 'block' => 'Block/unblock',
- 'developertools' => 'Developer tools',
- 'movepage' => 'Move page',
- 'export' => 'Export',
- 'allmessages' => 'Namespace 8 related',
- 'thumbnails' => 'Thumbnails',
- 'import' => 'Special:Import',
- 'importlog' => 'Import log',
- 'javaccripttest' => 'JavaScriptTest',
- 'accesskeys' => 'Keyboard access keys for power users',
- 'tooltips' => 'Tooltip help for the actions',
- 'stylesheets' => 'Stylesheets',
- 'scripts' => 'Scripts',
- 'metadata_cc' => 'Metadata',
- 'attribution' => 'Attribution',
- 'spamprotection' => 'Spam protection',
- 'info' => 'Info page',
- 'skin' => 'Skin names',
- 'patrolling' => 'Patrolling',
- 'patrol-log' => 'Patrol log',
- 'imagedeletion' => 'Image deletion',
- 'browsediffs' => 'Browsing diffs',
- 'newfiles' => 'Special:NewFiles',
- 'video-info' => 'Video information, used by Language::formatTimePeriod() to format lengths in the above messages',
- 'human-timestamps' => 'Human-readable timestamps',
- 'badimagelist' => 'Bad image list',
- 'variantname-zh' => "Short names for language variants used for language conversion links.
-Variants for Chinese language",
- 'variantname-gan' => 'Variants for Gan language',
- 'variantname-sr' => 'Variants for Serbian language',
- 'variantname-kk' => 'Variants for Kazakh language',
- 'variantname-ku' => 'Variants for Kurdish language',
- 'variantname-tg' => 'Variants for Tajiki language',
- 'variantname-iu' => 'Variants for Inuktitut language',
- 'variantname-shi' => 'Variants for Tachelhit language',
- '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',
- 'exif-compression' => 'Exif attributes',
- 'exif-copyrighted' => '',
- 'exif-unknowndate' => '',
- 'exif-photometricinterpretation' => '',
- 'exif-orientation' => '',
- 'exif-planarconfiguration' => '',
- 'exif-xyresolution' => '',
- 'exif-colorspace' => '',
- 'exif-componentsconfiguration' => '',
- 'exif-exposureprogram' => '',
- 'exif-subjectdistance-value' => '',
- 'exif-meteringmode' => '',
- 'exif-lightsource' => '',
- 'exif-flash' => 'Flash modes',
- 'exif-focalplaneresolutionunit' => '',
- 'exif-sensingmethod' => '',
- 'exif-filesource' => '',
- 'exif-scenetype' => '',
- 'exif-customrendered' => '',
- 'exif-exposuremode' => '',
- 'exif-whitebalance' => '',
- 'exif-scenecapturetype' => '',
- 'exif-gaincontrol' => '',
- 'exif-contrast' => '',
- 'exif-saturation' => '',
- 'exif-sharpness' => '',
- 'exif-subjectdistancerange' => '',
- 'exif-gpslatitude' => 'Pseudotags used for GPSLatitudeRef and GPSDestLatitudeRef',
- 'exif-gpslongitude' => 'Pseudotags used for GPSLongitudeRef and GPSDestLongitudeRef',
- 'exif-altituderef' => 'Pseudotags used for GPSAltitudeRef',
- 'exif-gpsstatus' => '',
- 'exif-gpsmeasuremode' => '',
- 'exif-gpsspeed' => 'Pseudotags used for GPSSpeedRef',
- 'exif-gpsdestdistanceref' => 'Pseudotags used for GPSDestDistanceRef',
- 'exif-gdop' => '',
- 'exif-objectcycle' => '',
- 'exif-gpsdirection' => 'Pseudotags used for GPSTrackRef, GPSImgDirectionRef and GPSDestBearingRef',
- 'exif-ycbcrpositioning' => '',
- 'exif-dc' => '',
- 'exif-rating' => '',
- 'exif-isospeedratings' => '',
- 'exif-maxaperturevalue' => '',
- 'exif-iimcategory' => '',
- 'exif-urgency' => '',
- 'edit-externally' => 'External editor support',
- 'all' => "'all' in various places, this might be different for inflected languages",
- 'confirmemail' => 'Email address confirmation',
- 'scarytransclusion' => 'Scary transclusion',
- 'deleteconflict' => 'Delete conflict',
- 'unit-pixel' => '',
- 'purge' => 'action=purge',
- 'watch-unwatch' => 'action=watch/unwatch',
- 'separators' => 'Separators for various lists, etc.',
- 'imgmulti' => 'Multipage image navigation',
- 'tablepager' => 'Table pager',
- 'autosumm' => 'Auto-summaries',
- 'autoblock_whitelist' => 'Autoblock whitelist',
- 'sizeunits' => 'Size units',
- 'bitrateunits' => 'Bitrate units',
- 'livepreview' => 'Live preview',
- 'lagwarning' => 'Friendlier slave lag warnings',
- 'watchlisteditor' => 'Watchlist editor',
- 'watchlisttools' => 'Watchlist editing tools',
- 'iranian-dates' => 'Iranian month names',
- 'hijri-dates' => 'Hijri month names',
- 'hebrew-dates' => 'Hebrew month names',
- 'signatures' => 'Signatures',
- 'CoreParserFunctions' => 'Core parser functions',
- 'version' => 'Special:Version',
- 'redirect' => 'Special:Redirect',
- 'fileduplicatesearch' => 'Special:FileDuplicateSearch',
- 'special-specialpages' => 'Special:SpecialPages',
- 'special-blank' => 'Special:BlankPage',
- 'external_images' => 'External image whitelist',
- 'special-tags' => 'Special:Tags',
- 'comparepages' => 'Special:ComparePages',
- 'db-error-messages' => 'Database error messages',
- 'html-forms' => 'HTML forms',
- 'sqlite' => 'SQLite database support',
- 'logging' => 'New logging system',
- 'logging-irc' => 'For IRC, see bug 34508. Do not change',
- 'feedback' => 'Feedback',
- 'searchsuggestions' => 'Search suggestions',
- 'apierrors' => 'API errors',
- 'duration' => 'Durations',
- 'cachedspecial' => 'SpecialCachedPage',
- 'rotation' => 'Image rotation',
- 'limitreport' => 'Limit report',
-);
diff --git a/maintenance/language/rebuildLanguage.php b/maintenance/language/rebuildLanguage.php
deleted file mode 100644
index 66948aeb..00000000
--- a/maintenance/language/rebuildLanguage.php
+++ /dev/null
@@ -1,126 +0,0 @@
-<?php
-/**
- * Rewrite the messages array in the files languages/messages/MessagesXx.php.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup MaintenanceLanguage
- * @defgroup MaintenanceLanguage MaintenanceLanguage
- */
-
-require_once __DIR__ . '/../commandLine.inc';
-require_once 'languages.inc';
-require_once 'writeMessagesArray.inc';
-
-/**
- * Rewrite a messages array.
- *
- * @param $languages
- * @param $code string The language code.
- * @param bool $write Write to the messages file?
- * @param bool $listUnknown List the unknown messages?
- * @param bool $removeUnknown Remove the unknown messages?
- * @param bool $removeDupes Remove the duplicated messages?
- * @param $dupeMsgSource string The source file intended to remove from the array.
- * @param $messagesFolder String: path to a folder to store the MediaWiki messages.
- */
-function rebuildLanguage( $languages, $code, $write, $listUnknown, $removeUnknown, $removeDupes, $dupeMsgSource, $messagesFolder ) {
- $messages = $languages->getMessages( $code );
- $messages = $messages['all'];
- if ( $removeDupes ) {
- $messages = removeDupes( $messages, $dupeMsgSource );
- }
- MessageWriter::writeMessagesToFile( $messages, $code, $write, $listUnknown, $removeUnknown, $messagesFolder );
-}
-
-/**
- * Remove duplicates from a message array.
- *
- * @param $oldMsgArray array The input message array.
- * @param $dupeMsgSource string The source file path for duplicates.
- * @return Array $newMsgArray The output message array, with duplicates removed.
- */
-function removeDupes( $oldMsgArray, $dupeMsgSource ) {
- if ( file_exists( $dupeMsgSource ) ) {
- include $dupeMsgSource;
- if ( !isset( $dupeMessages ) ) {
- echo "There are no duplicated messages in the source file provided.";
- exit( 1 );
- }
- } else {
- echo "The specified file $dupeMsgSource cannot be found.";
- exit( 1 );
- }
- $newMsgArray = $oldMsgArray;
- foreach ( $oldMsgArray as $key => $value ) {
- if ( array_key_exists( $key, $dupeMessages ) ) {
- unset( $newMsgArray[$key] );
- }
- }
- return $newMsgArray;
-}
-
-# Show help
-if ( isset( $options['help'] ) ) {
- echo <<<TEXT
-Run this script to rewrite the messages array in the files languages/messages/MessagesXX.php.
-Parameters:
- * lang: Language code (default: the installation default language). You can also specify "all" to check all the languages.
- * help: Show this help.
-Options:
- * dry-run: Do not write the array to the file.
- * no-unknown: Do not list the unknown messages.
- * remove-unknown: Remove unknown messages.
- * remove-duplicates: Remove duplicated messages based on a PHP source file.
- * messages-folder: An alternative folder with MediaWiki messages.
-
-TEXT;
- exit( 1 );
-}
-
-# Get the language code
-if ( isset( $options['lang'] ) ) {
- $wgCode = $options['lang'];
-} else {
- $wgCode = $wgContLang->getCode();
-}
-
-# Get the duplicate message source
-if ( isset( $options['remove-duplicates'] ) && ( strcmp( $options['remove-duplicates'], '' ) ) ) {
- $wgDupeMessageSource = $options['remove-duplicates'];
-} else {
- $wgDupeMessageSource = '';
-}
-
-# Get the options
-$wgWriteToFile = !isset( $options['dry-run'] );
-$wgListUnknownMessages = !isset( $options['no-unknown'] );
-$wgRemoveUnknownMessages = isset( $options['remove-unknown'] );
-$wgRemoveDuplicateMessages = isset( $options['remove-duplicates'] );
-$messagesFolder = isset( $options['messages-folder'] ) ? $options['messages-folder'] : false;
-
-# Get language objects
-$languages = new languages();
-
-# Write all the language
-if ( $wgCode == 'all' ) {
- foreach ( $languages->getLanguages() as $languageCode ) {
- rebuildLanguage( $languages, $languageCode, $wgWriteToFile, $wgListUnknownMessages, $wgRemoveUnknownMessages, $wgRemoveDuplicateMessages, $wgDupeMessageSource, $messagesFolder );
- }
-} else {
- rebuildLanguage( $languages, $wgCode, $wgWriteToFile, $wgListUnknownMessages, $wgRemoveUnknownMessages, $wgRemoveDuplicateMessages, $wgDupeMessageSource, $messagesFolder );
-}
diff --git a/maintenance/language/transstat.php b/maintenance/language/transstat.php
index 61b84a07..4a853b0f 100644
--- a/maintenance/language/transstat.php
+++ b/maintenance/language/transstat.php
@@ -24,7 +24,7 @@
* @author Antoine Musso <hashar at free dot fr>
*
* Output is posted from time to time on:
- * http://www.mediawiki.org/wiki/Localisation_statistics
+ * https://www.mediawiki.org/wiki/Localisation_statistics
*/
$optionsWithArgs = array( 'output' );
@@ -32,7 +32,6 @@ require_once __DIR__ . '/../commandLine.inc';
require_once 'languages.inc';
require_once __DIR__ . '/StatOutputs.php';
-
if ( isset( $options['help'] ) ) {
showUsage();
}
@@ -57,25 +56,23 @@ TEXT;
exit( 1 );
}
-
-
# Select an output engine
switch ( $options['output'] ) {
case 'wiki':
- $output = new wikiStatsOutput();
+ $output = new WikiStatsOutput();
break;
case 'text':
- $output = new textStatsOutput();
+ $output = new TextStatsOutput();
break;
case 'csv':
- $output = new csvStatsOutput();
+ $output = new CsvStatsOutput();
break;
default:
showUsage();
}
# Languages
-$wgLanguages = new languages();
+$wgLanguages = new Languages();
# Header
$output->heading();
@@ -97,7 +94,8 @@ $wgRequiredMessagesNumber = count( $wgGeneralMessages['required'] );
foreach ( $wgLanguages->getLanguages() as $code ) {
# Don't check English, RTL English or dummy language codes
if ( $code == 'en' || $code == 'enRTL' || ( is_array( $wgDummyLanguageCodes ) &&
- isset( $wgDummyLanguageCodes[$code] ) ) ) {
+ isset( $wgDummyLanguageCodes[$code] ) )
+ ) {
continue;
}
@@ -107,16 +105,33 @@ foreach ( $wgLanguages->getLanguages() as $code ) {
$messages = $wgLanguages->getMessages( $code );
$messagesNumber = count( $messages['translated'] );
$requiredMessagesNumber = count( $messages['required'] );
- $requiredMessagesPercent = $output->formatPercent( $requiredMessagesNumber, $wgRequiredMessagesNumber );
+ $requiredMessagesPercent = $output->formatPercent(
+ $requiredMessagesNumber,
+ $wgRequiredMessagesNumber
+ );
$obsoleteMessagesNumber = count( $messages['obsolete'] );
- $obsoleteMessagesPercent = $output->formatPercent( $obsoleteMessagesNumber, $messagesNumber, true );
+ $obsoleteMessagesPercent = $output->formatPercent(
+ $obsoleteMessagesNumber,
+ $messagesNumber,
+ true
+ );
$messagesWithMismatchVariables = $wgLanguages->getMessagesWithMismatchVariables( $code );
$emptyMessages = $wgLanguages->getEmptyMessages( $code );
$messagesWithWhitespace = $wgLanguages->getMessagesWithWhitespace( $code );
$nonXHTMLMessages = $wgLanguages->getNonXHTMLMessages( $code );
$messagesWithWrongChars = $wgLanguages->getMessagesWithWrongChars( $code );
- $problematicMessagesNumber = count( array_unique( array_merge( $messagesWithMismatchVariables, $emptyMessages, $messagesWithWhitespace, $nonXHTMLMessages, $messagesWithWrongChars ) ) );
- $problematicMessagesPercent = $output->formatPercent( $problematicMessagesNumber, $messagesNumber, true );
+ $problematicMessagesNumber = count( array_unique( array_merge(
+ $messagesWithMismatchVariables,
+ $emptyMessages,
+ $messagesWithWhitespace,
+ $nonXHTMLMessages,
+ $messagesWithWrongChars
+ ) ) );
+ $problematicMessagesPercent = $output->formatPercent(
+ $problematicMessagesNumber,
+ $messagesNumber,
+ true
+ );
# Output them
$output->blockstart();
diff --git a/maintenance/language/validate.php b/maintenance/language/validate.php
deleted file mode 100644
index 63d9b847..00000000
--- a/maintenance/language/validate.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-/**
- * Check language files for unrecognised variables.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup MaintenanceLanguage
- */
-
-if ( PHP_SAPI != 'cli' ) {
- die( "Run me from the command line please.\n" );
-}
-
-if ( !isset( $argv[1] ) ) {
- print "Usage: php {$argv[0]} <filename>\n";
- exit( 1 );
-}
-array_shift( $argv );
-
-define( 'MEDIAWIKI', 1 );
-define( 'NOT_REALLY_MEDIAWIKI', 1 );
-
-$IP = __DIR__ . '/../..';
-
-require_once "$IP/includes/Defines.php";
-require_once "$IP/languages/Language.php";
-
-$files = array();
-foreach ( $argv as $arg ) {
- $files = array_merge( $files, glob( $arg ) );
-}
-
-foreach ( $files as $filename ) {
- print "$filename...";
- $vars = getVars( $filename );
- $keys = array_keys( $vars );
- $diff = array_diff( $keys, Language::$mLocalisationKeys );
- if ( $diff ) {
- print "\nWarning: unrecognised variable(s): " . implode( ', ', $diff ) . "\n";
- } else {
- print " ok\n";
- }
-}
-
-function getVars( $filename ) {
- require $filename;
- $vars = get_defined_vars();
- unset( $vars['filename'] );
- return $vars;
-}
diff --git a/maintenance/language/writeMessagesArray.inc b/maintenance/language/writeMessagesArray.inc
deleted file mode 100644
index fc0da3f5..00000000
--- a/maintenance/language/writeMessagesArray.inc
+++ /dev/null
@@ -1,283 +0,0 @@
-<?php
-/**
- * Write a messages array as a PHP text.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup MaintenanceLanguage
- */
-
-/**
- * @ingroup MaintenanceLanguage
- */
-class MessageWriter {
- static $optionalComment = 'only translate this message to other languages if you have to change it';
- static $ignoredComment = "do not translate or duplicate this message to other languages";
-
- static $messageStructure;
- static $blockComments;
- static $ignoredMessages;
- static $optionalMessages;
-
- /**
- * Write a messages array as a PHP text and write it to the messages file.
- *
- * @param $messages Array: the messages array.
- * @param $code String: the language code.
- * @param $write Boolean: write to the messages file?
- * @param $listUnknown Boolean: list the unknown messages?
- * @param $removeUnknown Boolean: whether to remove unkown messages
- * @param $messagesFolder String: path to a folder to store the MediaWiki messages. Defaults to the current install.
- */
- public static function writeMessagesToFile( $messages, $code, $write, $listUnknown, $removeUnknown, $messagesFolder = false ) {
- # Rewrite the messages array
- $messages = self::writeMessagesArray( $messages, $code == 'en', false, $removeUnknown );
- $messagesText = $messages[0];
- $sortedMessages = $messages[1];
-
- # Write to the file
- if ( $messagesFolder ) {
- $filename = Language::getFileName( "$messagesFolder/Messages", $code );
- } else {
- $filename = Language::getMessagesFileName( $code );
- }
-
- if ( file_exists( $filename ) ) {
- $contents = file_get_contents( $filename );
- } else {
- $contents = '<?php
-$messages = array(
-);
-';
- }
-
- if ( strpos( $contents, '$messages' ) !== false ) {
- $contents = explode( '$messages', $contents );
- if ( $messagesText == '$messages' . $contents[1] ) {
- echo "Generated messages for language $code. Same as the current file.\n";
- } else {
- if ( $write ) {
- $new = $contents[0];
- $new .= $messagesText;
- 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'] ) ) {
- if ( $removeUnknown ) {
- echo "\nThe following " . count( $sortedMessages['unknown'] ) . " unknown messages have been removed:\n";
- } else {
- echo "\nThere are " . count( $sortedMessages['unknown'] ) . " unknown messages, please check them:\n";
- }
- foreach ( $sortedMessages['unknown'] as $key => $value ) {
- echo "* " . $key . "\n";
- }
- }
- } else {
- echo "Generated messages for language $code. There seem to be no messages array in the file.\n";
- }
- }
-
- /**
- * Write a messages array as a PHP text.
- *
- * @param $messages Array: the messages array.
- * @param $ignoredComments Boolean: show comments about ignored and optional
- * messages? (For English.)
- * @param $prefix String: base path for messages.inc and messageTypes.inc files
- * or false for default path (this directory)
- * @param $removeUnknown Boolean: whether to remove unkown messages
- *
- * @return Array of the PHP text and the sorted messages array.
- */
- public static function writeMessagesArray( $messages, $ignoredComments = false, $prefix = false, $removeUnknown = false ) {
- # Load messages
- $dir = $prefix ? $prefix : __DIR__;
-
- require $dir . '/messages.inc';
- self::$messageStructure = $wgMessageStructure;
- self::$blockComments = $wgBlockComments;
-
- require $dir . '/messageTypes.inc';
- self::$ignoredMessages = $wgIgnoredMessages;
- self::$optionalMessages = $wgOptionalMessages;
-
- # Sort messages to blocks
- $sortedMessages['unknown'] = $messages;
- foreach ( self::$messageStructure as $blockName => $block ) {
- /**
- * @var $block array
- */
- foreach ( $block as $key ) {
- if ( array_key_exists( $key, $sortedMessages['unknown'] ) ) {
- $sortedMessages[$blockName][$key] = $sortedMessages['unknown'][$key];
- unset( $sortedMessages['unknown'][$key] );
- }
- }
- }
-
- # Write all the messages
- $messagesText = "\$messages = array(
-";
- foreach ( $sortedMessages as $block => $messages ) {
- # Skip if it's the block of unknown messages - handle that in the end of file
- if ( $block == 'unknown' ) {
- continue;
- }
-
- if ( $ignoredComments ) {
- $ignored = self::$ignoredMessages;
- $optional = self::$optionalMessages;
- } else {
- $ignored = array();
- $optional = array();
- }
- $comments = self::makeComments( array_keys( $messages ), $ignored, $optional );
-
- # Write the block
- $messagesText .= self::writeMessagesBlock( self::$blockComments[$block], $messages, $comments );
- }
-
- # Write the unknown messages, alphabetically sorted.
- # Of course, we don't have any comments for them, because they are unknown.
- if ( !$removeUnknown ) {
- ksort( $sortedMessages['unknown'] );
- $messagesText .= self::writeMessagesBlock( 'Unknown messages', $sortedMessages['unknown'] );
- }
- $messagesText .= ");
-";
- return array( $messagesText, $sortedMessages );
- }
-
- /**
- * Generates an array of comments for messages.
- *
- * @param $messages Array: key of messages.
- * @param $ignored Array: list of ingored message keys.
- * @param $optional Array: list of optional message keys.
- * @return array
- */
- public static function makeComments( $messages, $ignored, $optional ) {
- # Comment collector
- $commentArray = array();
-
- # List of keys only
- foreach ( $messages as $key ) {
- if ( in_array( $key, $ignored ) ) {
- $commentArray[$key] = ' # ' . self::$ignoredComment;
- } elseif ( in_array( $key, $optional ) ) {
- $commentArray[$key] = ' # ' . self::$optionalComment;
- }
- }
-
- return $commentArray;
- }
-
- /**
- * Write a block of messages to PHP.
- *
- * @param $blockComment String: the comment of whole block.
- * @param $messages Array: the block messages.
- * @param $messageComments Array: optional comments for messages in this block.
- * @param $prefix String: prefix for every line, for indenting purposes.
- *
- * @return string The block, formatted in PHP.
- */
- public static function writeMessagesBlock( $blockComment, $messages,
- $messageComments = array(), $prefix = '' ) {
-
- $blockText = '';
-
- # Skip the block if it includes no messages
- if ( empty( $messages ) ) {
- return '';
- }
-
- # Format the block comment (if exists); check for multiple lines comments
- if ( !empty( $blockComment ) ) {
- if ( strpos( $blockComment, "\n" ) === false ) {
- $blockText .= "$prefix# $blockComment
-";
- } else {
- $blockText .= "$prefix/*
-$blockComment
-*/
-";
- }
- }
-
- # Get max key length
- $maxKeyLength = max( array_map( 'strlen', array_keys( $messages ) ) );
-
- # Format the messages
- foreach ( $messages as $key => $value ) {
- # Add the key name
- $blockText .= "$prefix'$key'";
-
- # Add the appropriate block whitespace
- $blockText .= str_repeat( ' ', $maxKeyLength - strlen( $key ) );
-
- # Refer to the value
- $blockText .= ' => ';
-
- # Check for the appropriate apostrophe and add the value
- # Quote \ here, because it needs always escaping
- $value = addcslashes( $value, '\\' );
-
- # For readability
- $single = "'";
- $double = '"';
-
- if ( strpos( $value, $single ) === false ) {
- # Nothing ugly, just use '
- $blockText .= $single . $value . $single;
- } elseif ( strpos( $value, $double ) === false && !preg_match( '/\$[a-zA-Z_\x7f-\xff]/', $value ) ) {
- # No "-quotes, no variables that need quoting, use "
- $blockText .= $double . $value . $double;
- } else {
- # Something needs quoting, pick the quote which causes less quoting
- $quote = substr_count( $value, $double ) + substr_count( $value, '$' ) >= substr_count( $value, $single ) ? $single : $double;
- if ( $quote === $double ) {
- $extra = '$';
- } else {
- $extra = '';
- }
- $blockText .= $quote . addcslashes( $value, $quote . $extra ) . $quote;
- }
-
- # Comma
- $blockText .= ',';
-
- # Add comments, if there is any
- if ( array_key_exists( $key, $messageComments ) ) {
- $blockText .= $messageComments[$key];
- }
-
- # Newline
- $blockText .= "
-";
- }
-
- # Newline to end the block
- $blockText .= "
-";
-
- return $blockText;
- }
-}
diff --git a/maintenance/language/zhtable/Makefile.py b/maintenance/language/zhtable/Makefile.py
index 7e197945..f902e581 100644
--- a/maintenance/language/zhtable/Makefile.py
+++ b/maintenance/language/zhtable/Makefile.py
@@ -30,9 +30,9 @@ def unichr3( *args ):
return [unichr( int( i[2:7], 16 ) ) for i in args if i[2:7]]
# DEFINE
-UNIHAN_VER = '6.2.0'
+UNIHAN_VER = '6.3.0'
SF_MIRROR = 'dfn'
-SCIM_TABLES_VER = '0.5.11'
+SCIM_TABLES_VER = '0.5.13'
SCIM_PINYIN_VER = '0.5.92'
LIBTABE_VER = '0.2.3'
# END OF DEFINE
@@ -59,7 +59,11 @@ def uncompress( fp, member, encoding = 'U8' ):
shutil.move( member, name )
if '/' in member:
shutil.rmtree( member.split( '/', 1 )[0] )
- return open( name, 'rb', encoding, 'ignore' )
+ if pyversion[:1] in ['2']:
+ fc = open( name, 'rb', encoding, 'ignore' )
+ else:
+ fc = open( name, 'r', encoding = encoding, errors = 'ignore' )
+ return fc
unzip = lambda path, member, encoding = 'U8': \
uncompress( zf.ZipFile( path ), member, encoding )
@@ -136,7 +140,10 @@ def unihanParser( path ):
def applyExcludes( mlist, path ):
""" Apply exclude rules from path to mlist. """
- excludes = open( path, 'rb', 'U8' ).read().split()
+ if pyversion[:1] in ['2']:
+ excludes = open( path, 'rb', 'U8' ).read().split()
+ else:
+ excludes = open( path, 'r', encoding = 'U8' ).read().split()
excludes = [word.split( '#' )[0].strip() for word in excludes]
excludes = '|'.join( excludes )
excptn = re.compile( '.*(?:%s).*' % excludes )
@@ -145,7 +152,7 @@ def applyExcludes( mlist, path ):
return mlist
def charManualTable( path ):
- fp = open( path, 'rb', 'U8' )
+ fp = open( path, 'r', encoding = 'U8' )
ret = {}
for line in fp:
elems = line.split( '#' )[0].split( '|' )
@@ -156,13 +163,18 @@ def charManualTable( path ):
def toManyRules( src_table ):
tomany = set()
- for ( f, t ) in src_table.iteritems():
- for i in range( 1, len( t ) ):
- tomany.add( t[i] )
+ if pyversion[:1] in ['2']:
+ for ( f, t ) in src_table.iteritems():
+ for i in range( 1, len( t ) ):
+ tomany.add( t[i] )
+ else:
+ for ( f, t ) in src_table.items():
+ for i in range( 1, len( t ) ):
+ tomany.add( t[i] )
return tomany
def removeRules( path, table ):
- fp = open( path, 'rb', 'U8' )
+ fp = open( path, 'r', encoding = 'U8' )
texc = list()
for line in fp:
elems = line.split( '=>' )
@@ -179,13 +191,18 @@ def removeRules( path, table ):
if t:
texc.append( t )
texcptn = re.compile( '^(?:%s)$' % '|'.join( texc ) )
- for (tmp_f, tmp_t) in table.copy().iteritems():
- if texcptn.match( tmp_t ):
- table.pop( tmp_f )
+ if pyversion[:1] in ['2']:
+ for (tmp_f, tmp_t) in table.copy().iteritems():
+ if texcptn.match( tmp_t ):
+ table.pop( tmp_f )
+ else:
+ for (tmp_f, tmp_t) in table.copy().items():
+ if texcptn.match( tmp_t ):
+ table.pop( tmp_f )
return table
def customRules( path ):
- fp = open( path, 'rb', 'U8' )
+ fp = open( path, 'r', encoding = 'U8' )
ret = dict()
for line in fp:
elems = line.split( '#' )[0].split()
@@ -210,7 +227,7 @@ def translate( text, conv_table ):
return text
def manualWordsTable( path, conv_table, reconv_table ):
- fp = open( path, 'rb', 'U8' )
+ fp = open( path, 'r', encoding = 'U8' )
reconv_table = {}
wordlist = [line.split( '#' )[0].strip() for line in fp]
wordlist = list( set( wordlist ) )
@@ -285,8 +302,12 @@ def main():
t2s_1tomany.update( charManualTable( 'trad2simp.manual' ) )
s2t_1tomany.update( charManualTable( 'simp2trad.manual' ) )
- t2s_1to1 = dict( [( f, t[0] ) for ( f, t ) in t2s_1tomany.iteritems()] )
- s2t_1to1 = dict( [( f, t[0] ) for ( f, t ) in s2t_1tomany.iteritems()] )
+ if pyversion[:1] in ['2']:
+ t2s_1to1 = dict( [( f, t[0] ) for ( f, t ) in t2s_1tomany.iteritems()] )
+ s2t_1to1 = dict( [( f, t[0] ) for ( f, t ) in s2t_1tomany.iteritems()] )
+ else:
+ t2s_1to1 = dict( [( f, t[0] ) for ( f, t ) in t2s_1tomany.items()] )
+ s2t_1to1 = dict( [( f, t[0] ) for ( f, t ) in s2t_1tomany.items()] )
s_tomany = toManyRules( t2s_1tomany )
t_tomany = toManyRules( s2t_1tomany )
@@ -333,10 +354,16 @@ def main():
# Final tables
# sorted list toHans
- t2s_1to1 = dict( [( f, t ) for ( f, t ) in t2s_1to1.iteritems() if f != t] )
+ if pyversion[:1] in ['2']:
+ t2s_1to1 = dict( [( f, t ) for ( f, t ) in t2s_1to1.iteritems() if f != t] )
+ else:
+ t2s_1to1 = dict( [( f, t ) for ( f, t ) in t2s_1to1.items() if f != t] )
toHans = dictToSortedList( t2s_1to1, 0 ) + dictToSortedList( t2s_word2word, 1 )
# sorted list toHant
- s2t_1to1 = dict( [( f, t ) for ( f, t ) in s2t_1to1.iteritems() if f != t] )
+ if pyversion[:1] in ['2']:
+ s2t_1to1 = dict( [( f, t ) for ( f, t ) in s2t_1to1.iteritems() if f != t] )
+ else:
+ s2t_1to1 = dict( [( f, t ) for ( f, t ) in s2t_1to1.items() if f != t] )
toHant = dictToSortedList( s2t_1to1, 0 ) + dictToSortedList( s2t_word2word, 1 )
# sorted list toCN
toCN = dictToSortedList( customRules( 'toCN.manual' ), 1 )
@@ -352,7 +379,7 @@ def main():
/**
* Simplified / Traditional Chinese conversion tables
*
- * Automatically generated using code and data in includes/zhtable/
+ * Automatically generated using code and data in maintenance/language/zhtable/
* Do not modify directly!
*
* @file
@@ -372,7 +399,10 @@ $zh2Hant = array(\n'''
+ PHPArray( toSG ) \
+ '\n);\n'
- f = open( os.path.join( '..', '..', '..', 'includes', 'ZhConversion.php' ), 'wb', encoding = 'utf8' )
+ if pyversion[:1] in ['2']:
+ f = open( os.path.join( '..', '..', '..', 'includes', 'ZhConversion.php' ), 'wb', encoding = 'utf8' )
+ else:
+ f = open( os.path.join( '..', '..', '..', 'includes', 'ZhConversion.php' ), 'w', buffering = 4096, encoding = 'utf8' )
print ('Writing ZhConversion.php ... ')
f.write( php )
f.close()
diff --git a/maintenance/language/zhtable/trad2simp_supp_unset.manual b/maintenance/language/zhtable/trad2simp_supp_unset.manual
deleted file mode 100644
index e69de29b..00000000
--- a/maintenance/language/zhtable/trad2simp_supp_unset.manual
+++ /dev/null
diff --git a/maintenance/language/zhtable/tradphrases.manual b/maintenance/language/zhtable/tradphrases.manual
index e20ca05b..69b2c832 100644
--- a/maintenance/language/zhtable/tradphrases.manual
+++ b/maintenance/language/zhtable/tradphrases.manual
@@ -3991,6 +3991,7 @@
學裡
獄裡
館裡
+箱裡
系列裡
村子裡
艷后
diff --git a/maintenance/locking/LockServerDaemon.php b/maintenance/locking/LockServerDaemon.php
deleted file mode 100644
index 01fbac72..00000000
--- a/maintenance/locking/LockServerDaemon.php
+++ /dev/null
@@ -1,640 +0,0 @@
-<?php
-/**
- * Simple lock server daemon that accepts lock/unlock requests.
- *
- * This code should not require MediaWiki setup or PHP files.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup LockManager Maintenance
- */
-
-if ( PHP_SAPI !== 'cli' ) {
- die( "This is not a valid entry point.\n" );
-}
-error_reporting( E_ALL );
-
-// Run the server...
-set_time_limit( 0 );
-LockServerDaemon::init(
- getopt( '', array(
- 'address:', 'port:', 'authKey:',
- 'lockTimeout::', 'maxClients::', 'maxBacklog::', 'maxLocks::',
- ) )
-)->main();
-
-/**
- * Simple lock server daemon that accepts lock/unlock requests
- *
- * @ingroup LockManager Maintenance
- */
-class LockServerDaemon {
- /** @var resource */
- protected $sock; // socket to listen/accept on
- /** @var Array */
- protected $sessions = array(); // (session => resource)
- /** @var Array */
- protected $deadSessions = array(); // (session => UNIX timestamp)
-
- /** @var LockHolder */
- protected $lockHolder;
-
- protected $address; // string IP address
- protected $port; // integer
- protected $authKey; // string key
- protected $lockTimeout; // integer number of seconds
- protected $maxBacklog; // integer
- protected $maxClients; // integer
-
- protected $startTime; // integer UNIX timestamp
- protected $ticks = 0; // integer counter
-
- /* @var LockServerDaemon */
- protected static $instance = null;
-
- /**
- * @params $config Array
- * @param array $config
- * @throws Exception
- * @return LockServerDaemon
- */
- public static function init( array $config ) {
- if ( self::$instance ) {
- throw new Exception( 'LockServer already initialized.' );
- }
- foreach ( array( 'address', 'port', 'authKey' ) as $par ) {
- if ( !isset( $config[$par] ) ) {
- die( "Usage: php LockServerDaemon.php " .
- "--address <address> --port <port> --authKey <key> " .
- "[--lockTimeout <seconds>] " .
- "[--maxLocks <integer>] [--maxClients <integer>] [--maxBacklog <integer>]\n"
- );
- }
- }
- self::$instance = new self( $config );
- return self::$instance;
- }
-
- /**
- * @params $config Array
- */
- protected function __construct( array $config ) {
- // Required parameters...
- $this->address = $config['address'];
- $this->port = $config['port'];
- $this->authKey = $config['authKey'];
- // Parameters with defaults...
- $this->lockTimeout = isset( $config['lockTimeout'] )
- ? (int)$config['lockTimeout']
- : 60;
- $this->maxClients = isset( $config['maxClients'] )
- ? (int)$config['maxClients']
- : 1000; // less than default FD_SETSIZE
- $this->maxBacklog = isset( $config['maxBacklog'] )
- ? (int)$config['maxBacklog']
- : 100;
- $maxLocks = isset( $config['maxLocks'] )
- ? (int)$config['maxLocks']
- : 10000;
-
- $this->lockHolder = new LockHolder( $maxLocks );
- }
-
- /**
- * @throws Exception
- * @return void
- */
- protected function setupServerSocket() {
- if ( !function_exists( 'socket_create' ) ) {
- throw new Exception( "PHP sockets extension missing from PHP CLI mode." );
- }
- $sock = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
- if ( $sock === false ) {
- throw new Exception( "socket_create(): " . socket_strerror( socket_last_error() ) );
- }
- socket_set_option( $sock, SOL_SOCKET, SO_REUSEADDR, 1 ); // bypass 2MLS
- socket_set_nonblock( $sock ); // don't block on accept()
- if ( socket_bind( $sock, $this->address, $this->port ) === false ) {
- throw new Exception( "socket_bind(): " .
- socket_strerror( socket_last_error( $sock ) ) );
- } elseif ( socket_listen( $sock, $this->maxBacklog ) === false ) {
- throw new Exception( "socket_listen(): " .
- socket_strerror( socket_last_error( $sock ) ) );
- }
- $this->sock = $sock;
- $this->startTime = time();
- }
-
- /**
- * Entry-point function that listens to the server socket, accepts
- * new clients, and recieves/responds to requests to lock resources.
- */
- public function main() {
- $this->setupServerSocket(); // setup listening socket
- $socketArray = new SocketArray(); // sockets being serviced
- $socketArray->addSocket( $this->sock ); // add listening socket
- do {
- list( $read, $write ) = $socketArray->socketsForSelect();
- if ( socket_select( $read, $write, $except = NULL, NULL ) < 1 ) {
- continue; // wait
- }
- // Check if there is a client trying to connect...
- if ( in_array( $this->sock, $read ) && $socketArray->size() < $this->maxClients ) {
- $newSock = socket_accept( $this->sock );
- if ( $newSock ) {
- socket_set_option( $newSock, SOL_SOCKET, SO_KEEPALIVE, 1 );
- socket_set_nonblock( $newSock ); // don't block on read()/write()
- $socketArray->addSocket( $newSock );
- }
- }
- // Loop through all the clients that have data to read...
- foreach ( $read as $read_sock ) {
- if ( $read_sock === $this->sock ) {
- continue; // skip listening socket
- }
- // Avoids PHP_NORMAL_READ per https://bugs.php.net/bug.php?id=33471
- $data = socket_read( $read_sock, 65535 );
- // Check if the client is disconnected
- if ( $data === false || $data === '' ) {
- $socketArray->closeSocket( $read_sock );
- $this->recordDeadSocket( $read_sock ); // remove session
- // Check if we reached the end of a message
- } elseif ( substr( $data, -1 ) === "\n" ) {
- // Newline is the last char (given ping-pong message usage)
- $cmd = $socketArray->readRcvBuffer( $read_sock ) . $data;
- // Perform the requested command...
- $response = $this->doCommand( rtrim( $cmd ), $read_sock );
- // Send the response to the client...
- $socketArray->appendSndBuffer( $read_sock, $response . "\n" );
- // Otherwise, we just have more message data to append
- } elseif ( !$socketArray->appendRcvBuffer( $read_sock, $data ) ) {
- $socketArray->closeSocket( $read_sock ); // too big
- $this->recordDeadSocket( $read_sock ); // remove session
- }
- }
- // Loop through all the clients that have data to write...
- foreach ( $write as $write_sock ) {
- $bytes = socket_write( $write_sock, $socketArray->readSndBuffer( $write_sock ) );
- // Check if the client is disconnected
- if ( $bytes === false ) {
- $socketArray->closeSocket( $write_sock );
- $this->recordDeadSocket( $write_sock ); // remove session
- // Otherwise, truncate these bytes from the start of the write buffer
- } else {
- $socketArray->consumeSndBuffer( $write_sock, $bytes );
- }
- }
- // Prune dead locks every few socket events...
- if ( ++$this->ticks >= 9 ) {
- $this->ticks = 0;
- $this->purgeExpiredLocks();
- }
- } while ( true );
- }
-
- /**
- * @param $data string
- * @param $sourceSock resource
- * @return string
- */
- protected function doCommand( $data, $sourceSock ) {
- $cmdArr = $this->getCommand( $data );
- if ( is_string( $cmdArr ) ) {
- return $cmdArr; // error
- }
- list( $function, $session, $type, $resources ) = $cmdArr;
- // On first command, track the session => sock correspondence
- if ( !isset( $this->sessions[$session] ) ) {
- $this->sessions[$session] = $sourceSock;
- unset( $this->deadSessions[$session] ); // renew if dead
- }
- if ( $function === 'ACQUIRE' ) {
- return $this->lockHolder->lock( $session, $type, $resources );
- } elseif ( $function === 'RELEASE' ) {
- return $this->lockHolder->unlock( $session, $type, $resources );
- } elseif ( $function === 'RELEASE_ALL' ) {
- return $this->lockHolder->release( $session );
- } elseif ( $function === 'STAT' ) {
- return $this->stat();
- }
- return 'INTERNAL_ERROR';
- }
-
- /**
- * @param $data string
- * @return Array
- */
- protected function getCommand( $data ) {
- $m = explode( ':', $data ); // <session, key, command, type, values>
- if ( count( $m ) == 5 ) {
- list( $session, $key, $command, $type, $values ) = $m;
- $goodKey = hash_hmac( 'sha1',
- "{$session}\n{$command}\n{$type}\n{$values}", $this->authKey );
- if ( $goodKey !== $key ) {
- return 'BAD_KEY';
- } elseif ( strlen( $session ) !== 32 ) {
- return 'BAD_SESSION';
- }
- $values = explode( '|', $values );
- if ( $command === 'ACQUIRE' ) {
- $needsLockArgs = true;
- } elseif ( $command === 'RELEASE' ) {
- $needsLockArgs = true;
- } elseif ( $command === 'RELEASE_ALL' ) {
- $needsLockArgs = false;
- } elseif ( $command === 'STAT' ) {
- $needsLockArgs = false;
- } else {
- return 'BAD_COMMAND';
- }
- if ( $needsLockArgs ) {
- if ( $type !== 'SH' && $type !== 'EX' ) {
- return 'BAD_TYPE';
- }
- foreach ( $values as $value ) {
- if ( strlen( $value ) !== 31 ) {
- return 'BAD_FORMAT';
- }
- }
- }
- return array( $command, $session, $type, $values );
- }
- return 'BAD_FORMAT';
- }
-
- /**
- * Remove a socket's corresponding session from tracking and
- * store it in the dead session tracking if it still has locks.
- *
- * @param $socket resource
- * @return bool
- */
- protected function recordDeadSocket( $socket ) {
- $session = array_search( $socket, $this->sessions );
- if ( $session !== false ) {
- unset( $this->sessions[$session] );
- // Record recently killed sessions that still have locks
- if ( $this->lockHolder->sessionHasLocks( $session ) ) {
- $this->deadSessions[$session] = time();
- }
- return true;
- }
- return false;
- }
-
- /**
- * Clear locks for sessions that have been dead for a while
- *
- * @return integer Number of sessions purged
- */
- protected function purgeExpiredLocks() {
- $count = 0;
- $now = time();
- foreach ( $this->deadSessions as $session => $timestamp ) {
- if ( ( $now - $timestamp ) > $this->lockTimeout ) {
- $this->lockHolder->release( $session );
- unset( $this->deadSessions[$session] );
- ++$count;
- }
- }
- return $count;
- }
-
- /**
- * Get the current timestamp and memory usage
- *
- * @return string
- */
- protected function stat() {
- return ( time() - $this->startTime ) . ':' . memory_get_usage();
- }
-}
-
-/**
- * LockServerDaemon helper class that keeps track socket states
- */
-class SocketArray {
- /* @var Array */
- protected $clients = array(); // array of client sockets
- /* @var Array */
- protected $rBuffers = array(); // corresponding socket read buffers
- /* @var Array */
- protected $wBuffers = array(); // corresponding socket write buffers
-
- const BUFFER_SIZE = 65535;
-
- /**
- * @return Array (list of sockets to read, list of sockets to write)
- */
- public function socketsForSelect() {
- $rSockets = array();
- $wSockets = array();
- foreach ( $this->clients as $key => $socket ) {
- if ( $this->wBuffers[$key] !== '' ) {
- $wSockets[] = $socket; // wait for writing to unblock
- } else {
- $rSockets[] = $socket; // wait for reading to unblock
- }
- }
- return array( $rSockets, $wSockets );
- }
-
- /**
- * @return integer Number of client sockets
- */
- public function size() {
- return count( $this->clients );
- }
-
- /**
- * @param $sock resource
- * @return bool
- */
- public function addSocket( $sock ) {
- $this->clients[] = $sock;
- $this->rBuffers[] = '';
- $this->wBuffers[] = '';
- return true;
- }
-
- /**
- * @param $sock resource
- * @return bool
- */
- public function closeSocket( $sock ) {
- $key = array_search( $sock, $this->clients );
- if ( $key === false ) {
- return false;
- }
- socket_close( $sock );
- unset( $this->clients[$key] );
- unset( $this->rBuffers[$key] );
- unset( $this->wBuffers[$key] );
- return true;
- }
-
- /**
- * @param $sock resource
- * @param $data string
- * @return bool
- */
- public function appendRcvBuffer( $sock, $data ) {
- $key = array_search( $sock, $this->clients );
- if ( $key === false ) {
- return false;
- } elseif ( ( strlen( $this->rBuffers[$key] ) + strlen( $data ) ) > self::BUFFER_SIZE ) {
- return false;
- }
- $this->rBuffers[$key] .= $data;
- return true;
- }
-
- /**
- * @param $sock resource
- * @return string|bool
- */
- public function readRcvBuffer( $sock ) {
- $key = array_search( $sock, $this->clients );
- if ( $key === false ) {
- return false;
- }
- $data = $this->rBuffers[$key];
- $this->rBuffers[$key] = ''; // consume data
- return $data;
- }
-
- /**
- * @param $sock resource
- * @param $data string
- * @return bool
- */
- public function appendSndBuffer( $sock, $data ) {
- $key = array_search( $sock, $this->clients );
- if ( $key === false ) {
- return false;
- } elseif ( ( strlen( $this->wBuffers[$key] ) + strlen( $data ) ) > self::BUFFER_SIZE ) {
- return false;
- }
- $this->wBuffers[$key] .= $data;
- return true;
- }
-
- /**
- * @param $sock resource
- * @return bool
- */
- public function readSndBuffer( $sock ) {
- $key = array_search( $sock, $this->clients );
- if ( $key === false ) {
- return false;
- }
- return $this->wBuffers[$key];
- }
-
- /**
- * @param $sock resource
- * @param $bytes integer
- * @return bool
- */
- public function consumeSndBuffer( $sock, $bytes ) {
- $key = array_search( $sock, $this->clients );
- if ( $key === false ) {
- return false;
- }
- $this->wBuffers[$key] = (string)substr( $this->wBuffers[$key], $bytes );
- return true;
- }
-}
-
-/**
- * LockServerDaemon helper class that keeps track of the locks
- */
-class LockHolder {
- /** @var Array */
- protected $shLocks = array(); // (key => session => 1)
- /** @var Array */
- protected $exLocks = array(); // (key => session)
-
- /** @var Array */
- protected $sessionIndexSh = array(); // (session => key => 1)
- /** @var Array */
- protected $sessionIndexEx = array(); // (session => key => 1)
- protected $lockCount = 0; // integer
-
- protected $maxLocks; // integer
-
- /**
- * @params $maxLocks integer Maximum number of locks to allow
- */
- public function __construct( $maxLocks ) {
- $this->maxLocks = $maxLocks;
- }
-
- /**
- * @param $session string
- * @return bool
- */
- public function sessionHasLocks( $session ) {
- return isset( $this->sessionIndexSh[$session] )
- || isset( $this->sessionIndexEx[$session] );
- }
-
- /**
- * @param $session string
- * @param $type string
- * @param $keys Array
- * @return string
- */
- public function lock( $session, $type, array $keys ) {
- if ( ( $this->lockCount + count( $keys ) ) > $this->maxLocks ) {
- return 'TOO_MANY_LOCKS';
- }
- if ( $type === 'SH' ) {
- // Check if any keys are already write-locked...
- foreach ( $keys as $key ) {
- if ( isset( $this->exLocks[$key] ) && $this->exLocks[$key] !== $session ) {
- return 'CANT_ACQUIRE';
- }
- }
- // Acquire the read-locks...
- foreach ( $keys as $key ) {
- $this->set_sh_lock( $key, $session );
- }
- return 'ACQUIRED';
- } elseif ( $type === 'EX' ) {
- // Check if any keys are already read-locked or write-locked...
- foreach ( $keys as $key ) {
- if ( isset( $this->exLocks[$key] ) && $this->exLocks[$key] !== $session ) {
- return 'CANT_ACQUIRE';
- }
- if ( isset( $this->shLocks[$key] ) ) {
- foreach ( $this->shLocks[$key] as $otherSession => $x ) {
- if ( $otherSession !== $session ) {
- return 'CANT_ACQUIRE';
- }
- }
- }
- }
- // Acquire the write-locks...
- foreach ( $keys as $key ) {
- $this->set_ex_lock( $key, $session );
- }
- return 'ACQUIRED';
- }
- return 'INTERNAL_ERROR';
- }
-
- /**
- * @param $session string
- * @param $type string
- * @param $keys Array
- * @return string
- */
- public function unlock( $session, $type, array $keys ) {
- if ( $type === 'SH' ) {
- foreach ( $keys as $key ) {
- $this->unset_sh_lock( $key, $session );
- }
- return 'RELEASED';
- } elseif ( $type === 'EX' ) {
- foreach ( $keys as $key ) {
- $this->unset_ex_lock( $key, $session );
- }
- return 'RELEASED';
- }
- return 'INTERNAL_ERROR';
- }
-
- /**
- * @param $session string
- * @return string
- */
- public function release( $session ) {
- if ( isset( $this->sessionIndexSh[$session] ) ) {
- foreach ( $this->sessionIndexSh[$session] as $key => $x ) {
- $this->unset_sh_lock( $key, $session );
- }
- }
- if ( isset( $this->sessionIndexEx[$session] ) ) {
- foreach ( $this->sessionIndexEx[$session] as $key => $x ) {
- $this->unset_ex_lock( $key, $session );
- }
- }
- return 'RELEASED_ALL';
- }
-
- /**
- * @param $key string
- * @param $session string
- * @return void
- */
- protected function set_sh_lock( $key, $session ) {
- if ( !isset( $this->shLocks[$key][$session] ) ) {
- $this->shLocks[$key][$session] = 1;
- $this->sessionIndexSh[$session][$key] = 1;
- ++$this->lockCount; // we are adding a lock
- }
- }
-
- /**
- * @param $key string
- * @param $session string
- * @return void
- */
- protected function set_ex_lock( $key, $session ) {
- if ( !isset( $this->exLocks[$key][$session] ) ) {
- $this->exLocks[$key] = $session;
- $this->sessionIndexEx[$session][$key] = 1;
- ++$this->lockCount; // we are adding a lock
- }
- }
-
- /**
- * @param $key string
- * @param $session string
- * @return void
- */
- protected function unset_sh_lock( $key, $session ) {
- if ( isset( $this->shLocks[$key][$session] ) ) {
- unset( $this->shLocks[$key][$session] );
- if ( !count( $this->shLocks[$key] ) ) {
- unset( $this->shLocks[$key] );
- }
- unset( $this->sessionIndexSh[$session][$key] );
- if ( !count( $this->sessionIndexSh[$session] ) ) {
- unset( $this->sessionIndexSh[$session] );
- }
- --$this->lockCount;
- }
- }
-
- /**
- * @param $key string
- * @param $session string
- * @return void
- */
- protected function unset_ex_lock( $key, $session ) {
- if ( isset( $this->exLocks[$key] ) && $this->exLocks[$key] === $session ) {
- unset( $this->exLocks[$key] );
- unset( $this->sessionIndexEx[$session][$key] );
- if ( !count( $this->sessionIndexEx[$session] ) ) {
- unset( $this->sessionIndexEx[$session] );
- }
- --$this->lockCount;
- }
- }
-}
diff --git a/maintenance/mctest.php b/maintenance/mctest.php
index eda101e7..a97d2e12 100644
--- a/maintenance/mctest.php
+++ b/maintenance/mctest.php
@@ -30,7 +30,7 @@ require_once __DIR__ . '/Maintenance.php';
*
* @ingroup Maintenance
*/
-class mcTest extends Maintenance {
+class McTest extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Makes several 'set', 'incr' and 'get' requests on every"
@@ -67,7 +67,7 @@ class mcTest extends Maintenance {
foreach ( $servers as $server ) {
$this->output(
str_pad( $server, $maxSrvLen ),
- $server # output channel
+ $server # output channel
);
$mcc = new MemCachedClientforWiki( array(
@@ -78,7 +78,7 @@ class mcTest extends Maintenance {
$set = 0;
$incr = 0;
$get = 0;
- $time_start = $this->microtime_float();
+ $time_start = microtime( true );
for ( $i = 1; $i <= $iterations; $i++ ) {
if ( $mcc->set( "test$i", $i ) ) {
$set++;
@@ -95,21 +95,12 @@ class mcTest extends Maintenance {
$get++;
}
}
- $exectime = $this->microtime_float() - $time_start;
+ $exectime = microtime( true ) - $time_start;
$this->output( " set: $set incr: $incr get: $get time: $exectime", $server );
}
}
-
- /**
- * Return microtime() as a float
- * @return float
- */
- private function microtime_float() {
- list( $usec, $sec ) = explode( " ", microtime() );
- return ( (float)$usec + (float)$sec );
- }
}
-$maintClass = "mcTest";
+$maintClass = "McTest";
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/mergeMessageFileList.php b/maintenance/mergeMessageFileList.php
index e9183377..2a6f8a8b 100644
--- a/maintenance/mergeMessageFileList.php
+++ b/maintenance/mergeMessageFileList.php
@@ -43,15 +43,23 @@ class MergeMessageFileList extends Maintenance {
function __construct() {
parent::__construct();
- $this->addOption( 'list-file', 'A file containing a list of extension setup files, one per line.', false, true );
+ $this->addOption(
+ 'list-file',
+ 'A file containing a list of extension setup files, one per line.',
+ false,
+ true
+ );
$this->addOption( 'extensions-dir', 'Path where extensions can be found.', false, true );
$this->addOption( 'output', 'Send output to this file (omit for stdout)', false, true );
- $this->mDescription = 'Merge $wgExtensionMessagesFiles from various extensions to produce a ' .
- 'single array containing all message files.';
+ $this->mDescription = 'Merge $wgExtensionMessagesFiles and $wgMessagesDirs from ' .
+ ' various extensions to produce a single file listing all message files and dirs.';
}
public function execute() {
- global $mmfl, $wgExtensionEntryPointListFiles;
+ // @codingStandardsIgnoreStart Ignore error: Global variable "$mmfl" is lacking 'wg' prefix
+ global $mmfl;
+ // @codingStandardsIgnoreEnd
+ global $wgExtensionEntryPointListFiles;
if ( !count( $wgExtensionEntryPointListFiles )
&& !$this->hasOption( 'list-file' )
@@ -117,6 +125,7 @@ class MergeMessageFileList extends Maintenance {
if ( $fileLines === false ) {
$this->hasError = true;
$this->error( "Unable to open list file $fileName." );
+
return $files;
}
# Strip comments, discard empty lines, and trim leading and trailing
@@ -134,6 +143,7 @@ class MergeMessageFileList extends Maintenance {
}
}
}
+
return $files;
}
}
@@ -148,7 +158,7 @@ foreach ( $mmfl['setupFiles'] as $fileName ) {
fwrite( STDERR, "Loading data from $fileName\n" );
}
// Include the extension to update $wgExtensionMessagesFiles
- if ( !( include_once( $fileName ) ) ) {
+ if ( !( include_once $fileName ) ) {
fwrite( STDERR, "Unable to read $fileName\n" );
exit( 1 );
}
@@ -158,7 +168,8 @@ $s =
"<" . "?php\n" .
"## This file is generated by mergeMessageFileList.php. Do not edit it directly.\n\n" .
"if ( defined( 'MW_NO_EXTENSION_MESSAGES' ) ) return;\n\n" .
- '$wgExtensionMessagesFiles = ' . var_export( $wgExtensionMessagesFiles, true ) . ";\n\n";
+ '$wgExtensionMessagesFiles = ' . var_export( $wgExtensionMessagesFiles, true ) . ";\n\n" .
+ '$wgMessagesDirs = ' . var_export( $wgMessagesDirs, true ) . ";\n\n";
$dirs = array(
$IP,
diff --git a/maintenance/minify.php b/maintenance/minify.php
index ec936c83..efecaad0 100644
--- a/maintenance/minify.php
+++ b/maintenance/minify.php
@@ -49,7 +49,6 @@ class MinifyScript extends Maintenance {
$this->mDescription = "Minify a file or set of files.\n\n" .
"If --outfile is not specified, then the output file names will have a .min extension\n" .
"added, e.g. jquery.js -> jquery.min.js.";
-
}
public function execute() {
@@ -66,6 +65,7 @@ class MinifyScript extends Maintenance {
// Minify one file
$this->minify( $this->getArg( 0 ), $this->getOption( 'outfile' ) );
+
return;
}
@@ -103,6 +103,7 @@ class MinifyScript extends Maintenance {
$this->error( "No file extension, cannot determine type: $fileName" );
exit( 1 );
}
+
return substr( $fileName, $dotPos + 1 );
}
diff --git a/maintenance/moveBatch.php b/maintenance/moveBatch.php
index 34e64282..713753f2 100644
--- a/maintenance/moveBatch.php
+++ b/maintenance/moveBatch.php
@@ -21,7 +21,7 @@
* @ingroup Maintenance
* @author Tim Starling
*
- * USAGE: php moveBatch.php [-u <user>] [-r <reason>] [-i <interval>] [listfile]
+ * USAGE: php moveBatch.php [-u <user>] [-r <reason>] [-i <interval>] [-noredirects] [listfile]
*
* [listfile] - file with two titles per line, separated with pipe characters;
* the first title is the source, the second is the destination.
@@ -29,6 +29,7 @@
* <user> - username to perform moves as
* <reason> - reason to be given for moves
* <interval> - number of seconds to sleep after each move
+ * <noredirects> - suppress creation of redirects
*
* This will print out error codes from Title::moveTo() if something goes wrong,
* e.g. immobile_namespace for namespaces which can't be moved
@@ -48,6 +49,7 @@ class MoveBatch extends Maintenance {
$this->addOption( 'u', "User to perform move", false, true );
$this->addOption( 'r', "Reason to move page", false, true );
$this->addOption( 'i', "Interval to sleep between moves" );
+ $this->addOption( 'noredirects', "Suppress creation of redirects" );
$this->addArg( 'listfile', 'List of pages to move, newline delimited', false );
}
@@ -62,6 +64,7 @@ class MoveBatch extends Maintenance {
$user = $this->getOption( 'u', 'Move page script' );
$reason = $this->getOption( 'r', '' );
$interval = $this->getOption( 'i', 0 );
+ $noredirects = $this->getOption( 'noredirects', false );
if ( $this->hasArg() ) {
$file = fopen( $this->getArg(), 'r' );
} else {
@@ -79,7 +82,9 @@ class MoveBatch extends Maintenance {
# Setup complete, now start
$dbw = wfGetDB( DB_MASTER );
+ // @codingStandardsIgnoreStart Ignore avoid function calls in a FOR loop test part warning
for ( $linenum = 1; !feof( $file ); $linenum++ ) {
+ // @codingStandardsIgnoreEnd
$line = fgets( $file );
if ( $line === false ) {
break;
@@ -96,10 +101,9 @@ class MoveBatch extends Maintenance {
continue;
}
-
$this->output( $source->getPrefixedText() . ' --> ' . $dest->getPrefixedText() );
$dbw->begin( __METHOD__ );
- $err = $source->moveTo( $dest, false, $reason );
+ $err = $source->moveTo( $dest, false, $reason, !$noredirects );
if ( $err !== true ) {
$msg = array_shift( $err[0] );
$this->output( "\nFAILED: " . wfMessage( $msg, $err[0] )->text() );
diff --git a/maintenance/mssql/archives/named_constraints.sql b/maintenance/mssql/archives/named_constraints.sql
new file mode 100644
index 00000000..94b77ea7
--- /dev/null
+++ b/maintenance/mssql/archives/named_constraints.sql
@@ -0,0 +1,38 @@
+DECLARE @fullyQualifiedTableName nvarchar(max),
+@tableName sysname,
+@fieldName sysname,
+@constr sysname,
+@constrNew sysname,
+@sqlcmd nvarchar(max),
+@sqlcreate nvarchar(max)
+
+SET @fullyQualifiedTableName = '/*_*//*$tableName*/'
+SET @tableName = '/*$tableName*/'
+SET @fieldName = '/*$fieldName*/'
+
+SELECT @constr = CONSTRAINT_NAME
+FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
+WHERE TABLE_NAME = @tableName
+AND CONSTRAINT_CATALOG = '/*$wgDBname*/'
+AND CONSTRAINT_SCHEMA = '/*$wgDBmwschema*/'
+AND CONSTRAINT_TYPE = 'CHECK'
+AND CONSTRAINT_NAME LIKE ('CK__' + left(@tableName,9) + '__' + left(@fieldName,5) + '%')
+
+SELECT @constrNew = CONSTRAINT_NAME
+FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
+WHERE TABLE_NAME = @tableName
+AND CONSTRAINT_CATALOG = '/*$wgDBname*/'
+AND CONSTRAINT_SCHEMA = '/*$wgDBmwschema*/'
+AND CONSTRAINT_TYPE = 'CHECK'
+AND CONSTRAINT_NAME = (@fieldName + '_ckc')
+
+IF @constr IS NOT NULL
+BEGIN
+ SET @sqlcmd = 'ALTER TABLE ' + @fullyQualifiedTableName + ' DROP CONSTRAINT [' + @constr + ']'
+ EXECUTE sp_executesql @sqlcmd
+END
+IF @constrNew IS NULL
+BEGIN
+ SET @sqlcreate = 'ALTER TABLE ' + @fullyQualifiedTableName + ' WITH NOCHECK ADD CONSTRAINT ' + @fieldName + '_ckc CHECK /*$checkConstraint*/;'
+ EXECUTE sp_executesql @sqlcreate
+END \ No newline at end of file
diff --git a/maintenance/mssql/archives/patch-fa_major_mime-chemical.sql b/maintenance/mssql/archives/patch-fa_major_mime-chemical.sql
new file mode 100644
index 00000000..18368087
--- /dev/null
+++ b/maintenance/mssql/archives/patch-fa_major_mime-chemical.sql
@@ -0,0 +1,4 @@
+ALTER TABLE /*_*/filearchive
+DROP CONSTRAINT fa_major_mime_ckc;
+ALTER TABLE /*_*/filearchive
+WITH NOCHECK ADD CONSTRAINT fa_major_mime_ckc CHECK (fa_major_mime IN('unknown', 'application', 'audio', 'image', 'text', 'video', 'message', 'model', 'multipart', 'chemical')); \ No newline at end of file
diff --git a/maintenance/mssql/archives/patch-img_major_mime-chemical.sql b/maintenance/mssql/archives/patch-img_major_mime-chemical.sql
new file mode 100644
index 00000000..eed07869
--- /dev/null
+++ b/maintenance/mssql/archives/patch-img_major_mime-chemical.sql
@@ -0,0 +1,4 @@
+ALTER TABLE /*_*/image
+DROP CONSTRAINT img_major_mime_ckc;
+ALTER TABLE /*_*/image
+WITH NOCHECK ADD CONSTRAINT img_major_mime_ckc CHECK (img_major_mime IN('unknown', 'application', 'audio', 'image', 'text', 'video', 'message', 'model', 'multipart', 'chemical')); \ No newline at end of file
diff --git a/maintenance/mssql/archives/patch-oi_major_mime-chemical.sql b/maintenance/mssql/archives/patch-oi_major_mime-chemical.sql
new file mode 100644
index 00000000..35482edc
--- /dev/null
+++ b/maintenance/mssql/archives/patch-oi_major_mime-chemical.sql
@@ -0,0 +1,4 @@
+ALTER TABLE /*_*/oldimage
+DROP CONSTRAINT oi_major_mime_ckc;
+ALTER TABLE /*_*/oldimage
+WITH NOCHECK ADD CONSTRAINT oi_major_mime_ckc CHECK (oi_major_mime IN('unknown', 'application', 'audio', 'image', 'text', 'video', 'message', 'model', 'multipart', 'chemical')); \ No newline at end of file
diff --git a/maintenance/mssql/archives/patch-page_page_lang.sql b/maintenance/mssql/archives/patch-page_page_lang.sql
new file mode 100644
index 00000000..d2f537b0
--- /dev/null
+++ b/maintenance/mssql/archives/patch-page_page_lang.sql
@@ -0,0 +1 @@
+ALTER TABLE /*_*/page ADD page_lang VARBINARY(35) DEFAULT NULL
diff --git a/maintenance/mssql/archives/patch-user_password_expires.sql b/maintenance/mssql/archives/patch-user_password_expires.sql
new file mode 100644
index 00000000..c22b10c7
--- /dev/null
+++ b/maintenance/mssql/archives/patch-user_password_expires.sql
@@ -0,0 +1 @@
+ALTER TABLE /*_*/mwuser ADD user_password_expires VARCHAR(14) DEFAULT NULL \ No newline at end of file
diff --git a/maintenance/mssql/tables.sql b/maintenance/mssql/tables.sql
index 7356c38f..b9cd7159 100644
--- a/maintenance/mssql/tables.sql
+++ b/maintenance/mssql/tables.sql
@@ -30,26 +30,30 @@
-- tables.
-- LINE:53
-CREATE TABLE /*$wgDBprefix*/user (
+CREATE TABLE /*_*/mwuser (
user_id INT NOT NULL PRIMARY KEY IDENTITY(0,1),
user_name NVARCHAR(255) NOT NULL UNIQUE DEFAULT '',
user_real_name NVARCHAR(255) NOT NULL DEFAULT '',
user_password NVARCHAR(255) NOT NULL DEFAULT '',
user_newpassword NVARCHAR(255) NOT NULL DEFAULT '',
- user_newpass_time DATETIME NULL,
+ user_newpass_time varchar(14) NULL DEFAULT NULL,
user_email NVARCHAR(255) NOT NULL DEFAULT '',
user_options NVARCHAR(MAX) NOT NULL DEFAULT '',
- user_touched DATETIME NOT NULL DEFAULT GETDATE(),
+ user_touched varchar(14) NOT NULL DEFAULT '',
user_token NCHAR(32) NOT NULL DEFAULT '',
- user_email_authenticated DATETIME DEFAULT NULL,
+ user_email_authenticated varchar(14) DEFAULT NULL,
user_email_token NCHAR(32) DEFAULT '',
- user_email_token_expires DATETIME DEFAULT NULL,
- user_registration DATETIME DEFAULT NULL,
- user_editcount INT NULL
+ user_email_token_expires varchar(14) DEFAULT NULL,
+ user_registration varchar(14) DEFAULT NULL,
+ user_editcount INT NULL DEFAULT NULL,
+ user_password_expires varchar(14) DEFAULT NULL
);
-CREATE INDEX /*$wgDBprefix*/user_email_token ON /*$wgDBprefix*/[user](user_email_token);
-CREATE UNIQUE INDEX /*$wgDBprefix*/[user_name] ON /*$wgDBprefix*/[user]([user_name]);
-;
+CREATE UNIQUE INDEX /*i*/user_name ON /*_*/mwuser (user_name);
+CREATE INDEX /*i*/user_email_token ON /*_*/mwuser (user_email_token);
+CREATE INDEX /*i*/user_email ON /*_*/mwuser (user_email);
+
+-- Insert a dummy user to represent anons
+INSERT INTO /*_*/mwuser (user_name) VALUES ('##Anonymous##');
--
-- User permissions have been broken out to a separate table;
@@ -57,86 +61,107 @@ CREATE UNIQUE INDEX /*$wgDBprefix*/[user_name] ON /*$wgDBprefix*/[user]([
-- permissions assigned to a user in each project.
--
-- This table replaces the old user_rights field which used a
--- comma-separated blob.
-CREATE TABLE /*$wgDBprefix*/user_groups (
- ug_user INT NOT NULL REFERENCES /*$wgDBprefix*/[user](user_id) ON DELETE CASCADE,
- ug_group NVARCHAR(16) NOT NULL DEFAULT '',
+-- comma-separated nvarchar(max).
+CREATE TABLE /*_*/user_groups (
+ ug_user INT NOT NULL REFERENCES /*_*/mwuser(user_id) ON DELETE CASCADE,
+ ug_group NVARCHAR(255) NOT NULL DEFAULT '',
+);
+CREATE UNIQUE clustered INDEX /*i*/ug_user_group ON /*_*/user_groups (ug_user, ug_group);
+CREATE INDEX /*i*/ug_group ON /*_*/user_groups(ug_group);
+
+-- Stores the groups the user has once belonged to.
+-- The user may still belong to these groups (check user_groups).
+-- Users are not autopromoted to groups from which they were removed.
+CREATE TABLE /*_*/user_former_groups (
+ ufg_user INT NOT NULL REFERENCES /*_*/mwuser(user_id) ON DELETE CASCADE,
+ ufg_group nvarchar(255) NOT NULL default ''
);
-CREATE UNIQUE clustered INDEX /*$wgDBprefix*/user_groups_unique ON /*$wgDBprefix*/user_groups(ug_user, ug_group);
-CREATE INDEX /*$wgDBprefix*/user_group ON /*$wgDBprefix*/user_groups(ug_group);
+CREATE UNIQUE INDEX /*i*/ufg_user_group ON /*_*/user_former_groups (ufg_user,ufg_group);
-- Stores notifications of user talk page changes, for the display
-- of the "you have new messages" box
--- Changed user_id column to mwuser_id to avoid clashing with user_id function
-CREATE TABLE /*$wgDBprefix*/user_newtalk (
- user_id INT NOT NULL DEFAULT 0 REFERENCES /*$wgDBprefix*/[user](user_id) ON DELETE CASCADE,
+-- Changed user_id column to user_id to avoid clashing with user_id function
+CREATE TABLE /*_*/user_newtalk (
+ user_id INT NOT NULL REFERENCES /*_*/mwuser(user_id) ON DELETE CASCADE,
user_ip NVARCHAR(40) NOT NULL DEFAULT '',
- user_last_timestamp DATETIME NOT NULL DEFAULT '',
+ user_last_timestamp varchar(14) DEFAULT NULL,
);
-CREATE INDEX /*$wgDBprefix*/user_group_id ON /*$wgDBprefix*/user_newtalk([user_id]);
-CREATE INDEX /*$wgDBprefix*/user_ip ON /*$wgDBprefix*/user_newtalk(user_ip);
+CREATE INDEX /*i*/un_user_id ON /*_*/user_newtalk (user_id);
+CREATE INDEX /*i*/un_user_ip ON /*_*/user_newtalk (user_ip);
--
-- User preferences and other fun stuff
--- replaces old user.user_options BLOB
+-- replaces old user.user_options nvarchar(max)
--
-CREATE TABLE /*$wgDBprefix*/user_properties (
- up_user INT NOT NULL,
- up_property NVARCHAR(32) NOT NULL,
+CREATE TABLE /*_*/user_properties (
+ up_user INT NOT NULL REFERENCES /*_*/mwuser(user_id) ON DELETE CASCADE,
+ up_property NVARCHAR(255) NOT NULL,
up_value NVARCHAR(MAX),
);
-CREATE UNIQUE clustered INDEX /*$wgDBprefix*/user_props_user_prop ON /*$wgDBprefix*/user_properties(up_user, up_property);
-CREATE INDEX /*$wgDBprefix*/user_props_prop ON /*$wgDBprefix*/user_properties(up_property);
+CREATE UNIQUE CLUSTERED INDEX /*i*/user_properties_user_property ON /*_*/user_properties (up_user,up_property);
+CREATE INDEX /*i*/user_properties_property ON /*_*/user_properties (up_property);
--
-- Core of the wiki: each page has an entry here which identifies
-- it by title and contains some essential metadata.
--
-CREATE TABLE /*$wgDBprefix*/page (
- page_id INT NOT NULL PRIMARY KEY clustered IDENTITY,
+CREATE TABLE /*_*/page (
+ page_id INT NOT NULL PRIMARY KEY IDENTITY(0,1),
page_namespace INT NOT NULL,
page_title NVARCHAR(255) NOT NULL,
- page_restrictions NVARCHAR(255) NULL,
+ page_restrictions NVARCHAR(255) NOT NULL,
page_counter BIGINT NOT NULL DEFAULT 0,
page_is_redirect BIT NOT NULL DEFAULT 0,
page_is_new BIT NOT NULL DEFAULT 0,
- page_random NUMERIC(15,14) NOT NULL DEFAULT RAND(),
- page_touched DATETIME NOT NULL DEFAULT GETDATE(),
- page_latest INT NOT NULL,
+ page_random real NOT NULL DEFAULT RAND(),
+ page_touched varchar(14) NOT NULL default '',
+ page_links_updated varchar(14) DEFAULT NULL,
+ page_latest INT, -- FK inserted later
page_len INT NOT NULL,
+ page_content_model nvarchar(32) default null,
+ page_lang VARBINARY(35) DEFAULT NULL
);
-CREATE UNIQUE INDEX /*$wgDBprefix*/page_unique_name ON /*$wgDBprefix*/page(page_namespace, page_title);
-CREATE INDEX /*$wgDBprefix*/page_random_idx ON /*$wgDBprefix*/page(page_random);
-CREATE INDEX /*$wgDBprefix*/page_len_idx ON /*$wgDBprefix*/page(page_len);
-;
+CREATE UNIQUE INDEX /*i*/name_title ON /*_*/page (page_namespace,page_title);
+CREATE INDEX /*i*/page_random ON /*_*/page (page_random);
+CREATE INDEX /*i*/page_len ON /*_*/page (page_len);
+CREATE INDEX /*i*/page_redirect_namespace_len ON /*_*/page (page_is_redirect, page_namespace, page_len);
+
+-- insert a dummy page
+INSERT INTO /*_*/page (page_namespace, page_title, page_restrictions, page_latest, page_len) VALUES (-1,'','',0,0);
--
-- Every edit of a page creates also a revision row.
-- This stores metadata about the revision, and a reference
-- to the TEXT storage backend.
--
-CREATE TABLE /*$wgDBprefix*/revision (
- rev_id INT NOT NULL UNIQUE IDENTITY,
- rev_page INT NOT NULL,
- rev_text_id INT NOT NULL,
- rev_comment NVARCHAR(max) NOT NULL,
- rev_user INT NOT NULL DEFAULT 0 /*REFERENCES [user](user_id)*/,
+CREATE TABLE /*_*/revision (
+ rev_id INT NOT NULL UNIQUE IDENTITY(0,1),
+ rev_page INT NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+ rev_text_id INT NOT NULL, -- FK added later
+ rev_comment NVARCHAR(255) NOT NULL,
+ rev_user INT REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
rev_user_text NVARCHAR(255) NOT NULL DEFAULT '',
- rev_timestamp DATETIME NOT NULL DEFAULT GETDATE(),
+ rev_timestamp varchar(14) NOT NULL default '',
rev_minor_edit BIT NOT NULL DEFAULT 0,
- rev_deleted BIT NOT NULL DEFAULT 0,
+ rev_deleted TINYINT NOT NULL DEFAULT 0,
rev_len INT,
- rev_parent_id INT DEFAULT NULL,
-
+ rev_parent_id INT DEFAULT NULL REFERENCES /*_*/revision(rev_id),
+ rev_sha1 nvarchar(32) not null default '',
+ rev_content_model nvarchar(32) default null,
+ rev_content_format nvarchar(64) default null
);
-CREATE UNIQUE clustered INDEX /*$wgDBprefix*/revision_unique ON /*$wgDBprefix*/revision(rev_page, rev_id);
-CREATE UNIQUE INDEX /*$wgDBprefix*/rev_id ON /*$wgDBprefix*/revision(rev_id);
-CREATE INDEX /*$wgDBprefix*/rev_timestamp ON /*$wgDBprefix*/revision(rev_timestamp);
-CREATE INDEX /*$wgDBprefix*/page_timestamp ON /*$wgDBprefix*/revision(rev_page, rev_timestamp);
-CREATE INDEX /*$wgDBprefix*/user_timestamp ON /*$wgDBprefix*/revision(rev_user, rev_timestamp);
-CREATE INDEX /*$wgDBprefix*/usertext_timestamp ON /*$wgDBprefix*/revision(rev_user_text, rev_timestamp);
-;
+CREATE UNIQUE CLUSTERED INDEX /*i*/rev_page_id ON /*_*/revision (rev_page, rev_id);
+CREATE INDEX /*i*/rev_timestamp ON /*_*/revision (rev_timestamp);
+CREATE INDEX /*i*/page_timestamp ON /*_*/revision (rev_page,rev_timestamp);
+CREATE INDEX /*i*/user_timestamp ON /*_*/revision (rev_user,rev_timestamp);
+CREATE INDEX /*i*/usertext_timestamp ON /*_*/revision (rev_user_text,rev_timestamp);
+CREATE INDEX /*i*/page_user_timestamp ON /*_*/revision (rev_page,rev_user,rev_timestamp);
+
+-- insert a dummy revision
+INSERT INTO /*_*/revision (rev_page,rev_text_id,rev_comment,rev_user,rev_len) VALUES (0,0,'',0,0);
+
+ALTER TABLE /*_*/page ADD CONSTRAINT FK_page_latest_page_id FOREIGN KEY (page_latest) REFERENCES /*_*/revision(rev_id);
--
-- Holds TEXT of individual page revisions.
@@ -145,12 +170,17 @@ CREATE INDEX /*$wgDBprefix*/usertext_timestamp ON /*$wgDBprefix*/revision
-- MediaWiki 1.4 and earlier: an upgrade will transform that
-- table INTo the 'text' table to minimize unnecessary churning
-- and downtime. If upgrading, the other fields will be left unused.
-CREATE TABLE /*$wgDBprefix*/text (
- old_id INT NOT NULL PRIMARY KEY clustered IDENTITY,
- old_text TEXT NOT NULL,
+CREATE TABLE /*_*/text (
+ old_id INT NOT NULL PRIMARY KEY IDENTITY(0,1),
+ old_text nvarchar(max) NOT NULL,
old_flags NVARCHAR(255) NOT NULL,
);
+-- insert a dummy text
+INSERT INTO /*_*/text (old_text,old_flags) VALUES ('','');
+
+ALTER TABLE /*_*/revision ADD CONSTRAINT FK_rev_text_id_old_id FOREIGN KEY (rev_text_id) REFERENCES /*_*/text(old_id) ON DELETE CASCADE;
+
--
-- Holding area for deleted articles, which may be viewed
-- or restored by admins through the Special:Undelete interface.
@@ -158,575 +188,1153 @@ CREATE TABLE /*$wgDBprefix*/text (
-- fields, with several caveats.
-- Cannot reasonably create views on this table, due to the presence of TEXT
-- columns.
-CREATE TABLE /*$wgDBprefix*/archive (
- ar_id NOT NULL PRIMARY KEY clustered IDENTITY,
+CREATE TABLE /*_*/archive (
+ ar_id int NOT NULL PRIMARY KEY IDENTITY,
ar_namespace SMALLINT NOT NULL DEFAULT 0,
ar_title NVARCHAR(255) NOT NULL DEFAULT '',
ar_text NVARCHAR(MAX) NOT NULL,
ar_comment NVARCHAR(255) NOT NULL,
- ar_user INT NULL REFERENCES /*$wgDBprefix*/[user](user_id) ON DELETE SET NULL,
+ ar_user INT REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
ar_user_text NVARCHAR(255) NOT NULL,
- ar_timestamp DATETIME NOT NULL DEFAULT GETDATE(),
+ ar_timestamp varchar(14) NOT NULL default '',
ar_minor_edit BIT NOT NULL DEFAULT 0,
ar_flags NVARCHAR(255) NOT NULL,
- ar_rev_id INT,
- ar_text_id INT,
- ar_deleted BIT NOT NULL DEFAULT 0,
- ar_len INT DEFAULT NULL,
- ar_page_id INT NULL,
- ar_parent_id INT NULL,
+ ar_rev_id INT NULL, -- NOT a FK, the row gets deleted from revision and moved here
+ ar_text_id INT REFERENCES /*_*/text(old_id) ON DELETE CASCADE,
+ ar_deleted TINYINT NOT NULL DEFAULT 0,
+ ar_len INT,
+ ar_page_id INT NULL, -- NOT a FK, the row gets deleted from page and moved here
+ ar_parent_id INT NULL REFERENCES /*_*/revision(rev_id),
+ ar_sha1 nvarchar(32) default null,
+ ar_content_model nvarchar(32) DEFAULT NULL,
+ ar_content_format nvarchar(64) DEFAULT NULL
);
-CREATE INDEX /*$wgDBprefix*/ar_name_title_timestamp ON /*$wgDBprefix*/archive(ar_namespace,ar_title,ar_timestamp);
-CREATE INDEX /*$wgDBprefix*/ar_usertext_timestamp ON /*$wgDBprefix*/archive(ar_user_text,ar_timestamp);
-CREATE INDEX /*$wgDBprefix*/ar_user_text ON /*$wgDBprefix*/archive(ar_user_text);
+CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp);
+CREATE INDEX /*i*/ar_usertext_timestamp ON /*_*/archive (ar_user_text,ar_timestamp);
+CREATE INDEX /*i*/ar_revid ON /*_*/archive (ar_rev_id);
--
-- Track page-to-page hyperlinks within the wiki.
--
-CREATE TABLE /*$wgDBprefix*/pagelinks (
- pl_from INT NOT NULL DEFAULT 0 REFERENCES /*$wgDBprefix*/page(page_id) ON DELETE CASCADE,
- pl_namespace SMALLINT NOT NULL DEFAULT 0,
+CREATE TABLE /*_*/pagelinks (
+ pl_from INT NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+ pl_namespace INT NOT NULL DEFAULT 0,
pl_title NVARCHAR(255) NOT NULL DEFAULT '',
);
-CREATE UNIQUE INDEX /*$wgDBprefix*/pl_from ON /*$wgDBprefix*/pagelinks(pl_from,pl_namespace,pl_title);
-CREATE UNIQUE INDEX /*$wgDBprefix*/pl_namespace ON /*$wgDBprefix*/pagelinks(pl_namespace,pl_title,pl_from);
+CREATE UNIQUE INDEX /*i*/pl_from ON /*_*/pagelinks (pl_from,pl_namespace,pl_title);
+CREATE UNIQUE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from);
+
--
-- Track template inclusions.
--
-CREATE TABLE /*$wgDBprefix*/templatelinks (
- tl_from INT NOT NULL DEFAULT 0 REFERENCES /*$wgDBprefix*/page(page_id) ON DELETE CASCADE,
- tl_namespace SMALLINT NOT NULL DEFAULT 0,
- tl_title NVARCHAR(255) NOT NULL DEFAULT '',
+CREATE TABLE /*_*/templatelinks (
+ tl_from int NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+ tl_namespace int NOT NULL default 0,
+ tl_title nvarchar(255) NOT NULL default ''
);
-CREATE UNIQUE INDEX /*$wgDBprefix*/tl_from ON /*$wgDBprefix*/templatelinks(tl_from,tl_namespace,tl_title);
-CREATE UNIQUE INDEX /*$wgDBprefix*/tl_namespace ON /*$wgDBprefix*/templatelinks(tl_namespace,tl_title,tl_from);
+
+CREATE UNIQUE INDEX /*i*/tl_from ON /*_*/templatelinks (tl_from,tl_namespace,tl_title);
+CREATE UNIQUE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from);
+
--
-- Track links to images *used inline*
-- We don't distinguish live from broken links here, so
--- they do not need to be changed ON upload/removal.
+-- they do not need to be changed on upload/removal.
--
-CREATE TABLE /*$wgDBprefix*/imagelinks (
- il_from INT NOT NULL DEFAULT 0 REFERENCES /*$wgDBprefix*/page(page_id) ON DELETE CASCADE,
- il_to NVARCHAR(255) NOT NULL DEFAULT '',
- CONSTRAINT /*$wgDBprefix*/il_from PRIMARY KEY(il_from,il_to),
+CREATE TABLE /*_*/imagelinks (
+ -- Key to page_id of the page containing the image / media link.
+ il_from int NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+
+ -- Filename of target image.
+ -- This is also the page_title of the file's description page;
+ -- all such pages are in namespace 6 (NS_FILE).
+ il_to nvarchar(255) NOT NULL default ''
);
-CREATE UNIQUE INDEX /*$wgDBprefix*/il_from_to ON /*$wgDBprefix*/imagelinks(il_from,il_to);
-CREATE UNIQUE INDEX /*$wgDBprefix*/il_to_from ON /*$wgDBprefix*/imagelinks(il_to,il_from);
+
+CREATE UNIQUE INDEX /*i*/il_from ON /*_*/imagelinks (il_from,il_to);
+CREATE UNIQUE INDEX /*i*/il_to ON /*_*/imagelinks (il_to,il_from);
--
-- Track category inclusions *used inline*
-- This tracks a single level of category membership
--- (folksonomic tagging, really).
--
-CREATE TABLE /*$wgDBprefix*/categorylinks (
- cl_from INT NOT NULL DEFAULT 0,
- cl_to NVARCHAR(255) NOT NULL DEFAULT '',
- cl_sortkey NVARCHAR(150) NOT NULL DEFAULT '',
- cl_timestamp DATETIME NOT NULL DEFAULT GETDATE(),
- CONSTRAINT /*$wgDBprefix*/cl_from PRIMARY KEY(cl_from, cl_to),
+CREATE TABLE /*_*/categorylinks (
+ -- Key to page_id of the page defined as a category member.
+ cl_from int NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+
+ -- Name of the category.
+ -- This is also the page_title of the category's description page;
+ -- all such pages are in namespace 14 (NS_CATEGORY).
+ cl_to nvarchar(255) NOT NULL default '',
+
+ -- A binary string obtained by applying a sortkey generation algorithm
+ -- (Collation::getSortKey()) to page_title, or cl_sortkey_prefix . "\n"
+ -- . page_title if cl_sortkey_prefix is nonempty.
+ cl_sortkey varbinary(230) NOT NULL default 0x,
+
+ -- A prefix for the raw sortkey manually specified by the user, either via
+ -- [[Category:Foo|prefix]] or {{defaultsort:prefix}}. If nonempty, it's
+ -- concatenated with a line break followed by the page title before the sortkey
+ -- conversion algorithm is run. We store this so that we can update
+ -- collations without reparsing all pages.
+ -- Note: If you change the length of this field, you also need to change
+ -- code in LinksUpdate.php. See bug 25254.
+ cl_sortkey_prefix varbinary(255) NOT NULL default 0x,
+
+ -- This isn't really used at present. Provided for an optional
+ -- sorting method by approximate addition time.
+ cl_timestamp varchar(14) NOT NULL,
+
+ -- Stores $wgCategoryCollation at the time cl_sortkey was generated. This
+ -- can be used to install new collation versions, tracking which rows are not
+ -- yet updated. '' means no collation, this is a legacy row that needs to be
+ -- updated by updateCollation.php. In the future, it might be possible to
+ -- specify different collations per category.
+ cl_collation nvarchar(32) NOT NULL default '',
+
+ -- Stores whether cl_from is a category, file, or other page, so we can
+ -- paginate the three categories separately. This never has to be updated
+ -- after the page is created, since none of these page types can be moved to
+ -- any other.
+ cl_type varchar(10) NOT NULL default 'page',
+ -- SQL server doesn't have enums, so we approximate with this
+ CONSTRAINT cl_type_ckc CHECK (cl_type IN('page', 'subcat', 'file'))
);
-CREATE UNIQUE INDEX /*$wgDBprefix*/cl_from_to ON /*$wgDBprefix*/categorylinks(cl_from,cl_to);
--- We always sort within a given category...
-CREATE INDEX /*$wgDBprefix*/cl_sortkey ON /*$wgDBprefix*/categorylinks(cl_to,cl_sortkey);
--- Not really used?
-CREATE INDEX /*$wgDBprefix*/cl_timestamp ON /*$wgDBprefix*/categorylinks(cl_to,cl_timestamp);
---;
+
+CREATE UNIQUE INDEX /*i*/cl_from ON /*_*/categorylinks (cl_from,cl_to);
+
+-- We always sort within a given category, and within a given type. FIXME:
+-- Formerly this index didn't cover cl_type (since that didn't exist), so old
+-- callers won't be using an index: fix this?
+CREATE INDEX /*i*/cl_sortkey ON /*_*/categorylinks (cl_to,cl_type,cl_sortkey,cl_from);
+
+-- Used by the API (and some extensions)
+CREATE INDEX /*i*/cl_timestamp ON /*_*/categorylinks (cl_to,cl_timestamp);
+
+-- FIXME: Not used, delete this
+CREATE INDEX /*i*/cl_collation ON /*_*/categorylinks (cl_collation);
--
-- Track all existing categories. Something is a category if 1) it has an en-
-- try somewhere in categorylinks, or 2) it once did. Categories might not
-- have corresponding pages, so they need to be tracked separately.
--
-CREATE TABLE /*$wgDBprefix*/category (
- cat_id int NOT NULL IDENTITY(1,1),
- cat_title nvarchar(255) NOT NULL,
+CREATE TABLE /*_*/category (
+ -- Primary key
+ cat_id int NOT NULL PRIMARY KEY IDENTITY,
+
+ -- Name of the category, in the same form as page_title (with underscores).
+ -- If there is a category page corresponding to this category, by definition,
+ -- it has this name (in the Category namespace).
+ cat_title nvarchar(255) NOT NULL,
+
+ -- The numbers of member pages (including categories and media), subcatego-
+ -- ries, and Image: namespace members, respectively. These are signed to
+ -- make underflow more obvious. We make the first number include the second
+ -- two for better sorting: subtracting for display is easy, adding for order-
+ -- ing is not.
cat_pages int NOT NULL default 0,
cat_subcats int NOT NULL default 0,
- cat_files int NOT NULL default 0,
- cat_hidden tinyint NOT NULL default 0,
+ cat_files int NOT NULL default 0
);
-CREATE UNIQUE INDEX /*$wgDBprefix*/cat_title ON /*$wgDBprefix*/category(cat_title);
--- For Special:Mostlinkedcategories
-CREATE INDEX /*$wgDBprefix*/cat_pages ON /*$wgDBprefix*/category(cat_pages);
+CREATE UNIQUE INDEX /*i*/cat_title ON /*_*/category (cat_title);
+-- For Special:Mostlinkedcategories
+CREATE INDEX /*i*/cat_pages ON /*_*/category (cat_pages);
-CREATE TABLE /*$wgDBprefix*/change_tag (
- ct_rc_id int NOT NULL default 0,
- ct_log_id int NOT NULL default 0,
- ct_rev_id int NOT NULL default 0,
- ct_tag varchar(255) NOT NULL,
- ct_params varchar(255) NOT NULL,
-);
-CREATE UNIQUE INDEX /*$wgDBprefix*/change_tag_rc_tag ON /*$wgDBprefix*/change_tag(ct_rc_id,ct_tag);
-CREATE UNIQUE INDEX /*$wgDBprefix*/change_tag_log_tag ON /*$wgDBprefix*/change_tag(ct_log_id,ct_tag);
-CREATE UNIQUE INDEX /*$wgDBprefix*/change_tag_rev_tag ON /*$wgDBprefix*/change_tag(ct_rev_id,ct_tag);
-CREATE INDEX /*$wgDBprefix*/change_tag_tag_id ON /*$wgDBprefix*/change_tag(ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
-CREATE TABLE /*$wgDBprefix*/tag_summary (
- ts_rc_id INT NOT NULL default 0,
- ts_log_id INT NOT NULL default 0,
- ts_rev_id INT NOT NULL default 0,
- ts_tags varchar(255) NOT NULL
+--
+-- Track links to external URLs
+--
+CREATE TABLE /*_*/externallinks (
+ -- Primary key
+ el_id int NOT NULL PRIMARY KEY IDENTITY,
+
+ -- page_id of the referring page
+ el_from int NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+
+ -- The URL
+ el_to nvarchar(max) NOT NULL,
+
+ -- In the case of HTTP URLs, this is the URL with any username or password
+ -- removed, and with the labels in the hostname reversed and converted to
+ -- lower case. An extra dot is added to allow for matching of either
+ -- example.com or *.example.com in a single scan.
+ -- Example:
+ -- http://user:password@sub.example.com/page.html
+ -- becomes
+ -- http://com.example.sub./page.html
+ -- which allows for fast searching for all pages under example.com with the
+ -- clause:
+ -- WHERE el_index LIKE 'http://com.example.%'
+ el_index nvarchar(450) NOT NULL
);
-CREATE UNIQUE INDEX /*$wgDBprefix*/tag_summary_rc_id ON /*$wgDBprefix*/tag_summary(ts_rc_id);
-CREATE UNIQUE INDEX /*$wgDBprefix*/tag_summary_log_id ON /*$wgDBprefix*/tag_summary(ts_log_id);
-CREATE UNIQUE INDEX /*$wgDBprefix*/tag_summary_rev_id ON /*$wgDBprefix*/tag_summary(ts_rev_id);
-CREATE TABLE /*$wgDBprefix*/valid_tag (
- vt_tag varchar(255) NOT NULL PRIMARY KEY
-);
+CREATE INDEX /*i*/el_from ON /*_*/externallinks (el_from);
+CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index);
--
--- Table for storing localisation data
+-- Track interlanguage links
--
-CREATE TABLE /*$wgDBprefix*/l10n_cache (
- -- language code
- lc_lang NVARCHAR(32) NOT NULL,
+CREATE TABLE /*_*/langlinks (
+ -- page_id of the referring page
+ ll_from int NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
- -- cache key
- lc_key NVARCHAR(255) NOT NULL,
+ -- Language code of the target
+ ll_lang nvarchar(20) NOT NULL default '',
- -- Value
- lc_value TEXT NOT NULL DEFAULT '',
+ -- Title of the target, including namespace
+ ll_title nvarchar(255) NOT NULL default ''
);
-CREATE INDEX /*$wgDBprefix*/lc_lang_key ON /*$wgDBprefix*/l10n_cache (lc_lang, lc_key);
---
--- Track links to external URLs
--- IE >= 4 supports no more than 2083 characters in a URL
-CREATE TABLE /*$wgDBprefix*/externallinks (
- el_id INT NOT NULL PRIMARY KEY clustered IDENTITY,
- el_from INT NOT NULL DEFAULT '0',
- el_to VARCHAR(2083) NOT NULL,
- el_index VARCHAR(896) NOT NULL,
-);
--- Maximum key length ON SQL Server is 900 bytes
-CREATE INDEX /*$wgDBprefix*/externallinks_index ON /*$wgDBprefix*/externallinks(el_index);
+CREATE UNIQUE INDEX /*i*/ll_from ON /*_*/langlinks (ll_from, ll_lang);
+CREATE INDEX /*i*/ll_lang ON /*_*/langlinks (ll_lang, ll_title);
---
--- Track INTerlanguage links
---
-CREATE TABLE /*$wgDBprefix*/langlinks (
- ll_from INT NOT NULL DEFAULT 0,
- ll_lang NVARCHAR(20) NOT NULL DEFAULT '',
- ll_title NVARCHAR(255) NOT NULL DEFAULT '',
- CONSTRAINT /*$wgDBprefix*/langlinks_pk PRIMARY KEY(ll_from, ll_lang),
-);
-CREATE UNIQUE INDEX /*$wgDBprefix*/langlinks_reverse_key ON /*$wgDBprefix*/langlinks(ll_lang,ll_title);
--
-- Track inline interwiki links
--
-CREATE TABLE /*$wgDBprefix*/iwlinks (
- -- page_id of the referring page
- iwl_from INT NOT NULL DEFAULT 0,
+CREATE TABLE /*_*/iwlinks (
+ -- page_id of the referring page
+ iwl_from int NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
- -- Interwiki prefix code of the target
- iwl_prefix NVARCHAR(20) NOT NULL DEFAULT '',
+ -- Interwiki prefix code of the target
+ iwl_prefix nvarchar(20) NOT NULL default '',
- -- Title of the target, including namespace
- iwl_title NVARCHAR(255) NOT NULL DEFAULT '',
+ -- Title of the target, including namespace
+ iwl_title nvarchar(255) NOT NULL default ''
);
-CREATE UNIQUE INDEX /*$wgDBprefix*/iwl_from ON /*$wgDBprefix*/iwlinks(iwl_from,iwl_prefix,iwl_title);
-CREATE UNIQUE INDEX /*$wgDBprefix*/iwl_prefix ON /*$wgDBprefix*/iwlinks(iwl_prefix,iwl_title);
+CREATE UNIQUE INDEX /*i*/iwl_from ON /*_*/iwlinks (iwl_from, iwl_prefix, iwl_title);
+CREATE INDEX /*i*/iwl_prefix_title_from ON /*_*/iwlinks (iwl_prefix, iwl_title, iwl_from);
+CREATE INDEX /*i*/iwl_prefix_from_title ON /*_*/iwlinks (iwl_prefix, iwl_from, iwl_title);
--
-- Contains a single row with some aggregate info
--- ON the state of the site.
+-- on the state of the site.
--
-CREATE TABLE /*$wgDBprefix*/site_stats (
- ss_row_id INT NOT NULL DEFAULT 1 PRIMARY KEY,
- ss_total_views BIGINT DEFAULT 0,
- ss_total_edits BIGINT DEFAULT 0,
- ss_good_articles BIGINT DEFAULT 0,
- ss_total_pages BIGINT DEFAULT -1,
- ss_users BIGINT DEFAULT -1,
- ss_active_users BIGINT DEFAULT -1,
- ss_admins INT DEFAULT -1,
- ss_images INT DEFAULT 0,
+CREATE TABLE /*_*/site_stats (
+ -- The single row should contain 1 here.
+ ss_row_id int NOT NULL,
+
+ -- Total number of page views, if hit counters are enabled.
+ ss_total_views bigint default 0,
+
+ -- Total number of edits performed.
+ ss_total_edits bigint default 0,
+
+ -- An approximate count of pages matching the following criteria:
+ -- * in namespace 0
+ -- * not a redirect
+ -- * contains the text '[['
+ -- See Article::isCountable() in includes/Article.php
+ ss_good_articles bigint default 0,
+
+ -- Total pages, theoretically equal to SELECT COUNT(*) FROM page; except faster
+ ss_total_pages bigint default '-1',
+
+ -- Number of users, theoretically equal to SELECT COUNT(*) FROM user;
+ ss_users bigint default '-1',
+
+ -- Number of users that still edit
+ ss_active_users bigint default '-1',
+
+ -- Number of images, equivalent to SELECT COUNT(*) FROM image
+ ss_images int default 0
);
--- INSERT INTO site_stats DEFAULT VALUES;
+-- Pointless index to assuage developer superstitions
+CREATE UNIQUE INDEX /*i*/ss_row_id ON /*_*/site_stats (ss_row_id);
+
--
-- Stores an ID for every time any article is visited;
--- depending ON $wgHitcounterUpdateFreq, it is
+-- depending on $wgHitcounterUpdateFreq, it is
-- periodically cleared and the page_counter column
--- in the page table updated for the all articles
+-- in the page table updated for all the articles
-- that have been visited.)
--
-CREATE TABLE /*$wgDBprefix*/hitcounter (
- hc_id BIGINT NOT NULL
+CREATE TABLE /*_*/hitcounter (
+ hc_id int NOT NULL
);
+
--
--- The Internet is full of jerks, alas. Sometimes it's handy
+-- The internet is full of jerks, alas. Sometimes it's handy
-- to block a vandal or troll account.
--
-CREATE TABLE /*$wgDBprefix*/ipblocks (
- ipb_id INT NOT NULL PRIMARY KEY,
- ipb_address NVARCHAR(255) NOT NULL,
- ipb_user INT NOT NULL DEFAULT 0,
- ipb_by INT NOT NULL DEFAULT 0,
- ipb_by_text NVARCHAR(255) NOT NULL DEFAULT '',
- ipb_reason NVARCHAR(255) NOT NULL,
- ipb_timestamp DATETIME NOT NULL DEFAULT GETDATE(),
- ipb_auto BIT NOT NULL DEFAULT 0,
- ipb_anon_only BIT NOT NULL DEFAULT 0,
- ipb_create_account BIT NOT NULL DEFAULT 1,
- ipb_enable_autoblock BIT NOT NULL DEFAULT 1,
- ipb_expiry DATETIME NOT NULL DEFAULT GETDATE(),
- ipb_range_start NVARCHAR(32) NOT NULL DEFAULT '',
- ipb_range_end NVARCHAR(32) NOT NULL DEFAULT '',
- ipb_deleted BIT NOT NULL DEFAULT 0,
- ipb_block_email BIT NOT NULL DEFAULT 0,
- ipb_allow_usertalk BIT NOT NULL DEFAULT 0,
- ipb_parent_block_id INT DEFAULT NULL,
+CREATE TABLE /*_*/ipblocks (
+ -- Primary key, introduced for privacy.
+ ipb_id int NOT NULL PRIMARY KEY IDENTITY,
+
+ -- Blocked IP address in dotted-quad form or user name.
+ ipb_address nvarchar(255) NOT NULL,
+
+ -- Blocked user ID or 0 for IP blocks.
+ ipb_user int REFERENCES /*_*/mwuser(user_id),
+
+ -- User ID who made the block.
+ ipb_by int REFERENCES /*_*/mwuser(user_id) ON DELETE CASCADE,
+
+ -- User name of blocker
+ ipb_by_text nvarchar(255) NOT NULL default '',
+
+ -- Text comment made by blocker.
+ ipb_reason nvarchar(255) NOT NULL,
+
+ -- Creation (or refresh) date in standard YMDHMS form.
+ -- IP blocks expire automatically.
+ ipb_timestamp varchar(14) NOT NULL default '',
+
+ -- Indicates that the IP address was banned because a banned
+ -- user accessed a page through it. If this is 1, ipb_address
+ -- will be hidden, and the block identified by block ID number.
+ ipb_auto bit NOT NULL default 0,
+
+ -- If set to 1, block applies only to logged-out users
+ ipb_anon_only bit NOT NULL default 0,
+
+ -- Block prevents account creation from matching IP addresses
+ ipb_create_account bit NOT NULL default 1,
+
+ -- Block triggers autoblocks
+ ipb_enable_autoblock bit NOT NULL default 1,
+
+ -- Time at which the block will expire.
+ -- May be "infinity"
+ ipb_expiry varchar(14) NOT NULL,
+
+ -- Start and end of an address range, in hexadecimal
+ -- Size chosen to allow IPv6
+ -- FIXME: these fields were originally blank for single-IP blocks,
+ -- but now they are populated. No migration was ever done. They
+ -- should be fixed to be blank again for such blocks (bug 49504).
+ ipb_range_start varchar(255) NOT NULL,
+ ipb_range_end varchar(255) NOT NULL,
+
+ -- Flag for entries hidden from users and Sysops
+ ipb_deleted bit NOT NULL default 0,
+
+ -- Block prevents user from accessing Special:Emailuser
+ ipb_block_email bit NOT NULL default 0,
+
+ -- Block allows user to edit their own talk page
+ ipb_allow_usertalk bit NOT NULL default 0,
+
+ -- ID of the block that caused this block to exist
+ -- Autoblocks set this to the original block
+ -- so that the original block being deleted also
+ -- deletes the autoblocks
+ ipb_parent_block_id int default NULL REFERENCES /*_*/ipblocks(ipb_id)
+
);
+
-- Unique index to support "user already blocked" messages
-- Any new options which prevent collisions should be included
---UNIQUE INDEX ipb_address (ipb_address(255), ipb_user, ipb_auto, ipb_anon_only),
-CREATE UNIQUE INDEX /*$wgDBprefix*/ipb_address ON /*$wgDBprefix*/ipblocks(ipb_address, ipb_user, ipb_auto, ipb_anon_only);
-CREATE INDEX /*$wgDBprefix*/ipb_user ON /*$wgDBprefix*/ipblocks(ipb_user);
-CREATE INDEX /*$wgDBprefix*/ipb_range ON /*$wgDBprefix*/ipblocks(ipb_range_start, ipb_range_end);
-CREATE INDEX /*$wgDBprefix*/ipb_timestamp ON /*$wgDBprefix*/ipblocks(ipb_timestamp);
-CREATE INDEX /*$wgDBprefix*/ipb_expiry ON /*$wgDBprefix*/ipblocks(ipb_expiry);
-;
+CREATE UNIQUE INDEX /*i*/ipb_address ON /*_*/ipblocks (ipb_address, ipb_user, ipb_auto, ipb_anon_only);
+
+CREATE INDEX /*i*/ipb_user ON /*_*/ipblocks (ipb_user);
+CREATE INDEX /*i*/ipb_range ON /*_*/ipblocks (ipb_range_start, ipb_range_end);
+CREATE INDEX /*i*/ipb_timestamp ON /*_*/ipblocks (ipb_timestamp);
+CREATE INDEX /*i*/ipb_expiry ON /*_*/ipblocks (ipb_expiry);
+CREATE INDEX /*i*/ipb_parent_block_id ON /*_*/ipblocks (ipb_parent_block_id);
+
--
-- Uploaded images and other files.
-CREATE TABLE /*$wgDBprefix*/image (
- img_name varchar(255) NOT NULL default '',
- img_size INT NOT NULL DEFAULT 0,
- img_width INT NOT NULL DEFAULT 0,
- img_height INT NOT NULL DEFAULT 0,
- img_metadata TEXT NOT NULL, -- was MEDIUMBLOB
- img_bits SMALLINT NOT NULL DEFAULT 0,
- img_media_type NVARCHAR(MAX) DEFAULT 'UNKNOWN',
- img_major_mime NVARCHAR(MAX) DEFAULT 'UNKNOWN',
- img_minor_mime NVARCHAR(MAX) NOT NULL DEFAULT 'unknown',
- img_description NVARCHAR(MAX) NOT NULL,
- img_user INT NOT NULL DEFAULT 0,
- img_user_text VARCHAR(255) NOT NULL DEFAULT '',
- img_timestamp DATETIME NOT NULL DEFAULT GETDATE(),
- img_sha1 VARCHAR(255) NOT NULL default '',
-);
--- Used by Special:Imagelist for sort-by-size
-CREATE INDEX /*$wgDBprefix*/img_size ON /*$wgDBprefix*/[image](img_size);
--- Used by Special:Newimages and Special:Imagelist
-CREATE INDEX /*$wgDBprefix*/img_timestamp ON /*$wgDBprefix*/[image](img_timestamp)
-CREATE INDEX /*$wgDBprefix*/[img_sha1] ON /*wgDBprefix*/[image](img_sha1)
+--
+CREATE TABLE /*_*/image (
+ -- Filename.
+ -- This is also the title of the associated description page,
+ -- which will be in namespace 6 (NS_FILE).
+ img_name varbinary(255) NOT NULL default 0x PRIMARY KEY,
+
+ -- File size in bytes.
+ img_size int NOT NULL default 0,
+
+ -- For images, size in pixels.
+ img_width int NOT NULL default 0,
+ img_height int NOT NULL default 0,
+
+ -- Extracted Exif metadata stored as a serialized PHP array.
+ img_metadata varbinary(max) NOT NULL,
+
+ -- For images, bits per pixel if known.
+ img_bits int NOT NULL default 0,
+
+ -- Media type as defined by the MEDIATYPE_xxx constants
+ img_media_type varchar(16) default null,
+
+ -- major part of a MIME media type as defined by IANA
+ -- see http://www.iana.org/assignments/media-types/
+ img_major_mime varchar(16) not null default 'unknown',
+
+ -- minor part of a MIME media type as defined by IANA
+ -- the minor parts are not required to adher to any standard
+ -- but should be consistent throughout the database
+ -- see http://www.iana.org/assignments/media-types/
+ img_minor_mime nvarchar(100) NOT NULL default 'unknown',
+
+ -- Description field as entered by the uploader.
+ -- This is displayed in image upload history and logs.
+ img_description nvarchar(255) NOT NULL,
+
+ -- user_id and user_name of uploader.
+ img_user int REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
+ img_user_text nvarchar(255) NOT NULL,
+
+ -- Time of the upload.
+ img_timestamp nvarchar(14) NOT NULL default '',
+
+ -- SHA-1 content hash in base-36
+ img_sha1 nvarchar(32) NOT NULL default '',
+
+ CONSTRAINT img_major_mime_ckc check (img_major_mime IN('unknown', 'application', 'audio', 'image', 'text', 'video', 'message', 'model', 'multipart', 'chemical')),
+ CONSTRAINT img_media_type_ckc check (img_media_type in('UNKNOWN', 'BITMAP', 'DRAWING', 'AUDIO', 'VIDEO', 'MULTIMEDIA', 'OFFICE', 'TEXT', 'EXECUTABLE', 'ARCHIVE'))
+);
+
+CREATE INDEX /*i*/img_usertext_timestamp ON /*_*/image (img_user_text,img_timestamp);
+-- Used by Special:ListFiles for sort-by-size
+CREATE INDEX /*i*/img_size ON /*_*/image (img_size);
+-- Used by Special:Newimages and Special:ListFiles
+CREATE INDEX /*i*/img_timestamp ON /*_*/image (img_timestamp);
+-- Used in API and duplicate search
+CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1);
+-- Used to get media of one type
+CREATE INDEX /*i*/img_media_mime ON /*_*/image (img_media_type,img_major_mime,img_minor_mime);
+
--
-- Previous revisions of uploaded files.
-- Awkwardly, image rows have to be moved into
-- this table at re-upload time.
--
-CREATE TABLE /*$wgDBprefix*/oldimage (
- oi_name VARCHAR(255) NOT NULL DEFAULT '',
- oi_archive_name VARCHAR(255) NOT NULL DEFAULT '',
- oi_size INT NOT NULL DEFAULT 0,
- oi_width INT NOT NULL DEFAULT 0,
- oi_height INT NOT NULL DEFAULT 0,
- oi_bits SMALLINT NOT NULL DEFAULT 0,
- oi_description NVARCHAR(MAX) NOT NULL,
- oi_user INT NOT NULL DEFAULT 0,
- oi_user_text VARCHAR(255) NOT NULL DEFAULT '',
- oi_timestamp DATETIME NOT NULL DEFAULT GETDATE(),
- oi_metadata TEXT NOT NULL,
- oi_media_type NVARCHAR(MAX) DEFAULT 'UNKNOWN',
- oi_major_mime NVARCHAR(MAX) NOT NULL DEFAULT 'UNKNOWN',
- oi_minor_mime NVARCHAR(MAX) NOT NULL DEFAULT 'unknown',
- oi_deleted BIT NOT NULL default 0,
- oi_sha1 VARCHAR(255) NOT NULL default '',
-);
-CREATE INDEX /*$wgDBprefix*/oi_usertext_timestamp ON /*$wgDBprefix*/oldimage(oi_user_text,oi_timestamp);
-CREATE INDEX /*$wgDBprefix*/oi_name_timestamp ON /*$wgDBprefix*/oldimage(oi_name, oi_timestamp);
-CREATE INDEX /*$wgDBprefix*/oi_name_archive_name ON /*$wgDBprefix*/oldimage(oi_name,oi_archive_name);
-CREATE INDEX /*$wgDBprefix*/[oi_sha1] ON /*$wgDBprefix*/oldimage(oi_sha1);
+CREATE TABLE /*_*/oldimage (
+ -- Base filename: key to image.img_name
+ oi_name varbinary(255) NOT NULL default 0x REFERENCES /*_*/image(img_name) ON DELETE CASCADE ON UPDATE CASCADE,
+
+ -- Filename of the archived file.
+ -- This is generally a timestamp and '!' prepended to the base name.
+ oi_archive_name varbinary(255) NOT NULL default 0x,
+
+ -- Other fields as in image...
+ oi_size int NOT NULL default 0,
+ oi_width int NOT NULL default 0,
+ oi_height int NOT NULL default 0,
+ oi_bits int NOT NULL default 0,
+ oi_description nvarchar(255) NOT NULL,
+ oi_user int REFERENCES /*_*/mwuser(user_id),
+ oi_user_text nvarchar(255) NOT NULL,
+ oi_timestamp varchar(14) NOT NULL default '',
+
+ oi_metadata nvarchar(max) NOT NULL,
+ oi_media_type varchar(16) default null,
+ oi_major_mime varchar(16) not null default 'unknown',
+ oi_minor_mime nvarchar(100) NOT NULL default 'unknown',
+ oi_deleted tinyint NOT NULL default 0,
+ oi_sha1 nvarchar(32) NOT NULL default '',
+
+ CONSTRAINT oi_major_mime_ckc check (oi_major_mime IN('unknown', 'application', 'audio', 'image', 'text', 'video', 'message', 'model', 'multipart', 'chemical')),
+ CONSTRAINT oi_media_type_ckc check (oi_media_type IN('UNKNOWN', 'BITMAP', 'DRAWING', 'AUDIO', 'VIDEO', 'MULTIMEDIA', 'OFFICE', 'TEXT', 'EXECUTABLE', 'ARCHIVE'))
+);
+
+CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timestamp);
+CREATE INDEX /*i*/oi_name_timestamp ON /*_*/oldimage (oi_name,oi_timestamp);
+-- oi_archive_name truncated to 14 to avoid key length overflow
+CREATE INDEX /*i*/oi_name_archive_name ON /*_*/oldimage (oi_name,oi_archive_name);
+CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1);
+
--
-- Record of deleted file data
--
-CREATE TABLE /*$wgDBprefix*/filearchive (
- fa_id INT NOT NULL PRIMARY KEY,
- fa_name NVARCHAR(255) NOT NULL DEFAULT '',
- fa_archive_name NVARCHAR(255) DEFAULT '',
- fa_storage_group NVARCHAR(16),
- fa_storage_key NVARCHAR(64) DEFAULT '',
- fa_deleted_user INT,
- fa_deleted_timestamp NVARCHAR(14) DEFAULT NULL,
- fa_deleted_reason NVARCHAR(255),
- fa_size SMALLINT DEFAULT 0,
- fa_width SMALLINT DEFAULT 0,
- fa_height SMALLINT DEFAULT 0,
- fa_metadata NVARCHAR(MAX), -- was mediumblob
- fa_bits SMALLINT DEFAULT 0,
- fa_media_type NVARCHAR(11) DEFAULT NULL,
- fa_major_mime NVARCHAR(11) DEFAULT 'unknown',
- fa_minor_mime NVARCHAR(32) DEFAULT 'unknown',
- fa_description NVARCHAR(255),
- fa_user INT DEFAULT 0,
- fa_user_text NVARCHAR(255) DEFAULT '',
- fa_timestamp DATETIME DEFAULT GETDATE(),
- fa_deleted BIT NOT NULL DEFAULT 0,
-);
--- Pick by image name
-CREATE INDEX /*$wgDBprefix*/filearchive_name ON /*$wgDBprefix*/filearchive(fa_name,fa_timestamp);
--- Pick by dupe files
-CREATE INDEX /*$wgDBprefix*/filearchive_dupe ON /*$wgDBprefix*/filearchive(fa_storage_group,fa_storage_key);
--- Pick by deletion time
-CREATE INDEX /*$wgDBprefix*/filearchive_time ON /*$wgDBprefix*/filearchive(fa_deleted_timestamp);
--- Pick by deleter
-CREATE INDEX /*$wgDBprefix*/filearchive_user ON /*$wgDBprefix*/filearchive(fa_deleted_user);
+CREATE TABLE /*_*/filearchive (
+ -- Unique row id
+ fa_id int NOT NULL PRIMARY KEY IDENTITY,
+
+ -- Original base filename; key to image.img_name, page.page_title, etc
+ fa_name nvarchar(255) NOT NULL default '',
+
+ -- Filename of archived file, if an old revision
+ fa_archive_name nvarchar(255) default '',
+
+ -- Which storage bin (directory tree or object store) the file data
+ -- is stored in. Should be 'deleted' for files that have been deleted;
+ -- any other bin is not yet in use.
+ fa_storage_group nvarchar(16),
+
+ -- SHA-1 of the file contents plus extension, used as a key for storage.
+ -- eg 8f8a562add37052a1848ff7771a2c515db94baa9.jpg
+ --
+ -- If NULL, the file was missing at deletion time or has been purged
+ -- from the archival storage.
+ fa_storage_key nvarchar(64) default '',
+
+ -- Deletion information, if this file is deleted.
+ fa_deleted_user int,
+ fa_deleted_timestamp varchar(14) default '',
+ fa_deleted_reason nvarchar(max),
+
+ -- Duped fields from image
+ fa_size int default 0,
+ fa_width int default 0,
+ fa_height int default 0,
+ fa_metadata nvarchar(max),
+ fa_bits int default 0,
+ fa_media_type varchar(16) default null,
+ fa_major_mime varchar(16) not null default 'unknown',
+ fa_minor_mime nvarchar(100) default 'unknown',
+ fa_description nvarchar(255),
+ fa_user int default 0 REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
+ fa_user_text nvarchar(255),
+ fa_timestamp varchar(14) default '',
+
+ -- Visibility of deleted revisions, bitfield
+ fa_deleted tinyint NOT NULL default 0,
+
+ -- sha1 hash of file content
+ fa_sha1 nvarchar(32) NOT NULL default '',
+
+ CONSTRAINT fa_major_mime_ckc check (fa_major_mime in('unknown', 'application', 'audio', 'image', 'text', 'video', 'message', 'model', 'multipart', 'chemical')),
+ CONSTRAINT fa_media_type_ckc check (fa_media_type in('UNKNOWN', 'BITMAP', 'DRAWING', 'AUDIO', 'VIDEO', 'MULTIMEDIA', 'OFFICE', 'TEXT', 'EXECUTABLE', 'ARCHIVE'))
+);
+
+-- pick out by image name
+CREATE INDEX /*i*/fa_name ON /*_*/filearchive (fa_name, fa_timestamp);
+-- pick out dupe files
+CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_storage_key);
+-- sort by deletion time
+CREATE INDEX /*i*/fa_deleted_timestamp ON /*_*/filearchive (fa_deleted_timestamp);
+-- sort by uploader
+CREATE INDEX /*i*/fa_user_timestamp ON /*_*/filearchive (fa_user_text,fa_timestamp);
+-- find file by sha1, 10 bytes will be enough for hashes to be indexed
+CREATE INDEX /*i*/fa_sha1 ON /*_*/filearchive (fa_sha1);
+
+
+--
+-- Store information about newly uploaded files before they're
+-- moved into the actual filestore
+--
+CREATE TABLE /*_*/uploadstash (
+ us_id int NOT NULL PRIMARY KEY IDENTITY,
+
+ -- the user who uploaded the file.
+ us_user int REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
+
+ -- file key. this is how applications actually search for the file.
+ -- this might go away, or become the primary key.
+ us_key nvarchar(255) NOT NULL,
+
+ -- the original path
+ us_orig_path nvarchar(255) NOT NULL,
+
+ -- the temporary path at which the file is actually stored
+ us_path nvarchar(255) NOT NULL,
+
+ -- which type of upload the file came from (sometimes)
+ us_source_type nvarchar(50),
+
+ -- the date/time on which the file was added
+ us_timestamp varchar(14) NOT NULL,
+
+ us_status nvarchar(50) NOT NULL,
+
+ -- chunk counter starts at 0, current offset is stored in us_size
+ us_chunk_inx int NULL,
+
+ -- Serialized file properties from FSFile::getProps()
+ us_props nvarchar(max),
+
+ -- file size in bytes
+ us_size int NOT NULL,
+ -- this hash comes from FSFile::getSha1Base36(), and is 31 characters
+ us_sha1 nvarchar(31) NOT NULL,
+ us_mime nvarchar(255),
+ -- Media type as defined by the MEDIATYPE_xxx constants, should duplicate definition in the image table
+ us_media_type varchar(16) default null,
+ -- image-specific properties
+ us_image_width int,
+ us_image_height int,
+ us_image_bits smallint,
+
+ CONSTRAINT us_media_type_ckc check (us_media_type in('UNKNOWN', 'BITMAP', 'DRAWING', 'AUDIO', 'VIDEO', 'MULTIMEDIA', 'OFFICE', 'TEXT', 'EXECUTABLE', 'ARCHIVE'))
+);
+
+-- sometimes there's a delete for all of a user's stuff.
+CREATE INDEX /*i*/us_user ON /*_*/uploadstash (us_user);
+-- pick out files by key, enforce key uniqueness
+CREATE UNIQUE INDEX /*i*/us_key ON /*_*/uploadstash (us_key);
+-- the abandoned upload cleanup script needs this
+CREATE INDEX /*i*/us_timestamp ON /*_*/uploadstash (us_timestamp);
+
--
-- Primarily a summary table for Special:Recentchanges,
-- this table contains some additional info on edits from
-- the last few days, see Article::editUpdates()
--
-CREATE TABLE /*$wgDBprefix*/recentchanges (
- rc_id INT NOT NULL,
- rc_timestamp DATETIME DEFAULT GETDATE(),
- rc_cur_time DATETIME DEFAULT GETDATE(),
- rc_user INT DEFAULT 0,
- rc_user_text NVARCHAR(255) DEFAULT '',
- rc_namespace SMALLINT DEFAULT 0,
- rc_title NVARCHAR(255) DEFAULT '',
- rc_comment NVARCHAR(255) DEFAULT '',
- rc_minor BIT DEFAULT 0,
- rc_bot BIT DEFAULT 0,
- rc_new BIT DEFAULT 0,
- rc_cur_id INT DEFAULT 0,
- rc_this_oldid INT DEFAULT 0,
- rc_last_oldid INT DEFAULT 0,
- rc_type tinyint DEFAULT 0,
- rc_patrolled BIT DEFAULT 0,
- rc_ip NCHAR(40) DEFAULT '',
- rc_old_len INT DEFAULT 0,
- rc_new_len INT DEFAULT 0,
- rc_deleted BIT DEFAULT 0,
- rc_logid INT DEFAULT 0,
- rc_log_type NVARCHAR(255) NULL DEFAULT NULL,
- rc_log_action NVARCHAR(255) NULL DEFAULT NULL,
- rc_params NVARCHAR(MAX) DEFAULT '',
-);
-CREATE INDEX /*$wgDBprefix*/rc_timestamp ON /*$wgDBprefix*/recentchanges(rc_timestamp);
-CREATE INDEX /*$wgDBprefix*/rc_namespace_title ON /*$wgDBprefix*/recentchanges(rc_namespace, rc_title);
-CREATE INDEX /*$wgDBprefix*/rc_cur_id ON /*$wgDBprefix*/recentchanges(rc_cur_id);
-CREATE INDEX /*$wgDBprefix*/new_name_timestamp ON /*$wgDBprefix*/recentchanges(rc_new,rc_namespace,rc_timestamp);
-CREATE INDEX /*$wgDBprefix*/rc_ip ON /*$wgDBprefix*/recentchanges(rc_ip);
-CREATE INDEX /*$wgDBprefix*/rc_ns_usertext ON /*$wgDBprefix*/recentchanges(rc_namespace, rc_user_text);
-CREATE INDEX /*$wgDBprefix*/rc_user_text ON /*$wgDBprefix*/recentchanges(rc_user_text, rc_timestamp);
-;
-
-CREATE TABLE /*$wgDBprefix*/watchlist (
- wl_user INT NOT NULL,
- wl_namespace SMALLINT NOT NULL DEFAULT 0,
- wl_title NVARCHAR(255) NOT NULL DEFAULT '',
- wl_notificationtimestamp NVARCHAR(14) DEFAULT NULL,
-
-);
-CREATE UNIQUE INDEX /*$wgDBprefix*/namespace_title ON /*$wgDBprefix*/watchlist(wl_namespace,wl_title);
-
--- Needs fulltext index.
-CREATE TABLE /*$wgDBprefix*/searchindex (
- si_page INT NOT NULL unique REFERENCES /*$wgDBprefix*/page(page_id) ON DELETE CASCADE,
- si_title varbinary(max) NOT NULL,
- si_text varbinary(max) NOT NULL,
- si_ext CHAR(4) NOT NULL DEFAULT '.txt',
-);
-CREATE FULLTEXT CATALOG wikidb AS DEFAULT;
-CREATE UNIQUE CLUSTERED INDEX searchindex_page ON searchindex (si_page);
-CREATE FULLTEXT INDEX on searchindex (si_title TYPE COLUMN si_ext, si_text TYPE COLUMN si_ext)
-KEY INDEX searchindex_page
-;
-
--- This table is not used unless profiling is turned on
-CREATE TABLE profiling (
- pf_count INTEGER NOT NULL DEFAULT 0,
- pf_time NUMERIC(18,10) NOT NULL DEFAULT 0,
- pf_name NVARCHAR(200) NOT NULL,
- pf_server NVARCHAR(200) NULL
-);
-CREATE UNIQUE INDEX pf_name_server ON profiling (pf_name, pf_server);
-
---
--- Recognized INTerwiki link prefixes
---
-CREATE TABLE /*$wgDBprefix*/interwiki (
- iw_prefix NCHAR(32) NOT NULL PRIMARY KEY,
- iw_url NCHAR(127) NOT NULL,
- iw_api TEXT NOT NULL DEFAULT '',
- iw_wikiid NVARCHAR(64) NOT NULL DEFAULT '',
- iw_local BIT NOT NULL,
- iw_trans BIT NOT NULL DEFAULT 0,
+CREATE TABLE /*_*/recentchanges (
+ rc_id int NOT NULL PRIMARY KEY IDENTITY,
+ rc_timestamp varchar(14) not null default '',
+
+ -- This is no longer used
+ -- Field kept in database for downgrades
+ -- @todo: add drop patch with 1.24
+ rc_cur_time varchar(14) NOT NULL default '',
+
+ -- As in revision
+ rc_user int NOT NULL default 0 REFERENCES /*_*/mwuser(user_id),
+ rc_user_text nvarchar(255) NOT NULL,
+
+ -- When pages are renamed, their RC entries do _not_ change.
+ rc_namespace int NOT NULL default 0,
+ rc_title nvarchar(255) NOT NULL default '',
+
+ -- as in revision...
+ rc_comment nvarchar(255) NOT NULL default '',
+ rc_minor bit NOT NULL default 0,
+
+ -- Edits by user accounts with the 'bot' rights key are
+ -- marked with a 1 here, and will be hidden from the
+ -- default view.
+ rc_bot bit NOT NULL default 0,
+
+ -- Set if this change corresponds to a page creation
+ rc_new bit NOT NULL default 0,
+
+ -- Key to page_id (was cur_id prior to 1.5).
+ -- This will keep links working after moves while
+ -- retaining the at-the-time name in the changes list.
+ rc_cur_id int REFERENCES /*_*/page(page_id),
+
+ -- rev_id of the given revision
+ rc_this_oldid int REFERENCES /*_*/revision(rev_id),
+
+ -- rev_id of the prior revision, for generating diff links.
+ rc_last_oldid int REFERENCES /*_*/revision(rev_id),
+
+ -- The type of change entry (RC_EDIT,RC_NEW,RC_LOG,RC_EXTERNAL)
+ rc_type tinyint NOT NULL default 0,
+
+ -- The source of the change entry (replaces rc_type)
+ -- default of '' is temporary, needed for initial migration
+ rc_source nvarchar(16) not null default '',
+
+ -- If the Recent Changes Patrol option is enabled,
+ -- users may mark edits as having been reviewed to
+ -- remove a warning flag on the RC list.
+ -- A value of 1 indicates the page has been reviewed.
+ rc_patrolled bit NOT NULL default 0,
+
+ -- Recorded IP address the edit was made from, if the
+ -- $wgPutIPinRC option is enabled.
+ rc_ip nvarchar(40) NOT NULL default '',
+
+ -- Text length in characters before
+ -- and after the edit
+ rc_old_len int,
+ rc_new_len int,
+
+ -- Visibility of recent changes items, bitfield
+ rc_deleted tinyint NOT NULL default 0,
+
+ -- Value corresponding to log_id, specific log entries
+ rc_logid int, -- FK added later
+ -- Store log type info here, or null
+ rc_log_type nvarchar(255) NULL default NULL,
+ -- Store log action or null
+ rc_log_action nvarchar(255) NULL default NULL,
+ -- Log params
+ rc_params nvarchar(max) NULL
);
+CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp);
+CREATE INDEX /*i*/rc_namespace_title ON /*_*/recentchanges (rc_namespace, rc_title);
+CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id);
+CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace,rc_timestamp);
+CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip);
+CREATE INDEX /*i*/rc_ns_usertext ON /*_*/recentchanges (rc_namespace, rc_user_text);
+CREATE INDEX /*i*/rc_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp);
+
+
+CREATE TABLE /*_*/watchlist (
+ -- Key to user.user_id
+ wl_user int NOT NULL REFERENCES /*_*/mwuser(user_id) ON DELETE CASCADE,
+
+ -- Key to page_namespace/page_title
+ -- Note that users may watch pages which do not exist yet,
+ -- or existed in the past but have been deleted.
+ wl_namespace int NOT NULL default 0,
+ wl_title nvarchar(255) NOT NULL default '',
+
+ -- Timestamp used to send notification e-mails and show "updated since last visit" markers on
+ -- history and recent changes / watchlist. Set to NULL when the user visits the latest revision
+ -- of the page, which means that they should be sent an e-mail on the next change.
+ wl_notificationtimestamp varchar(14)
+
+);
+
+CREATE UNIQUE INDEX /*i*/wl_user ON /*_*/watchlist (wl_user, wl_namespace, wl_title);
+CREATE INDEX /*i*/namespace_title ON /*_*/watchlist (wl_namespace, wl_title);
+
+
+--
+-- Our search index for the builtin MediaWiki search
+--
+CREATE TABLE /*_*/searchindex (
+ -- Key to page_id
+ si_page int NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+
+ -- Munged version of title
+ si_title nvarchar(255) NOT NULL default '',
+
+ -- Munged version of body text
+ si_text nvarchar(max) NOT NULL
+);
+
+CREATE UNIQUE INDEX /*i*/si_page ON /*_*/searchindex (si_page);
+-- Fulltext index is defined in MssqlInstaller.php
+
+--
+-- Recognized interwiki link prefixes
+--
+CREATE TABLE /*_*/interwiki (
+ -- The interwiki prefix, (e.g. "Meatball", or the language prefix "de")
+ iw_prefix nvarchar(32) NOT NULL,
+
+ -- The URL of the wiki, with "$1" as a placeholder for an article name.
+ -- Any spaces in the name will be transformed to underscores before
+ -- insertion.
+ iw_url nvarchar(max) NOT NULL,
+
+ -- The URL of the file api.php
+ iw_api nvarchar(max) NOT NULL,
+
+ -- The name of the database (for a connection to be established with wfGetLB( 'wikiid' ))
+ iw_wikiid nvarchar(64) NOT NULL,
+
+ -- A boolean value indicating whether the wiki is in this project
+ -- (used, for example, to detect redirect loops)
+ iw_local bit NOT NULL,
+
+ -- Boolean value indicating whether interwiki transclusions are allowed.
+ iw_trans bit NOT NULL default 0
+);
+
+CREATE UNIQUE INDEX /*i*/iw_prefix ON /*_*/interwiki (iw_prefix);
+
+
--
-- Used for caching expensive grouped queries
--
-CREATE TABLE /*$wgDBprefix*/querycache (
- qc_type NCHAR(32) NOT NULL,
- qc_value INT NOT NULL DEFAULT '0',
- qc_namespace SMALLINT NOT NULL DEFAULT 0,
- qc_title NCHAR(255) NOT NULL DEFAULT '',
- CONSTRAINT /*$wgDBprefix*/qc_pk PRIMARY KEY (qc_type,qc_value)
+CREATE TABLE /*_*/querycache (
+ -- A key name, generally the base name of of the special page.
+ qc_type nvarchar(32) NOT NULL,
+
+ -- Some sort of stored value. Sizes, counts...
+ qc_value int NOT NULL default 0,
+
+ -- Target namespace+title
+ qc_namespace int NOT NULL default 0,
+ qc_title nvarchar(255) NOT NULL default ''
);
+CREATE INDEX /*i*/qc_type ON /*_*/querycache (qc_type,qc_value);
+
+
--
-- For a few generic cache operations if not using Memcached
--
-CREATE TABLE /*$wgDBprefix*/objectcache (
- keyname NCHAR(255) NOT NULL DEFAULT '',
- [value] NVARCHAR(MAX), -- IMAGE,
- exptime DATETIME, -- This is treated as a DATETIME
-);
-CREATE CLUSTERED INDEX /*$wgDBprefix*/[objectcache_time] ON /*$wgDBprefix*/objectcache(exptime);
-CREATE UNIQUE INDEX /*$wgDBprefix*/[objectcache_PK] ON /*wgDBprefix*/objectcache(keyname);
---
--- Cache of INTerwiki transclusion
---
-CREATE TABLE /*$wgDBprefix*/transcache (
- tc_url NVARCHAR(255) NOT NULL PRIMARY KEY,
- tc_contents NVARCHAR(MAX),
- tc_time INT NOT NULL,
-);
-
-CREATE TABLE /*$wgDBprefix*/logging (
- log_id INT PRIMARY KEY IDENTITY,
- log_type NCHAR(10) NOT NULL DEFAULT '',
- log_action NCHAR(10) NOT NULL DEFAULT '',
- log_timestamp DATETIME NOT NULL DEFAULT GETDATE(),
- log_user INT NOT NULL DEFAULT 0,
- log_user_text NVARCHAR(255) NOT NULL DEFAULT '',
- log_namespace INT NOT NULL DEFAULT 0,
- log_title NVARCHAR(255) NOT NULL DEFAULT '',
- log_page INT NULL DEFAULT NULL,
- log_comment NVARCHAR(255) NOT NULL DEFAULT '',
- log_params NVARCHAR(MAX) NOT NULL,
- log_deleted BIT NOT NULL DEFAULT 0,
-);
-CREATE INDEX /*$wgDBprefix*/type_time ON /*$wgDBprefix*/logging (log_type, log_timestamp);
-CREATE INDEX /*$wgDBprefix*/user_time ON /*$wgDBprefix*/logging (log_user, log_timestamp);
-CREATE INDEX /*$wgDBprefix*/page_time ON /*$wgDBprefix*/logging (log_namespace, log_title, log_timestamp);
-CREATE INDEX /*$wgDBprefix*/times ON /*$wgDBprefix*/logging (log_timestamp);
-CREATE INDEX /*$wgDBprefix*/log_user_type_time ON /*$wgDBprefix*/logging (log_user, log_type, log_timestamp);
-CREATE INDEX /*$wgDBprefix*/log_page_id_time ON /*$wgDBprefix*/logging (log_page,log_timestamp);
-
-CREATE TABLE /*$wgDBprefix*/log_search (
- -- The type of ID (rev ID, log ID, rev timestamp, username)
- ls_field NVARCHAR(32) NOT NULL,
- -- The value of the ID
- ls_value NVARCHAR(255) NOT NULL,
- -- Key to log_id
- ls_log_id INT NOT NULL default 0,
-);
-CREATE UNIQUE INDEX /*$wgDBprefix*/ls_field_val ON /*$wgDBprefix*/log_search (ls_field,ls_value,ls_log_id);
-CREATE INDEX /*$wgDBprefix*/ls_log_id ON /*$wgDBprefix*/log_search (ls_log_id);
+CREATE TABLE /*_*/objectcache (
+ keyname nvarchar(255) NOT NULL default '' PRIMARY KEY,
+ value varbinary(max),
+ exptime varchar(14)
+);
+CREATE INDEX /*i*/exptime ON /*_*/objectcache (exptime);
+
+
+--
+-- Cache of interwiki transclusion
+--
+CREATE TABLE /*_*/transcache (
+ tc_url nvarchar(255) NOT NULL,
+ tc_contents nvarchar(max),
+ tc_time varchar(14) NOT NULL
+);
+
+CREATE UNIQUE INDEX /*i*/tc_url_idx ON /*_*/transcache (tc_url);
+
+
+CREATE TABLE /*_*/logging (
+ -- Log ID, for referring to this specific log entry, probably for deletion and such.
+ log_id int NOT NULL PRIMARY KEY IDENTITY(0,1),
+
+ -- Symbolic keys for the general log type and the action type
+ -- within the log. The output format will be controlled by the
+ -- action field, but only the type controls categorization.
+ log_type nvarchar(32) NOT NULL default '',
+ log_action nvarchar(32) NOT NULL default '',
+
+ -- Timestamp. Duh.
+ log_timestamp varchar(14) NOT NULL default '',
+
+ -- The user who performed this action; key to user_id
+ log_user int REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
+
+ -- Name of the user who performed this action
+ log_user_text nvarchar(255) NOT NULL default '',
+
+ -- Key to the page affected. Where a user is the target,
+ -- this will point to the user page.
+ log_namespace int NOT NULL default 0,
+ log_title nvarchar(255) NOT NULL default '',
+ log_page int NULL REFERENCES /*_*/page(page_id) ON DELETE SET NULL,
+
+ -- Freeform text. Interpreted as edit history comments.
+ log_comment nvarchar(255) NOT NULL default '',
+
+ -- miscellaneous parameters:
+ -- LF separated list (old system) or serialized PHP array (new system)
+ log_params nvarchar(max) NOT NULL,
+
+ -- rev_deleted for logs
+ log_deleted tinyint NOT NULL default 0
+);
+
+CREATE INDEX /*i*/type_time ON /*_*/logging (log_type, log_timestamp);
+CREATE INDEX /*i*/user_time ON /*_*/logging (log_user, log_timestamp);
+CREATE INDEX /*i*/page_time ON /*_*/logging (log_namespace, log_title, log_timestamp);
+CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp);
+CREATE INDEX /*i*/log_user_type_time ON /*_*/logging (log_user, log_type, log_timestamp);
+CREATE INDEX /*i*/log_page_id_time ON /*_*/logging (log_page,log_timestamp);
+CREATE INDEX /*i*/type_action ON /*_*/logging (log_type, log_action, log_timestamp);
+CREATE INDEX /*i*/log_user_text_type_time ON /*_*/logging (log_user_text, log_type, log_timestamp);
+CREATE INDEX /*i*/log_user_text_time ON /*_*/logging (log_user_text, log_timestamp);
+
+INSERT INTO /*_*/logging (log_user,log_page,log_params) VALUES(0,0,'');
+
+ALTER TABLE /*_*/recentchanges ADD CONSTRAINT FK_rc_logid_log_id FOREIGN KEY (rc_logid) REFERENCES /*_*/logging(log_id) ON DELETE CASCADE;
+
+CREATE TABLE /*_*/log_search (
+ -- The type of ID (rev ID, log ID, rev timestamp, username)
+ ls_field nvarchar(32) NOT NULL,
+ -- The value of the ID
+ ls_value nvarchar(255) NOT NULL,
+ -- Key to log_id
+ ls_log_id int REFERENCES /*_*/logging(log_id) ON DELETE CASCADE
+);
+CREATE UNIQUE INDEX /*i*/ls_field_val ON /*_*/log_search (ls_field,ls_value,ls_log_id);
+CREATE INDEX /*i*/ls_log_id ON /*_*/log_search (ls_log_id);
-- Jobs performed by parallel apache threads or a command-line daemon
-CREATE TABLE /*$wgDBprefix*/job (
- job_id INT NOT NULL PRIMARY KEY,
- job_cmd NVARCHAR(200) NOT NULL DEFAULT '',
- job_namespace INT NOT NULL,
- job_title NVARCHAR(200) NOT NULL,
- job_params NVARCHAR(255) NOT NULL,
+CREATE TABLE /*_*/job (
+ job_id int NOT NULL PRIMARY KEY IDENTITY,
+
+ -- Command name
+ -- Limited to 60 to prevent key length overflow
+ job_cmd nvarchar(60) NOT NULL default '',
+
+ -- Namespace and title to act on
+ -- Should be 0 and '' if the command does not operate on a title
+ job_namespace int NOT NULL,
+ job_title nvarchar(255) NOT NULL,
+
+ -- Timestamp of when the job was inserted
+ -- NULL for jobs added before addition of the timestamp
+ job_timestamp nvarchar(14) NULL default NULL,
+
+ -- Any other parameters to the command
+ -- Stored as a PHP serialized array, or an empty string if there are no parameters
+ job_params nvarchar(max) NOT NULL,
+
+ -- Random, non-unique, number used for job acquisition (for lock concurrency)
+ job_random int NOT NULL default 0,
+
+ -- The number of times this job has been locked
+ job_attempts int NOT NULL default 0,
+
+ -- Field that conveys process locks on rows via process UUIDs
+ job_token nvarchar(32) NOT NULL default '',
+
+ -- Timestamp when the job was locked
+ job_token_timestamp varchar(14) NULL default NULL,
+
+ -- Base 36 SHA1 of the job parameters relevant to detecting duplicates
+ job_sha1 nvarchar(32) NOT NULL default ''
);
-CREATE INDEX /*$wgDBprefix*/job_idx ON /*$wgDBprefix*/job(job_cmd,job_namespace,job_title);
+
+CREATE INDEX /*i*/job_sha1 ON /*_*/job (job_sha1);
+CREATE INDEX /*i*/job_cmd_token ON /*_*/job (job_cmd,job_token,job_random);
+CREATE INDEX /*i*/job_cmd_token_id ON /*_*/job (job_cmd,job_token,job_id);
+CREATE INDEX /*i*/job_cmd ON /*_*/job (job_cmd, job_namespace, job_title);
+CREATE INDEX /*i*/job_timestamp ON /*_*/job (job_timestamp);
+
-- Details of updates to cached special pages
-CREATE TABLE /*$wgDBprefix*/querycache_info (
- qci_type NVARCHAR(32) NOT NULL DEFAULT '' PRIMARY KEY,
- qci_timestamp NVARCHAR(14) NOT NULL DEFAULT '19700101000000',
+CREATE TABLE /*_*/querycache_info (
+ -- Special page name
+ -- Corresponds to a qc_type value
+ qci_type nvarchar(32) NOT NULL default '',
+
+ -- Timestamp of last update
+ qci_timestamp varchar(14) NOT NULL default ''
);
+CREATE UNIQUE INDEX /*i*/qci_type ON /*_*/querycache_info (qci_type);
+
+
-- For each redirect, this table contains exactly one row defining its target
-CREATE TABLE /*$wgDBprefix*/redirect (
- rd_from INT NOT NULL DEFAULT 0 REFERENCES /*$wgDBprefix*/[page](page_id) ON DELETE CASCADE,
- rd_namespace SMALLINT NOT NULL DEFAULT '0',
- rd_title NVARCHAR(255) NOT NULL DEFAULT '',
- rd_interwiki NVARCHAR(32) DEFAULT NULL,
- rd_fragment NVARCHAR(255) DEFAULT NULL,
+CREATE TABLE /*_*/redirect (
+ -- Key to the page_id of the redirect page
+ rd_from int NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+
+ -- Key to page_namespace/page_title of the target page.
+ -- The target page may or may not exist, and due to renames
+ -- and deletions may refer to different page records as time
+ -- goes by.
+ rd_namespace int NOT NULL default 0,
+ rd_title nvarchar(255) NOT NULL default '',
+ rd_interwiki nvarchar(32) default NULL,
+ rd_fragment nvarchar(255) default NULL
);
-CREATE UNIQUE INDEX /*$wgDBprefix*/rd_ns_title ON /*$wgDBprefix*/redirect(rd_namespace,rd_title,rd_from);
+
+CREATE INDEX /*i*/rd_ns_title ON /*_*/redirect (rd_namespace,rd_title,rd_from);
+
-- Used for caching expensive grouped queries that need two links (for example double-redirects)
-CREATE TABLE /*$wgDBprefix*/querycachetwo (
- qcc_type NCHAR(32) NOT NULL,
- qcc_value INT NOT NULL DEFAULT 0,
- qcc_namespace INT NOT NULL DEFAULT 0,
- qcc_title NCHAR(255) NOT NULL DEFAULT '',
- qcc_namespacetwo INT NOT NULL DEFAULT 0,
- qcc_titletwo NCHAR(255) NOT NULL DEFAULT '',
- CONSTRAINT /*$wgDBprefix*/qcc_type PRIMARY KEY(qcc_type,qcc_value),
-);
-CREATE UNIQUE INDEX /*$wgDBprefix*/qcc_title ON /*$wgDBprefix*/querycachetwo(qcc_type,qcc_namespace,qcc_title);
-CREATE UNIQUE INDEX /*$wgDBprefix*/qcc_titletwo ON /*$wgDBprefix*/querycachetwo(qcc_type,qcc_namespacetwo,qcc_titletwo);
-
-
---- Used for storing page restrictions (i.e. protection levels)
-CREATE TABLE /*$wgDBprefix*/page_restrictions (
- pr_page INT NOT NULL REFERENCES /*$wgDBprefix*/page(page_id) ON DELETE CASCADE,
- pr_type NVARCHAR(200) NOT NULL,
- pr_level NVARCHAR(200) NOT NULL,
- pr_cascade SMALLINT NOT NULL,
- pr_user INT NULL,
- pr_expiry DATETIME NULL,
- pr_id INT UNIQUE IDENTITY,
- CONSTRAINT /*$wgDBprefix*/pr_pagetype PRIMARY KEY(pr_page,pr_type),
-);
-CREATE INDEX /*$wgDBprefix*/pr_page ON /*$wgDBprefix*/page_restrictions(pr_page);
-CREATE INDEX /*$wgDBprefix*/pr_typelevel ON /*$wgDBprefix*/page_restrictions(pr_type,pr_level);
-CREATE INDEX /*$wgDBprefix*/pr_pagelevel ON /*$wgDBprefix*/page_restrictions(pr_level);
-CREATE INDEX /*$wgDBprefix*/pr_cascade ON /*$wgDBprefix*/page_restrictions(pr_cascade);
-;
+CREATE TABLE /*_*/querycachetwo (
+ -- A key name, generally the base name of of the special page.
+ qcc_type nvarchar(32) NOT NULL,
+
+ -- Some sort of stored value. Sizes, counts...
+ qcc_value int NOT NULL default 0,
+
+ -- Target namespace+title
+ qcc_namespace int NOT NULL default 0,
+ qcc_title nvarchar(255) NOT NULL default '',
+
+ -- Target namespace+title2
+ qcc_namespacetwo int NOT NULL default 0,
+ qcc_titletwo nvarchar(255) NOT NULL default ''
+);
+
+CREATE INDEX /*i*/qcc_type ON /*_*/querycachetwo (qcc_type,qcc_value);
+CREATE INDEX /*i*/qcc_title ON /*_*/querycachetwo (qcc_type,qcc_namespace,qcc_title);
+CREATE INDEX /*i*/qcc_titletwo ON /*_*/querycachetwo (qcc_type,qcc_namespacetwo,qcc_titletwo);
+
+
+-- Used for storing page restrictions (i.e. protection levels)
+CREATE TABLE /*_*/page_restrictions (
+ -- Field for an ID for this restrictions row (sort-key for Special:ProtectedPages)
+ pr_id int NOT NULL PRIMARY KEY IDENTITY,
+ -- Page to apply restrictions to (Foreign Key to page).
+ pr_page int NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+ -- The protection type (edit, move, etc)
+ pr_type nvarchar(60) NOT NULL,
+ -- The protection level (Sysop, autoconfirmed, etc)
+ pr_level nvarchar(60) NOT NULL,
+ -- Whether or not to cascade the protection down to pages transcluded.
+ pr_cascade bit NOT NULL,
+ -- Field for future support of per-user restriction.
+ pr_user int NULL,
+ -- Field for time-limited protection.
+ pr_expiry varchar(14) NULL
+);
+
+CREATE UNIQUE INDEX /*i*/pr_pagetype ON /*_*/page_restrictions (pr_page,pr_type);
+CREATE INDEX /*i*/pr_typelevel ON /*_*/page_restrictions (pr_type,pr_level);
+CREATE INDEX /*i*/pr_level ON /*_*/page_restrictions (pr_level);
+CREATE INDEX /*i*/pr_cascade ON /*_*/page_restrictions (pr_cascade);
+
-- Protected titles - nonexistent pages that have been protected
-CREATE TABLE /*$wgDBprefix*/protected_titles (
+CREATE TABLE /*_*/protected_titles (
pt_namespace int NOT NULL,
- pt_title NVARCHAR(255) NOT NULL,
- pt_user int NOT NULL,
- pt_reason NVARCHAR(3555),
- pt_timestamp DATETIME NOT NULL,
- pt_expiry DATETIME NOT NULL default '',
- pt_create_perm NVARCHAR(60) NOT NULL,
- PRIMARY KEY (pt_namespace,pt_title),
+ pt_title nvarchar(255) NOT NULL,
+ pt_user int REFERENCES /*_*/mwuser(user_id) ON DELETE SET NULL,
+ pt_reason nvarchar(255),
+ pt_timestamp varchar(14) NOT NULL,
+ pt_expiry varchar(14) NOT NULL,
+ pt_create_perm nvarchar(60) NOT NULL
);
-CREATE INDEX /*$wgDBprefix*/pt_timestamp ON /*$wgDBprefix*/protected_titles(pt_timestamp);
-;
+
+CREATE UNIQUE INDEX /*i*/pt_namespace_title ON /*_*/protected_titles (pt_namespace,pt_title);
+CREATE INDEX /*i*/pt_timestamp ON /*_*/protected_titles (pt_timestamp);
+
-- Name/value pairs indexed by page_id
-CREATE TABLE /*$wgDBprefix*/page_props (
- pp_page int NOT NULL,
- pp_propname NVARCHAR(60) NOT NULL,
- pp_value NVARCHAR(MAX) NOT NULL,
- PRIMARY KEY (pp_page,pp_propname)
+CREATE TABLE /*_*/page_props (
+ pp_page int NOT NULL REFERENCES /*_*/page(page_id) ON DELETE CASCADE,
+ pp_propname nvarchar(60) NOT NULL,
+ pp_value nvarchar(max) NOT NULL
);
+CREATE UNIQUE INDEX /*i*/pp_page_propname ON /*_*/page_props (pp_page,pp_propname);
+CREATE UNIQUE INDEX /*i*/pp_propname_page ON /*_*/page_props (pp_propname,pp_page);
+
+
-- A table to log updates, one text key row per update.
-CREATE TABLE /*$wgDBprefix*/updatelog (
- ul_key NVARCHAR(255) NOT NULL,
- PRIMARY KEY (ul_key)
+CREATE TABLE /*_*/updatelog (
+ ul_key nvarchar(255) NOT NULL PRIMARY KEY,
+ ul_value nvarchar(max)
);
--- NOTE To enable full text indexing on SQL 2008 you need to create an account FDH$MSSQLSERVER
--- AND assign a password for the FDHOST process to run under
--- Once you have assigned a password to that account, you need to run the following stored procedure
--- replacing XXXXX with the password you used.
--- EXEC sp_fulltext_resetfdhostaccount @username = 'FDH$MSSQLSERVER', @password = 'XXXXXX' ;
+-- A table to track tags for revisions, logs and recent changes.
+CREATE TABLE /*_*/change_tag (
+ -- RCID for the change
+ ct_rc_id int NULL REFERENCES /*_*/recentchanges(rc_id),
+ -- LOGID for the change
+ ct_log_id int NULL REFERENCES /*_*/logging(log_id),
+ -- REVID for the change
+ ct_rev_id int NULL REFERENCES /*_*/revision(rev_id),
+ -- Tag applied
+ ct_tag nvarchar(255) NOT NULL,
+ -- Parameters for the tag, presently unused
+ ct_params nvarchar(max) NULL
+);
+
+CREATE UNIQUE INDEX /*i*/change_tag_rc_tag ON /*_*/change_tag (ct_rc_id,ct_tag);
+CREATE UNIQUE INDEX /*i*/change_tag_log_tag ON /*_*/change_tag (ct_log_id,ct_tag);
+CREATE UNIQUE INDEX /*i*/change_tag_rev_tag ON /*_*/change_tag (ct_rev_id,ct_tag);
+-- Covering index, so we can pull all the info only out of the index.
+CREATE INDEX /*i*/change_tag_tag_id ON /*_*/change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id);
+
+
+-- Rollup table to pull a LIST of tags simply without ugly GROUP_CONCAT
+-- that only works on MySQL 4.1+
+CREATE TABLE /*_*/tag_summary (
+ -- RCID for the change
+ ts_rc_id int NULL REFERENCES /*_*/recentchanges(rc_id),
+ -- LOGID for the change
+ ts_log_id int NULL REFERENCES /*_*/logging(log_id),
+ -- REVID for the change
+ ts_rev_id int NULL REFERENCES /*_*/revision(rev_id),
+ -- Comma-separated list of tags
+ ts_tags nvarchar(max) NOT NULL
+);
+
+CREATE UNIQUE INDEX /*i*/tag_summary_rc_id ON /*_*/tag_summary (ts_rc_id);
+CREATE UNIQUE INDEX /*i*/tag_summary_log_id ON /*_*/tag_summary (ts_log_id);
+CREATE UNIQUE INDEX /*i*/tag_summary_rev_id ON /*_*/tag_summary (ts_rev_id);
+
+
+CREATE TABLE /*_*/valid_tag (
+ vt_tag nvarchar(255) NOT NULL PRIMARY KEY
+);
+
+-- Table for storing localisation data
+CREATE TABLE /*_*/l10n_cache (
+ -- Language code
+ lc_lang nvarchar(32) NOT NULL,
+ -- Cache key
+ lc_key nvarchar(255) NOT NULL,
+ -- Value
+ lc_value varbinary(max) NOT NULL
+);
+CREATE INDEX /*i*/lc_lang_key ON /*_*/l10n_cache (lc_lang, lc_key);
+
+-- Table for caching JSON message texts for the resource loader
+CREATE TABLE /*_*/msg_resource (
+ -- Resource name
+ mr_resource nvarchar(255) NOT NULL,
+ -- Language code
+ mr_lang nvarchar(32) NOT NULL,
+ -- JSON blob
+ mr_blob varbinary(max) NOT NULL,
+ -- Timestamp of last update
+ mr_timestamp varchar(14) NOT NULL
+);
+CREATE UNIQUE INDEX /*i*/mr_resource_lang ON /*_*/msg_resource (mr_resource, mr_lang);
+
+-- Table for administering which message is contained in which resource
+CREATE TABLE /*_*/msg_resource_links (
+ mrl_resource varbinary(255) NOT NULL,
+ -- Message key
+ mrl_message varbinary(255) NOT NULL
+);
+CREATE UNIQUE INDEX /*i*/mrl_message_resource ON /*_*/msg_resource_links (mrl_message, mrl_resource);
+
+-- Table caching which local files a module depends on that aren't
+-- registered directly, used for fast retrieval of file dependency.
+-- Currently only used for tracking images that CSS depends on
+CREATE TABLE /*_*/module_deps (
+ -- Module name
+ md_module nvarchar(255) NOT NULL,
+ -- Skin name
+ md_skin nvarchar(32) NOT NULL,
+ -- JSON nvarchar(max) with file dependencies
+ md_deps nvarchar(max) NOT NULL
+);
+CREATE UNIQUE INDEX /*i*/md_module_skin ON /*_*/module_deps (md_module, md_skin);
+
+-- Holds all the sites known to the wiki.
+CREATE TABLE /*_*/sites (
+ -- Numeric id of the site
+ site_id int NOT NULL PRIMARY KEY IDENTITY,
+
+ -- Global identifier for the site, ie 'enwiktionary'
+ site_global_key nvarchar(32) NOT NULL,
+
+ -- Type of the site, ie 'mediawiki'
+ site_type nvarchar(32) NOT NULL,
+
+ -- Group of the site, ie 'wikipedia'
+ site_group nvarchar(32) NOT NULL,
+
+ -- Source of the site data, ie 'local', 'wikidata', 'my-magical-repo'
+ site_source nvarchar(32) NOT NULL,
+
+ -- Language code of the sites primary language.
+ site_language nvarchar(32) NOT NULL,
+
+ -- Protocol of the site, ie 'http://', 'irc://', '//'
+ -- This field is an index for lookups and is build from type specific data in site_data.
+ site_protocol nvarchar(32) NOT NULL,
+
+ -- Domain of the site in reverse order, ie 'org.mediawiki.www.'
+ -- This field is an index for lookups and is build from type specific data in site_data.
+ site_domain NVARCHAR(255) NOT NULL,
+
+ -- Type dependent site data.
+ site_data nvarchar(max) NOT NULL,
+
+ -- If site.tld/path/key:pageTitle should forward users to the page on
+ -- the actual site, where "key" is the local identifier.
+ site_forward bit NOT NULL,
+
+ -- Type dependent site config.
+ -- For instance if template transclusion should be allowed if it's a MediaWiki.
+ site_config nvarchar(max) NOT NULL
+);
+
+CREATE UNIQUE INDEX /*i*/sites_global_key ON /*_*/sites (site_global_key);
+CREATE INDEX /*i*/sites_type ON /*_*/sites (site_type);
+CREATE INDEX /*i*/sites_group ON /*_*/sites (site_group);
+CREATE INDEX /*i*/sites_source ON /*_*/sites (site_source);
+CREATE INDEX /*i*/sites_language ON /*_*/sites (site_language);
+CREATE INDEX /*i*/sites_protocol ON /*_*/sites (site_protocol);
+CREATE INDEX /*i*/sites_domain ON /*_*/sites (site_domain);
+CREATE INDEX /*i*/sites_forward ON /*_*/sites (site_forward);
+
+-- Links local site identifiers to their corresponding site.
+CREATE TABLE /*_*/site_identifiers (
+ -- Key on site.site_id
+ si_site int NOT NULL REFERENCES /*_*/sites(site_id) ON DELETE CASCADE,
+
+ -- local key type, ie 'interwiki' or 'langlink'
+ si_type nvarchar(32) NOT NULL,
+
+ -- local key value, ie 'en' or 'wiktionary'
+ si_key nvarchar(32) NOT NULL
+);
---- Add the full-text capabilities, depricated in SQL Server 2005, FTS is enabled on all user created tables by default unless you are using SQL Server 2005 Express
---sp_fulltext_database 'enable';
---sp_fulltext_catalog 'WikiCatalog', 'create'
---sp_fulltext_table
---sp_fulltext_column
---sp_fulltext_table 'Articles', 'activate'
+CREATE UNIQUE INDEX /*i*/site_ids_type ON /*_*/site_identifiers (si_type, si_key);
+CREATE INDEX /*i*/site_ids_site ON /*_*/site_identifiers (si_site);
+CREATE INDEX /*i*/site_ids_key ON /*_*/site_identifiers (si_key);
diff --git a/maintenance/mssql/update-keys.sql b/maintenance/mssql/update-keys.sql
new file mode 100644
index 00000000..4d2c1c12
--- /dev/null
+++ b/maintenance/mssql/update-keys.sql
@@ -0,0 +1,31 @@
+-- Update keys for Microsoft SQL Server
+-- SQL to insert update keys into the initial tables after a
+-- fresh installation of MediaWiki's database.
+-- This is read and executed by the install script; you should
+-- not have to run it by itself unless doing a manual install.
+-- Insert keys here if either the unnecessary would cause heavy
+-- processing or could potentially cause trouble by lowering field
+-- sizes, adding constraints, etc.
+-- When adjusting field sizes, it is recommended removing old
+-- patches but to play safe, update keys should also inserted here.
+
+--
+-- The /*_*/ comments in this and other files are
+-- replaced with the defined table prefix by the installer
+-- and updater scripts. If you are installing or running
+-- updates manually, you will need to manually insert the
+-- table prefix if any when running these scripts.
+--
+
+INSERT INTO /*_*/updatelog
+ SELECT 'filearchive-fa_major_mime-patch-fa_major_mime-chemical.sql' AS ul_key, null as ul_value
+ UNION SELECT 'image-img_major_mime-patch-img_major_mime-chemical.sql', null
+ UNION SELECT 'oldimage-oi_major_mime-patch-oi_major_mime-chemical.sql', null
+ UNION SELECT 'cl_type-category_types-ck', null
+ UNION SELECT 'fa_major_mime-major_mime-ck', null
+ UNION SELECT 'fa_media_type-media_type-ck', null
+ UNION SELECT 'img_major_mime-major_mime-ck', null
+ UNION SELECT 'img_media_type-media_type-ck', null
+ UNION SELECT 'oi_major_mime-major_mime-ck', null
+ UNION SELECT 'oi_media_type-media_type-ck', null
+ UNION SELECT 'us_media_type-media_type-ck', null; \ No newline at end of file
diff --git a/maintenance/mwdocgen.php b/maintenance/mwdocgen.php
index b22dd885..ee0ff017 100644
--- a/maintenance/mwdocgen.php
+++ b/maintenance/mwdocgen.php
@@ -152,15 +152,13 @@ You might want to delete the temporary file:
---------------------------------------------------
TEXT
- );
+ );
if ( $exitcode !== 0 ) {
$this->error( "Something went wrong (exit: $exitcode)\n",
$exitcode );
}
-
}
-
}
$maintClass = 'MWDocGen';
diff --git a/maintenance/mwjsduck-gen b/maintenance/mwjsduck-gen
index bc10bc2c..5247637b 100644
--- a/maintenance/mwjsduck-gen
+++ b/maintenance/mwjsduck-gen
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
+set -e
JSDUCK_MWVERSION=master
if [[ "$1" == "--version" && "$2" != "" ]]
@@ -6,7 +7,8 @@ then
JSDUCK_MWVERSION="$2"
elif [[ "$*" != "" ]]
then
- echo "Usage $0: [--version <mediawiki version>]"
+ FILENAME=$(basename $0)
+ echo "Usage: $FILENAME [--version <mediawiki version>]"
echo
exit 1
fi
@@ -15,7 +17,9 @@ MWCORE_DIR=$(cd $(dirname $0)/..; pwd)
jsduck \
--config=$MWCORE_DIR/maintenance/jsduck/config.json \
---footer="Documentation for MediaWiki core ($JSDUCK_MWVERSION). Generated on {DATE} by {JSDUCK} {VERSION}." \
-&& echo 'JSDuck execution finished.'
+--footer="Documentation for branch ($JSDUCK_MWVERSION) on {DATE} by {JSDUCK} {VERSION}." \
+--processes 0
+
+echo 'JSDuck execution finished.'
ln -s ../../resources $MWCORE_DIR/docs/js/modules
diff --git a/maintenance/namespaceDupes.php b/maintenance/namespaceDupes.php
index ff024682..cbc389be 100644
--- a/maintenance/namespaceDupes.php
+++ b/maintenance/namespaceDupes.php
@@ -3,7 +3,7 @@
* Check for articles to fix after adding/deleting namespaces
*
* Copyright © 2005-2007 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -44,16 +44,13 @@ class NamespaceConflictChecker extends Maintenance {
$this->mDescription = "";
$this->addOption( 'fix', 'Attempt to automatically fix errors' );
$this->addOption( 'suffix', "Dupes will be renamed with correct namespace with " .
- "<text> appended after the article name", false, true );
+ "<text> appended after the article name", false, true );
$this->addOption( 'prefix', "Do an explicit check for the given title prefix " .
- "appended after the article name", false, true );
+ "appended after the article name", false, true );
}
public function execute() {
- global $wgTitle;
-
$this->db = wfGetDB( DB_MASTER );
- $wgTitle = Title::newFromText( 'Namespace title conflict cleanup script' );
$fix = $this->hasOption( 'fix' );
$suffix = $this->getOption( 'suffix', '' );
@@ -75,8 +72,8 @@ class NamespaceConflictChecker extends Maintenance {
/**
* @todo Document
- * @param $fix Boolean: whether or not to fix broken entries
- * @param $suffix String: suffix to append to renamed articles
+ * @param bool $fix Whether or not to fix broken entries
+ * @param string $suffix Suffix to append to renamed articles
*
* @return bool
*/
@@ -141,13 +138,14 @@ class NamespaceConflictChecker extends Maintenance {
foreach ( $spaces as $name => $ns ) {
$ok = $this->checkNamespace( $ns, $name, $fix, $suffix ) && $ok;
}
+
return $ok;
}
/**
* Get the interwiki list
*
- * @return Array
+ * @return array
*/
private function getInterwikiList() {
$result = Interwiki::getAllPrefixes();
@@ -155,15 +153,16 @@ class NamespaceConflictChecker extends Maintenance {
foreach ( $result as $row ) {
$prefixes[] = $row['iw_prefix'];
}
+
return $prefixes;
}
/**
* @todo Document
- * @param $ns Integer: a namespace id
- * @param $name String
- * @param $fix Boolean: whether to fix broken entries
- * @param $suffix String: suffix to append to renamed articles
+ * @param int $ns A namespace id
+ * @param string $name
+ * @param bool $fix Whether to fix broken entries
+ * @param string $suffix Suffix to append to renamed articles
* @return bool
*/
private function checkNamespace( $ns, $name, $fix, $suffix = '' ) {
@@ -181,19 +180,21 @@ class NamespaceConflictChecker extends Maintenance {
$ok = $this->resolveConflict( $row, $resolvable, $suffix ) && $ok;
}
}
+
return $ok;
}
/**
* @todo Do this for real
- * @param $key
- * @param $prefix
- * @param $fix
- * @param $suffix string
+ * @param int $key
+ * @param string $prefix
+ * @param bool $fix
+ * @param string $suffix
* @return bool
*/
private function checkPrefix( $key, $prefix, $fix, $suffix = '' ) {
$this->output( "Checking prefix \"$prefix\" vs namespace $key\n" );
+
return $this->checkNamespace( $key, $prefix, $fix, $suffix );
}
@@ -201,45 +202,42 @@ class NamespaceConflictChecker extends Maintenance {
* Find pages in mainspace that have a prefix of the new namespace
* so we know titles that will need migrating
*
- * @param $ns Integer: namespace id (id for new namespace?)
- * @param $name String: prefix that is being made a namespace
+ * @param int $ns Namespace id (id for new namespace?)
+ * @param string $name Prefix that is being made a namespace
*
* @return array
*/
private function getConflicts( $ns, $name ) {
- $page = 'page';
- $table = $this->db->tableName( $page );
-
- $prefix = $this->db->strencode( $name );
- $encNamespace = $this->db->addQuotes( $ns );
-
- $titleSql = "TRIM(LEADING '$prefix:' FROM {$page}_title)";
+ $titleSql = "TRIM(LEADING {$this->db->addQuotes( "$name:" )} FROM page_title)";
if ( $ns == 0 ) {
// An interwiki; try an alternate encoding with '-' for ':'
- $titleSql = $this->db->buildConcat( array( "'$prefix-'", $titleSql ) );
+ $titleSql = $this->db->buildConcat( array(
+ $this->db->addQuotes( "$name-" ),
+ $titleSql,
+ ) );
}
- $sql = "SELECT {$page}_id AS id,
- {$page}_title AS oldtitle,
- $encNamespace + {$page}_namespace AS namespace,
- $titleSql AS title,
- {$page}_namespace AS oldnamespace
- FROM {$table}
- WHERE ( {$page}_namespace=0 OR {$page}_namespace=1 )
- AND {$page}_title " . $this->db->buildLike( $name . ':', $this->db->anyString() );
-
- $result = $this->db->query( $sql, __METHOD__ );
-
- $set = array();
- foreach ( $result as $row ) {
- $set[] = $row;
- }
- return $set;
+ return iterator_to_array( $this->db->select( 'page',
+ array(
+ 'id' => 'page_id',
+ 'oldtitle' => 'page_title',
+ 'namespace' => $this->db->addQuotes( $ns ) . ' + page_namespace',
+ 'title' => $titleSql,
+ 'oldnamespace' => 'page_namespace',
+ ),
+ array(
+ 'page_namespace' => array( 0, 1 ),
+ 'page_title' . $this->db->buildLike( "$name:", $this->db->anyString() ),
+ ),
+ __METHOD__
+ ) );
}
/**
* Report any conflicts we find
*
+ * @param stdClass $row
+ * @param string $suffix
* @return bool
*/
private function reportConflict( $row, $suffix ) {
@@ -252,6 +250,7 @@ class NamespaceConflictChecker extends Maintenance {
$row->oldnamespace,
$row->oldtitle ) );
$this->output( "... *** cannot resolve automatically; illegal title ***\n" );
+
return false;
}
@@ -266,6 +265,7 @@ class NamespaceConflictChecker extends Maintenance {
$id = $newTitle->getArticleID();
if ( $id ) {
$this->output( "... *** cannot resolve automatically; page exists with ID $id ***\n" );
+
return false;
} else {
return true;
@@ -275,9 +275,9 @@ class NamespaceConflictChecker extends Maintenance {
/**
* Resolve any conflicts
*
- * @param $row Object: row from the page table to fix
- * @param $resolvable Boolean
- * @param $suffix String: suffix to append to the fixed page
+ * @param stClass $row Row from the page table to fix
+ * @param bool $resolvable
+ * @param string $suffix Suffix to append to the fixed page
* @return bool
*/
private function resolveConflict( $row, $resolvable, $suffix ) {
@@ -289,6 +289,7 @@ class NamespaceConflictChecker extends Maintenance {
$title = Title::makeTitleSafe( $row->namespace, $row->title );
if ( !$title ) {
$this->output( "... !!! invalid title\n" );
+
return false;
}
$id = $title->getArticleID();
@@ -301,15 +302,16 @@ class NamespaceConflictChecker extends Maintenance {
$this->output( "... *** using suffixed form [[" . $title->getPrefixedText() . "]] ***\n" );
}
$this->resolveConflictOn( $row, 'page', 'page' );
+
return true;
}
/**
* Resolve a given conflict
*
- * @param $row Object: row from the old broken entry
- * @param $table String: table to update
- * @param $prefix String: prefix for column name, like page or ar
+ * @param stdClass $row Row from the old broken entry
+ * @param string $table Table to update
+ * @param string $prefix Prefix for column name, like page or ar
* @return bool
*/
private function resolveConflictOn( $row, $table, $prefix ) {
@@ -327,6 +329,7 @@ class NamespaceConflictChecker extends Maintenance {
),
__METHOD__ );
$this->output( "ok.\n" );
+
return true;
}
}
diff --git a/maintenance/nextJobDB.php b/maintenance/nextJobDB.php
deleted file mode 100644
index 219b5d8e..00000000
--- a/maintenance/nextJobDB.php
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-/**
- * Pick a database that has pending jobs
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-
-require_once __DIR__ . '/Maintenance.php';
-
-/**
- * Maintenance script that picks a database that has pending jobs.
- *
- * @ingroup Maintenance
- */
-class nextJobDB extends Maintenance {
- public function __construct() {
- parent::__construct();
- $this->mDescription = "Pick a database that has pending jobs";
- $this->addOption( 'type', "Search by job type", false, true );
- $this->addOption( 'types', "Space separated list of job types to search for", false, true );
- }
-
- public function execute() {
- global $wgJobTypesExcludedFromDefaultQueue;
-
- // job type required/picked
- if ( $this->hasOption( 'types' ) ) {
- $types = explode( ' ', $this->getOption( 'types' ) );
- } elseif ( $this->hasOption( 'type' ) ) {
- $types = array( $this->getOption( 'type' ) );
- } else {
- $types = false;
- }
-
- // Handle any required periodic queue maintenance
- $this->executeReadyPeriodicTasks();
-
- // Get all the queues with jobs in them
- $pendingDBs = JobQueueAggregator::singleton()->getAllReadyWikiQueues();
- if ( !count( $pendingDBs ) ) {
- return; // no DBs with jobs or cache is both empty and locked
- }
-
- do {
- $again = false;
-
- $candidates = array(); // list of (type, db)
- // Flatten the tree of candidates into a flat list so that a random
- // item can be selected, weighing each queue (type/db tuple) equally.
- foreach ( $pendingDBs as $type => $dbs ) {
- if (
- ( is_array( $types ) && in_array( $type, $types ) ) ||
- ( $types === false && !in_array( $type, $wgJobTypesExcludedFromDefaultQueue ) )
- ) {
- foreach ( $dbs as $db ) {
- $candidates[] = array( $type, $db );
- }
- }
- }
- if ( !count( $candidates ) ) {
- return; // no jobs for this type
- }
-
- list( $type, $db ) = $candidates[mt_rand( 0, count( $candidates ) - 1 )];
- if ( JobQueueGroup::singleton( $db )->isQueueDeprioritized( $type ) ) {
- $pendingDBs[$type] = array_diff( $pendingDBs[$type], array( $db ) );
- $again = true;
- }
- } while ( $again );
-
- if ( $this->hasOption( 'types' ) ) {
- $this->output( $db . " " . $type . "\n" );
- } else {
- $this->output( $db . "\n" );
- }
- }
-
- /**
- * Do all ready periodic jobs for all databases every 5 minutes (and .1% of the time)
- * @return integer
- */
- private function executeReadyPeriodicTasks() {
- global $wgLocalDatabases, $wgMemc;
-
- $count = 0;
- $memcKey = 'jobqueue:periodic:lasttime';
- $timestamp = (int)$wgMemc->get( $memcKey ); // UNIX timestamp or 0
- if ( ( time() - $timestamp ) > 300 || mt_rand( 0, 999 ) == 0 ) { // 5 minutes
- if ( $wgMemc->add( "$memcKey:rebuild", 1, 1800 ) ) { // lock
- foreach ( $wgLocalDatabases as $db ) {
- $count += JobQueueGroup::singleton( $db )->executeReadyPeriodicTasks();
- }
- $wgMemc->set( $memcKey, time() );
- $wgMemc->delete( "$memcKey:rebuild" ); // unlock
- }
- }
-
- return $count;
- }
-}
-
-$maintClass = "nextJobDb";
-require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/nukeNS.php b/maintenance/nukeNS.php
index 479dcf76..64bf1b6f 100644
--- a/maintenance/nukeNS.php
+++ b/maintenance/nukeNS.php
@@ -91,7 +91,7 @@ class NukeNS extends Maintenance {
$child = $this->runChild( 'NukePage', 'nukePage.php' );
$child->deleteRevisions( $revs );
$this->purgeRedundantText( true );
- $n_deleted ++;
+ $n_deleted++;
}
} else {
$this->output( "skip: " . $title->getPrefixedText() . "\n" );
diff --git a/maintenance/oracle/alterSharedConstraints.php b/maintenance/oracle/alterSharedConstraints.php
index 435625d5..eea6f7b1 100644
--- a/maintenance/oracle/alterSharedConstraints.php
+++ b/maintenance/oracle/alterSharedConstraints.php
@@ -44,6 +44,7 @@ class AlterSharedConstraints extends Maintenance {
if ( $wgSharedDB == null ) {
$this->output( "Database sharing is not enabled\n" );
+
return;
}
@@ -56,35 +57,38 @@ class AlterSharedConstraints extends Maintenance {
$ltable = "{$wgDBprefix}{$stable}";
}
- $result = $dbw->query( "SELECT uc.constraint_name, uc.table_name, ucc.column_name, uccpk.table_name pk_table_name, uccpk.column_name pk_column_name, uc.delete_rule, uc.deferrable, uc.deferred
- FROM user_constraints uc, user_cons_columns ucc, user_cons_columns uccpk
- WHERE uc.constraint_type = 'R'
- AND ucc.constraint_name = uc.constraint_name
- AND uccpk.constraint_name = uc.r_constraint_name
- AND uccpk.table_name = '$ltable'" );
+ $result = $dbw->query( "SELECT uc.constraint_name, uc.table_name, ucc.column_name,
+ uccpk.table_name pk_table_name, uccpk.column_name pk_column_name,
+ uc.delete_rule, uc.deferrable, uc.deferred
+ FROM user_constraints uc, user_cons_columns ucc, user_cons_columns uccpk
+ WHERE uc.constraint_type = 'R'
+ AND ucc.constraint_name = uc.constraint_name
+ AND uccpk.constraint_name = uc.r_constraint_name
+ AND uccpk.table_name = '$ltable'" );
while ( ( $row = $result->fetchRow() ) !== false ) {
- $this->output( "Altering {$row['constraint_name']} ..." );
+ $this->output( "Altering {$row['constraint_name']} ..." );
- try {
- $dbw->query( "ALTER TABLE {$row['table_name']} DROP CONSTRAINT {$wgDBprefix}{$row['constraint_name']}" );
- } catch ( DBQueryError $exdb ) {
- if ( $exdb->errno != 2443 ) {
- throw $exdb;
- }
+ try {
+ $dbw->query( "ALTER TABLE {$row['table_name']}
+ DROP CONSTRAINT {$wgDBprefix}{$row['constraint_name']}" );
+ } catch ( DBQueryError $exdb ) {
+ if ( $exdb->errno != 2443 ) {
+ throw $exdb;
}
+ }
- $deleteRule = $row['delete_rule'] == 'NO ACTION' ? '' : "ON DELETE {$row['delete_rule']}";
- $dbw->query( "ALTER TABLE {$row['table_name']} ADD CONSTRAINT {$wgDBprefix}{$row['constraint_name']}
+ $deleteRule = $row['delete_rule'] == 'NO ACTION' ? '' : "ON DELETE {$row['delete_rule']}";
+ $dbw->query( "ALTER TABLE {$row['table_name']}
+ ADD CONSTRAINT {$wgDBprefix}{$row['constraint_name']}
FOREIGN KEY ({$row['column_name']})
REFERENCES {$wgSharedDB}.$stable({$row['pk_column_name']})
{$deleteRule} {$row['deferrable']} INITIALLY {$row['deferred']}" );
- $this->output( "DONE\n" );
+ $this->output( "DONE\n" );
}
}
}
-
}
$maintClass = "AlterSharedConstraints";
diff --git a/maintenance/oracle/archives/patch-logging_user_text_time_index.sql b/maintenance/oracle/archives/patch-logging_user_text_time_index.sql
new file mode 100644
index 00000000..e04abf5f
--- /dev/null
+++ b/maintenance/oracle/archives/patch-logging_user_text_time_index.sql
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+CREATE INDEX &mw_prefix.logging_i07 ON &mw_prefix.logging (log_user_text, log_timestamp);
+
diff --git a/maintenance/oracle/archives/patch-logging_user_text_type_time_index.sql b/maintenance/oracle/archives/patch-logging_user_text_type_time_index.sql
new file mode 100644
index 00000000..c1c0d4f2
--- /dev/null
+++ b/maintenance/oracle/archives/patch-logging_user_text_type_time_index.sql
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+CREATE INDEX &mw_prefix.logging_i06 ON &mw_prefix.logging (log_user_text, log_type, log_timestamp);
+
diff --git a/maintenance/oracle/archives/patch-page-page_lang.sql b/maintenance/oracle/archives/patch-page-page_lang.sql
new file mode 100644
index 00000000..cae7cf90
--- /dev/null
+++ b/maintenance/oracle/archives/patch-page-page_lang.sql
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.page ADD page_lang VARCHAR2(35);
diff --git a/maintenance/oracle/archives/patch-page_links_updated.sql b/maintenance/oracle/archives/patch-page_links_updated.sql
new file mode 100644
index 00000000..53603294
--- /dev/null
+++ b/maintenance/oracle/archives/patch-page_links_updated.sql
@@ -0,0 +1,4 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.page ADD page_links_updated TIMESTAMP(6) WITH TIME ZONE;
+
diff --git a/maintenance/oracle/archives/patch-rc_source.sql b/maintenance/oracle/archives/patch-rc_source.sql
new file mode 100644
index 00000000..0c80afab
--- /dev/null
+++ b/maintenance/oracle/archives/patch-rc_source.sql
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.recentchanges ADD rc_source VARCHAR2(16);
diff --git a/maintenance/oracle/archives/patch-user_password_expire.sql b/maintenance/oracle/archives/patch-user_password_expire.sql
new file mode 100644
index 00000000..824cc820
--- /dev/null
+++ b/maintenance/oracle/archives/patch-user_password_expire.sql
@@ -0,0 +1,3 @@
+define mw_prefix='{$wgDBprefix}';
+
+ALTER TABLE &mw_prefix.mwuser ADD user_password_expires TIMESTAMP(6) WITH TIME ZONE;
diff --git a/maintenance/oracle/archives/patch_16_17_schema_changes.sql b/maintenance/oracle/archives/patch_16_17_schema_changes.sql
index 64c28481..cd99f7cc 100644
--- a/maintenance/oracle/archives/patch_16_17_schema_changes.sql
+++ b/maintenance/oracle/archives/patch_16_17_schema_changes.sql
@@ -67,7 +67,7 @@ CREATE TABLE &mw_prefix.msg_resource (
mr_lang varchar2(32) NOT NULL,
mr_blob BLOB NOT NULL,
mr_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL
-) ;
+);
CREATE UNIQUE INDEX &mw_prefix.msg_resource_u01 ON &mw_prefix.msg_resource (mr_resource, mr_lang);
ALTER TABLE &mw_prefix.oldimage MODIFY oi_name DEFAULT 0;
diff --git a/maintenance/oracle/tables.sql b/maintenance/oracle/tables.sql
index acfabc33..36be16e4 100644
--- a/maintenance/oracle/tables.sql
+++ b/maintenance/oracle/tables.sql
@@ -2,7 +2,7 @@
define mw_prefix='{$wgDBprefix}';
-CREATE SEQUENCE user_user_id_seq MINVALUE 0 START WITH 0;
+CREATE SEQUENCE user_user_id_seq;
CREATE TABLE &mw_prefix.mwuser ( -- replace reserved word 'user'
user_id NUMBER NOT NULL,
user_name VARCHAR2(255) NOT NULL,
@@ -18,7 +18,8 @@ CREATE TABLE &mw_prefix.mwuser ( -- replace reserved word 'user'
user_options CLOB,
user_touched TIMESTAMP(6) WITH TIME ZONE,
user_registration TIMESTAMP(6) WITH TIME ZONE,
- user_editcount NUMBER
+ user_editcount NUMBER,
+ user_password_expires TIMESTAMP(6) WITH TIME ZONE
);
ALTER TABLE &mw_prefix.mwuser ADD CONSTRAINT &mw_prefix.mwuser_pk PRIMARY KEY (user_id);
CREATE UNIQUE INDEX &mw_prefix.mwuser_u01 ON &mw_prefix.mwuser (user_name);
@@ -27,7 +28,8 @@ CREATE INDEX &mw_prefix.mwuser_i02 ON &mw_prefix.mwuser (user_email, user_name);
-- Create a dummy user to satisfy fk contraints especially with revisions
INSERT INTO &mw_prefix.mwuser
- VALUES (user_user_id_seq.nextval,'Anonymous',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, '', current_timestamp, current_timestamp, 0);
+ (user_id, user_name, user_options, user_touched, user_registration, user_editcount)
+ VALUES (0,'Anonymous','', current_timestamp, current_timestamp,0);
CREATE TABLE &mw_prefix.user_groups (
ug_user NUMBER DEFAULT 0 NOT NULL,
@@ -72,9 +74,11 @@ CREATE TABLE &mw_prefix.page (
page_is_new CHAR(1) DEFAULT '0' NOT NULL,
page_random NUMBER(15,14) NOT NULL,
page_touched TIMESTAMP(6) WITH TIME ZONE,
+ page_links_updated TIMESTAMP(6) WITH TIME ZONE,
page_latest NUMBER DEFAULT 0 NOT NULL, -- FK?
page_len NUMBER DEFAULT 0 NOT NULL,
- page_content_model VARCHAR2(32)
+ page_content_model VARCHAR2(32),
+ page_lang VARCHAR2(35) DEFAULT NULL
);
ALTER TABLE &mw_prefix.page ADD CONSTRAINT &mw_prefix.page_pk PRIMARY KEY (page_id);
CREATE UNIQUE INDEX &mw_prefix.page_u01 ON &mw_prefix.page (page_namespace,page_title);
@@ -84,7 +88,7 @@ CREATE INDEX &mw_prefix.page_i03 ON &mw_prefix.page (page_is_redirect, page_name
-- Create a dummy page to satisfy fk contraints especially with revisions
INSERT INTO &mw_prefix.page
- VALUES (0, 0, ' ', NULL, 0, 0, 0, 0, current_timestamp, 0, 0, NULL);
+ VALUES (0, 0, ' ', NULL, 0, 0, 0, 0, current_timestamp, NULL, 0, 0, NULL, NULL);
/*$mw$*/
CREATE TRIGGER &mw_prefix.page_set_random BEFORE INSERT ON &mw_prefix.page
@@ -402,7 +406,7 @@ CREATE SEQUENCE recentchanges_rc_id_seq;
CREATE TABLE &mw_prefix.recentchanges (
rc_id NUMBER NOT NULL,
rc_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL,
- rc_cur_time TIMESTAMP(6) WITH TIME ZONE NOT NULL,
+ rc_cur_time TIMESTAMP(6) WITH TIME ZONE,
rc_user NUMBER DEFAULT 0 NOT NULL,
rc_user_text VARCHAR2(255) NOT NULL,
rc_namespace NUMBER DEFAULT 0 NOT NULL,
@@ -415,6 +419,7 @@ CREATE TABLE &mw_prefix.recentchanges (
rc_this_oldid NUMBER DEFAULT 0 NOT NULL,
rc_last_oldid NUMBER DEFAULT 0 NOT NULL,
rc_type CHAR(1) DEFAULT '0' NOT NULL,
+ rc_source VARCHAR2(16),
rc_patrolled CHAR(1) DEFAULT '0' NOT NULL,
rc_ip VARCHAR2(15),
rc_old_len NUMBER,
@@ -509,6 +514,8 @@ CREATE INDEX &mw_prefix.logging_i02 ON &mw_prefix.logging (log_user, log_timesta
CREATE INDEX &mw_prefix.logging_i03 ON &mw_prefix.logging (log_namespace, log_title, log_timestamp);
CREATE INDEX &mw_prefix.logging_i04 ON &mw_prefix.logging (log_timestamp);
CREATE INDEX &mw_prefix.logging_i05 ON &mw_prefix.logging (log_type, log_action, log_timestamp);
+CREATE INDEX &mw_prefix.logging_i06 ON &mw_prefix.logging (log_user_text, log_type, log_timestamp);
+CREATE INDEX &mw_prefix.logging_i07 ON &mw_prefix.logging (log_user_text, log_timestamp);
CREATE TABLE &mw_prefix.log_search (
ls_field VARCHAR2(32) NOT NULL,
@@ -663,7 +670,7 @@ CREATE TABLE &mw_prefix.msg_resource (
mr_lang varchar2(32) NOT NULL,
mr_blob BLOB NOT NULL,
mr_timestamp TIMESTAMP(6) WITH TIME ZONE NOT NULL
-) ;
+);
CREATE UNIQUE INDEX &mw_prefix.msg_resource_u01 ON &mw_prefix.msg_resource (mr_resource, mr_lang);
CREATE TABLE &mw_prefix.msg_resource_links (
diff --git a/maintenance/oracle/update-keys.sql b/maintenance/oracle/update-keys.sql
new file mode 100644
index 00000000..7761d0c5
--- /dev/null
+++ b/maintenance/oracle/update-keys.sql
@@ -0,0 +1,29 @@
+-- SQL to insert update keys into the initial tables after a
+-- fresh installation of MediaWiki's database.
+-- This is read and executed by the install script; you should
+-- not have to run it by itself unless doing a manual install.
+-- Insert keys here if either the unnecessary would cause heavy
+-- processing or could potentially cause trouble by lowering field
+-- sizes, adding constraints, etc.
+-- When adjusting field sizes, it is recommended removing old
+-- patches but to play safe, update keys should also inserted here.
+
+-- The /*_*/ comments in this and other files are
+-- replaced with the defined table prefix by the installer
+-- and updater scripts. If you are installing or running
+-- updates manually, you will need to manually insert the
+-- table prefix if any when running these scripts.
+--
+
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'filearchive-fa_major_mime-patch-fa_major_mime-chemical.sql', null );
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'image-img_major_mime-patch-img_major_mime-chemical.sql', null );
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'oldimage-oi_major_mime-patch-oi_major_mime-chemical.sql', null );
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'user_groups-ug_group-patch-ug_group-length-increase-255.sql', null );
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'user_former_groups-ufg_group-patch-ufg_group-length-increase-255.sql', null );
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'user_properties-up_property-patch-up_property.sql', null );
diff --git a/maintenance/orphans.php b/maintenance/orphans.php
index b4d255ab..7e27107a 100644
--- a/maintenance/orphans.php
+++ b/maintenance/orphans.php
@@ -6,7 +6,7 @@
* Man this is depressing.
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -40,15 +40,13 @@ class Orphans extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Look for 'orphan' revisions hooked to pages which don't exist\n" .
- "and 'childless' pages with no revisions\n" .
- "Then, kill the poor widows and orphans\n" .
- "Man this is depressing";
+ "and 'childless' pages with no revisions\n" .
+ "Then, kill the poor widows and orphans\n" .
+ "Man this is depressing";
$this->addOption( 'fix', 'Actually fix broken entries' );
}
public function execute() {
- global $wgTitle;
- $wgTitle = Title::newFromText( 'Orphan revision cleanup script' );
$this->checkOrphans( $this->hasOption( 'fix' ) );
$this->checkSeparation( $this->hasOption( 'fix' ) );
# Does not work yet, do not use
@@ -57,8 +55,8 @@ class Orphans extends Maintenance {
/**
* Lock the appropriate tables for the script
- * @param $db DatabaseBase object
- * @param $extraTable String The name of any extra tables to lock (eg: text)
+ * @param DatabaseBase $db
+ * @param string $extraTable The name of any extra tables to lock (eg: text)
*/
private function lockTables( $db, $extraTable = array() ) {
$tbls = array( 'page', 'revision', 'redirect' );
@@ -70,7 +68,7 @@ class Orphans extends Maintenance {
/**
* Check for orphan revisions
- * @param $fix bool Whether to fix broken revisions when found
+ * @param bool $fix Whether to fix broken revisions when found
*/
private function checkOrphans( $fix ) {
$dbw = wfGetDB( DB_MASTER );
@@ -81,7 +79,8 @@ class Orphans extends Maintenance {
$this->lockTables( $dbw );
}
- $this->output( "Checking for orphan revision table entries... (this may take a while on a large wiki)\n" );
+ $this->output( "Checking for orphan revision table entries... "
+ . "(this may take a while on a large wiki)\n" );
$result = $dbw->query( "
SELECT *
FROM $revision LEFT OUTER JOIN $page ON rev_page=page_id
@@ -90,8 +89,13 @@ class Orphans extends Maintenance {
$orphans = $result->numRows();
if ( $orphans > 0 ) {
global $wgContLang;
+
$this->output( "$orphans orphan revisions...\n" );
- $this->output( sprintf( "%10s %10s %14s %20s %s\n", 'rev_id', 'rev_page', 'rev_timestamp', 'rev_user_text', 'rev_comment' ) );
+ $this->output( sprintf(
+ "%10s %10s %14s %20s %s\n",
+ 'rev_id', 'rev_page', 'rev_timestamp', 'rev_user_text', 'rev_comment'
+ ) );
+
foreach ( $result as $row ) {
$comment = ( $row->rev_comment == '' )
? ''
@@ -119,7 +123,7 @@ class Orphans extends Maintenance {
}
/**
- * @param $fix bool
+ * @param bool $fix
* @todo DON'T USE THIS YET! It will remove entries which have children,
* but which aren't properly attached (eg if page_latest is bogus
* but valid revisions do exist)
@@ -133,7 +137,8 @@ class Orphans extends Maintenance {
$this->lockTables( $dbw );
}
- $this->output( "\nChecking for childless page table entries... (this may take a while on a large wiki)\n" );
+ $this->output( "\nChecking for childless page table entries... "
+ . "(this may take a while on a large wiki)\n" );
$result = $dbw->query( "
SELECT *
FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id
@@ -167,7 +172,7 @@ class Orphans extends Maintenance {
/**
* Check for pages where page_latest is wrong
- * @param $fix bool Whether to fix broken entries
+ * @param bool $fix Whether to fix broken entries
*/
private function checkSeparation( $fix ) {
$dbw = wfGetDB( DB_MASTER );
@@ -178,7 +183,8 @@ class Orphans extends Maintenance {
$this->lockTables( $dbw, array( 'user', 'text' ) );
}
- $this->output( "\nChecking for pages whose page_latest links are incorrect... (this may take a while on a large wiki)\n" );
+ $this->output( "\nChecking for pages whose page_latest links are incorrect... "
+ . "(this may take a while on a large wiki)\n" );
$result = $dbw->query( "
SELECT *
FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id
diff --git a/maintenance/pageExists.php b/maintenance/pageExists.php
new file mode 100644
index 00000000..3bde81ef
--- /dev/null
+++ b/maintenance/pageExists.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * @ingroup Maintenance
+ */
+class PageExists extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Report whether a specific page exists";
+ $this->addArg( 'title', 'Page title to check whether it exists' );
+ }
+
+ public function execute() {
+ $titleArg = $this->getArg();
+ $title = Title::newFromText( $titleArg );
+ $pageExists = $title && $title->exists();
+
+ $text = '';
+ $code = 0;
+ if ( $pageExists ) {
+ $text = "{$title} exists.";
+ } else {
+ $text = "{$titleArg} doesn't exist.";
+ $code = 1;
+ }
+ $this->output( $text );
+ $this->error( '', $code );
+ }
+}
+
+$maintClass = "PageExists";
+require_once RUN_MAINTENANCE_IF_MAIN;
+
diff --git a/maintenance/parse.php b/maintenance/parse.php
index 3ac7a281..638d7c5b 100644
--- a/maintenance/parse.php
+++ b/maintenance/parse.php
@@ -62,7 +62,12 @@ class CLIParser extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Parse a given wikitext";
- $this->addOption( 'title', 'Title name for the given wikitext (Default: \'CLIParser\')', false, true );
+ $this->addOption(
+ 'title',
+ 'Title name for the given wikitext (Default: \'CLIParser\')',
+ false,
+ true
+ );
$this->addArg( 'file', 'File containing wikitext (Default: stdin)', false );
}
@@ -90,7 +95,8 @@ class CLIParser extends Maintenance {
if ( $input_file === $php_stdin ) {
$ctrl = wfIsWindows() ? 'CTRL+Z' : 'CTRL+D';
- $this->error( basename( __FILE__ ) . ": warning: reading wikitext from STDIN. Press $ctrl to parse.\n" );
+ $this->error( basename( __FILE__ )
+ . ": warning: reading wikitext from STDIN. Press $ctrl to parse.\n" );
}
return file_get_contents( $input_file );
@@ -107,13 +113,13 @@ class CLIParser extends Maintenance {
* Default title is 'CLIParser', it can be overriden with the option
* --title <Your:Title>
*
- * @return Title object
+ * @return Title
*/
protected function getTitle() {
- $title =
- $this->getOption( 'title' )
+ $title = $this->getOption( 'title' )
? $this->getOption( 'title' )
: 'CLIParser';
+
return Title::newFromText( $title );
}
@@ -123,9 +129,9 @@ class CLIParser extends Maintenance {
*/
protected function parse( $wikitext ) {
return $this->parser->parse(
- $wikitext
- , $this->getTitle()
- , new ParserOptions()
+ $wikitext,
+ $this->getTitle(),
+ new ParserOptions()
);
}
}
diff --git a/maintenance/patchSql.php b/maintenance/patchSql.php
index 31ce1566..5d9fc1b4 100644
--- a/maintenance/patchSql.php
+++ b/maintenance/patchSql.php
@@ -33,7 +33,10 @@ class PatchSql extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Run an SQL file into the DB, replacing prefix and charset vars";
- $this->addArg( 'patch-name', 'Name of the patch file, either full path or in maintenance/archives' );
+ $this->addArg(
+ 'patch-name',
+ 'Name of the patch file, either full path or in maintenance/archives'
+ );
}
public function getDbType() {
diff --git a/maintenance/populateBacklinkNamespace.php b/maintenance/populateBacklinkNamespace.php
new file mode 100644
index 00000000..054f7921
--- /dev/null
+++ b/maintenance/populateBacklinkNamespace.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * Optional upgrade script to populate *_from_namespace fields
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script to populate *_from_namespace fields
+ *
+ * @ingroup Maintenance
+ */
+class PopulateBacklinkNamespace extends LoggedUpdateMaintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Populate the *_from_namespace fields";
+ $this->addOption( 'lastUpdatedId', "Highest page_id with updated links", false, true );
+ }
+
+ protected function getUpdateKey() {
+ return 'populate *_from_namespace';
+ }
+
+ protected function updateSkippedMessage() {
+ return '*_from_namespace column of backlink tables already populated.';
+ }
+
+ public function doDBUpdates() {
+ $force = $this->getOption( 'force' );
+
+ $db = $this->getDB( DB_MASTER );
+
+ $this->output( "Updating *_from_namespace fields in links tables.\n" );
+
+ $start = $this->getOption( 'lastUpdatedId' );
+ if ( !$start ) {
+ $start = $db->selectField( 'page', 'MIN(page_id)', false, __METHOD__ );
+ }
+ if ( !$start ) {
+ $this->output( "Nothing to do." );
+ return false;
+ }
+ $end = $db->selectField( 'page', 'MAX(page_id)', false, __METHOD__ );
+
+ # Do remaining chunk
+ $end += $this->mBatchSize - 1;
+ $blockStart = $start;
+ $blockEnd = $start + $this->mBatchSize - 1;
+ while ( $blockEnd <= $end ) {
+ $this->output( "...doing page_id from $blockStart to $blockEnd\n" );
+ $cond = "page_id BETWEEN $blockStart AND $blockEnd";
+ $res = $db->select( 'page', array( 'page_id', 'page_namespace' ), $cond, __METHOD__ );
+ foreach ( $res as $row ) {
+ $db->update( 'pagelinks',
+ array( 'pl_from_namespace' => $row->page_namespace ),
+ array( 'pl_from' => $row->page_id ),
+ __METHOD__
+ );
+ $db->update( 'templatelinks',
+ array( 'tl_from_namespace' => $row->page_namespace ),
+ array( 'tl_from' => $row->page_id ),
+ __METHOD__
+ );
+ $db->update( 'imagelinks',
+ array( 'il_from_namespace' => $row->page_namespace ),
+ array( 'il_from' => $row->page_id ),
+ __METHOD__
+ );
+ }
+ $blockStart += $this->mBatchSize - 1;
+ $blockEnd += $this->mBatchSize - 1;
+ wfWaitForSlaves();
+ }
+ return true;
+ }
+}
+
+$maintClass = "PopulateBacklinkNamespace";
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/populateBloomCache.php b/maintenance/populateBloomCache.php
new file mode 100644
index 00000000..40ad5fc6
--- /dev/null
+++ b/maintenance/populateBloomCache.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Script to populate a bloom filter with a BloomFilter* class
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Script to populate a bloom filter with a BloomFilter* class
+ *
+ * @ingroup Maintenance
+ */
+class PopulateBloomFilter extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->addOption( 'cache', 'Bloom cache store name', true, true );
+ $this->addOption( 'filter', 'Bloom filter name', true, true );
+ $this->addOption( 'domain', 'Bloom filter domain', true, true );
+ $this->addOption( 'delay', 'Sleep delay between batches (us)', false, true );
+ $this->mDescription = "Populate the specified bloom filter";
+ }
+
+ public function execute() {
+ $type = $this->getOption( 'filter' );
+ $domain = $this->getOption( 'domain' );
+ $bcache = BloomCache::get( $this->getOption( 'cache' ) );
+ $delay = $this->getOption( 'delay', 1e5 );
+
+ if ( !method_exists( "BloomFilter{$type}", 'merge' ) ) {
+ $this->error( "No \"BloomFilter{$type}::merge\" method found.", 1 );
+ }
+
+ $virtualKey = "$domain:$type";
+ $status = $bcache->getStatus( $virtualKey );
+ if ( $status == false ) {
+ $this->error( "Could not query virtual bloom filter '$virtualKey'.", 1 );
+ }
+
+ $startTime = microtime( true );
+ $this->output( "Current timestamp is '$startTime'.\n" );
+ $this->output( "Current filter timestamp is '{$status['asOfTime']}'.\n" );
+
+ do {
+ $status = call_user_func_array(
+ array( "BloomFilter{$type}", 'merge' ),
+ array( $bcache, $domain, $virtualKey, $status )
+ );
+ if ( $status == false ) {
+ $this->error( "Could not query virtual bloom filter '$virtualKey'.", 1 );
+ }
+ $this->output( "Filter updated to timestamp '{$status['asOfTime']}'.\n" );
+ usleep( $delay );
+ } while ( $status['asOfTime'] && $status['asOfTime'] < $startTime );
+
+ $this->output( "Done, filter $type of domain $domain reached time '$startTime'.\n" );
+ }
+}
+
+$maintClass = "PopulateBloomFilter";
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/populateCategory.php b/maintenance/populateCategory.php
index 4c8cdaa1..ab0ca1ed 100644
--- a/maintenance/populateCategory.php
+++ b/maintenance/populateCategory.php
@@ -51,9 +51,24 @@ When the script has finished, it will make a note of this in the database, and
will not run again without the --force option.
TEXT;
# '
- $this->addOption( 'begin', 'Only do categories whose names are alphabetically after the provided name', false, true );
- $this->addOption( 'max-slave-lag', 'If slave lag exceeds this many seconds, wait until it drops before continuing. Default: 10', false, true );
- $this->addOption( 'throttle', 'Wait this many milliseconds after each category. Default: 0', false, true );
+ $this->addOption(
+ 'begin',
+ 'Only do categories whose names are alphabetically after the provided name',
+ false,
+ true
+ );
+ $this->addOption(
+ 'max-slave-lag',
+ 'If slave lag exceeds this many seconds, wait until it drops before continuing. Default: 10',
+ false,
+ true
+ );
+ $this->addOption(
+ 'throttle',
+ 'Wait this many milliseconds after each category. Default: 0',
+ false,
+ true
+ );
$this->addOption( 'force', 'Run regardless of whether the database says it\'s been run already' );
}
@@ -77,8 +92,9 @@ TEXT;
);
if ( $row ) {
$this->output( "Category table already populated. Use php " .
- "maintenance/populateCategory.php\n--force from the command line " .
- "to override.\n" );
+ "maintenance/populateCategory.php\n--force from the command line " .
+ "to override.\n" );
+
return true;
}
}
@@ -126,16 +142,17 @@ TEXT;
}
if ( $dbw->insert(
- 'updatelog',
- array( 'ul_key' => 'populate category' ),
- __METHOD__,
- 'IGNORE'
- )
- ) {
+ 'updatelog',
+ array( 'ul_key' => 'populate category' ),
+ __METHOD__,
+ 'IGNORE'
+ ) ) {
$this->output( "Category population complete.\n" );
+
return true;
} else {
$this->output( "Could not insert category population row.\n" );
+
return false;
}
}
diff --git a/maintenance/populateFilearchiveSha1.php b/maintenance/populateFilearchiveSha1.php
index c579d4fc..850a5a5a 100644
--- a/maintenance/populateFilearchiveSha1.php
+++ b/maintenance/populateFilearchiveSha1.php
@@ -51,6 +51,7 @@ class PopulateFilearchiveSha1 extends LoggedUpdateMaintenance {
if ( !$dbw->fieldExists( $table, 'fa_sha1', __METHOD__ ) ) {
$this->output( "fa_sha1 column does not exist\n\n", true );
+
return false;
}
diff --git a/maintenance/populateImageSha1.php b/maintenance/populateImageSha1.php
index 126d22d9..e9123aa3 100644
--- a/maintenance/populateImageSha1.php
+++ b/maintenance/populateImageSha1.php
@@ -33,9 +33,15 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance {
parent::__construct();
$this->mDescription = "Populate the img_sha1 field";
$this->addOption( 'force', "Recalculate sha1 for rows that already have a value" );
+ $this->addOption( 'multiversiononly', "Calculate only for files with several versions" );
$this->addOption( 'method', "Use 'pipe' to pipe to mysql command line,\n" .
"\t\tdefault uses Database class", false, true );
- $this->addOption( 'file', 'Fix for a specific file, without File: namespace prefixed', false, true );
+ $this->addOption(
+ 'file',
+ 'Fix for a specific file, without File: namespace prefixed',
+ false,
+ true
+ );
}
protected function getUpdateKey() {
@@ -47,7 +53,7 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance {
}
public function execute() {
- if ( $this->getOption( 'file' ) ) {
+ if ( $this->getOption( 'file' ) || $this->hasOption( 'multiversiononly' ) ) {
$this->doDBUpdates(); // skip update log checks/saves
} else {
parent::execute();
@@ -71,18 +77,27 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance {
);
if ( !$res ) {
$this->error( "No such file: $file", true );
+
return false;
}
$this->output( "Populating img_sha1 field for specified files\n" );
} else {
- if ( $force ) {
+ if ( $this->hasOption( 'multiversiononly' ) ) {
+ $conds = array();
+ $this->output( "Populating and recalculating img_sha1 field for versioned files\n" );
+ } elseif ( $force ) {
$conds = array();
$this->output( "Populating and recalculating img_sha1 field\n" );
} else {
$conds = array( 'img_sha1' => '' );
$this->output( "Populating img_sha1 field\n" );
}
- $res = $dbw->select( 'image', array( 'img_name' ), $conds, __METHOD__ );
+ if ( $this->hasOption( 'multiversiononly' ) ) {
+ $res = $dbw->select( 'oldimage',
+ array( 'img_name' => 'DISTINCT(oi_name)' ), $conds, __METHOD__ );
+ } else {
+ $res = $dbw->select( 'image', array( 'img_name' ), $conds, __METHOD__ );
+ }
}
$imageTable = $dbw->tableName( 'image' );
@@ -109,10 +124,12 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance {
"Done %d of %d, %5.3f%% \r", $i, $numRows, $i / $numRows * 100 ) );
wfWaitForSlaves();
}
+
$file = wfLocalFile( $row->img_name );
if ( !$file ) {
continue;
}
+
// Upgrade the current file version...
$sha1 = $file->getRepo()->getFileSha1( $file->getPath() );
if ( strval( $sha1 ) !== '' ) { // file on disk and hashed properly
diff --git a/maintenance/populateLogSearch.php b/maintenance/populateLogSearch.php
index d65635e5..4c1a72e8 100644
--- a/maintenance/populateLogSearch.php
+++ b/maintenance/populateLogSearch.php
@@ -31,7 +31,12 @@ require_once __DIR__ . '/Maintenance.php';
* @ingroup Maintenance
*/
class PopulateLogSearch extends LoggedUpdateMaintenance {
- static $tableMap = array( 'rev' => 'revision', 'fa' => 'filearchive', 'oi' => 'oldimage', 'ar' => 'archive' );
+ private static $tableMap = array(
+ 'rev' => 'revision',
+ 'fa' => 'filearchive',
+ 'oi' => 'oldimage',
+ 'ar' => 'archive'
+ );
public function __construct() {
parent::__construct();
@@ -51,11 +56,13 @@ class PopulateLogSearch extends LoggedUpdateMaintenance {
$db = $this->getDB( DB_MASTER );
if ( !$db->tableExists( 'log_search' ) ) {
$this->error( "log_search does not exist" );
+
return false;
}
$start = $db->selectField( 'logging', 'MIN(log_id)', false, __FUNCTION__ );
if ( !$start ) {
$this->output( "Nothing to do.\n" );
+
return true;
}
$end = $db->selectField( 'logging', 'MAX(log_id)', false, __FUNCTION__ );
@@ -121,8 +128,8 @@ class PopulateLogSearch extends LoggedUpdateMaintenance {
// Add item author relations...
$log->addRelations( 'target_author_id', $userIds, $row->log_id );
$log->addRelations( 'target_author_ip', $userIPs, $row->log_id );
- // RevisionDelete logs - log events
} elseif ( LogEventsList::typeAction( $row, $delTypes, 'event' ) ) {
+ // RevisionDelete logs - log events
$params = LogPage::extractParams( $row->log_params );
// Param format: <item CSV> [<ofield> <nfield>]
if ( count( $params ) < 1 ) {
@@ -154,6 +161,7 @@ class PopulateLogSearch extends LoggedUpdateMaintenance {
wfWaitForSlaves();
}
$this->output( "Done populating log_search table.\n" );
+
return true;
}
}
diff --git a/maintenance/populateLogUsertext.php b/maintenance/populateLogUsertext.php
index e579e522..96cb1ec9 100644
--- a/maintenance/populateLogUsertext.php
+++ b/maintenance/populateLogUsertext.php
@@ -52,6 +52,7 @@ class PopulateLogUsertext extends LoggedUpdateMaintenance {
$start = $db->selectField( 'logging', 'MIN(log_id)', false, __METHOD__ );
if ( !$start ) {
$this->output( "Nothing to do.\n" );
+
return true;
}
$end = $db->selectField( 'logging', 'MAX(log_id)', false, __METHOD__ );
@@ -77,6 +78,7 @@ class PopulateLogUsertext extends LoggedUpdateMaintenance {
wfWaitForSlaves();
}
$this->output( "Done populating log_user_text field.\n" );
+
return true;
}
}
diff --git a/maintenance/populateParentId.php b/maintenance/populateParentId.php
index e29fa5f1..f77978fc 100644
--- a/maintenance/populateParentId.php
+++ b/maintenance/populateParentId.php
@@ -49,6 +49,7 @@ class PopulateParentId extends LoggedUpdateMaintenance {
$db = wfGetDB( DB_MASTER );
if ( !$db->tableExists( 'revision' ) ) {
$this->error( "revision table does not exist" );
+
return false;
}
$this->output( "Populating rev_parent_id column\n" );
@@ -56,6 +57,7 @@ class PopulateParentId extends LoggedUpdateMaintenance {
$end = $db->selectField( 'revision', 'MAX(rev_id)', false, __FUNCTION__ );
if ( is_null( $start ) || is_null( $end ) ) {
$this->output( "...revision table seems to be empty, nothing to do.\n" );
+
return true;
}
# Do remaining chunk
@@ -85,10 +87,16 @@ class PopulateParentId extends LoggedUpdateMaintenance {
# If there are none, check the the highest ID with a lower timestamp
if ( !$previousID ) {
# Get the highest older timestamp
- $lastTimestamp = $db->selectField( 'revision', 'rev_timestamp',
- array( 'rev_page' => $row->rev_page, "rev_timestamp < " . $db->addQuotes( $row->rev_timestamp ) ),
+ $lastTimestamp = $db->selectField(
+ 'revision',
+ 'rev_timestamp',
+ array(
+ 'rev_page' => $row->rev_page,
+ "rev_timestamp < " . $db->addQuotes( $row->rev_timestamp )
+ ),
__METHOD__,
- array( 'ORDER BY' => 'rev_timestamp DESC' ) );
+ array( 'ORDER BY' => 'rev_timestamp DESC' )
+ );
# If there is one, let the highest rev ID win
if ( $lastTimestamp ) {
$previousID = $db->selectField( 'revision', 'rev_id',
@@ -113,6 +121,7 @@ class PopulateParentId extends LoggedUpdateMaintenance {
wfWaitForSlaves();
}
$this->output( "rev_parent_id population complete ... {$count} rows [{$changed} changed]\n" );
+
return true;
}
}
diff --git a/maintenance/populateRecentChangesSource.php b/maintenance/populateRecentChangesSource.php
new file mode 100644
index 00000000..25a51d72
--- /dev/null
+++ b/maintenance/populateRecentChangesSource.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Upgrade script to populate the rc_source field
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script to populate the rc_source field.
+ *
+ * @ingroup Maintenance
+ * @since 1.22
+ */
+class PopulateRecentChangesSource extends LoggedUpdateMaintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription =
+ "Populates rc_source field of the recentchanges table with the data in rc_type.";
+ $this->setBatchSize( 100 );
+ }
+
+ protected function doDBUpdates() {
+ $dbw = $this->getDB( DB_MASTER );
+ if ( !$dbw->fieldExists( 'recentchanges', 'rc_source' ) ) {
+ $this->error( 'rc_source field in recentchanges table does not exist.' );
+ }
+
+ $start = $dbw->selectField( 'recentchanges', 'MIN(rc_id)', false, __METHOD__ );
+ if ( !$start ) {
+ $this->output( "Nothing to do.\n" );
+
+ return true;
+ }
+ $end = $dbw->selectField( 'recentchanges', 'MAX(rc_id)', false, __METHOD__ );
+ $end += $this->mBatchSize - 1;
+ $blockStart = $start;
+ $blockEnd = $start + $this->mBatchSize - 1;
+
+ $updatedValues = $this->buildUpdateCondition( $dbw );
+
+ while ( $blockEnd <= $end ) {
+ $cond = "rc_id BETWEEN $blockStart AND $blockEnd";
+
+ $dbw->update(
+ 'recentchanges',
+ array( $updatedValues ),
+ array(
+ "rc_source = ''",
+ "rc_id BETWEEN $blockStart AND $blockEnd"
+ ),
+ __METHOD__
+ );
+
+ $this->output( "." );
+ wfWaitForSlaves();
+
+ $blockStart += $this->mBatchSize;
+ $blockEnd += $this->mBatchSize;
+ }
+
+ $this->output( "\nDone.\n" );
+ }
+
+ protected function getUpdateKey() {
+ return __CLASS__;
+ }
+
+ protected function buildUpdateCondition( DatabaseBase $dbw ) {
+ $rcNew = $dbw->addQuotes( RC_NEW );
+ $rcSrcNew = $dbw->addQuotes( RecentChange::SRC_NEW );
+ $rcEdit = $dbw->addQuotes( RC_EDIT );
+ $rcSrcEdit = $dbw->addQuotes( RecentChange::SRC_EDIT );
+ $rcLog = $dbw->addQuotes( RC_LOG );
+ $rcSrcLog = $dbw->addQuotes( RecentChange::SRC_LOG );
+ $rcExternal = $dbw->addQuotes( RC_EXTERNAL );
+ $rcSrcExternal = $dbw->addQuotes( RecentChange::SRC_EXTERNAL );
+
+ return "rc_source = CASE
+ WHEN rc_type = $rcNew THEN $rcSrcNew
+ WHEN rc_type = $rcEdit THEN $rcSrcEdit
+ WHEN rc_type = $rcLog THEN $rcSrcLog
+ WHEN rc_type = $rcExternal THEN $rcSrcExternal
+ ELSE ''
+ END";
+ }
+}
+
+$maintClass = "PopulateRecentChangesSource";
+require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/populateRevisionLength.php b/maintenance/populateRevisionLength.php
index 3c69125a..b73ac7f2 100644
--- a/maintenance/populateRevisionLength.php
+++ b/maintenance/populateRevisionLength.php
@@ -1,6 +1,7 @@
<?php
/**
- * Populates the rev_len field for old revisions created before MW 1.10.
+ * Populates the rev_len and ar_len fields for old revisions created
+ * before MW 1.10.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,86 +25,128 @@
require_once __DIR__ . '/Maintenance.php';
/**
- * Maintenance script that populates the rev_len field for old revisions
- * created before MW 1.10.
+ * Maintenance script that populates the rev_len and ar_len fields
+ * for old revisions created before MW 1.10.
*
* @ingroup Maintenance
*/
class PopulateRevisionLength extends LoggedUpdateMaintenance {
public function __construct() {
parent::__construct();
- $this->mDescription = "Populates the rev_len field";
+ $this->mDescription = "Populates the rev_len and ar_len fields";
$this->setBatchSize( 200 );
}
protected function getUpdateKey() {
- return 'populate rev_len';
- }
-
- protected function updateSkippedMessage() {
- return 'rev_len column of revision table already populated.';
+ return 'populate rev_len and ar_len';
}
public function doDBUpdates() {
$db = $this->getDB( DB_MASTER );
if ( !$db->tableExists( 'revision' ) ) {
$this->error( "revision table does not exist", true );
+ } elseif ( !$db->tableExists( 'archive' ) ) {
+ $this->error( "archive table does not exist", true );
} elseif ( !$db->fieldExists( 'revision', 'rev_len', __METHOD__ ) ) {
$this->output( "rev_len column does not exist\n\n", true );
+
return false;
}
$this->output( "Populating rev_len column\n" );
+ $rev = $this->doLenUpdates( 'revision', 'rev_id', 'rev', Revision::selectFields() );
+
+ $this->output( "Populating ar_len column\n" );
+ $ar = $this->doLenUpdates( 'archive', 'ar_id', 'ar', Revision::selectArchiveFields() );
+
+ $this->output( "rev_len and ar_len population complete "
+ . "[$rev revision rows, $ar archive rows].\n" );
+
+ return true;
+ }
- $start = $db->selectField( 'revision', 'MIN(rev_id)', false, __METHOD__ );
- $end = $db->selectField( 'revision', 'MAX(rev_id)', false, __METHOD__ );
+ /**
+ * @param string $table
+ * @param string $idCol
+ * @param string $prefix
+ * @param array $fields
+ * @return int
+ */
+ protected function doLenUpdates( $table, $idCol, $prefix, $fields ) {
+ $db = $this->getDB( DB_MASTER );
+ $start = $db->selectField( $table, "MIN($idCol)", false, __METHOD__ );
+ $end = $db->selectField( $table, "MAX($idCol)", false, __METHOD__ );
if ( !$start || !$end ) {
- $this->output( "...revision table seems to be empty.\n" );
- return true;
+ $this->output( "...$table table seems to be empty.\n" );
+
+ return 0;
}
# Do remaining chunks
$blockStart = intval( $start );
$blockEnd = intval( $start ) + $this->mBatchSize - 1;
$count = 0;
- $missing = 0;
- $fields = Revision::selectFields();
+
while ( $blockStart <= $end ) {
- $this->output( "...doing rev_id from $blockStart to $blockEnd\n" );
+ $this->output( "...doing $idCol from $blockStart to $blockEnd\n" );
$res = $db->select(
- 'revision',
+ $table,
$fields,
array(
- "rev_id >= $blockStart",
- "rev_id <= $blockEnd",
- "rev_len IS NULL"
+ "$idCol >= $blockStart",
+ "$idCol <= $blockEnd",
+ "{$prefix}_len IS NULL"
),
__METHOD__
);
+
+ $db->begin( __METHOD__ );
# Go through and update rev_len from these rows.
foreach ( $res as $row ) {
- $rev = new Revision( $row );
- $content = $rev->getContent();
- if ( !$content ) {
- # This should not happen, but sometimes does (bug 20757)
- $this->output( "Content of revision {$row->rev_id} unavailable!\n" );
- $missing++;
- }
- else {
- # Update the row...
- $db->update( 'revision',
- array( 'rev_len' => $content->getSize() ),
- array( 'rev_id' => $row->rev_id ),
- __METHOD__ );
+ if ( $this->upgradeRow( $row, $table, $idCol, $prefix ) ) {
$count++;
}
}
+ $db->commit( __METHOD__ );
+
$blockStart += $this->mBatchSize;
$blockEnd += $this->mBatchSize;
wfWaitForSlaves();
}
- $this->output( "rev_len population complete ... {$count} rows changed ({$missing} missing)\n" );
+ return $count;
+ }
+
+ /**
+ * @param stdClass $row
+ * @param string $table
+ * @param string $idCol
+ * @param string $prefix
+ * @return bool
+ */
+ protected function upgradeRow( $row, $table, $idCol, $prefix ) {
+ $db = $this->getDB( DB_MASTER );
+
+ $rev = ( $table === 'archive' )
+ ? Revision::newFromArchiveRow( $row )
+ : new Revision( $row );
+
+ $content = $rev->getContent();
+ if ( !$content ) {
+ # This should not happen, but sometimes does (bug 20757)
+ $id = $row->$idCol;
+ $this->output( "Content of $table $id unavailable!\n" );
+
+ return false;
+ }
+
+ # Update the row...
+ $db->update( $table,
+ array( "{$prefix}_len" => $content->getSize() ),
+ array( $idCol => $row->$idCol ),
+ __METHOD__
+ );
+
return true;
}
}
diff --git a/maintenance/populateRevisionSha1.php b/maintenance/populateRevisionSha1.php
index 89bfb85b..f06b56be 100644
--- a/maintenance/populateRevisionSha1.php
+++ b/maintenance/populateRevisionSha1.php
@@ -50,6 +50,7 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$this->error( "archive table does not exist", true );
} elseif ( !$db->fieldExists( 'revision', 'rev_sha1', __METHOD__ ) ) {
$this->output( "rev_sha1 column does not exist\n\n", true );
+
return false;
}
@@ -61,15 +62,17 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$this->output( "Populating ar_sha1 column legacy rows\n" );
$ac += $this->doSha1LegacyUpdates();
- $this->output( "rev_sha1 and ar_sha1 population complete [$rc revision rows, $ac archive rows].\n" );
+ $this->output( "rev_sha1 and ar_sha1 population complete "
+ . "[$rc revision rows, $ac archive rows].\n" );
+
return true;
}
/**
- * @param $table string
- * @param $idCol
- * @param $prefix string
- * @return Integer Rows changed
+ * @param string $table
+ * @param string $idCol
+ * @param string $prefix
+ * @return int Rows changed
*/
protected function doSha1Updates( $table, $idCol, $prefix ) {
$db = $this->getDB( DB_MASTER );
@@ -77,6 +80,7 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$end = $db->selectField( $table, "MAX($idCol)", false, __METHOD__ );
if ( !$start || !$end ) {
$this->output( "...$table table seems to be empty.\n" );
+
return 0;
}
@@ -103,6 +107,7 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$blockEnd += $this->mBatchSize;
wfWaitForSlaves();
}
+
return $count;
}
@@ -130,14 +135,15 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
}
}
$db->commit( __METHOD__ );
+
return $count;
}
/**
- * @param $row
- * @param $table
- * @param $idCol
- * @param $prefix
+ * @param stdClass $row
+ * @param string $table
+ * @param string $idCol
+ * @param string $prefix
* @return bool
*/
protected function upgradeRow( $row, $table, $idCol, $prefix ) {
@@ -149,11 +155,13 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$text = $rev->getSerializedData();
} catch ( MWException $e ) {
$this->output( "Data of revision with {$idCol}={$row->$idCol} unavailable!\n" );
+
return false; // bug 22624?
}
if ( !is_string( $text ) ) {
# This should not happen, but sometimes does (bug 20757)
$this->output( "Data of revision with {$idCol}={$row->$idCol} unavailable!\n" );
+
return false;
} else {
$db->update( $table,
@@ -161,12 +169,13 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
array( $idCol => $row->$idCol ),
__METHOD__
);
+
return true;
}
}
/**
- * @param $row
+ * @param stdClass $row
* @return bool
*/
protected function upgradeLegacyArchiveRow( $row ) {
@@ -175,12 +184,14 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
$rev = Revision::newFromArchiveRow( $row );
} catch ( MWException $e ) {
$this->output( "Text of revision with timestamp {$row->ar_timestamp} unavailable!\n" );
+
return false; // bug 22624?
}
$text = $rev->getSerializedData();
if ( !is_string( $text ) ) {
# This should not happen, but sometimes does (bug 20757)
$this->output( "Data of revision with timestamp {$row->ar_timestamp} unavailable!\n" );
+
return false;
} else {
# Archive table as no PK, but (NS,title,time) should be near unique.
@@ -195,6 +206,7 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
),
__METHOD__
);
+
return true;
}
}
diff --git a/maintenance/postgres/mediawiki_mysql2postgres.pl b/maintenance/postgres/mediawiki_mysql2postgres.pl
index 8f170abc..34837e1b 100644
--- a/maintenance/postgres/mediawiki_mysql2postgres.pl
+++ b/maintenance/postgres/mediawiki_mysql2postgres.pl
@@ -1,7 +1,6 @@
#!/usr/bin/perl
## Convert data from a MySQL mediawiki database into a Postgres mediawiki database
-## svn: $Id$
## NOTE: It is probably easier to dump your wiki using maintenance/dumpBackup.php
## and then import it with maintenance/importDump.php
@@ -181,7 +180,7 @@ $MYSQLSOCKET and $conninfo .= "\n-- socket $MYSQLSOCKET";
print qq{
-- Dump of MySQL Mediawiki tables for import into a Postgres Mediawiki schema
-- Performed by the program: $0
--- Version: $VERSION (subversion }.q{$LastChangedRevision$}.qq{)
+-- Version: $VERSION
-- Author: Greg Sabino Mullane <greg\@turnstep.com> Comments welcome
--
-- This file was created: $now
diff --git a/maintenance/postgres/tables.sql b/maintenance/postgres/tables.sql
index 5ed7de99..400050e7 100644
--- a/maintenance/postgres/tables.sql
+++ b/maintenance/postgres/tables.sql
@@ -12,18 +12,23 @@ SET client_min_messages = 'ERROR';
DROP SEQUENCE IF EXISTS user_user_id_seq CASCADE;
DROP SEQUENCE IF EXISTS page_page_id_seq CASCADE;
DROP SEQUENCE IF EXISTS revision_rev_id_seq CASCADE;
-DROP SEQUENCE IF EXISTS page_restrictions_id_seq CASCADE;
+DROP SEQUENCE IF EXISTS text_old_id_seq CASCADE;
+DROP SEQUENCE IF EXISTS page_restrictions_pr_id_seq CASCADE;
DROP SEQUENCE IF EXISTS ipblocks_ipb_id_seq CASCADE;
+DROP SEQUENCE IF EXISTS filearchive_fa_id_seq CASCADE;
+DROP SEQUENCE IF EXISTS uploadstash_us_id_seq CASCADE;
DROP SEQUENCE IF EXISTS recentchanges_rc_id_seq CASCADE;
DROP SEQUENCE IF EXISTS logging_log_id_seq CASCADE;
DROP SEQUENCE IF EXISTS job_job_id_seq CASCADE;
DROP SEQUENCE IF EXISTS category_cat_id_seq CASCADE;
DROP SEQUENCE IF EXISTS archive_ar_id_seq CASCADE;
DROP SEQUENCE IF EXISTS externallinks_el_id_seq CASCADE;
+DROP SEQUENCE IF EXISTS sites_site_id_seq CASCADE;
DROP FUNCTION IF EXISTS page_deleted() CASCADE;
DROP FUNCTION IF EXISTS ts2_page_title() CASCADE;
DROP FUNCTION IF EXISTS ts2_page_text() CASCADE;
DROP FUNCTION IF EXISTS add_interwiki(TEXT,INT,SMALLINT) CASCADE;
+DROP TYPE IF EXISTS media_type CASCADE;
CREATE SEQUENCE user_user_id_seq MINVALUE 0 START WITH 0;
CREATE TABLE mwuser ( -- replace reserved word 'user'
@@ -40,7 +45,8 @@ CREATE TABLE mwuser ( -- replace reserved word 'user'
user_email_authenticated TIMESTAMPTZ,
user_touched TIMESTAMPTZ,
user_registration TIMESTAMPTZ,
- user_editcount INTEGER
+ user_editcount INTEGER,
+ user_password_expires TIMESTAMPTZ NULL
);
CREATE INDEX user_email_token_idx ON mwuser (user_email_token);
@@ -80,9 +86,11 @@ CREATE TABLE page (
page_is_new SMALLINT NOT NULL DEFAULT 0,
page_random NUMERIC(15,14) NOT NULL DEFAULT RANDOM(),
page_touched TIMESTAMPTZ,
+ page_links_updated TIMESTAMPTZ NULL,
page_latest INTEGER NOT NULL, -- FK?
page_len INTEGER NOT NULL,
- page_content_model TEXT
+ page_content_model TEXT,
+ page_lang TEXT DEFAULT NULL
);
CREATE UNIQUE INDEX page_unique_name ON page (page_namespace, page_title);
CREATE INDEX page_main_title ON page (page_title text_pattern_ops) WHERE page_namespace = 0;
@@ -152,11 +160,13 @@ ALTER TABLE page_restrictions ADD CONSTRAINT page_restrictions_pk PRIMARY KEY (p
CREATE TABLE page_props (
pp_page INTEGER NOT NULL REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
pp_propname TEXT NOT NULL,
- pp_value TEXT NOT NULL
+ pp_value TEXT NOT NULL,
+ pp_sortkey FLOAT
);
ALTER TABLE page_props ADD CONSTRAINT page_props_pk PRIMARY KEY (pp_page,pp_propname);
CREATE INDEX page_props_propname ON page_props (pp_propname);
CREATE UNIQUE INDEX pp_propname_page ON page_props (pp_propname,pp_page);
+CREATE INDEX pp_propname_sortkey_page ON page_props (pp_propname, pp_sortkey, pp_page) WHERE (pp_sortkey IS NOT NULL);
CREATE SEQUENCE archive_ar_id_seq;
CREATE TABLE archive (
@@ -196,6 +206,7 @@ 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 DEFERRABLE INITIALLY DEFERRED,
+ pl_from_namespace INTEGER NOT NULL DEFAULT 0,
pl_namespace SMALLINT NOT NULL,
pl_title TEXT NOT NULL
);
@@ -204,6 +215,7 @@ CREATE INDEX pagelinks_title ON pagelinks (pl_title);
CREATE TABLE templatelinks (
tl_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ tl_from_namespace INTEGER NOT NULL DEFAULT 0,
tl_namespace SMALLINT NOT NULL,
tl_title TEXT NOT NULL
);
@@ -212,6 +224,7 @@ CREATE INDEX templatelinks_from ON templatelinks (tl_from);
CREATE TABLE imagelinks (
il_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
+ il_from_namespace INTEGER NOT NULL DEFAULT 0,
il_to TEXT NOT NULL
);
CREATE UNIQUE INDEX il_from ON imagelinks (il_to,il_from);
@@ -399,7 +412,7 @@ CREATE SEQUENCE recentchanges_rc_id_seq;
CREATE TABLE recentchanges (
rc_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('recentchanges_rc_id_seq'),
rc_timestamp TIMESTAMPTZ NOT NULL,
- rc_cur_time TIMESTAMPTZ NOT NULL,
+ rc_cur_time TIMESTAMPTZ NULL,
rc_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED,
rc_user_text TEXT NOT NULL,
rc_namespace SMALLINT NOT NULL,
@@ -412,6 +425,7 @@ CREATE TABLE recentchanges (
rc_this_oldid INTEGER NOT NULL,
rc_last_oldid INTEGER NOT NULL,
rc_type SMALLINT NOT NULL DEFAULT 0,
+ rc_source TEXT NOT NULL,
rc_patrolled SMALLINT NOT NULL DEFAULT 0,
rc_ip CIDR,
rc_old_len INTEGER,
@@ -438,6 +452,7 @@ CREATE TABLE watchlist (
);
CREATE UNIQUE INDEX wl_user_namespace_title ON watchlist (wl_namespace, wl_title, wl_user);
CREATE INDEX wl_user ON watchlist (wl_user);
+CREATE INDEX wl_user_notificationtimestamp ON watchlist (wl_user, wl_notificationtimestamp);
CREATE TABLE interwiki (
@@ -510,6 +525,8 @@ CREATE INDEX logging_page_time ON logging (log_namespace, log_title, log_timesta
CREATE INDEX logging_times ON logging (log_timestamp);
CREATE INDEX logging_user_type_time ON logging (log_user, log_type, log_timestamp);
CREATE INDEX logging_page_id_time ON logging (log_page, log_timestamp);
+CREATE INDEX logging_user_text_type_time ON logging (log_user_text, log_type, log_timestamp);
+CREATE INDEX logging_user_text_time ON logging (log_user_text, log_timestamp);
CREATE TABLE log_search (
ls_field TEXT NOT NULL,
@@ -666,7 +683,7 @@ CREATE INDEX user_properties_property ON user_properties (up_property);
CREATE TABLE l10n_cache (
lc_lang TEXT NOT NULL,
lc_key TEXT NOT NULL,
- lc_value TEXT NOT NULL
+ lc_value BYTEA NOT NULL
);
CREATE INDEX l10n_cache_lc_lang_key ON l10n_cache (lc_lang, lc_key);
diff --git a/maintenance/postgres/update-keys.sql b/maintenance/postgres/update-keys.sql
new file mode 100644
index 00000000..7761d0c5
--- /dev/null
+++ b/maintenance/postgres/update-keys.sql
@@ -0,0 +1,29 @@
+-- SQL to insert update keys into the initial tables after a
+-- fresh installation of MediaWiki's database.
+-- This is read and executed by the install script; you should
+-- not have to run it by itself unless doing a manual install.
+-- Insert keys here if either the unnecessary would cause heavy
+-- processing or could potentially cause trouble by lowering field
+-- sizes, adding constraints, etc.
+-- When adjusting field sizes, it is recommended removing old
+-- patches but to play safe, update keys should also inserted here.
+
+-- The /*_*/ comments in this and other files are
+-- replaced with the defined table prefix by the installer
+-- and updater scripts. If you are installing or running
+-- updates manually, you will need to manually insert the
+-- table prefix if any when running these scripts.
+--
+
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'filearchive-fa_major_mime-patch-fa_major_mime-chemical.sql', null );
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'image-img_major_mime-patch-img_major_mime-chemical.sql', null );
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'oldimage-oi_major_mime-patch-oi_major_mime-chemical.sql', null );
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'user_groups-ug_group-patch-ug_group-length-increase-255.sql', null );
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'user_former_groups-ufg_group-patch-ufg_group-length-increase-255.sql', null );
+INSERT INTO /*_*/updatelog (ul_key, ul_value)
+ VALUES( 'user_properties-up_property-patch-up_property.sql', null );
diff --git a/maintenance/preprocessDump.php b/maintenance/preprocessDump.php
index 0dc19e28..17d97b05 100644
--- a/maintenance/preprocessDump.php
+++ b/maintenance/preprocessDump.php
@@ -4,7 +4,7 @@
* It may be useful for getting preprocessor statistics or filling the
* preprocessor cache.
*
- * Copyright © 2011 Platonides - http://www.mediawiki.org/
+ * Copyright © 2011 Platonides - https://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
@@ -41,6 +41,7 @@ class PreprocessDump extends DumpIterator {
public function getStripList() {
global $wgParser;
+
return $wgParser->getStripList();
}
@@ -75,7 +76,7 @@ class PreprocessDump extends DumpIterator {
/**
* Callback function for each revision, preprocessToObj()
- * @param $rev Revision
+ * @param Revision $rev
*/
public function processRevision( $rev ) {
$content = $rev->getContent( Revision::RAW );
@@ -87,7 +88,8 @@ class PreprocessDump extends DumpIterator {
try {
$this->mPreprocessor->preprocessToObj( strval( $content->getNativeData() ), 0 );
} catch ( Exception $e ) {
- $this->error( "Caught exception " . $e->getMessage() . " in " . $rev->getTitle()->getPrefixedText() );
+ $this->error( "Caught exception " . $e->getMessage() . " in "
+ . $rev->getTitle()->getPrefixedText() );
}
}
}
diff --git a/maintenance/preprocessorFuzzTest.php b/maintenance/preprocessorFuzzTest.php
index 563ea459..cb55f0f2 100644
--- a/maintenance/preprocessorFuzzTest.php
+++ b/maintenance/preprocessorFuzzTest.php
@@ -45,7 +45,8 @@ class PPFuzzTester {
// public $outputTypes = array( 'OT_HTML', 'OT_WIKI', 'OT_PREPROCESS' );
public $entryPoints = array( 'testSrvus', 'testPst', 'testPreprocess' );
public $verbose = false;
- static $currentTest = false;
+
+ private static $currentTest = false;
function execute() {
if ( !file_exists( 'results' ) ) {
@@ -120,6 +121,7 @@ class PPFuzzTester {
// It's done by the MW UI, so it's a reasonably legitimate thing to do.
global $wgContLang;
$s = $wgContLang->normalize( $s );
+
return $s;
}
@@ -135,7 +137,8 @@ class PPFuzzTester {
function pickEntryPoint() {
$count = count( $this->entryPoints );
- return $this->entryPoints[ mt_rand( 0, $count - 1 ) ];
+
+ return $this->entryPoints[mt_rand( 0, $count - 1 )];
}
}
@@ -155,7 +158,8 @@ class PPFuzzTest {
}
/**
- * @param $title Title
+ * @param Title $title
+ * @return array
*/
function templateHook( $title ) {
$titleText = $title->getPrefixedDBkey();
@@ -181,6 +185,7 @@ class PPFuzzTest {
'text' => $text,
'finalTitle' => $finalTitle );
}
+
return $this->templates[$titleText];
}
@@ -195,7 +200,13 @@ class PPFuzzTest {
$options = ParserOptions::newFromUser( $wgUser );
$options->setTemplateCallback( array( $this, 'templateHook' ) );
$options->setTimestamp( wfTimestampNow() );
- $this->output = call_user_func( array( $wgParser, $this->entryPoint ), $this->mainText, $this->title, $options );
+ $this->output = call_user_func(
+ array( $wgParser, $this->entryPoint ),
+ $this->mainText,
+ $this->title,
+ $options
+ );
+
return $this->output;
}
@@ -203,7 +214,8 @@ class PPFuzzTest {
$s = "Title: " . $this->title->getPrefixedDBkey() . "\n" .
// "Output type: {$this->outputType}\n" .
"Entry point: {$this->entryPoint}\n" .
- "User: " . ( $this->fancySig ? 'fancy' : 'no-fancy' ) . ' ' . var_export( $this->nickname, true ) . "\n" .
+ "User: " . ( $this->fancySig ? 'fancy' : 'no-fancy' ) .
+ ' ' . var_export( $this->nickname, true ) . "\n" .
"Main text: " . var_export( $this->mainText, true ) . "\n";
foreach ( $this->templates as $titleText => $template ) {
$finalTitle = $template['finalTitle'];
@@ -214,6 +226,7 @@ class PPFuzzTest {
}
}
$s .= "Output: " . var_export( $this->output, true ) . "\n";
+
return $s;
}
}
diff --git a/maintenance/pruneFileCache.php b/maintenance/pruneFileCache.php
index 48d38977..455e9c07 100644
--- a/maintenance/pruneFileCache.php
+++ b/maintenance/pruneFileCache.php
@@ -75,8 +75,8 @@ class PruneFileCache extends Maintenance {
}
/**
- * @param $dir string
- * @param $report string|bool Use 'report' to report the directories being scanned
+ * @param string $dir
+ * @param string|bool $report Use 'report' to report the directories being scanned
*/
protected function prune_directory( $dir, $report = false ) {
$tsNow = time();
@@ -95,8 +95,8 @@ class PruneFileCache extends Maintenance {
// Sanity check the file extension against known cache types
if ( $mts < $this->minSurviveTimestamp
&& preg_match( '/\.(?:html|cache)(?:\.gz)?$/', $file )
- && unlink( $path ) )
- {
+ && unlink( $path )
+ ) {
$daysOld = round( ( $tsNow - $mts ) / 86400, 2 );
$this->output( "Deleted `$path` [days=$daysOld]\n" );
}
diff --git a/maintenance/purgeChangedFiles.php b/maintenance/purgeChangedFiles.php
index 9f83ee7f..1e702dea 100644
--- a/maintenance/purgeChangedFiles.php
+++ b/maintenance/purgeChangedFiles.php
@@ -69,7 +69,9 @@ class PurgeChangedFiles extends Maintenance {
implode( ',', array_keys( self::$typeMappings ) ) . ',all)', false, true );
$this->addOption( 'htcp-dest', 'HTCP announcement destination (IP:port)', false, true );
$this->addOption( 'dry-run', 'Do not send purge requests' );
+ $this->addOption( 'sleep-per-batch', 'Milliseconds to sleep between batches', false, true );
$this->addOption( 'verbose', 'Show more output', false, false, 'v' );
+ $this->setBatchSize( 100 );
}
public function execute() {
@@ -119,7 +121,7 @@ class PurgeChangedFiles extends Maintenance {
$this->mOptions['verbose'] = 1;
}
- $this->verbose( 'Purging files that were: ' . implode( ', ', $typeList ) . "\n");
+ $this->verbose( 'Purging files that were: ' . implode( ', ', $typeList ) . "\n" );
foreach ( $typeList as $type ) {
$this->verbose( "Checking for {$type} files...\n" );
$this->purgeFromLogType( $type );
@@ -154,6 +156,7 @@ class PurgeChangedFiles extends Maintenance {
__METHOD__
);
+ $bSize = 0;
foreach ( $res as $row ) {
$file = $repo->newFile( Title::makeTitle( NS_FILE, $row->log_title ) );
@@ -174,7 +177,6 @@ class PurgeChangedFiles extends Maintenance {
// Sanity check to avoid data loss
$repo->getBackend()->delete( array( 'src' => $file->getPath() ) );
$this->verbose( "Deleted orphan file: {$file->getPath()}.\n" );
-
} else {
$this->error( "File was not deleted: {$file->getPath()}.\n" );
}
@@ -182,8 +184,7 @@ class PurgeChangedFiles extends Maintenance {
// Purge items from fileachive table (rows are likely here)
$this->purgeFromArchiveTable( $repo, $file );
-
- } else if ( $logType === 'move' ) {
+ } elseif ( $logType === 'move' ) {
// Purge the target file as well
$params = unserialize( $row->log_params );
@@ -197,6 +198,12 @@ class PurgeChangedFiles extends Maintenance {
}
$this->verbose( "Purged file {$row->log_title}; {$type} @{$row->log_timestamp}.\n" );
+
+ if ( $this->hasOption( 'sleep-per-batch' ) && ++$bSize > $this->mBatchSize ) {
+ $bSize = 0;
+ // sleep-per-batch is milliseconds, usleep wants micro seconds.
+ usleep( 1000 * (int)$this->getOption( 'sleep-per-batch' ) );
+ }
}
}
}
@@ -223,7 +230,6 @@ class PurgeChangedFiles extends Maintenance {
// Sanity check to avoid data loss
$repo->getBackend()->delete( array( 'src' => $ofile->getPath() ) );
$this->output( "Deleted orphan file: {$ofile->getPath()}.\n" );
-
} else {
$this->error( "File was not deleted: {$ofile->getPath()}.\n" );
}
@@ -235,6 +241,7 @@ class PurgeChangedFiles extends Maintenance {
protected function getDeletedPath( LocalRepo $repo, LocalFile $file ) {
$hash = $repo->getFileSha1( $file->getPath() );
$key = "{$hash}.{$file->getExtension()}";
+
return $repo->getDeletedHashPath( $key ) . $key;
}
@@ -248,7 +255,6 @@ class PurgeChangedFiles extends Maintenance {
$this->output( $msg );
}
}
-
}
$maintClass = "PurgeChangedFiles";
diff --git a/maintenance/purgeChangedPages.php b/maintenance/purgeChangedPages.php
index 071ac09c..67022094 100644
--- a/maintenance/purgeChangedPages.php
+++ b/maintenance/purgeChangedPages.php
@@ -160,10 +160,11 @@ class PurgeChangedPages extends Maintenance {
* If this returns an empty array for a non-empty query result, then all the rows
* had the same column value and the query should be repeated with a higher LIMIT.
*
- * @TODO: move this elsewhere
+ * @todo move this elsewhere
*
* @param ResultWrapper $res Query result sorted by $column (ascending)
* @param string $column
+ * @param int $limit
* @return array (array of rows, string column value)
*/
protected function pageableSortedRows( ResultWrapper $res, $column, $limit ) {
@@ -183,6 +184,7 @@ class PurgeChangedPages extends Maintenance {
}
}
$lastValueLeft = count( $rows ) ? $rows[count( $rows ) - 1]->$column : null;
+
return array( $rows, $lastValueLeft );
}
}
diff --git a/maintenance/purgeList.php b/maintenance/purgeList.php
index 2f895201..2e196309 100644
--- a/maintenance/purgeList.php
+++ b/maintenance/purgeList.php
@@ -51,7 +51,9 @@ class PurgeList extends Maintenance {
$this->output( "Done!\n" );
}
- /** Purge URL coming from stdin */
+ /**
+ * Purge URL coming from stdin
+ */
private function doPurge() {
$stdin = $this->getStdin();
$urls = array();
@@ -78,7 +80,11 @@ class PurgeList extends Maintenance {
$this->sendPurgeRequest( $urls );
}
- /** Purge a namespace or all pages */
+ /**
+ * Purge a namespace or all pages
+ *
+ * @param int|bool $namespace
+ */
private function purgeNamespace( $namespace = false ) {
$dbr = wfGetDB( DB_SLAVE );
$startId = 0;
@@ -114,7 +120,7 @@ class PurgeList extends Maintenance {
/**
* Helper to purge an array of $urls
- * @param $urls array List of URLS to purge from squids
+ * @param array $urls List of URLS to purge from squids
*/
private function sendPurgeRequest( $urls ) {
if ( $this->hasOption( 'delay' ) ) {
@@ -135,7 +141,6 @@ class PurgeList extends Maintenance {
$u->doUpdate();
}
}
-
}
$maintClass = "PurgeList";
diff --git a/maintenance/purgeOldText.inc b/maintenance/purgeOldText.inc
deleted file mode 100644
index db961d81..00000000
--- a/maintenance/purgeOldText.inc
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-
-/**
- * Support functions for cleaning up redundant text records
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- * @author Rob Church <robchur@gmail.com>
- */
-
-function PurgeRedundantText( $delete = false ) {
-
- # Data should come off the master, wrapped in a transaction
- $dbw = wfGetDB( DB_MASTER );
- $dbw->begin( __METHOD__ );
-
- $tbl_arc = $dbw->tableName( 'archive' );
- $tbl_rev = $dbw->tableName( 'revision' );
- $tbl_txt = $dbw->tableName( 'text' );
-
- # Get "active" text records from the revisions table
- echo "Searching for active text records in revisions table...";
- $res = $dbw->query( "SELECT DISTINCT rev_text_id FROM $tbl_rev" );
- foreach ( $res as $row ) {
- $cur[] = $row->rev_text_id;
- }
- echo "done.\n";
-
- # Get "active" text records from the archive table
- echo "Searching for active text records in archive table...";
- $res = $dbw->query( "SELECT DISTINCT ar_text_id FROM $tbl_arc" );
- $cur = array();
- foreach ( $res as $row ) {
- $cur[] = $row->ar_text_id;
- }
- echo "done.\n";
-
- # Get the IDs of all text records not in these sets
- 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();
- foreach ( $res as $row ) {
- $old[] = $row->old_id;
- }
- echo "done.\n";
-
- # Inform the user of what we're going to do
- $count = count( $old );
- echo "$count inactive items found.\n";
-
- # Delete as appropriate
- if ( $delete && $count ) {
- echo "Deleting...";
- $set = implode( ', ', $old );
- $dbw->query( "DELETE FROM $tbl_txt WHERE old_id IN ( $set )" );
- echo "done.\n";
- }
-
- # Done
- $dbw->commit( __METHOD__ );
-
-}
diff --git a/maintenance/purgeParserCache.php b/maintenance/purgeParserCache.php
index ca2a0414..9970c1fd 100644
--- a/maintenance/purgeParserCache.php
+++ b/maintenance/purgeParserCache.php
@@ -37,7 +37,8 @@ class PurgeParserCache extends Maintenance {
$this->addDescription( "Remove old objects from the parser cache. " .
"This only works when the parser cache is in an SQL database." );
$this->addOption( 'expiredate', 'Delete objects expiring before this date.', false, true );
- $this->addOption( 'age',
+ $this->addOption(
+ 'age',
'Delete objects created more than this many seconds ago, assuming $wgParserCacheExpireTime ' .
'has been consistent.',
false, true );
@@ -77,8 +78,8 @@ class PurgeParserCache extends Maintenance {
$stars = floor( $percent / 2 );
$this->output( '[' . str_repeat( '*', $stars ) . str_repeat( '.', 50 - $stars ) . '] ' .
"$percentString%\r" );
-
}
}
+
$maintClass = 'PurgeParserCache';
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/reassignEdits.php b/maintenance/reassignEdits.php
index 7e15c09e..679cadb9 100644
--- a/maintenance/reassignEdits.php
+++ b/maintenance/reassignEdits.php
@@ -67,11 +67,11 @@ class ReassignEdits extends Maintenance {
/**
* Reassign edits from one user to another
*
- * @param $from User to take edits from
- * @param $to User to assign edits to
- * @param $rc bool Update the recent changes table
- * @param $report bool Don't change things; just echo numbers
- * @return integer Number of entries changed, or that would be changed
+ * @param User $from User to take edits from
+ * @param User $to User to assign edits to
+ * @param bool $rc Update the recent changes table
+ * @param bool $report Don't change things; just echo numbers
+ * @return int Number of entries changed, or that would be changed
*/
private function doReassignEdits( &$from, &$to, $rc = false, $report = false ) {
$dbw = wfGetDB( DB_MASTER );
@@ -79,13 +79,23 @@ class ReassignEdits extends Maintenance {
# Count things
$this->output( "Checking current edits..." );
- $res = $dbw->select( 'revision', 'COUNT(*) AS count', $this->userConditions( $from, 'rev_user', 'rev_user_text' ), __METHOD__ );
+ $res = $dbw->select(
+ 'revision',
+ 'COUNT(*) AS count',
+ $this->userConditions( $from, 'rev_user', 'rev_user_text' ),
+ __METHOD__
+ );
$row = $dbw->fetchObject( $res );
$cur = $row->count;
$this->output( "found {$cur}.\n" );
$this->output( "Checking deleted edits..." );
- $res = $dbw->select( 'archive', 'COUNT(*) AS count', $this->userConditions( $from, 'ar_user', 'ar_user_text' ), __METHOD__ );
+ $res = $dbw->select(
+ 'archive',
+ 'COUNT(*) AS count',
+ $this->userConditions( $from, 'ar_user', 'ar_user_text' ),
+ __METHOD__
+ );
$row = $dbw->fetchObject( $res );
$del = $row->count;
$this->output( "found {$del}.\n" );
@@ -93,7 +103,12 @@ class ReassignEdits extends Maintenance {
# Don't count recent changes if we're not supposed to
if ( $rc ) {
$this->output( "Checking recent changes..." );
- $res = $dbw->select( 'recentchanges', 'COUNT(*) AS count', $this->userConditions( $from, 'rc_user', 'rc_user_text' ), __METHOD__ );
+ $res = $dbw->select(
+ 'recentchanges',
+ 'COUNT(*) AS count',
+ $this->userConditions( $from, 'rc_user', 'rc_user_text' ),
+ __METHOD__
+ );
$row = $dbw->fetchObject( $res );
$rec = $row->count;
$this->output( "found {$rec}.\n" );
@@ -125,6 +140,7 @@ class ReassignEdits extends Maintenance {
}
$dbw->commit( __METHOD__ );
+
return (int)$total;
}
@@ -132,22 +148,24 @@ class ReassignEdits extends Maintenance {
* Return the most efficient set of user conditions
* i.e. a user => id mapping, or a user_text => text mapping
*
- * @param $user User for the condition
- * @param $idfield string Field name containing the identifier
- * @param $utfield string Field name containing the user text
+ * @param User $user User for the condition
+ * @param string $idfield Field name containing the identifier
+ * @param string $utfield Field name containing the user text
* @return array
*/
private function userConditions( &$user, $idfield, $utfield ) {
- return $user->getId() ? array( $idfield => $user->getId() ) : array( $utfield => $user->getName() );
+ return $user->getId()
+ ? array( $idfield => $user->getId() )
+ : array( $utfield => $user->getName() );
}
/**
* Return user specifications
* i.e. user => id, user_text => text
*
- * @param $user User for the spec
- * @param $idfield string Field name containing the identifier
- * @param $utfield string Field name containing the user text
+ * @param User $user User for the spec
+ * @param string $idfield Field name containing the identifier
+ * @param string $utfield Field name containing the user text
* @return array
*/
private function userSpecification( &$user, $idfield, $utfield ) {
@@ -157,7 +175,7 @@ class ReassignEdits extends Maintenance {
/**
* Initialise the user object
*
- * @param $username string Username or IP address
+ * @param string $username Username or IP address
* @return User
*/
private function initialiseUser( $username ) {
@@ -172,10 +190,9 @@ class ReassignEdits extends Maintenance {
}
}
$user->load();
+
return $user;
}
-
-
}
$maintClass = "ReassignEdits";
diff --git a/maintenance/rebuildFileCache.php b/maintenance/rebuildFileCache.php
index 12ed9fac..6ce54b9f 100644
--- a/maintenance/rebuildFileCache.php
+++ b/maintenance/rebuildFileCache.php
@@ -49,7 +49,7 @@ class RebuildFileCache extends Maintenance {
public function execute() {
global $wgUseFileCache, $wgReadOnly, $wgContentNamespaces, $wgRequestTime;
- global $wgTitle, $wgOut;
+ global $wgOut;
if ( !$wgUseFileCache ) {
$this->error( "Nothing to do -- \$wgUseFileCache is disabled.", true );
}
@@ -104,22 +104,22 @@ class RebuildFileCache extends Maintenance {
$rebuilt = false;
$wgRequestTime = microtime( true ); # bug 22852
- $wgTitle = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
- if ( null == $wgTitle ) {
+ $title = Title::makeTitleSafe( $row->page_namespace, $row->page_title );
+ if ( null == $title ) {
$this->output( "Page {$row->page_id} has bad title\n" );
continue; // broken title?
}
$context = new RequestContext;
- $context->setTitle( $wgTitle );
- $article = Article::newFromTitle( $wgTitle, $context );
+ $context->setTitle( $title );
+ $article = Article::newFromTitle( $title, $context );
$context->setWikiPage( $article->getPage() );
$wgOut = $context->getOutput(); // set display title
// If the article is cacheable, then load it
if ( $article->isFileCacheable() ) {
- $cache = HTMLFileCache::newFromTitle( $wgTitle, 'view' );
+ $cache = HTMLFileCache::newFromTitle( $title, 'view' );
if ( $cache->isCacheGood() ) {
if ( $overwrite ) {
$rebuilt = true;
@@ -151,11 +151,6 @@ class RebuildFileCache extends Maintenance {
$blockEnd += $this->mBatchSize;
}
$this->output( "Done!\n" );
-
- // Remove these to be safe
- if ( isset( $wgTitle ) ) {
- unset( $wgTitle );
- }
}
}
diff --git a/maintenance/rebuildImages.php b/maintenance/rebuildImages.php
index 53bf823f..5a149678 100644
--- a/maintenance/rebuildImages.php
+++ b/maintenance/rebuildImages.php
@@ -8,7 +8,7 @@
* add them only.
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -79,6 +79,7 @@ class ImageBuilder extends Maintenance {
if ( !isset( $this->repo ) ) {
$this->repo = RepoGroup::singleton()->getLocalRepo();
}
+
return $this->repo;
}
@@ -149,6 +150,7 @@ class ImageBuilder extends Maintenance {
// Create a File object from the row
// This will also upgrade it
$file = $this->getRepo()->newFileFromRow( $row );
+
return $file->getUpgraded();
}
@@ -161,9 +163,11 @@ class ImageBuilder extends Maintenance {
// This will also upgrade it
if ( $row->oi_archive_name == '' ) {
$this->output( "Empty oi_archive_name for oi_name={$row->oi_name}\n" );
+
return false;
}
$file = $this->getRepo()->newFileFromRow( $row );
+
return $file->getUpgraded();
}
@@ -201,14 +205,22 @@ class ImageBuilder extends Maintenance {
if ( $filename == '' ) {
$this->output( "Empty filename for $fullpath\n" );
+
return;
}
if ( !$this->dryrun ) {
$file = wfLocalFile( $filename );
- if ( !$file->recordUpload( '', '(recovered file, missing upload log entry)', '', '', '',
- false, $timestamp ) )
- {
+ if ( !$file->recordUpload(
+ '',
+ '(recovered file, missing upload log entry)',
+ '',
+ '',
+ '',
+ false,
+ $timestamp
+ ) ) {
$this->output( "Error uploading file $fullpath\n" );
+
return;
}
}
diff --git a/maintenance/rebuildLocalisationCache.php b/maintenance/rebuildLocalisationCache.php
index b7f306b1..b04639c0 100644
--- a/maintenance/rebuildLocalisationCache.php
+++ b/maintenance/rebuildLocalisationCache.php
@@ -52,6 +52,7 @@ class RebuildLocalisationCache extends Maintenance {
if ( $this->hasOption( 'memory-limit' ) ) {
return parent::memoryLimit();
}
+
return '1000M';
}
@@ -90,7 +91,7 @@ class RebuildLocalisationCache extends Maintenance {
if ( $this->hasOption( 'outdir' ) ) {
$conf['storeDirectory'] = $this->getOption( 'outdir' );
}
- $lc = new LocalisationCache_BulkLoad( $conf );
+ $lc = new LocalisationCacheBulkLoad( $conf );
$allCodes = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) );
if ( $this->hasOption( 'lang' ) ) {
@@ -148,9 +149,9 @@ class RebuildLocalisationCache extends Maintenance {
/**
* Helper function to rebuild list of languages codes. Prints the code
* for each language which is rebuilt.
- * @param $codes array List of language codes to rebuild.
- * @param $lc LocalisationCache Instance of LocalisationCache_BulkLoad (?)
- * @param $force bool Rebuild up-to-date languages
+ * @param array $codes List of language codes to rebuild.
+ * @param LocalisationCache $lc Instance of LocalisationCacheBulkLoad (?)
+ * @param bool $force Rebuild up-to-date languages
* @return int Number of rebuilt languages
*/
private function doRebuild( $codes, $lc, $force ) {
@@ -162,6 +163,7 @@ class RebuildLocalisationCache extends Maintenance {
$numRebuilt++;
}
}
+
return $numRebuilt;
}
diff --git a/maintenance/rebuildall.php b/maintenance/rebuildall.php
index 1268d209..eeee9c21 100644
--- a/maintenance/rebuildall.php
+++ b/maintenance/rebuildall.php
@@ -42,7 +42,8 @@ class RebuildAll extends Maintenance {
public function execute() {
// Rebuild the text index
if ( wfGetDB( DB_SLAVE )->getType() != 'postgres' ) {
- $this->output( "** Rebuilding fulltext search index (if you abort this will break searching; run this script again to fix):\n" );
+ $this->output( "** Rebuilding fulltext search index (if you abort "
+ . "this will break searching; run this script again to fix):\n" );
$rebuildText = $this->runChild( 'RebuildTextIndex', 'rebuildtextindex.php' );
$rebuildText->execute();
}
@@ -53,7 +54,8 @@ class RebuildAll extends Maintenance {
$rebuildRC->execute();
// Rebuild link tables
- $this->output( "\n\n** Rebuilding links tables -- this can take a long time. It should be safe to abort via ctrl+C if you get bored.\n" );
+ $this->output( "\n\n** Rebuilding links tables -- this can take a long time. "
+ . "It should be safe to abort via ctrl+C if you get bored.\n" );
$rebuildLinks = $this->runChild( 'RefreshLinks', 'refreshLinks.php' );
$rebuildLinks->execute();
diff --git a/maintenance/rebuildrecentchanges.php b/maintenance/rebuildrecentchanges.php
index 18348258..f4b0505e 100644
--- a/maintenance/rebuildrecentchanges.php
+++ b/maintenance/rebuildrecentchanges.php
@@ -69,25 +69,31 @@ class RebuildRecentchanges extends Maintenance {
$cutoff = time() - $wgRCMaxAge;
$dbw->insertSelect( 'recentchanges', array( 'page', 'revision' ),
array(
- 'rc_timestamp' => 'rev_timestamp',
- 'rc_cur_time' => 'rev_timestamp',
- 'rc_user' => 'rev_user',
- 'rc_user_text' => 'rev_user_text',
- 'rc_namespace' => 'page_namespace',
- 'rc_title' => 'page_title',
- 'rc_comment' => 'rev_comment',
- 'rc_minor' => 'rev_minor_edit',
- 'rc_bot' => 0,
- 'rc_new' => 'page_is_new',
- 'rc_cur_id' => 'page_id',
+ 'rc_timestamp' => 'rev_timestamp',
+ 'rc_user' => 'rev_user',
+ 'rc_user_text' => 'rev_user_text',
+ 'rc_namespace' => 'page_namespace',
+ 'rc_title' => 'page_title',
+ 'rc_comment' => 'rev_comment',
+ 'rc_minor' => 'rev_minor_edit',
+ 'rc_bot' => 0,
+ 'rc_new' => 'page_is_new',
+ 'rc_cur_id' => 'page_id',
'rc_this_oldid' => 'rev_id',
'rc_last_oldid' => 0, // is this ok?
- 'rc_type' => $dbw->conditional( 'page_is_new != 0', RC_NEW, RC_EDIT ),
- 'rc_deleted' => 'rev_deleted'
- ), array(
+ 'rc_type' => $dbw->conditional( 'page_is_new != 0', RC_NEW, RC_EDIT ),
+ 'rc_source' => $dbw->conditional(
+ 'page_is_new != 0',
+ $dbw->addQuotes( RecentChange::SRC_NEW ),
+ $dbw->addQuotes( RecentChange::SRC_EDIT )
+ ),
+ 'rc_deleted' => 'rev_deleted'
+ ),
+ array(
'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ),
'rev_page=page_id'
- ), __METHOD__,
+ ),
+ __METHOD__,
array(), // INSERT options
array( 'ORDER BY' => 'rev_timestamp DESC', 'LIMIT' => 5000 ) // SELECT options
);
@@ -144,6 +150,7 @@ class RebuildRecentchanges extends Maintenance {
'rc_last_oldid' => $lastOldId,
'rc_new' => $new,
'rc_type' => $new,
+ 'rc_source' => $new === 1 ? RecentChange::SRC_NEW : RecentChange::SRC_EDIT,
'rc_old_len' => $lastSize,
'rc_new_len' => $size,
), array(
@@ -172,42 +179,42 @@ class RebuildRecentchanges extends Maintenance {
// Some logs don't go in RC. This should check for that
$basicRCLogs = array_diff( $wgLogTypes, array_keys( $wgLogRestrictions ) );
- // Escape...blah blah
- $selectLogs = array();
- foreach ( $basicRCLogs as $logtype ) {
- $safetype = $dbw->strencode( $logtype );
- $selectLogs[] = "'$safetype'";
- }
-
$cutoff = time() - $wgRCMaxAge;
list( $logging, $page ) = $dbw->tableNamesN( 'logging', 'page' );
- $dbw->insertSelect( 'recentchanges', array( 'user', "$logging LEFT JOIN $page ON (log_namespace=page_namespace AND log_title=page_title)" ),
+ $dbw->insertSelect(
+ 'recentchanges',
array(
- 'rc_timestamp' => 'log_timestamp',
- 'rc_cur_time' => 'log_timestamp',
- 'rc_user' => 'log_user',
- 'rc_user_text' => 'user_name',
- 'rc_namespace' => 'log_namespace',
- 'rc_title' => 'log_title',
- 'rc_comment' => 'log_comment',
- 'rc_minor' => 0,
- 'rc_bot' => 0,
- 'rc_patrolled' => 1,
- 'rc_new' => 0,
+ 'user',
+ "$logging LEFT JOIN $page ON (log_namespace=page_namespace AND log_title=page_title)"
+ ),
+ array(
+ 'rc_timestamp' => 'log_timestamp',
+ 'rc_user' => 'log_user',
+ 'rc_user_text' => 'user_name',
+ 'rc_namespace' => 'log_namespace',
+ 'rc_title' => 'log_title',
+ 'rc_comment' => 'log_comment',
+ 'rc_minor' => 0,
+ 'rc_bot' => 0,
+ 'rc_patrolled' => 1,
+ 'rc_new' => 0,
'rc_this_oldid' => 0,
'rc_last_oldid' => 0,
- 'rc_type' => RC_LOG,
- 'rc_cur_id' => $dbw->cascadingDeletes() ? 'page_id' : 'COALESCE(page_id, 0)',
- 'rc_log_type' => 'log_type',
+ 'rc_type' => RC_LOG,
+ 'rc_source' => $dbw->addQuotes( RecentChange::SRC_LOG ),
+ 'rc_cur_id' => $dbw->cascadingDeletes() ? 'page_id' : 'COALESCE(page_id, 0)',
+ 'rc_log_type' => 'log_type',
'rc_log_action' => 'log_action',
- 'rc_logid' => 'log_id',
- 'rc_params' => 'log_params',
- 'rc_deleted' => 'log_deleted'
- ), array(
+ 'rc_logid' => 'log_id',
+ 'rc_params' => 'log_params',
+ 'rc_deleted' => 'log_deleted'
+ ),
+ array(
'log_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) ),
'log_user=user_id',
- 'log_type IN(' . implode( ',', $selectLogs ) . ')'
- ), __METHOD__,
+ 'log_type' => $basicRCLogs,
+ ),
+ __METHOD__,
array(), // INSERT options
array( 'ORDER BY' => 'log_timestamp DESC', 'LIMIT' => 5000 ) // SELECT options
);
@@ -222,7 +229,8 @@ class RebuildRecentchanges extends Maintenance {
$dbw = wfGetDB( DB_MASTER );
- list( $recentchanges, $usergroups, $user ) = $dbw->tableNamesN( 'recentchanges', 'user_groups', 'user' );
+ list( $recentchanges, $usergroups, $user ) =
+ $dbw->tableNamesN( 'recentchanges', 'user_groups', 'user' );
$botgroups = User::getGroupsWithPermission( 'bot' );
$autopatrolgroups = $wgUseRCPatrol ? User::getGroupsWithPermission( 'autopatrol' ) : array();
@@ -288,7 +296,6 @@ class RebuildRecentchanges extends Maintenance {
$messageMemc->delete( wfMemcKey( 'rcfeed', $feed, 'timestamp' ) ); # Good enough for now.
}
}
-
}
$maintClass = "RebuildRecentchanges";
diff --git a/maintenance/rebuildtextindex.php b/maintenance/rebuildtextindex.php
index c651f720..bc85c666 100644
--- a/maintenance/rebuildtextindex.php
+++ b/maintenance/rebuildtextindex.php
@@ -50,8 +50,6 @@ class RebuildTextIndex extends Maintenance {
}
public function execute() {
- global $wgTitle;
-
// Shouldn't be needed for Postgres
$this->db = wfGetDB( DB_MASTER );
if ( $this->db->getType() == 'postgres' ) {
@@ -61,15 +59,15 @@ class RebuildTextIndex extends Maintenance {
$this->db = wfGetDB( DB_MASTER );
if ( $this->db->getType() == 'sqlite' ) {
if ( !DatabaseSqlite::getFulltextSearchModule() ) {
- $this->error( "Your version of SQLite module for PHP doesn't support full-text search (FTS3).\n", true );
+ $this->error( "Your version of SQLite module for PHP doesn't "
+ . "support full-text search (FTS3).\n", true );
}
if ( !$this->db->checkForEnabledSearch() ) {
- $this->error( "Your database schema is not configured for full-text search support. Run update.php.\n", true );
+ $this->error( "Your database schema is not configured for "
+ . "full-text search support. Run update.php.\n", true );
}
}
- $wgTitle = Title::newFromText( "Rebuild text index script" );
-
if ( $this->db->getType() == 'mysql' ) {
$this->dropMysqlTextIndex();
$this->populateSearchIndex();
diff --git a/maintenance/refreshImageMetadata.php b/maintenance/refreshImageMetadata.php
index 7fe5c4c1..831118ca 100644
--- a/maintenance/refreshImageMetadata.php
+++ b/maintenance/refreshImageMetadata.php
@@ -5,7 +5,7 @@
* Usage: php refreshImageMetadata.php
*
* Copyright © 2011 Brian Wolff
- * http://www.mediawiki.org/
+ * https://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
@@ -47,15 +47,41 @@ class RefreshImageMetadata extends Maintenance {
$this->mDescription = 'Script to update image metadata records';
$this->setBatchSize( 200 );
- $this->addOption( 'force', 'Reload metadata from file even if the metadata looks ok', false, false, 'f' );
- $this->addOption( 'broken-only', 'Only fix really broken records, leave old but still compatible records alone.' );
- $this->addOption( 'verbose', 'Output extra information about each upgraded/non-upgraded file.', false, false, 'v' );
+ $this->addOption(
+ 'force',
+ 'Reload metadata from file even if the metadata looks ok',
+ false,
+ false,
+ 'f'
+ );
+ $this->addOption(
+ 'broken-only',
+ 'Only fix really broken records, leave old but still compatible records alone.'
+ );
+ $this->addOption(
+ 'verbose',
+ 'Output extra information about each upgraded/non-upgraded file.',
+ false,
+ false,
+ 'v'
+ );
$this->addOption( 'start', 'Name of file to start with', false, true );
$this->addOption( 'end', 'Name of file to end with', false, true );
- $this->addOption( 'mime', '(Inefficient!) Only refresh files with this mime type. Can accept wild-card image/*', false, true );
- $this->addOption( 'metadata-contains', '(Inefficient!) Only refresh files where the img_metadata field contains this string. Can be used if its known a specific property was being extracted incorrectly.', false, true );
-
+ $this->addOption(
+ 'mime',
+ '(Inefficient!) Only refresh files with this MIME type. Can accept wild-card image/*',
+ false,
+ true
+ );
+ $this->addOption(
+ 'metadata-contains',
+ '(Inefficient!) Only refresh files where the img_metadata field '
+ . 'contains this string. Can be used if its known a specific '
+ . 'property was being extracted incorrectly.',
+ false,
+ true
+ );
}
public function execute() {
@@ -121,7 +147,7 @@ class RefreshImageMetadata extends Maintenance {
// to weed out any inconsequential changes.
$error++;
$this->output( "Warning: File:{$row->img_name} used to have " .
- "$oldLength bytes of metadata but now has $newLength bytes.\n" );
+ "$oldLength bytes of metadata but now has $newLength bytes.\n" );
} elseif ( $verbose ) {
$this->output( "Refreshed File:{$row->img_name}.\n" );
}
@@ -134,20 +160,17 @@ class RefreshImageMetadata extends Maintenance {
if ( $newLength < $oldLength - 5 ) {
$error++;
$this->output( "Warning: File:{$row->img_name} used to have " .
- "$oldLength bytes of metadata but now has $newLength bytes. (forced)\n" );
-
+ "$oldLength bytes of metadata but now has $newLength bytes. (forced)\n" );
}
if ( $verbose ) {
$this->output( "Forcibly refreshed File:{$row->img_name}.\n" );
}
- }
- else {
+ } else {
if ( $verbose ) {
$this->output( "Skipping File:{$row->img_name}.\n" );
}
}
}
-
}
$conds2 = array( 'img_name > ' . $dbw->addQuotes( $row->img_name ) );
wfWaitForSlaves();
@@ -155,14 +178,18 @@ class RefreshImageMetadata extends Maintenance {
$total = $upgraded + $leftAlone;
if ( $force ) {
- $this->output( "\nFinished refreshing file metadata for $total files. $upgraded needed to be refreshed, $leftAlone did not need to be but were refreshed anyways, and $error refreshes were suspicious.\n" );
+ $this->output( "\nFinished refreshing file metadata for $total files. "
+ . "$upgraded needed to be refreshed, $leftAlone did not need to "
+ . "be but were refreshed anyways, and $error refreshes were suspicious.\n" );
} else {
- $this->output( "\nFinished refreshing file metadata for $total files. $upgraded were refreshed, $leftAlone were already up to date, and $error refreshes were suspicious.\n" );
+ $this->output( "\nFinished refreshing file metadata for $total files. "
+ . "$upgraded were refreshed, $leftAlone were already up to date, "
+ . "and $error refreshes were suspicious.\n" );
}
}
/**
- * @param $dbw DatabaseBase
+ * @param DatabaseBase $dbw
* @return array
*/
function getConditions( $dbw ) {
@@ -185,12 +212,13 @@ class RefreshImageMetadata extends Maintenance {
if ( $like ) {
$conds[] = 'img_metadata ' . $dbw->buildLike( $dbw->anyString(), $like, $dbw->anyString() );
}
+
return $conds;
}
/**
- * @param $force bool
- * @param $brokenOnly bool
+ * @param bool $force
+ * @param bool $brokenOnly
*/
function setupParameters( $force, $brokenOnly ) {
global $wgUpdateCompatibleMetadata;
@@ -207,6 +235,5 @@ class RefreshImageMetadata extends Maintenance {
}
}
-
$maintClass = 'RefreshImageMetadata';
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/refreshLinks.php b/maintenance/refreshLinks.php
index 98ea9301..0c2f722c 100644
--- a/maintenance/refreshLinks.php
+++ b/maintenance/refreshLinks.php
@@ -57,15 +57,16 @@ class RefreshLinks extends Maintenance {
/**
* Do the actual link refreshing.
- * @param $start int Page_id to start from
- * @param $newOnly bool Only do pages with 1 edit
- * @param $maxLag int Max DB replication lag
- * @param $end int Page_id to stop at
- * @param $redirectsOnly bool Only fix redirects
- * @param $oldRedirectsOnly bool Only fix redirects without redirect entries
+ * @param int $start Page_id to start from
+ * @param bool $newOnly Only do pages with 1 edit
+ * @param int $maxLag Max DB replication lag
+ * @param int $end Page_id to stop at
+ * @param bool $redirectsOnly Only fix redirects
+ * @param bool $oldRedirectsOnly Only fix redirects without redirect entries
*/
private function doRefreshLinks( $start, $newOnly = false, $maxLag = false,
- $end = 0, $redirectsOnly = false, $oldRedirectsOnly = false ) {
+ $end = 0, $redirectsOnly = false, $oldRedirectsOnly = false
+ ) {
global $wgParser, $wgUseTidy;
$reportingInterval = 100;
@@ -185,7 +186,7 @@ class RefreshLinks extends Maintenance {
* entry in the "redirect" table points to the correct page and not to an
* invalid one.
*
- * @param $id int The page ID to check
+ * @param int $id The page ID to check
*/
private function fixRedirect( $id ) {
$page = WikiPage::newFromID( $id );
@@ -196,6 +197,7 @@ class RefreshLinks extends Maintenance {
// Delete any redirect table entry for it
$dbw->delete( 'redirect', array( 'rd_from' => $id ),
__METHOD__ );
+
return;
}
@@ -222,7 +224,7 @@ class RefreshLinks extends Maintenance {
/**
* Run LinksUpdate for all links on a given page_id
- * @param $id int The page_id
+ * @param int $id The page_id
*/
public static function fixLinksFromArticle( $id ) {
$page = WikiPage::newFromID( $id );
@@ -251,8 +253,8 @@ class RefreshLinks extends Maintenance {
* Removes non-existing links from pages from pagelinks, imagelinks,
* categorylinks, templatelinks, externallinks, interwikilinks, langlinks and redirect tables.
*
- * @param $maxLag int
- * @param $batchSize int The size of deletion batches
+ * @param int $maxLag
+ * @param int $batchSize The size of deletion batches
*
* @author Merlijn van Deen <valhallasw@arctus.nl>
*/
diff --git a/maintenance/removeUnusedAccounts.php b/maintenance/removeUnusedAccounts.php
index 16cb17ab..90dc6220 100644
--- a/maintenance/removeUnusedAccounts.php
+++ b/maintenance/removeUnusedAccounts.php
@@ -58,12 +58,13 @@ class RemoveUnusedAccounts extends Maintenance {
}
$touchedSeconds = 86400 * $touched;
foreach ( $res as $row ) {
- # Check the account, but ignore it if it's within a $excludedGroups group or if it's touched within the $touchedSeconds seconds.
+ # Check the account, but ignore it if it's within a $excludedGroups
+ # group or if it's touched within the $touchedSeconds seconds.
$instance = User::newFromId( $row->user_id );
if ( count( array_intersect( $instance->getEffectiveGroups(), $excludedGroups ) ) == 0
&& $this->isInactiveAccount( $row->user_id, true )
&& wfTimestamp( TS_UNIX, $row->user_touched ) < wfTimestamp( TS_UNIX, time() - $touchedSeconds )
- ) {
+ ) {
# Inactive; print out the name and flag it
$del[] = $row->user_id;
$this->output( $row->user_name . "\n" );
@@ -85,7 +86,12 @@ class RemoveUnusedAccounts extends Maintenance {
$this->output( "done.\n" );
# Update the site_stats.ss_users field
$users = $dbw->selectField( 'user', 'COUNT(*)', array(), __METHOD__ );
- $dbw->update( 'site_stats', array( 'ss_users' => $users ), array( 'ss_row_id' => 1 ), __METHOD__ );
+ $dbw->update(
+ 'site_stats',
+ array( 'ss_users' => $users ),
+ array( 'ss_row_id' => 1 ),
+ __METHOD__
+ );
} elseif ( $count > 0 ) {
$this->output( "\nRun the script again with --delete to remove them from the database.\n" );
}
@@ -96,8 +102,8 @@ class RemoveUnusedAccounts extends Maintenance {
* Could the specified user account be deemed inactive?
* (No edits, no deleted edits, no log entries, no current/old uploads)
*
- * @param $id User's ID
- * @param $master bool Perform checking on the master
+ * @param int $id User's ID
+ * @param bool $master Perform checking on the master
* @return bool
*/
private function isInactiveAccount( $id, $master = false ) {
diff --git a/maintenance/renderDump.php b/maintenance/renderDump.php
index 0cde28c5..169f512c 100644
--- a/maintenance/renderDump.php
+++ b/maintenance/renderDump.php
@@ -7,7 +7,7 @@
* Templates etc are pulled from the local wiki database, not from the dump.
*
* Copyright (C) 2006 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -78,12 +78,13 @@ class DumpRenderer extends Maintenance {
/**
* Callback function for each revision, turn into HTML and save
- * @param $rev Revision
+ * @param Revision $rev
*/
public function handleRevision( $rev ) {
$title = $rev->getTitle();
if ( !$title ) {
$this->error( "Got bogus revision with null title!" );
+
return;
}
$display = $title->getPrefixedText();
diff --git a/maintenance/resetUserTokens.php b/maintenance/resetUserTokens.php
index bfe04d79..08be5537 100644
--- a/maintenance/resetUserTokens.php
+++ b/maintenance/resetUserTokens.php
@@ -34,9 +34,15 @@ require_once __DIR__ . '/Maintenance.php';
class ResetUserTokens extends Maintenance {
public function __construct() {
parent::__construct();
- $this->mDescription = "Reset the user_token of all users on the wiki. Note that this may log some of them out.";
+ $this->mDescription =
+ "Reset the user_token of all users on the wiki. Note that this may log some of them out.";
$this->addOption( 'nowarn', "Hides the 5 seconds warning", false, false );
- $this->addOption( 'nulls', 'Only reset tokens that are currently null (string of \x00\'s)', false, false );
+ $this->addOption(
+ 'nulls',
+ 'Only reset tokens that are currently null (string of \x00\'s)',
+ false,
+ false
+ );
$this->setBatchSize( 1000 );
}
@@ -45,14 +51,16 @@ class ResetUserTokens extends Maintenance {
if ( !$this->getOption( 'nowarn' ) ) {
if ( $this->nullsOnly ) {
- $this->output( "The script is about to reset the user_token for USERS WITH NULL TOKENS in the database.\n" );
+ $this->output( "The script is about to reset the user_token "
+ . "for USERS WITH NULL TOKENS in the database.\n" );
} else {
$this->output( "The script is about to reset the user_token for ALL USERS in the database.\n" );
$this->output( "This may log some of them out and is not necessary unless you believe your\n" );
$this->output( "user table has been compromised.\n" );
}
$this->output( "\n" );
- $this->output( "Abort with control-c in the next five seconds (skip this countdown with --nowarn) ... " );
+ $this->output( "Abort with control-c in the next five seconds "
+ . "(skip this countdown with --nowarn) ... " );
wfCountDown( 5 );
}
@@ -62,7 +70,7 @@ class ResetUserTokens extends Maintenance {
$where = array();
if ( $this->nullsOnly ) {
// Have to build this by hand, because \ is escaped in helper functions
- $where = array( 'user_token = \'' . str_repeat( '\0', 32) . '\'' );
+ $where = array( 'user_token = \'' . str_repeat( '\0', 32 ) . '\'' );
}
$maxid = $dbr->selectField( 'user', 'MAX(user_id)', array(), __METHOD__ );
@@ -90,9 +98,7 @@ class ResetUserTokens extends Maintenance {
$max = $min + $this->mBatchSize;
wfWaitForSlaves();
-
- } while ( $max <= $maxid );
-
+ } while ( $min <= $maxid );
}
private function updateUser( $userid ) {
diff --git a/maintenance/resources/update-oojs-ui.sh b/maintenance/resources/update-oojs-ui.sh
new file mode 100644
index 00000000..1b352922
--- /dev/null
+++ b/maintenance/resources/update-oojs-ui.sh
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+
+# This script generates a commit that updates our distribution copy of OOjs UI
+
+if [ -z "$1" ]
+then
+ # Missing required parameter
+ echo >&2 "Usage: $0 path/to/repo/for/oojs-ui"
+ exit 1
+fi
+
+TARGET_REPO=$(cd "$(dirname $0)/../.."; pwd)
+TARGET_DIR=resources/lib/oojs-ui
+UI_REPO=$1
+
+function oojsuihash() {
+ grep "OOjs UI v" "$TARGET_REPO/$TARGET_DIR/oojs-ui.js" \
+ | head -n 1 \
+ | grep -Eo '\([a-z0-9]+\)' \
+ | sed 's/^(//' \
+ | sed 's/)$//'
+}
+
+function oojsuitag() {
+ grep "OOjs UI v" "$TARGET_REPO/$TARGET_DIR/oojs-ui.js" \
+ | head -n 1 \
+ | grep -Eo '\bv[0-9a-z.-]+\b'
+}
+
+function oojsuiversion() {
+ grep "OOjs UI v" "$TARGET_REPO/$TARGET_DIR/oojs-ui.js" \
+ | head -n 1 \
+ | grep -Eo '\bv[0-9a-z.-]+\b.*$'
+}
+
+# Prepare working tree
+cd "$TARGET_REPO" &&
+git reset $TARGET_DIR && git checkout $TARGET_DIR && git fetch origin &&
+git checkout -B upstream-oojsui origin/master || exit 1
+
+cd $UI_REPO || exit 1
+
+# Read the old version and check for changes
+OLDHASH=$(oojsuihash)
+if [ -z "$OLDHASH" ]
+then
+ OLDTAG=$(oojsuitag)
+fi
+if [ "$OLDHASH" == "" ]
+then
+ OLDHASH=$(git rev-parse "$OLDTAG")
+ if [ $? != 0 ]
+ then
+ echo "Could not find OOjs UI version"
+ cd -
+ exit 1
+ fi
+fi
+if [ "$(git rev-parse $OLDHASH)" == "$(git rev-parse HEAD)" ]
+then
+ echo "No changes (already at $OLDHASH)"
+ cd -
+ exit 0
+fi
+
+# Build the distribution
+npm install && grunt git-build || exit 1
+
+# Get the list of changes
+NEWCHANGES=$(git log $OLDHASH.. --oneline --no-merges --reverse --color=never)
+NEWCHANGESDISPLAY=$(git log $OLDHASH.. --oneline --no-merges --reverse --color=always)
+
+# Copy files
+# - Exclude the default non-svg stylesheet
+rsync --recursive --delete --force --exclude 'oojs-ui.css' --exclude 'oojs-ui*.rtl.css' ./dist/ "$TARGET_REPO/$TARGET_DIR" || exit 1
+
+# Read the new version
+NEWVERSION=$(oojsuiversion)
+
+# Generate commit
+cd "$TARGET_REPO"
+COMMITMSG=$(cat <<END
+Update OOjs UI to $NEWVERSION
+
+New changes:
+$NEWCHANGES
+END
+)
+git add -u $TARGET_DIR && git add $TARGET_DIR && git commit -m "$COMMITMSG"
+cat >&2 <<END
+
+
+Created commit with changes:
+$NEWCHANGESDISPLAY
+END
diff --git a/maintenance/resources/update-oojs.sh b/maintenance/resources/update-oojs.sh
new file mode 100644
index 00000000..d9e6fb9d
--- /dev/null
+++ b/maintenance/resources/update-oojs.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+
+if [ -n "$2" ]
+then
+ # Too many parameters
+ echo >&2 "Usage: $0 [<version>]"
+ exit 1
+fi
+
+REPO_DIR=$(cd "$(dirname $0)/../.."; pwd) # Root dir of the git repo working tree
+TARGET_DIR="resources/lib/oojs" # Destination relative to the root of the repo
+NPM_DIR=$(mktemp -d 2>/dev/null || mktemp -d -t 'update-oojs') # e.g. /tmp/update-oojs.rI0I5Vir
+
+# Prepare working tree
+cd "$REPO_DIR" &&
+git reset $TARGET_DIR && git checkout $TARGET_DIR && git fetch origin &&
+git checkout -B upstream-oojs origin/master || exit 1
+
+# Fetch upstream version
+cd $NPM_DIR
+if [ -n "$1" ]
+then
+ npm install "oojs@$1" || exit 1
+else
+ npm install oojs || exit 1
+fi
+
+OOJS_VERSION=$(node -e 'console.log(JSON.parse(require("fs").readFileSync("./node_modules/oojs/package.json")).version);')
+if [ "$OOJS_VERSION" == "" ]
+then
+ echo 'Could not find OOjs version'
+ exit 1
+fi
+
+# Copy file(s)
+rsync --force ./node_modules/oojs/dist/oojs.jquery.js "$REPO_DIR/$TARGET_DIR" || exit 1
+
+# Clean up temporary area
+rm -rf "$NPM_DIR"
+
+# Generate commit
+cd $REPO_DIR || exit 1
+
+COMMITMSG=$(cat <<END
+Update OOjs to v$OOJS_VERSION
+
+Release notes:
+ https://git.wikimedia.org/blob/oojs%2Fcore.git/v$OOJS_VERSION/History.md
+END
+)
+
+# Stage deletion, modification and creation of files. Then commit.
+git add --update $TARGET_DIR && git add $TARGET_DIR && git commit -m "$COMMITMSG" || exit 1
diff --git a/maintenance/rollbackEdits.php b/maintenance/rollbackEdits.php
index e5e33c02..967dda85 100644
--- a/maintenance/rollbackEdits.php
+++ b/maintenance/rollbackEdits.php
@@ -33,8 +33,14 @@ require_once __DIR__ . '/Maintenance.php';
class RollbackEdits extends Maintenance {
public function __construct() {
parent::__construct();
- $this->mDescription = "Rollback all edits by a given user or IP provided they're the most recent edit";
- $this->addOption( 'titles', 'A list of titles, none means all titles where the given user is the most recent', false, true );
+ $this->mDescription =
+ "Rollback all edits by a given user or IP provided they're the most recent edit";
+ $this->addOption(
+ 'titles',
+ 'A list of titles, none means all titles where the given user is the most recent',
+ false,
+ true
+ );
$this->addOption( 'user', 'A user or IP to rollback all edits for', true, true );
$this->addOption( 'summary', 'Edit summary to use', false, true );
$this->addOption( 'bot', 'Mark the edits as bot' );
@@ -66,6 +72,7 @@ class RollbackEdits extends Maintenance {
if ( !$titles ) {
$this->output( 'No suitable titles to be rolled back' );
+
return;
}
@@ -84,7 +91,7 @@ class RollbackEdits extends Maintenance {
/**
* Get all pages that should be rolled back for a given user
- * @param $user String a name to check against rev_user_text
+ * @param string $user A name to check against rev_user_text
* @return array
*/
private function getRollbackTitles( $user ) {
@@ -99,6 +106,7 @@ class RollbackEdits extends Maintenance {
foreach ( $results as $row ) {
$titles[] = Title::makeTitle( $row->page_namespace, $row->page_title );
}
+
return $titles;
}
}
diff --git a/maintenance/runBatchedQuery.php b/maintenance/runBatchedQuery.php
index 93ba24a9..af889050 100644
--- a/maintenance/runBatchedQuery.php
+++ b/maintenance/runBatchedQuery.php
@@ -33,7 +33,8 @@ require_once __DIR__ . '/Maintenance.php';
class BatchedQueryRunner extends Maintenance {
public function __construct() {
parent::__construct();
- $this->mDescription = "Run a query repeatedly until it affects 0 rows, and wait for slaves in between.\n" .
+ $this->mDescription =
+ "Run a query repeatedly until it affects 0 rows, and wait for slaves in between.\n" .
"NOTE: You need to set a LIMIT clause yourself.";
}
@@ -60,6 +61,5 @@ class BatchedQueryRunner extends Maintenance {
}
}
-
$maintClass = "BatchedQueryRunner";
require_once RUN_MAINTENANCE_IF_MAIN;
diff --git a/maintenance/runJobs.php b/maintenance/runJobs.php
index 429edf42..40605ceb 100644
--- a/maintenance/runJobs.php
+++ b/maintenance/runJobs.php
@@ -2,10 +2,6 @@
/**
* Run pending jobs.
*
- * Options:
- * --maxjobs <num> (default 10000)
- * --type <job_cmd>
- *
* 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
@@ -40,19 +36,20 @@ class RunJobs extends Maintenance {
$this->addOption( 'maxtime', 'Maximum amount of wall-clock time', false, true );
$this->addOption( 'type', 'Type of job to run', false, true );
$this->addOption( 'procs', 'Number of processes to use', false, true );
+ $this->addOption( 'nothrottle', 'Ignore job throttling configuration', false, false );
+ $this->addOption( 'result', 'Set to JSON to print only a JSON response', false, true );
}
public function memoryLimit() {
if ( $this->hasOption( 'memory-limit' ) ) {
return parent::memoryLimit();
}
+
// Don't eat all memory on the machine if we get a bad job.
return "150M";
}
public function execute() {
- global $wgTitle;
-
if ( wfReadOnly() ) {
$this->error( "Unable to run jobs; the wiki is in read-only mode.", 1 ); // die
}
@@ -68,112 +65,29 @@ class RunJobs extends Maintenance {
}
}
}
- $maxJobs = $this->getOption( 'maxjobs', false );
- $maxTime = $this->getOption( 'maxtime', false );
- $startTime = time();
- $type = $this->getOption( 'type', false );
- $wgTitle = Title::newFromText( 'RunJobs.php' );
- $jobsRun = 0; // counter
-
- $group = JobQueueGroup::singleton();
- // Handle any required periodic queue maintenance
- $count = $group->executeReadyPeriodicTasks();
- if ( $count > 0 ) {
- $this->runJobsLog( "Executed $count periodic queue task(s)." );
- }
-
- $flags = JobQueueGroup::USE_CACHE | JobQueueGroup::USE_PRIORITY;
- $lastTime = time(); // time since last slave check
- do {
- $job = ( $type === false )
- ? $group->pop( JobQueueGroup::TYPE_DEFAULT, $flags )
- : $group->pop( $type ); // job from a single queue
- if ( $job ) { // found a job
- ++$jobsRun;
- $this->runJobsLog( $job->toString() . " STARTING" );
-
- // Set timer to stop the job if too much CPU time is used
- set_time_limit( $maxTime ?: 0 );
- // Run the job...
- wfProfileIn( __METHOD__ . '-' . get_class( $job ) );
- $t = microtime( true );
- try {
- $status = $job->run();
- $error = $job->getLastError();
- } catch ( MWException $e ) {
- $status = false;
- $error = get_class( $e ) . ': ' . $e->getMessage();
- $e->report(); // write error to STDERR and the log
- }
- $timeMs = intval( ( microtime( true ) - $t ) * 1000 );
- wfProfileOut( __METHOD__ . '-' . get_class( $job ) );
- // Disable the timer
- set_time_limit( 0 );
-
- // Mark the job as done on success or when the job cannot be retried
- if ( $status !== false || !$job->allowRetries() ) {
- $group->ack( $job ); // done
- }
-
- if ( $status === false ) {
- $this->runJobsLog( $job->toString() . " t=$timeMs error={$error}" );
- } else {
- $this->runJobsLog( $job->toString() . " t=$timeMs good" );
- }
-
- // Break out if we hit the job count or wall time limits...
- if ( $maxJobs && $jobsRun >= $maxJobs ) {
- break;
- } elseif ( $maxTime && ( time() - $startTime ) > $maxTime ) {
- break;
- }
- // Don't let any of the main DB slaves get backed up
- $timePassed = time() - $lastTime;
- if ( $timePassed >= 5 || $timePassed < 0 ) {
- wfWaitForSlaves();
- $lastTime = time();
- }
- // Don't let any queue slaves/backups fall behind
- if ( $jobsRun > 0 && ( $jobsRun % 100 ) == 0 ) {
- $group->waitForBackups();
- }
+ $json = ( $this->getOption( 'result' ) === 'json' );
- // Bail if near-OOM instead of in a job
- $this->assertMemoryOK();
- }
- } while ( $job ); // stop when there are no jobs
- }
-
- /**
- * Make sure that this script is not too close to the memory usage limit
- * @throws MWException
- */
- private function assertMemoryOK() {
- static $maxBytes = null;
- if ( $maxBytes === null ) {
- $m = array();
- if ( preg_match( '!^(\d+)(k|m|g|)$!i', ini_get( 'memory_limit' ), $m ) ) {
- list( , $num, $unit ) = $m;
- $conv = array( 'g' => 1024 * 1024 * 1024, 'm' => 1024 * 1024, 'k' => 1024, '' => 1 );
- $maxBytes = $num * $conv[strtolower( $unit )];
- } else {
- $maxBytes = 0;
- }
+ $runner = new JobRunner();
+ if ( !$json ) {
+ $runner->setDebugHandler( array( $this, 'debugInternal' ) );
}
- $usedBytes = memory_get_usage();
- if ( $maxBytes && $usedBytes >= 0.95 * $maxBytes ) {
- throw new MWException( "Detected excessive memory usage ($usedBytes/$maxBytes)." );
+ $response = $runner->run( array(
+ 'type' => $this->getOption( 'type', false ),
+ 'maxJobs' => $this->getOption( 'maxjobs', false ),
+ 'maxTime' => $this->getOption( 'maxtime', false ),
+ 'throttle' => $this->hasOption( 'nothrottle' ) ? false : true,
+ ) );
+ if ( $json ) {
+ $this->output( FormatJson::encode( $response, true ) );
}
}
/**
- * Log the job message
- * @param $msg String The message to log
+ * @param string $s
*/
- private function runJobsLog( $msg ) {
- $this->output( wfTimestamp( TS_DB ) . " $msg\n" );
- wfDebugLog( 'runJobs', $msg );
+ public function debugInternal( $s ) {
+ $this->output( $s );
}
}
diff --git a/maintenance/runScript.php b/maintenance/runScript.php
new file mode 100644
index 00000000..385db157
--- /dev/null
+++ b/maintenance/runScript.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Convenience maintenance script wrapper, useful for scripts
+ * or extensions located outside of standard locations.
+ *
+ * To use, give the maintenance script as a relative or full path.
+ *
+ * Example usage:
+ *
+ * If your pwd is mediawiki base folder:
+ * php maintenance/runScript.php extensions/Wikibase/lib/maintenance/dispatchChanges.php
+ *
+ * If your pwd is maintenance folder:
+ * php runScript.php ../extensions/Wikibase/lib/maintenance/dispatchChanges.php
+ *
+ * Or full path:
+ * php /var/www/mediawiki/maintenance/runScript.php maintenance/runJobs.php
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (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
+ *
+ * @author Katie Filbert < aude.wiki@gmail.com >
+ * @file
+ * @ingroup Maintenance
+ */
+$IP = getenv( 'MW_INSTALL_PATH' );
+
+if ( $IP === false ) {
+ $IP = dirname( __DIR__ );
+
+ putenv( "MW_INSTALL_PATH=$IP" );
+}
+
+require_once "$IP/maintenance/Maintenance.php";
+
+if ( !isset( $argv[1] ) ) {
+ fwrite( STDERR, "This script requires a maintainance script as an argument.\n"
+ . "Usage: runScript.php extensions/Wikibase/lib/maintenance/dispatchChanges\n" );
+ exit( 1 );
+}
+
+$scriptFilename = $argv[1];
+array_shift( $argv );
+
+$scriptFile = realpath( $scriptFilename );
+
+if ( !$scriptFile ) {
+ fwrite( STDERR, "The MediaWiki script file \"{$scriptFilename}\" does not exist.\n" );
+ exit( 1 );
+}
+
+require_once $scriptFile;
diff --git a/maintenance/showCacheStats.php b/maintenance/showCacheStats.php
index cd9768d4..3d16af14 100644
--- a/maintenance/showCacheStats.php
+++ b/maintenance/showCacheStats.php
@@ -46,17 +46,6 @@ class ShowCacheStats extends Maintenance {
if ( get_class( $wgMemc ) == 'EmptyBagOStuff' ) {
$this->error( "You are running EmptyBagOStuff, I can not provide any statistics.", true );
}
- $session = intval( $wgMemc->get( wfMemcKey( 'stats', 'request_with_session' ) ) );
- $noSession = intval( $wgMemc->get( wfMemcKey( 'stats', 'request_without_session' ) ) );
- $total = $session + $noSession;
- if ( $total == 0 ) {
- $this->error( "You either have no stats or the cache isn't running. Aborting.", true );
- }
- $this->output( "Requests\n" );
- $this->output( sprintf( "with session: %-10d %6.2f%%\n", $session, $session / $total * 100 ) );
- $this->output( sprintf( "without session: %-10d %6.2f%%\n", $noSession, $noSession / $total * 100 ) );
- $this->output( sprintf( "total: %-10d %6.2f%%\n", $total, 100 ) );
-
$this->output( "\nParser cache\n" );
$hits = intval( $wgMemc->get( wfMemcKey( 'stats', 'pcache_hit' ) ) );
@@ -66,8 +55,16 @@ class ShowCacheStats extends Maintenance {
$total = $hits + $expired + $absent + $stub;
if ( $total ) {
$this->output( sprintf( "hits: %-10d %6.2f%%\n", $hits, $hits / $total * 100 ) );
- $this->output( sprintf( "expired: %-10d %6.2f%%\n", $expired, $expired / $total * 100 ) );
- $this->output( sprintf( "absent: %-10d %6.2f%%\n", $absent, $absent / $total * 100 ) );
+ $this->output( sprintf(
+ "expired: %-10d %6.2f%%\n",
+ $expired,
+ $expired / $total * 100
+ ) );
+ $this->output( sprintf(
+ "absent: %-10d %6.2f%%\n",
+ $absent,
+ $absent / $total * 100
+ ) );
$this->output( sprintf( "stub threshold: %-10d %6.2f%%\n", $stub, $stub / $total * 100 ) );
$this->output( sprintf( "total: %-10d %6.2f%%\n", $total, 100 ) );
} else {
@@ -81,7 +78,11 @@ class ShowCacheStats extends Maintenance {
$total = $hits + $misses;
if ( $total ) {
$this->output( sprintf( "hits: %-10d %6.2f%%\n", $hits, $hits / $total * 100 ) );
- $this->output( sprintf( "misses: %-10d %6.2f%%\n", $misses, $misses / $total * 100 ) );
+ $this->output( sprintf(
+ "misses: %-10d %6.2f%%\n",
+ $misses,
+ $misses / $total * 100
+ ) );
$this->output( sprintf( "updates: %-10d\n", $updates ) );
} else {
$this->output( "no statistics available\n" );
@@ -94,8 +95,16 @@ class ShowCacheStats extends Maintenance {
$total = $hits + $misses + $uncacheable;
if ( $total ) {
$this->output( sprintf( "hits: %-10d %6.2f%%\n", $hits, $hits / $total * 100 ) );
- $this->output( sprintf( "misses: %-10d %6.2f%%\n", $misses, $misses / $total * 100 ) );
- $this->output( sprintf( "uncacheable: %-10d %6.2f%%\n", $uncacheable, $uncacheable / $total * 100 ) );
+ $this->output( sprintf(
+ "misses: %-10d %6.2f%%\n",
+ $misses,
+ $misses / $total * 100
+ ) );
+ $this->output( sprintf(
+ "uncacheable: %-10d %6.2f%%\n",
+ $uncacheable,
+ $uncacheable / $total * 100
+ ) );
} else {
$this->output( "no statistics available\n" );
}
diff --git a/maintenance/showJobs.php b/maintenance/showJobs.php
index afd7c745..b8dc5548 100644
--- a/maintenance/showJobs.php
+++ b/maintenance/showJobs.php
@@ -38,7 +38,10 @@ class ShowJobs extends Maintenance {
parent::__construct();
$this->mDescription = "Show number of jobs waiting in master database";
$this->addOption( 'group', 'Show number of jobs per job type' );
- $this->addOption( 'list', 'Show a complete list of all jobs in a machine-readable format, instead of statistics' );
+ $this->addOption(
+ 'list',
+ 'Show a complete list of all jobs in a machine-readable format, instead of statistics'
+ );
}
public function execute() {
@@ -56,14 +59,16 @@ class ShowJobs extends Maintenance {
} elseif ( $this->hasOption( 'group' ) ) {
foreach ( $group->getQueueTypes() as $type ) {
$queue = $group->get( $type );
+ $delayed = $queue->getDelayedCount();
$pending = $queue->getSize();
$claimed = $queue->getAcquiredCount();
$abandoned = $queue->getAbandonedCount();
$active = max( 0, $claimed - $abandoned );
- if ( ( $pending + $claimed ) > 0 ) {
+ if ( ( $pending + $claimed + $delayed + $abandoned ) > 0 ) {
$this->output(
"{$type}: $pending queued; " .
- "$claimed claimed ($active active, $abandoned abandoned)\n"
+ "$claimed claimed ($active active, $abandoned abandoned); " .
+ "$delayed delayed\n"
);
}
}
diff --git a/maintenance/showSiteStats.php b/maintenance/showSiteStats.php
index 49148b33..374a66e9 100644
--- a/maintenance/showSiteStats.php
+++ b/maintenance/showSiteStats.php
@@ -41,6 +41,7 @@ class ShowSiteStats extends Maintenance {
parent::__construct();
$this->mDescription = "Show the cached statistics";
}
+
public function execute() {
$fields = array(
'ss_total_views' => 'Total views',
@@ -65,7 +66,11 @@ class ShowSiteStats extends Maintenance {
// Show them
foreach ( $fields as $field => $desc ) {
- $this->output( sprintf( "%-{$max_length_desc}s: %{$max_length_value}d\n", $desc, $stats->$field ) );
+ $this->output( sprintf(
+ "%-{$max_length_desc}s: %{$max_length_value}d\n",
+ $desc,
+ $stats->$field
+ ) );
}
}
}
diff --git a/maintenance/sql.php b/maintenance/sql.php
index a628b0bc..afa3ef72 100644
--- a/maintenance/sql.php
+++ b/maintenance/sql.php
@@ -34,15 +34,17 @@ class MwSql extends Maintenance {
parent::__construct();
$this->mDescription = "Send SQL queries to a MediaWiki database";
$this->addOption( 'cluster', 'Use an external cluster by name', false, true );
+ $this->addOption( 'wikidb', 'The database wiki ID to use if not the current one', false, true );
$this->addOption( 'slave', 'Use a slave server (either "any" or by name)', false, true );
}
public function execute() {
+ $wiki = $this->getOption( 'wikidb' ) ?: false;
// Get the appropriate load balancer (for this wiki)
if ( $this->hasOption( 'cluster' ) ) {
- $lb = wfGetLBFactory()->getExternalLB( $this->getOption( 'cluster' ) );
+ $lb = wfGetLBFactory()->getExternalLB( $this->getOption( 'cluster' ), $wiki );
} else {
- $lb = wfGetLB();
+ $lb = wfGetLB( $wiki );
}
// Figure out which server to use
if ( $this->hasOption( 'slave' ) ) {
@@ -51,7 +53,8 @@ class MwSql extends Maintenance {
$index = DB_SLAVE;
} else {
$index = null;
- for ( $i = 0; $i < $lb->getServerCount(); ++$i ) {
+ $serverCount = $lb->getServerCount();
+ for ( $i = 0; $i < $serverCount; ++$i ) {
if ( $lb->getServerName( $i ) === $server ) {
$index = $i;
break;
@@ -65,9 +68,9 @@ class MwSql extends Maintenance {
$index = DB_MASTER;
}
// Get a DB handle (with this wiki's DB selected) from the appropriate load balancer
- $dbw = $lb->getConnection( $index );
- if ( $this->hasOption( 'slave' ) && $dbw->getLBInfo( 'master' ) !== null ) {
- $this->error( "The server selected ({$dbw->getServer()}) is not a slave.", 1 );
+ $db = $lb->getConnection( $index, array(), $wiki );
+ if ( $this->hasOption( 'slave' ) && $db->getLBInfo( 'master' ) !== null ) {
+ $this->error( "The server selected ({$db->getServer()}) is not a slave.", 1 );
}
if ( $this->hasArg( 0 ) ) {
@@ -76,7 +79,7 @@ class MwSql extends Maintenance {
$this->error( "Unable to open input file", true );
}
- $error = $dbw->sourceStream( $file, false, array( $this, 'sqlPrintResult' ) );
+ $error = $db->sourceStream( $file, false, array( $this, 'sqlPrintResult' ) );
if ( $error !== true ) {
$this->error( $error, true );
} else {
@@ -85,12 +88,12 @@ class MwSql extends Maintenance {
}
$useReadline = function_exists( 'readline_add_history' )
- && Maintenance::posix_isatty( 0 /*STDIN*/ );
+ && Maintenance::posix_isatty( 0 /*STDIN*/ );
if ( $useReadline ) {
global $IP;
$historyFile = isset( $_ENV['HOME'] ) ?
- "{$_ENV['HOME']}/.mwsql_history" : "$IP/maintenance/.mwsql_history";
+ "{$_ENV['HOME']}/.mwsql_history" : "$IP/maintenance/.mwsql_history";
readline_read_history( $historyFile );
}
@@ -102,7 +105,7 @@ class MwSql extends Maintenance {
# User simply pressed return key
continue;
}
- $done = $dbw->streamStatementEnd( $wholeLine, $line );
+ $done = $db->streamStatementEnd( $wholeLine, $line );
$wholeLine .= $line;
@@ -114,16 +117,16 @@ class MwSql extends Maintenance {
if ( $useReadline ) {
# Delimiter is eated by streamStatementEnd, we add it
# up in the history (bug 37020)
- readline_add_history( $wholeLine . $dbw->getDelimiter() );
+ readline_add_history( $wholeLine . $db->getDelimiter() );
readline_write_history( $historyFile );
}
try {
- $res = $dbw->query( $wholeLine );
- $this->sqlPrintResult( $res, $dbw );
+ $res = $db->query( $wholeLine );
+ $this->sqlPrintResult( $res, $db );
$prompt = $newPrompt;
$wholeLine = '';
} catch ( DBQueryError $e ) {
- $doDie = ! Maintenance::posix_isatty( 0 );
+ $doDie = !Maintenance::posix_isatty( 0 );
$this->error( $e, $doDie );
}
}
@@ -132,8 +135,8 @@ class MwSql extends Maintenance {
/**
* Print the results, callback for $db->sourceStream()
- * @param $res ResultWrapper The results object
- * @param $db DatabaseBase object
+ * @param ResultWrapper $res The results object
+ * @param DatabaseBase $db
*/
public function sqlPrintResult( $res, $db ) {
if ( !$res ) {
diff --git a/maintenance/sqlite.inc b/maintenance/sqlite.inc
index 08188cad..5c0fd07f 100644
--- a/maintenance/sqlite.inc
+++ b/maintenance/sqlite.inc
@@ -40,9 +40,9 @@ class Sqlite {
* Checks given files for correctness of SQL syntax. MySQL DDL will be converted to
* SQLite-compatible during processing.
* Will throw exceptions on SQL errors
- * @param $files
+ * @param array|string $files
* @throws MWException
- * @return mixed true if no error or error string in case of errors
+ * @return bool True if no error or error string in case of errors
*/
public static function checkSqlSyntax( $files ) {
if ( !Sqlite::isPresent() ) {
@@ -78,6 +78,7 @@ class Sqlite {
foreach ( $columns as $col ) {
if ( !isset( $allowedTypes[strtolower( $col->type )] ) ) {
$db->close();
+
return "Table {$table->name} has column {$col->name} with non-native type '{$col->type}'";
}
}
@@ -86,6 +87,7 @@ class Sqlite {
return $e->getMessage();
}
$db->close();
+
return true;
}
-};
+}
diff --git a/maintenance/sqlite.php b/maintenance/sqlite.php
index 8a785245..edc9e145 100644
--- a/maintenance/sqlite.php
+++ b/maintenance/sqlite.php
@@ -32,7 +32,10 @@ class SqliteMaintenance extends Maintenance {
public function __construct() {
parent::__construct();
$this->mDescription = "Performs some operations specific to SQLite database backend";
- $this->addOption( 'vacuum', 'Clean up database by removing deleted pages. Decreases database file size' );
+ $this->addOption(
+ 'vacuum',
+ 'Clean up database by removing deleted pages. Decreases database file size'
+ );
$this->addOption( 'integrity', 'Check database for integrity' );
$this->addOption( 'backup-to', 'Backup database to the given file', false, true );
$this->addOption( 'check-syntax', 'Check SQL file(s) for syntax errors', false, true );
@@ -52,6 +55,7 @@ class SqliteMaintenance extends Maintenance {
// Should work even if we use a non-SQLite database
if ( $this->hasOption( 'check-syntax' ) ) {
$this->checkSyntax();
+
return;
}
@@ -59,6 +63,7 @@ class SqliteMaintenance extends Maintenance {
if ( $this->db->getType() != 'sqlite' ) {
$this->error( "This maintenance script requires a SQLite database.\n" );
+
return;
}
@@ -98,6 +103,7 @@ class SqliteMaintenance extends Maintenance {
if ( !$res || $res->numRows() == 0 ) {
$this->error( "Error: integrity check query returned nothing.\n" );
+
return;
}
diff --git a/maintenance/sqlite/archives/initial-indexes.sql b/maintenance/sqlite/archives/initial-indexes.sql
index 1a59be5a..954c85d3 100644
--- a/maintenance/sqlite/archives/initial-indexes.sql
+++ b/maintenance/sqlite/archives/initial-indexes.sql
@@ -237,13 +237,13 @@ CREATE UNIQUE INDEX /*i*/iw_prefix ON /*_*/interwiki_tmp (iw_prefix);
CREATE TABLE /*_*/page_restrictions_tmp (
+ pr_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
pr_page int NOT NULL,
pr_type varbinary(60) NOT NULL,
pr_level varbinary(60) NOT NULL,
pr_cascade tinyint NOT NULL,
pr_user int NULL,
- pr_expiry varbinary(14) NULL,
- pr_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT
+ pr_expiry varbinary(14) NULL
);
CREATE UNIQUE INDEX /*i*/pr_pagetype ON /*_*/page_restrictions_tmp (pr_page,pr_type);
diff --git a/maintenance/sqlite/archives/patch-drop-rc_cur_time.sql b/maintenance/sqlite/archives/patch-drop-rc_cur_time.sql
new file mode 100644
index 00000000..350479fb
--- /dev/null
+++ b/maintenance/sqlite/archives/patch-drop-rc_cur_time.sql
@@ -0,0 +1,45 @@
+-- rc_cur_time is no longer used, delete the field
+CREATE TABLE /*_*/recentchanges_tmp (
+ rc_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ rc_timestamp varbinary(14) NOT NULL default '',
+ rc_user int unsigned NOT NULL default 0,
+ rc_user_text varchar(255) binary NOT NULL,
+ rc_namespace int NOT NULL default 0,
+ rc_title varchar(255) binary NOT NULL default '',
+ rc_comment varchar(255) binary NOT NULL default '',
+ rc_minor tinyint unsigned NOT NULL default 0,
+ rc_bot tinyint unsigned NOT NULL default 0,
+ rc_new tinyint unsigned NOT NULL default 0,
+ rc_cur_id int unsigned NOT NULL default 0,
+ rc_this_oldid int unsigned NOT NULL default 0,
+ rc_last_oldid int unsigned NOT NULL default 0,
+ rc_type tinyint unsigned NOT NULL default 0,
+ rc_source varchar(16) binary not null default '',
+ rc_patrolled tinyint unsigned NOT NULL default 0,
+ rc_ip varbinary(40) NOT NULL default '',
+ rc_old_len int,
+ rc_new_len int,
+ rc_deleted tinyint unsigned NOT NULL default 0,
+ rc_logid int unsigned NOT NULL default 0,
+ rc_log_type varbinary(255) NULL default NULL,
+ rc_log_action varbinary(255) NULL default NULL,
+ rc_params blob NULL
+) /*$wgDBTableOptions*/;
+
+INSERT INTO /*_*/recentchanges_tmp
+ SELECT rc_id, rc_timestamp, rc_user, rc_user_text, rc_namespace, rc_title, rc_comment, rc_minor,
+ rc_bot, rc_new, rc_cur_id, rc_this_oldid, rc_last_oldid, rc_type, rc_source, rc_patrolled,
+ rc_ip, rc_old_len, rc_new_len, rc_deleted, rc_logid, rc_log_type, rc_log_action, rc_params
+ FROM /*_*/recentchanges;
+
+DROP TABLE /*_*/recentchanges;
+
+ALTER TABLE /*_*/recentchanges_tmp RENAME TO /*_*/recentchanges;
+
+CREATE INDEX /*i*/rc_timestamp ON /*_*/recentchanges (rc_timestamp);
+CREATE INDEX /*i*/rc_namespace_title ON /*_*/recentchanges (rc_namespace, rc_title);
+CREATE INDEX /*i*/rc_cur_id ON /*_*/recentchanges (rc_cur_id);
+CREATE INDEX /*i*/new_name_timestamp ON /*_*/recentchanges (rc_new,rc_namespace,rc_timestamp);
+CREATE INDEX /*i*/rc_ip ON /*_*/recentchanges (rc_ip);
+CREATE INDEX /*i*/rc_ns_usertext ON /*_*/recentchanges (rc_namespace, rc_user_text);
+CREATE INDEX /*i*/rc_user_text ON /*_*/recentchanges (rc_user_text, rc_timestamp); \ No newline at end of file
diff --git a/maintenance/sqlite/archives/patch-page-page_lang.sql b/maintenance/sqlite/archives/patch-page-page_lang.sql
new file mode 100644
index 00000000..8de2dc7b
--- /dev/null
+++ b/maintenance/sqlite/archives/patch-page-page_lang.sql
@@ -0,0 +1,3 @@
+-- Add page_lang column
+
+ALTER TABLE /*$wgDBprefix*/page ADD COLUMN page_lang TEXT default NULL;
diff --git a/maintenance/storage/checkStorage.php b/maintenance/storage/checkStorage.php
index 03dc113a..0f996625 100644
--- a/maintenance/storage/checkStorage.php
+++ b/maintenance/storage/checkStorage.php
@@ -34,7 +34,6 @@ if ( !defined( 'MEDIAWIKI' ) ) {
$cs->check( $fix, $xml );
}
-
// ----------------------------------------------------------------------------------
/**
@@ -212,8 +211,12 @@ class CheckStorage {
$curIds = array();
if ( count( $objectRevs ) ) {
$headerLength = 300;
- $res = $dbr->select( 'text', array( 'old_id', 'old_flags', "LEFT(old_text, $headerLength) AS header" ),
- array( 'old_id IN (' . implode( ',', $objectRevs ) . ')' ), __METHOD__ );
+ $res = $dbr->select(
+ 'text',
+ array( 'old_id', 'old_flags', "LEFT(old_text, $headerLength) AS header" ),
+ array( 'old_id IN (' . implode( ',', $objectRevs ) . ')' ),
+ __METHOD__
+ );
foreach ( $res as $row ) {
$oldId = $row->old_id;
$matches = array();
@@ -224,7 +227,11 @@ class CheckStorage {
$className = strtolower( $matches[2] );
if ( strlen( $className ) != $matches[1] ) {
- $this->error( 'restore text', "Error: invalid object header, wrong class name length", $oldId );
+ $this->error(
+ 'restore text',
+ "Error: invalid object header, wrong class name length",
+ $oldId
+ );
continue;
}
@@ -263,8 +270,12 @@ class CheckStorage {
$externalConcatBlobs = array();
if ( count( $concatBlobs ) ) {
$headerLength = 300;
- $res = $dbr->select( 'text', array( 'old_id', 'old_flags', "LEFT(old_text, $headerLength) AS header" ),
- array( 'old_id IN (' . implode( ',', array_keys( $concatBlobs ) ) . ')' ), __METHOD__ );
+ $res = $dbr->select(
+ 'text',
+ array( 'old_id', 'old_flags', "LEFT(old_text, $headerLength) AS header" ),
+ array( 'old_id IN (' . implode( ',', array_keys( $concatBlobs ) ) . ')' ),
+ __METHOD__
+ );
foreach ( $res as $row ) {
$flags = explode( ',', $row->old_flags );
if ( in_array( 'external', $flags ) ) {
@@ -272,7 +283,11 @@ class CheckStorage {
if ( in_array( 'object', $flags ) ) {
$urlParts = explode( '/', $row->header );
if ( $urlParts[0] != 'DB:' ) {
- $this->error( 'unfixable', "Error: unrecognised external storage type \"{$urlParts[0]}", $row->old_id );
+ $this->error(
+ 'unfixable',
+ "Error: unrecognised external storage type \"{$urlParts[0]}",
+ $row->old_id
+ );
} else {
$cluster = $urlParts[2];
$id = $urlParts[3];
@@ -284,12 +299,20 @@ class CheckStorage {
);
}
} else {
- $this->error( 'unfixable', "Error: invalid flags \"{$row->old_flags}\" on concat bulk row {$row->old_id}",
+ $this->error(
+ 'unfixable',
+ "Error: invalid flags \"{$row->old_flags}\" on concat bulk row {$row->old_id}",
$concatBlobs[$row->old_id] );
}
- } elseif ( strcasecmp( substr( $row->header, 0, strlen( self::CONCAT_HEADER ) ), self::CONCAT_HEADER ) ) {
- $this->error( 'restore text', "Error: Incorrect object header for concat bulk row {$row->old_id}",
- $concatBlobs[$row->old_id] );
+ } elseif ( strcasecmp(
+ substr( $row->header, 0, strlen( self::CONCAT_HEADER ) ),
+ self::CONCAT_HEADER
+ ) ) {
+ $this->error(
+ 'restore text',
+ "Error: Incorrect object header for concat bulk row {$row->old_id}",
+ $concatBlobs[$row->old_id]
+ );
} # else good
unset( $concatBlobs[$row->old_id] );
@@ -299,7 +322,6 @@ class CheckStorage {
// Check targets of unresolved stubs
$this->checkExternalConcatBlobs( $externalConcatBlobs );
-
// next chunk
}
@@ -331,7 +353,6 @@ class CheckStorage {
}
}
-
function error( $type, $msg, $ids ) {
if ( is_array( $ids ) && count( $ids ) == 1 ) {
$ids = reset( $ids );
@@ -374,17 +395,23 @@ class CheckStorage {
array( 'blob_id IN( ' . implode( ',', $blobIds ) . ')' ), __METHOD__ );
foreach ( $res as $row ) {
if ( strcasecmp( $row->header, self::CONCAT_HEADER ) ) {
- $this->error( 'restore text', "Error: invalid header on target $cluster/{$row->blob_id} of two-part ES URL",
- $oldIds[$row->blob_id] );
+ $this->error(
+ 'restore text',
+ "Error: invalid header on target $cluster/{$row->blob_id} of two-part ES URL",
+ $oldIds[$row->blob_id]
+ );
}
unset( $oldIds[$row->blob_id] );
-
}
$extDb->freeResult( $res );
// Print errors for missing blobs rows
foreach ( $oldIds as $blobId => $oldIds2 ) {
- $this->error( 'restore text', "Error: missing target $cluster/$blobId for two-part ES URL", $oldIds2 );
+ $this->error(
+ 'restore text',
+ "Error: missing target $cluster/$blobId for two-part ES URL",
+ $oldIds2
+ );
}
}
}
@@ -405,6 +432,7 @@ class CheckStorage {
// Write revision list
if ( !file_put_contents( $revFileName, implode( "\n", $revIds ) ) ) {
echo "Error writing revision list, can't restore text\n";
+
return;
}
@@ -421,12 +449,14 @@ class CheckStorage {
if ( $exitStatus ) {
echo "mwdumper died with exit status $exitStatus\n";
+
return;
}
$file = fopen( $filteredXmlFileName, 'r' );
if ( !$file ) {
echo "Unable to open filtered XML file\n";
+
return;
}
@@ -448,6 +478,7 @@ class CheckStorage {
if ( $content === null ) {
echo "Revision $id is broken, we have no content available\n";
+
return;
}
@@ -459,12 +490,14 @@ class CheckStorage {
// be safe, we'll skip it and leave it broken
echo "Revision $id is blank in the dump, may have been broken before export\n";
+
return;
}
if ( !$id ) {
// No ID, can't import
echo "No id tag in revision, can't import\n";
+
return;
}
@@ -473,6 +506,7 @@ class CheckStorage {
$oldId = $dbr->selectField( 'revision', 'rev_text_id', array( 'rev_id' => $id ), __METHOD__ );
if ( !$oldId ) {
echo "Missing revision row for rev_id $id\n";
+
return;
}
diff --git a/maintenance/storage/compressOld.php b/maintenance/storage/compressOld.php
index 8cb55487..cfffbbca 100644
--- a/maintenance/storage/compressOld.php
+++ b/maintenance/storage/compressOld.php
@@ -59,12 +59,41 @@ class CompressOld extends Maintenance {
parent::__construct();
$this->mDescription = 'Compress the text of a wiki';
$this->addOption( 'type', 'Set compression type to either: gzip|concat', false, true, 't' );
- $this->addOption( 'chunksize', 'Maximum number of revisions in a concat chunk', false, true, 'c' );
- $this->addOption( 'begin-date', 'Earliest date to check for uncompressed revisions', false, true, 'b' );
+ $this->addOption(
+ 'chunksize',
+ 'Maximum number of revisions in a concat chunk',
+ false,
+ true,
+ 'c'
+ );
+ $this->addOption(
+ 'begin-date',
+ 'Earliest date to check for uncompressed revisions',
+ false,
+ true,
+ 'b'
+ );
$this->addOption( 'end-date', 'Latest revision date to compress', false, true, 'e' );
- $this->addOption( 'startid', 'The id to start from (gzip -> text table, concat -> page table)', false, true, 's' );
- $this->addOption( 'extdb', 'Store specified revisions in an external cluster (untested)', false, true );
- $this->addOption( 'endid', 'The page_id to stop at (only when using concat compression type)', false, true, 'n' );
+ $this->addOption(
+ 'startid',
+ 'The id to start from (gzip -> text table, concat -> page table)',
+ false,
+ true,
+ 's'
+ );
+ $this->addOption(
+ 'extdb',
+ 'Store specified revisions in an external cluster (untested)',
+ false,
+ true
+ );
+ $this->addOption(
+ 'endid',
+ 'The page_id to stop at (only when using concat compression type)',
+ false,
+ true,
+ 'n'
+ );
}
public function execute() {
@@ -107,23 +136,36 @@ class CompressOld extends Maintenance {
}
}
- /** @todo document */
+ /**
+ * @todo document
+ * @param int $start
+ * @param string $extdb
+ */
private function compressOldPages( $start = 0, $extdb = '' ) {
$chunksize = 50;
$this->output( "Starting from old_id $start...\n" );
$dbw = wfGetDB( DB_MASTER );
do {
- $res = $dbw->select( 'text', array( 'old_id', 'old_flags', 'old_text' ),
- "old_id>=$start", __METHOD__, array( 'ORDER BY' => 'old_id', 'LIMIT' => $chunksize, 'FOR UPDATE' ) );
+ $res = $dbw->select(
+ 'text',
+ array( 'old_id', 'old_flags', 'old_text' ),
+ "old_id>=$start",
+ __METHOD__,
+ array( 'ORDER BY' => 'old_id', 'LIMIT' => $chunksize, 'FOR UPDATE' )
+ );
+
if ( $res->numRows() == 0 ) {
break;
}
+
$last = $start;
+
foreach ( $res as $row ) {
# print " {$row->old_id} - {$row->old_namespace}:{$row->old_title}\n";
$this->compressPage( $row, $extdb );
$last = $row->old_id;
}
+
$start = $last + 1; # Deletion may leave long empty stretches
$this->output( "$start...\n" );
} while ( true );
@@ -131,12 +173,14 @@ class CompressOld extends Maintenance {
/**
* @todo document
- * @param $row
- * @param $extdb
+ * @param stdClass $row
+ * @param string $extdb
* @return bool
*/
private function compressPage( $row, $extdb ) {
- if ( false !== strpos( $row->old_flags, 'gzip' ) || false !== strpos( $row->old_flags, 'object' ) ) {
+ if ( false !== strpos( $row->old_flags, 'gzip' )
+ || false !== strpos( $row->old_flags, 'object' )
+ ) {
#print "Already compressed row {$row->old_id}\n";
return false;
}
@@ -150,6 +194,7 @@ class CompressOld extends Maintenance {
$compress = $storeObj->store( $extdb, $compress );
if ( $compress === false ) {
$this->error( "Unable to store object" );
+
return false;
}
}
@@ -164,21 +209,22 @@ class CompressOld extends Maintenance {
), __METHOD__,
array( 'LIMIT' => 1 )
);
+
return true;
}
/**
- * @param $startId
- * @param $maxChunkSize
- * @param $beginDate
- * @param $endDate
- * @param $extdb string
- * @param $maxPageId bool|int
+ * @param int $startId
+ * @param int $maxChunkSize
+ * @param string $beginDate
+ * @param string $endDate
+ * @param string $extdb
+ * @param bool|int $maxPageId
* @return bool
*/
private function compressWithConcat( $startId, $maxChunkSize, $beginDate,
- $endDate, $extdb = "", $maxPageId = false )
- {
+ $endDate, $extdb = "", $maxPageId = false
+ ) {
$loadStyle = self::LS_CHUNKED;
$dbr = wfGetDB( DB_SLAVE );
@@ -213,12 +259,15 @@ class CompressOld extends Maintenance {
# overwriting bulk storage concat rows. Don't compress external references, because
# the script doesn't yet delete rows from external storage.
$conds = array(
- 'old_flags NOT ' . $dbr->buildLike( $dbr->anyString(), 'object', $dbr->anyString() ) . ' AND old_flags NOT '
- . $dbr->buildLike( $dbr->anyString(), 'external', $dbr->anyString() ) );
+ 'old_flags NOT ' . $dbr->buildLike( $dbr->anyString(), 'object', $dbr->anyString() )
+ . ' AND old_flags NOT '
+ . $dbr->buildLike( $dbr->anyString(), 'external', $dbr->anyString() )
+ );
if ( $beginDate ) {
if ( !preg_match( '/^\d{14}$/', $beginDate ) ) {
$this->error( "Invalid begin date \"$beginDate\"\n" );
+
return false;
}
$conds[] = "rev_timestamp>'" . $beginDate . "'";
@@ -226,6 +275,7 @@ class CompressOld extends Maintenance {
if ( $endDate ) {
if ( !preg_match( '/^\d{14}$/', $endDate ) ) {
$this->error( "Invalid end date \"$endDate\"\n" );
+
return false;
}
$conds[] = "rev_timestamp<'" . $endDate . "'";
@@ -303,8 +353,10 @@ class CompressOld extends Maintenance {
$usedChunk = false;
$primaryOldid = $revs[$i]->rev_text_id;
+ // @codingStandardsIgnoreStart Ignore avoid function calls in a FOR loop test part warning
# Get the text of each revision and add it to the object
for ( $j = 0; $j < $thisChunkSize && $chunk->isHappy(); $j++ ) {
+ // @codingStandardsIgnoreEnd
$oldid = $revs[$i + $j]->rev_text_id;
# Get text
@@ -350,9 +402,10 @@ class CompressOld extends Maintenance {
if ( $usedChunk ) {
if ( $extdb != "" ) {
# Move blob objects to External Storage
- $stored = $storeObj->store( $extdb, serialize( $chunk ));
+ $stored = $storeObj->store( $extdb, serialize( $chunk ) );
if ( $stored === false ) {
$this->error( "Unable to store object" );
+
return false;
}
# Store External Storage URLs instead of Stub placeholders
@@ -406,9 +459,9 @@ class CompressOld extends Maintenance {
}
$this->output( "\n" );
}
+
return true;
}
-
}
$maintClass = 'CompressOld';
diff --git a/maintenance/storage/fixBug20757.php b/maintenance/storage/fixBug20757.php
index 101aa068..d2fe3b42 100644
--- a/maintenance/storage/fixBug20757.php
+++ b/maintenance/storage/fixBug20757.php
@@ -57,14 +57,9 @@ class FixBug20757 extends Maintenance {
$totalRevs = $dbr->selectField( 'text', 'MAX(old_id)', false, __METHOD__ );
- if ( $dbr->getType() == 'mysql'
- && version_compare( $dbr->getServerVersion(), '4.1.0', '>=' ) )
- {
+ if ( $dbr->getType() == 'mysql' ) {
// In MySQL 4.1+, the binary field old_text has a non-working LOWER() function
$lowerLeft = 'LOWER(CONVERT(LEFT(old_text,22) USING latin1))';
- } else {
- // No CONVERT() in MySQL 4.0
- $lowerLeft = 'LOWER(LEFT(old_text,22))';
}
while ( true ) {
@@ -301,14 +296,15 @@ class FixBug20757 extends Maintenance {
$this->mapCache[$pageId] = $map;
$this->mapCacheSize += count( $map );
}
+
return $this->mapCache[$pageId];
}
/**
* This is based on part of HistoryBlobStub::getText().
* Determine if the text can be retrieved from the row in the normal way.
- * @param $stub
- * @param $secondaryRow
+ * @param array $stub
+ * @param stdClass $secondaryRow
* @return bool
*/
function isUnbrokenStub( $stub, $secondaryRow ) {
@@ -316,7 +312,10 @@ class FixBug20757 extends Maintenance {
$text = $secondaryRow->old_text;
if ( in_array( 'external', $flags ) ) {
$url = $text;
- @list( /* $proto */ , $path ) = explode( '://', $url, 2 );
+ wfSuppressWarnings();
+ list( /* $proto */, $path ) = explode( '://', $url, 2 );
+ wfRestoreWarnings();
+
if ( $path == "" ) {
return false;
}
@@ -343,6 +342,7 @@ class FixBug20757 extends Maintenance {
$obj->uncompress();
$text = $obj->getItem( $stub['hash'] );
+
return $text !== false;
}
}
diff --git a/maintenance/storage/orphanStats.php b/maintenance/storage/orphanStats.php
index 1df1501e..c5213ad1 100644
--- a/maintenance/storage/orphanStats.php
+++ b/maintenance/storage/orphanStats.php
@@ -32,11 +32,13 @@ require_once __DIR__ . '/../Maintenance.php';
class OrphanStats extends Maintenance {
public function __construct() {
parent::__construct();
- $this->mDescription = "how some statistics on the blob_orphans table, created with trackBlobs.php";
+ $this->mDescription =
+ "Show some statistics on the blob_orphans table, created with trackBlobs.php";
}
protected function &getDB( $cluster, $groups = array(), $wiki = false ) {
$lb = wfGetLBFactory()->getExternalLB( $cluster );
+
return $lb->getConnection( DB_SLAVE );
}
@@ -54,12 +56,17 @@ class OrphanStats extends Maintenance {
foreach ( $res as $boRow ) {
$extDB = $this->getDB( $boRow->bo_cluster );
- $blobRow = $extDB->selectRow( 'blobs', '*', array( 'blob_id' => $boRow->bo_blob_id ), __METHOD__ );
+ $blobRow = $extDB->selectRow(
+ 'blobs',
+ '*',
+ array( 'blob_id' => $boRow->bo_blob_id ),
+ __METHOD__
+ );
$num++;
$size = strlen( $blobRow->blob_text );
$totalSize += $size;
- $hashes[ sha1( $blobRow->blob_text ) ] = true;
+ $hashes[sha1( $blobRow->blob_text )] = true;
$maxSize = max( $size, $maxSize );
}
unset( $res );
@@ -67,8 +74,8 @@ class OrphanStats extends Maintenance {
$this->output( "Number of orphans: $num\n" );
if ( $num > 0 ) {
$this->output( "Average size: " . round( $totalSize / $num, 0 ) . " bytes\n" .
- "Max size: $maxSize\n" .
- "Number of unique texts: " . count( $hashes ) . "\n" );
+ "Max size: $maxSize\n" .
+ "Number of unique texts: " . count( $hashes ) . "\n" );
}
}
}
diff --git a/maintenance/storage/recompressTracked.php b/maintenance/storage/recompressTracked.php
index b2663165..910f56bd 100644
--- a/maintenance/storage/recompressTracked.php
+++ b/maintenance/storage/recompressTracked.php
@@ -27,14 +27,16 @@ require __DIR__ . '/../commandLine.inc';
if ( count( $args ) < 1 ) {
echo "Usage: php recompressTracked.php [options] <cluster> [... <cluster>...]
-Moves blobs indexed by trackBlobs.php to a specified list of destination clusters, and recompresses them in the process. Restartable.
+Moves blobs indexed by trackBlobs.php to a specified list of destination clusters,
+and recompresses them in the process. Restartable.
Options:
- --procs <procs> Set the number of child processes (default 1)
- --copy-only Copy only, do not update the text table. Restart without this option to complete.
- --debug-log <file> Log debugging data to the specified file
- --info-log <file> Log progress messages to the specified file
- --critical-log <file> Log error messages to the specified file
+ --procs <procs> Set the number of child processes (default 1)
+ --copy-only Copy only, do not update the text table. Restart
+ without this option to complete.
+ --debug-log <file> Log debugging data to the specified file
+ --info-log <file> Log progress messages to the specified file
+ --critical-log <file> Log error messages to the specified file
";
exit( 1 );
}
@@ -63,8 +65,15 @@ class RecompressTracked {
public $debugLog, $infoLog, $criticalLog;
public $store;
- static $optionsWithArgs = array( 'procs', 'slave-id', 'debug-log', 'info-log', 'critical-log' );
- static $cmdLineOptionMap = array(
+ private static $optionsWithArgs = array(
+ 'procs',
+ 'slave-id',
+ 'debug-log',
+ 'info-log',
+ 'critical-log'
+ );
+
+ private static $cmdLineOptionMap = array(
'no-count' => 'noCount',
'procs' => 'numProcs',
'copy-only' => 'copyOnly',
@@ -86,6 +95,7 @@ class RecompressTracked {
$jobOptions[$classOption] = $options[$cmdOption];
}
}
+
return new self( $jobOptions );
}
@@ -109,7 +119,6 @@ class RecompressTracked {
if ( $this->debugLog ) {
$this->logToFile( $msg, $this->debugLog );
}
-
}
function info( $msg ) {
@@ -181,13 +190,16 @@ class RecompressTracked {
$dbr = wfGetDB( DB_SLAVE );
if ( !$dbr->tableExists( 'blob_tracking' ) ) {
$this->critical( "Error: blob_tracking table does not exist" );
+
return false;
}
$row = $dbr->selectRow( 'blob_tracking', '*', false, __METHOD__ );
if ( !$row ) {
$this->info( "Warning: blob_tracking table contains no rows, skipping this wiki." );
+
return false;
}
+
return true;
}
@@ -267,6 +279,7 @@ class RecompressTracked {
if ( isset( $pipes[$slaveId] ) ) {
$this->prevSlaveId = $slaveId;
$this->dispatchToSlave( $slaveId, $args );
+
return;
}
}
@@ -276,6 +289,8 @@ class RecompressTracked {
/**
* Dispatch a command to a specified slave
+ * @param int $slaveId
+ * @param array|string $args
*/
function dispatchToSlave( $slaveId, $args ) {
$args = (array)$args;
@@ -339,6 +354,9 @@ class RecompressTracked {
/**
* Display a progress report
+ * @param string $label
+ * @param int $current
+ * @param int $end
*/
function report( $label, $current, $end ) {
$this->numBatches++;
@@ -434,14 +452,14 @@ class RecompressTracked {
$args = explode( ' ', $line );
$cmd = array_shift( $args );
switch ( $cmd ) {
- case 'doPage':
- $this->doPage( intval( $args[0] ) );
- break;
- case 'doOrphanList':
- $this->doOrphanList( array_map( 'intval', $args ) );
- break;
- case 'quit':
- return;
+ case 'doPage':
+ $this->doPage( intval( $args[0] ) );
+ break;
+ case 'doOrphanList':
+ $this->doOrphanList( array_map( 'intval', $args ) );
+ break;
+ case 'quit':
+ return;
}
$this->waitForSlaves();
}
@@ -449,6 +467,8 @@ class RecompressTracked {
/**
* Move tracked text in a given page
+ *
+ * @param int $pageId
*/
function doPage( $pageId ) {
$title = Title::newFromId( $pageId );
@@ -527,6 +547,9 @@ class RecompressTracked {
* without data loss.
*
* The transaction is kept short to reduce locking.
+ *
+ * @param int $textId
+ * @param string $url
*/
function moveTextRow( $textId, $url ) {
if ( $this->copyOnly ) {
@@ -560,6 +583,8 @@ class RecompressTracked {
*
* This function completes any moves that only have done bt_new_url. This
* can happen when the script is interrupted, or when --copy-only is used.
+ *
+ * @param array $conds
*/
function finishIncompleteMoves( $conds ) {
$dbr = wfGetDB( DB_SLAVE );
@@ -602,21 +627,25 @@ class RecompressTracked {
if ( $cluster === false ) {
$cluster = reset( $this->destClusters );
}
+
return $cluster;
}
/**
* Gets a DB master connection for the given external cluster name
- * @param $cluster string
+ * @param string $cluster
* @return DatabaseBase
*/
function getExtDB( $cluster ) {
$lb = wfGetLBFactory()->getExternalLB( $cluster );
+
return $lb->getConnection( DB_MASTER );
}
/**
* Move an orphan text_id to the new cluster
+ *
+ * @param array $textIds
*/
function doOrphanList( $textIds ) {
// Finish incomplete moves
@@ -683,6 +712,8 @@ class CgzCopyTransaction {
/**
* Create a transaction from a RecompressTracked object
+ * @param RecompressTracked $parent
+ * @param string $blobClass
*/
function __construct( $parent, $blobClass ) {
$this->blobClass = $blobClass;
@@ -694,8 +725,8 @@ class CgzCopyTransaction {
/**
* Add text.
* Returns false if it's ready to commit.
- * @param $text string
- * @param $textId
+ * @param string $text
+ * @param int $textId
* @return bool
*/
function addItem( $text, $textId ) {
@@ -706,6 +737,7 @@ class CgzCopyTransaction {
$hash = $this->cgz->addItem( $text );
$this->referrers[$textId] = $hash;
$this->texts[$textId] = $text;
+
return $this->cgz->isHappy();
}
@@ -769,6 +801,7 @@ class CgzCopyTransaction {
$this->critical( "Warning: concurrent operation detected, are there two conflicting " .
"processes running, doing the same job?" );
}
+
return;
}
$this->recompress();
diff --git a/maintenance/storage/resolveStubs.php b/maintenance/storage/resolveStubs.php
index e47d6407..290f1649 100644
--- a/maintenance/storage/resolveStubs.php
+++ b/maintenance/storage/resolveStubs.php
@@ -65,6 +65,9 @@ function resolveStubs() {
/**
* Resolve a history stub
+ * @param int $id
+ * @param string $stubText
+ * @param string $flags
*/
function resolveStub( $id, $stubText, $flags ) {
$fname = 'resolveStub';
@@ -77,12 +80,18 @@ function resolveStub( $id, $stubText, $flags ) {
if ( strtolower( get_class( $stub ) ) !== 'historyblobstub' ) {
print "Error found object of class " . get_class( $stub ) . ", expecting historyblobstub\n";
+
return;
}
# Get the (maybe) external row
- $externalRow = $dbr->selectRow( 'text', array( 'old_text' ),
- array( 'old_id' => $stub->mOldId, 'old_flags' . $dbr->buildLike( $dbr->anyString(), 'external', $dbr->anyString() ) ),
+ $externalRow = $dbr->selectRow(
+ 'text',
+ array( 'old_text' ),
+ array(
+ 'old_id' => $stub->mOldId,
+ 'old_flags' . $dbr->buildLike( $dbr->anyString(), 'external', $dbr->anyString() )
+ ),
$fname
);
diff --git a/maintenance/storage/testCompression.php b/maintenance/storage/testCompression.php
index fdc28d9b..f7ec6624 100644
--- a/maintenance/storage/testCompression.php
+++ b/maintenance/storage/testCompression.php
@@ -24,8 +24,9 @@
$optionsWithArgs = array( 'start', 'limit', 'type' );
require __DIR__ . '/../commandLine.inc';
-if ( !isset( $args[0] ) ) {
- echo "Usage: php testCompression.php [--type=<type>] [--start=<start-date>] [--limit=<num-revs>] <page-title>\n";
+if ( !isset( $args[0] ) ) {
+ echo "Usage: php testCompression.php [--type=<type>] [--start=<start-date>] " .
+ "[--limit=<num-revs>] <page-title>\n";
exit( 1 );
}
@@ -45,7 +46,6 @@ if ( isset( $options['limit'] ) ) {
}
$type = isset( $options['type'] ) ? $options['type'] : 'ConcatenatedGzipHistoryBlob';
-
$dbr = wfGetDB( DB_SLAVE );
$res = $dbr->select(
array( 'page', 'revision', 'text' ),
diff --git a/maintenance/storage/trackBlobs.php b/maintenance/storage/trackBlobs.php
index 7857dd95..a3f93862 100644
--- a/maintenance/storage/trackBlobs.php
+++ b/maintenance/storage/trackBlobs.php
@@ -24,7 +24,6 @@
require __DIR__ . '/../commandLine.inc';
-
if ( count( $args ) < 1 ) {
echo "Usage: php trackBlobs.php <cluster> [... <cluster>]\n";
echo "Adds blobs from a given ES cluster to the blob_tracking table\n";
@@ -127,6 +126,7 @@ class TrackBlobs {
$this->textClause .= 'old_text' . $dbr->buildLike( "DB://$cluster/", $dbr->anyString() );
}
}
+
return $this->textClause;
}
@@ -134,6 +134,7 @@ class TrackBlobs {
if ( !preg_match( '!^DB://(\w+)/(\d+)(?:/([0-9a-fA-F]+)|)$!', $text, $m ) ) {
return false;
}
+
return array(
'cluster' => $m[1],
'id' => intval( $m[2] ),
@@ -306,6 +307,7 @@ class TrackBlobs {
function findOrphanBlobs() {
if ( !extension_loaded( 'gmp' ) ) {
echo "Can't find orphan blobs, need bitfield support provided by GMP.\n";
+
return;
}
diff --git a/maintenance/syncFileBackend.php b/maintenance/syncFileBackend.php
index f0be709f..14a1502f 100644
--- a/maintenance/syncFileBackend.php
+++ b/maintenance/syncFileBackend.php
@@ -71,6 +71,7 @@ class SyncFileBackend extends Maintenance {
if ( $this->isQuiet() ) {
print $id; // give a single machine-readable number
}
+
return;
}
@@ -104,7 +105,7 @@ class SyncFileBackend extends Maintenance {
}
// Periodically update the position file
- $callback = function( $pos ) use ( $startFromPosFile, $posFile, $start ) {
+ $callback = function ( $pos ) use ( $startFromPosFile, $posFile, $start ) {
if ( $startFromPosFile && $pos >= $start ) { // successfully advanced
file_put_contents( $posFile, $pos, LOCK_EX );
}
@@ -141,12 +142,12 @@ class SyncFileBackend extends Maintenance {
* Sync $dst backend to $src backend based on the $src logs given after $start.
* Returns the journal entry ID this advanced to and handled (inclusive).
*
- * @param $src FileBackend
- * @param $dst FileBackend
- * @param $start integer Starting journal position
- * @param $end integer Starting journal position
- * @param $callback Closure Callback to update any position file
- * @return integer|false Journal entry ID or false if there are none
+ * @param FileBackend $src
+ * @param FileBackend $dst
+ * @param int $start Starting journal position
+ * @param int $end Starting journal position
+ * @param Closure $callback Callback to update any position file
+ * @return int|bool Journal entry ID or false if there are none
*/
protected function syncBackends(
FileBackend $src, FileBackend $dst, $start, $end, Closure $callback
@@ -198,9 +199,9 @@ class SyncFileBackend extends Maintenance {
/**
* Sync particular files of backend $src to the corresponding $dst backend files
*
- * @param $paths Array
- * @param $src FileBackend
- * @param $dst FileBackend
+ * @param array $paths
+ * @param FileBackend $src
+ * @param FileBackend $dst
* @return Status
*/
protected function syncFileBatch( array $paths, FileBackend $src, FileBackend $dst ) {
@@ -221,6 +222,9 @@ class SyncFileBackend extends Maintenance {
return $status;
}
+ $src->preloadFileStat( array( 'srcs' => $sPaths, 'latest' => 1 ) );
+ $dst->preloadFileStat( array( 'srcs' => $dPaths, 'latest' => 1 ) );
+
$ops = array();
$fsFiles = array();
foreach ( $sPaths as $i => $sPath ) {
@@ -235,6 +239,7 @@ class SyncFileBackend extends Maintenance {
if ( !$fsFile ) {
$this->error( "Unable to sync '$dPath': could not get local copy." );
$status->fatal( 'backend-fail-internal', $src->getName() );
+
return $status;
}
$fsFiles[] = $fsFile; // keep TempFSFile objects alive as needed
@@ -251,6 +256,7 @@ class SyncFileBackend extends Maintenance {
} else { // error
$this->error( "Unable to sync '$dPath': could not stat file." );
$status->fatal( 'backend-fail-internal', $src->getName() );
+
return $status;
}
}
@@ -273,8 +279,9 @@ class SyncFileBackend extends Maintenance {
/**
* Substitute the backend name of storage paths with that of a given one
*
- * @param $paths Array|string List of paths or single string path
- * @return Array|string
+ * @param array|string $paths List of paths or single string path
+ * @param FileBackend $backend
+ * @return array|string
*/
protected function replaceNamePaths( $paths, FileBackend $backend ) {
return preg_replace(
diff --git a/maintenance/tables.sql b/maintenance/tables.sql
index de92ef53..02286848 100644
--- a/maintenance/tables.sql
+++ b/maintenance/tables.sql
@@ -126,7 +126,12 @@ CREATE TABLE /*_*/user (
-- Meant primarily for heuristic checks to give an impression of whether
-- the account has been used much.
--
- user_editcount int
+ user_editcount int,
+
+ -- Expiration date for user password. Use $user->expirePassword()
+ -- to force a password reset.
+ user_password_expires varbinary(14) DEFAULT NULL
+
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/user_name ON /*_*/user (user_name);
@@ -256,6 +261,11 @@ CREATE TABLE /*_*/page (
-- of contained templates.
page_touched binary(14) NOT NULL default '',
+ -- This timestamp is updated whenever a page is re-parsed and
+ -- it has all the link tracking tables updated for it. This is
+ -- useful for de-duplicating expensive backlink update jobs.
+ page_links_updated varbinary(14) NULL default NULL,
+
-- Handy key to revision.rev_id of the current revision.
-- This may be 0 during page creation, but that shouldn't
-- happen outside of a transaction... hopefully.
@@ -265,7 +275,10 @@ CREATE TABLE /*_*/page (
page_len int unsigned NOT NULL,
-- content model, see CONTENT_MODEL_XXX constants
- page_content_model varbinary(32) DEFAULT NULL
+ page_content_model varbinary(32) DEFAULT NULL,
+
+ -- Page content language
+ page_lang varbinary(35) DEFAULT NULL
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/name_title ON /*_*/page (page_namespace,page_title);
@@ -460,6 +473,8 @@ CREATE INDEX /*i*/ar_revid ON /*_*/archive (ar_rev_id);
CREATE TABLE /*_*/pagelinks (
-- Key to the page_id of the page containing the link.
pl_from int unsigned NOT NULL default 0,
+ -- Namespace for this page
+ pl_from_namespace int NOT NULL default 0,
-- Key to page_namespace/page_title of the target page.
-- The target page may or may not exist, and due to renames
@@ -470,7 +485,8 @@ CREATE TABLE /*_*/pagelinks (
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/pl_from ON /*_*/pagelinks (pl_from,pl_namespace,pl_title);
-CREATE UNIQUE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from);
+CREATE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from);
+CREATE INDEX /*i*/pl_backlinks_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from_namespace,pl_from);
--
@@ -479,6 +495,8 @@ CREATE UNIQUE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,p
CREATE TABLE /*_*/templatelinks (
-- Key to the page_id of the page containing the link.
tl_from int unsigned NOT NULL default 0,
+ -- Namespace for this page
+ tl_from_namespace int NOT NULL default 0,
-- Key to page_namespace/page_title of the target page.
-- The target page may or may not exist, and due to renames
@@ -489,7 +507,8 @@ CREATE TABLE /*_*/templatelinks (
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/tl_from ON /*_*/templatelinks (tl_from,tl_namespace,tl_title);
-CREATE UNIQUE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from);
+CREATE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from);
+CREATE INDEX /*i*/tl_backlinks_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from_namespace,tl_from);
--
@@ -500,6 +519,8 @@ CREATE UNIQUE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_tit
CREATE TABLE /*_*/imagelinks (
-- Key to page_id of the page containing the image / media link.
il_from int unsigned NOT NULL default 0,
+ -- Namespace for this page
+ il_from_namespace int NOT NULL default 0,
-- Filename of target image.
-- This is also the page_title of the file's description page;
@@ -508,7 +529,8 @@ CREATE TABLE /*_*/imagelinks (
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/il_from ON /*_*/imagelinks (il_from,il_to);
-CREATE UNIQUE INDEX /*i*/il_to ON /*_*/imagelinks (il_to,il_from);
+CREATE INDEX /*i*/il_to ON /*_*/imagelinks (il_to,il_from);
+CREATE INDEX /*i*/il_backlinks_namespace ON /*_*/imagelinks (il_to,il_from_namespace,il_from);
--
@@ -714,7 +736,7 @@ CREATE UNIQUE INDEX /*i*/ss_row_id ON /*_*/site_stats (ss_row_id);
--
CREATE TABLE /*_*/hitcounter (
hc_id int unsigned NOT NULL
-) ENGINE=HEAP MAX_ROWS=25000;
+) ENGINE=MEMORY MAX_ROWS=25000;
--
@@ -825,7 +847,8 @@ CREATE TABLE /*_*/image (
-- major part of a MIME media type as defined by IANA
-- see http://www.iana.org/assignments/media-types/
- img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown",
+ -- for "chemical" cf. http://dx.doi.org/10.1021/ci9803233 by the ACS
+ img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") NOT NULL default "unknown",
-- minor part of a MIME media type as defined by IANA
-- the minor parts are not required to adher to any standard
@@ -884,7 +907,7 @@ CREATE TABLE /*_*/oldimage (
oi_metadata mediumblob NOT NULL,
oi_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
- oi_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown",
+ oi_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") NOT NULL default "unknown",
oi_minor_mime varbinary(100) NOT NULL default "unknown",
oi_deleted tinyint unsigned NOT NULL default 0,
oi_sha1 varbinary(32) NOT NULL default ''
@@ -934,7 +957,7 @@ CREATE TABLE /*_*/filearchive (
fa_metadata mediumblob,
fa_bits int default 0,
fa_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
- fa_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") default "unknown",
+ fa_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart", "chemical") default "unknown",
fa_minor_mime varbinary(100) default "unknown",
fa_description tinyblob,
fa_user int unsigned default 0,
@@ -991,12 +1014,12 @@ CREATE TABLE /*_*/uploadstash (
-- chunk counter starts at 0, current offset is stored in us_size
us_chunk_inx int unsigned NULL,
- -- Serialized file properties from File::getPropsFromPath
+ -- Serialized file properties from FSFile::getProps()
us_props blob,
-- file size in bytes
us_size int unsigned NOT NULL,
- -- this hash comes from File::sha1Base36(), and is 31 characters
+ -- this hash comes from FSFile::getSha1Base36(), and is 31 characters
us_sha1 varchar(31) NOT NULL,
us_mime varchar(255),
-- Media type as defined by the MEDIATYPE_xxx constants, should duplicate definition in the image table
@@ -1025,9 +1048,6 @@ CREATE TABLE /*_*/recentchanges (
rc_id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
rc_timestamp varbinary(14) NOT NULL default '',
- -- This is no longer used
- rc_cur_time varbinary(14) NOT NULL default '',
-
-- As in revision
rc_user int unsigned NOT NULL default 0,
rc_user_text varchar(255) binary NOT NULL,
@@ -1062,6 +1082,10 @@ CREATE TABLE /*_*/recentchanges (
-- The type of change entry (RC_EDIT,RC_NEW,RC_LOG,RC_EXTERNAL)
rc_type tinyint unsigned NOT NULL default 0,
+ -- The source of the change entry (replaces rc_type)
+ -- default of '' is temporary, needed for initial migration
+ rc_source varchar(16) binary not null default '',
+
-- If the Recent Changes Patrol option is enabled,
-- users may mark edits as having been reviewed to
-- remove a warning flag on the RC list.
@@ -1109,14 +1133,16 @@ CREATE TABLE /*_*/watchlist (
wl_namespace int NOT NULL default 0,
wl_title varchar(255) binary NOT NULL default '',
- -- Timestamp when user was last sent a notification e-mail;
- -- cleared when the user visits the page.
+ -- Timestamp used to send notification e-mails and show "updated since last visit" markers on
+ -- history and recent changes / watchlist. Set to NULL when the user visits the latest revision
+ -- of the page, which means that they should be sent an e-mail on the next change.
wl_notificationtimestamp varbinary(14)
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/wl_user ON /*_*/watchlist (wl_user, wl_namespace, wl_title);
CREATE INDEX /*i*/namespace_title ON /*_*/watchlist (wl_namespace, wl_title);
+CREATE INDEX /*i*/wl_user_notificationtimestamp ON /*_*/watchlist (wl_user, wl_notificationtimestamp);
--
@@ -1256,6 +1282,8 @@ CREATE INDEX /*i*/times ON /*_*/logging (log_timestamp);
CREATE INDEX /*i*/log_user_type_time ON /*_*/logging (log_user, log_type, log_timestamp);
CREATE INDEX /*i*/log_page_id_time ON /*_*/logging (log_page,log_timestamp);
CREATE INDEX /*i*/type_action ON /*_*/logging (log_type, log_action, log_timestamp);
+CREATE INDEX /*i*/log_user_text_type_time ON /*_*/logging (log_user_text, log_type, log_timestamp);
+CREATE INDEX /*i*/log_user_text_time ON /*_*/logging (log_user_text, log_timestamp);
CREATE TABLE /*_*/log_search (
@@ -1369,6 +1397,8 @@ CREATE INDEX /*i*/qcc_titletwo ON /*_*/querycachetwo (qcc_type,qcc_namespacetwo,
-- Used for storing page restrictions (i.e. protection levels)
CREATE TABLE /*_*/page_restrictions (
+ -- Field for an ID for this restrictions row (sort-key for Special:ProtectedPages)
+ pr_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
-- Page to apply restrictions to (Foreign Key to page).
pr_page int NOT NULL,
-- The protection type (edit, move, etc)
@@ -1380,9 +1410,7 @@ CREATE TABLE /*_*/page_restrictions (
-- Field for future support of per-user restriction.
pr_user int NULL,
-- Field for time-limited protection.
- pr_expiry varbinary(14) NULL,
- -- Field for an ID for this restrictions row (sort-key for Special:ProtectedPages)
- pr_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT
+ pr_expiry varbinary(14) NULL
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/pr_pagetype ON /*_*/page_restrictions (pr_page,pr_type);
@@ -1410,12 +1438,13 @@ CREATE INDEX /*i*/pt_timestamp ON /*_*/protected_titles (pt_timestamp);
CREATE TABLE /*_*/page_props (
pp_page int NOT NULL,
pp_propname varbinary(60) NOT NULL,
- pp_value blob NOT NULL
+ pp_value blob NOT NULL,
+ pp_sortkey float DEFAULT NULL
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/pp_page_propname ON /*_*/page_props (pp_page,pp_propname);
CREATE UNIQUE INDEX /*i*/pp_propname_page ON /*_*/page_props (pp_propname,pp_page);
-
+CREATE UNIQUE INDEX /*i*/pp_propname_sortkey_page ON /*_*/page_props (pp_propname,pp_sortkey,pp_page);
-- A table to log updates, one text key row per update.
CREATE TABLE /*_*/updatelog (
@@ -1514,7 +1543,7 @@ CREATE UNIQUE INDEX /*i*/md_module_skin ON /*_*/module_deps (md_module, md_skin)
-- Holds all the sites known to the wiki.
CREATE TABLE /*_*/sites (
--- Numeric id of the site
+ -- Numeric id of the site
site_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
-- Global identifier for the site, ie 'enwiktionary'
diff --git a/maintenance/term/MWTerm.php b/maintenance/term/MWTerm.php
index c52f07cc..d90d0695 100644
--- a/maintenance/term/MWTerm.php
+++ b/maintenance/term/MWTerm.php
@@ -35,8 +35,8 @@ class AnsiTermColorer {
/**
* Return ANSI terminal escape code for changing text attribs/color
*
- * @param $color String: semicolon-separated list of attribute/color codes
- * @return String
+ * @param string $color Semicolon-separated list of attribute/color codes
+ * @return string
*/
public function color( $color ) {
global $wgCommandLineDarkBg;
@@ -49,7 +49,7 @@ class AnsiTermColorer {
/**
* Return ANSI terminal escape code for restoring default text attributes
*
- * @return String
+ * @return string
*/
public function reset() {
return $this->color( 0 );
diff --git a/maintenance/undelete.php b/maintenance/undelete.php
index c890c69b..adebd277 100644
--- a/maintenance/undelete.php
+++ b/maintenance/undelete.php
@@ -47,7 +47,7 @@ class Undelete extends Maintenance {
if ( !$wgUser ) {
$this->error( "Invalid username", true );
}
- $archive = new PageArchive( $title );
+ $archive = new PageArchive( $title, RequestContext::getMain()->getConfig() );
$this->output( "Undeleting " . $title->getPrefixedDBkey() . '...' );
$archive->undelete( array(), $reason );
$this->output( "done\n" );
diff --git a/maintenance/update-keys.sql b/maintenance/update-keys.sql
new file mode 100644
index 00000000..dfbb67ea
--- /dev/null
+++ b/maintenance/update-keys.sql
@@ -0,0 +1,29 @@
+-- SQL to insert update keys into the initial tables after a
+-- fresh installation of MediaWiki's database.
+-- This is read and executed by the install script; you should
+-- not have to run it by itself unless doing a manual install.
+-- Insert keys here if either the unnecessary would cause heavy
+-- processing or could potentially cause trouble by lowering field
+-- sizes, adding constraints, etc.
+-- When adjusting field sizes, it is recommended removing old
+-- patches but to play safe, update keys should also inserted here.
+
+-- This is a shared file used for both MySQL and SQLite installs.
+-- Therefore inserting multiple values is not possible using the
+-- INSERT INTO VALUES syntax.
+--
+--
+-- The /*_*/ comments in this and other files are
+-- replaced with the defined table prefix by the installer
+-- and updater scripts. If you are installing or running
+-- updates manually, you will need to manually insert the
+-- table prefix if any when running these scripts.
+--
+
+INSERT IGNORE INTO /*_*/updatelog
+ SELECT 'filearchive-fa_major_mime-patch-fa_major_mime-chemical.sql' AS ul_key, null as ul_value
+ UNION SELECT 'image-img_major_mime-patch-img_major_mime-chemical.sql', null
+ UNION SELECT 'oldimage-oi_major_mime-patch-oi_major_mime-chemical.sql', null
+ UNION SELECT 'user_groups-ug_group-patch-ug_group-length-increase-255.sql', null
+ UNION SELECT 'user_former_groups-ufg_group-patch-ufg_group-length-increase-255.sql', null
+ UNION SELECT 'user_properties-up_property-patch-up_property.sql', null; \ No newline at end of file
diff --git a/maintenance/update.php b/maintenance/update.php
index 19429716..046d73cd 100644
--- a/maintenance/update.php
+++ b/maintenance/update.php
@@ -1,3 +1,4 @@
+#!/usr/bin/env php
<?php
/**
* Run all updaters.
@@ -25,7 +26,7 @@
* @ingroup Maintenance
*/
-if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.3.2' ) < 0 ) ) {
+if ( !function_exists( 'version_compare' ) || ( version_compare( PHP_VERSION, '5.3.2' ) < 0 ) ) {
require dirname( __FILE__ ) . '/../includes/PHPVersionError.php';
wfPHPVersionError( 'cli' );
}
@@ -47,13 +48,19 @@ class UpdateMediaWiki extends Maintenance {
$this->addOption( 'doshared', 'Also update shared tables' );
$this->addOption( 'nopurge', 'Do not purge the objectcache table after updates' );
$this->addOption( 'noschema', 'Only do the updates that are not done during schema updates' );
- $this->addOption( 'schema', 'Output SQL to do the schema updates instead of doing them. Works even when $wgAllowSchemaUpdates is false', false, true );
+ $this->addOption(
+ 'schema',
+ 'Output SQL to do the schema updates instead of doing them. Works '
+ . 'even when $wgAllowSchemaUpdates is false',
+ false,
+ true
+ );
$this->addOption( 'force', 'Override when $wgAllowSchemaUpdates disables this script' );
}
function getDbType() {
/* If we used the class constant PHP4 would give a parser error here */
- return 2 /* Maintenance::DB_ADMIN */;
+ return 2; /* Maintenance::DB_ADMIN */
}
function compatChecks() {
@@ -74,30 +81,22 @@ class UpdateMediaWiki extends Maintenance {
$test = new PhpXmlBugTester();
if ( !$test->ok ) {
$this->error(
- "Your system has a combination of PHP and libxml2 versions which is buggy\n" .
+ "Your system has a combination of PHP and libxml2 versions that is buggy\n" .
"and can cause hidden data corruption in MediaWiki and other web apps.\n" .
- "Upgrade to PHP 5.2.9 or later and libxml2 2.7.3 or later!\n" .
- "ABORTING (see http://bugs.php.net/bug.php?id=45996).\n",
- true );
- }
-
- $test = new PhpRefCallBugTester;
- $test->execute();
- if ( !$test->ok ) {
- $ver = phpversion();
- $this->error(
- "PHP $ver is not compatible with MediaWiki due to a bug involving\n" .
- "reference parameters to __call. Upgrade to PHP 5.3.2 or higher, or \n" .
- "downgrade to PHP 5.3.0 to fix this.\n" .
- "ABORTING (see http://bugs.php.net/bug.php?id=50394 for details)\n",
+ "Upgrade to libxml2 2.7.3 or later.\n" .
+ "ABORTING (see https://bugs.php.net/bug.php?id=45996).\n",
true );
}
}
function execute() {
- global $wgVersion, $wgTitle, $wgLang, $wgAllowSchemaUpdates;
+ global $wgVersion, $wgLang, $wgAllowSchemaUpdates;
- if ( !$wgAllowSchemaUpdates && !( $this->hasOption( 'force' ) || $this->hasOption( 'schema' ) || $this->hasOption( 'noschema' ) ) ) {
+ if ( !$wgAllowSchemaUpdates
+ && !( $this->hasOption( 'force' )
+ || $this->hasOption( 'schema' )
+ || $this->hasOption( 'noschema' ) )
+ ) {
$this->error( "Do not run update.php on this wiki. If you're seeing this you should\n"
. "probably ask for some help in performing your schema updates or use\n"
. "the --noschema and --schema options to get an SQL file for someone\n"
@@ -118,7 +117,8 @@ class UpdateMediaWiki extends Maintenance {
}
$wgLang = Language::factory( 'en' );
- $wgTitle = Title::newFromText( "MediaWiki database updater" );
+
+ define( 'MW_UPDATER', true );
$this->output( "MediaWiki {$wgVersion} Updater\n\n" );
@@ -142,10 +142,13 @@ class UpdateMediaWiki extends Maintenance {
$this->output( "Depending on the size of your database this may take a while!\n" );
if ( !$this->hasOption( 'quick' ) ) {
- $this->output( "Abort with control-c in the next five seconds (skip this countdown with --quick) ... " );
+ $this->output( "Abort with control-c in the next five seconds "
+ . "(skip this countdown with --quick) ... " );
wfCountDown( 5 );
}
+ $time1 = new MWTimestamp();
+
$shared = $this->hasOption( 'doshared' );
$updates = array( 'core', 'extensions' );
@@ -178,8 +181,10 @@ class UpdateMediaWiki extends Maintenance {
if ( !$this->hasOption( 'nopurge' ) ) {
$updater->purgeCache();
}
+ $time2 = new MWTimestamp();
- $this->output( "\nDone.\n" );
+ $timeDiff = $time2->diff( $time1 );
+ $this->output( "\nDone in " . $timeDiff->format( "%i:%S" ) . ".\n" );
}
function afterFinalSetup() {
@@ -190,7 +195,7 @@ class UpdateMediaWiki extends Maintenance {
# cache from $wgExtensionFunctions (bug 20471)
$wgLocalisationCacheConf = array(
'class' => 'LocalisationCache',
- 'storeClass' => 'LCStore_Null',
+ 'storeClass' => 'LCStoreNull',
'storeDirectory' => false,
'manualRecache' => false,
);
diff --git a/maintenance/updateArticleCount.php b/maintenance/updateArticleCount.php
index 7964a21f..470647a4 100644
--- a/maintenance/updateArticleCount.php
+++ b/maintenance/updateArticleCount.php
@@ -49,10 +49,16 @@ class UpdateArticleCount extends Maintenance {
if ( $this->hasOption( 'update' ) ) {
$this->output( "Updating site statistics table... " );
$dbw = wfGetDB( DB_MASTER );
- $dbw->update( 'site_stats', array( 'ss_good_articles' => $result ), array( 'ss_row_id' => 1 ), __METHOD__ );
+ $dbw->update(
+ 'site_stats',
+ array( 'ss_good_articles' => $result ),
+ array( 'ss_row_id' => 1 ),
+ __METHOD__
+ );
$this->output( "done.\n" );
} else {
- $this->output( "To update the site statistics table, run the script with the --update option.\n" );
+ $this->output( "To update the site statistics table, run the script "
+ . "with the --update option.\n" );
}
}
}
diff --git a/maintenance/updateCollation.php b/maintenance/updateCollation.php
index 964b3138..342ffbad 100644
--- a/maintenance/updateCollation.php
+++ b/maintenance/updateCollation.php
@@ -47,7 +47,7 @@ class UpdateCollation extends Maintenance {
$this->mDescription = <<<TEXT
This script will find all rows in the categorylinks table whose collation is
out-of-date (cl_collation != '$wgCategoryCollation') and repopulate cl_sortkey
-using the page title and cl_sortkey_prefix. If everything's collation is
+using the page title and cl_sortkey_prefix. If all collations are
up-to-date, it will do nothing.
TEXT;
@@ -120,6 +120,7 @@ TEXT;
}
if ( $count == 0 ) {
$this->output( "Collations up-to-date.\n" );
+
return;
}
$this->output( "Fixing collation for $count rows.\n" );
@@ -150,7 +151,8 @@ TEXT;
# This is an old-style row, so the sortkey needs to be
# converted.
if ( $row->cl_sortkey == $title->getText()
- || $row->cl_sortkey == $title->getPrefixedText() ) {
+ || $row->cl_sortkey == $title->getPrefixedText()
+ ) {
$prefix = '';
} else {
# Custom sortkey, use it as a prefix
@@ -188,15 +190,14 @@ TEXT;
__METHOD__
);
}
+ if ( $row ) {
+ $batchConds = array( $this->getBatchCondition( $row, $dbw ) );
+ }
}
if ( !$dryRun ) {
$dbw->commit( __METHOD__ );
}
- if ( $row ) {
- $batchConds = array( $this->getBatchCondition( $row ) );
- }
-
$count += $res->numRows();
$this->output( "$count done.\n" );
@@ -218,9 +219,11 @@ TEXT;
/**
* Return an SQL expression selecting rows which sort above the given row,
* assuming an ordering of cl_to, cl_type, cl_from
+ * @param stdClass $row
+ * @param DatabaseBase $dbw
+ * @return string
*/
- function getBatchCondition( $row ) {
- $dbw = $this->getDB( DB_MASTER );
+ function getBatchCondition( $row, $dbw ) {
$fields = array( 'cl_to', 'cl_type', 'cl_from' );
$first = true;
$cond = false;
@@ -238,6 +241,7 @@ TEXT;
$prefix .= " AND $equality";
}
}
+
return $cond;
}
diff --git a/maintenance/updateDoubleWidthSearch.php b/maintenance/updateDoubleWidthSearch.php
index 41988d1b..796cedd9 100644
--- a/maintenance/updateDoubleWidthSearch.php
+++ b/maintenance/updateDoubleWidthSearch.php
@@ -36,7 +36,12 @@ class UpdateDoubleWidthSearch extends Maintenance {
parent::__construct();
$this->mDescription = "Script to normalize double-byte latin UTF-8 characters";
$this->addOption( 'q', 'quiet', false, true );
- $this->addOption( 'l', 'How long the searchindex and revision tables will be locked for', false, true );
+ $this->addOption(
+ 'l',
+ 'How long the searchindex and revision tables will be locked for',
+ false,
+ true
+ );
}
public function getDbType() {
@@ -67,6 +72,7 @@ class UpdateDoubleWidthSearch extends Maintenance {
$sql = "SELECT si_page FROM $searchindex
WHERE ( si_text RLIKE '$regexp' )
OR ( si_title RLIKE '$regexp' )";
+
return $dbw->query( $sql, __METHOD__ );
}
}
diff --git a/maintenance/updateRestrictions.php b/maintenance/updateRestrictions.php
index 175447e7..5b5cc048 100644
--- a/maintenance/updateRestrictions.php
+++ b/maintenance/updateRestrictions.php
@@ -59,7 +59,12 @@ class UpdateRestrictions extends Maintenance {
while ( $blockEnd <= $end ) {
$this->output( "...doing page_id from $blockStart to $blockEnd\n" );
$cond = "page_id BETWEEN $blockStart AND $blockEnd AND page_restrictions !=''";
- $res = $db->select( 'page', array( 'page_id', 'page_namespace', 'page_restrictions' ), $cond, __METHOD__ );
+ $res = $db->select(
+ 'page',
+ array( 'page_id', 'page_namespace', 'page_restrictions' ),
+ $cond,
+ __METHOD__
+ );
$batch = array();
foreach ( $res as $row ) {
$oldRestrictions = array();
@@ -108,7 +113,13 @@ class UpdateRestrictions extends Maintenance {
// Kill any broken rows from previous imports
$db->delete( 'page_restrictions', array( 'pr_level' => '' ) );
// Kill other invalid rows
- $db->deleteJoin( 'page_restrictions', 'page', 'pr_page', 'page_id', array( 'page_namespace' => NS_MEDIAWIKI ) );
+ $db->deleteJoin(
+ 'page_restrictions',
+ 'page',
+ 'pr_page',
+ 'page_id',
+ array( 'page_namespace' => NS_MEDIAWIKI )
+ );
$this->output( "...Done!\n" );
}
}
diff --git a/maintenance/updateSearchIndex.php b/maintenance/updateSearchIndex.php
index 0691bee8..68a51bd9 100644
--- a/maintenance/updateSearchIndex.php
+++ b/maintenance/updateSearchIndex.php
@@ -42,8 +42,18 @@ class UpdateSearchIndex extends Maintenance {
$this->mDescription = "Script for periodic off-peak updating of the search index";
$this->addOption( 's', 'starting timestamp', false, true );
$this->addOption( 'e', 'Ending timestamp', false, true );
- $this->addOption( 'p', 'File for saving/loading timestamps, searchUpdate.WIKI_ID.pos by default', false, true );
- $this->addOption( 'l', 'How long the searchindex and revision tables will be locked for', false, true );
+ $this->addOption(
+ 'p',
+ 'File for saving/loading timestamps, searchUpdate.WIKI_ID.pos by default',
+ false,
+ true
+ );
+ $this->addOption(
+ 'l',
+ 'How long the searchindex and revision tables will be locked for',
+ false,
+ true
+ );
}
public function getDbType() {
diff --git a/maintenance/updateSpecialPages.php b/maintenance/updateSpecialPages.php
index 3432cb20..61642828 100644
--- a/maintenance/updateSpecialPages.php
+++ b/maintenance/updateSpecialPages.php
@@ -34,34 +34,32 @@ class UpdateSpecialPages extends Maintenance {
parent::__construct();
$this->addOption( 'list', 'List special page names' );
$this->addOption( 'only', 'Only update "page"; case sensitive, ' .
- 'check correct case by calling this script with --list or on ' .
- 'includes/QueryPage.php. Ex: --only=BrokenRedirects', false, true );
+ 'check correct case by calling this script with --list. ' .
+ 'Ex: --only=BrokenRedirects', false, true );
$this->addOption( 'override', 'Also update pages that have updates disabled' );
}
public function execute() {
- global $IP, $wgQueryPages, $wgQueryCacheLimit, $wgDisableQueryPageUpdate;
+ global $wgQueryCacheLimit, $wgDisableQueryPageUpdate;
- if ( !$this->hasOption( 'list' ) && !$this->hasOption( 'only' ) ) {
- $this->doSpecialPageCacheUpdates();
- }
$dbw = wfGetDB( DB_MASTER );
- // This is needed to initialise $wgQueryPages
- require_once "$IP/includes/QueryPage.php";
+ $this->doSpecialPageCacheUpdates( $dbw );
- foreach ( $wgQueryPages as $page ) {
+ foreach ( QueryPage::getPages() as $page ) {
list( $class, $special ) = $page;
$limit = isset( $page[2] ) ? $page[2] : null;
# --list : just show the name of pages
if ( $this->hasOption( 'list' ) ) {
- $this->output( "$special\n" );
+ $this->output( "$special [QueryPage]\n" );
continue;
}
- if ( !$this->hasOption( 'override' ) && $wgDisableQueryPageUpdate && in_array( $special, $wgDisableQueryPageUpdate ) ) {
- $this->output( sprintf( "%-30s disabled\n", $special ) );
+ if ( !$this->hasOption( 'override' )
+ && $wgDisableQueryPageUpdate && in_array( $special, $wgDisableQueryPageUpdate )
+ ) {
+ $this->output( sprintf( "%-30s [QueryPage] disabled\n", $special ) );
continue;
}
@@ -81,7 +79,7 @@ class UpdateSpecialPages extends Maintenance {
}
if ( !$this->hasOption( 'only' ) || $this->getOption( 'only' ) == $queryPage->getName() ) {
- $this->output( sprintf( '%-30s ', $special ) );
+ $this->output( sprintf( '%-30s [QueryPage] ', $special ) );
if ( $queryPage->isExpensive() ) {
$t1 = explode( ' ', microtime() );
# Do the query
@@ -112,9 +110,6 @@ class UpdateSpecialPages extends Maintenance {
sleep( 10 );
} while ( !wfGetLB()->pingAll() );
$this->output( "Reconnected\n\n" );
- } else {
- # Commit the results
- $dbw->commit( __METHOD__ );
}
# Wait for the slave to catch up
wfWaitForSlaves();
@@ -128,32 +123,41 @@ class UpdateSpecialPages extends Maintenance {
}
}
- public function doSpecialPageCacheUpdates() {
+ public function doSpecialPageCacheUpdates( $dbw ) {
global $wgSpecialPageCacheUpdates;
- $dbw = wfGetDB( DB_MASTER );
foreach ( $wgSpecialPageCacheUpdates as $special => $call ) {
- if ( !is_callable( $call ) ) {
- $this->error( "Uncallable function $call!" );
+ # --list : just show the name of pages
+ if ( $this->hasOption( 'list' ) ) {
+ $this->output( "$special [callback]\n" );
continue;
}
- $this->output( sprintf( '%-30s ', $special ) );
- $t1 = explode( ' ', microtime() );
- call_user_func( $call, $dbw );
- $t2 = explode( ' ', microtime() );
- $elapsed = ( $t2[0] - $t1[0] ) + ( $t2[1] - $t1[1] );
- $hours = intval( $elapsed / 3600 );
- $minutes = intval( $elapsed % 3600 / 60 );
- $seconds = $elapsed - $hours * 3600 - $minutes * 60;
- if ( $hours ) {
- $this->output( $hours . 'h ' );
- }
- if ( $minutes ) {
- $this->output( $minutes . 'm ' );
+
+ if ( !$this->hasOption( 'only' ) || $this->getOption( 'only' ) == $special ) {
+ if ( !is_callable( $call ) ) {
+ $this->error( "Uncallable function $call!" );
+ continue;
+ }
+ $this->output( sprintf( '%-30s [callback] ', $special ) );
+ $t1 = explode( ' ', microtime() );
+ call_user_func( $call, $dbw );
+ $t2 = explode( ' ', microtime() );
+
+ $this->output( "completed in " );
+ $elapsed = ( $t2[0] - $t1[0] ) + ( $t2[1] - $t1[1] );
+ $hours = intval( $elapsed / 3600 );
+ $minutes = intval( $elapsed % 3600 / 60 );
+ $seconds = $elapsed - $hours * 3600 - $minutes * 60;
+ if ( $hours ) {
+ $this->output( $hours . 'h ' );
+ }
+ if ( $minutes ) {
+ $this->output( $minutes . 'm ' );
+ }
+ $this->output( sprintf( "%.2fs\n", $seconds ) );
+ # Wait for the slave to catch up
+ wfWaitForSlaves();
}
- $this->output( sprintf( "completed in %.2fs\n", $seconds ) );
- # Wait for the slave to catch up
- wfWaitForSlaves();
}
}
}
diff --git a/maintenance/userDupes.inc b/maintenance/userDupes.inc
index 8bd80c97..15e1174f 100644
--- a/maintenance/userDupes.inc
+++ b/maintenance/userDupes.inc
@@ -3,7 +3,7 @@
* Helper class for update.php.
*
* Copyright © 2005 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://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
@@ -46,7 +46,7 @@ class UserDupes {
/**
* Output some text via the output callback provided
- * @param $str String Text to print
+ * @param string $str Text to print
*/
private function out( $str ) {
call_user_func( $this->outputCallback, $str );
@@ -61,6 +61,7 @@ class UserDupes {
$info = $this->db->indexInfo( 'user', 'user_name', __METHOD__ );
if ( !$info ) {
$this->out( "WARNING: doesn't seem to have user_name index at all!\n" );
+
return false;
}
@@ -95,13 +96,14 @@ class UserDupes {
* not requested. (If doing resolution, edits may be reassigned.)
* Status information will be echo'd to stdout.
*
- * @param $doDelete bool: pass true to actually remove things
- * from the database; false to just check.
+ * @param bool $doDelete Pass true to actually remove things
+ * from the database; false to just check.
* @return bool
*/
function checkDupes( $doDelete = false ) {
if ( $this->hasUniqueIndex() ) {
echo wfWikiID() . " already has a unique index on its user table.\n";
+
return true;
}
@@ -125,7 +127,8 @@ class UserDupes {
if ( $this->reassigned > 0 ) {
if ( $doDelete ) {
- $this->out( "$this->reassigned duplicate accounts had edits reassigned to a canonical record id.\n" );
+ $this->out( "$this->reassigned duplicate accounts had edits "
+ . "reassigned to a canonical record id.\n" );
} else {
$this->out( "$this->reassigned duplicate accounts need to have edits reassigned.\n" );
}
@@ -133,22 +136,27 @@ class UserDupes {
if ( $this->trimmed > 0 ) {
if ( $doDelete ) {
- $this->out( "$this->trimmed duplicate user records were deleted from " . wfWikiID() . ".\n" );
+ $this->out( "$this->trimmed duplicate user records were deleted from "
+ . wfWikiID() . ".\n" );
} else {
- $this->out( "$this->trimmed duplicate user accounts were found on " . wfWikiID() . " which can be removed safely.\n" );
+ $this->out( "$this->trimmed duplicate user accounts were found on "
+ . wfWikiID() . " which can be removed safely.\n" );
}
}
if ( $this->failed > 0 ) {
$this->out( "Something terribly awry; $this->failed duplicate accounts were not removed.\n" );
+
return false;
}
if ( $this->trimmed == 0 || $doDelete ) {
$this->out( "It is now safe to apply the unique index on user_name.\n" );
+
return true;
} else {
$this->out( "Run this script again with the --fix option to automatically delete them.\n" );
+
return false;
}
}
@@ -184,7 +192,7 @@ class UserDupes {
function getDupes() {
$user = $this->db->tableName( 'user' );
$result = $this->db->query(
- "SELECT user_name,COUNT(*) AS n
+ "SELECT user_name,COUNT(*) AS n
FROM $user
GROUP BY user_name
HAVING n > 1", __METHOD__ );
@@ -193,6 +201,7 @@ class UserDupes {
foreach ( $result as $row ) {
$list[] = $row->user_name;
}
+
return $list;
}
@@ -200,8 +209,8 @@ class UserDupes {
* Examine user records for the given name. Try to see which record
* will be the one that actually gets used, then check remaining records
* for edits. If the dupes have no edits, we can safely remove them.
- * @param $name string
- * @param $doDelete bool
+ * @param string $name
+ * @param bool $doDelete
* @access private
*/
function examine( $name, $doDelete ) {
@@ -249,7 +258,7 @@ class UserDupes {
* Count the number of edits attributed to this user.
* Does not currently check log table or other things
* where it might show up...
- * @param $userid int
+ * @param int $userid
* @return int
* @access private
*/
@@ -262,8 +271,8 @@ class UserDupes {
}
/**
- * @param $from int
- * @param $to int
+ * @param int $from
+ * @param int $to
* @access private
*/
function reassignEdits( $from, $to ) {
@@ -277,7 +286,7 @@ class UserDupes {
/**
* Remove a user account line.
- * @param $userid int
+ * @param int $userid
* @access private
*/
function trimAccount( $userid ) {
@@ -285,5 +294,4 @@ class UserDupes {
$this->db->delete( 'user', array( 'user_id' => $userid ), __METHOD__ );
$this->out( " ok" );
}
-
}
diff --git a/maintenance/userOptions.inc b/maintenance/userOptions.inc
index 51da80d3..99ba3b83 100644
--- a/maintenance/userOptions.inc
+++ b/maintenance/userOptions.inc
@@ -30,7 +30,7 @@ require_once __DIR__ . '/commandLine.inc';
/**
* @ingroup Maintenance
*/
-class userOptions {
+class UserOptions {
public $mQuick;
public $mQuiet;
public $mDry;
@@ -40,21 +40,24 @@ class userOptions {
private $mMode, $mReady;
- /** Constructor. Will show usage and exit if script options are not correct */
+ /**
+ * Constructor. Will show usage and exit if script options are not correct
+ * @param array $opts
+ * @param array $args
+ */
function __construct( $opts, $args ) {
if ( !$this->checkOpts( $opts, $args ) ) {
- userOptions::showUsageAndExit();
+ UserOptions::showUsageAndExit();
} else {
$this->mReady = $this->initializeOpts( $opts, $args );
}
}
-
/**
* This is used to check options. Only needed on construction
*
- * @param $opts array
- * @param $args array
+ * @param array $opts
+ * @param array $args
*
* @return bool
*/
@@ -73,8 +76,8 @@ class userOptions {
/**
* load script options in the object
*
- * @param $opts array
- * @param $args array
+ * @param array $opts
+ * @param array $args
*
* @return bool
*/
@@ -108,7 +111,8 @@ class userOptions {
return false;
}
- $this->{ $this->mMode } ();
+ $this->{$this->mMode}();
+
return true;
}
@@ -140,7 +144,7 @@ class userOptions {
array( 'user_id' ),
array(),
__METHOD__
- );
+ );
foreach ( $result as $id ) {
@@ -156,15 +160,18 @@ class userOptions {
$userValue = $user->getOption( $this->mAnOption );
if ( $userValue <> $defaultOptions[$this->mAnOption] ) {
+ // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
@$ret[$this->mAnOption][$userValue]++;
+ // @codingStandardsIgnoreEnd
}
-
} else {
foreach ( $defaultOptions as $name => $defaultValue ) {
$userValue = $user->getOption( $name );
if ( $userValue <> $defaultValue ) {
+ // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
@$ret[$name][$userValue]++;
+ // @codingStandardsIgnoreEnd
}
}
}
@@ -179,7 +186,6 @@ class userOptions {
}
}
-
/** Change our users options */
private function CHANGER() {
$this->warn();
@@ -190,7 +196,7 @@ class userOptions {
array( 'user_id' ),
array(),
__METHOD__
- );
+ );
foreach ( $result as $id ) {
@@ -202,7 +208,8 @@ class userOptions {
if ( $curValue == $this->mOldValue ) {
if ( !$this->mQuiet ) {
- print "Setting {$this->mAnOption} for $username from '{$this->mOldValue}' to '{$this->mNewValue}'): ";
+ print "Setting {$this->mAnOption} for $username from '{$this->mOldValue}' " .
+ "to '{$this->mNewValue}'): ";
}
// Change value
@@ -215,7 +222,6 @@ class userOptions {
if ( !$this->mQuiet ) {
print " OK\n";
}
-
} elseif ( !$this->mQuiet ) {
print "Not changing '$username' using <{$this->mAnOption}> = '$curValue'\n";
}
@@ -232,6 +238,7 @@ class userOptions {
foreach ( $def as $optname => $defaultValue ) {
array_push( $ret, $optname );
}
+
return $ret;
}
@@ -240,7 +247,7 @@ class userOptions {
#
public static function showUsageAndExit() {
-print <<<USAGE
+ print <<<USAGE
This script pass through all users and change one of their options.
The new option is NOT validated.
@@ -264,7 +271,7 @@ Options:
--dry : do not save user settings back to database
USAGE;
- exit( 0 );
+ exit( 0 );
}
/**
@@ -277,14 +284,14 @@ USAGE;
return true;
}
-print <<<WARN
+ 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;
wfCountDown( 5 );
+
return true;
}
-
}
diff --git a/maintenance/userOptions.php b/maintenance/userOptions.php
index e0de3574..53db48cd 100644
--- a/maintenance/userOptions.php
+++ b/maintenance/userOptions.php
@@ -28,7 +28,7 @@
require_once 'userOptions.inc';
// Load up our tool system, exit with usage() if options are not fine
-$uo = new userOptions( $options, $args );
+$uo = new UserOptions( $options, $args );
$uo->run();
diff --git a/maintenance/waitForSlave.php b/maintenance/waitForSlave.php
index a62d1618..c9b1abba 100644
--- a/maintenance/waitForSlave.php
+++ b/maintenance/waitForSlave.php
@@ -34,6 +34,7 @@ class WaitForSlave extends Maintenance {
parent::__construct();
$this->addArg( 'maxlag', 'How long to wait for the slaves, default 10 seconds', false );
}
+
public function execute() {
wfWaitForSlaves( $this->getArg( 0, 10 ) );
}
diff --git a/maintenance/wrapOldPasswords.php b/maintenance/wrapOldPasswords.php
new file mode 100644
index 00000000..37272a01
--- /dev/null
+++ b/maintenance/wrapOldPasswords.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * Maintenance script to wrap all old-style passwords in a layered type
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+require_once __DIR__ . '/Maintenance.php';
+
+/**
+ * Maintenance script to wrap all passwords of a certain type in a specified layered
+ * type that wraps around the old type.
+ *
+ * @since 1.24
+ * @ingroup Maintenance
+ */
+class WrapOldPasswords extends Maintenance {
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Wrap all passwords of a certain type in a new layered type";
+ $this->addOption( 'type',
+ 'Password type to wrap passwords in (must inherit LayeredParameterizedPassword)', true, true );
+ $this->addOption( 'verbose', 'Enables verbose output', false, false, 'v' );
+ $this->setBatchSize( 100 );
+ }
+
+ public function execute() {
+ global $wgAuth;
+
+ if ( !$wgAuth->allowSetLocalPassword() ) {
+ $this->error( '$wgAuth does not allow local passwords. Aborting.', true );
+ }
+
+ $passwordFactory = new PasswordFactory();
+ $passwordFactory->init( RequestContext::getMain()->getConfig() );
+
+ $typeInfo = $passwordFactory->getTypes();
+ $layeredType = $this->getOption( 'type' );
+
+ // Check that type exists and is a layered type
+ if ( !isset( $typeInfo[$layeredType] ) ) {
+ $this->error( 'Undefined password type', true );
+ }
+
+ $passObj = $passwordFactory->newFromType( $layeredType );
+ if ( !$passObj instanceof LayeredParameterizedPassword ) {
+ $this->error( 'Layered parameterized password type must be used.', true );
+ }
+
+ // Extract the first layer type
+ $typeConfig = $typeInfo[$layeredType];
+ $firstType = $typeConfig['types'][0];
+
+ // Get a list of password types that are applicable
+ $dbw = $this->getDB( DB_MASTER );
+ $typeCond = 'user_password' . $dbw->buildLike( ":$firstType:", $dbw->anyString() );
+
+ $minUserId = 0;
+ do {
+ $dbw->begin();
+
+ $res = $dbw->select( 'user',
+ array( 'user_id', 'user_name', 'user_password' ),
+ array(
+ 'user_id > ' . $dbw->addQuotes( $minUserId ),
+ $typeCond
+ ),
+ __METHOD__,
+ array(
+ 'ORDER BY' => 'user_id',
+ 'LIMIT' => $this->mBatchSize,
+ 'LOCK IN SHARE MODE',
+ )
+ );
+
+ /** @var User[] $updateUsers */
+ $updateUsers = array();
+ foreach ( $res as $row ) {
+ if ( $this->hasOption( 'verbose' ) ) {
+ $this->output( "Updating password for user {$row->user_name} ({$row->user_id}).\n" );
+ }
+
+ $user = User::newFromId( $row->user_id );
+ /** @var ParameterizedPassword $password */
+ $password = $passwordFactory->newFromCiphertext( $row->user_password );
+ /** @var LayeredParameterizedPassword $layeredPassword */
+ $layeredPassword = $passwordFactory->newFromType( $layeredType );
+ $layeredPassword->partialCrypt( $password );
+
+ $updateUsers[] = $user;
+ $dbw->update( 'user',
+ array( 'user_password' => $layeredPassword->toString() ),
+ array( 'user_id' => $row->user_id ),
+ __METHOD__
+ );
+
+ $minUserId = $row->user_id;
+ }
+
+ $dbw->commit();
+
+ // Clear memcached so old passwords are wiped out
+ foreach ( $updateUsers as $user ) {
+ $user->clearSharedCache();
+ }
+ } while ( $res->numRows() );
+ }
+}
+
+$maintClass = "WrapOldPasswords";
+require_once RUN_MAINTENANCE_IF_MAIN;