From b9b85843572bf283f48285001e276ba7e61b63f6 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Sun, 22 Feb 2009 13:37:51 +0100 Subject: updated to MediaWiki 1.14.0 --- maintenance/Doxyfile | 39 +- maintenance/FiveUpgrade.inc | 47 +- maintenance/addwiki.php | 1 + maintenance/archives/patch-ipb_allow_usertalk.sql | 3 + maintenance/archives/patch-linktables.sql | 2 +- maintenance/archives/patch-log_user_text.sql | 5 + maintenance/archives/patch-ss_active_users.sql | 3 + maintenance/backup.inc | 14 +- maintenance/benchmarkPurge.php | 22 +- maintenance/checkAutoLoader.php | 19 +- maintenance/checkBadRedirects.php | 30 + maintenance/checkImages.php | 45 ++ maintenance/cleanupImages.php | 26 +- maintenance/cleanupTitles.php | 21 +- maintenance/deleteBatch.php | 7 +- maintenance/dumpBackup.php | 3 + maintenance/dumpTextPass.php | 2 +- maintenance/edit.php | 11 +- maintenance/findhooks.php | 1 + maintenance/generateSitemap.php | 6 +- maintenance/importDump.php | 22 +- maintenance/importImages.inc.php | 39 ++ maintenance/importImages.php | 61 +- maintenance/importTextFile.php | 4 +- maintenance/interwiki.sql | 11 +- maintenance/language/checkLanguage.inc | 376 ++++++++--- maintenance/language/checkLanguage.php | 7 +- maintenance/language/countMessages.php | 40 ++ maintenance/language/diffLanguage.php | 1 - maintenance/language/languages.inc | 336 +++++++++- maintenance/language/messageTypes.inc | 39 +- maintenance/language/messages.inc | 412 ++++++++++-- maintenance/language/transstat.php | 4 +- maintenance/moveBatch.php | 7 +- maintenance/namespaceDupes.php | 2 +- maintenance/nukePage.inc | 19 +- maintenance/ourusers.php | 48 +- maintenance/parserTests.inc | 220 +++++- maintenance/parserTests.php | 22 +- maintenance/parserTests.txt | 640 ++++++++++++++---- maintenance/parserTestsStaticParserHook.php | 23 +- .../postgres/archives/patch-ipb_address_unique.sql | 1 - maintenance/postgres/compare_schemas.pl | 3 +- maintenance/postgres/mediawiki_mysql2postgres.pl | 6 +- maintenance/postgres/tables.sql | 13 +- maintenance/rebuildFileCache.php | 91 +++ maintenance/refreshLinks.inc | 8 +- maintenance/removeUnusedAccounts.inc | 4 +- maintenance/removeUnusedAccounts.php | 31 +- maintenance/renameDbPrefix.php | 68 ++ maintenance/runJobs.php | 2 +- maintenance/sql.php | 6 +- maintenance/stats.php | 6 +- maintenance/storage/blob_tracking.sql | 57 ++ maintenance/storage/compressOld.inc | 10 +- maintenance/storage/compressOld.php | 6 +- maintenance/storage/dumpRev.php | 50 +- maintenance/storage/orphanStats.php | 46 ++ maintenance/storage/recompressTracked.php | 742 +++++++++++++++++++++ maintenance/storage/testCompression.php | 81 +++ maintenance/storage/trackBlobs.php | 316 +++++++++ maintenance/tables.sql | 14 +- maintenance/updateArticleCount.inc.php | 15 +- maintenance/updateRestrictions.php | 23 +- maintenance/updateSpecialPages.php | 93 +-- maintenance/updaters.inc | 74 +- 66 files changed, 3761 insertions(+), 645 deletions(-) create mode 100644 maintenance/archives/patch-ipb_allow_usertalk.sql create mode 100644 maintenance/archives/patch-log_user_text.sql create mode 100644 maintenance/archives/patch-ss_active_users.sql create mode 100644 maintenance/checkBadRedirects.php create mode 100644 maintenance/checkImages.php create mode 100644 maintenance/language/countMessages.php create mode 100644 maintenance/rebuildFileCache.php create mode 100644 maintenance/renameDbPrefix.php create mode 100644 maintenance/storage/blob_tracking.sql create mode 100644 maintenance/storage/orphanStats.php create mode 100644 maintenance/storage/recompressTracked.php create mode 100644 maintenance/storage/testCompression.php create mode 100644 maintenance/storage/trackBlobs.php (limited to 'maintenance') diff --git a/maintenance/Doxyfile b/maintenance/Doxyfile index df67ba60..cdc748d8 100644 --- a/maintenance/Doxyfile +++ b/maintenance/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.5.1 +# Doxyfile 1.5.6 # # Some placeholders have been added for MediaWiki usage: @@ -7,6 +7,8 @@ # {{STRIP_FROM_PATH}} # {{SVNSTAT}} # {{INPUT}} +# +# A number of MediaWiki-specific aliases are near the end of this file. #--------------------------------------------------------------------------- # Project related configuration options @@ -16,7 +18,6 @@ PROJECT_NUMBER = {{CURRENT_VERSION}} OUTPUT_DIRECTORY = {{OUTPUT_DIRECTORY}} CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English -USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ @@ -41,12 +42,11 @@ MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO -TAB_SIZE = 4 -ALIASES = +TAB_SIZE = 8 OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO -DISTRIBUTE_GROUP_DOC = NO +DISTRIBUTE_GROUP_DOC = YES SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options @@ -59,7 +59,7 @@ EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO -HIDE_IN_BODY_DOCS = NO +HIDE_IN_BODY_DOCS = YES INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO @@ -174,7 +174,7 @@ CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO -TOC_EXPAND = NO +TOC_EXPAND = YES DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = YES @@ -190,8 +190,8 @@ COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = -PDF_HYPERLINKS = NO -USE_PDFLATEX = NO +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- @@ -206,7 +206,7 @@ RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- -GENERATE_MAN = YES +GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO @@ -268,8 +268,6 @@ DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = -MAX_DOT_GRAPH_WIDTH = 1024 -MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO @@ -279,3 +277,20 @@ DOT_CLEANUP = YES # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO + +ALIASES = "type{1}= \1 :" \ + "types{2}= \1 or \2 :" \ + "types{3}= \1 , \2 , or \3 :" \ + "arrayof{2}= Array of \2" \ + "null=\type{Null}" \ + "boolean=\type{Boolean}" \ + "bool=\boolean" \ + "integer=\type{Integer}" \ + "int=\integer" \ + "string=\type{String}" \ + "str=\string" \ + "mixed=\type{Mixed}" \ + "access=\par Access:\n" \ + "private=\access private" \ + "protected=\access protected" \ + "public=\access public" \ No newline at end of file diff --git a/maintenance/FiveUpgrade.inc b/maintenance/FiveUpgrade.inc index 7ae8f5d0..5632241a 100644 --- a/maintenance/FiveUpgrade.inc +++ b/maintenance/FiveUpgrade.inc @@ -20,8 +20,9 @@ class FiveUpgrade { function FiveUpgrade() { $this->conversionTables = $this->prepareWindows1252(); - $this->dbw =& $this->newConnection(); - $this->dbr =& $this->streamConnection(); + $this->loadBalancers = array(); + $this->dbw = wfGetDB( DB_MASTER ); + $this->dbr = $this->streamConnection(); $this->cleanupSwaps = array(); $this->emailAuth = false; # don't preauthenticate emails @@ -67,13 +68,23 @@ class FiveUpgrade { * @return Database * @access private */ - function &newConnection() { - global $wgDBadminuser, $wgDBadminpassword, $wgDBtype; - global $wgDBserver, $wgDBname; - $dbclass = 'Database' . ucfirst( $wgDBtype ) ; - $db = new $dbclass( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname ); + function newConnection() { + $lb = wfGetLBFactory()->newMainLB(); + $db = $lb->getConnection( DB_MASTER ); + + $this->loadBalancers[] = $lb; return $db; } + + /** + * Commit transactions and close the connections when we're done... + */ + function close() { + foreach( $this->loadBalancers as $lb ) { + $lb->commitMasterChanges(); + $lb->closeAll(); + } + } /** * Open a second connection to the master server, with buffering off. @@ -82,13 +93,13 @@ class FiveUpgrade { * @return Database * @access private */ - function &streamConnection() { + function streamConnection() { global $wgDBtype; $timeout = 3600 * 24; $db =& $this->newConnection(); $db->bufferResults( false ); - if ($wgDBtype == 'mysql') { + if ($wgDBtype == 'mysql') { $db->query( "SET net_read_timeout=$timeout" ); $db->query( "SET net_write_timeout=$timeout" ); } @@ -877,17 +888,17 @@ END; $add = array(); while( $row = $this->dbr->fetchObject( $result ) ) { $add[] = array( - 'wl_user' => $row->wl_user, - 'wl_namespace' => Namespace::getSubject( $row->wl_namespace ), - 'wl_title' => $this->conv( $row->wl_title ), - 'wl_notificationtimestamp' => '0' ); + 'wl_user' => $row->wl_user, + 'wl_namespace' => MWNamespace::getSubject( $row->wl_namespace ), + 'wl_title' => $this->conv( $row->wl_title ), + 'wl_notificationtimestamp' => '0' ); $this->addChunk( $add ); $add[] = array( - 'wl_user' => $row->wl_user, - 'wl_namespace' => Namespace::getTalk( $row->wl_namespace ), - 'wl_title' => $this->conv( $row->wl_title ), - 'wl_notificationtimestamp' => '0' ); + 'wl_user' => $row->wl_user, + 'wl_namespace' => MWNamespace::getTalk( $row->wl_namespace ), + 'wl_title' => $this->conv( $row->wl_title ), + 'wl_notificationtimestamp' => '0' ); $this->addChunk( $add ); } $this->lastChunk( $add ); @@ -988,7 +999,7 @@ CREATE TABLE $1 ( -- Filename of target image. -- This is also the page_title of the file's description page; - -- all such pages are in namespace 6 (NS_IMAGE). + -- all such pages are in namespace 6 (NS_FILE). il_to varchar(255) binary NOT NULL default '', UNIQUE KEY il_from(il_from,il_to), diff --git a/maintenance/addwiki.php b/maintenance/addwiki.php index b9c48506..ebe52f2e 100644 --- a/maintenance/addwiki.php +++ b/maintenance/addwiki.php @@ -49,6 +49,7 @@ function addWiki( $lang, $site, $dbName ) dbsource( "$IP/extensions/CheckUser/cu_log.sql", $dbw ); dbsource( "$IP/extensions/TitleKey/titlekey.sql", $dbw ); dbsource( "$IP/extensions/Oversight/hidden.sql", $dbw ); + dbsource( "$IP/extensions/GlobalBlocking/localdb_patches/setup-global_block_whitelist.sql", $dbw ); $dbw->query( "INSERT INTO site_stats(ss_row_id) VALUES (1)" ); diff --git a/maintenance/archives/patch-ipb_allow_usertalk.sql b/maintenance/archives/patch-ipb_allow_usertalk.sql new file mode 100644 index 00000000..92e7d9a4 --- /dev/null +++ b/maintenance/archives/patch-ipb_allow_usertalk.sql @@ -0,0 +1,3 @@ +-- Adding ipb_allow_usertalk for blocks +ALTER TABLE /*$wgDBprefix*/ipblocks + ADD ipb_allow_usertalk bool NOT NULL default 1; diff --git a/maintenance/archives/patch-linktables.sql b/maintenance/archives/patch-linktables.sql index ae9768a8..b15878c3 100644 --- a/maintenance/archives/patch-linktables.sql +++ b/maintenance/archives/patch-linktables.sql @@ -49,7 +49,7 @@ CREATE TABLE /*$wgDBprefix*/imagelinks ( -- Filename of target image. -- This is also the page_title of the file's description page; - -- all such pages are in namespace 6 (NS_IMAGE). + -- all such pages are in namespace 6 (NS_FILE). il_to varchar(255) binary NOT NULL default '', UNIQUE KEY il_from(il_from,il_to), diff --git a/maintenance/archives/patch-log_user_text.sql b/maintenance/archives/patch-log_user_text.sql new file mode 100644 index 00000000..f89a35f6 --- /dev/null +++ b/maintenance/archives/patch-log_user_text.sql @@ -0,0 +1,5 @@ +ALTER TABLE /*$wgDBprefix*/logging + ADD log_user_text varchar(255) binary NOT NULL default '', + ADD log_target_id int unsigned NULL, + CHANGE `log_type` `log_type` VARBINARY( 15 ) NOT NULL, + CHANGE `log_action` `log_action` VARBINARY( 15 ) NOT NULL; diff --git a/maintenance/archives/patch-ss_active_users.sql b/maintenance/archives/patch-ss_active_users.sql new file mode 100644 index 00000000..a583cdc8 --- /dev/null +++ b/maintenance/archives/patch-ss_active_users.sql @@ -0,0 +1,3 @@ +-- More statistics, for version 1.14 + +ALTER TABLE /*$wgDBprefix*/site_stats ADD ss_active_users bigint default '-1'; diff --git a/maintenance/backup.inc b/maintenance/backup.inc index bf52c1f3..e2e5363e 100644 --- a/maintenance/backup.inc +++ b/maintenance/backup.inc @@ -175,7 +175,7 @@ class BackupDumper { // extension point for subclasses to add options } - function dump( $history, $text = MW_EXPORT_TEXT ) { + function dump( $history, $text = WikiExporter::TEXT ) { # Notice messages will foul up your XML output even if they're # relatively harmless. if( ini_get( 'display_errors' ) ) @@ -192,13 +192,21 @@ class BackupDumper { if( !$this->skipHeader ) $exporter->openStream(); - - if( is_null( $this->pages ) ) { + # Log item dumps: all or by range + if( $history & WikiExporter::LOGS ) { + if( $this->startId || $this->endId ) { + $exporter->logsByRange( $this->startId, $this->endId ); + } else { + $exporter->allLogs(); + } + # Page dumps: all or by page ID range + } else if( is_null( $this->pages ) ) { if( $this->startId || $this->endId ) { $exporter->pagesByRange( $this->startId, $this->endId ); } else { $exporter->allPages(); } + # Dump of specific pages } else { $exporter->pagesByName( $this->pages ); } diff --git a/maintenance/benchmarkPurge.php b/maintenance/benchmarkPurge.php index 76302a01..796e1da2 100644 --- a/maintenance/benchmarkPurge.php +++ b/maintenance/benchmarkPurge.php @@ -9,7 +9,12 @@ /** */ require_once( "commandLine.inc" ); -/** @todo document */ +/** + * 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? + */ function benchSquid( $urls, $trials = 1 ) { $start = wfTime(); for( $i = 0; $i < $trials; $i++) { @@ -22,7 +27,10 @@ function benchSquid( $urls, $trials = 1 ) { count( $urls ), $pertrial * 1000.0, $pertitle * 1000.0 ); } -/** @todo document */ +/** + * Get an array of randomUrl()'s. + * @param $length int How many urls to add to the array + */ function randomUrlList( $length ) { $list = array(); for( $i = 0; $i < $length; $i++ ) { @@ -31,13 +39,19 @@ function randomUrlList( $length ) { return $list; } -/** @todo document */ +/** + * Return a random URL of the wiki. Not necessarily an actual title in the + * database, but at least a URL that looks like one. + */ function randomUrl() { global $wgServer, $wgArticlePath; return $wgServer . str_replace( '$1', randomTitle(), $wgArticlePath ); } -/** @todo document */ +/** + * Create a random title string (not necessarily a Title object). + * For use with randomUrl(). + */ function randomTitle() { $str = ''; $length = mt_rand( 1, 20 ); diff --git a/maintenance/checkAutoLoader.php b/maintenance/checkAutoLoader.php index c2909ef7..554395ca 100644 --- a/maintenance/checkAutoLoader.php +++ b/maintenance/checkAutoLoader.php @@ -3,17 +3,24 @@ if ( php_sapi_name() != 'cli' ) exit; $IP = dirname(__FILE__) .'/..'; require( "$IP/includes/AutoLoader.php" ); -$files = array_unique( AutoLoader::$localClasses ); +$files = array_unique( $wgAutoloadLocalClasses ); foreach ( $files as $file ) { - $parseInfo = parsekit_compile_file( "$IP/$file" ); - $classes = array_keys( $parseInfo['class_table'] ); + if( function_exists( 'parsekit_compile_file' ) ){ + $parseInfo = parsekit_compile_file( "$IP/$file" ); + $classes = array_keys( $parseInfo['class_table'] ); + } else { + $contents = file_get_contents( "$IP/$file" ); + $m = array(); + preg_match_all( '/\n\s*class\s+([a-zA-Z0-9_]+)/', $contents, $m, PREG_PATTERN_ORDER ); + $classes = $m[1]; + } foreach ( $classes as $class ) { - if ( !isset( AutoLoader::$localClasses[$class] ) ) { + if ( !isset( $wgAutoloadLocalClasses[$class] ) ) { //printf( "%-50s Unlisted, in %s\n", $class, $file ); echo " '$class' => '$file',\n"; - } elseif ( AutoLoader::$localClasses[$class] !== $file ) { - echo "$class: Wrong file: found in $file, listed in " . AutoLoader::$localClasses[$class] . "\n"; + } elseif ( $wgAutoloadLocalClasses[$class] !== $file ) { + echo "$class: Wrong file: found in $file, listed in " . $wgAutoloadLocalClasses[$class] . "\n"; } } diff --git a/maintenance/checkBadRedirects.php b/maintenance/checkBadRedirects.php new file mode 100644 index 00000000..48a4b0e6 --- /dev/null +++ b/maintenance/checkBadRedirects.php @@ -0,0 +1,30 @@ +select( + array( 'page' ), + array( 'page_namespace','page_title', 'page_latest' ), + array( 'page_is_redirect' => 1 ) ); + +$count = $result->numRows(); +echo "Found $count total redirects.\n"; +echo "Looking for bad redirects:\n"; +echo "\n"; + +foreach( $result as $row ) { + $title = Title::makeTitle( $row->page_namespace, $row->page_title ); + $rev = Revision::newFromId( $row->page_latest ); + if( $rev ) { + $target = Title::newFromRedirect( $rev->getText() ); + if( !$target ) { + echo $title->getPrefixedText(); + echo "\n"; + } + } +} + +echo "\n"; +echo "done.\n"; diff --git a/maintenance/checkImages.php b/maintenance/checkImages.php new file mode 100644 index 00000000..994cd5b9 --- /dev/null +++ b/maintenance/checkImages.php @@ -0,0 +1,45 @@ +getLocalRepo(); + +$numImages = 0; +$numGood = 0; + +do { + $res = $dbr->select( 'image', '*', array( 'img_name > ' . $dbr->addQuotes( $start ) ) ); + foreach ( $res as $row ) { + $numImages++; + $start = $row->img_name; + $file = $localRepo->newFileFromRow( $row ); + $path = $file->getPath(); + if ( !$path ) { + echo "{$row->img_name}: not locally accessible\n"; + continue; + } + $stat = @stat( $file->getPath() ); + if ( !$stat ) { + echo "{$row->img_name}: missing\n"; + continue; + } + + if ( $stat['size'] == 0 && $row->img_size != 0 ) { + echo "{$row->img_name}: truncated, was {$row->img_size}\n"; + continue; + } + + if ( $stat['size'] != $row->img_size ) { + echo "{$row->img_name}: size mismatch DB={$row->img_size}, actual={$stat['size']}\n"; + continue; + } + + $numGood++; + } + +} while ( $res->numRows() ); + +echo "Good images: $numGood/$numImages\n"; diff --git a/maintenance/cleanupImages.php b/maintenance/cleanupImages.php index 79ff54e8..00903f22 100644 --- a/maintenance/cleanupImages.php +++ b/maintenance/cleanupImages.php @@ -54,6 +54,9 @@ class ImageCleanup extends TableCleanup { // About half of old bad image names have percent-codes $cleaned = rawurldecode( $cleaned ); + + // We also have some HTML entities there + $cleaned = Sanitizer::decodeCharReferences( $cleaned ); // Some are old latin-1 $cleaned = $wgContLang->checkTitleEncoding( $cleaned ); @@ -61,11 +64,13 @@ class ImageCleanup extends TableCleanup { // Many of remainder look like non-normalized unicode $cleaned = UtfNormal::cleanUp( $cleaned ); - $title = Title::makeTitleSafe( NS_IMAGE, $cleaned ); + $title = Title::makeTitleSafe( NS_FILE, $cleaned ); if( is_null( $title ) ) { $this->log( "page $source ($cleaned) is illegal." ); $safe = $this->buildSafeTitle( $cleaned ); + if( $safe === false ) + return $this->progress( 0 ); $this->pokeFile( $source, $safe ); return $this->progress( 1 ); } @@ -110,8 +115,8 @@ class ImageCleanup extends TableCleanup { $version = 0; $final = $new; - while( $db->selectField( 'image', 'img_name', - array( 'img_name' => $final ), __METHOD__ ) ) { + while( $db->selectField( 'image', 'img_name', array( 'img_name' => $final ), __METHOD__ ) || + Title::makeTitle( NS_FILE, $final )->exists() ) { $this->log( "Rename conflicts with '$final'..." ); $version++; $final = $this->appendTitle( $new, "_$version" ); @@ -123,14 +128,23 @@ class ImageCleanup extends TableCleanup { $this->log( "DRY RUN: would rename $path to $finalPath" ); } else { $this->log( "renaming $path to $finalPath" ); + // XXX: should this use File::move()? FIXME? $db->begin(); $db->update( 'image', array( 'img_name' => $final ), array( 'img_name' => $orig ), __METHOD__ ); + $db->update( 'oldimage', + array( 'oi_name' => $final ), + array( 'oi_name' => $orig ), + __METHOD__ ); + $db->update( 'page', + array( 'page_title' => $final ), + array( 'page_title' => $orig, 'page_namespace' => NS_FILE ), + __METHOD__ ); $dir = dirname( $finalPath ); if( !file_exists( $dir ) ) { - if( !mkdir( $dir, 0777, true ) ) { + if( !wfMkdirParents( $dir ) ) { $this->log( "RENAME FAILED, COULD NOT CREATE $dir" ); $db->rollback(); return; @@ -153,11 +167,11 @@ class ImageCleanup extends TableCleanup { function buildSafeTitle( $name ) { global $wgLegalTitleChars; $x = preg_replace_callback( - "/([^$wgLegalTitleChars])/", + "/([^$wgLegalTitleChars]|~)/", array( $this, 'hexChar' ), $name ); - $test = Title::makeTitleSafe( NS_IMAGE, $x ); + $test = Title::makeTitleSafe( NS_FILE, $x ); if( is_null( $test ) || $test->getDBkey() !== $x ) { $this->log( "Unable to generate safe title from '$name', got '$x'" ); return false; diff --git a/maintenance/cleanupTitles.php b/maintenance/cleanupTitles.php index a6991829..4d76ac7a 100644 --- a/maintenance/cleanupTitles.php +++ b/maintenance/cleanupTitles.php @@ -48,19 +48,30 @@ class TitleCleanup extends TableCleanup { $title = Title::newFromText( $verified ); - if( is_null( $title ) ) { + if( !is_null( $title ) && $title->equals( $current ) && $title->canExist() ) { + return $this->progress( 0 ); // all is fine + } + + if( $row->page_namespace == NS_FILE && $this->fileExists( $row->page_title ) ) { + $this->log( "file $row->page_title needs cleanup, please run cleanupImages.php." ); + return $this->progress( 0 ); + } elseif( is_null( $title ) ) { $this->log( "page $row->page_id ($display) is illegal." ); $this->moveIllegalPage( $row ); return $this->progress( 1 ); - } - - if( !$title->equals( $current ) ) { + } else { $this->log( "page $row->page_id ($display) doesn't match self." ); $this->moveInconsistentPage( $row, $title ); return $this->progress( 1 ); } + } - $this->progress( 0 ); + function fileExists( $name ) { + // XXX: Doesn't actually check for file existence, just presence of image record. + // This is reasonable, since cleanupImages.php only iterates over the image table. + $dbr = wfGetDB( DB_SLAVE ); + $row = $dbr->selectRow( 'image', array( 'img_name' ), array( 'img_name' => $name ), __METHOD__ ); + return $row !== false; } function moveIllegalPage( $row ) { diff --git a/maintenance/deleteBatch.php b/maintenance/deleteBatch.php index d10948a0..5aeea781 100644 --- a/maintenance/deleteBatch.php +++ b/maintenance/deleteBatch.php @@ -2,9 +2,10 @@ /** * Deletes a batch of pages - * Usage: php deleteBatch.php [-u ] [-r ] [-i ] + * Usage: php deleteBatch.php [-u ] [-r ] [-i ] [listfile] * where - * is a file where each line contains the title of a page to be deleted. + * [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. * is the username * is the delete reason * is the number of seconds to sleep for after each delete @@ -70,7 +71,7 @@ for ( $linenum = 1; !feof( $file ); $linenum++ ) { print $page->getPrefixedText(); $dbw->begin(); - if( $page->getNamespace() == NS_IMAGE ) { + if( $page->getNamespace() == NS_FILE ) { $art = new ImagePage( $page ); $img = wfFindFile( $art->mTitle ); if( !$img || !$img->delete( $reason ) ) { diff --git a/maintenance/dumpBackup.php b/maintenance/dumpBackup.php index bb431242..de7ce655 100644 --- a/maintenance/dumpBackup.php +++ b/maintenance/dumpBackup.php @@ -63,6 +63,8 @@ if( isset( $options['full'] ) ) { $dumper->dump( WikiExporter::FULL, $textMode ); } elseif( isset( $options['current'] ) ) { $dumper->dump( WikiExporter::CURRENT, $textMode ); +} elseif( isset( $options['logs'] ) ) { + $dumper->dump( WikiExporter::LOGS ); } else { $dumper->progress( << [] Actions: --full Dump complete history of every page. --current Includes only the latest revision of each page. + --logs Dump action logs for every page. Options: --quiet Don't dump status reports to stderr. diff --git a/maintenance/dumpTextPass.php b/maintenance/dumpTextPass.php index eb4cc072..e85fe421 100644 --- a/maintenance/dumpTextPass.php +++ b/maintenance/dumpTextPass.php @@ -487,7 +487,7 @@ class TextPassDumper extends BackupDumper { function clearOpenElement( $style ) { if( $this->openElement ) { - $this->buffer .= wfElement( $this->openElement[0], $this->openElement[1], $style ); + $this->buffer .= Xml::element( $this->openElement[0], $this->openElement[1], $style ); $this->openElement = false; } } diff --git a/maintenance/edit.php b/maintenance/edit.php index 037f9a9a..64178045 100644 --- a/maintenance/edit.php +++ b/maintenance/edit.php @@ -58,15 +58,20 @@ $text = file_get_contents( 'php://stdin' ); # Do the edit print "Saving... "; -$success = $wgArticle->doEdit( $text, $summary, +$status = $wgArticle->doEdit( $text, $summary, ( $minor ? EDIT_MINOR : 0 ) | ( $bot ? EDIT_FORCE_BOT : 0 ) | ( $autoSummary ? EDIT_AUTOSUMMARY : 0 ) | ( $noRC ? EDIT_SUPPRESS_RC : 0 ) ); -if ( $success ) { +if ( $status->isOK() ) { print "done\n"; + $exit = 0; } else { print "failed\n"; - exit( 1 ); + $exit = 1; +} +if ( !$status->isGood() ) { + print $status->getWikiText() . "\n"; } +exit( $exit ); diff --git a/maintenance/findhooks.php b/maintenance/findhooks.php index 7a2ba53f..d7cad253 100644 --- a/maintenance/findhooks.php +++ b/maintenance/findhooks.php @@ -31,6 +31,7 @@ $pathinc = array( $IP.'/includes/', $IP.'/includes/api/', $IP.'/includes/db/', + $IP.'/includes/diff/', $IP.'/includes/filerepo/', $IP.'/includes/parser/', $IP.'/includes/specials/', diff --git a/maintenance/generateSitemap.php b/maintenance/generateSitemap.php index cc3f523a..52dc33ae 100644 --- a/maintenance/generateSitemap.php +++ b/maintenance/generateSitemap.php @@ -80,8 +80,8 @@ class GenerateSitemap { NS_USER_TALK => '0.1', NS_PROJECT => '0.5', NS_PROJECT_TALK => '0.1', - NS_IMAGE => '0.5', - NS_IMAGE_TALK => '0.1', + NS_FILE => '0.5', + NS_FILE_TALK => '0.1', NS_MEDIAWIKI => '0.0', NS_MEDIAWIKI_TALK => '0.1', NS_TEMPLATE => '0.0', @@ -424,7 +424,7 @@ class GenerateSitemap { * * @static * - * @param string $url An RFC 2396 compilant URL + * @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 * diff --git a/maintenance/importDump.php b/maintenance/importDump.php index 99e69ce8..eb51126a 100644 --- a/maintenance/importDump.php +++ b/maintenance/importDump.php @@ -48,13 +48,10 @@ class BackupReader { function handleRevision( $rev ) { $title = $rev->getTitle(); - if (!$title) { + if( !$title ) { $this->progress( "Got bogus revision with null title!" ); return; } - #$timestamp = $rev->getTimestamp(); - #$display = $title->getPrefixedText(); - #echo "$display $timestamp\n"; $this->revCount++; $this->report(); @@ -79,6 +76,15 @@ class BackupReader { } } + function handleLogItem( $rev ) { + $this->revCount++; + $this->report(); + + if( !$this->dryRun ) { + call_user_func( $this->logItemCallback, $rev ); + } + } + function report( $final = false ) { if( $final xor ( $this->pageCount % $this->reportingInterval == 0 ) ) { $this->showReport(); @@ -95,7 +101,11 @@ class BackupReader { $rate = '-'; $revrate = '-'; } - $this->progress( "$this->pageCount ($rate pages/sec $revrate revs/sec)" ); + # Logs dumps don't have page tallies + if( $this->pageCount ) + $this->progress( "$this->pageCount ($rate pages/sec $revrate revs/sec)" ); + else + $this->progress( "$this->revCount ($revrate revs/sec)" ); } wfWaitForSlaves(5); } @@ -129,6 +139,8 @@ class BackupReader { array( &$this, 'handleRevision' ) ); $this->uploadCallback = $importer->setUploadCallback( array( &$this, 'handleUpload' ) ); + $this->logItemCallback = $importer->setLogItemCallback( + array( &$this, 'handleLogItem' ) ); return $importer->doImport(); } diff --git a/maintenance/importImages.inc.php b/maintenance/importImages.inc.php index 53895778..290f3c07 100644 --- a/maintenance/importImages.inc.php +++ b/maintenance/importImages.inc.php @@ -46,4 +46,43 @@ function splitFilename( $filename ) { unset( $parts[ count( $parts ) - 1 ] ); $fname = implode( '.', $parts ); return array( $fname, $ext ); +} + +/** + * Find an auxilliary file with the given extension, matching + * the give base file path. $maxStrip determines how many extensions + * may be stripped from the original file name before appending the + * new extension. For example, with $maxStrip = 1 (the default), + * file files acme.foo.bar.txt and acme.foo.txt would be auxilliary + * files for acme.foo.bar and the extension ".txt". With $maxStrip = 2, + * acme.txt would also be acceptable. + * + * @param $file base path + * @param $auxExtension the extension to be appended to the base path + * @param $maxStrip the maximum number of extensions to strip from the base path (default: 1) + * @return string or false + */ +function findAuxFile( $file, $auxExtension, $maxStrip = 1 ) { + if ( strpos( $auxExtension, '.' ) !== 0 ) { + $auxExtension = '.' . $auxExtension; + } + + $d = dirname( $file ); + $n = basename( $file ); + + while ( $maxStrip >= 0 ) { + $f = $d . '/' . $n . $auxExtension; + + if ( file_exists( $f ) ) { + return $f; + } + + $idx = strrpos( $n, '.' ); + if ( !$idx ) break; + + $n = substr( $n, 0, $idx ); + $maxStrip -= 1; + } + + return false; } \ No newline at end of file diff --git a/maintenance/importImages.php b/maintenance/importImages.php index 63bbec5f..4c6082b2 100644 --- a/maintenance/importImages.php +++ b/maintenance/importImages.php @@ -9,7 +9,7 @@ * @author Rob Church */ -$optionsWithArguments = array( 'extensions', 'overwrite' ); +$optionsWithArgs = array( 'extensions', 'comment', 'comment-file', 'comment-ext', 'user', 'license' ); require_once( 'commandLine.inc' ); require_once( 'importImages.inc.php' ); $added = $skipped = $overwritten = 0; @@ -39,9 +39,19 @@ if( count( $args ) > 0 ) { $wgUser = $user; # Get the upload comment - $comment = isset( $options['comment'] ) - ? $options['comment'] - : 'Importing image file'; + $comment = 'Importing image file'; + + if ( isset( $options['comment-file'] ) ) { + $comment = file_get_contents( $options['comment-file'] ); + if ( $comment === false || $comment === NULL ) { + die( "failed to read comment file: {$options['comment-file']}\n" ); + } + } + else if ( isset( $options['comment'] ) ) { + $comment = $options['comment']; + } + + $commentExt = isset( $options['comment-ext'] ) ? $options['comment-ext'] : false; # Get the license specifier $license = isset( $options['license'] ) ? $options['license'] : ''; @@ -53,7 +63,7 @@ if( count( $args ) > 0 ) { $base = wfBaseName( $file ); # Validate a title - $title = Title::makeTitleSafe( NS_IMAGE, $base ); + $title = Title::makeTitleSafe( NS_FILE, $base ); if( !is_object( $title ) ) { echo( "{$base} could not be imported; a valid title cannot be produced\n" ); continue; @@ -75,15 +85,40 @@ if( count( $args ) > 0 ) { $svar = 'added'; } + # Find comment text + $commentText = false; + + if ( $commentExt ) { + $f = findAuxFile( $file, $commentExt ); + if ( !$f ) { + echo( " No comment file with extension {$commentExt} found for {$file}, using default comment. " ); + } else { + $commentText = file_get_contents( $f ); + if ( !$f ) { + echo( " Failed to load comment file {$f}, using default comment. " ); + } + } + } + + if ( !$commentText ) { + $commentText = $comment; + } + # Import the file - $archive = $image->publish( $file ); - if( WikiError::isError( $archive ) || !$archive->isGood() ) { - echo( "failed.\n" ); - continue; + if ( isset( $options['dry'] ) ) { + echo( " publishing {$file}... " ); + } else { + $archive = $image->publish( $file ); + if( WikiError::isError( $archive ) || !$archive->isGood() ) { + echo( "failed.\n" ); + continue; + } } $$svar++; - if ( $image->recordUpload( $archive->value, $comment, $license ) ) { + if ( isset( $options['dry'] ) ) { + echo( "done.\n" ); + } else if ( $image->recordUpload( $archive->value, $commentText, $license ) ) { # We're done! echo( "done.\n" ); } else { @@ -123,10 +158,14 @@ USAGE: php importImages.php [options] Options: --extensions= Comma-separated list of allowable extensions, defaults to \$wgFileExtensions ---overwrite Overwrite existing images if a conflicting-named image is found +--overwrite Overwrite existing images if a conflicting-named image is found --user= Set username of uploader, default 'Maintenance script' --comment= Set upload summary comment, default 'Importing image file' +--comment-file= Set upload summary comment the the content of . +--comment-ext= Causes the comment for each file to be loaded from a file with the same name + but the extension . --license= Use an optional license template +--dry Dry run, don't import anything END; exit(); diff --git a/maintenance/importTextFile.php b/maintenance/importTextFile.php index 5004c3c0..0a0068d7 100644 --- a/maintenance/importTextFile.php +++ b/maintenance/importTextFile.php @@ -24,19 +24,19 @@ if( count( $args ) < 1 || isset( $options['help'] ) ) { $title = isset( $options['title'] ) ? $options['title'] : titleFromFilename( $filename ); $title = Title::newFromUrl( $title ); - echo( "\nUsing title '" . $title->getPrefixedText() . "'..." ); if( is_object( $title ) ) { + echo( "\nUsing title '" . $title->getPrefixedText() . "'..." ); if( !$title->exists() || !isset( $options['nooverwrite'] ) ) { $text = file_get_contents( $filename ); $user = isset( $options['user'] ) ? $options['user'] : 'Maintenance script'; $user = User::newFromName( $user ); - echo( "\nUsing username '" . $user->getName() . "'..." ); 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 ); diff --git a/maintenance/interwiki.sql b/maintenance/interwiki.sql index c8e088f5..2521d381 100644 --- a/maintenance/interwiki.sql +++ b/maintenance/interwiki.sql @@ -8,22 +8,16 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('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), -('codersbase','http://www.codersbase.com/index.php/$1',0), # 2008-02-27: Fatal error ('commons','http://commons.wikimedia.org/wiki/$1',0), ('corpknowpedia','http://corpknowpedia.org/wiki/index.php/$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), +('doi','http://dx.doi.org/$1',0), ('drumcorpswiki','http://www.drumcorpswiki.com/index.php/$1',0), ('dwjwiki','http://www.suberic.net/cgi-bin/dwj/wiki.cgi?$1',0), -('efnetceewiki','http://purl.net/wiki/c/$1',0), # 2008-02-27: does not appear to be working -('efnetcppwiki','http://purl.net/wiki/cpp/$1',0), # 2008-02-27: does not appear to be working -('efnetpythonwiki','http://purl.net/wiki/python/$1',0), # 2008-02-27: does not appear to be working -('efnetxmlwiki','http://purl.net/wiki/xml/$1',0), # 2008-02-27: does not appear to be working -('eljwiki','http://elj.sourceforge.net/phpwiki/index.php/$1',0), # 2008-02-27: Fatal PhpWiki Error ('emacswiki','http://www.emacswiki.org/cgi-bin/wiki.pl?$1',0), ('elibre','http://enciclopedia.us.es/index.php/$1',0), -('eokulturcentro','http://esperanto.toulouse.free.fr/wakka.php?wiki=$1',0), # 2007-02-27: no access to database ('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), @@ -31,12 +25,10 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('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), -('gotamac','http://www.got-a-mac.org/$1',0), # 2008-02-27: appears ill maintained; loads of spambots ('hammondwiki','http://www.dairiki.org/HammondWiki/$1',0), ('hewikisource','http://he.wikisource.org/wiki/$1',1), ('hrwiki','http://www.hrwiki.org/index.php/$1',0), ('imdb','http://us.imdb.com/Title?$1',0), -('infosecpedia','http://www.infosecpedia.org/pedia/index.php/$1',0), # 2008-02-27: lot of spambot activity ('jargonfile','http://sunir.org/apps/meta.pl?wiki=JargonFile&redirect=$1',0), ('jspwiki','http://www.jspwiki.org/wiki/$1',0), ('keiki','http://kei.ki/en/$1',0), @@ -57,7 +49,6 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local) VALUES ('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), -('orgpatterns','http://www.bell-labs.com/cgi-user/OrgPatterns/OrgPatterns?$1',0), # 2008-02-27: may not be working. Please double check ('patwiki','http://gauss.ffii.org/$1',0), # 2008-02-27: lots of spambots ('pmeg','http://www.bertilow.com/pmeg/$1.php',0), ('ppr','http://c2.com/cgi/wiki?$1',0), diff --git a/maintenance/language/checkLanguage.inc b/maintenance/language/checkLanguage.inc index 2cfd1b04..52281b57 100644 --- a/maintenance/language/checkLanguage.inc +++ b/maintenance/language/checkLanguage.inc @@ -13,41 +13,36 @@ class CheckLanguageCLI { protected $checks = array(); protected $L = null; - protected $defaultChecks = array( - 'untranslated', 'obsolete', 'variables', 'empty', 'plural', - 'whitespace', 'xhtml', 'chars', 'links', 'unbalanced' - ); - protected $results = array(); private $includeExif = false; /** - * GLOBALS: $wgLanguageCode; + * Constructor. + * @param $options Options for script. */ public function __construct( Array $options ) { - if ( isset( $options['help'] ) ) { echo $this->help(); exit(); } - if ( isset($options['lang']) ) { + if ( isset( $options['lang'] ) ) { $this->code = $options['lang']; } else { global $wgLanguageCode; $this->code = $wgLanguageCode; } - if ( isset($options['level']) ) { + if ( isset( $options['level'] ) ) { $this->level = $options['level']; } - $this->doLinks = isset($options['links']); - $this->includeExif = !isset($options['noexif']); - $this->checkAll = isset($options['all']); + $this->doLinks = isset( $options['links'] ); + $this->includeExif = !isset( $options['noexif'] ); + $this->checkAll = isset( $options['all'] ); - if ( isset($options['wikilang']) ) { + if ( isset( $options['wikilang'] ) ) { $this->wikiCode = $options['wikilang']; } @@ -55,57 +50,136 @@ class CheckLanguageCLI { $this->checks = explode( ',', $options['whitelist'] ); } elseif ( isset( $options['blacklist'] ) ) { $this->checks = array_diff( - $this->defaultChecks, + isset( $options['easy'] ) ? $this->easyChecks() : $this->defaultChecks(), explode( ',', $options['blacklist'] ) ); + } elseif ( isset( $options['easy'] ) ) { + $this->checks = $this->easyChecks(); } else { - $this->checks = $this->defaultChecks; + $this->checks = $this->defaultChecks(); } - if ( isset($options['output']) ) { + if ( isset( $options['output'] ) ) { $this->output = $options['output']; } - # Some additional checks not enabled by default - if ( isset( $options['duplicate'] ) ) { - $this->checks[] = 'duplicate'; - } - $this->L = new languages( $this->includeExif ); } + /** + * Get the default checks. + * @return A list of the default checks. + */ + protected function defaultChecks() { + return array( + 'untranslated', 'duplicate', 'obsolete', 'variables', 'empty', 'plural', + 'whitespace', 'xhtml', 'chars', 'links', 'unbalanced', 'namespace', + 'projecttalk', 'magic', 'magic-old', 'magic-over', 'magic-case', + 'special', 'special-old', + ); + } + + /** + * Get the checks which check other things than messages. + * @return A list of the non-message checks. + */ + protected function nonMessageChecks() { + return array( + 'namespace', 'projecttalk', 'magic', 'magic-old', 'magic-over', + 'magic-case', 'special', 'special-old', + ); + } + + /** + * Get the checks that can easily be treated by non-speakers of the language. + * @return A list of the easy checks. + */ + protected function easyChecks() { + return array( + 'duplicate', 'obsolete', 'empty', 'whitespace', 'xhtml', 'chars', 'magic-old', + 'magic-over', 'magic-case', 'special-old', + ); + } + + /** + * Get all checks. + * @return An array of all check names mapped to their function names. + */ protected function getChecks() { - $checks = array(); - $checks['untranslated'] = 'getUntranslatedMessages'; - $checks['duplicate'] = 'getDuplicateMessages'; - $checks['obsolete'] = 'getObsoleteMessages'; - $checks['variables'] = 'getMessagesWithoutVariables'; - $checks['plural'] = 'getMessagesWithoutPlural'; - $checks['empty'] = 'getEmptyMessages'; - $checks['whitespace'] = 'getMessagesWithWhitespace'; - $checks['xhtml'] = 'getNonXHTMLMessages'; - $checks['chars'] = 'getMessagesWithWrongChars'; - $checks['links'] = 'getMessagesWithDubiousLinks'; - $checks['unbalanced'] = 'getMessagesWithUnbalanced'; - return $checks; + return array( + 'untranslated' => 'getUntranslatedMessages', + 'duplicate' => 'getDuplicateMessages', + 'obsolete' => 'getObsoleteMessages', + 'variables' => 'getMessagesWithMismatchVariables', + 'plural' => 'getMessagesWithoutPlural', + 'empty' => 'getEmptyMessages', + 'whitespace' => 'getMessagesWithWhitespace', + 'xhtml' => 'getNonXHTMLMessages', + 'chars' => 'getMessagesWithWrongChars', + 'links' => 'getMessagesWithDubiousLinks', + 'unbalanced' => 'getMessagesWithUnbalanced', + 'namespace' => 'getUntranslatedNamespaces', + 'projecttalk' => 'getProblematicProjectTalks', + 'magic' => 'getUntranslatedMagicWords', + 'magic-old' => 'getObsoleteMagicWords', + 'magic-over' => 'getOverridingMagicWords', + 'magic-case' => 'getCaseMismatchMagicWords', + 'special' => 'getUntraslatedSpecialPages', + 'special-old' => 'getObsoleteSpecialPages', + ); + } + + /** + * Get total count for each check non-messages check. + * @return An array of all check names mapped to a two-element array: + * function name to get the total count and language code or null + * for checked code. + */ + protected function getTotalCount() { + return array( + 'namespace' => array( 'getNamespaceNames', 'en' ), + 'projecttalk' => null, + 'magic' => array( 'getMagicWords', 'en' ), + 'magic-old' => array( 'getMagicWords', null ), + 'magic-over' => array( 'getMagicWords', null ), + 'magic-case' => array( 'getMagicWords', null ), + 'special' => array( 'getSpecialPageAliases', 'en' ), + 'special-old' => array( 'getSpecialPageAliases', null ), + ); } + /** + * Get all check descriptions. + * @return An array of all check names mapped to their descriptions. + */ protected function getDescriptions() { - $descriptions = array(); - $descriptions['untranslated'] = '$1 message(s) of $2 are not translated to $3, but exist in en:'; - $descriptions['duplicate'] = '$1 message(s) of $2 are translated the same in en and $3:'; - $descriptions['obsolete'] = '$1 message(s) of $2 do not exist in en or are in the ignore list, but are in $3'; - $descriptions['variables'] = '$1 message(s) of $2 in $3 don\'t use some variables that en uses:'; - $descriptions['plural'] = '$1 message(s) of $2 in $3 don\'t use {{plural}} while en uses:'; - $descriptions['empty'] = '$1 message(s) of $2 in $3 are empty or -:'; - $descriptions['whitespace'] = '$1 message(s) of $2 in $3 have trailing whitespace:'; - $descriptions['xhtml'] = '$1 message(s) of $2 in $3 contain illegal XHTML:'; - $descriptions['chars'] = '$1 message(s) of $2 in $3 include hidden chars which should not be used in the messages:'; - $descriptions['links'] = '$1 message(s) of $2 in $3 have problematic link(s):'; - $descriptions['unbalanced'] = '$1 message(s) of $2 in $3 have unbalanced {[]}:'; - return $descriptions; + 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:', + '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:', + '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:', + '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:', + '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:', + ); } + /** + * Get help. + * @return The help string. + */ protected function help() { return <<