diff options
Diffstat (limited to 'maintenance')
392 files changed, 22019 insertions, 5740 deletions
diff --git a/maintenance/7zip.inc b/maintenance/7zip.inc index 6bb06668..590cad23 100644 --- a/maintenance/7zip.inc +++ b/maintenance/7zip.inc @@ -32,7 +32,7 @@ * @ingroup Maintenance */ class SevenZipStream { - var $stream; + protected $stream; private function stripPath( $path ) { $prefix = 'mediawiki.compress.7z://'; diff --git a/maintenance/Doxyfile b/maintenance/Doxyfile index e3ba4e5a..ffc8c3b0 100644 --- a/maintenance/Doxyfile +++ b/maintenance/Doxyfile @@ -1,5 +1,7 @@ -# Doxyfile 1.7.5.1 +# Doxyfile 1.7.6.1 +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for MediaWiki. # # Some placeholders have been added for MediaWiki usage: # {{OUTPUT_DIRECTORY}} @@ -44,7 +46,7 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO -TAB_SIZE = 8 +TAB_SIZE = 4 ALIASES = "type{1}=<b> \1 </b>:" \ "types{2}=<b> \1 </b> or <b> \2 </b>:" \ "types{3}=<b> \1 </b>, <b> \2 </b>, or <b> \3 </b>:" \ @@ -62,7 +64,9 @@ ALIASES = "type{1}=<b> \1 </b>:" \ "protected=\access protected" \ "public=\access public" \ "copyright=\note" \ - "license=\note" + "license=\note" \ + "codeCoverageIgnore=" +TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO @@ -71,13 +75,14 @@ EXTENSION_MAPPING = BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO -IDL_PROPERTY_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = YES SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO SYMBOL_CACHE_SIZE = 0 +LOOKUP_CACHE_SIZE = 1 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -171,8 +176,11 @@ FILE_PATTERNS = *.c \ *.PHP5 \ *.M \ *.MM \ - *.PY + *.PY \ + *.txt \ + README RECURSIVE = YES +EXCLUDE = {{EXCLUDE}} EXCLUDE_SYMLINKS = YES EXCLUDE_PATTERNS = LocalSettings.php AdminSettings.php StartProfiler.php .svn */.git/* {{EXCLUDE_PATTERNS}} EXCLUDE_SYMBOLS = @@ -213,7 +221,7 @@ HTML_STYLESHEET = HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 -HTML_COLORSTYLE_GAMMA = 80 +HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES HTML_ALIGN_MEMBERS = YES HTML_DYNAMIC_SECTIONS = NO @@ -355,7 +363,7 @@ MSCFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO -DOT_MULTI_TARGETS = NO +DOT_MULTI_TARGETS = YES GENERATE_LEGEND = YES DOT_CLEANUP = YES diff --git a/maintenance/Maintenance.php b/maintenance/Maintenance.php index 69d11313..30e93c90 100644 --- a/maintenance/Maintenance.php +++ b/maintenance/Maintenance.php @@ -23,7 +23,7 @@ // Make sure we're on PHP5.3.2 or better if ( !function_exists( 'version_compare' ) || version_compare( PHP_VERSION, '5.3.2' ) < 0 ) { // We need to use dirname( __FILE__ ) here cause __DIR__ is PHP5.3+ - require_once( dirname( __FILE__ ) . '/../includes/PHPVersionError.php' ); + require_once dirname( __FILE__ ) . '/../includes/PHPVersionError.php'; wfPHPVersionError( 'cli' ); } @@ -54,8 +54,8 @@ abstract class Maintenance { * Constants for DB access type * @see Maintenance::getDbType() */ - const DB_NONE = 0; - const DB_STD = 1; + const DB_NONE = 0; + const DB_STD = 1; const DB_ADMIN = 2; // Const for getStdin() @@ -109,6 +109,12 @@ abstract class Maintenance { private $mDb = null; /** + * Used when creating separate schema files. + * @var resource + */ + public $fileHandle; + + /** * List of all the core maintenance scripts. This is added * to scripts added by extensions in $wgMaintenanceScripts * and returned by getMaintenanceScripts() @@ -147,7 +153,7 @@ abstract class Maintenance { return false; // last call should be to this function } $includeFuncs = array( 'require_once', 'require', 'include', 'include_once' ); - for( $i=1; $i < $count; $i++ ) { + for ( $i = 1; $i < $count; $i++ ) { if ( !in_array( $bt[$i]['function'], $includeFuncs ) ) { return false; // previous calls should all be "requires" } @@ -321,7 +327,7 @@ abstract class Maintenance { } if ( $channel === null ) { $this->cleanupChanneled(); - print( $out ); + print $out; } else { $out = preg_replace( '/\n\z/', '', $out ); $this->outputChanneled( $out, $channel ); @@ -336,7 +342,7 @@ abstract class Maintenance { */ protected function error( $err, $die = 0 ) { $this->outputChanneled( false ); - if ( php_sapi_name() == 'cli' ) { + if ( PHP_SAPI == 'cli' ) { fwrite( STDERR, $err . "\n" ); } else { print $err; @@ -420,9 +426,10 @@ abstract class Maintenance { $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 ); + $this->addOption( 'profiler', 'Set to "text" or "trace" to show profiling output', false, true ); # Save generic options to display them separately in help - $this->mGenericParameters = $this->mParams ; + $this->mGenericParameters = $this->mParams; # Script dependant options: @@ -446,11 +453,11 @@ abstract class Maintenance { */ public function runChild( $maintClass, $classFile = null ) { // Make sure the class is loaded first - if ( !MWInit::classExists( $maintClass ) ) { + if ( !class_exists( $maintClass ) ) { if ( $classFile ) { - require_once( $classFile ); + require_once $classFile; } - if ( !MWInit::classExists( $maintClass ) ) { + if ( !class_exists( $maintClass ) ) { $this->error( "Cannot spawn child: $maintClass" ); } } @@ -470,31 +477,28 @@ abstract class Maintenance { * Do some sanity checking and basic setup */ public function setup() { - global $wgCommandLineMode, $wgRequestTime; + global $IP, $wgCommandLineMode, $wgRequestTime; # Abort if called from a web server if ( isset( $_SERVER ) && isset( $_SERVER['REQUEST_METHOD'] ) ) { $this->error( 'This script must be run from the command line', true ); } + if ( $IP === null ) { + $this->error( "\$IP not set, aborting!\n" . + '(Did you forget to call parent::__construct() in your maintenance script?)', 1 ); + } + # Make sure we can handle script parameters - if ( !function_exists( 'hphp_thread_set_warmup_enabled' ) && !ini_get( 'register_argc_argv' ) ) { + if ( !defined( 'HPHP_VERSION' ) && !ini_get( 'register_argc_argv' ) ) { $this->error( 'Cannot get command line arguments, register_argc_argv is set to false', true ); } - if ( version_compare( phpversion(), '5.2.4' ) >= 0 ) { - // Send PHP warnings and errors to stderr instead of stdout. - // This aids in diagnosing problems, while keeping messages - // out of redirected output. - if ( ini_get( 'display_errors' ) ) { - ini_set( 'display_errors', 'stderr' ); - } - - // Don't touch the setting on earlier versions of PHP, - // as setting it would disable output if you'd wanted it. - - // Note that exceptions are also sent to stderr when - // command-line mode is on, regardless of PHP version. + // Send PHP warnings and errors to stderr instead of stdout. + // This aids in diagnosing problems, while keeping messages + // out of redirected output. + if ( ini_get( 'display_errors' ) ) { + ini_set( 'display_errors', 'stderr' ); } $this->loadParamsAndArgs(); @@ -515,8 +519,11 @@ abstract class Maintenance { define( 'MEDIAWIKI', true ); $wgCommandLineMode = true; + # Turn off output buffering if it's on - @ob_end_flush(); + while ( ob_get_level() > 0 ) { + ob_end_flush(); + } $this->validateParamsAndArgs(); } @@ -633,7 +640,7 @@ abstract class Maintenance { } elseif ( substr( $arg, 0, 1 ) == '-' ) { # Short options for ( $p = 1; $p < strlen( $arg ); $p++ ) { - $option = $arg { $p } ; + $option = $arg { $p }; if ( !isset( $this->mParams[$option] ) && isset( $this->mShortParamsMap[$option] ) ) { $option = $this->mShortParamsMap[$option]; } @@ -711,7 +718,7 @@ abstract class Maintenance { * @param $force boolean Whether to force the help to show, default false */ protected function maybeHelp( $force = false ) { - if( !$force && !$this->hasOption( 'help' ) ) { + if ( !$force && !$this->hasOption( 'help' ) ) { return; } @@ -742,8 +749,9 @@ abstract class Maintenance { } else { $output .= '[' . $arg['name'] . ']'; } - if ( $k < count( $this->mArgList ) - 1 ) + if ( $k < count( $this->mArgList ) - 1 ) { $output .= ' '; + } } } $this->output( "$output\n\n" ); @@ -764,7 +772,7 @@ abstract class Maintenance { $this->output( "\n" ); $scriptDependantParams = $this->mDependantParameters; - if( count($scriptDependantParams) > 0 ) { + if ( count( $scriptDependantParams ) > 0 ) { $this->output( "Script dependant parameters:\n" ); // Parameters description foreach ( $scriptDependantParams as $par => $info ) { @@ -789,7 +797,7 @@ abstract class Maintenance { $this->mGenericParameters, $this->mDependantParameters ); - if( count($scriptSpecificParams) > 0 ) { + if ( count( $scriptSpecificParams ) > 0 ) { $this->output( "Script specific parameters:\n" ); // Parameters description foreach ( $scriptSpecificParams as $par => $info ) { @@ -805,7 +813,7 @@ abstract class Maintenance { } // Print arguments - if( count( $this->mArgList ) > 0 ) { + if ( count( $this->mArgList ) > 0 ) { $this->output( "Arguments:\n" ); // Arguments description foreach ( $this->mArgList as $info ) { @@ -838,7 +846,7 @@ abstract class Maintenance { $wgCommandLineMode = true; # Override $wgServer - if( $this->hasOption( 'server') ) { + if ( $this->hasOption( 'server' ) ) { $wgServer = $this->getOption( 'server', $wgServer ); } @@ -875,6 +883,16 @@ abstract class Maintenance { $wgShowSQLErrors = true; @set_time_limit( 0 ); $this->adjustMemoryLimit(); + + // Per-script profiling; useful for debugging + $forcedProfiler = $this->getOption( 'profiler' ); + if ( $forcedProfiler === 'text' ) { + Profiler::setInstance( new ProfilerSimpleText( array() ) ); + Profiler::instance()->setTemplated( true ); + } elseif ( $forcedProfiler === 'trace' ) { + Profiler::setInstance( new ProfilerSimpleTrace( array() ) ); + Profiler::instance()->setTemplated( true ); + } } /** @@ -905,7 +923,7 @@ abstract class Maintenance { if ( isset( $this->mOptions['conf'] ) ) { $settingsFile = $this->mOptions['conf']; - } elseif ( defined("MW_CONFIG_FILE") ) { + } elseif ( defined( "MW_CONFIG_FILE" ) ) { $settingsFile = MW_CONFIG_FILE; } else { $settingsFile = "$IP/LocalSettings.php"; @@ -922,7 +940,7 @@ 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 ); + "Use --conf to specify it.", true ); } $wgCommandLineMode = true; return $settingsFile; @@ -938,13 +956,9 @@ abstract class Maintenance { $dbw = $this->getDB( 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 $this->output( 'Searching for active text records in revisions table...' ); - $res = $dbw->query( "SELECT DISTINCT rev_text_id FROM $tbl_rev" ); + $res = $dbw->select( 'revision', 'rev_text_id', array(), __METHOD__, array( 'DISTINCT' ) ); foreach ( $res as $row ) { $cur[] = $row->rev_text_id; } @@ -952,16 +966,19 @@ abstract class Maintenance { # Get "active" text records from the archive table $this->output( 'Searching for active text records in archive table...' ); - $res = $dbw->query( "SELECT DISTINCT ar_text_id FROM $tbl_arc" ); + $res = $dbw->select( 'archive', 'ar_text_id', array(), __METHOD__, array( 'DISTINCT' ) ); foreach ( $res as $row ) { - $cur[] = $row->ar_text_id; + # old pre-MW 1.5 records can have null ar_text_id's. + if ( $row->ar_text_id !== null ) { + $cur[] = $row->ar_text_id; + } } $this->output( "done.\n" ); # Get the IDs of all text records not in these sets $this->output( 'Searching for inactive text records...' ); - $set = implode( ', ', $cur ); - $res = $dbw->query( "SELECT old_id FROM $tbl_txt WHERE old_id NOT IN ( $set )" ); + $cond = 'old_id NOT IN ( ' . $dbw->makeList( $cur ) . ' )'; + $res = $dbw->select( 'text', 'old_id', array( $cond ), __METHOD__, array( 'DISTINCT' ) ); $old = array(); foreach ( $res as $row ) { $old[] = $row->old_id; @@ -975,8 +992,7 @@ abstract class Maintenance { # Delete as appropriate if ( $delete && $count ) { $this->output( 'Deleting...' ); - $set = implode( ', ', $old ); - $dbw->query( "DELETE FROM $tbl_txt WHERE old_id IN ( $set )" ); + $dbw->delete( 'text', array( 'old_id' => $old ), __METHOD__ ); $this->output( "done.\n" ); } @@ -1026,7 +1042,7 @@ abstract class Maintenance { ( strpos( file_get_contents( $file ), '$maintClass' ) === false ) ) { continue; } - require( $file ); + require $file; $vars = get_defined_vars(); if ( array_key_exists( 'maintClass', $vars ) ) { self::$mCoreScripts[$vars['maintClass']] = $file; @@ -1068,7 +1084,7 @@ abstract class Maintenance { */ private function lockSearchindex( &$db ) { $write = array( 'searchindex' ); - $read = array( 'page', 'revision', 'text', 'interwiki', 'l10n_cache' ); + $read = array( 'page', 'revision', 'text', 'interwiki', 'l10n_cache', 'user' ); $db->lockTables( $read, $write, __CLASS__ . '::' . __METHOD__ ); } @@ -1077,7 +1093,7 @@ abstract class Maintenance { * @param &$db DatabaseBase object */ private function unlockSearchindex( &$db ) { - $db->unlockTables( __CLASS__ . '::' . __METHOD__ ); + $db->unlockTables( __CLASS__ . '::' . __METHOD__ ); } /** @@ -1144,7 +1160,7 @@ abstract class Maintenance { $title = $titleObj->getPrefixedDBkey(); $this->output( "$title..." ); # Update searchindex - $u = new SearchUpdate( $pageId, $titleObj->getText(), $rev->getText() ); + $u = new SearchUpdate( $pageId, $titleObj->getText(), $rev->getContent() ); $u->doUpdate(); $this->output( "\n" ); } @@ -1160,7 +1176,7 @@ abstract class Maintenance { * @return bool */ public static function posix_isatty( $fd ) { - if ( !MWInit::functionExists( 'posix_isatty' ) ) { + if ( !function_exists( 'posix_isatty' ) ) { return !$fd; } else { return posix_isatty( $fd ); @@ -1190,7 +1206,9 @@ abstract class Maintenance { $st = fgets( STDIN, 1024 ); } } - if ( $st === false ) return false; + if ( $st === false ) { + return false; + } $resp = trim( $st ); return $resp; } @@ -1208,7 +1226,7 @@ abstract class Maintenance { $encPrompt = wfEscapeShellArg( $prompt ); $command = "read -er -p $encPrompt && echo \"\$REPLY\""; $encCommand = wfEscapeShellArg( $command ); - $line = wfShellExec( "$bash -c $encCommand", $retval ); + $line = wfShellExec( "$bash -c $encCommand", $retval, array(), array( 'walltime' => 0 ) ); if ( $retval == 0 ) { return $line; diff --git a/maintenance/Makefile b/maintenance/Makefile index 30b568dc..25554751 100644 --- a/maintenance/Makefile +++ b/maintenance/Makefile @@ -8,7 +8,9 @@ test: doc: php mwdocgen.php --all - @echo 'Doc generation done. Look at ./docs/html/' + ./mwjsduck-gen + @echo 'PHP documentation (by Doxygen) in ./docs/html/' + @echo 'JS documentation (by JSDuck) in ./docs/js/' man: php mwdocgen.php --all --generate-man diff --git a/maintenance/README b/maintenance/README index d6e76917..5cb6f5f5 100644 --- a/maintenance/README +++ b/maintenance/README @@ -56,15 +56,15 @@ installations. importDump.php XML dump importer - + 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 + Move a batch of pages namespaceDupes.php Check articles name to see if they conflict with new/existing namespaces @@ -93,7 +93,7 @@ installations. runJobs.php Immediately complete all jobs in the job queue - stats.php + showCacheStats.php Show all statistics stored in the cache undelete.php @@ -106,4 +106,4 @@ installations. Update pages restriction to the new schema userOptions.php - Change user options
\ No newline at end of file + Change user options diff --git a/maintenance/archives/patch-archive-ar_content_format.sql b/maintenance/archives/patch-archive-ar_content_format.sql new file mode 100644 index 00000000..81f9fca8 --- /dev/null +++ b/maintenance/archives/patch-archive-ar_content_format.sql @@ -0,0 +1,2 @@ +ALTER TABLE /*$wgDBprefix*/archive + ADD ar_content_format varbinary(64) DEFAULT NULL; diff --git a/maintenance/archives/patch-archive-ar_content_model.sql b/maintenance/archives/patch-archive-ar_content_model.sql new file mode 100644 index 00000000..1a8b630e --- /dev/null +++ b/maintenance/archives/patch-archive-ar_content_model.sql @@ -0,0 +1,2 @@ +ALTER TABLE /*$wgDBprefix*/archive + ADD ar_content_model varbinary(32) DEFAULT NULL; diff --git a/maintenance/archives/patch-archive-ar_id.sql b/maintenance/archives/patch-archive-ar_id.sql new file mode 100644 index 00000000..ddd1d7b4 --- /dev/null +++ b/maintenance/archives/patch-archive-ar_id.sql @@ -0,0 +1,8 @@ +-- +-- patch-archive-ar_id.sql +-- +-- Bug 39675. Add archive.ar_id. + +ALTER TABLE /*$wgDBprefix*/archive + ADD COLUMN ar_id int unsigned NOT NULL AUTO_INCREMENT FIRST, + ADD PRIMARY KEY (ar_id); diff --git a/maintenance/archives/patch-archive-user-index.sql b/maintenance/archives/patch-archive-user-index.sql index 62baa2dd..997b4a97 100644 --- a/maintenance/archives/patch-archive-user-index.sql +++ b/maintenance/archives/patch-archive-user-index.sql @@ -1,4 +1,4 @@ -- Adds a user,timestamp index to the archive table -- Used for browsing deleted contributions and renames -ALTER TABLE /*$wgDBprefix*/archive +ALTER TABLE /*$wgDBprefix*/archive ADD INDEX usertext_timestamp ( ar_user_text , ar_timestamp ); diff --git a/maintenance/archives/patch-backlinkindexes.sql b/maintenance/archives/patch-backlinkindexes.sql index 5facd9ea..22cc5871 100644 --- a/maintenance/archives/patch-backlinkindexes.sql +++ b/maintenance/archives/patch-backlinkindexes.sql @@ -1,10 +1,10 @@ --- +-- -- patch-backlinkindexes.sql --- +-- -- Per bug 6440 / http://bugzilla.wikimedia.org/show_bug.cgi?id=6440 -- -- Improve performance of the "what links here"-type queries --- +-- ALTER TABLE /*$wgDBprefix*/pagelinks DROP INDEX pl_namespace, @@ -13,7 +13,7 @@ ALTER TABLE /*$wgDBprefix*/pagelinks ALTER TABLE /*$wgDBprefix*/templatelinks DROP INDEX tl_namespace, ADD INDEX tl_namespace(tl_namespace, tl_title, tl_from); - + ALTER TABLE /*$wgDBprefix*/imagelinks DROP INDEX il_to, ADD INDEX il_to(il_to, il_from); diff --git a/maintenance/archives/patch-category.sql b/maintenance/archives/patch-category.sql index 416500c3..97a5690d 100644 --- a/maintenance/archives/patch-category.sql +++ b/maintenance/archives/patch-category.sql @@ -8,7 +8,7 @@ CREATE TABLE /*$wgDBprefix*/category ( cat_files int signed NOT NULL default 0, cat_hidden tinyint(1) unsigned NOT NULL default 0, - + PRIMARY KEY (cat_id), UNIQUE KEY (cat_title), diff --git a/maintenance/archives/patch-categorylinks.sql b/maintenance/archives/patch-categorylinks.sql index 02168d7f..0af0cf91 100644 --- a/maintenance/archives/patch-categorylinks.sql +++ b/maintenance/archives/patch-categorylinks.sql @@ -6,7 +6,7 @@ CREATE TABLE /*$wgDBprefix*/categorylinks ( -- Key to page_id of the page defined as a category member. cl_from int unsigned NOT NULL default '0', - + -- 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). @@ -17,20 +17,20 @@ CREATE TABLE /*$wgDBprefix*/categorylinks ( -- isn't always ideal, but collations seem to be an exciting -- and dangerous new world in MySQL... -- - -- Truncate so that the cl_sortkey key fits in 1000 bytes + -- Truncate so that the cl_sortkey key fits in 1000 bytes -- (MyISAM 5 with server_character_set=utf8) cl_sortkey varchar(70) binary NOT NULL default '', - + -- This isn't really used at present. Provided for an optional -- sorting method by approximate addition time. cl_timestamp timestamp NOT NULL, - + UNIQUE KEY cl_from(cl_from,cl_to), - + -- This key is trouble. It's incomplete, AND it's too big -- when collation is set to UTF-8. Bleeeacch! KEY cl_sortkey(cl_to,cl_sortkey), - + -- Not really used? KEY cl_timestamp(cl_to,cl_timestamp) diff --git a/maintenance/archives/patch-categorylinksindex.sql b/maintenance/archives/patch-categorylinksindex.sql index 8a9ff123..24ad84fe 100644 --- a/maintenance/archives/patch-categorylinksindex.sql +++ b/maintenance/archives/patch-categorylinksindex.sql @@ -1,10 +1,10 @@ --- +-- -- patch-categorylinksindex.sql --- +-- -- Per bug 10280 / http://bugzilla.wikimedia.org/show_bug.cgi?id=10280 -- -- Improve enum continuation performance of the what pages belong to a category query --- +-- ALTER TABLE /*$wgDBprefix*/categorylinks DROP INDEX cl_sortkey, diff --git a/maintenance/archives/patch-change_tag.sql b/maintenance/archives/patch-change_tag.sql index 030e086b..3079a5bb 100644 --- a/maintenance/archives/patch-change_tag.sql +++ b/maintenance/archives/patch-change_tag.sql @@ -13,20 +13,3 @@ 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 ( - ts_rc_id int NULL, - ts_log_id int NULL, - ts_rev_id int NULL, - ts_tags BLOB NOT NULL -) /*$wgDBTableOptions*/; - -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 varchar(255) NOT NULL PRIMARY KEY -) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-drop-ss_admins.sql b/maintenance/archives/patch-drop-ss_admins.sql new file mode 100644 index 00000000..13c3d3b0 --- /dev/null +++ b/maintenance/archives/patch-drop-ss_admins.sql @@ -0,0 +1,2 @@ +-- field is deprecated and no longer updated as of 1.5 +ALTER TABLE /*_*/site_stats DROP COLUMN ss_admins;
\ No newline at end of file diff --git a/maintenance/archives/patch-eu_local_id.sql b/maintenance/archives/patch-eu_local_id.sql deleted file mode 100644 index bb59d067..00000000 --- a/maintenance/archives/patch-eu_local_id.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE /*_*/external_user -CHANGE COLUMN eu_wiki_id -eu_local_id int unsigned NOT NULL; diff --git a/maintenance/archives/patch-external_user.sql b/maintenance/archives/patch-external_user.sql deleted file mode 100644 index 176b46d4..00000000 --- a/maintenance/archives/patch-external_user.sql +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE /*_*/external_user ( - -- Foreign key to user_id - eu_local_id int unsigned NOT NULL PRIMARY KEY, - - -- Some opaque identifier provided by the external database - eu_external_id varchar(255) binary NOT NULL -) /*$wgDBTableOptions*/; - -CREATE UNIQUE INDEX /*i*/eu_external_id ON /*_*/external_user (eu_external_id); diff --git a/maintenance/archives/patch-externallinks-el_id.sql b/maintenance/archives/patch-externallinks-el_id.sql new file mode 100644 index 00000000..d4b51b51 --- /dev/null +++ b/maintenance/archives/patch-externallinks-el_id.sql @@ -0,0 +1,8 @@ +-- +-- patch-extenallinks-el_id.sql +-- +-- Bug 15441. Add externallinks.el_id. + +ALTER TABLE /*$wgDBprefix*/externallinks + ADD COLUMN el_id int unsigned NOT NULL AUTO_INCREMENT FIRST, + ADD PRIMARY KEY (el_id); diff --git a/maintenance/archives/patch-externallinks.sql b/maintenance/archives/patch-externallinks.sql index 0a4768ca..fc5017db 100644 --- a/maintenance/archives/patch-externallinks.sql +++ b/maintenance/archives/patch-externallinks.sql @@ -5,7 +5,7 @@ CREATE TABLE /*$wgDBprefix*/externallinks ( el_from int(8) unsigned NOT NULL default '0', el_to blob NOT NULL, el_index blob NOT NULL, - + KEY (el_from, el_to(40)), KEY (el_to(60), el_from), KEY (el_index(60)) diff --git a/maintenance/archives/patch-fa_deleted.sql b/maintenance/archives/patch-fa_deleted.sql index 3483f8cf..7ab65239 100644 --- a/maintenance/archives/patch-fa_deleted.sql +++ b/maintenance/archives/patch-fa_deleted.sql @@ -1,3 +1,3 @@ -- Adding fa_deleted field for additional content suppression -ALTER TABLE /*$wgDBprefix*/filearchive +ALTER TABLE /*$wgDBprefix*/filearchive ADD fa_deleted tinyint unsigned NOT NULL default '0'; diff --git a/maintenance/archives/patch-fa_sha1.sql b/maintenance/archives/patch-fa_sha1.sql new file mode 100644 index 00000000..931bc44d --- /dev/null +++ b/maintenance/archives/patch-fa_sha1.sql @@ -0,0 +1,4 @@ +-- Add fa_sha1 and related index +ALTER TABLE /*$wgDBprefix*/filearchive + ADD COLUMN fa_sha1 varbinary(32) NOT NULL default ''; +CREATE INDEX /*i*/fa_sha1 ON /*$wgDBprefix*/filearchive (fa_sha1(10)); diff --git a/maintenance/archives/patch-filearchive-user-index.sql b/maintenance/archives/patch-filearchive-user-index.sql index c79000ad..0d8c3ab1 100644 --- a/maintenance/archives/patch-filearchive-user-index.sql +++ b/maintenance/archives/patch-filearchive-user-index.sql @@ -1,5 +1,5 @@ -- Adding index to sort by uploader -ALTER TABLE /*$wgDBprefix*/filearchive +ALTER TABLE /*$wgDBprefix*/filearchive ADD INDEX fa_user_timestamp (fa_user_text,fa_timestamp), -- Remove useless, incomplete index DROP INDEX fa_deleted_user; diff --git a/maintenance/archives/patch-filearchive.sql b/maintenance/archives/patch-filearchive.sql index 587a2ab4..f75da8be 100644 --- a/maintenance/archives/patch-filearchive.sql +++ b/maintenance/archives/patch-filearchive.sql @@ -4,30 +4,30 @@ CREATE TABLE /*$wgDBprefix*/filearchive ( -- Unique row id fa_id int not null auto_increment, - + -- Original base filename; key to image.img_name, page.page_title, etc fa_name varchar(255) binary NOT NULL default '', - + -- Filename of archived file, if an old revision fa_archive_name varchar(255) binary 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 varbinary(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 varbinary(64) default '', - + -- Deletion information, if this file is deleted. fa_deleted_user int, fa_deleted_timestamp binary(14) default '', fa_deleted_reason text, - + -- Duped fields from image fa_size int unsigned default '0', fa_width int default '0', @@ -41,7 +41,7 @@ CREATE TABLE /*$wgDBprefix*/filearchive ( fa_user int unsigned default '0', fa_user_text varchar(255) binary default '', fa_timestamp binary(14) default '', - + PRIMARY KEY (fa_id), INDEX (fa_name, fa_timestamp), -- pick out by image name INDEX (fa_storage_group, fa_storage_key), -- pick out dupe files diff --git a/maintenance/archives/patch-hitcounter.sql b/maintenance/archives/patch-hitcounter.sql index 50e56e0c..c87c9592 100644 --- a/maintenance/archives/patch-hitcounter.sql +++ b/maintenance/archives/patch-hitcounter.sql @@ -1,5 +1,5 @@ -- --- hitcounter table is used to buffer page hits before they are periodically +-- hitcounter table is used to buffer page hits before they are periodically -- counted and added to the cur_counter column in the cur table. -- December 2003 -- diff --git a/maintenance/archives/patch-image-user-index.sql b/maintenance/archives/patch-image-user-index.sql index db56b221..a74d7bd5 100644 --- a/maintenance/archives/patch-image-user-index.sql +++ b/maintenance/archives/patch-image-user-index.sql @@ -1,8 +1,8 @@ --- +-- -- image-user-index.sql --- +-- -- Add user/timestamp index to current image versions --- +-- ALTER TABLE /*$wgDBprefix*/image ADD INDEX img_usertext_timestamp (img_user_text,img_timestamp); diff --git a/maintenance/archives/patch-img_media_mime-index.sql b/maintenance/archives/patch-img_media_mime-index.sql new file mode 100644 index 00000000..bfaf84f9 --- /dev/null +++ b/maintenance/archives/patch-img_media_mime-index.sql @@ -0,0 +1,4 @@ +-- New index on image table to allow searches for types i.e. video webm +-- Added 2013-01-08 + +CREATE INDEX /*i*/img_media_mime ON /*_*/image (img_media_type,img_major_mime,img_minor_mime); diff --git a/maintenance/archives/patch-img_media_type.sql b/maintenance/archives/patch-img_media_type.sql index 857eb98e..87b8c2f5 100644 --- a/maintenance/archives/patch-img_media_type.sql +++ b/maintenance/archives/patch-img_media_type.sql @@ -4,11 +4,11 @@ ALTER TABLE /*$wgDBprefix*/image ADD ( -- Media type as defined by the MEDIATYPE_xxx constants img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - + -- 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", - + -- 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 diff --git a/maintenance/archives/patch-img_sha1.sql b/maintenance/archives/patch-img_sha1.sql index 35950f58..0a375c4f 100644 --- a/maintenance/archives/patch-img_sha1.sql +++ b/maintenance/archives/patch-img_sha1.sql @@ -1,8 +1,8 @@ -- Add img_sha1, oi_sha1 and related indexes ALTER TABLE /*$wgDBprefix*/image ADD COLUMN img_sha1 varbinary(32) NOT NULL default '', - ADD INDEX img_sha1 (img_sha1); + ADD INDEX img_sha1 (img_sha1(10)); ALTER TABLE /*$wgDBprefix*/oldimage ADD COLUMN oi_sha1 varbinary(32) NOT NULL default '', - ADD INDEX oi_sha1 (oi_sha1); + ADD INDEX oi_sha1 (oi_sha1(10)); diff --git a/maintenance/archives/patch-indexes.sql b/maintenance/archives/patch-indexes.sql index c56838fd..c24d9953 100644 --- a/maintenance/archives/patch-indexes.sql +++ b/maintenance/archives/patch-indexes.sql @@ -1,8 +1,8 @@ --- +-- -- patch-indexes.sql --- +-- -- Fix up table indexes; new to stable release in November 2003 --- +-- ALTER TABLE IF EXISTS /*$wgDBprefix*/links DROP INDEX l_from, diff --git a/maintenance/archives/patch-interwiki.sql b/maintenance/archives/patch-interwiki.sql index 321765b9..57b79456 100644 --- a/maintenance/archives/patch-interwiki.sql +++ b/maintenance/archives/patch-interwiki.sql @@ -5,16 +5,16 @@ CREATE TABLE /*$wgDBprefix*/interwiki ( -- The interwiki prefix, (e.g. "Meatball", or the language prefix "de") iw_prefix varchar(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 blob NOT NULL, - + -- A boolean value indicating whether the wiki is in this project -- (used, for example, to detect redirect loops) iw_local BOOL NOT NULL, - + UNIQUE KEY iw_prefix (iw_prefix) ) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-ipb_anon_only.sql b/maintenance/archives/patch-ipb_anon_only.sql index fcd257c7..bb39c1d9 100644 --- a/maintenance/archives/patch-ipb_anon_only.sql +++ b/maintenance/archives/patch-ipb_anon_only.sql @@ -1,9 +1,9 @@ --- Add extra option fields to the ipblocks table, add some extra indexes, --- convert infinity values in ipb_expiry to something that sorts better, --- extend ipb_address and range fields, add a unique index for block conflict +-- Add extra option fields to the ipblocks table, add some extra indexes, +-- convert infinity values in ipb_expiry to something that sorts better, +-- extend ipb_address and range fields, add a unique index for block conflict -- detection. --- Conflicts in the new unique index can be handled by creating a new +-- Conflicts in the new unique index can be handled by creating a new -- table and inserting into it instead of doing an ALTER TABLE. @@ -22,7 +22,7 @@ CREATE TABLE /*$wgDBprefix*/ipblocks_newunique ( ipb_expiry varbinary(14) NOT NULL default '', ipb_range_start tinyblob NOT NULL, ipb_range_end tinyblob NOT NULL, - + PRIMARY KEY ipb_id (ipb_id), UNIQUE INDEX ipb_address_unique (ipb_address(255), ipb_user, ipb_auto), INDEX ipb_user (ipb_user), @@ -32,8 +32,8 @@ CREATE TABLE /*$wgDBprefix*/ipblocks_newunique ( ) /*$wgDBTableOptions*/; -INSERT IGNORE INTO /*$wgDBprefix*/ipblocks_newunique - (ipb_id, ipb_address, ipb_user, ipb_by, ipb_reason, ipb_timestamp, ipb_auto, ipb_expiry, ipb_range_start, ipb_range_end, ipb_anon_only, ipb_create_account) +INSERT IGNORE INTO /*$wgDBprefix*/ipblocks_newunique + (ipb_id, ipb_address, ipb_user, ipb_by, ipb_reason, ipb_timestamp, ipb_auto, ipb_expiry, ipb_range_start, ipb_range_end, ipb_anon_only, ipb_create_account) SELECT ipb_id, ipb_address, ipb_user, ipb_by, ipb_reason, ipb_timestamp, ipb_auto, ipb_expiry, ipb_range_start, ipb_range_end, 0 , ipb_user=0 FROM /*$wgDBprefix*/ipblocks; diff --git a/maintenance/archives/patch-ipb_by_text.sql b/maintenance/archives/patch-ipb_by_text.sql index c0b620d3..e809d102 100644 --- a/maintenance/archives/patch-ipb_by_text.sql +++ b/maintenance/archives/patch-ipb_by_text.sql @@ -4,7 +4,7 @@ ALTER TABLE /*$wgDBprefix*/ipblocks ADD ipb_by_text varchar(255) binary NOT NULL default ''; -UPDATE /*$wgDBprefix*/ipblocks +UPDATE /*$wgDBprefix*/ipblocks JOIN /*$wgDBprefix*/user ON ipb_by = user_id SET ipb_by_text = user_name WHERE ipb_by != 0;
\ No newline at end of file diff --git a/maintenance/archives/patch-ipb_deleted.sql b/maintenance/archives/patch-ipb_deleted.sql index fad94778..b12ddaaa 100644 --- a/maintenance/archives/patch-ipb_deleted.sql +++ b/maintenance/archives/patch-ipb_deleted.sql @@ -1,3 +1,3 @@ -- Adding ipb_deleted field for hiding usernames -ALTER TABLE /*$wgDBprefix*/ipblocks +ALTER TABLE /*$wgDBprefix*/ipblocks ADD ipb_deleted bool NOT NULL default 0; diff --git a/maintenance/archives/patch-ipb_range_start.sql b/maintenance/archives/patch-ipb_range_start.sql index 64a906d4..84cba8f6 100644 --- a/maintenance/archives/patch-ipb_range_start.sql +++ b/maintenance/archives/patch-ipb_range_start.sql @@ -1,5 +1,5 @@ -- Add the range handling fields -ALTER TABLE /*$wgDBprefix*/ipblocks +ALTER TABLE /*$wgDBprefix*/ipblocks ADD ipb_range_start tinyblob NOT NULL default '', ADD ipb_range_end tinyblob NOT NULL default '', ADD INDEX ipb_range (ipb_range_start(8), ipb_range_end(8)); @@ -7,15 +7,15 @@ ALTER TABLE /*$wgDBprefix*/ipblocks -- Initialise fields -- Only range blocks match ipb_address LIKE '%/%', this fact is used in the code already -UPDATE /*$wgDBprefix*/ipblocks - SET - ipb_range_start = LPAD(HEX( +UPDATE /*$wgDBprefix*/ipblocks + SET + ipb_range_start = LPAD(HEX( (SUBSTRING_INDEX(ipb_address, '.', 1) << 24) + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 2), '.', -1) << 16) + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 3), '.', -1) << 24) + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '/', 1), '.', -1)) ), 8, '0' ), - ipb_range_end = LPAD(HEX( + ipb_range_end = LPAD(HEX( (SUBSTRING_INDEX(ipb_address, '.', 1) << 24) + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 2), '.', -1) << 16) + (SUBSTRING_INDEX(SUBSTRING_INDEX(ipb_address, '.', 3), '.', -1) << 24) diff --git a/maintenance/archives/patch-iwl_prefix_title_from-non-unique.sql b/maintenance/archives/patch-iwl_prefix_title_from-non-unique.sql new file mode 100644 index 00000000..bff63c74 --- /dev/null +++ b/maintenance/archives/patch-iwl_prefix_title_from-non-unique.sql @@ -0,0 +1,5 @@ +-- +-- Makes the iwl_prefix_title_from index for the iwlinks table non-unique +-- +DROP INDEX /*i*/iwl_prefix_title_from ON /*_*/iwlinks; +CREATE INDEX /*i*/iwl_prefix_title_from ON /*_*/iwlinks (iwl_prefix, iwl_title, iwl_from); diff --git a/maintenance/archives/patch-iwlinks-from-title-index.sql b/maintenance/archives/patch-iwlinks-from-title-index.sql new file mode 100644 index 00000000..8b73f9e3 --- /dev/null +++ b/maintenance/archives/patch-iwlinks-from-title-index.sql @@ -0,0 +1,4 @@ +-- +-- Recreates the iwl_prefix_from_title index for the iwlinks table +-- +CREATE INDEX /*i*/iwl_prefix_from_title ON /*_*/iwlinks (iwl_prefix, iwl_from, iwl_title); diff --git a/maintenance/archives/patch-iwlinks.sql b/maintenance/archives/patch-iwlinks.sql index 89b34cb1..b7bd3f13 100644 --- a/maintenance/archives/patch-iwlinks.sql +++ b/maintenance/archives/patch-iwlinks.sql @@ -1,10 +1,10 @@ --- +-- -- Track inline interwiki links -- CREATE TABLE /*_*/iwlinks ( -- page_id of the referring page iwl_from int unsigned NOT NULL default 0, - + -- Interwiki prefix code of the target iwl_prefix varbinary(20) NOT NULL default '', diff --git a/maintenance/archives/patch-job.sql b/maintenance/archives/patch-job.sql index c9199efb..662f5d27 100644 --- a/maintenance/archives/patch-job.sql +++ b/maintenance/archives/patch-job.sql @@ -1,7 +1,7 @@ -- Jobs performed by parallel apache threads or a command-line daemon CREATE TABLE /*_*/job ( job_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, - + -- Command name -- Limited to 60 to prevent key length overflow job_cmd varbinary(60) NOT NULL default '', diff --git a/maintenance/archives/patch-job_attempts.sql b/maintenance/archives/patch-job_attempts.sql new file mode 100644 index 00000000..47b73e81 --- /dev/null +++ b/maintenance/archives/patch-job_attempts.sql @@ -0,0 +1,4 @@ +ALTER TABLE /*_*/job + ADD COLUMN job_attempts integer unsigned NOT NULL default 0; + +CREATE INDEX /*i*/job_cmd_token_id ON /*_*/job (job_cmd,job_token,job_id); diff --git a/maintenance/archives/patch-job_token.sql b/maintenance/archives/patch-job_token.sql new file mode 100644 index 00000000..080fa97c --- /dev/null +++ b/maintenance/archives/patch-job_token.sql @@ -0,0 +1,9 @@ +ALTER TABLE /*_*/job + ADD COLUMN job_random integer unsigned NOT NULL default 0, + ADD COLUMN job_token varbinary(32) NOT NULL default '', + ADD COLUMN job_token_timestamp varbinary(14) NULL default NULL, + ADD COLUMN job_sha1 varbinary(32) NOT NULL default ''; + +CREATE INDEX /*i*/job_sha1 ON /*_*/job (job_sha1); +CREATE INDEX /*i*/job_cmd_token ON /*_*/job (job_cmd,job_token,job_random); + diff --git a/maintenance/archives/patch-kill-iwl_pft.sql b/maintenance/archives/patch-kill-iwl_pft.sql deleted file mode 100644 index 96e14356..00000000 --- a/maintenance/archives/patch-kill-iwl_pft.sql +++ /dev/null @@ -1,7 +0,0 @@ --- --- Kill the old iwl_prefix_from_title index, which may be present on some --- installs if they ran update.php between it being added and being renamed --- - -DROP INDEX /*i*/iwl_prefix_from_title ON /*_*/iwlinks; - diff --git a/maintenance/archives/patch-langlinks.sql b/maintenance/archives/patch-langlinks.sql index ffff07c0..5594acd5 100644 --- a/maintenance/archives/patch-langlinks.sql +++ b/maintenance/archives/patch-langlinks.sql @@ -1,7 +1,7 @@ CREATE TABLE /*$wgDBprefix*/langlinks ( -- page_id of the referring page ll_from int unsigned NOT NULL default '0', - + -- Language code of the target ll_lang varbinary(20) NOT NULL default '', diff --git a/maintenance/archives/patch-linktables.sql b/maintenance/archives/patch-linktables.sql index b15878c3..d53d2ea3 100644 --- a/maintenance/archives/patch-linktables.sql +++ b/maintenance/archives/patch-linktables.sql @@ -6,13 +6,13 @@ DROP TABLE IF EXISTS /*$wgDBprefix*/links; CREATE TABLE /*$wgDBprefix*/links ( -- Key to the page_id of the page containing the link. l_from int unsigned NOT NULL default '0', - + -- Key to the page_id of the link target. -- An unfortunate consequence of this is that rename -- operations require changing the links entries for -- all links to the moved page. l_to int unsigned NOT NULL default '0', - + UNIQUE KEY l_from(l_from,l_to), KEY (l_to) @@ -27,7 +27,7 @@ DROP TABLE IF EXISTS /*$wgDBprefix*/brokenlinks; CREATE TABLE /*$wgDBprefix*/brokenlinks ( -- Key to the page_id of the page containing the link. bl_from int unsigned NOT NULL default '0', - + -- Text of the target page title ("namesapce:title"). -- Unfortunately this doesn't split the namespace index -- key and therefore can't easily be joined to anything. @@ -46,12 +46,12 @@ DROP TABLE IF EXISTS /*$wgDBprefix*/imagelinks; CREATE TABLE /*$wgDBprefix*/imagelinks ( -- Key to page_id of the page containing the image / media link. il_from int unsigned NOT NULL default '0', - + -- 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 varchar(255) binary NOT NULL default '', - + UNIQUE KEY il_from(il_from,il_to), KEY (il_to) diff --git a/maintenance/archives/patch-log_search-rename-index.sql b/maintenance/archives/patch-log_search-rename-index.sql index 41e051d8..7e1113e6 100644 --- a/maintenance/archives/patch-log_search-rename-index.sql +++ b/maintenance/archives/patch-log_search-rename-index.sql @@ -1,7 +1,7 @@ -- Rename the primary unique index from PRIMARY to ls_field_val -- This is for MySQL only and is necessary only for databases which were updated -- between MW 1.16 development revisions r50567 and r51465. -ALTER TABLE /*_*/log_search - DROP PRIMARY KEY, +ALTER TABLE /*_*/log_search + DROP PRIMARY KEY, ADD UNIQUE INDEX ls_field_val (ls_field,ls_value,ls_log_id); diff --git a/maintenance/archives/patch-log_user_text.sql b/maintenance/archives/patch-log_user_text.sql index 9a783d87..12ca75e5 100644 --- a/maintenance/archives/patch-log_user_text.sql +++ b/maintenance/archives/patch-log_user_text.sql @@ -1,4 +1,4 @@ -ALTER TABLE /*$wgDBprefix*/logging +ALTER TABLE /*$wgDBprefix*/logging ADD log_user_text varchar(255) binary NOT NULL default '', ADD log_page int unsigned NULL, CHANGE log_type log_type varbinary(32) NOT NULL, diff --git a/maintenance/archives/patch-logging-times-index.sql b/maintenance/archives/patch-logging-times-index.sql index e66ceec4..5f24f5c3 100644 --- a/maintenance/archives/patch-logging-times-index.sql +++ b/maintenance/archives/patch-logging-times-index.sql @@ -1,8 +1,8 @@ --- +-- -- patch-logging-times-index.sql --- +-- -- Add a very humble index on logging times --- +-- ALTER TABLE /*$wgDBprefix*/logging ADD INDEX times (log_timestamp); diff --git a/maintenance/archives/patch-logging.sql b/maintenance/archives/patch-logging.sql index b5cfdf72..79df0dd4 100644 --- a/maintenance/archives/patch-logging.sql +++ b/maintenance/archives/patch-logging.sql @@ -7,21 +7,21 @@ CREATE TABLE /*$wgDBprefix*/logging ( -- action field, but only the type controls categorization. log_type varbinary(10) NOT NULL default '', log_action varbinary(10) NOT NULL default '', - + -- Timestamp. Duh. log_timestamp binary(14) NOT NULL default '19700101000000', - + -- The user who performed this action; key to user_id log_user int unsigned NOT NULL default 0, - + -- Key to the page affected. Where a user is the target, -- this will point to the user page. log_namespace int NOT NULL default 0, log_title varchar(255) binary NOT NULL default '', - + -- Freeform text. Interpreted as edit history comments. log_comment varchar(255) NOT NULL default '', - + -- LF separated list of miscellaneous parameters log_params blob NOT NULL, diff --git a/maintenance/archives/patch-mime_minor_length.sql b/maintenance/archives/patch-mime_minor_length.sql index 8b63d1f0..88dd64cf 100644 --- a/maintenance/archives/patch-mime_minor_length.sql +++ b/maintenance/archives/patch-mime_minor_length.sql @@ -3,8 +3,8 @@ ALTER TABLE /*_*/filearchive ALTER TABLE /*_*/image MODIFY COLUMN img_minor_mime varbinary(100) NOT NULL default "unknown"; - + ALTER TABLE /*_*/oldimage MODIFY COLUMN oi_minor_mime varbinary(100) NOT NULL default "unknown"; - + INSERT INTO /*_*/updatelog(ul_key) VALUES ('mime_minor_length'); diff --git a/maintenance/archives/patch-msg_resource.sql b/maintenance/archives/patch-msg_resource.sql index f4f35339..9fa05d2a 100644 --- a/maintenance/archives/patch-msg_resource.sql +++ b/maintenance/archives/patch-msg_resource.sql @@ -2,7 +2,7 @@ CREATE TABLE /*_*/msg_resource ( -- Resource name mr_resource varbinary(255) NOT NULL, - -- Language code + -- Language code mr_lang varbinary(32) NOT NULL, -- JSON blob. This is an incomplete JSON object, i.e. without the wrapping {} mr_blob mediumblob NOT NULL, diff --git a/maintenance/archives/patch-oi_metadata.sql b/maintenance/archives/patch-oi_metadata.sql index bc848878..df043c55 100644 --- a/maintenance/archives/patch-oi_metadata.sql +++ b/maintenance/archives/patch-oi_metadata.sql @@ -1,10 +1,10 @@ --- +-- -- patch-oi_metadata.sql --- +-- -- Add data to allow for direct reference to old images -- Some re-indexing here. -- Old images can be included into pages effeciently now. --- +-- ALTER TABLE /*$wgDBprefix*/oldimage DROP INDEX oi_name, diff --git a/maintenance/archives/patch-oldimage-user-index.sql b/maintenance/archives/patch-oldimage-user-index.sql index 949625eb..2c7f8071 100644 --- a/maintenance/archives/patch-oldimage-user-index.sql +++ b/maintenance/archives/patch-oldimage-user-index.sql @@ -1,8 +1,8 @@ --- +-- -- oldimage-user-index.sql --- +-- -- Add user/timestamp index to old image versions --- +-- ALTER TABLE /*$wgDBprefix*/oldimage ADD INDEX oi_usertext_timestamp (oi_user_text,oi_timestamp); diff --git a/maintenance/archives/patch-page-page_content_model.sql b/maintenance/archives/patch-page-page_content_model.sql new file mode 100644 index 00000000..30434d93 --- /dev/null +++ b/maintenance/archives/patch-page-page_content_model.sql @@ -0,0 +1,2 @@ +ALTER TABLE /*$wgDBprefix*/page + ADD page_content_model varbinary(32) DEFAULT NULL; diff --git a/maintenance/archives/patch-page_props-propname-page-index.sql b/maintenance/archives/patch-page_props-propname-page-index.sql new file mode 100644 index 00000000..822fa04d --- /dev/null +++ b/maintenance/archives/patch-page_props-propname-page-index.sql @@ -0,0 +1,4 @@ +-- +-- Creates the pp_propname_page index on page_props +-- +CREATE UNIQUE INDEX /*i*/pp_propname_page ON /*_*/page_props (pp_propname, pp_page); diff --git a/maintenance/archives/patch-pagelinks.sql b/maintenance/archives/patch-pagelinks.sql index 118592fb..cea89b52 100644 --- a/maintenance/archives/patch-pagelinks.sql +++ b/maintenance/archives/patch-pagelinks.sql @@ -1,7 +1,7 @@ -- -- Create the new pagelinks table to merge links and brokenlinks data, -- and populate it. --- +-- -- Unlike the old links and brokenlinks, these records will not need to be -- altered when target pages are created, deleted, or renamed. This should -- reduce the amount of severe database frustration that happens when widely- @@ -19,14 +19,14 @@ CREATE TABLE /*$wgDBprefix*/pagelinks ( -- Key to the page_id of the page containing the link. pl_from int unsigned 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 -- and deletions may refer to different page records as time -- goes by. pl_namespace int NOT NULL default '0', pl_title varchar(255) binary NOT NULL default '', - + UNIQUE KEY pl_from(pl_from,pl_namespace,pl_title), KEY (pl_namespace,pl_title) diff --git a/maintenance/archives/patch-parsercache.sql b/maintenance/archives/patch-parsercache.sql index 395a81bd..5fe241c3 100644 --- a/maintenance/archives/patch-parsercache.sql +++ b/maintenance/archives/patch-parsercache.sql @@ -1,5 +1,5 @@ -- --- parsercache table, for cacheing complete parsed articles +-- parsercache table, for cacheing complete parsed articles -- before they are imbedded in the skin. -- diff --git a/maintenance/archives/patch-pl-tl-il-unique.sql b/maintenance/archives/patch-pl-tl-il-unique.sql index 186a2036..a3566705 100644 --- a/maintenance/archives/patch-pl-tl-il-unique.sql +++ b/maintenance/archives/patch-pl-tl-il-unique.sql @@ -1,6 +1,6 @@ --- +-- -- patch-pl-tl-il-unique-index.sql --- +-- -- Make reorderings of UNIQUE indices UNIQUE as well DROP INDEX /*i*/pl_namespace ON /*_*/pagelinks; diff --git a/maintenance/archives/patch-querycache.sql b/maintenance/archives/patch-querycache.sql index e6da79cc..8e1a5188 100644 --- a/maintenance/archives/patch-querycache.sql +++ b/maintenance/archives/patch-querycache.sql @@ -3,14 +3,14 @@ CREATE TABLE /*$wgDBprefix*/querycache ( -- A key name, generally the base name of of the special page. qc_type varbinary(32) NOT NULL, - + -- Some sort of stored value. Sizes, counts... qc_value int unsigned NOT NULL default '0', - + -- Target namespace+title qc_namespace int NOT NULL default '0', qc_title varchar(255) binary NOT NULL default '', - + KEY (qc_type,qc_value) ) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-querycachetwo.sql b/maintenance/archives/patch-querycachetwo.sql index 01623bc7..79131310 100644 --- a/maintenance/archives/patch-querycachetwo.sql +++ b/maintenance/archives/patch-querycachetwo.sql @@ -3,14 +3,14 @@ CREATE TABLE /*$wgDBprefix*/querycachetwo ( -- A key name, generally the base name of of the special page. qcc_type varbinary(32) NOT NULL, - + -- Some sort of stored value. Sizes, counts... qcc_value int unsigned NOT NULL default '0', - + -- Target namespace+title qcc_namespace int NOT NULL default '0', qcc_title varchar(255) binary NOT NULL default '', - + -- Target namespace+title2 qcc_namespacetwo int NOT NULL default '0', qcc_titletwo varchar(255) binary NOT NULL default '', diff --git a/maintenance/archives/patch-rc_deleted.sql b/maintenance/archives/patch-rc_deleted.sql index 04ead974..f4bbd0f9 100644 --- a/maintenance/archives/patch-rc_deleted.sql +++ b/maintenance/archives/patch-rc_deleted.sql @@ -1,6 +1,6 @@ -- Adding rc_deleted field for revisiondelete -- Add rc_logid to match log_id -ALTER TABLE /*$wgDBprefix*/recentchanges +ALTER TABLE /*$wgDBprefix*/recentchanges ADD rc_deleted tinyint unsigned NOT NULL default '0', ADD rc_logid int unsigned NOT NULL default '0', ADD rc_log_type varbinary(255) NULL default NULL, diff --git a/maintenance/archives/patch-rc_id.sql b/maintenance/archives/patch-rc_id.sql index 3b023753..28caee0e 100644 --- a/maintenance/archives/patch-rc_id.sql +++ b/maintenance/archives/patch-rc_id.sql @@ -1,6 +1,6 @@ -- Primary key in recentchanges -ALTER TABLE /*$wgDBprefix*/recentchanges +ALTER TABLE /*$wgDBprefix*/recentchanges ADD rc_id int NOT NULL auto_increment, ADD PRIMARY KEY rc_id (rc_id); diff --git a/maintenance/archives/patch-rc_ip.sql b/maintenance/archives/patch-rc_ip.sql index 6b0b0534..4d93300f 100644 --- a/maintenance/archives/patch-rc_ip.sql +++ b/maintenance/archives/patch-rc_ip.sql @@ -1,6 +1,6 @@ -- Adding the rc_ip field for logging of IP addresses in recentchanges -ALTER TABLE /*$wgDBprefix*/recentchanges +ALTER TABLE /*$wgDBprefix*/recentchanges ADD rc_ip varbinary(40) NOT NULL default '', ADD INDEX rc_ip (rc_ip); diff --git a/maintenance/archives/patch-rc_moved.sql b/maintenance/archives/patch-rc_moved.sql new file mode 100644 index 00000000..2fa1de6b --- /dev/null +++ b/maintenance/archives/patch-rc_moved.sql @@ -0,0 +1,4 @@ +-- rc_moved_to_ns and rc_moved_to_title is no longer used, delete the fields + +ALTER TABLE /*$wgDBprefix*/recentchanges DROP COLUMN rc_moved_to_ns, + DROP COLUMN rc_moved_to_title; diff --git a/maintenance/archives/patch-redirect.sql b/maintenance/archives/patch-redirect.sql index 5d7218bc..d2957df4 100644 --- a/maintenance/archives/patch-redirect.sql +++ b/maintenance/archives/patch-redirect.sql @@ -1,7 +1,7 @@ -- -- Create the new redirect table. -- For each redirect, this table contains exactly one row defining its target --- +-- CREATE TABLE /*$wgDBprefix*/redirect ( -- Key to the page_id of the redirect page rd_from int unsigned NOT NULL default '0', diff --git a/maintenance/archives/patch-rename-iwl_prefix.sql b/maintenance/archives/patch-rename-iwl_prefix.sql index 4b11b36b..4a410037 100644 --- a/maintenance/archives/patch-rename-iwl_prefix.sql +++ b/maintenance/archives/patch-rename-iwl_prefix.sql @@ -1,4 +1,4 @@ --- +-- -- Recreates the iwl_prefix index for the iwlinks table -- CREATE UNIQUE INDEX /*i*/iwl_prefix_title_from ON /*_*/iwlinks (iwl_prefix, iwl_title, iwl_from); diff --git a/maintenance/archives/patch-restructure.sql b/maintenance/archives/patch-restructure.sql index 7b638483..a5bc3e52 100644 --- a/maintenance/archives/patch-restructure.sql +++ b/maintenance/archives/patch-restructure.sql @@ -38,7 +38,6 @@ CREATE TABLE /*$wgDBprefix*/revision ( 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), @@ -53,7 +52,7 @@ CREATE TABLE /*$wgDBprefix*/revision ( -- 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) -- ); diff --git a/maintenance/archives/patch-revision-rev_content_format.sql b/maintenance/archives/patch-revision-rev_content_format.sql new file mode 100644 index 00000000..22aeb8a7 --- /dev/null +++ b/maintenance/archives/patch-revision-rev_content_format.sql @@ -0,0 +1,2 @@ +ALTER TABLE /*$wgDBprefix*/revision + ADD rev_content_format varbinary(64) DEFAULT NULL; diff --git a/maintenance/archives/patch-revision-rev_content_model.sql b/maintenance/archives/patch-revision-rev_content_model.sql new file mode 100644 index 00000000..1ba05721 --- /dev/null +++ b/maintenance/archives/patch-revision-rev_content_model.sql @@ -0,0 +1,2 @@ +ALTER TABLE /*$wgDBprefix*/revision + ADD rev_content_model varbinary(32) DEFAULT NULL; diff --git a/maintenance/archives/patch-searchindex.sql b/maintenance/archives/patch-searchindex.sql index 9b635a8f..36507a2b 100644 --- a/maintenance/archives/patch-searchindex.sql +++ b/maintenance/archives/patch-searchindex.sql @@ -10,13 +10,13 @@ DROP TABLE IF EXISTS /*$wgDBprefix*/searchindex; CREATE TABLE /*$wgDBprefix*/searchindex ( -- Key to page_id si_page int unsigned NOT NULL, - + -- Munged version of title si_title varchar(255) NOT NULL default '', - + -- Munged version of body text si_text mediumtext NOT NULL, - + UNIQUE KEY (si_page) ) ENGINE=MyISAM; diff --git a/maintenance/archives/patch-sites.sql b/maintenance/archives/patch-sites.sql new file mode 100644 index 00000000..88392748 --- /dev/null +++ b/maintenance/archives/patch-sites.sql @@ -0,0 +1,71 @@ +-- Patch to add the sites and site_identifiers tables. +-- Licence: GNU GPL v2+ +-- Author: Jeroen De Dauw < jeroendedauw@gmail.com > + + +-- Holds all the sites known to the wiki. +CREATE TABLE IF NOT EXISTS /*_*/sites ( +-- Numeric id of the site + site_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + + -- Global identifier for the site, ie 'enwiktionary' + site_global_key varbinary(32) NOT NULL, + + -- Type of the site, ie 'mediawiki' + site_type varbinary(32) NOT NULL, + + -- Group of the site, ie 'wikipedia' + site_group varbinary(32) NOT NULL, + + -- Source of the site data, ie 'local', 'wikidata', 'my-magical-repo' + site_source varbinary(32) NOT NULL, + + -- Language code of the sites primary language. + site_language varbinary(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 varbinary(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 VARCHAR(255) NOT NULL, + + -- Type dependent site data. + site_data BLOB 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 bool NOT NULL, + + -- Type dependent site config. + -- For instance if template transclusion should be allowed if it's a MediaWiki. + site_config BLOB NOT NULL +) /*$wgDBTableOptions*/; + +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 IF NOT EXISTS /*_*/site_identifiers ( + -- Key on site.site_id + si_site INT UNSIGNED NOT NULL, + + -- local key type, ie 'interwiki' or 'langlink' + si_type varbinary(32) NOT NULL, + + -- local key value, ie 'en' or 'wiktionary' + si_key varbinary(32) NOT NULL +) /*$wgDBTableOptions*/; + +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);
\ No newline at end of file diff --git a/maintenance/archives/patch-tag_summary.sql b/maintenance/archives/patch-tag_summary.sql new file mode 100644 index 00000000..a81b3680 --- /dev/null +++ b/maintenance/archives/patch-tag_summary.sql @@ -0,0 +1,12 @@ +-- Rollup table to pull a LIST of tags simply without ugly GROUP_CONCAT that only works on MySQL 4.1+ +-- Andrew Garrett, 2009-01 +CREATE TABLE /*_*/tag_summary ( + ts_rc_id int NULL, + ts_log_id int NULL, + ts_rev_id int NULL, + ts_tags BLOB NOT NULL +) /*$wgDBTableOptions*/; + +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); diff --git a/maintenance/archives/patch-templatelinks.sql b/maintenance/archives/patch-templatelinks.sql index a545b34e..086b6a1b 100644 --- a/maintenance/archives/patch-templatelinks.sql +++ b/maintenance/archives/patch-templatelinks.sql @@ -4,16 +4,15 @@ CREATE TABLE /*$wgDBprefix*/templatelinks ( -- Key to the page_id of the page containing the link. tl_from int unsigned 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 -- and deletions may refer to different page records as time -- goes by. tl_namespace int NOT NULL default '0', tl_title varchar(255) binary NOT NULL default '', - + UNIQUE KEY tl_from(tl_from,tl_namespace,tl_title), KEY (tl_namespace,tl_title) - ) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-testrun.sql b/maintenance/archives/patch-testrun.sql index 8591d81d..6699b554 100644 --- a/maintenance/archives/patch-testrun.sql +++ b/maintenance/archives/patch-testrun.sql @@ -12,13 +12,13 @@ drop table if exists /*$wgDBprefix*/testrun; create table /*$wgDBprefix*/testrun ( tr_id int not null auto_increment, - + tr_date char(14) binary, tr_mw_version blob, tr_php_version blob, tr_db_version blob, tr_uname blob, - + primary key (tr_id) ) engine=InnoDB; @@ -26,10 +26,10 @@ create table /*$wgDBprefix*/testitem ( ti_run int not null, ti_name varchar(255), ti_success bool, - + unique key (ti_run, ti_name), key (ti_run, ti_success), - + foreign key (ti_run) references /*$wgDBprefix*/testrun(tr_id) on delete cascade ) engine=InnoDB; diff --git a/maintenance/archives/patch-ufg_group-length-increase-255.sql b/maintenance/archives/patch-ufg_group-length-increase-255.sql new file mode 100644 index 00000000..4b7f0d38 --- /dev/null +++ b/maintenance/archives/patch-ufg_group-length-increase-255.sql @@ -0,0 +1,2 @@ +ALTER TABLE /*_*/user_former_groups + MODIFY COLUMN ufg_group varbinary(255) NOT NULL default ''; diff --git a/maintenance/archives/patch-ufg_group-length-increase.sql b/maintenance/archives/patch-ufg_group-length-increase.sql deleted file mode 100644 index e24cba02..00000000 --- a/maintenance/archives/patch-ufg_group-length-increase.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE /*_*/user_former_groups - MODIFY COLUMN ufg_group varbinary(32) NOT NULL default ''; diff --git a/maintenance/archives/patch-ug_group-length-increase-255.sql b/maintenance/archives/patch-ug_group-length-increase-255.sql new file mode 100644 index 00000000..79e17ac0 --- /dev/null +++ b/maintenance/archives/patch-ug_group-length-increase-255.sql @@ -0,0 +1,2 @@ +ALTER TABLE /*_*/user_groups + MODIFY COLUMN ug_group varbinary(255) NOT NULL default ''; diff --git a/maintenance/archives/patch-ug_group-length-increase.sql b/maintenance/archives/patch-ug_group-length-increase.sql deleted file mode 100644 index e944a858..00000000 --- a/maintenance/archives/patch-ug_group-length-increase.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE /*_*/user_groups - MODIFY COLUMN ug_group varbinary(32) NOT NULL default ''; diff --git a/maintenance/archives/patch-uploadstash-us_props.sql b/maintenance/archives/patch-uploadstash-us_props.sql new file mode 100644 index 00000000..d64515a8 --- /dev/null +++ b/maintenance/archives/patch-uploadstash-us_props.sql @@ -0,0 +1,2 @@ +ALTER TABLE /*$wgDBprefix*/uploadstash + ADD COLUMN us_props blob; diff --git a/maintenance/archives/patch-uploadstash.sql b/maintenance/archives/patch-uploadstash.sql index 2512076f..14eaeab0 100644 --- a/maintenance/archives/patch-uploadstash.sql +++ b/maintenance/archives/patch-uploadstash.sql @@ -1,10 +1,10 @@ -- --- Store information about newly uploaded files before they're +-- Store information about newly uploaded files before they're -- moved into the actual filestore -- CREATE TABLE /*_*/uploadstash ( us_id int unsigned NOT NULL PRIMARY KEY auto_increment, - + -- the user who uploaded the file. us_user int unsigned NOT NULL, @@ -14,16 +14,16 @@ CREATE TABLE /*_*/uploadstash ( -- the original path us_orig_path varchar(255) NOT NULL, - + -- the temporary path at which the file is actually stored us_path varchar(255) NOT NULL, - + -- which type of upload the file came from (sometimes) us_source_type varchar(50), - + -- the date/time on which the file was added us_timestamp varbinary(14) not null, - + us_status varchar(50) not null, -- file properties from File::getPropsFromPath. these may prove unnecessary. @@ -33,12 +33,11 @@ CREATE TABLE /*_*/uploadstash ( us_sha1 varchar(31) NOT NULL, us_mime varchar(255), -- Media type as defined by the MEDIATYPE_xxx constants, should duplicate definition in the image table - us_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, + us_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, -- image-specific properties us_image_width int unsigned, us_image_height int unsigned, us_image_bits smallint unsigned - ) /*$wgDBTableOptions*/; -- sometimes there's a delete for all of a user's stuff. diff --git a/maintenance/archives/patch-user-realname.sql b/maintenance/archives/patch-user-realname.sql index 96edaa43..de7cee75 100644 --- a/maintenance/archives/patch-user-realname.sql +++ b/maintenance/archives/patch-user-realname.sql @@ -1,5 +1,5 @@ -- Add a 'real name' field where users can specify the name they want -- used for author attribution or other places that real names matter. -ALTER TABLE user +ALTER TABLE user ADD (user_real_name varchar(255) binary NOT NULL default ''); diff --git a/maintenance/archives/patch-user_former_groups.sql b/maintenance/archives/patch-user_former_groups.sql index ef56db06..b043196d 100644 --- a/maintenance/archives/patch-user_former_groups.sql +++ b/maintenance/archives/patch-user_former_groups.sql @@ -1,9 +1,9 @@ --- Stores the groups the user has once belonged to. +-- Stores the groups the user has once belonged to. -- The user may still belong these groups. Check user_groups. CREATE TABLE /*_*/user_former_groups ( -- Key to user_id ufg_user int unsigned NOT NULL default 0, - ufg_group varbinary(32) NOT NULL default '' + ufg_group varbinary(255) NOT NULL default '' ) /*$wgDBTableOptions*/; CREATE UNIQUE INDEX /*i*/ufg_user_group ON /*_*/user_former_groups (ufg_user,ufg_group); diff --git a/maintenance/archives/patch-user_groups.sql b/maintenance/archives/patch-user_groups.sql index c3740332..1683cf2a 100644 --- a/maintenance/archives/patch-user_groups.sql +++ b/maintenance/archives/patch-user_groups.sql @@ -9,7 +9,7 @@ CREATE TABLE /*$wgDBprefix*/user_groups ( -- Key to user_id ug_user int unsigned NOT NULL default '0', - + -- Group names are short symbolic string keys. -- The set of group names is open-ended, though in practice -- only some predefined ones are likely to be used. @@ -19,7 +19,7 @@ CREATE TABLE /*$wgDBprefix*/user_groups ( -- permissions of any group they're explicitly in, plus -- the implicit '*' and 'user' groups. ug_group varbinary(16) NOT NULL default '', - + PRIMARY KEY (ug_user,ug_group), KEY (ug_group) ) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-user_properties.sql b/maintenance/archives/patch-user_properties.sql index e30e00dc..85b00616 100644 --- a/maintenance/archives/patch-user_properties.sql +++ b/maintenance/archives/patch-user_properties.sql @@ -10,10 +10,10 @@ CREATE TABLE /*_*/user_properties( -- Foreign key to user.user_id up_user int not null, - + -- Name of the option being saved. This is indexed for bulk lookup. up_property varbinary(32) not null, - + -- Property value as a string. up_value blob ) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-user_rights.sql b/maintenance/archives/patch-user_rights.sql index 9866654c..4947cb1f 100644 --- a/maintenance/archives/patch-user_rights.sql +++ b/maintenance/archives/patch-user_rights.sql @@ -8,10 +8,10 @@ CREATE TABLE /*$wgDBprefix*/user_rights ( -- Key to user_id ur_user int unsigned NOT NULL, - + -- Comma-separated list of permission keys ur_rights tinyblob NOT NULL, - + UNIQUE KEY ur_user (ur_user) ) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/patch-valid_tag.sql b/maintenance/archives/patch-valid_tag.sql new file mode 100644 index 00000000..994a5d53 --- /dev/null +++ b/maintenance/archives/patch-valid_tag.sql @@ -0,0 +1,4 @@ +-- Andrew Garrett, 2009-01 +CREATE TABLE /*_*/valid_tag ( + vt_tag varchar(255) NOT NULL PRIMARY KEY +) /*$wgDBTableOptions*/; diff --git a/maintenance/archives/upgradeLogging.php b/maintenance/archives/upgradeLogging.php index 2c28011b..0749bbf6 100644 --- a/maintenance/archives/upgradeLogging.php +++ b/maintenance/archives/upgradeLogging.php @@ -21,7 +21,7 @@ * @ingroup MaintenanceArchive */ -require( __DIR__ . '/../commandLine.inc' ); +require __DIR__ . '/../commandLine.inc'; /** * Maintenance script that upgrade for log_id/log_deleted fields in a @@ -34,9 +34,9 @@ class UpdateLogging { /** * @var DatabaseBase */ - var $dbw; - var $batchSize = 1000; - var $minTs = false; + public $dbw; + public $batchSize = 1000; + public $minTs = false; function execute() { $this->dbw = wfGetDB( DB_MASTER ); @@ -211,4 +211,3 @@ EOT; $ul = new UpdateLogging; $ul->execute(); - diff --git a/maintenance/attachLatest.php b/maintenance/attachLatest.php index 475cafc9..2cf277fe 100644 --- a/maintenance/attachLatest.php +++ b/maintenance/attachLatest.php @@ -24,7 +24,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to correct wrong values in the `page_latest` field @@ -83,4 +83,4 @@ class AttachLatest extends Maintenance { } $maintClass = "AttachLatest"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/backup.inc b/maintenance/backup.inc index e3dc488b..3dc94c88 100644 --- a/maintenance/backup.inc +++ b/maintenance/backup.inc @@ -40,17 +40,17 @@ 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 $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 $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 $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; @@ -116,7 +116,7 @@ class BackupDumper { */ function loadPlugin( $class, $file ) { if ( $file != '' ) { - require_once( $file ); + require_once $file; } $register = array( $class, 'register' ); call_user_func_array( $register, array( &$this ) ); @@ -133,7 +133,7 @@ class BackupDumper { $matches = array(); if ( preg_match( '/^--(.+?)(?:=(.+?)(?::(.+?))?)?$/', $arg, $matches ) ) { @list( /* $full */ , $opt, $val, $param ) = $matches; - switch( $opt ) { + switch ( $opt ) { case "plugin": $this->loadPlugin( $val, $param ); break; @@ -170,11 +170,8 @@ class BackupDumper { break; case "force-normal": if ( !function_exists( 'utf8_normalize' ) ) { - wfDl( "php_utfnormal.so" ); - if ( !function_exists( 'utf8_normalize' ) ) { - $this->fatalError( "Failed to load UTF-8 normalization extension. " . - "Install or remove --force-normal parameter to use slower code." ); - } + $this->fatalError( "UTF-8 normalization extension not loaded. " . + "Install or remove --force-normal parameter to use slower code." ); } break; default: @@ -202,8 +199,9 @@ class BackupDumper { 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' ) ) + if ( ini_get( 'display_errors' ) ) { ini_set( 'display_errors', 'stderr' ); + } $this->initProgress( $history ); @@ -215,8 +213,9 @@ class BackupDumper { $wrapper = new ExportProgressFilter( $this->sink, $this ); $exporter->setOutputSink( $wrapper ); - if ( !$this->skipHeader ) + if ( !$this->skipHeader ) { $exporter->openStream(); + } # Log item dumps: all or by range if ( $history & WikiExporter::LOGS ) { if ( $this->startId || $this->endId ) { @@ -225,7 +224,7 @@ class BackupDumper { $exporter->allLogs(); } # Page dumps: all or by page ID range - } else if ( is_null( $this->pages ) ) { + } elseif ( is_null( $this->pages ) ) { if ( $this->startId || $this->endId ) { $exporter->pagesByRange( $this->startId, $this->endId ); } elseif ( $this->revStartId || $this->revEndId ) { @@ -238,8 +237,9 @@ class BackupDumper { $exporter->pagesByName( $this->pages ); } - if ( !$this->skipFooter ) + if ( !$this->skipFooter ) { $exporter->closeStream(); + } $this->report( true ); } @@ -365,7 +365,7 @@ class BackupDumper { function fatalError( $msg ) { $this->progress( "$msg\n" ); - die(1); + die( 1 ); } } diff --git a/maintenance/backupPrefetch.inc b/maintenance/backupPrefetch.inc index 0e12a1ce..04352b9b 100644 --- a/maintenance/backupPrefetch.inc +++ b/maintenance/backupPrefetch.inc @@ -48,10 +48,10 @@ class BaseDump { var $infiles = null; function BaseDump( $infile ) { - $this->infiles = explode(';',$infile); + $this->infiles = explode( ';', $infile ); $this->reader = new XMLReader(); - $infile = array_shift($this->infiles); - if (defined( 'LIBXML_PARSEHUGE' ) ) { + $infile = array_shift( $this->infiles ); + if ( defined( 'LIBXML_PARSEHUGE' ) ) { $this->reader->open( $infile, null, LIBXML_PARSEHUGE ); } else { @@ -110,8 +110,8 @@ class BaseDump { } } else { $this->close(); - if (count($this->infiles)) { - $infile = array_shift($this->infiles); + if ( count( $this->infiles ) ) { + $infile = array_shift( $this->infiles ); $this->reader->open( $infile ); $this->atEnd = false; } @@ -181,7 +181,7 @@ class BaseDump { } $buffer = ""; while ( $this->reader->read() ) { - switch( $this->reader->nodeType ) { + switch ( $this->reader->nodeType ) { case XMLReader::TEXT: // case XMLReader::WHITESPACE: case XMLReader::SIGNIFICANT_WHITESPACE: diff --git a/maintenance/backupTextPass.inc b/maintenance/backupTextPass.inc index f1f09546..c515c6fe 100644 --- a/maintenance/backupTextPass.inc +++ b/maintenance/backupTextPass.inc @@ -24,7 +24,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/backup.inc' ); +require_once __DIR__ . '/backup.inc'; /** * @ingroup Maintenance @@ -141,8 +141,9 @@ class TextPassDumper extends BackupDumper { 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' ) ) + if ( ini_get( 'display_errors' ) ) { ini_set( 'display_errors', 'stderr' ); + } $this->initProgress( $this->history ); @@ -169,7 +170,7 @@ class TextPassDumper extends BackupDumper { $this->xmlwriterobj = new XmlDumpWriter(); $input = fopen( $this->input, "rt" ); - $result = $this->readDump( $input ); + $this->readDump( $input ); if ( $this->spawnProc ) { $this->closeSpawn(); @@ -182,7 +183,7 @@ class TextPassDumper extends BackupDumper { global $IP; $url = $this->processFileOpt( $val, $param ); - switch( $opt ) { + switch ( $opt ) { case 'prefetch': require_once "$IP/maintenance/backupPrefetch.inc"; $this->prefetch = new BaseDump( $url ); @@ -214,7 +215,7 @@ class TextPassDumper extends BackupDumper { function processFileOpt( $val, $param ) { $fileURIs = explode( ';', $param ); foreach ( $fileURIs as $URI ) { - switch( $val ) { + switch ( $val ) { case "file": $newURI = $URI; break; @@ -294,11 +295,11 @@ class TextPassDumper extends BackupDumper { } function setTimeExceeded() { - $this->timeExceeded = True; + $this->timeExceeded = true; } function checkIfTimeExceeded() { - if ( $this->maxTimeAllowed && ( $this->lastTime - $this->timeOfCheckpoint > $this->maxTimeAllowed ) ) { + if ( $this->maxTimeAllowed && ( $this->lastTime - $this->timeOfCheckpoint > $this->maxTimeAllowed ) ) { return true; } return false; @@ -413,6 +414,8 @@ class TextPassDumper extends BackupDumper { * @throws MWException */ function getText( $id ) { + global $wgContentHandlerUseDB; + $prefetchNotTried = true; // Whether or not we already tried to get the text via prefetch. $text = false; // The candidate for a good text. false if no proper value. $failures = 0; // The number of times, this invocation of getText already failed. @@ -478,7 +481,28 @@ class TextPassDumper extends BackupDumper { if ( ! isset( $this->db ) ) { throw new MWException( "No database available" ); } - $revLength = $this->db->selectField( 'revision', 'rev_len', array( 'rev_id' => $revID ) ); + + $revLength = strlen( $text ); + if ( $wgContentHandlerUseDB ) { + $row = $this->db->selectRow( + 'revision', + array( 'rev_len', 'rev_content_model' ), + array( 'rev_id' => $revID ), + __METHOD__ + ); + if ( $row ) { + // only check the length for the wikitext content handler, + // it's a wasted (and failed) check otherwise + if ( $row->rev_content_model == CONTENT_MODEL_WIKITEXT ) { + $revLength = $row->rev_len; + } + } + + } + else { + $revLength = $this->db->selectField( 'revision', 'rev_len', array( 'rev_id' => $revID ) ); + } + if ( strlen( $text ) == $revLength ) { if ( $tryIsPrefetch ) { $this->prefetchCount++; @@ -611,17 +635,21 @@ class TextPassDumper extends BackupDumper { private function closeSpawn() { wfSuppressWarnings(); - if ( $this->spawnRead ) + if ( $this->spawnRead ) { fclose( $this->spawnRead ); + } $this->spawnRead = false; - if ( $this->spawnWrite ) + if ( $this->spawnWrite ) { fclose( $this->spawnWrite ); + } $this->spawnWrite = false; - if ( $this->spawnErr ) + if ( $this->spawnErr ) { fclose( $this->spawnErr ); + } $this->spawnErr = false; - if ( $this->spawnProc ) + if ( $this->spawnProc ) { pclose( $this->spawnProc ); + } $this->spawnProc = false; wfRestoreWarnings(); } @@ -631,11 +659,15 @@ class TextPassDumper extends BackupDumper { $ok = fwrite( $this->spawnWrite, "$id\n" ); // $this->progress( ">> $id" ); - if ( !$ok ) return false; + if ( !$ok ) { + return false; + } $ok = fflush( $this->spawnWrite ); // $this->progress( ">> [flush]" ); - if ( !$ok ) return false; + if ( !$ok ) { + return false; + } // check that the text id they are sending is the one we asked for // this avoids out of sync revision text errors we have encountered in the past @@ -649,18 +681,24 @@ class TextPassDumper extends BackupDumper { $len = fgets( $this->spawnRead ); // $this->progress( "<< " . trim( $len ) ); - if ( $len === false ) return false; + if ( $len === false ) { + return false; + } $nbytes = intval( $len ); // actual error, not zero-length text - if ( $nbytes < 0 ) return false; + if ( $nbytes < 0 ) { + return false; + } $text = ""; // Subprocess may not send everything at once, we have to loop. while ( $nbytes > strlen( $text ) ) { $buffer = fread( $this->spawnRead, $nbytes - strlen( $text ) ); - if ( $buffer === false ) break; + if ( $buffer === false ) { + break; + } $text .= $buffer; } diff --git a/maintenance/benchmarks/Benchmarker.php b/maintenance/benchmarks/Benchmarker.php index c198e0ff..dd558f32 100644 --- a/maintenance/benchmarks/Benchmarker.php +++ b/maintenance/benchmarks/Benchmarker.php @@ -27,7 +27,7 @@ * @ingroup Benchmark */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; /** * Base class for benchmark scripts. @@ -48,20 +48,20 @@ abstract class Benchmarker extends Maintenance { 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'] ) ) { - $ret = get_class( $bench['function'][0] ). '->' . $bench['function'][1]; + $ret = get_class( $bench['function'][0] ) . '->' . $bench['function'][1]; $bench['function'] = $ret; } @@ -75,7 +75,7 @@ abstract class Benchmarker extends Maintenance { } } - public function getFormattedResults( ) { + public function getFormattedResults() { $ret = ''; foreach( $this->results as $res ) { // show function with args @@ -85,7 +85,7 @@ abstract class Benchmarker extends Maintenance { join( ', ', $res['arguments'] ) ); $ret .= sprintf( " %6.2fms (%6.2fms each)\n", - $res['delta'] * 1000, + $res['delta'] * 1000, $res['average'] * 1000 ); } diff --git a/maintenance/benchmarks/README b/maintenance/benchmarks/README new file mode 100644 index 00000000..c021abd2 --- /dev/null +++ b/maintenance/benchmarks/README @@ -0,0 +1,7 @@ +This directory hold several benchmarking scripts used as a proof of speed +or to track PHP performances over time. + +To get somehow accurate result, you might want to bound the PHP process +to a specific CPU with `taskset` and raise its priority with `nice`. Example: + + $ taskset 1 nice -n-10 php bench_wfIsWindows.php diff --git a/maintenance/benchmarks/bench_HTTP_HTTPS.php b/maintenance/benchmarks/bench_HTTP_HTTPS.php index fa76ae22..6f800fb3 100644 --- a/maintenance/benchmarks/bench_HTTP_HTTPS.php +++ b/maintenance/benchmarks/bench_HTTP_HTTPS.php @@ -24,7 +24,7 @@ * @author Platonides */ -require_once( __DIR__ . '/Benchmarker.php' ); +require_once __DIR__ . '/Benchmarker.php'; /** * Maintenance script that benchmarks HTTP request vs HTTPS request. @@ -62,4 +62,4 @@ class bench_HTTP_HTTPS extends Benchmarker { } $maintClass = 'bench_HTTP_HTTPS'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/benchmarks/bench_delete_truncate.php b/maintenance/benchmarks/bench_delete_truncate.php index d9741496..3eff534b 100644 --- a/maintenance/benchmarks/bench_delete_truncate.php +++ b/maintenance/benchmarks/bench_delete_truncate.php @@ -21,7 +21,7 @@ * @ingroup Benchmark */ -require_once( __DIR__ . '/Benchmarker.php' ); +require_once __DIR__ . '/Benchmarker.php'; /** * Maintenance script that benchmarks SQL DELETE vs SQL TRUNCATE. @@ -101,4 +101,4 @@ class BenchmarkDeleteTruncate extends Benchmarker { } $maintClass = "BenchmarkDeleteTruncate"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/benchmarks/bench_if_switch.php b/maintenance/benchmarks/bench_if_switch.php index 1f590d4d..80fd9623 100644 --- a/maintenance/benchmarks/bench_if_switch.php +++ b/maintenance/benchmarks/bench_if_switch.php @@ -24,7 +24,7 @@ * @author Platonides */ -require_once( __DIR__ . '/Benchmarker.php' ); +require_once __DIR__ . '/Benchmarker.php'; /** * Maintenance script that benchmark if elseif... versus switch case. @@ -93,4 +93,4 @@ class bench_if_switch extends Benchmarker { } $maintClass = 'bench_if_switch'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +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 9fa7c8e3..bd21b186 100644 --- a/maintenance/benchmarks/bench_strtr_str_replace.php +++ b/maintenance/benchmarks/bench_strtr_str_replace.php @@ -23,14 +23,14 @@ * @ingroup Benchmark */ -require_once( __DIR__ . '/Benchmarker.php' ); +require_once __DIR__ . '/Benchmarker.php'; function bfNormalizeTitleStrTr( $str ) { - return strtr( $str, '_', ' ' ); + return strtr( $str, '_', ' ' ); } function bfNormalizeTitleStrReplace( $str ) { - return str_replace( '_', ' ', $str ); + return str_replace( '_', ' ', $str ); } /** @@ -75,4 +75,4 @@ class bench_strtr_str_replace extends Benchmarker { } $maintClass = 'bench_strtr_str_replace'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +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 f5987800..078293eb 100644 --- a/maintenance/benchmarks/bench_utf8_title_check.php +++ b/maintenance/benchmarks/bench_utf8_title_check.php @@ -21,7 +21,7 @@ * @ingroup Benchmark */ -require_once( __DIR__ . '/Benchmarker.php' ); +require_once __DIR__ . '/Benchmarker.php'; /** * This little benchmark executes the regexp used in Language->checkTitleEncoding() @@ -38,7 +38,7 @@ class bench_utf8_title_check extends Benchmarker { public function __construct() { parent::__construct(); - $this->data = array ( + $this->data = array( "", "United States of America", // 7bit ASCII "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e", @@ -123,4 +123,4 @@ class bench_utf8_title_check extends Benchmarker { } $maintClass = 'bench_utf8_title_check'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/benchmarks/bench_wfBaseConvert.php b/maintenance/benchmarks/bench_wfBaseConvert.php new file mode 100644 index 00000000..f8a21562 --- /dev/null +++ b/maintenance/benchmarks/bench_wfBaseConvert.php @@ -0,0 +1,77 @@ +<?php +/** + * Benchmark for wfBaseConvert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Benchmark + * @author Tyler Romeo + */ + +require_once __DIR__ . '/Benchmarker.php'; + +/** + * Maintenance script that benchmarks wfBaseConvert(). + * + * @ingroup Benchmark + */ +class bench_wfBaseConvert extends Benchmarker { + + public function __construct() { + parent::__construct(); + $this->mDescription = "Benchmark for wfBaseConvert."; + $this->addOption( "inbase", "Input base", false, true ); + $this->addOption( "outbase", "Output base", false, true ); + $this->addOption( "length", "Size in digits to generate for input", false, true ); + } + + public function execute() { + $inbase = $this->getOption( "inbase", 36 ); + $outbase = $this->getOption( "outbase", 16 ); + $length = $this->getOption( "length", 128 ); + $number = self::makeRandomNumber( $inbase, $length ); + + $this->bench( array( + array( + 'function' => 'wfBaseConvert', + 'args' => array( $number, $inbase, $outbase, 0, true, 'php' ) + ), + array( + 'function' => 'wfBaseConvert', + 'args' => array( $number, $inbase, $outbase, 0, true, 'bcmath' ) + ), + array( + 'function' => 'wfBaseConvert', + 'args' => array( $number, $inbase, $outbase, 0, true, 'gmp' ) + ), + )); + + $this->output( $this->getFormattedResults() ); + } + + protected static function makeRandomNumber( $base, $length ) { + $baseChars = "0123456789abcdefghijklmnopqrstuvwxyz"; + $res = ""; + for( $i = 0; $i < $length; $i++ ) { + $res .= $baseChars[mt_rand(0, $base - 1)]; + } + return $res; + } +} + +$maintClass = 'bench_wfBaseConvert'; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/benchmarks/bench_wfIsWindows.php b/maintenance/benchmarks/bench_wfIsWindows.php index 85439827..1cd2016b 100644 --- a/maintenance/benchmarks/bench_wfIsWindows.php +++ b/maintenance/benchmarks/bench_wfIsWindows.php @@ -24,7 +24,7 @@ * @author Platonides */ -require_once( __DIR__ . '/Benchmarker.php' ); +require_once __DIR__ . '/Benchmarker.php'; /** * Maintenance script that benchmarks wfIsWindows(). @@ -66,4 +66,4 @@ class bench_wfIsWindows extends Benchmarker { } $maintClass = 'bench_wfIsWindows'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/benchmarks/benchmarkHooks.php b/maintenance/benchmarks/benchmarkHooks.php index fdb016f4..3f5d6db0 100644 --- a/maintenance/benchmarks/benchmarkHooks.php +++ b/maintenance/benchmarks/benchmarkHooks.php @@ -21,7 +21,7 @@ * @ingroup Benchmark */ -require_once( __DIR__ . '/Benchmarker.php' ); +require_once __DIR__ . '/Benchmarker.php'; /** * Maintenance script that benchmarks %MediaWiki hooks. @@ -84,4 +84,4 @@ class BenchmarkHooks extends Benchmarker { } $maintClass = 'BenchmarkHooks'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/benchmarks/benchmarkPurge.php b/maintenance/benchmarks/benchmarkPurge.php index ec686b2a..fd863d52 100644 --- a/maintenance/benchmarks/benchmarkPurge.php +++ b/maintenance/benchmarks/benchmarkPurge.php @@ -21,7 +21,7 @@ * @ingroup Benchmark */ -require_once( __DIR__ . '/Benchmarker.php' ); +require_once __DIR__ . '/Benchmarker.php'; /** * Maintenance script that benchmarks Squid purge. @@ -112,4 +112,4 @@ class BenchmarkPurge extends Benchmarker { } $maintClass = "BenchmarkPurge"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cdb.php b/maintenance/cdb.php index c06c2cd0..d42f9f7a 100644 --- a/maintenance/cdb.php +++ b/maintenance/cdb.php @@ -23,12 +23,12 @@ */ /** */ -require_once( __DIR__ . '/commandLine.inc' ); +require_once __DIR__ . '/commandLine.inc'; function cdbShowHelp( $command ) { $commandList = array( 'load' => 'load a cdb file for reading', - 'get' => 'get a value for a key', + 'get' => 'get a value for a key', 'exit' => 'exit cdb', 'quit' => 'exit cdb', 'help' => 'help about a command', @@ -55,7 +55,9 @@ do { static $fileHandle; $line = Maintenance::readconsole(); - if ( $line === false ) exit; + if ( $line === false ) { + exit; + } $args = explode( ' ', $line ); $command = array_shift( $args ); @@ -67,25 +69,25 @@ do { cdbShowHelp( array_shift( $args ) ); break; case 'load': - if( !isset( $args[0] ) ) { + if ( !isset( $args[0] ) ) { print "Need a filename there buddy\n"; break; } $file = $args[0]; print "Loading cdb file $file..."; $fileHandle = CdbReader::open( $file ); - if( !$fileHandle ) { + if ( !$fileHandle ) { print "not a cdb file or unable to read it\n"; } else { print "ok\n"; } break; case 'get': - if( !$fileHandle ) { + if ( !$fileHandle ) { print "Need to load a cdb file first\n"; break; } - if( !isset( $args[0] ) ) { + if ( !isset( $args[0] ) ) { print "Need to specify a key, Luke\n"; break; } diff --git a/maintenance/changePassword.php b/maintenance/changePassword.php index f276fc16..5d98e1f5 100644 --- a/maintenance/changePassword.php +++ b/maintenance/changePassword.php @@ -24,7 +24,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to change the password of a given user. @@ -46,7 +46,7 @@ class ChangePassword extends Maintenance { } elseif ( $this->hasOption( "userid" ) ) { $user = User::newFromId( $this->getOption( 'userid' ) ); } else { - $this->error( "A \"user\" or \"userid\" must be set to change the password for" , true ); + $this->error( "A \"user\" or \"userid\" must be set to change the password for", true ); } if ( !$user || !$user->getId() ) { $this->error( "No such user: " . $this->getOption( 'user' ), true ); @@ -62,4 +62,4 @@ class ChangePassword extends Maintenance { } $maintClass = "ChangePassword"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/checkAutoLoader.php b/maintenance/checkAutoLoader.php deleted file mode 100644 index 8d0e442b..00000000 --- a/maintenance/checkAutoLoader.php +++ /dev/null @@ -1,63 +0,0 @@ -<?php -/** - * Check the autoloader - * - * 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 check classes definitions in the autoloader. - * - * @ingroup Maintenance - */ -class CheckAutoLoader extends Maintenance { - public function __construct() { - parent::__construct(); - $this->mDescription = "AutoLoader sanity checks"; - } - public function execute() { - global $wgAutoloadLocalClasses, $IP; - $files = array_unique( $wgAutoloadLocalClasses ); - - foreach ( $files as $file ) { - 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( $wgAutoloadLocalClasses[$class] ) ) { - // printf( "%-50s Unlisted, in %s\n", $class, $file ); - $this->output( "\t'$class' => '$file',\n" ); - } elseif ( $wgAutoloadLocalClasses[$class] !== $file ) { - $this->output( "$class: Wrong file: found in $file, listed in " . $wgAutoloadLocalClasses[$class] . "\n" ); - } - } - } - } -} - -$maintClass = "CheckAutoLoader"; -require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/checkBadRedirects.php b/maintenance/checkBadRedirects.php index 670b93de..a96e9b80 100644 --- a/maintenance/checkBadRedirects.php +++ b/maintenance/checkBadRedirects.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to check that pages marked as being redirects really are. @@ -50,7 +50,7 @@ class CheckBadRedirects extends Maintenance { $title = Title::makeTitle( $row->page_namespace, $row->page_title ); $rev = Revision::newFromId( $row->page_latest ); if ( $rev ) { - $target = Title::newFromRedirect( $rev->getText() ); + $target = $rev->getContent()->getRedirectTarget(); if ( !$target ) { $this->output( $title->getPrefixedText() . "\n" ); } @@ -61,4 +61,4 @@ class CheckBadRedirects extends Maintenance { } $maintClass = "CheckBadRedirects"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/checkImages.php b/maintenance/checkImages.php index c05d9151..e6aea537 100644 --- a/maintenance/checkImages.php +++ b/maintenance/checkImages.php @@ -20,7 +20,7 @@ * @file * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to check images to see if they exist, are readable, etc. @@ -87,4 +87,4 @@ class CheckImages extends Maintenance { } $maintClass = "CheckImages"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/checkLess.php b/maintenance/checkLess.php new file mode 100644 index 00000000..d02d8a7b --- /dev/null +++ b/maintenance/checkLess.php @@ -0,0 +1,72 @@ +<?php +/** + * Checks LESS files in known resources for errors + * + * 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 CheckLess extends Maintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = 'Checks LESS files for errors'; + } + + 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; + } + + $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 ); + } + } +} + +$maintClass = 'CheckLess'; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/checkSyntax.php b/maintenance/checkSyntax.php index 0a22f58c..dc8626df 100644 --- a/maintenance/checkSyntax.php +++ b/maintenance/checkSyntax.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to check syntax of all PHP files in MediaWiki. @@ -221,12 +221,14 @@ class CheckSyntax extends Maintenance { private function isSuitableFile( $file ) { $file = str_replace( '\\', '/', $file ); $ext = pathinfo( $file, PATHINFO_EXTENSION ); - if ( $ext != 'php' && $ext != 'inc' && $ext != 'php5' ) + if ( $ext != 'php' && $ext != 'inc' && $ext != 'php5' ) { return false; + } foreach ( $this->mIgnorePaths as $regex ) { $m = array(); - if ( preg_match( "~{$regex}~", $file, $m ) ) + if ( preg_match( "~{$regex}~", $file, $m ) ) { return false; + } } return true; } @@ -328,14 +330,15 @@ class CheckSyntax extends Maintenance { private function checkForMistakes( $file ) { foreach ( $this->mNoStyleCheckPaths as $regex ) { $m = array(); - if ( preg_match( "~{$regex}~", $file, $m ) ) + if ( preg_match( "~{$regex}~", $file, $m ) ) { return; + } } $text = file_get_contents( $file ); $tokens = token_get_all( $text ); - $this->checkEvilToken( $file, $tokens, '@', 'Error supression operator (@)'); + $this->checkEvilToken( $file, $tokens, '@', 'Error supression operator (@)' ); $this->checkRegex( $file, $text, '/^[\s\r\n]+<\?/', 'leading whitespace' ); $this->checkRegex( $file, $text, '/\?>[\s\r\n]*$/', 'trailing ?>' ); $this->checkRegex( $file, $text, '/^[\xFF\xFE\xEF]/', 'byte-order mark' ); @@ -367,5 +370,4 @@ class CheckSyntax extends Maintenance { } $maintClass = "CheckSyntax"; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/checkUsernames.php b/maintenance/checkUsernames.php index dd5e0022..6df189fc 100644 --- a/maintenance/checkUsernames.php +++ b/maintenance/checkUsernames.php @@ -21,8 +21,7 @@ * @ingroup Maintenance */ - -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to check that database usernames are actually valid. @@ -37,25 +36,34 @@ class CheckUsernames extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Verify that database usernames are actually valid"; + $this->setBatchSize( 1000 ); } function execute() { $dbr = wfGetDB( DB_SLAVE ); - $res = $dbr->select( 'user', - array( 'user_id', 'user_name' ), - null, - __METHOD__ - ); + $maxUserId = 0; + do { + $res = $dbr->select( 'user', + array( 'user_id', 'user_name' ), + array( 'user_id > ' . $maxUserId ), + __METHOD__, + array( + 'ORDER BY' => 'user_id', + 'LIMIT' => $this->mBatchSize, + ) + ); - foreach ( $res as $row ) { - 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 ); + foreach ( $res as $row ) { + 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 ); + } } - } + $maxUserId = $row->user_id; + } while ( $res->numRows() ); } } $maintClass = "CheckUsernames"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cleanupAncientTables.php b/maintenance/cleanupAncientTables.php index dbc2e0d3..694efaa6 100644 --- a/maintenance/cleanupAncientTables.php +++ b/maintenance/cleanupAncientTables.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to cleans up old database tables, dropping old indexes @@ -38,7 +38,7 @@ class CleanupAncientTables extends Maintenance { } public function execute() { - if( !$this->hasOption( 'force' ) ) { + 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" @@ -61,7 +61,7 @@ class CleanupAncientTables extends Maintenance { 'validate', // 1.6 ); - foreach( $ancientTables as $table ) { + foreach ( $ancientTables as $table ) { if ( $db->tableExists( $table, __METHOD__ ) ) { $this->output( "Dropping table $table..." ); $db->dropTable( $table, __METHOD__ ); @@ -78,7 +78,7 @@ class CleanupAncientTables extends Maintenance { 'user_timestamp', 'usertext_timestamp', ); - foreach( $oldIndexes as $index ) { + foreach ( $oldIndexes as $index ) { if ( $db->indexExists( 'text', $index, __METHOD__ ) ) { $this->output( "Dropping index $index from the text table..." ); $db->query( "DROP INDEX " . $db->addIdentifierQuotes( $index ) @@ -97,7 +97,7 @@ class CleanupAncientTables extends Maintenance { 'old_minor_edit', 'inverse_timestamp', ); - foreach( $oldFields as $field ) { + foreach ( $oldFields as $field ) { if ( $db->fieldExists( 'text', $field, __METHOD__ ) ) { $this->output( "Dropping the $field field from the text table..." ); $db->query( "ALTER TABLE " . $db->tableName( 'text' ) @@ -110,4 +110,4 @@ class CleanupAncientTables extends Maintenance { } $maintClass = "CleanupAncientTables"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cleanupCaps.php b/maintenance/cleanupCaps.php index ec2aa957..1a47ac4e 100644 --- a/maintenance/cleanupCaps.php +++ b/maintenance/cleanupCaps.php @@ -29,7 +29,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/cleanupTable.inc' ); +require_once __DIR__ . '/cleanupTable.inc'; /** * Maintenance script to clean up broken page links when somebody turns on $wgCapitalLinks. @@ -103,4 +103,4 @@ class CapsCleanup extends TableCleanup { } $maintClass = "CapsCleanup"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cleanupImages.php b/maintenance/cleanupImages.php index 4e7b937d..0e0b6194 100644 --- a/maintenance/cleanupImages.php +++ b/maintenance/cleanupImages.php @@ -29,7 +29,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/cleanupTable.inc' ); +require_once __DIR__ . '/cleanupTable.inc'; /** * Maintenance script to clean up broken, unparseable upload filenames. @@ -213,4 +213,4 @@ class ImageCleanup extends TableCleanup { } $maintClass = "ImageCleanup"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cleanupPreferences.php b/maintenance/cleanupPreferences.php index f37af775..06ae17fb 100644 --- a/maintenance/cleanupPreferences.php +++ b/maintenance/cleanupPreferences.php @@ -1,52 +1,52 @@ -<?php
-/**
- * Remove hidden preferences from the database.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @author TyA <tya.wiki@gmail.com>
- * @see [[bugzilla:30976]]
- * @ingroup Maintenance
- */
-
-require_once( __DIR__ . '/Maintenance.php' );
-
-/**
- * Maintenance script that removes hidden preferences from the database.
- *
- * @ingroup Maintenance
- */
-class CleanupPreferences extends Maintenance {
- public function execute() {
- global $wgHiddenPrefs;
-
- $dbw = wfGetDB( DB_MASTER );
- $dbw->begin();
- foreach( $wgHiddenPrefs as $item ) {
- $dbw->delete(
- 'user_properties',
- array( 'up_property' => $item ),
- __METHOD__
- );
- };
- $dbw->commit();
- $this->output( "Finished!\n" );
- }
-}
-
-$maintClass = 'CleanupPreferences'; // Tells it to run the class
-require_once( RUN_MAINTENANCE_IF_MAIN );
+<?php +/** + * Remove hidden preferences from the database. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @author TyA <tya.wiki@gmail.com> + * @see [[bugzilla:30976]] + * @ingroup Maintenance + */ + +require_once __DIR__ . '/Maintenance.php'; + +/** + * Maintenance script that removes hidden preferences from the database. + * + * @ingroup Maintenance + */ +class CleanupPreferences extends Maintenance { + public function execute() { + global $wgHiddenPrefs; + + $dbw = wfGetDB( DB_MASTER ); + $dbw->begin( __METHOD__ ); + foreach ( $wgHiddenPrefs as $item ) { + $dbw->delete( + 'user_properties', + array( 'up_property' => $item ), + __METHOD__ + ); + }; + $dbw->commit( __METHOD__ ); + $this->output( "Finished!\n" ); + } +} + +$maintClass = 'CleanupPreferences'; // Tells it to run the class +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cleanupRemovedModules.php b/maintenance/cleanupRemovedModules.php index 2085da94..84eec289 100644 --- a/maintenance/cleanupRemovedModules.php +++ b/maintenance/cleanupRemovedModules.php @@ -22,7 +22,7 @@ * @author Roan Kattouw */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to remove cache entries for removed ResourceLoader modules @@ -58,7 +58,7 @@ class CleanupRemovedModules extends Maintenance { $this->output( "Batch $i: $numRows rows\n" ); $i++; wfWaitForSlaves( $maxlag ); - } while( $numRows > 0 ); + } while ( $numRows > 0 ); $this->output( "done\n" ); $this->output( "Cleaning up msg_resource table...\n" ); @@ -72,7 +72,7 @@ class CleanupRemovedModules extends Maintenance { $this->output( "Batch $i: $numRows rows\n" ); $i++; wfWaitForSlaves( $maxlag ); - } while( $numRows > 0 ); + } while ( $numRows > 0 ); $this->output( "done\n" ); $this->output( "Cleaning up msg_resource_links table...\n" ); @@ -85,10 +85,10 @@ class CleanupRemovedModules extends Maintenance { $this->output( "Batch $i: $numRows rows\n" ); $i++; wfWaitForSlaves( $maxlag ); - } while( $numRows > 0 ); + } while ( $numRows > 0 ); $this->output( "done\n" ); } } $maintClass = "CleanupRemovedModules"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cleanupSpam.php b/maintenance/cleanupSpam.php index e20bcd87..4b8c9feb 100644 --- a/maintenance/cleanupSpam.php +++ b/maintenance/cleanupSpam.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to cleanup all spam from a given hostname. @@ -44,7 +44,7 @@ class CleanupSpam extends Maintenance { $username = wfMessage( 'spambot_username' )->text(); $wgUser = User::newFromName( $username ); if ( !$wgUser ) { - $this->error( "Invalid username", true ); + $this->error( "Invalid username specified in 'spambot_username' message: $username", true ); } // Create the user if necessary if ( !$wgUser->getId() ) { @@ -103,7 +103,8 @@ class CleanupSpam extends Maintenance { $rev = Revision::newFromTitle( $title ); $currentRevId = $rev->getId(); - while ( $rev && ( $rev->isDeleted( Revision::DELETED_TEXT ) || LinkFilter::matchEntry( $rev->getText() , $domain ) ) ) { + while ( $rev && ( $rev->isDeleted( Revision::DELETED_TEXT ) + || LinkFilter::matchEntry( $rev->getContent( Revision::RAW ), $domain ) ) ) { $rev = $rev->getPrevious(); } @@ -117,8 +118,10 @@ class CleanupSpam extends Maintenance { $page = WikiPage::factory( $title ); if ( $rev ) { // Revert to this revision + $content = $rev->getContent( Revision::RAW ); + $this->output( "reverting\n" ); - $page->doEdit( $rev->getText(), wfMessage( 'spam_reverting', $domain )->inContentLanguage()->text(), + $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 @@ -126,8 +129,11 @@ class CleanupSpam extends Maintenance { $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->doEdit( '', wfMessage( 'spam_blanking', $domain )->inContentLanguage()->text() ); + $page->doEditContent( $content, wfMessage( 'spam_blanking', $domain )->inContentLanguage()->text() ); } $dbw->commit( __METHOD__ ); } @@ -135,4 +141,4 @@ class CleanupSpam extends Maintenance { } $maintClass = "CleanupSpam"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cleanupTable.inc b/maintenance/cleanupTable.inc index 57acfd82..cbd1be6b 100644 --- a/maintenance/cleanupTable.inc +++ b/maintenance/cleanupTable.inc @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Generic class to cleanup a database table. Already subclasses Maintenance. @@ -41,6 +41,8 @@ class TableCleanup extends Maintenance { public $batchSize = 100; public $reportInterval = 100; + protected $processed, $updated, $count, $startTime, $table; + public function __construct() { parent::__construct(); $this->addOption( 'dry-run', 'Perform a dry run' ); @@ -66,6 +68,9 @@ class TableCleanup extends Maintenance { $this->table = $table; } + /** + * @param int $updated + */ protected function progress( $updated ) { $this->updated += $updated; $this->processed++; @@ -96,12 +101,16 @@ class TableCleanup extends Maintenance { flush(); } + /** + * @param array $params + * @throws MWException + */ public function runTable( $params ) { $dbr = wfGetDB( DB_SLAVE ); if ( array_diff( array_keys( $params ), - array( 'table', 'conds', 'index', 'callback' ) ) ) - { + array( 'table', 'conds', 'index', 'callback' ) ) + ) { throw new MWException( __METHOD__ . ': Missing parameter ' . implode( ', ', $params ) ); } @@ -111,7 +120,6 @@ class TableCleanup extends Maintenance { $this->init( $count, $table ); $this->output( "Processing $table...\n" ); - $index = (array)$params['index']; $indexConds = array(); $options = array( @@ -156,6 +164,10 @@ class TableCleanup extends Maintenance { $this->output( "Finished $table... $this->updated of $this->processed rows updated\n" ); } + /** + * @param array $matches + * @return string + */ protected function hexChar( $matches ) { return sprintf( "\\x%02x", ord( $matches[1] ) ); } diff --git a/maintenance/cleanupTitles.php b/maintenance/cleanupTitles.php index ad2577aa..5b5ef184 100644 --- a/maintenance/cleanupTitles.php +++ b/maintenance/cleanupTitles.php @@ -29,7 +29,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/cleanupTable.inc' ); +require_once __DIR__ . '/cleanupTable.inc'; /** * Maintenance script to clean up broken, unparseable titles. @@ -42,6 +42,9 @@ class TitleCleanup extends TableCleanup { $this->mDescription = "Script to clean up broken, unparseable titles"; } + /** + * @param object $row + */ protected function processRow( $row ) { global $wgContLang; $display = Title::makeName( $row->page_namespace, $row->page_title ); @@ -51,40 +54,54 @@ class TitleCleanup extends TableCleanup { if ( !is_null( $title ) && $title->canExist() && $title->getNamespace() == $row->page_namespace - && $title->getDBkey() === $row->page_title ) - { - return $this->progress( 0 ); // all is fine + && $title->getDBkey() === $row->page_title + ) { + $this->progress( 0 ); // all is fine + + return; } if ( $row->page_namespace == NS_FILE && $this->fileExists( $row->page_title ) ) { $this->output( "file $row->page_title needs cleanup, please run cleanupImages.php.\n" ); - return $this->progress( 0 ); + $this->progress( 0 ); } elseif ( is_null( $title ) ) { $this->output( "page $row->page_id ($display) is illegal.\n" ); $this->moveIllegalPage( $row ); - return $this->progress( 1 ); + $this->progress( 1 ); } else { $this->output( "page $row->page_id ($display) doesn't match self.\n" ); $this->moveInconsistentPage( $row, $title ); - return $this->progress( 1 ); + $this->progress( 1 ); } } + /** + * @param string $name + * @return bool + */ protected 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; } + /** + * @param object $row + */ protected function moveIllegalPage( $row ) { $legal = 'A-Za-z0-9_/\\\\-'; $legalized = preg_replace_callback( "!([^$legal])!", array( &$this, 'hexChar' ), $row->page_title ); - if ( $legalized == '.' ) $legalized = '(dot)'; - if ( $legalized == '_' ) $legalized = '(space)'; + if ( $legalized == '.' ) { + $legalized = '(dot)'; + } + if ( $legalized == '_' ) { + $legalized = '(space)'; + } $legalized = 'Broken/' . $legalized; $title = Title::newFromText( $legalized ); @@ -100,9 +117,11 @@ class TitleCleanup extends TableCleanup { $dest = $title->getDBkey(); if ( $this->dryrun ) { - $this->output( "DRY RUN: would rename $row->page_id ($row->page_namespace,'$row->page_title') to ($row->page_namespace,'$dest')\n" ); + $this->output( "DRY RUN: would rename $row->page_id ($row->page_namespace," . + "'$row->page_title') to ($row->page_namespace,'$dest')\n" ); } else { - $this->output( "renaming $row->page_id ($row->page_namespace,'$row->page_title') to ($row->page_namespace,'$dest')\n" ); + $this->output( "renaming $row->page_id ($row->page_namespace," . + "'$row->page_title') to ($row->page_namespace,'$dest')\n" ); $dbw = wfGetDB( DB_MASTER ); $dbw->update( 'page', array( 'page_title' => $dest ), @@ -111,17 +130,23 @@ class TitleCleanup extends TableCleanup { } } + /** + * @param object $row + * @param Title $title + */ protected function moveInconsistentPage( $row, $title ) { if ( $title->exists() || $title->getInterwiki() || !$title->canExist() ) { if ( $title->getInterwiki() || !$title->canExist() ) { - $prior = $title->getPrefixedDbKey(); + $prior = $title->getPrefixedDBkey(); } else { $prior = $title->getDBkey(); } # Old cleanupTitles could move articles there. See bug 23147. $ns = $row->page_namespace; - if ( $ns < 0 ) $ns = 0; + if ( $ns < 0 ) { + $ns = 0; + } $clean = 'Broken/' . $prior; $verified = Title::makeTitleSafe( $ns, $clean ); @@ -139,9 +164,11 @@ class TitleCleanup extends TableCleanup { $dest = $title->getDBkey(); if ( $this->dryrun ) { - $this->output( "DRY RUN: would rename $row->page_id ($row->page_namespace,'$row->page_title') to ($ns,'$dest')\n" ); + $this->output( "DRY RUN: would rename $row->page_id ($row->page_namespace," . + "'$row->page_title') to ($ns,'$dest')\n" ); } else { - $this->output( "renaming $row->page_id ($row->page_namespace,'$row->page_title') to ($ns,'$dest')\n" ); + $this->output( "renaming $row->page_id ($row->page_namespace," . + "'$row->page_title') to ($ns,'$dest')\n" ); $dbw = wfGetDB( DB_MASTER ); $dbw->update( 'page', array( @@ -156,4 +183,4 @@ class TitleCleanup extends TableCleanup { } $maintClass = "TitleCleanup"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cleanupUploadStash.php b/maintenance/cleanupUploadStash.php index cc329461..c2ba5558 100644 --- a/maintenance/cleanupUploadStash.php +++ b/maintenance/cleanupUploadStash.php @@ -25,7 +25,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to remove old or broken uploads from temporary uploaded @@ -41,50 +41,98 @@ class UploadStashCleanup extends Maintenance { } public function execute() { + global $wgUploadStashMaxAge; + $repo = RepoGroup::singleton()->getLocalRepo(); + $tempRepo = $repo->getTempRepo(); $dbr = $repo->getSlaveDb(); // how far back should this look for files to delete? - global $wgUploadStashMaxAge; + $cutoff = time() - $wgUploadStashMaxAge; $this->output( "Getting list of files to clean up...\n" ); $res = $dbr->select( 'uploadstash', 'us_key', - 'us_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( time() - $wgUploadStashMaxAge ) ), + 'us_timestamp < ' . $dbr->addQuotes( $dbr->timestamp( $cutoff ) ), __METHOD__ ); - if( !is_object( $res ) || $res->numRows() == 0 ) { - $this->output( "No files to cleanup!\n" ); - // nothing to do. - return; - } + // Delete all registered stash files... + if ( $res->numRows() == 0 ) { + $this->output( "No stashed files to cleanup according to the DB.\n" ); + } else { + // finish the read before starting writes. + $keys = array(); + foreach ( $res as $row ) { + array_push( $keys, $row->us_key ); + } + + $this->output( 'Removing ' . count( $keys ) . " file(s)...\n" ); + // this could be done some other, more direct/efficient way, but using + // UploadStash's own methods means it's less likely to fall accidentally + // out-of-date someday + $stash = new UploadStash( $repo ); - // finish the read before starting writes. - $keys = array(); - foreach( $res as $row ) { - array_push( $keys, $row->us_key ); + $i = 0; + foreach ( $keys as $key ) { + $i++; + try { + $stash->getFile( $key, true ); + $stash->removeFileNoAuth( $key ); + } catch ( UploadStashBadPathException $ex ) { + $this->output( "Failed removing stashed upload with key: $key\n" ); + } catch ( UploadStashZeroLengthFileException $ex ) { + $this->output( "Failed removing stashed upload with key: $key\n" ); + } + if ( $i % 100 == 0 ) { + $this->output( "$i\n" ); + } + } + $this->output( "$i done\n" ); } - $this->output( 'Removing ' . count($keys) . " file(s)...\n" ); - // this could be done some other, more direct/efficient way, but using - // UploadStash's own methods means it's less likely to fall accidentally - // out-of-date someday - $stash = new UploadStash( $repo ); + // Delete all the corresponding thumbnails... + $dir = $tempRepo->getZonePath( 'thumb' ); + $iterator = $tempRepo->getBackend()->getFileList( array( 'dir' => $dir ) ); + $this->output( "Deleting old thumbnails...\n" ); + $i = 0; + 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 ) { + $this->output( "$i\n" ); + } + } + } + $this->output( "$i done\n" ); + // Apparently lots of stash files are not registered in the DB... + $dir = $tempRepo->getZonePath( 'public' ); + $iterator = $tempRepo->getBackend()->getFileList( array( 'dir' => $dir, 'adviseStat' => 1 ) ); + $this->output( "Deleting orphaned temp files...\n" ); + if ( strpos( $dir, '/local-temp' ) === false ) { // sanity check + $this->error( "Temp repo is not using the temp container.", 1 ); // die + } $i = 0; - foreach( $keys as $key ) { - $i++; - try { - $stash->getFile( $key, true ); - $stash->removeFileNoAuth( $key ); - } catch ( UploadStashBadPathException $ex ) { - $this->output( "Failed removing stashed upload with key: $key\n" ); + 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 ( $i % 100 == 0 ) { - $this->output( "$i\n" ); + 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 ) { + $this->output( "$i\n" ); + } } } $this->output( "$i done\n" ); @@ -92,4 +140,4 @@ class UploadStashCleanup extends Maintenance { } $maintClass = "UploadStashCleanup"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cleanupWatchlist.php b/maintenance/cleanupWatchlist.php index fbab6a3c..f1a7b481 100644 --- a/maintenance/cleanupWatchlist.php +++ b/maintenance/cleanupWatchlist.php @@ -29,7 +29,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/cleanupTable.inc' ); +require_once __DIR__ . '/cleanupTable.inc'; /** * Maintenance script to remove broken, unparseable titles in the watchlist table. @@ -77,9 +77,9 @@ class WatchlistCleanup extends TableCleanup { if ( !$this->dryrun && $this->hasOption( 'fix' ) ) { $dbw = wfGetDB( DB_MASTER ); $dbw->delete( 'watchlist', array( - 'wl_user' => $row->wl_user, + 'wl_user' => $row->wl_user, 'wl_namespace' => $row->wl_namespace, - 'wl_title' => $row->wl_title ), + 'wl_title' => $row->wl_title ), __METHOD__ ); $this->output( "- removed\n" ); return 1; @@ -90,4 +90,4 @@ class WatchlistCleanup extends TableCleanup { } $maintClass = "WatchlistCleanup"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/clear_stats.php b/maintenance/clearCacheStats.php index 4581d532..6a966121 100644 --- a/maintenance/clear_stats.php +++ b/maintenance/clearCacheStats.php @@ -21,14 +21,14 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to remove all statistics tracking from the cache. * * @ingroup Maintenance */ -class clear_stats extends Maintenance { +class ClearCacheStats extends Maintenance { public function __construct() { parent::__construct(); @@ -56,5 +56,5 @@ class clear_stats extends Maintenance { } } -$maintClass = "clear_stats"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +$maintClass = "ClearCacheStats"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/clear_interwiki_cache.php b/maintenance/clearInterwikiCache.php index 88769df2..80c9004e 100644 --- a/maintenance/clear_interwiki_cache.php +++ b/maintenance/clearInterwikiCache.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to clear the cache of interwiki prefixes for all local wikis. @@ -55,4 +55,4 @@ class ClearInterwikiCache extends Maintenance { } $maintClass = "ClearInterwikiCache"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/commandLine.inc b/maintenance/commandLine.inc index 86a558d0..be071422 100644 --- a/maintenance/commandLine.inc +++ b/maintenance/commandLine.inc @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; global $optionsWithArgs; if ( !isset( $optionsWithArgs ) ) { @@ -55,5 +55,5 @@ class CommandLineInc extends Maintenance { } $maintClass = 'CommandLineInc'; -require( RUN_MAINTENANCE_IF_MAIN ); +require RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/compareParsers.php b/maintenance/compareParsers.php index a3337173..fabc2571 100644 --- a/maintenance/compareParsers.php +++ b/maintenance/compareParsers.php @@ -28,7 +28,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/dumpIterator.php' ); +require_once __DIR__ . '/dumpIterator.php'; /** * Maintenance script to take page text out of an XML dump file and render @@ -55,8 +55,8 @@ class CompareParsers extends DumpIterator { } public function checkOptions() { - if ( $this->hasOption('save-failed') ) { - $this->saveFailed = $this->getOption('save-failed'); + if ( $this->hasOption( 'save-failed' ) ) { + $this->saveFailed = $this->getOption( 'save-failed' ); } $this->stripParametersEnabled = $this->hasOption( 'strip-parameters' ); @@ -87,8 +87,9 @@ class CompareParsers extends DumpIterator { public function conclusions() { $this->error( "{$this->failed} failed revisions out of {$this->count}" ); - if ($this->count > 0) + if ( $this->count > 0 ) { $this->output( " (" . ( $this->failed / $this->count ) . "%)\n" ); + } } function stripParameters( $text ) { @@ -114,15 +115,24 @@ class CompareParsers extends DumpIterator { $parser1 = new $parser1Name(); $parser2 = new $parser2Name(); - $output1 = $parser1->parse( $rev->getText(), $title, $this->options ); - $output2 = $parser2->parse( $rev->getText(), $title, $this->options ); + $content = $rev->getContent(); + + if ( $content->getModel() !== CONTENT_MODEL_WIKITEXT ) { + $this->error( "Page {$title->getPrefixedText()} does not contain wikitext but {$content->getModel()}\n" ); + return; + } + + $text = strval( $content->getNativeData() ); + + $output1 = $parser1->parse( $text, $title, $this->options ); + $output2 = $parser2->parse( $text, $title, $this->options ); if ( $output1->getText() != $output2->getText() ) { $this->failed++; $this->error( "Parsing for {$title->getPrefixedText()} differs\n" ); if ( $this->saveFailed ) { - file_put_contents( $this->saveFailed . '/' . rawurlencode( $title->getPrefixedText() ) . ".txt", $rev->getText()); + file_put_contents( $this->saveFailed . '/' . rawurlencode( $title->getPrefixedText() ) . ".txt", $text ); } if ( $this->showDiff ) { $this->output( wfDiff( $this->stripParameters( $output1->getText() ), $this->stripParameters( $output2->getText() ), '' ) ); @@ -146,4 +156,4 @@ class CompareParsers extends DumpIterator { } $maintClass = "CompareParsers"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/convertLinks.php b/maintenance/convertLinks.php index 5f7b02e4..17b91110 100644 --- a/maintenance/convertLinks.php +++ b/maintenance/convertLinks.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to convert from the old links schema (string->ID) @@ -80,9 +80,9 @@ 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' ) ) { + if ( $dbw->tableExists( 'pagelinks' ) ) { $this->output( "...have pagelinks; skipping old links table updates\n" ); return; } @@ -177,15 +177,16 @@ 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" ); - if ( $tuplesAdded != 0 ) { + if ( $tuplesAdded != 0 ) { if ( $reportLinksConvProgress ) { $this->output( "Inserting $tuplesAdded tuples into $links_temp..." ); } $dbw->query( implode( "", $sqlWrite ) ); $totalTuplesInserted += $tuplesAdded; - if ( $reportLinksConvProgress ) + if ( $reportLinksConvProgress ) { $this->output( " done. Total $totalTuplesInserted tuples inserted.\n" ); - $this->performanceLog( $fh, $totalTuplesInserted . " " . ( $this->getMicroTime() - $baseTime ) . "\n" ); + $this->performanceLog( $fh, $totalTuplesInserted . " " . ( $this->getMicroTime() - $baseTime ) . "\n" ); + } } } $this->output( "$totalTuplesInserted valid titles and $numBadLinks invalid titles were processed.\n\n" ); @@ -258,4 +259,4 @@ This gives a huge speed improvement for very large links tables which are MyISAM } $maintClass = "ConvertLinks"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/convertUserOptions.php b/maintenance/convertUserOptions.php index 7c9ca269..34c643bb 100644 --- a/maintenance/convertUserOptions.php +++ b/maintenance/convertUserOptions.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to convert user options to the new `user_properties` table. @@ -56,7 +56,7 @@ class ConvertUserOptions extends Maintenance { array( 'LIMIT' => 50, 'FOR UPDATE' ) ); $id = $this->convertOptionBatch( $res, $dbw ); - $dbw->commit(); + $dbw->commit( __METHOD__ ); wfWaitForSlaves(); @@ -96,4 +96,4 @@ class ConvertUserOptions extends Maintenance { } $maintClass = "ConvertUserOptions"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/copyFileBackend.php b/maintenance/copyFileBackend.php index aebdee17..21ef4ffa 100644 --- a/maintenance/copyFileBackend.php +++ b/maintenance/copyFileBackend.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Copy all files in one container of one backend to another. @@ -35,6 +35,8 @@ require_once( __DIR__ . '/Maintenance.php' ); * @ingroup Maintenance */ class CopyFileBackend extends Maintenance { + protected $statCache = array(); + public function __construct() { parent::__construct(); $this->mDescription = "Copy files in one backend to another."; @@ -43,8 +45,10 @@ class CopyFileBackend extends Maintenance { $this->addOption( 'containers', 'Pipe separated list of containers', true, true ); $this->addOption( 'subdir', 'Only do items in this child directory', false, true ); $this->addOption( 'ratefile', 'File to check periodically for batch size', false, true ); + $this->addOption( 'prestat', 'Stat the destination files first (try to use listings)' ); $this->addOption( 'skiphash', 'Skip SHA-1 sync checks for files' ); $this->addOption( 'missingonly', 'Only copy files missing from destination listing' ); + $this->addOption( 'syncviadelete', 'Delete destination files missing from source listing' ); $this->addOption( 'utf8only', 'Skip source files that do not have valid UTF-8 names' ); $this->setBatchSize( 50 ); } @@ -53,7 +57,7 @@ class CopyFileBackend extends Maintenance { $src = FileBackendGroup::singleton()->get( $this->getOption( 'src' ) ); $dst = FileBackendGroup::singleton()->get( $this->getOption( 'dst' ) ); $containers = explode( '|', $this->getOption( 'containers' ) ); - $subDir = $this->getOption( rtrim( 'subdir', '/' ), '' ); + $subDir = rtrim( $this->getOption( 'subdir', '' ), '/' ); $rateFile = $this->getOption( 'ratefile' ); @@ -61,7 +65,6 @@ class CopyFileBackend extends Maintenance { $this->error( "Cannot check for UTF-8, mbstring extension missing.", 1 ); // die } - $count = 0; foreach ( $containers as $container ) { if ( $subDir != '' ) { $backendRel = "$container/$subDir"; @@ -71,40 +74,46 @@ class CopyFileBackend extends Maintenance { $this->output( "Doing container '$container'...\n" ); } - $srcPathsRel = $src->getFileList( array( - 'dir' => $src->getRootStoragePath() . "/$backendRel" ) ); - if ( $srcPathsRel === null ) { - $this->error( "Could not list files in $container.", 1 ); // die - } - - // Do a listing comparison if specified if ( $this->hasOption( 'missingonly' ) ) { - $relFilesSrc = array(); - $relFilesDst = array(); - foreach ( $srcPathsRel as $srcPathRel ) { - $relFilesSrc[] = $srcPathRel; + $this->output( "\tBuilding list of missing files..." ); + $srcPathsRel = $this->getListingDiffRel( $src, $dst, $backendRel ); + $this->output( count( $srcPathsRel ) . " file(s) need to be copied.\n" ); + } else { + $srcPathsRel = $src->getFileList( array( + 'dir' => $src->getRootStoragePath() . "/$backendRel", + 'adviseStat' => true // avoid HEADs + ) ); + if ( $srcPathsRel === null ) { + $this->error( "Could not list files in $container.", 1 ); // die } + } + + if ( $this->getOption( 'prestat' ) && !$this->hasOption( 'missingonly' ) ) { + // Build the stat cache for the destination files + $this->output( "\tBuilding destination stat cache..." ); $dstPathsRel = $dst->getFileList( array( - 'dir' => $dst->getRootStoragePath() . "/$backendRel" ) ); + 'dir' => $dst->getRootStoragePath() . "/$backendRel", + 'adviseStat' => true // avoid HEADs + ) ); if ( $dstPathsRel === null ) { $this->error( "Could not list files in $container.", 1 ); // die } + $this->statCache = array(); // clear foreach ( $dstPathsRel as $dstPathRel ) { - $relFilesDst[] = $dstPathRel; + $path = $dst->getRootStoragePath() . "/$backendRel/$dstPathRel"; + $this->statCache[sha1( $path )] = $dst->getFileStat( array( 'src' => $path ) ); } - // Only copy the missing files over in the next loop - $srcPathsRel = array_diff( $relFilesSrc, $relFilesDst ); - $this->output( count( $srcPathsRel ) . " file(s) need to be copied.\n" ); - unset( $relFilesSrc ); - unset( $relFilesDst ); + $this->output( "done [" . count( $this->statCache ) . " file(s)]\n" ); } + $this->output( "\tCopying file(s)...\n" ); + $count = 0; $batchPaths = array(); foreach ( $srcPathsRel as $srcPathRel ) { // Check up on the rate file periodically to adjust the concurrency if ( $rateFile && ( !$count || ( $count % 500 ) == 0 ) ) { $this->mBatchSize = max( 1, (int)file_get_contents( $rateFile ) ); - $this->output( "Batch size is now {$this->mBatchSize}.\n" ); + $this->output( "\tBatch size is now {$this->mBatchSize}.\n" ); } $batchPaths[$srcPathRel] = 1; // remove duplicates if ( count( $batchPaths ) >= $this->mBatchSize ) { @@ -117,6 +126,36 @@ class CopyFileBackend extends Maintenance { $this->copyFileBatch( array_keys( $batchPaths ), $backendRel, $src, $dst ); $batchPaths = array(); // done } + $this->output( "\tCopied $count file(s).\n" ); + + if ( $this->hasOption( 'syncviadelete' ) ) { + $this->output( "\tBuilding list of excess destination files..." ); + $delPathsRel = $this->getListingDiffRel( $dst, $src, $backendRel ); + $this->output( count( $delPathsRel ) . " file(s) need to be deleted.\n" ); + + $this->output( "\tDeleting file(s)...\n" ); + $count = 0; + $batchPaths = array(); + foreach ( $delPathsRel as $delPathRel ) { + // Check up on the rate file periodically to adjust the concurrency + if ( $rateFile && ( !$count || ( $count % 500 ) == 0 ) ) { + $this->mBatchSize = max( 1, (int)file_get_contents( $rateFile ) ); + $this->output( "\tBatch size is now {$this->mBatchSize}.\n" ); + } + $batchPaths[$delPathRel] = 1; // remove duplicates + if ( count( $batchPaths ) >= $this->mBatchSize ) { + $this->delFileBatch( array_keys( $batchPaths ), $backendRel, $dst ); + $batchPaths = array(); // done + } + ++$count; + } + if ( count( $batchPaths ) ) { // left-overs + $this->delFileBatch( array_keys( $batchPaths ), $backendRel, $dst ); + $batchPaths = array(); // done + } + + $this->output( "\tDeleted $count file(s).\n" ); + } if ( $subDir != '' ) { $this->output( "Finished container '$container', directory '$subDir'.\n" ); @@ -125,34 +164,101 @@ class CopyFileBackend extends Maintenance { } } - $this->output( "Done [$count file(s)].\n" ); + $this->output( "Done.\n" ); + } + + /** + * @param FileBackend $src + * @param FileBackend $dst + * @param string $backendRel + * @return array (rel paths in $src minus those in $dst) + */ + protected function getListingDiffRel( FileBackend $src, FileBackend $dst, $backendRel ) { + $srcPathsRel = $src->getFileList( array( + 'dir' => $src->getRootStoragePath() . "/$backendRel" ) ); + if ( $srcPathsRel === null ) { + $this->error( "Could not list files in source container.", 1 ); // die + } + $dstPathsRel = $dst->getFileList( array( + 'dir' => $dst->getRootStoragePath() . "/$backendRel" ) ); + if ( $dstPathsRel === null ) { + $this->error( "Could not list files in destination container.", 1 ); // die + } + // Get the list of destination files + $relFilesDstSha1 = array(); + foreach ( $dstPathsRel as $dstPathRel ) { + $relFilesDstSha1[sha1( $dstPathRel )] = 1; + } + unset( $dstPathsRel ); // free + // Get the list of missing files + $missingPathsRel = array(); + foreach ( $srcPathsRel as $srcPathRel ) { + if ( !isset( $relFilesDstSha1[sha1( $srcPathRel )] ) ) { + $missingPathsRel[] = $srcPathRel; + } + } + unset( $srcPathsRel ); // free + + return $missingPathsRel; } + /** + * @param array $srcPathsRel + * @param string $backendRel + * @param FileBackend $src + * @param FileBackend $dst + * @return void + */ protected function copyFileBatch( array $srcPathsRel, $backendRel, FileBackend $src, FileBackend $dst ) { $ops = array(); $fsFiles = array(); $copiedRel = array(); // for output message + $wikiId = $src->getWikiId(); + + // Download the batch of source files into backend cache... + if ( $this->hasOption( 'missingonly' ) ) { + $srcPaths = array(); + foreach ( $srcPathsRel as $srcPathRel ) { + $srcPaths[] = $src->getRootStoragePath() . "/$backendRel/$srcPathRel"; + } + $t_start = microtime( true ); + $fsFiles = $src->getLocalReferenceMulti( array( 'srcs' => $srcPaths, 'latest' => 1 ) ); + $ellapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); + $this->output( "\n\tDownloaded these file(s) [{$ellapsed_ms}ms]:\n\t" . + implode( "\n\t", $srcPaths ) . "\n\n" ); + } + + // Determine what files need to be copied over... foreach ( $srcPathsRel as $srcPathRel ) { $srcPath = $src->getRootStoragePath() . "/$backendRel/$srcPathRel"; $dstPath = $dst->getRootStoragePath() . "/$backendRel/$srcPathRel"; if ( $this->hasOption( 'utf8only' ) && !mb_check_encoding( $srcPath, 'UTF-8' ) ) { - $this->error( "Detected illegal (non-UTF8) path for $srcPath." ); + $this->error( "$wikiId: Detected illegal (non-UTF8) path for $srcPath." ); continue; - } elseif ( $this->filesAreSame( $src, $dst, $srcPath, $dstPath ) ) { - $this->output( "Already have $srcPathRel.\n" ); + } elseif ( !$this->hasOption( 'missingonly' ) + && $this->filesAreSame( $src, $dst, $srcPath, $dstPath ) ) + { + $this->output( "\tAlready have $srcPathRel.\n" ); continue; // assume already copied... } - // Note: getLocalReference() is fast for FS backends - $fsFile = $src->getLocalReference( array( 'src' => $srcPath, 'latest' => 1 ) ); + $fsFile = array_key_exists( $srcPath, $fsFiles ) + ? $fsFiles[$srcPath] + : $src->getLocalReference( array( 'src' => $srcPath, 'latest' => 1 ) ); if ( !$fsFile ) { - $this->error( "Could not get local copy of $srcPath.", 1 ); // die + $src->clearCache( array( $srcPath ) ); + if ( $src->fileExists( array( 'src' => $srcPath, 'latest' => 1 ) ) === false ) { + $this->error( "$wikiId: File '$srcPath' was listed but does not exist." ); + } else { + $this->error( "$wikiId: Could not get local copy of $srcPath." ); + } + continue; } elseif ( !$fsFile->exists() ) { // FSFileBackends just return the path for getLocalReference() and paths with // illegal slashes may get normalized to a different path. This can cause the // local reference to not exist...skip these broken files. - $this->error( "Detected possible illegal path for $srcPath." ); + $this->error( "$wikiId: Detected possible illegal path for $srcPath." ); continue; } $fsFiles[] = $fsFile; // keep TempFSFile objects alive as needed @@ -160,13 +266,14 @@ class CopyFileBackend extends Maintenance { $status = $dst->prepare( array( 'dir' => dirname( $dstPath ), 'bypassReadOnly' => 1 ) ); if ( !$status->isOK() ) { $this->error( print_r( $status->getErrorsArray(), true ) ); - $this->error( "Could not copy $srcPath to $dstPath.", 1 ); // die + $this->error( "$wikiId: Could not copy $srcPath to $dstPath.", 1 ); // die } $ops[] = array( 'op' => 'store', 'src' => $fsFile->getPath(), 'dst' => $dstPath, 'overwrite' => 1 ); $copiedRel[] = $srcPathRel; } + // Copy in the batch of source files... $t_start = microtime( true ); $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); if ( !$status->isOK() ) { @@ -176,26 +283,75 @@ class CopyFileBackend extends Maintenance { $ellapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); if ( !$status->isOK() ) { $this->error( print_r( $status->getErrorsArray(), true ) ); - $this->error( "Could not copy file batch.", 1 ); // die + $this->error( "$wikiId: Could not copy file batch.", 1 ); // die } elseif ( count( $copiedRel ) ) { - $this->output( "\nCopied these file(s) [{$ellapsed_ms}ms]:\n" . - implode( "\n", $copiedRel ) . "\n\n" ); + $this->output( "\n\tCopied these file(s) [{$ellapsed_ms}ms]:\n\t" . + implode( "\n\t", $copiedRel ) . "\n\n" ); + } + } + + /** + * @param array $dstPathsRel + * @param string $backendRel + * @param FileBackend $dst + * @return void + */ + protected function delFileBatch( + array $dstPathsRel, $backendRel, FileBackend $dst + ) { + $ops = array(); + $deletedRel = array(); // for output message + $wikiId = $dst->getWikiId(); + + // Determine what files need to be copied over... + foreach ( $dstPathsRel as $dstPathRel ) { + $dstPath = $dst->getRootStoragePath() . "/$backendRel/$dstPathRel"; + $ops[] = array( 'op' => 'delete', 'src' => $dstPath ); + $deletedRel[] = $dstPathRel; + } + + // Delete the batch of source files... + $t_start = microtime( true ); + $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); + if ( !$status->isOK() ) { + sleep( 10 ); // wait and retry copy again + $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); + } + $ellapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); + if ( !$status->isOK() ) { + $this->error( print_r( $status->getErrorsArray(), true ) ); + $this->error( "$wikiId: Could not delete file batch.", 1 ); // die + } elseif ( count( $deletedRel ) ) { + $this->output( "\n\tDeleted these file(s) [{$ellapsed_ms}ms]:\n\t" . + implode( "\n\t", $deletedRel ) . "\n\n" ); } } + /** + * @param FileBackend $src + * @param FileBackend $dst + * @param string $sPath + * @param string $dPath + * @return bool + */ protected function filesAreSame( FileBackend $src, FileBackend $dst, $sPath, $dPath ) { $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 ( - ( $src->fileExists( array( 'src' => $sPath, 'latest' => 1 ) ) - === $dst->fileExists( array( 'src' => $dPath, 'latest' => 1 ) ) // short-circuit - ) && ( $src->getFileSize( array( 'src' => $sPath, 'latest' => 1 ) ) - === $dst->getFileSize( array( 'src' => $dPath, 'latest' => 1 ) ) // short-circuit - ) && ( $skipHash || ( $src->getFileSha1Base36( array( 'src' => $sPath, 'latest' => 1 ) ) + 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 ) ) - ) ) + ) ); } } $maintClass = 'CopyFileBackend'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/copyJobQueue.php b/maintenance/copyJobQueue.php new file mode 100644 index 00000000..e833115b --- /dev/null +++ b/maintenance/copyJobQueue.php @@ -0,0 +1,99 @@ +<?php +/** + * Copy all jobs from one job queue system to another. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Maintenance + */ + +require_once __DIR__ . '/Maintenance.php'; + +/** + * Copy all jobs from one job queue system to another. + * This uses an ad-hoc $wgJobQueueMigrationConfig setting, + * which is a map of queue system names to JobQueue::factory() parameters. + * The parameters should not have wiki or type settings and thus partial. + * + * @ingroup Maintenance + */ +class CopyJobQueue extends Maintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = "Copy jobs from one queue system to another."; + $this->addOption( 'src', 'Key to $wgJobQueueMigrationConfig for source', true, true ); + $this->addOption( 'dst', 'Key to $wgJobQueueMigrationConfig for destination', true, true ); + $this->addOption( 'type', 'Types of jobs to copy (use "all" for all)', true, true ); + $this->setBatchSize( 500 ); + } + + public function execute() { + global $wgJobQueueMigrationConfig; + + $srcKey = $this->getOption( 'src' ); + $dstKey = $this->getOption( 'dst' ); + + if ( !isset( $wgJobQueueMigrationConfig[$srcKey] ) ) { + $this->error( "\$wgJobQueueMigrationConfig not set for '$srcKey'.", 1 ); + } elseif ( !isset( $wgJobQueueMigrationConfig[$dstKey] ) ) { + $this->error( "\$wgJobQueueMigrationConfig not set for '$dstKey'.", 1 ); + } + + $types = ( $this->getOption( 'type' ) === 'all' ) + ? JobQueueGroup::singleton()->getQueueTypes() + : array( $this->getOption( 'type' ) ); + + foreach ( $types as $type ) { + $baseConfig = array( 'type' => $type, 'wiki' => wfWikiID() ); + $src = JobQueue::factory( $baseConfig + $wgJobQueueMigrationConfig[$srcKey] ); + $dst = JobQueue::factory( $baseConfig + $wgJobQueueMigrationConfig[$dstKey] ); + + list( $total, $totalOK ) = $this->copyJobs( $src, $dst, $src->getAllQueuedJobs() ); + $this->output( "Copied $totalOK/$total queued $type jobs.\n" ); + + list( $total, $totalOK ) = $this->copyJobs( $src, $dst, $src->getAllDelayedJobs() ); + $this->output( "Copied $totalOK/$total delayed $type jobs.\n" ); + } + } + + protected function copyJobs( JobQueue $src, JobQueue $dst, $jobs ) { + $total = 0; + $totalOK = 0; + $batch = array(); + foreach ( $jobs as $job ) { + ++$total; + $batch[] = $job; + if ( count( $batch ) >= $this->mBatchSize ) { + if ( $dst->push( $batch ) ) { + $totalOK += count( $batch ); + } + $batch = array(); + $dst->waitForBackups(); + } + } + if ( count( $batch ) ) { + if ( $dst->push( $batch ) ) { + $totalOK += count( $batch ); + } + $dst->waitForBackups(); + } + return array( $total, $totalOK ); + } +} + +$maintClass = 'CopyJobQueue'; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/createAndPromote.php b/maintenance/createAndPromote.php index ad5333fc..aa25ee60 100644 --- a/maintenance/createAndPromote.php +++ b/maintenance/createAndPromote.php @@ -1,6 +1,6 @@ <?php /** - * Creates an account and grant it administrator rights. + * Creates an account and grants it rights. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,65 +20,98 @@ * @file * @ingroup Maintenance * @author Rob Church <robchur@gmail.com> + * @author Pablo Castellano <pablo@anche.no> */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** - * Maintenance script to create an account and grant it administrator rights. + * Maintenance script to create an account and grant it rights. * * @ingroup Maintenance */ class CreateAndPromote extends Maintenance { + static $permitRoles = array( 'sysop', 'bureaucrat', 'bot' ); + public function __construct() { parent::__construct(); - $this->mDescription = "Create a new user account"; - $this->addOption( "sysop", "Grant the account sysop rights" ); - $this->addOption( "bureaucrat", "Grant the account bureaucrat rights" ); + $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." ); + foreach ( self::$permitRoles as $role ) { + $this->addOption( $role, "Add the account to the {$role} group" ); + } $this->addArg( "username", "Username of new user" ); - $this->addArg( "password", "Password to set" ); + $this->addArg( "password", "Password to set (not required if --force is used)", false ); } public function execute() { $username = $this->getArg( 0 ); $password = $this->getArg( 1 ); - - $this->output( wfWikiID() . ": Creating and promoting User:{$username}..." ); + $force = $this->hasOption( 'force' ); + $inGroups = array(); $user = User::newFromName( $username ); if ( !is_object( $user ) ) { $this->error( "invalid username.", true ); - } elseif ( 0 != $user->idForName() ) { - $this->error( "account exists.", true ); } - # Try to set the password - try { - $user->setPassword( $password ); - } catch ( PasswordError $pwe ) { - $this->error( $pwe->getText(), true ); + $exists = ( 0 !== $user->idForName() ); + + if ( $exists && !$force ) { + $this->error( "Account exists. Perhaps you want the --force option?", true ); + } elseif ( !$exists && !$password ) { + $this->error( "Argument <password> required!", false ); + $this->maybeHelp( true ); + } elseif ( $exists ) { + $inGroups = $user->getGroups(); } - # Insert the account into the database - $user->addToDatabase(); - $user->saveSettings(); + $promotions = array_diff( array_filter( self::$permitRoles, array( $this, 'hasOption' ) ), $inGroups ); - # Promote user - if ( $this->hasOption( 'sysop' ) ) { - $user->addGroup( 'sysop' ); + 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"; + if ( $exists ) { + $this->output( wfWikiID() . ": Promoting $promoText" ); + } else { + $this->output( wfWikiID() . ": Creating and promoting $promoText" ); + } } - if ( $this->hasOption( 'bureaucrat' ) ) { - $user->addGroup( 'bureaucrat' ); + + if ( $password ) { + # Try to set the password + try { + $user->setPassword( $password ); + if ( $exists ) { + $this->output( "Password set.\n" ); + $user->saveSettings(); + } + } catch ( PasswordError $pwe ) { + $this->error( $pwe->getText(), true ); + } } - # Increment site_stats.ss_users - $ssu = new SiteStatsUpdate( 0, 0, 0, 0, 1 ); - $ssu->doUpdate(); + if ( !$exists ) { + # Insert the account into the database + $user->addToDatabase(); + $user->saveSettings(); + } + + # Promote user + array_map( array( $user, 'addGroup' ), $promotions ); + + if ( !$exists ) { + # Increment site_stats.ss_users + $ssu = new SiteStatsUpdate( 0, 0, 0, 0, 1 ); + $ssu->doUpdate(); + } $this->output( "done.\n" ); } } $maintClass = "CreateAndPromote"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/cssjanus/README b/maintenance/cssjanus/README index 9b922156..1b96d1a2 100644 --- a/maintenance/cssjanus/README +++ b/maintenance/cssjanus/README @@ -8,18 +8,18 @@ Author: `Lindsey Simon <elsigh@google.com>` 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). +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 +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 +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. +language context work in a RTL language all the way, but it is a start. ==Getting the code== @@ -31,7 +31,7 @@ Check out the latest development version anonymously with: {{{ $ svn checkout http://cssjanus.googlecode.com/svn/trunk/ cssjanus -}}} +}}} ==Using== @@ -41,13 +41,13 @@ 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 - + 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 +from django. You should be good to go with that setup. Please let me know otherwise. ==Bugs, Patches== @@ -76,13 +76,13 @@ Thanks to Jens Meiert for the German translation. {{{ 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. diff --git a/maintenance/deleteArchivedFiles.inc b/maintenance/deleteArchivedFiles.inc index e638b17c..d58e9a40 100644 --- a/maintenance/deleteArchivedFiles.inc +++ b/maintenance/deleteArchivedFiles.inc @@ -27,7 +27,7 @@ * @ingroup Maintenance */ class DeleteArchivedFilesImplementation { - static public function doDelete( $output, $force ) { + public static function doDelete( $output, $force ) { # Data should come off the master, wrapped in a transaction $dbw = wfGetDB( DB_MASTER ); $dbw->begin( __METHOD__ ); @@ -35,14 +35,19 @@ class DeleteArchivedFilesImplementation { $repo = RepoGroup::singleton()->getLocalRepo(); # Get "active" revisions from the filearchive table $output->handleOutput( "Searching for and deleting archived files...\n" ); - $res = $dbw->query( "SELECT fa_id,fa_storage_group,fa_storage_key FROM $tbl_arch" ); + $res = $dbw->query( "SELECT fa_id,fa_storage_group,fa_storage_key,fa_sha1 FROM $tbl_arch" ); $count = 0; foreach ( $res as $row ) { $key = $row->fa_storage_key; $group = $row->fa_storage_group; $id = $row->fa_id; $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key; - $sha1 = substr( $key, 0, strcspn( $key, '.' ) ); + if ( isset( $row->fa_sha1 ) ) { + $sha1 = $row->fa_sha1; + } else { + // old row, populate from key + $sha1 = LocalRepo::getHashFromKey( $key ); + } // Check if the file is used anywhere... $inuse = $dbw->selectField( 'oldimage', '1', array( 'oi_sha1' => $sha1, diff --git a/maintenance/deleteArchivedFiles.php b/maintenance/deleteArchivedFiles.php index 85ffc23b..ad7b54d0 100644 --- a/maintenance/deleteArchivedFiles.php +++ b/maintenance/deleteArchivedFiles.php @@ -24,8 +24,8 @@ * @author Aaron Schulz */ -require_once( __DIR__ . '/Maintenance.php' ); -require_once( __DIR__ . '/deleteArchivedFiles.inc' ); +require_once __DIR__ . '/Maintenance.php'; +require_once __DIR__ . '/deleteArchivedFiles.inc'; /** * Maintenance script to delete archived (non-current) files from the database. @@ -55,4 +55,4 @@ class DeleteArchivedFiles extends Maintenance { } $maintClass = "DeleteArchivedFiles"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/deleteArchivedRevisions.inc b/maintenance/deleteArchivedRevisions.inc index 414d41ad..dd8e3dd4 100644 --- a/maintenance/deleteArchivedRevisions.inc +++ b/maintenance/deleteArchivedRevisions.inc @@ -36,7 +36,7 @@ class DeleteArchivedRevisionsImplementation { * purgeRedundantText(). See Maintenance for a description of * those methods. */ - static public function doDelete( $maint ) { + public static function doDelete( $maint ) { $dbw = wfGetDB( DB_MASTER ); $dbw->begin( __METHOD__ ); diff --git a/maintenance/deleteArchivedRevisions.php b/maintenance/deleteArchivedRevisions.php index 4b658bbb..ffd581c1 100644 --- a/maintenance/deleteArchivedRevisions.php +++ b/maintenance/deleteArchivedRevisions.php @@ -24,8 +24,8 @@ * @author Aaron Schulz */ -require_once( __DIR__ . '/Maintenance.php' ); -require_once( __DIR__ . '/deleteArchivedRevisions.inc' ); +require_once __DIR__ . '/Maintenance.php'; +require_once __DIR__ . '/deleteArchivedRevisions.inc'; /** * Maintenance script to delete archived (deleted from public) revisions @@ -59,4 +59,4 @@ class DeleteArchivedRevisions extends Maintenance { } $maintClass = "DeleteArchivedRevisions"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/deleteBatch.php b/maintenance/deleteBatch.php index 936a52b8..c1cc03cd 100644 --- a/maintenance/deleteBatch.php +++ b/maintenance/deleteBatch.php @@ -28,7 +28,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to delete a batch of pages. @@ -121,4 +121,4 @@ class DeleteBatch extends Maintenance { } $maintClass = "DeleteBatch"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/deleteDefaultMessages.php b/maintenance/deleteDefaultMessages.php index 4ab6d1d9..7d8c80e4 100644 --- a/maintenance/deleteDefaultMessages.php +++ b/maintenance/deleteDefaultMessages.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that deletes all pages in the MediaWiki namespace @@ -51,7 +51,7 @@ class DeleteDefaultMessages extends Maintenance { ) ); - if( $dbr->numRows( $res ) == 0 ) { + if ( $dbr->numRows( $res ) == 0 ) { # No more messages left $this->output( "done.\n" ); return; @@ -86,4 +86,4 @@ class DeleteDefaultMessages extends Maintenance { } $maintClass = "DeleteDefaultMessages"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/deleteEqualMessages.php b/maintenance/deleteEqualMessages.php new file mode 100644 index 00000000..81758913 --- /dev/null +++ b/maintenance/deleteEqualMessages.php @@ -0,0 +1,193 @@ +<?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'; + +/** + * Maintenance script that deletes all pages in the MediaWiki namespace + * of which the content is equal to the system default. + * + * @ingroup Maintenance + */ +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->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 ); + } + + /** + * @param string|bool $langCode See --lang-code option. + */ + protected function fetchMessageInfo( $langCode, array &$messageInfo ) { + global $wgContLang; + + if ( $langCode ) { + $this->output( "\n... fetching message info for language: $langCode" ); + $nonContLang = true; + } else { + $this->output( "\n... fetching message info for content language" ); + $langCode = $wgContLang->getCode(); + $nonContLang = false; + } + + /* Based on SpecialAllmessages::reallyDoQuery #filter=modified */ + + $l10nCache = Language::getLocalisationCache(); + $messageNames = $l10nCache->getSubitemList( 'en', 'messages' ); + // Normalise message names for NS_MEDIAWIKI page_title + $messageNames = array_map( array( $wgContLang, 'ucfirst' ), $messageNames ); + + $statuses = AllmessagesTablePager::getCustomisedStatuses( $messageNames, $langCode, $nonContLang ); + // getCustomisedStatuses is stripping the sub page from the page titles, add it back + $titleSuffix = $nonContLang ? "/$langCode" : ''; + + foreach ( $messageNames as $key ) { + $customised = isset( $statuses['pages'][$key] ); + if ( $customised ) { + $actual = wfMessage( $key )->inLanguage( $langCode )->plain(); + $default = wfMessage( $key )->inLanguage( $langCode )->useDatabase( false )->plain(); + + $messageInfo['relevantPages']++; + + if ( + // Exclude messages that are empty by default, such as sitenotice, specialpage + // summaries and accesskeys. + $default !== '' && $default !== '-' && + $actual === $default + ) { + $hasTalk = isset( $statuses['talks'][$key] ); + $messageInfo['results'][] = array( + 'title' => $key . $titleSuffix, + 'hasTalk' => $hasTalk, + ); + $messageInfo['equalPages']++; + if ( $hasTalk ) { + $messageInfo['equalPagesTalks']++; + } + } + } + } + } + + public function execute() { + $doDelete = $this->hasOption( 'delete' ); + $doDeleteTalk = $this->hasOption( 'delete-talk' ); + $langCode = $this->getOption( 'lang-code' ); + + $messageInfo = array( + 'relevantPages' => 0, + 'equalPages' => 0, + 'equalPagesTalks' => 0, + 'results' => array(), + ); + + $this->output( 'Checking for pages with default message...' ); + + // Load message information + if ( $langCode ) { + $langCodes = Language::fetchLanguageNames( null, 'mwfile' ); + if ( $langCode === '*' ) { + // All valid lang-code subpages in NS_MEDIAWIKI that + // override the messsages in that language + foreach ( $langCodes as $key => $value ) { + $this->fetchMessageInfo( $key, $messageInfo ); + } + // Lastly, the base pages in NS_MEDIAWIKI that override + // messages in content language + $this->fetchMessageInfo( false, $messageInfo ); + } else { + if ( !isset( $langCodes[$langCode] ) ) { + $this->error( 'Invalid language code: ' . $langCode, 1 ); + } + $this->fetchMessageInfo( $langCode, $messageInfo ); + } + } else { + $this->fetchMessageInfo( false, $messageInfo ); + } + + 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" ); + + if ( !$doDelete ) { + $list = ''; + foreach ( $messageInfo['results'] as $result ) { + $title = Title::makeTitle( NS_MEDIAWIKI, $result['title'] ); + $list .= "* [[$title]]\n"; + if ( $result['hasTalk'] ) { + $title = Title::makeTitle( NS_MEDIAWIKI_TALK, $result['title'] ); + $list .= "* [[$title]]\n"; + } + } + $this->output( "\nList:\n$list\nRun the script again with --delete to delete these pages" ); + if ( $messageInfo['equalPagesTalks'] !== 0 ) { + $this->output( " (include --delete-talk to also delete the talk pages)" ); + } + $this->output( "\n" ); + return; + } + + $user = User::newFromName( 'MediaWiki default' ); + if ( !$user ) { + $this->error( "Invalid username", true ); + } + global $wgUser; + $wgUser = $user; + + // Hide deletions from RecentChanges + $user->addGroup( 'bot' ); + + // Handle deletion + $this->output( "\n...deleting equal messages (this may take a long time!)..." ); + $dbw = wfGetDB( DB_MASTER ); + 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 ); + $error = ''; // Passed by ref + $page->doDeleteArticle( 'No longer required', false, 0, false, $error, $user ); + if ( $result['hasTalk'] && $doDeleteTalk ) { + $title = Title::makeTitle( NS_MEDIAWIKI_TALK, $result['title'] ); + $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 ); + } + $dbw->commit( __METHOD__ ); + } + $this->output( "\n\ndone!\n" ); + } +} + +$maintClass = "DeleteEqualMessages"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/deleteImageMemcached.php b/maintenance/deleteImageMemcached.php index 3c8c5fdd..835de352 100644 --- a/maintenance/deleteImageMemcached.php +++ b/maintenance/deleteImageMemcached.php @@ -24,7 +24,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that deletes image information from the object cache. @@ -59,13 +59,15 @@ class DeleteImageCache extends Maintenance { $total = $this->getImageCount(); foreach ( $res as $row ) { - if ( $i % $this->report == 0 ) + if ( $i % $this->report == 0 ) { $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 ) ); - if ( $sleep != 0 ) + if ( $sleep != 0 ) { usleep( $sleep ); + } ++$i; } @@ -78,4 +80,4 @@ class DeleteImageCache extends Maintenance { } $maintClass = "DeleteImageCache"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/deleteOldRevisions.php b/maintenance/deleteOldRevisions.php index 6a3e211b..847d8634 100644 --- a/maintenance/deleteOldRevisions.php +++ b/maintenance/deleteOldRevisions.php @@ -22,7 +22,7 @@ * @author Rob Church <robchur@gmail.com> */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that deletes old (non-current) revisions from the database. @@ -48,48 +48,45 @@ class DeleteOldRevisions extends Maintenance { $dbw = wfGetDB( DB_MASTER ); $dbw->begin( __METHOD__ ); - $tbl_pag = $dbw->tableName( 'page' ); - $tbl_rev = $dbw->tableName( 'revision' ); - - $pageIdClause = ''; - $revPageClause = ''; + $pageConds = array(); + $revConds = array(); # If a list of page_ids was provided, limit results to that set of page_ids - if ( sizeof( $args ) > 0 ) { - $pageIdList = implode( ',', $args ); - $pageIdClause = " WHERE page_id IN ({$pageIdList})"; - $revPageClause = " AND rev_page IN ({$pageIdList})"; - $this->output( "Limiting to {$tbl_pag}.page_id IN ({$pageIdList})\n" ); + if ( count( $args ) > 0 ) { + $pageConds['page_id'] = $args; + $revConds['rev_page'] = $args; + $this->output( "Limiting to page IDs " . implode( ',', $args ) . "\n" ); } # Get "active" revisions from the page table $this->output( "Searching for active revisions..." ); - $res = $dbw->query( "SELECT page_latest FROM $tbl_pag{$pageIdClause}" ); - $cur = array(); + $res = $dbw->select( 'page', 'page_latest', $pageConds, __METHOD__ ); + $latestRevs = array(); foreach ( $res as $row ) { - $cur[] = $row->page_latest; + $latestRevs[] = $row->page_latest; } $this->output( "done.\n" ); # Get all revisions that aren't in this set - $old = array(); $this->output( "Searching for inactive revisions..." ); - $set = implode( ', ', $cur ); - $res = $dbw->query( "SELECT rev_id FROM $tbl_rev WHERE rev_id NOT IN ( $set ){$revPageClause}" ); + if ( count( $latestRevs ) > 0 ) { + $revConds[] = 'rev_id NOT IN (' . $dbw->makeList( $latestRevs ) . ')'; + } + $res = $dbw->select( 'revision', 'rev_id', $revConds, __METHOD__ ); + $oldRevs = array(); foreach ( $res as $row ) { - $old[] = $row->rev_id; + $oldRevs[] = $row->rev_id; } $this->output( "done.\n" ); # Inform the user of what we're going to do - $count = count( $old ); + $count = count( $oldRevs ); $this->output( "$count old revisions found.\n" ); # Delete as appropriate if ( $delete && $count ) { $this->output( "Deleting..." ); - $set = implode( ', ', $old ); - $dbw->query( "DELETE FROM $tbl_rev WHERE rev_id IN ( $set )" ); + $dbw->delete( 'revision', array( 'rev_id' => $oldRevs ), __METHOD__ ); $this->output( "done.\n" ); } @@ -103,5 +100,4 @@ class DeleteOldRevisions extends Maintenance { } $maintClass = "DeleteOldRevisions"; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/deleteOrphanedRevisions.php b/maintenance/deleteOrphanedRevisions.php index 5dc7567f..f0a96928 100644 --- a/maintenance/deleteOrphanedRevisions.php +++ b/maintenance/deleteOrphanedRevisions.php @@ -24,7 +24,7 @@ * @todo More efficient cleanup of text records */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that deletes revisions which refer to a nonexisting page. @@ -54,14 +54,15 @@ class DeleteOrphanedRevisions extends Maintenance { # Stash 'em all up for deletion (if needed) $revisions = array(); - foreach ( $res as $row ) + foreach ( $res as $row ) { $revisions[] = $row->rev_id; + } $count = count( $revisions ); $this->output( "found {$count}.\n" ); # Nothing to do? if ( $report || $count == 0 ) { - $dbw->commit(); + $dbw->commit( __METHOD__ ); exit( 0 ); } @@ -83,12 +84,12 @@ class DeleteOrphanedRevisions extends Maintenance { * @param $dbw DatabaseBase class (needs to be a master) */ private function deleteRevs( $id, &$dbw ) { - if ( !is_array( $id ) ) + if ( !is_array( $id ) ) { $id = array( $id ); + } $dbw->delete( 'revision', array( 'rev_id' => $id ), __METHOD__ ); } } $maintClass = "DeleteOrphanedRevisions"; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/deleteRevision.php b/maintenance/deleteRevision.php index ad6470d9..6bc0f7cd 100644 --- a/maintenance/deleteRevision.php +++ b/maintenance/deleteRevision.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that deletes one or more revisions by moving them @@ -85,4 +85,4 @@ class DeleteRevision extends Maintenance { } $maintClass = "DeleteRevision"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/deleteSelfExternals.php b/maintenance/deleteSelfExternals.php index da220d64..a0976228 100644 --- a/maintenance/deleteSelfExternals.php +++ b/maintenance/deleteSelfExternals.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that deletes self-references to $wgServer @@ -47,10 +47,12 @@ class DeleteSelfExternals extends Maintenance { . $db->buildLike( $wgServer . '/', $db->anyString() ), $this->mBatchSize ); $this->output( "Deleting a batch\n" ); $db->query( $q ); - if ( !$db->affectedRows() ) return; + if ( !$db->affectedRows() ) { + return; + } } } } $maintClass = "DeleteSelfExternals"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/dev/includes/router.php b/maintenance/dev/includes/router.php index ac96f459..a3cc0ba3 100644 --- a/maintenance/dev/includes/router.php +++ b/maintenance/dev/includes/router.php @@ -21,12 +21,12 @@ * @file */ -if ( php_sapi_name() != 'cli-server' ) { +if ( PHP_SAPI != 'cli-server' ) { die( "This script can only be run by php's cli-server sapi." ); } -ini_set('display_errors', 1); -error_reporting(E_ALL); +ini_set( 'display_errors', 1 ); +error_reporting( E_ALL ); if ( isset( $_SERVER["SCRIPT_FILENAME"] ) ) { # Known resource, sometimes a script sometimes a file @@ -58,7 +58,7 @@ if ( $ext == 'php' || $ext == 'php5' ) { # We use require and return true here because when you return false # the php webserver will discard post data and things like login # will not function in the dev environment. - require( $file ); + require $file; return true; } $mime = false; @@ -83,16 +83,16 @@ if ( $mime ) { # 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 - $f = fopen($file, 'rb'); + $f = fopen( $file, 'rb' ); if ( preg_match( '#^text/#', $mime ) ) { # Text should have a charset=UTF-8 (php's webserver does this too) - header("Content-Type: $mime; charset=UTF-8"); + header( "Content-Type: $mime; charset=UTF-8" ); } else { - header("Content-Type: $mime"); + header( "Content-Type: $mime" ); } - header("Content-Length: " . filesize($file)); + header( "Content-Length: " . filesize( $file ) ); // Stream that out to the browser - fpassthru($f); + fpassthru( $f ); return true; } diff --git a/maintenance/dictionary/mediawiki.dic b/maintenance/dictionary/mediawiki.dic new file mode 100644 index 00000000..164b5b05 --- /dev/null +++ b/maintenance/dictionary/mediawiki.dic @@ -0,0 +1,4556 @@ +ænglisc +ævar +&add +& +&bar +&sim +&url +ABNF +API +Aacute +Aborted +Abuse +Account +Accum +Acirc +Action +Activity +Agrave +All +Allocations +Ancientpages +Anim +Api +Apitestsysop +Apitestuser +Aring +Article +As +Atilde +Auml +Autopromote +BACKCOMPAT +Backlinks +Blacklist +Block +Blocked +Blocks +Bodytext +Broken +COMPUTERNAME +CRLF +CURLOPT +Campaign +Capture +Categories +Category +Ccedil +Central +Changes +Check +Click +Client +Clientfor +Colorer +Compare +Config +Console +Continue +Contribs +Contributions +Conversiontable +Coordinates +Create +Creation +Cview +DDLMODE +DWIM +DWIMD +Daily +Dbkeyform +Deadendpages +Debugtext +Delete +Deletedrevs +Denied +Dfile +Double +Duplicate +EAGAIN +EBML +ECMA +EDITFILTERMERGED +EINPROGRESS +EINTR +EOCDR +ETAG +Eacute +Ecirc +Edit +Editor +Education +Egrave +Ehcache +Elig +Email +Empty +End +English +Enlist +Euml +Eval +Events +Exists +Expand +Expression +Ext +External +Extracts +Extraneous +FFFD +FOLLOWLOCATION +Failure +Featured +Feed +Feedback +Feedbackv +Feeds +Fewestrevisions +Ffile +File +Filearchive +Filedelete +Files +Filter +Filters +Flag +Flagged +GI +GRAPHEME +Gadget +Gadgets +Geo +Get +Global +Groups +HEA +HTM +Hardblock +Help +Helpful +ID +IPTC +IWBacklinks +IWLinks +Iacute +Icirc +Igrave +Illegal +Image +Images +Implict +Import +Info +Invalidateemail +Isarticle +Item +Iuml +LOCALISATIONCACHE +Lang +Lastmod +Links +Linktags +List +Listredirects +Living +Log +Login +Logout +Logs +Lonelypages +Longpages +Love +Ltitle +MSVC +Mark +Match +Matrix +Members +Mesg +Messages +Metatags +Mobile +Mostcategories +Mostimages +Mostinterwikis +Mostlinked +Mostlinkedcategories +Mostlinkedtemplates +Mostrevisions +Move +Mssql +Mwstore +Myuploads +NEWPAGE +NOTIC +Name +Need +No +Noscript +Not +Notalk +Notice +Notification +Ntilde +Oacute +Ocirc +Ograve +Oldreviewedpages +Open +Options +Oslash +Otilde +Ouml +PAGEEDITDATE +PAGEEDITOR +PAGEEDITTIME +PAGEINTRO +PAGEMINOREDIT +PAGESUMMARY +PARSEHUGE +PARSERFIRSTCALLINIT +PHPTAL +PMID +Page +Pages +Param +Parse +Parsers +Pass +Passpass +Patrol +People +Plugin +Possible +Program +Props +Protect +Protected +Protectexpiry +Protectother +Protectreason +Protectreasonother +Purge +Query +Queued +Random +Rapid +Ratings +Raw +Recent +Redirects +Redis +Referer +Refresh +Regexlike +Replacer +Reset +Resursive +Revert +Review +Revisions +Rollback +Rsd +SEGSIZE +STDERR +SYSDBA +Scaron +Scribunto +Search +Section +Set +Shortpages +Site +Siteinfo +Solr +Stabilize +Stash +Stats +Status +Success +Syntax +TMPDIR +TOOLBOXEND +TRANSLIT +Tagging +Tags +Template +Templates +Textform +Tfile +Throttled +Timestamp +Title +Titles +Token +Tokens +Tracking +Transcode +Triage +UNWATCHURL +Uacute +Ucirc +Ugrave +Unblock +Uncategorizedcategories +Uncategorizedimages +Uncategorizedpages +Uncategorizedtemplates +Undelete +Unusedcategories +Unusedimages +Unusedtemplates +Unwatchedpages +Upload +Urlform +Usage +User +Usercreate +Userdir +Userlang +Userrights +Users +Useruser +Ustart +Uuml +Value +Video +View +Visual +WATCHINGUSERNAME +WEBPVP +Wantedcategories +Wantedfiles +Wantedpages +Wantedtemplates +Warning +Watch +Watchingusers +Watchlist +Wiki +Wikibase +Withoutinterwiki +Wrong +XX +Xml +YYYY +YYYYMMDDHHMMSS +Yacute +Yuml +\ +a +aa +aacute +abbrv +abcdefghijklmnopqrstuvwxyz +abf +aboutpage +aboutsite +abusefilter +abusefiltercheckmatch +abusefilterchecksyntax +abusefilterevalexpression +abusefilters +abusefilterunblockautopromote +abuselog +abusive +ac +acad +accel +acceptlang +accessdenied +accesskey +accesskeycache +accesskeys +accessors +acchits +account +accountcreator +accum +acirc +aclimit +acprefix +action +actioncomplete +actionhidden +actions +actiontext +actionthrottled +actionthrottledtext +actiontoken +activeusers +activity +acuxvalidate +add +addablegroups +addbegin +addedline +addedwatchtext +addergroup +addergroups +addin +adding +additional +addr +address +addresses +addsection +addstudent +admin +administrator +adnum +adrelid +adsrc +advancedediting +advancedrc +advancedrendering +advancedsearchoptions +advancedwatchlist +aelig +af +afl +aft +afttest +afvf +age +aggregators +agrave +ahandler +ahttp +ai +aifc +aiff +aiprop +ajaxwatch +al +alefsym +algo +algos +all +all's +allcategories +alldata +alle +allexamples +allhidden +allimages +allimit +alllinks +alllogstext +allmessages +allmonths +allowedctypes +allowedonly +allowemail +allowsduplicates +allowusertalk +allpages +allpagesbadtitle +allpagesprefix +allpagesredirect +allpagessubmit +allrev +alltitles +alltransclusions +allusers +aloption +alprefix +alreadyblocked +alreadydone +alreadyexists +alreadyrolled +alunique +am +anchor +anchorclose +anchorencode +and +andconvert +andtitle +anon +anoneditwarning +anonlogin +anonnotice +anononly +anonpreviewwarning +anontalk +anontalkpagetext +anontoken +anonuserpage +anonymous +anti +antispoof +antivirus +anymap +ap +apcond +apdir +api +api's +apibase +apihelp +apihighlimits +apis +aplimit +apnamespace +apng +apos +appendnotsupported +appendtext +apprefix +approve +aprops +aqbt +aqct +archivename +aren +args +argsarams +aring +arnfjörð +article +articleexists +articlefeedbackv +articleid +articlelink +articlepage +articlepath +articles +aryeh +asc +ascending +asctime +asdf +aspx +assert +astriks +asymp +async +asynccopyuploaddisabled +asyncdownload +at +atend +atext +atid +atilde +atime +atlimit +atoi +atom +atprefix +atthasdef +attibs +attibute +attlen +attname +attnum +attrdef +attrelid +attrib +attribs +attributename +attrs +atttypid +atunique +au +auml +authplugins +autoaccount +autobiography +autoblock +autoblocked +autoblockedtext +autoblocker +autoblockid +autoblocking +autoblockip +autoblocks +autocad +autocomment +autocomments +autocomplete +autoconfirm +autoconfirmed +autocreate +autocreated +autocreation +autodetection +autoflag +autofocus +autogen +autogenerated +autohide +autoload +autoloader +autoloaders +autoloading +automagically +automatic +autonym +autopatrol +autoplay +autopromote +autopromoted +autopromotion +autoreview +autoreviewer +autoreviewrestore +autosumm +autosummaries +autosummary +axto +azərbaycanca +backends +backlink +backlinks +backlinksubtitle +backported +backslashed +backtraces +bad +badaccess +badarticleerror +badcontinue +baddiff +bademail +badfilename +badformat +badgenerator +badhookmsg +badinterwiki +badip +badipaddress +badkey +badmd +badmime +badminpassword +badminuser +badnamespace +badoption +badparams +badport +badretype +badrevids +badsig +badsiglength +badsyntax +badtag +badtimestamp +badtitle +badtitletext +badtoken +badtype +badupload +baduser +badversion +balancer +balancers +banjar +barstein +base +basefont +basename +basepagename +basepagenamee +basetimestamp +bashkir +bashpid +bcancel +bceffd +bcmath +bcompress +bcpio +bdop +bdquo +becampus +beinstructor +belarusian +beonline +bereviewer +berror +bestq +besttype +bg +bgcolor +bgzip +bidi +bigdelete +binhex +bitdepth +bitfield +bitfields +bitmask +bjarmason +bk +bkey +bkinvalidparammix +bkmissingparam +bkusers +bl +blanking +blanknamespace +blankpage +blegh +bleh +blinvalidparammix +blksize +blmissingparam +block +blockable +blocked +blockedasrange +blockedby +blockedbyid +blockedemailuser +blockedexpiry +blockedfrommail +blockednoreason +blockedreason +blockedtext +blockedtitle +blockemail +blockexpiry +blockid +blockinfo +blockip +blocklink +blocklogentry +blocklogpage +blocklogtext +blockme +blockquote +blockreason +blocks +blocktoken +bloggs +blogs +blogspot +bltitle +bluelink +bluelinks +bmwschema +bmysql +bname +bodycontent +boldening +bolding +booksources +bool +boolean +borderhack +bot +botedit +boteditletter +bots +bottom +bottomscripts +bpassword +bpatch +bpchar +bport +bprefix +broeck +brokenlibxml +brokenredirects +brokenredirectstext +browsearchive +brvbar +bserver +bservers +bssl +btestpassword +btestuser +btype +bucket +bucketcount +bugfix +bugfixes +buglist +bugzilla +buildpath +buildpathentry +bulgakov +bulkdelcourses +bulkdelorgs +bureaucrat +buser +by +byemail +byid +bytea +bytesleft +bytesread +bytevalue +cacheable +cached +cachedcount +cachedsidebar +cachedspecial +cachedtimestamp +calimit +callargs +campaign +campus +cancelto +cannotdelete +cannotundelete +canonicalised +canonicalization +canonicalize +canonicalizes +canonicalizing +canremember +canreset +cansecurelogin +cantblock +cantcreate +cantdelete +cantedit +cantexecute +canthide +cantimport +cantmove +cantmovefile +cantopenfile +cantoverwrite +cantrollback +cantsend +cantunblock +cantundelete +capitalizeallnouns +captchaid +captchas +captchaword +cascade +cascadeable +cascadeon +cascadeprotected +cascadeprotectedwarning +cascading +cascadingness +categories +categories's +categorieshtml +category +categoryfinder +categoryinfo +categorylinks +categorymembers +categorypage +categoryviewer +catids +catlinks +catpage +catrope +cattitles +ccedil +ccme +ccmeonemails +cdab +cdel +cdlink +cedil +ceebc +cellpadding +cellspacing +central +centralauth +centralnotice +centralnoticeallocations +centralnoticelogs +centralnoticequerycampaign +cgroup +cgroups +change +change's +changeablegroups +changed +changedby +changedorcreated +changeemail +changelog +changeslist +changing +characters +chardiff +charoff +chars +checkfreq +checkmatrix +checkstatus +checkuser +checkuserlog +chgrp +childs +chillu +chmoding +choicesstring +chrs +chunk +chunked +chunking +ci +cidr +cidrtoobroad +circ +citeseer +ckers +ckey +cl +clamav +clamscan +classname +clcategorie +cldir +cldr +clear +clearable +clearyourcache +clfrom +clickjacking +clicktracking +clientfor +clientpool +cllimit +clober +closed +clto +cm +cminvalidparammix +cmmissingparam +cmnamespace +cmtitle +co +code +codemap +codepoint +codestr +coi +colgroup +collapsable +collectionsaveascommunitypage +collectionsaveasuserpage +colname +cologneblue +colonseparator +colorer +colspan +commafy +commafying +comment +commentedit +commenthidden +comments +commitdiff +commoncssjs +compactpro +compare +compat +complete +cond +condcomment +condeferrable +condeferred +conds +config +confirmdeletetext +confirmed +confirmedittext +confirmemail +confirmrecreate +conflimit +confstr +conkey +conname +conrelid +console +content +contentformat +contenthandler +contentlanguage +contentless +contentmodel +contenttoobig +continue +contribs +contribslink +conttitle +contype +conv +converttitles +convmv +cookieprefix +cooltalk +coord +coordinates +copyrightico +copyrightpage +copyrightwarning +copyuploadbaddomain +copyuploaddisabled +copyvio +copywarn +cors +couldn +counter +countmsg +country +course +courseid +cpio +cprefs +cprotected +crarr +crashbug +create +createaccount +createonly +createpage +createtalk +creationsort +creativecommons +creditspage +crocker +cryptrand +csize +csrf +css +cssclass +csslinks +cssprefs +cta +ctime +ctor +ctype +cu +cul +curation +curdiff +curid +curlink +curren +currentarticle +currentbrowser +currentday +currentdayname +currentdow +currenthour +currentmonth +currentmonthabbrev +currentmonthname +currentmonthnamegen +currentrev +currentrevisionlink +currenttime +currenttimestamp +currentversion +currentweek +currentyear +customcssprotected +customised +customjsprotected +cut +cyber +cygwin +cyrl +d'oh +dadedad +dairiki +danga +danielc +darr +datalen +dataset +datasets +datasize +datatable +datatype +datedefault +dateformat +dateheader +dateopts +daysago +dbcnt +dbconnect +dberrortext +dbg +dbgfm +dbkey +dbkeys +dbks +dbname +dbrepllag +dbsettings +dbtype +dbversion +ddjvu +de +deadend +deadendpagestext +deadenpages +dealies +debughtml +decline +declined +decls +decr +decrease +default +defaultcontentmodel +defaultmessagetext +defaultmissing +defaultns +defaultsort +defaultval +deferr +definite +deflimit +defs +deja +delete +deleteall +deletecomment +deleteconfirm +deleted +deletedhistory +deletedline +deletedonly +deletedrevision +deletedrevs +deletedtext +deletedwhileediting +deleteeducation +deleteglobalaccount +deletelogentry +deleteone +deleteotherreason +deletepage +deletereason +deletereasonotherlist +deleterevision +deleteset +deletethispage +deletetoken +deletion +deletionlog +delim +dellogpage +dellogpagetext +delundel +deprecated +deps +depth +dequeue +dequeued +dequeueing +dequeues +derivatives +desc +descending +description +descriptionmsg +descriptionmsgparams +descriptionurl +deserialization +deserialize +dest +detail +details +devangari +devel +df +dflt +dhtml +diams +didn +diff +diff's +diffchange +diffhist +difflink +diffonly +difftext +diffto +difftocontent +difftotext +dim +dimensions +dir +direction +directionmark +directorycreateerror +directorynotreadableerror +directoryreadonlyerror +dirmark +dirname +disabled +disabledtranscode +disablemail +disablepp +disablesuggest +disclaimerpage +diskussion +displayname +displayrc +displaysearchoptions +displaytitle +displaytitles +displaywatchlist +distclean +distro +djava +djob +djvu +djvudump +djvulibre +djvutoxml +djvutxt +djvuxml +djvuzone +dkjsagfjsgashfajsh +dlen +dltk +dmoz +dnsbl +dnsblacklist +dnumber +docm +docroot +doctype +doctypes +docx +dodiff +doesn +domain +domainnames +domainpart +domainparts +domas +doms +dotdotcount +dotm +dotsc +dotsi +dotsm +dotso +dotwise +dotx +doubleclick +doublequote +doxygen +dpos +dr +dropdown +dump +dumpfm +dupfunc +duplicatefiles +duplicatesoffile +dvips +dwfx +dwhitelist +e +eacute +earth +eauth +ecirc +ecmascript +edit +editbutton +editconflict +editconflicts +editcount +editfont +editform +edithelp +edithelppage +edithelpurl +editingcomment +editinginterface +editingold +editingsection +editinterface +editintro +edititis +editlink +editmyoptions +editmyprivateinfo +editmyusercss +editmyuserjs +editmywatchlist +editnotice +editnotsupported +editondblclick +editor +editownusertalk +editpage +editprotected +editreasons +editredlink +editrestriction +edits +editsection +editsectionhint +editsectiononrightclick +editsemiprotected +editsonly +editthispage +edittime +edittoken +edittools +editurl +editusercss +editusercssjs +edituserjs +edoe +egrave +ehcache +ei +eich +eiinvalidparammix +eimissingparam +eititle +el +elapsedreal +elemname +elink +eltitle +email +emailable +emailaddress +emailauthenticated +emailauthentication +emailauthenticationclass +emailcapture +emailconfirm +emailconfirmed +emailconfirmlink +emaildisabled +emailling +emaillink +emailnotauthenticated +emailtoken +emailuser +embeddedin +empty +emptyfile +emptynewsection +emptypage +emsenhuber +emsp +en +enabled +enabledonly +enableparser +encapsed +enctype +end +endcode +endcond +endian +endid +endl +endsortkey +endsortkeyprefix +endtime +endverbatim +enhancedchanges +enlist +enotif +enotifminoredits +enotifrevealaddr +enotifusertalkpages +enotifwatchlistpages +enqueueing +enroll +ensp +entirewatchlist +entityid +envcmd +enwiki +eocdr +ep +eparticle +epcampus +epcoordinator +epinstructor +eponline +erevoke +errno +error +errorbox +errormessage +errorpagetitle +errors +errorstr +errortext +errorunknown +errstr +es +escapenoentities +escapeshellarg +esearch +español +española +etag +eu +euml +event +eventid +ex +exampleextension +examples +excludegroup +excludepage +excludeuser +executables +exempt +existingwiki +exists +exiv +expandtab +expandtemplates +expandurl +experiment +expertise +expiry +expiryarray +explainconflict +export +exportnowrap +exportxml +expression +exptime +extauth +extendwatchlist +extensionname +extensions +extensiontags +external +externaldberror +externaldiff +externaledit +externaleditor +externallinks +externalstore +extet +extiw +extlink +extlinks +extracts +extradata +extrafields +extraq +extratags +exturlusage +extuser +exxaammppllee +fa +facto +failback +failover +failsafe +fallbacks +false +falsy +fancysig +fastcgi +faux +favicon +fclose +fdef +fdff +feature +featured +featuredfeed +feed +feed's +feedback +feedbackid +feedcontributions +feedformat +feeditems +feedlink +feedlinks +feedurl +feedwatchlist +feff +female +fetchfileerror +fffe +ffff +fffff +ffffff +fieldname +fieldset +fieldsets +file +filearchive +filebackend +filecache +filecopyerror +filedelete +filedeleteerror +fileexists +fileextensions +filehidden +filehist +filehistory +fileinfo +filejournal +filekey +filelinks +filemissing +filemover +filemtime +filename +filenames +filenotfound +filepage +filepath +filerenameerror +filerepo +filerevert +filerevisions +files +filesize +filesort +filesorts +filesystem's +filesystems +filetoc +filetoobig +filetype +filetypemismatch +fileversions +filter +filterbots +filteriw +filterlanglinks +filterlocal +filterredir +filterwatched +findnext +finfo +firefox +firstname +firstrev +firsttime +fishbowl +fixme +fixup +flac +flag +flagconfig +flagged +flags +flagtype +flatlist +flds +float +fmttime +fname +fnof +foldmarker +foldmethod +followpolicy +footericon +footericons +footerlinks +fopen +for +forall +forbidden +forcearticlepath +forcebot +forceditsummary +forceeditsummary +forcelinkupdate +forcetoc +forcontent +formaction +format +formatmodules +formatted +formatters +formatting +formedness +formenctype +formnovalidate +formtype +forupdate +found +founder +fr +frac +frameless +framesets +frasl +fread +freedomdefined +freeform +freenode +frickin +from +fromdb +fromdbmaster +fromid +fromrev +fromrevid +fromtitle +frontends +fseek +fsockopen +fsync +ftp +fullhistory +fullpagename +fullpagenamee +fulluri +fullurl +funcname +functionhooks +functionname +futuresplash +fvalue +ga +gack +gadgetcategories +gadgets +gaid +gaifilterredir +gallerybox +gallerycaption +gallerytext +gapdir +gapfilterredir +gaplimit +gapprefix +garber +gblblock +gblock +gblrights +gc +gcldir +gcllimit +gender +general +generatexml +generator +geocoordinate +geosearch +gerrit +getcookie +getenv +getheader +getimagesize +getlink +getmac +getmarkashelpfulitem +getmypid +getrusage +gettimeofday +gettingstarted +gettoken +getuid +gfdl +ggp +ghostscript +gimpbaseenums +git +gitblit +gitdir +github +global +globalauth +globalblock +globalblocks +globalgroupmembership +globalgrouppermissions +globalgroups +globalsettings +globalunblock +globalusage +globaluserinfo +globe +gmail +gmdate +goodtitle +gopher +graymap +grayscale +greant +greymap +group +groupcounts +groupless +groupmember +grouppage +groupperms +groupprms +groups +growinglink +grxml +gs +gtar +gu +guesstimezone +gui +guid +gunblock +guser +gwicke +gzcompress +gzdeflate +gzencode +gzhandler +gzip +gzipped +gzipping +hacky +hansm +hant +hardblocks +hardcode +hardcoding +harr +hash +hashar +hashcheckfailed +hashsearchdisabled +hashtable +hashtables +hasmatch +hasmsg +hasn +hasrelated +headelement +headerpos +headhtml +headitems +headlinks +headscripts +height +hellip +help +helpful +helppage +helptext +helpurl +helpurls +helpwindow +hexdump +hexstring +hidden +hiddencat +hiddencategories +hiddencats +hide +hideanons +hidebots +hidediff +hideliu +hideminor +hidemyself +hidename +hidepatrolled +hideredirects +hiderevision +hideuser +hidpi +highlimit +highmax +highuse +hilfe +hiphop +histfirst +histlast +historyempty +historysubmit +historywarning +hit +hitcount +hitcounter +hits +hmac +hmtl +hobby +homelink +hookaborted +horohoe +hostnames +hours +hphp +hplist +hpos +hreflang +hslots +htaccess +htcp +html +htmlelements +htmlescaped +htmlform +htmlish +htmllist +htmlnest +htmlpair +htmlpairs +htmlsingle +htmlsingleallowed +htmlsingleonly +htmlspecialchars +htmltidy +http +httpaccept +httpbl +https +i +ia +iabn +iacute +icirc +icononly +iconv +icubench +icutest +id +idanduser +ids +ie's +ieinternals +ietf +iexcl +ifconfig +iframe +igbinary +iges +ignorewarnings +igrave +ii +iicontinue +iiprop +iiurlparam +iiurlwidth +iker +ilfrom +ilto +im +image +imagegetsize +imageinfo +imageinvalidfilename +imagelinks +imagemagick +imagemaxsize +imagenocrossnamespace +imagepage +imagerepository +imagerotate +images +imagesize +imagetype +imagetypemismatch +imageusage +imagick +imgmultigo +imgmultigoto +imgmultipagenext +imgmultipageprev +imgs +imgserv +immobilenamespace +implicitgroups +import +importbadinterwiki +importcantopen +importlogpage +importlogpagetext +importnofile +importtoken +importupload +importuploaderrorpartial +importuploaderrorsize +importuploaderrortemp +in +iname +inbound +includable +include +includecomments +includelocal +includeonly +includexmlnamespace +incr +increase +indefinite +index +indexfield +indexpageids +indexpolicy +indstr +infin +infinite +infiniteblock +info +infoaction +infobox +infoline +infomsg +ingroups +injectjs +inkscape +inlanguagecode +inlined +inno +inputneeded +insb +inser +instantcommons +institution +instructor +int +integer +integeroutofrange +intentionallyblankpage +interlang +interlangs +interlanguage +internal +internaledit +internalerror +interwiki +interwikimap +interwikipage +interwikis +interwikisource +intnull +intoken +intra +intro +intrw +ints +intval +invalid +invalidaction +invalidations +invalidcategory +invaliddomain +invalidemail +invalidemailaddress +invalidexpiry +invalidip +invalidlang +invalidlevel +invalidmode +invalidoldimage +invalidpage +invalidpageid +invalidparameter +invalidparammix +invalidpath +invalidrange +invalidsection +invalidsessiondata +invalidsha +invalidspecialpage +invalidtags +invalidtime +invalidtitle +invalidtoken +invaliduser +invalue +iorm +ip +ipbblocked +ipblock +ipblocks +ipbnounblockself +ipchain +ipedits +iphash +ipinrange +ipusers +iquest +irc +ircs +isam +isapi +isbot +isconnected +iscur +isin +isip +ismap +isminor +ismodsince +ismulti +isnew +ispermalink +isself +isset +istainted +istalk +iswatch +it +item +itemid +itemprop +itemref +itemscope +itemtype +iter +iu +iuinvalidparammix +iumissingparam +iuml +iw +iwbacklinks +iwbl +iwlfrom +iwlinks +iwlprefix +iwltitle +iwprefix +iwtitle +iwurl +javascript +javascripttest +jbartsh +jconds +jdk's +jhtml +jimbo +joaat +jobqueue +jointype +jorsch +journaling +jpeg +jpegtran +jslint +jsmimetype +jsminplus +json +jsonfm +jsparse +jstext +jsvarurl +justthis +kabardian +kangxi +kashubia +kattouw +kblength +kernowek +key +keygen +keylen +keyname +keynames +keytype +khash +kludgy +knownnamespace +konqueror +kpos +kuza +labarga +labelmsg +laggedslavemode +laggy +lang +langbacklinks +langcode +langcodes +langconversion +langlinks +langprop +langs +language +languagelinks +languages +languageshtml +laquo +large +larr +last +lastdiff +lastdot +lastedit +lasteditor +lastedittime +lastlink +lastmod +lastmodifiedat +lastname +lastrevid +lastvisited +latgalian +laxström +lbase +lbl +lcattrib +lceil +lcomments +lcount +lcrocker +ldquo +le +leavemessage +len +length +leprop +lesque +lettercase +level +lfloor +lg +lgname +lgpassword +lgpl +lgtoken +lguserid +lgusername +libcurl +libel +libgimpbase +libketama +libmemcached +libre +libtidy +ligabue +lighttpd +limit +limitable +line +linenumber +linestart +link +linkarr +linkcolour +linkprefix +links +linkstoimage +linktbl +linktext +linktodiffs +linktrail +linktype +linkupdate +list +listable +listadmins +listbots +listfiles +listgrouprights +listinfo +listingcontinuesabbrev +listoutput +listresult +lists +listtags +listuser +listusers +listusersfrom +livepreview +ll +llfrom +lllang +lltitle +lnumber +local +localday +localdayname +localdow +locale +localhour +localmonth +localmonthabbrev +localmonthname +localmonthnamegen +localname +localonly +localsettings +localtimezone +localweek +localyear +lock +lockandhid +lockdb +lockdir +locked +lockmanager +log +logaction +logentry +logevent +logevents +logextract +loggedin +logid +login +loginend +loginerror +loginfo +loginlanguagelinks +loginlink +loginprompt +loginreqlink +loginreqpagetext +loginreqtitle +logins +loginstart +logitem +loglink +loglist +logname +logonly +logopath +logourl +logout +logpage +logtext +logtitle +logtype +longpage +longpageerror +lookie +lookups +loopback +lossless +lossy +lowast +lowercaps +lowercased +lowlimit +lsaquo +lsquo +ltags +ltitle +ltrimmed +lurl +lysator +möller +macr +magicarr +magicfile +magick +magicword +magicwordkey +magicwords +magnus +mahaction +mailerror +mailmypassword +mailnologin +mailparts +mailpassword +mailtext +mailto +mainmodule +mainpage +maintainership +makesafe +male +malloc +manske +manualthumb +mark +markashelpful +markaspatrolledlink +markaspatrolledtext +markbot +markbotedits +markedaspatrollederror +markpatrolled +masse +match +matchcount +mathml +mathtt +matrixes +matroska +max +maxage +maxdim +maxlag +maxlength +maxlifetime +maxqueue +maxresults +maxsize +maxuploadsize +maxwidth +mazeland +mbresponse +mbstring +mckey +mcklmqw +mcrypt +mcvalue +md +mdash +medialink +mediaqueries +mediatype +mediawarning +mediawiki's +mediawikipage +megapixels +member +memberingroups +members +memc +memcache +memcached +memlimit +memoryp +memsw +merge +mergeable +merged +mergehistory +mergelog +mergelogpagetext +message +messagekey +messagename +messagepattern +messages +messagetype +meta +metacharacters +metachars +metadata +metadataversion +metafile +mhash +mhtml +micrblogging +microdata +microsyntaxes +microtime +middot +migurski +millitime +mime +mimer +mimesearchdisabled +mimetype +min +minangkabau +minh +minification +minified +minifier +minifies +minify +minifying +minimal +minor +minordefault +minoredit +minoreditletter +minsize +misconfigured +misermode +mismatch +misresolved +missing +missingcommentheader +missingcommenttext +missingdata +missingparam +missingpermission +missingresult +missingrev +missingsummary +missingtext +missingtitle +missinguser +mituzas +mixedapproval +mkdir +mms +mobile +mobileformat +mobileview +modified +modifiedarticleprotection +modify +modsecurity +modsince +module +moduledisabled +modulename +modules +monitor +monobook +monospace +monospaced +month +monthsall +moodbar +moredotdotdot +morelinkstoimage +morethan +move +movedarticleprotection +moveddeleted +movedto +movefile +movelogpage +movelogpagetext +movenologintext +movenotallowed +movenotallowedfile +moveonly +moveoverredirect +movepage +moves +movestable +movesubpages +movetalk +movethispage +movetoken +mozilla +mpeg +mpegurl +mpga +mplink +mptitle +msdn +msdownload +msec +msexcel +msgid +msgkey +msgs +msgsize +msgsmall +msgtext +msie +msmetafile +mssql +msvideo +msword +mtime +mtype +mullane +multi +multibyte +multicast +multipage +multipageimage +multipageimagenavbox +multipart +multiselect +multisource +multithreaded +multival +multivalue +multpages +munge +musso +mustbeloggedin +mustbeposted +mutator +mutators +muxers +mwdumper +mwfile +mwstore +mwsuggest +mwuser +mxircecho +mycontributions +mycontris +myext +myextension +myisam +mykey +mypage +mypreferences +mysqldump +mytalk +mytext +mywatchlist +nabla +name +namehidden +nameinlowercase +names +namespace +namespacealiases +namespacebanner +namespacee +namespacenotice +namespacenumber +namespaceoptions +namespaceprotected +namespaces +namespacesall +namespaceselector +namespacing +nassert +nbase +nbsp +nbytes +nchanges +ncount +ndash +nearmatch +nedersaksies +nedersaksisch +needreblock +needservers +needtoken +netcdf +netware +never +new +newaddr +newarticletext +newarticletextanon +newer +newerthanrevid +newgroups +newheader +newid +newimages +newlen +newmessagesdifflink +newmessagesdifflinkplural +newmessageslink +newmessageslinkplural +newname +newnames +newnamespace +newpage +newpageletter +newpages +newpageshidepatrolled +newparams +newpass +newpassword +newpos +newquery +newrevid +news +newsectionlink +newsectionsummary +newset +newsfeed +newsize +newtalk +newtalks +newtalkseparator +newtext +newtimestamp +newtitle +newuser +newuserlogpage +newuserlogpagetext +newusers +newwidth +newwindow +nextdiff +nextid +nextlink +nextn +nextpage +nextredirect +nextrevision +nextval +nfkc +nginx +nheight +niklas +nlink +nlinks +nmime +nnnn +nntp +no +noanimatethumb +noanontoken +noapiwrite +noarchivename +noarticle +noarticletext +noarticletextanon +noautopatrol +noblock +nobots +nobucket +nobuffer +nochange +nochanges +noclasses +nocode +nocomment +nocomplete +nocontent +nocontentconvert +nocontinue +noconvertlink +nocookiesfornew +nocopyright +nocourseid +nocreate +nocreatetext +nocredits +nocta +nodata +nodatabase +nodb +nodefault +nodeid +nodeleteablefile +nodeletion +nodelist +nodename +nodirection +nodotdot +noedit +noeditsection +noemail +noemailprefs +noemailtitle +noeventid +noexec +noexpertise +noexpression +nofeed +nofeedbackid +nofile +nofilekey +nofilename +nofilter +noflagtype +noflip +nofollow +nofound +nogallery +nogomatch +nogroup +noheader +noheadings +nohires +noids +noimage +noimageredirect +noimages +noinclude +noindex +noindexing +nointerwikipage +nointerwikiuserrights +noitem +nojs +nolabel +nolang +nolicense +nolimit +nolink +nolinkstoimage +nologging +nologin +nomahaction +nominornewtalk +nomodule +non +noname +nonamespacenumber +nonascii +noncascading +nondefaults +none +nonewsectionlink +nonexistent +nonfile +nonfilenamespace +nonincludable +noninfringement +noninitial +nonlocal +nonote +nonredirects +nonsense +nonunicodebrowser +noobjective +noofexpiries +noofprotections +noop +nooptions +nooverride +nopaction +nopage +nopageid +nopagetext +nopagetitle +noparser +nopathinfo +nopermission +noport +noprefix +noproject +noprop +noprotections +noquestion +noradius +noratelimit +norating +norcid +noread +noreason +noredir +noredirect +norequest +norestrictiontypes +noresult +noreturnto +norev +norevid +noreviewed +normalizedtitle +norole +norollbackdiff +noscale +noschema +noscript +nosearch +nosectiontitle +nosession +noshade +noskipnotif +noslash +nosniff +nosort +nosortdirection +nosource +nospecialpagetext +nost +nosubaction +nosubject +nosubpage +nosubpages +nosuccess +nosuchaction +nosuchactiontext +nosuchdatabase +nosuchlogid +nosuchpageid +nosuchrcid +nosuchrevid +nosuchsection +nosuchsectiontext +nosuchsectiontitle +nosuchspecialpage +nosuchuser +nosuchusershort +nosummary +notacceptable +notag +notaglist +notalk +notallowed +notanarticle +notarget +notcached +notdeleted +note +notempdir +notemplate +notext +nothumb +notif +notificationtimestamp +notificationtimestamps +notin +notitle +notitleconvert +notloggedin +notminor +noto +notoc +notoggle +notoken +notransform +notreviewable +notrustworthy +notspecialpage +notsuspended +notvisiblerev +notwatched +notwikitext +notype +noudp +noupdates +nouploadmodule +nouser +nouserid +nousername +nouserspecified +novalues +noview +nowatchlist +nowellwritten +nowiki +nowlocal +nowserver +nparsing +ns +nsassociated +nsfrom +nsinvert +nslinks +nslist +nsname +nsnum +nspname +nsselect +nstab +nsub +ntfs +ntilde +ntitle +nuke +null +nullable +numauthors +number +numberheadings +numberingroup +numberof +numberofactiveusers +numberofadmins +numberofarticles +numberofedits +numberoffiles +numberofpages +numberofusers +numberofviews +numberofwatchingusers +numedits +numentries +numericized +numgroups +numtalkauthors +numtalkedits +numwatchers +nwidth +oacute +objectcache +objective +ocirc +ocount +oelig +of +officedocument +offset +offsite +ofname +ogevents +ogghandler +ograve +old +oldaddr +oldcountable +older +olderror +oldfile +oldgroups +oldid +oldimage +oldlen +oldnamespace +oldquery +oldrev +oldrevid +oldreviewedpages +oldshared +oldsig +oldsize +oldtext +oldtitle +oldtitlemsg +oline +oname +onkeyup +online +onload +onlyauthor +onlyinclude +onlypst +onlyquery +onsubmit +onthisday +ontop +openbasedir +opendoc +opendocument +opensearch +opensearchdescription +openssl's +openxml +openxmlformats +oplus +oppositedm +optgroup +optgroups +optionname +options +optionstoken +optionvalue +optstack +or +ordertype +ordf +ordm +org +origcategory +ortime +oslash +other +otherlanguages +otherlist +otheroption +otherreason +othertime +otilde +otimes +otitle +ouml +outparam +outputter +outputtype +outreachwiki +over +overridable +override +oversight +oversighted +oversighter +overwrite +overwroteimage +own +owner +paction +page +pagecannotexist +pagecategories +pagecategorieslink +pageclass +pagecontent +pagecount +pagecss +pagedeleted +pagedlinks +pageid +pageids +pageimages +pageinfo +pagelink +pagelinks +pagemerge +pagename +pagenamee +pagenames +pagenum +pageoffset +pagepropnames +pageprops +pagerestrictions +pages +pageselector +pageset +pagesetmodule +pagesincategory +pagesinnamespace +pageswithprop +pagetextmsg +pagetitle +pagetools +pagetriage +pagetriageaction +pagetriagelist +pagetriagestats +pagetriagetagging +pagetriagetemplate +pageurl +pageview +param +parameters +paraminfo +paramlist +paramname +params +paren +parens +parentid +parenttree +parms +parse +parsedcomment +parseddescription +parsedsummary +parseerror +parseinline +parsemag +parser +parsercache +parserfuncs +parserfunctions +parserhook +parserrender +parsetree +parsevalue +parsoid +partialupload +partname +pass's +passthru +password +passwordfor +passwordreset +passwordtooshort +paste +pastexpiry +pathchar +pathinfo +pathname +patrol +patroldisabled +patrolled +patrollink +patrolmarks +patroltoken +pattern +pcache +pcntl +pcomment +pdbk +pdf's +pendingdelta +perc +perfcached +perfcachedts +perm +perma +permalink +permdenied +permil +permissiondenied +permissionerror +permissionserrors +permissionserrorstext +permissiontype +perp +perrow +pgsql +photoshop +php +php's +phpfm +phps +phpsapi +phpunit +phpversion +phpwiki +phrasewise +phtml +pi +pipermail +pixmap +pkey +pkuk +pl +plain +plainlink +plainlinks +plaintext +plfrom +plink +pllimit +plns +plpgsql +pltitle +pltitles +plusminus +plusmn +pname +pnmtojpeg +pnmtopng +poolcounter +popts +popularpages +portlet +portlets +posplus +possible +postcomment +postgre +postsep +potd +potm +potx +poweredby +poweredbyico +powersearch +pp +ppam +ppsm +ppsx +pptm +pptx +precaching +precompiled +preferences +preferencestoken +prefill +prefilled +prefix +prefixindex +prefixsearchdisabled +prefs +prefsection +prefsnologin +prefsnologintext +prefsubmit +preload +preloads +preloadtitle +prepending +prependtext +preprocess +preprocessing +preprocessors +presentationml +presep +prevchar +prevdiff +previd +previewconflict +previewhead +previewheader +previewnote +previewonfirst +previewontop +previewtext +previousrevision +prevlink +prevn +prexpiry +prfiltercascade +prfx +primary +printableversion +printfooter +printurl +privacypage +private +privs +prlevel +probabalistically +probs +proc +processings +procs +prodromou +profession +profileinfo +programmatically +project +projectpage +promotion +prop +properties +property +propname +props +prot +protect +protectcomment +protectedarticle +protectedinterface +protectednamespace +protectedpage +protectedpages +protectedpagetext +protectedpagewarning +protectedtitle +protectedtitles +protection +protections +protectlevel +protectlogpage +protectlogtext +protectthispage +protecttoken +proto +protocol +protocols +protos +proxied +proxyblocker +proxyblockreason +proxyunbannable +prtype +psir +pst +psttext +psychedelix +pt +ptext +ptool +pubdate +publicsuffix +publishfailed +punycode +purge +purged +qabardjajəbza +qbar +qbsettings +qmoicj +qp +quasit +query +querycache +querycachetwo +querycur +querydiff +querykey +querymodule +querymodules +querypage +querypages +querystring +querytype +question +queuefull +quickbar +quicktemplate +quicktime +qunit +quux +qvalues +rabdiff +radic +radius +raggett +raii +raimond +random +randompage +randomredirect +randstr +range +rangeblock +rangeblocks +rangedisabled +rangeend +rangestart +raquo +rarr +rarticle +rasterizations +rasterize +rasterized +rasterizer +ratelimited +ratelimits +rating +ratings +raw +rawfm +rawrow +rbspan +rc +rcdays +rceil +rcfeed +rcid +rcids +rclimit +rcoptions +rcpatroldisabled +rctitle +rctoken +rdev +rdfa +rdfrom +rdftype +rdquo +read +readable +readapidenied +readarray +reader +readline +readonlyreason +readonlytext +readonlywarning +readrequired +readrights +realaudio +realllly +realname +realpath +reason +reasonlist +reasonstr +reblock +rebuildtextindex +recache +recached +recaching +recalc +recentchange +recentchanges +recentchangescount +recentchangesdays +recentchangeslinked +recentchangestext +recenteditcount +recentedits +recip +recips +recreate +recurse +recurses +redir +redirect +redirectable +redirectcreated +redirectedfrom +redirections +redirectpagesub +redirectparams +redirects +redirectsnippet +redirectstofile +redirecttitle +redirectto +redirid +redirlinks +redirs +redis +redlink +redlinks +redocument +reedyboy +reenables +reencode +reference +refetch +refresheducation +refreshlinks +regexes +regexlike +region +registered +registration +registrationdate +reimport +reindexation +reindexed +releasenotes +relevance +relevant +relicense +relimit +relkind +relname +relnamespace +remarticle +remembermypassword +rememberpassword +removablegroups +removal +remove +removed +removedwatchtext +removetags +remreviewer +remstudent +renameuser +renaming +renderable +renormalized +repeating +repl +replaceafter +replacer +replacers +replag +replyto +reporttime +repos +request +requested +requestid +requeue +required +rerender +rerendered +rescnt +researcher +resends +reset +resetkinds +resetlink +resetpass +resized +resolutioninfo +resolutionunit +resolve +resolved +resourceloader +responsecode +restore +restorelink +restoreprefs +restricted +result +resultset +resultsperpage +retrievedfrom +returnto +returntoquery +retval +reupload +revalidate +revalidation +revdel +revdelete +revdelete'd +revdelundel +revert +reverting +revertpage +reverts +revid +revids +review +reviewactivity +reviewed +reviewer +reviewing +revision +revisionasof +revisionday +revisiondelete +revisionid +revisionmonth +revisions +revisiontext +revisiontimestamp +revisionuser +revisionyear +revlink +revwrongpage +rfloor +rgba +richtext +rights +rightscode +rightsinfo +rightslog +rightslogtext +rked +rmdir +rn +rnlimit +robotstxt +roff +role +rollback +rollbacker +rollbacklink +rollbacklinkcount +rollbacktoken +rootpage +rootuserpages +rowcount +rown +rownum +rowsarr +rowset +rowspan +rowspans +rsaquo +rsargs +rsd +rsdf +rsquo +rss +rsvg +ruleset +rulesets +rusyn +rv +rvcontinue +rvdiffto +rvlimit +rvparse +rvprop +rvstart +rvstartid +rvtoken +sabino +safemode +safesubst +sais +sameorigin +samp +sansserif +save +savearticle +savedprefs +saveprefs +saveusergroups +sawfish +sbin +sbquo +scaler +scalers +scaron +score +screensize +scribunto +scriptable +scriptbuilder +scriptpath +scrolltop +sdot +search +search's +searchaction +searcharticle +searchboxes +searchbutton +searcheverything +searchform +searchindex +searchinfo +searchlimit +searchmenu +searchnamespaces +searchoptions +searchresulttext +searchstring +searchtitle +secondary +section +sectionanchor +sectionedit +sectioneditnotsupported +sectionformat +sectionnumber +sectionprop +sections +sectionsnippet +sectionsnotsupported +sectiontitle +securelogin +seiten +selectandother +selectorother +self +selflink +selfmove +semiglobal +semiprotected +semiprotectedpagewarning +sendemail +sendmail +sentences +serialize +servedby +servername +servertime +serverurl +sess +session +sessionfailure +sessionid +sessionkey +setchange +setcookie +setemail +setext +setglobalaccountstatus +setnewtype +setnotificationtimestamp +setopt +setrename +setrlimit +setstatus +sha +shar +sharding +shared +shareddescriptionfollows +sharedfile +sharedrepo +sharedupload +shellscript +shiftwidth +shockwave +short +shorturl +shouldn +shouting +show +showalldb +showbots +showdeleted +showdiff +showdifflinks +showfilename +showhiddencats +showhideminor +showhooks +showingresults +showinitializer +showjumplinks +showlinkedto +showme +showmeta +shownavigation +shownumberswatching +showpreview +showredirs +showreviewed +showsizediff +showtoc +showtoolbar +showunreviewed +shtml +si +siebrand +sighhhh +sigkill +sigmaf +signup +sigsegv +sigterm +sii +siit +siiurlwidth +simplesearch +singlegroup +singularthey +sinumberingroup +siprop +site +siteadmin +sitecsspreview +sitedir +siteinfo +sitejspreview +sitemap +sitemaps +sitematrix +sitename +sitenotice +siteprop +sitesearch +sitestats +sitestatsupdate +siteuser +sitewide +size +sizediff +sizediffdisabled +sizes +skey +skinclass +skinkey +skinname +skinnameclass +skins +skipcache +skipcaptcha +skipnotif +skname +sktemplate +slideshow +sm +smaxage +smil +smtp +snippet +sodipodi +softtabstop +solaris +somecontent +somefeed +someuser +sorani +sorbs +sorbsreason +sort +sortdirection +sortkey +sortkeyprefix +sortkeys +source +soxred +spam +spamdetected +spamprotected +spamprotectionmatch +spamprotectiontext +spamprotectiontitle +spcontent +special +specialpage +specialpagealiases +specialpageattributes +specialpagegroup +specialpages +specialprotected +speedtip +speedy +speex +spekking +spellcheck +spezial +spoofable +spreadsheetml +sprefs +sprintf +sprotected +sql's +sqlite +sqltotal +sr +srchres +srcset +srgs +srprop +srwhat +stabilize +stable +stablesettings +stansvik +start +startid +startime +startsortkey +startsortkeyprefix +starttime +starttimestamp +stash +stashfailed +stashimageinfo +state +staticredirect +statistics +statline +status +statuskey +stdclass +stdout +steward +stopwords +storedversion +strcasecmp +strcmp +string +stripos +stripslashes +strlen +strpos +strrpos +strtime +strtok +strtolower +strtotime +strtr +struct +strval +stubthreshold +student +studies +stuffit +stxt +stylename +stylepath +styleversion +subaction +subarray +subcat +subcats +subclassing +subcond +subconds +subdir +subdomain +subdomains +sube +subelement +subelements +subfunction +subfunctions +subimages +subitem +subitems +subject +subjectid +subjectids +subjectpagename +subjectpagenamee +subjectspace +subjectspacee +subkey +subkeys +sublevels +submatch +submodule +submodule's +submodules +subnet +subpage +subpagename +subpagenamee +subpages +subpagestr +subparents +subprocesses +subsql +substr +succ +success +successbox +suckage +suggest +suggestion +suhosin +suhosin's +summ +summary +summarymissed +summaryrequired +supe +superdomain +superglobals +superset +suppress +suppressed +suppressedredirect +suppressionlog +suppressionlogtext +suppressredirect +suppressrevision +svgs +svn +svnroot +sybase +symlinked +syms +sysinfo +sysop +system +systemnachrichten +szdiff +szlig +szymon +t +tabindex +tablealign +tablecell +tablename +tablesorter +tablestack +tabletags +tabletype +tabstop +tag +tagfilter +tagline +taglist +tags +tagset +tagstack +tailorings +talk +talkable +talkfrom +talkid +talkids +talkmove +talkmoveoverredirect +talkpage +talkpageheader +talkpagelinktext +talkpagename +talkpagenamee +talkpagetext +talkspace +talkspacee +talkto +taraškievica +tarask +target +tb +tbase +tbody +tboverride +tcount +tcsh +tddate +tdtime +teardown +telnet +temp +tempdir +template +templatelinks +templatepage +templates +templatesused +templatesusedpreview +templatesusedsection +tempname +tempout +test +testclean +testdata +testmailuser +testpass +testrunner +testswarm +testuser +testutf +texi +texinfo +text +textarea +textareas +textares +textbox +textboxsize +texthidden +textid +textlink +textmissing +textoverride +textsf +textsize +textvector +texvc +tfoot +tful +tg +that'll +thead +thelink +theora +thetasym +thinsp +thisisdeleted +thispage +thumbborder +thumbcaption +thumberror +thumbheight +thumbhtml +thumbimage +thumbinner +thumbmime +thumbnail +thumbnailing +thumbnailsize +thumbname +thumbsize +thumbtext +thumburl +thumbwidth +timeago +timeanddate +timecond +timecorrection +timeframe +timekey +timeoffset +timep +timespans +timestamp +timestamps +timestamptz +timezonelegend +timezoneregion +timezoneuseoffset +timezoneuseserverdefault +tino +title +titleblacklist +titleconversion +titleexists +titlemsg +titleprefixeddbkey +titleprotected +titleprotectedwarning +titles +titlesnippet +titletext +titlevector +tl +tllimit +tltemplates +tmpfile +to +toclevel +tocline +tocnumber +tocsection +toctext +toctitle +tofragment +toggle +toid +token +tokenname +tokens +tolang +tongminh +toobig +toofewexpiries +toohigh +toolarray +toolbarparent +toolboxend +toolboxlink +toolong +toolow +tooltiponly +tooshort +top +toparse +topbar +toplevel +toplinks +toponly +torev +torevid +tornevall +torunblocked +totalcnt +totalcount +totalhits +totalmemory +totaltime +totitle +touched +tplarg +transcludable +transclude +transcluded +transcluding +transclusion +transclusions +transcode +transcodekey +transcoder +transcodereset +transcodestatus +transcoding +translatewiki +transstat +transwiki +troff +true +truespeed +trustworthy +truthy +tsearch +tsquery +tuple +tweakblogs +tweakers +txt +txtfm +type +typemustmatch +typeof +typname +tzstring +uacute +uarr +uc +ucfirst +ucirc +udpprofile +ufffd +ugrave +ui +uint +ulimit +ulink +ulinks +uname +unanchored +unapprove +unary +unattached +unauthenticate +unavailable +unblock +unblocklogentry +unblockself +unblocktoken +unbuffered +uncacheable +uncached +uncategorized +unclosable +uncompress +undel +undelete +undeleted +undeletion +undo +undoafter +undofailure +undorev +unescape +unescaped +unfeature +unfeatured +unflag +ungrouped +unhelpful +unhidden +unhide +unidata +unindent +unindexed +uniq +unique +universaleditbutton +unixtime +unknown +unknownerror +unknownnamespace +unlock +unlockdb +unlogged +unmakesafe +unmark +unmerge +unmodified +unoversight +unoversighted +unpadded +unpatrolled +unpatrolledletter +unprefixed +unprintables +unprotect +unprotectedarticle +unprotection +unprotectthispage +unredacted +unrequest +unrequested +unresolve +unresolved +unreviewed +unreviewedpages +unsanitized +unseed +unserialization +unserialize +unserialized +unserializing +unsetting +unstub +unstubbed +unstubbing +unstubs +unsupportednamespace +unsupportedrepo +untaint +untracked +untrustworthiness +unused +unusual +unversioned +unviewable +unviewed +unwatch +unwatched +unwatchedpages +unwatching +unwatchthispage +unwikified +unwritable +upconvert +updateddate +updatedtime +updatelog +upgradedoc +upgrader +upload +upload's +uploaddisabled +uploadedimage +uploadjava +uploadlogpage +uploadlogpagetext +uploadnewversion +uploadnologintext +uploadpage +uploadscripted +uploadsource +uploadstash +uploadvirus +uppercased +upsih +urandom +url +url's +urlaction +urldecode +urldecoded +urlencode +urlencoded +urlheight +urlparam +urlparm +urlpath +urlvar +urlwidth +ursh +us +usedomain +useemail +uselang +uselivepreview +usemod +usemsgcache +usenewrc +user +useragent +useragents +userblock +usercan +usercontribs +usercreate +usercreated +usercss +usercsspreview +usercssyoucanpreview +userdailycontribs +userdir +userdoesnotexist +usereditcount +useredits +useremail +userexists +usergroup +usergroups +userhidden +userid +userinfo +userinvalidcssjstitle +userips +userjs +userjsprev +userjspreview +userjsyoucanpreview +userlang +userlangattributes +userlink +userlinks +userlogin +userloginlink +userloginprompt +userlogout +usermaildisabled +usermessage +username +usernameless +usernames +userpage +userpages +userpageurl +userprefix +userrights +userrightstoken +users +usersbody +userspace +usertalk +usertalklink +usertext +usertoollinks +useskin +useto +usort +ustar +ustoken +utfnormal +uuml +validate +validationbuilder +valign +vals +value +values +vandal +vandalism +variables +variant +variantarticlepath +varlang +varname +vars +varval +vasiliev +vasilvv +vbase +vbscript +vcount +vcsize +venema's +verbosify +version +versioning +versionlink +versionlog +versionrequired +versionrequiredtext +very +vhost +vi +vibber +videoinfo +view +viewcount +viewdeleted +viewhelppage +viewmyprivateinfo +viewmywatchlist +viewprevnext +viewsource +viewsourcelink +viewsourcetext +viewvc +viewyourtext +visible +visualeditor +viurlwidth +voff +vofp +voicexml +vorbis +vpad +vrml +vslow +vvcv +vxml +wais +wait +wakeup +walltime +warmup +warning +wasdeleted +wasn +watch +watchcreations +watchdefault +watchdeletion +watched +watchlist +watchlistdays +watchlisthideanons +watchlisthidebots +watchlisthideliu +watchlisthideminor +watchlisthideown +watchlisthidepatrolled +watchlistraw +watchlists +watchlisttoken +watchmoves +watchthis +watchthispage +watchtoken +watchuser +wb +wbmp +wbxml +wddx +wddxfm +weblog +webm +webp +webrequest +webserver +weeks +weierp +weight +wellwritten +werdna +wget +what +whatlinkshere +whatwg +wheely +wheter +whitelist +whitelisted +whitelistedittext +whitelisting +whois +wicke +width +widthx +wierkosz +wietse +wiki +wiki'd +wiki's +wikia +wikiadmin +wikibase +wikibits +wikibooks +wikidb +wikifarm +wikiid +wikilink +wikilinks +wikilove +wikiloveimagelog +wikimedia +wikimediacommons +wikipage +wikipedia +wikipedian +wikipedias +wikis +wikisyntax +wikitable +wikitables +wikitech +wikitext +wikiuser +wiktionary +wincache +wininet +withaccess +withaction +witheditsonly +withlanglinks +withoutlanglinks +wl +wlallrev +wldir +wlend +wlexcludeuser +wllimit +wlowner +wlprop +wltoken +wmf's +wml +wmlc +wmls +wmlsc +wmlscript +wmlscriptc +wordcount +wordprocessingml +wordwg +workalike +worldwind +wouldn +wr +writeapi +writeapidenied +writedisabled +writerequired +writerights +wrongpassword +x +xbitmap +xcache +xcancel +xdebug +xdiff +xdomain +xdomains +xff +xhtmldefaultnamespace +xhtmlnamespaces +xiff +xlam +xlsb +xlsm +xlsx +xltm +xltx +xml +xmldoublequote +xmlfm +xmlimport +xmlns +xmlsafe +xmlselect +xor +xpinstall +xpixmap +xpsdocument +xtended +xwindowdump +xxxx +xxxxx +yacute +yaml +yamlfm +year +yes +youhavenewmessages +youhavenewmessagesfromusers +youhavenewmessagesmanyusers +youhavenewmessagesmulti +yourdiff +yourdomainname +youremail +yourgender +yourinternal +yourlanguage +yourname +yournick +yourpassword +yourrealname +yourtext +yourvariant +yourwiki +yuml +yyyymmddhhiiss +zhdaemon +zhengzhu +zhtable +zijdel +zlib +zoffset +zwnj diff --git a/maintenance/doMaintenance.php b/maintenance/doMaintenance.php index 2bb2a0f4..3bd508cb 100644 --- a/maintenance/doMaintenance.php +++ b/maintenance/doMaintenance.php @@ -34,7 +34,7 @@ if ( !defined( 'RUN_MAINTENANCE_IF_MAIN' ) ) { // Wasn't included from the file scope, halt execution (probably wanted the class) // If a class is using commandLine.inc (old school maintenance), they definitely // cannot be included and will proceed with execution -if( !Maintenance::shouldExecute() && $maintClass != 'CommandLineInc' ) { +if ( !Maintenance::shouldExecute() && $maintClass != 'CommandLineInc' ) { return; } @@ -53,27 +53,29 @@ $maintenance->setup(); // to $maintenance->mSelf. Keep that here for b/c $self = $maintenance->getName(); -// Detect compiled mode -if ( isset( $_SERVER['MW_COMPILED'] ) ) { - define( 'MW_COMPILED', 1 ); -} else { - # Get the MWInit class - require_once( "$IP/includes/Init.php" ); - require_once( "$IP/includes/AutoLoader.php" ); -} - +# Start the autoloader, so that extensions can derive classes from core files +require_once "$IP/includes/AutoLoader.php"; # Stub the profiler -require_once( MWInit::compiledPath( 'includes/profiler/Profiler.php' ) ); +require_once "$IP/includes/profiler/Profiler.php"; + +# Start the profiler +$wgProfiler = array(); +if ( file_exists( "$IP/StartProfiler.php" ) ) { + require "$IP/StartProfiler.php"; +} // Some other requires -if ( !defined( 'MW_COMPILED' ) ) { - require_once( "$IP/includes/Defines.php" ); +require_once "$IP/includes/Defines.php"; +require_once "$IP/includes/DefaultSettings.php"; + +# Load composer's autoloader if present +if ( is_readable( "$IP/vendor/autoload.php" ) ) { + require_once "$IP/vendor/autoload.php"; } -require_once( MWInit::compiledPath( 'includes/DefaultSettings.php' ) ); if ( defined( 'MW_CONFIG_CALLBACK' ) ) { # Use a callback function to configure MediaWiki - MWFunction::call( MW_CONFIG_CALLBACK ); + call_user_func( MW_CONFIG_CALLBACK ); } else { if ( file_exists( "$IP/../wmf-config/wikimedia-mode" ) ) { // Load settings, using wikimedia-mode if needed @@ -82,25 +84,26 @@ if ( defined( 'MW_CONFIG_CALLBACK' ) ) { # Maybe a hook? global $cluster; $cluster = 'pmtpa'; - require( MWInit::interpretedPath( '../wmf-config/wgConf.php' ) ); + require "$IP/../wmf-config/wgConf.php"; } // Require the configuration (probably LocalSettings.php) - require( $maintenance->loadSettings() ); + require $maintenance->loadSettings(); } if ( $maintenance->getDbType() === Maintenance::DB_ADMIN && is_readable( "$IP/AdminSettings.php" ) ) { - require( MWInit::interpretedPath( 'AdminSettings.php' ) ); + require "$IP/AdminSettings.php"; } if ( $maintenance->getDbType() === Maintenance::DB_NONE ) { - if ( $wgLocalisationCacheConf['storeClass'] === false && ( $wgLocalisationCacheConf['store'] == 'db' || ( $wgLocalisationCacheConf['store'] == 'detect' && !$wgCacheDirectory ) ) ) + if ( $wgLocalisationCacheConf['storeClass'] === false && ( $wgLocalisationCacheConf['store'] == 'db' || ( $wgLocalisationCacheConf['store'] == 'detect' && !$wgCacheDirectory ) ) ) { $wgLocalisationCacheConf['storeClass'] = 'LCStore_Null'; + } } $maintenance->finalSetup(); // Some last includes -require_once( MWInit::compiledPath( 'includes/Setup.php' ) ); +require_once "$IP/includes/Setup.php"; // Much much faster startup than creating a title object $wgTitle = null; @@ -111,8 +114,18 @@ try { // Potentially debug globals $maintenance->globals(); + + // Perform deferred updates. + DeferredUpdates::doUpdates( 'commit' ); + + // log profiling info + wfLogProfilingData(); + + // Commit and close up! + $factory = wfGetLBFactory(); + $factory->commitMasterChanges(); + $factory->shutdown(); } catch ( MWException $mwe ) { - echo( $mwe->getText() ); + echo $mwe->getText(); exit( 1 ); } - diff --git a/maintenance/dumpBackup.php b/maintenance/dumpBackup.php index c9546c60..25a777cd 100644 --- a/maintenance/dumpBackup.php +++ b/maintenance/dumpBackup.php @@ -27,10 +27,10 @@ $originalDir = getcwd(); -$optionsWithArgs = array( 'pagelist', 'start', 'end', 'revstart', 'revend'); +$optionsWithArgs = array( 'pagelist', 'start', 'end', 'revstart', 'revend' ); -require_once( __DIR__ . '/commandLine.inc' ); -require_once( __DIR__ . '/backup.inc' ); +require_once __DIR__ . '/commandLine.inc'; +require_once __DIR__ . '/backup.inc'; $dumper = new BackupDumper( $argv ); @@ -44,8 +44,8 @@ if ( isset( $options['pagelist'] ) ) { $pages = file( $options['pagelist'] ); chdir( $olddir ); if ( $pages === false ) { - echo( "Unable to open file {$options['pagelist']}\n" ); - die(1); + echo "Unable to open file {$options['pagelist']}\n"; + die( 1 ); } $pages = array_map( 'trim', $pages ); $dumper->pages = array_filter( $pages, create_function( '$x', 'return $x !== "";' ) ); @@ -79,7 +79,7 @@ if ( isset( $options['full'] ) ) { $dumper->dump( WikiExporter::STABLE, $textMode ); } elseif ( isset( $options['logs'] ) ) { $dumper->dump( WikiExporter::LOGS ); -} elseif ( isset($options['revrange'] ) ) { +} elseif ( isset( $options['revrange'] ) ) { $dumper->dump( WikiExporter::RANGE, $textMode ); } else { $dumper->progress( <<<ENDS diff --git a/maintenance/dumpIterator.php b/maintenance/dumpIterator.php index 3657f960..dd468a9f 100644 --- a/maintenance/dumpIterator.php +++ b/maintenance/dumpIterator.php @@ -26,7 +26,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Base class for interating over a dump. @@ -47,13 +47,13 @@ abstract class DumpIterator extends Maintenance { } public function execute() { - if (! ( $this->hasOption('file') ^ $this->hasOption('dump') ) ) { - $this->error("You must provide a file or dump", true); + if ( !( $this->hasOption( 'file' ) ^ $this->hasOption( 'dump' ) ) ) { + $this->error( "You must provide a file or dump", true ); } $this->checkOptions(); - if ( $this->hasOption('file') ) { + if ( $this->hasOption( 'file' ) ) { $revision = new WikiRevision; $revision->setText( file_get_contents( $this->getOption( 'file' ) ) ); @@ -64,10 +64,10 @@ abstract class DumpIterator extends Maintenance { $this->startTime = microtime( true ); - if ( $this->getOption('dump') == '-' ) { + 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 ); @@ -81,9 +81,10 @@ abstract class DumpIterator extends Maintenance { $this->conclusions(); $delta = microtime( true ) - $this->startTime; - $this->error( "Done {$this->count} revisions in " . round($delta, 2) . " seconds " ); - if ($delta > 0) - $this->error( round($this->count / $delta, 2) . " pages/sec" ); + $this->error( "Done {$this->count} revisions in " . round( $delta, 2 ) . " seconds " ); + if ( $delta > 0 ) { + $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) @@ -96,7 +97,7 @@ abstract class DumpIterator extends Maintenance { if ( $this->getDbType() == Maintenance::DB_NONE ) { global $wgUseDatabaseMessages, $wgLocalisationCacheConf, $wgHooks; $wgUseDatabaseMessages = false; - $wgLocalisationCacheConf['storeClass'] = 'LCStore_Null'; + $wgLocalisationCacheConf['storeClass'] = 'LCStore_Null'; $wgHooks['InterwikiLoadPrefix'][] = 'DumpIterator::disableInterwikis'; } } @@ -122,9 +123,10 @@ abstract class DumpIterator extends Maintenance { $this->count++; if ( isset( $this->from ) ) { - if ( $this->from != $title ) + if ( $this->from != $title ) { return; - $this->output( "Skipped " . ($this->count - 1) . " pages\n" ); + } + $this->output( "Skipped " . ( $this->count - 1 ) . " pages\n" ); $this->count = 1; $this->from = null; @@ -168,11 +170,11 @@ class SearchDump extends DumpIterator { * @param $rev Revision */ public function processRevision( $rev ) { - if ( preg_match( $this->getOption( 'regex' ), $rev->getText() ) ) { + if ( preg_match( $this->getOption( 'regex' ), $rev->getContent()->getTextForSearchIndex() ) ) { $this->output( $rev->getTitle() . " matches at edit from " . $rev->getTimestamp() . "\n" ); } } } $maintClass = "SearchDump"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/dumpLinks.php b/maintenance/dumpLinks.php index 153fdd79..be0b4633 100644 --- a/maintenance/dumpLinks.php +++ b/maintenance/dumpLinks.php @@ -30,7 +30,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that generates a plaintext link dump. @@ -63,17 +63,17 @@ class DumpLinks extends Maintenance { $this->output( "\n" ); } $page = Title::makeTitle( $row->page_namespace, $row->page_title ); - $this->output( $page->getPrefixedUrl() ); + $this->output( $page->getPrefixedURL() ); $lastPage = $row->page_id; } $link = Title::makeTitle( $row->pl_namespace, $row->pl_title ); - $this->output( " " . $link->getPrefixedUrl() ); + $this->output( " " . $link->getPrefixedURL() ); } - if ( isset( $lastPage ) ) + if ( isset( $lastPage ) ) { $this->output( "\n" ); + } } } $maintClass = "DumpLinks"; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/dumpSisterSites.php b/maintenance/dumpSisterSites.php index e05e154e..5f0c5b7c 100644 --- a/maintenance/dumpSisterSites.php +++ b/maintenance/dumpSisterSites.php @@ -25,7 +25,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that generates a page name dump for SisterSites usage. @@ -43,14 +43,15 @@ class DumpSisterSites extends Maintenance { $dbr->bufferResults( false ); $result = $dbr->select( 'page', array( 'page_namespace', 'page_title' ), - array( 'page_namespace' => NS_MAIN, - 'page_is_redirect' => 0, + array( + 'page_namespace' => NS_MAIN, + 'page_is_redirect' => 0, ), __METHOD__ ); foreach ( $result as $row ) { $title = Title::makeTitle( $row->page_namespace, $row->page_title ); - $url = $title->getFullUrl(); + $url = $title->getFullURL(); $text = $title->getPrefixedText(); $this->output( "$url $text\n" ); } @@ -58,4 +59,4 @@ class DumpSisterSites extends Maintenance { } $maintClass = "DumpSisterSites"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/dumpTextPass.php b/maintenance/dumpTextPass.php index 72d7d97c..5d783cb9 100644 --- a/maintenance/dumpTextPass.php +++ b/maintenance/dumpTextPass.php @@ -26,8 +26,8 @@ $originalDir = getcwd(); -require_once( __DIR__ . '/commandLine.inc' ); -require_once( __DIR__ . '/backupTextPass.inc' ); +require_once __DIR__ . '/commandLine.inc'; +require_once __DIR__ . '/backupTextPass.inc'; $dumper = new TextPassDumper( $argv ); @@ -64,5 +64,3 @@ Options: ENDS ); } - - diff --git a/maintenance/dumpUploads.php b/maintenance/dumpUploads.php index 0d0dfcf3..1a9293cb 100644 --- a/maintenance/dumpUploads.php +++ b/maintenance/dumpUploads.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to dump a the list of files uploaded, @@ -125,4 +125,4 @@ By default, outputs relative paths against the parent directory of \$wgUploadDir } $maintClass = "UploadDumper"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/edit.php b/maintenance/edit.php index 59df5e88..7c24f0fa 100644 --- a/maintenance/edit.php +++ b/maintenance/edit.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to make a page edit. @@ -52,6 +52,8 @@ 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 ); } @@ -63,15 +65,17 @@ class EditCLI extends Maintenance { if ( !$wgTitle ) { $this->error( "Invalid title", true ); } + $context->setTitle( $wgTitle ); $page = WikiPage::factory( $wgTitle ); # Read the text $text = $this->getStdin( Maintenance::STDIN_ALL ); + $content = ContentHandler::makeContent( $text, $wgTitle ); # Do the edit $this->output( "Saving... " ); - $status = $page->doEdit( $text, $summary, + $status = $page->doEditContent( $content, $summary, ( $minor ? EDIT_MINOR : 0 ) | ( $bot ? EDIT_FORCE_BOT : 0 ) | ( $autoSummary ? EDIT_AUTOSUMMARY : 0 ) | @@ -91,5 +95,4 @@ class EditCLI extends Maintenance { } $maintClass = "EditCLI"; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/eraseArchivedFile.php b/maintenance/eraseArchivedFile.php new file mode 100644 index 00000000..1c3f0376 --- /dev/null +++ b/maintenance/eraseArchivedFile.php @@ -0,0 +1,119 @@ +<?php +/** + * Delete archived (non-current) files from storage + * + * 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 Aaron Schulz + */ + +require_once __DIR__ . '/Maintenance.php'; + +/** + * Maintenance script to delete archived (non-current) files from storage. + * + * @TODO: Maybe add some simple logging + * + * @ingroup Maintenance + * @since 1.22 + */ +class EraseArchivedFile extends Maintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = "Erases traces of deleted files."; + $this->addOption( 'delete', 'Perform the deletion' ); + $this->addOption( 'filename', 'File name', false, true ); + $this->addOption( 'filekey', 'File storage key (with extension) or "*"', true, true ); + } + + public function execute() { + if ( !$this->hasOption( 'delete' ) ) { + $this->output( "Use --delete to actually confirm this script\n" ); + } + + $filekey = $this->getOption( 'filekey' ); + $filename = $this->getOption( 'filename' ); + + if ( $filekey === '*' ) { // all versions by name + if ( !strlen( $filename ) ) { + $this->error( "Missing --filename parameter.", 1 ); + } + $afile = false; + } else { // specified version + $dbw = wfGetDB( DB_MASTER ); + $row = $dbw->selectRow( 'filearchive', '*', + array( 'fa_storage_group' => 'deleted', 'fa_storage_key' => $filekey ), + __METHOD__ ); + if ( !$row ) { + $this->error( "No deleted file exists with key '$filekey'.", 1 ); + } + $filename = $row->fa_name; + $afile = ArchivedFile::newFromRow( $row ); + } + + $file = wfLocalFile( $filename ); + if ( $file->exists() ) { + $this->error( "File '$filename' is still a public file, use the delete form.\n", 1 ); + } + + $this->output( "Purging all thumbnails for file '$filename'..." ); + $file->purgeCache(); + $file->purgeHistory(); + $this->output( "done.\n" ); + + if ( $afile instanceof ArchivedFile ) { + $this->scrubVersion( $afile ); + } else { + $this->output( "Finding deleted versions of file '$filename'...\n" ); + $this->scrubAllVersions( $filename ); + $this->output( "Done\n" ); + } + } + + protected function scrubAllVersions( $name ) { + $dbw = wfGetDB( DB_MASTER ); + $res = $dbw->select( 'filearchive', '*', + array( 'fa_name' => $name, 'fa_storage_group' => 'deleted' ), + __METHOD__ ); + foreach ( $res as $row ) { + $this->scrubVersion( ArchivedFile::newFromRow( $row ) ); + } + } + + protected function scrubVersion( ArchivedFile $archivedFile ) { + $key = $archivedFile->getStorageKey(); + $name = $archivedFile->getName(); + $ts = $archivedFile->getTimestamp(); + $repo = RepoGroup::singleton()->getLocalRepo(); + $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key; + if ( $this->hasOption( 'delete' ) ) { + $status = $repo->getBackend()->delete( array( 'src' => $path ) ); + if ( $status->isOK() ) { + $this->output( "Deleted version '$key' ($ts) of file '$name'\n" ); + } else { + $this->output( "Failed to delete version '$key' ($ts) of file '$name'\n" ); + $this->output( print_r( $status->getErrorsArray(), true ) ); + } + } else { + $this->output( "Would delete version '{$key}' ({$ts}) of file '$name'\n" ); + } + } +} + +$maintClass = "EraseArchivedFile"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/eval.php b/maintenance/eval.php index 5aefe1c9..abedc61a 100644 --- a/maintenance/eval.php +++ b/maintenance/eval.php @@ -34,7 +34,7 @@ $optionsWithArgs = array( 'd' ); /** */ -require_once( __DIR__ . "/commandLine.inc" ); +require_once __DIR__ . "/commandLine.inc"; if ( isset( $options['d'] ) ) { $d = $options['d']; @@ -43,7 +43,7 @@ if ( isset( $options['d'] ) ) { } if ( $d > 1 ) { $lb = wfGetLB(); - $serverCount = $lb->getServerCount(); + $serverCount = $lb->getServerCount(); for ( $i = 0; $i < $serverCount; $i++ ) { $server = $lb->getServerInfo( $i ); $server['flags'] |= DBO_DEBUG; @@ -80,5 +80,3 @@ while ( ( $line = Maintenance::readconsole() ) !== false ) { } print "\n"; - - diff --git a/maintenance/fetchText.php b/maintenance/fetchText.php index a705bcca..05470d30 100644 --- a/maintenance/fetchText.php +++ b/maintenance/fetchText.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script used to fetch page text in a subprocess. @@ -45,7 +45,7 @@ class FetchText extends Maintenance { * * note that that the text string itself is *not* followed by newline */ - public function execute() { + public function execute() { $db = wfGetDB( DB_SLAVE ); $stdin = $this->getStdin(); while ( !feof( $stdin ) ) { @@ -56,12 +56,12 @@ class FetchText extends Maintenance { } $textId = intval( $line ); $text = $this->doGetText( $db, $textId ); - if ($text === false) { + if ( $text === false ) { # actual error, not zero-length text $textLen = "-1"; } else { - $textLen = strlen($text); + $textLen = strlen( $text ); } $this->output( $textId . "\n" . $textLen . "\n" . $text ); } @@ -88,4 +88,4 @@ class FetchText extends Maintenance { } $maintClass = "FetchText"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/fileOpPerfTest.php b/maintenance/fileOpPerfTest.php index 501bcfc3..9dba8183 100644 --- a/maintenance/fileOpPerfTest.php +++ b/maintenance/fileOpPerfTest.php @@ -21,11 +21,8 @@ * @ingroup Maintenance */ -$initialTime = microtime( true ); -$wgProfiler = array( 'class' => 'ProfilerSimpleText' ); error_reporting( E_ALL ); - -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to test fileop performance. @@ -40,10 +37,13 @@ class TestFileOpPerformance extends Maintenance { $this->addOption( 'b2', 'Backend 2', false, true ); $this->addOption( 'srcdir', 'File source directory', true, true ); $this->addOption( 'maxfiles', 'Max files', false, true ); - $this->addOption( 'quick', 'Avoid operation pre-checks' ); + $this->addOption( 'quick', 'Avoid operation pre-checks (use doQuickOperations())' ); + $this->addOption( 'parallelize', '"parallelize" flag for doOperations()', false, true ); } public function execute() { + Profiler::setInstance( new ProfilerSimpleText( array() ) ); // clear + $backend = FileBackendGroup::singleton()->get( $this->getOption( 'b1' ) ); $this->doPerfTest( $backend ); @@ -52,9 +52,8 @@ class TestFileOpPerformance extends Maintenance { $this->doPerfTest( $backend ); } - $profiler = Profiler::instance(); - $profiler->setTemplated( true ); - $profiler->logData(); // prints + Profiler::instance()->setTemplated( true ); + // NOTE: as of MW1.21, $profiler->logData() is called implicitly by doMaintenance.php. } protected function doPerfTest( FileBackend $backend ) { @@ -78,7 +77,7 @@ class TestFileOpPerformance extends Maintenance { $this->output( "Using '$dirname/$file' in operations.\n" ); $dst = $baseDir . '/' . wfBaseName( $file ); $ops1[] = array( 'op' => 'store', - 'src' => "$dirname/$file", 'dst' => $dst, 'overwrite' => 1); + 'src' => "$dirname/$file", 'dst' => $dst, 'overwrite' => 1 ); $ops2[] = array( 'op' => 'copy', 'src' => "$dst", 'dst' => "$dst-1", 'overwrite' => 1 ); $ops3[] = array( 'op' => 'move', @@ -95,52 +94,57 @@ class TestFileOpPerformance extends Maintenance { $method = $this->hasOption( 'quick' ) ? 'doQuickOperations' : 'doOperations'; + $opts = array( 'force' => 1 ); + if ( $this->hasOption( 'parallelize' ) ) { + $opts['parallelize'] = ( $this->getOption( 'parallelize' ) === 'true' ); + } + $start = microtime( true ); - $status = $backend->$method( $ops1, array( 'force' => 1 ) ); + $status = $backend->$method( $ops1, $opts ); $e = ( microtime( true ) - $start ) * 1000; if ( $status->getErrorsArray() ) { print_r( $status->getErrorsArray() ); - exit(0); + exit( 0 ); } $this->output( $backend->getName() . ": Stored " . count( $ops1 ) . " files in $e ms.\n" ); $start = microtime( true ); - $backend->$method( $ops2, array( 'force' => 1 ) ); + $backend->$method( $ops2, $opts ); $e = ( microtime( true ) - $start ) * 1000; if ( $status->getErrorsArray() ) { print_r( $status->getErrorsArray() ); - exit(0); + exit( 0 ); } $this->output( $backend->getName() . ": Copied " . count( $ops2 ) . " files in $e ms.\n" ); $start = microtime( true ); - $backend->$method( $ops3, array( 'force' => 1 ) ); + $backend->$method( $ops3, $opts ); $e = ( microtime( true ) - $start ) * 1000; if ( $status->getErrorsArray() ) { print_r( $status->getErrorsArray() ); - exit(0); + exit( 0 ); } $this->output( $backend->getName() . ": Moved " . count( $ops3 ) . " files in $e ms.\n" ); $start = microtime( true ); - $backend->$method( $ops4, array( 'force' => 1 ) ); + $backend->$method( $ops4, $opts ); $e = ( microtime( true ) - $start ) * 1000; if ( $status->getErrorsArray() ) { print_r( $status->getErrorsArray() ); - exit(0); + exit( 0 ); } $this->output( $backend->getName() . ": Deleted " . count( $ops4 ) . " files in $e ms.\n" ); $start = microtime( true ); - $backend->$method( $ops5, array( 'force' => 1 ) ); + $backend->$method( $ops5, $opts ); $e = ( microtime( true ) - $start ) * 1000; if ( $status->getErrorsArray() ) { print_r( $status->getErrorsArray() ); - exit(0); + exit( 0 ); } $this->output( $backend->getName() . ": Deleted " . count( $ops5 ) . " files in $e ms.\n" ); } } $maintClass = "TestFileOpPerformance"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/findHooks.php b/maintenance/findHooks.php index e273c545..373170ff 100644 --- a/maintenance/findHooks.php +++ b/maintenance/findHooks.php @@ -34,7 +34,7 @@ * @author Antoine Musso <hashar at free dot fr> */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that compares documented and actually present mismatches. @@ -64,6 +64,7 @@ class FindHooks extends Maintenance { $IP . '/includes/actions/', $IP . '/includes/api/', $IP . '/includes/cache/', + $IP . '/includes/content/', $IP . '/includes/context/', $IP . '/includes/db/', $IP . '/includes/diff/', @@ -114,7 +115,7 @@ class FindHooks extends Maintenance { */ private function getHooksFromDoc( $doc ) { if ( $this->hasOption( 'online' ) ) { - return $this->getHooksFromOnlineDoc( ); + return $this->getHooksFromOnlineDoc(); } else { return $this->getHooksFromLocalDoc( $doc ); } @@ -136,7 +137,7 @@ class FindHooks extends Maintenance { * Get hooks from www.mediawiki.org using the API * @return array of documented hooks */ - private function getHooksFromOnlineDoc( ) { + 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 ); @@ -170,7 +171,7 @@ class FindHooks extends Maintenance { private function getHooksFromFile( $file ) { $content = file_get_contents( $file ); $m = array(); - preg_match_all( '/(?:wfRunHooks|Hooks\:\:run)\(\s*([\'"])(.*?)\1/', $content, $m ); + preg_match_all( '/(?:wfRunHooks|Hooks\:\:run|ContentHandler\:\:runLegacyHooks)\(\s*([\'"])(.*?)\1/', $content, $m ); return $m[2]; } @@ -247,4 +248,4 @@ class FindHooks extends Maintenance { } $maintClass = 'FindHooks'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/fixDoubleRedirects.php b/maintenance/fixDoubleRedirects.php index 6f017eca..523be7ef 100644 --- a/maintenance/fixDoubleRedirects.php +++ b/maintenance/fixDoubleRedirects.php @@ -25,7 +25,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that fixes double redirects. @@ -55,7 +55,12 @@ class FixDoubleRedirects extends Maintenance { $dbr = wfGetDB( DB_SLAVE ); - $tables = array( 'redirect', 'pa' => 'page', 'pb' => 'page' ); + // See also SpecialDoubleRedirects + $tables = array( + 'redirect', + 'pa' => 'page', + 'pb' => 'page', + ); $fields = array( 'pa.page_namespace AS pa_namespace', 'pa.page_title AS pa_title', @@ -66,6 +71,7 @@ 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 'pb.page_is_redirect' => 1, ); @@ -83,12 +89,18 @@ class FixDoubleRedirects extends Maintenance { } $jobs = array(); + $processedTitles = "\n"; $n = 0; foreach ( $res as $row ) { $titleA = Title::makeTitle( $row->pa_namespace, $row->pa_title ); $titleB = Title::makeTitle( $row->pb_namespace, $row->pb_title ); - $job = new DoubleRedirectJob( $titleA, array( 'reason' => 'maintenance', 'redirTitle' => $titleB->getPrefixedDBkey() ) ); + $processedTitles .= "* [[$titleA]]\n"; + + $job = new DoubleRedirectJob( $titleA, array( + 'reason' => 'maintenance', + 'redirTitle' => $titleB->getPrefixedDBkey() + ) ); if ( !$async ) { $success = ( $dryrun ? true : $job->run() ); @@ -112,14 +124,14 @@ class FixDoubleRedirects extends Maintenance { if ( count( $jobs ) ) { $this->queueJobs( $jobs, $dryrun ); } - $this->output( "$n double redirects processed.\n" ); + $this->output( "$n double redirects processed" . $processedTitles . "\n" ); } protected function queueJobs( $jobs, $dryrun = false ) { $this->output( "Queuing batch of " . count( $jobs ) . " double redirects.\n" ); - Job::batchInsert( $dryrun ? array() : $jobs ); + JobQueueGroup::singleton()->push( $dryrun ? array() : $jobs ); } } $maintClass = "FixDoubleRedirects"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/fixExtLinksProtocolRelative.php b/maintenance/fixExtLinksProtocolRelative.php index 2403ec68..02d65ed1 100644 --- a/maintenance/fixExtLinksProtocolRelative.php +++ b/maintenance/fixExtLinksProtocolRelative.php @@ -23,7 +23,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that fixes any entriy for protocol-relative URLs @@ -66,11 +66,13 @@ class FixExtLinksProtocolRelative extends LoggedUpdateMaintenance { $db->insert( 'externallinks', array( array( + 'el_id' => $db->nextSequenceValue( 'externallinks_el_id_seq' ), 'el_from' => $row->el_from, 'el_to' => $row->el_to, 'el_index' => "http:{$row->el_index}", ), array( + 'el_id' => $db->nextSequenceValue( 'externallinks_el_id_seq' ), 'el_from' => $row->el_from, 'el_to' => $row->el_to, 'el_index' => "https:{$row->el_index}", @@ -85,4 +87,4 @@ class FixExtLinksProtocolRelative extends LoggedUpdateMaintenance { } $maintClass = "FixExtLinksProtocolRelative"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/fixSlaveDesync.php b/maintenance/fixSlaveDesync.php index 8bf556f0..e4e557fe 100644 --- a/maintenance/fixSlaveDesync.php +++ b/maintenance/fixSlaveDesync.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that fixes erroneous page_latest values @@ -67,7 +67,7 @@ class FixSlaveDesync extends Maintenance { $dbw = wfGetDB( DB_MASTER ); $masterIDs = array(); $res = $dbw->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ ); - $this->output( "Number of pages: " . $dbw->numRows( $res ) . "\n" ); + $this->output( "Number of pages: " . $res->numRows() . "\n" ); foreach ( $res as $row ) { $masterIDs[$row->page_id] = $row->page_latest; if ( !( ++$n % 10000 ) ) { @@ -106,10 +106,10 @@ class FixSlaveDesync extends Maintenance { $db = wfGetDB( $i ); /* if ( !$db->masterPosWait( $masterFile, $masterPos, 10 ) ) { - $this->output( "Slave is too lagged, aborting\n" ); - $dbw->commit( __METHOD__ ); - sleep(10); - return; + $this->output( "Slave is too lagged, aborting\n" ); + $dbw->commit( __METHOD__ ); + sleep(10); + return; }*/ $latest = $db->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), __METHOD__ ); $max = $db->selectField( 'revision', 'MAX(rev_id)', false, __METHOD__ ); @@ -213,4 +213,4 @@ class FixSlaveDesync extends Maintenance { } $maintClass = "FixSlaveDesync"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/fixTimestamps.php b/maintenance/fixTimestamps.php index 84d08d39..b0609d17 100644 --- a/maintenance/fixTimestamps.php +++ b/maintenance/fixTimestamps.php @@ -25,7 +25,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that fixes timestamp corruption caused by one or @@ -125,4 +125,4 @@ class FixTimestamps extends Maintenance { } $maintClass = "FixTimestamps"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/fixUserRegistration.php b/maintenance/fixUserRegistration.php index 91d42a5d..097936c9 100644 --- a/maintenance/fixUserRegistration.php +++ b/maintenance/fixUserRegistration.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that fixes the user_registration field. @@ -58,4 +58,4 @@ class FixUserRegistration extends Maintenance { } $maintClass = "FixUserRegistration"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/formatInstallDoc.php b/maintenance/formatInstallDoc.php index 600ca976..e2b3c419 100644 --- a/maintenance/formatInstallDoc.php +++ b/maintenance/formatInstallDoc.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ .'/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that formats RELEASE-NOTE file to wiki text or HTML markup. @@ -75,6 +75,4 @@ class MaintenanceFormatInstallDoc extends Maintenance { } $maintClass = 'MaintenanceFormatInstallDoc'; -require_once( RUN_MAINTENANCE_IF_MAIN ); - - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/fuzz-tester.php b/maintenance/fuzz-tester.php index 1c96a571..548bb2f2 100644 --- a/maintenance/fuzz-tester.php +++ b/maintenance/fuzz-tester.php @@ -118,7 +118,6 @@ Wiki configuration for testing: // 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 - $wgBlockOpenProxies = true; // Some block pages require this to be true in order to test. $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). @@ -127,17 +126,17 @@ Wiki configuration for testing: $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"); + 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"); + 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: @@ -181,7 +180,7 @@ TODO: // ///////////////////////// COMMAND LINE HELP //////////////////////////////////// // This is a command line script, load MediaWiki env (gives command line options); -require_once( __DIR__ . '/commandLine.inc' ); +require_once __DIR__ . '/commandLine.inc'; // if the user asked for an explanation of command line options. if ( isset( $options["help"] ) ) { @@ -657,6 +656,7 @@ class wikiFuzz { "}}", "{{INT:googlesearch|", "}}", + "{{ROOTPAGENAME}}", "{{BASEPAGENAME}}", "{{CONTENTLANGUAGE}}", "{{PAGESINNAMESPACE:}}", @@ -747,7 +747,7 @@ class wikiFuzz { /** ** Randomly returns one element of the input array. */ - static public function chooseInput( array $input ) { + public static function chooseInput( array $input ) { $randindex = wikiFuzz::randnum( count( $input ) - 1 ); return $input[$randindex]; } @@ -761,7 +761,7 @@ class wikiFuzz { * @param $start int * @return int */ - static public function randnum( $finish, $start = 0 ) { + public static function randnum( $finish, $start = 0 ) { return mt_rand( $start, $finish ); } @@ -769,7 +769,7 @@ class wikiFuzz { * Returns a mix of random text and random wiki syntax. * @return string */ - static private function randstring() { + private static function randstring() { $thestring = ""; for ( $i = 0; $i < 40; $i++ ) { @@ -801,7 +801,7 @@ class wikiFuzz { * or random data from "other". * @return string */ - static private function makestring() { + private static function makestring() { $what = wikiFuzz::randnum( 2 ); if ( $what == 0 ) { return wikiFuzz::randstring(); @@ -818,7 +818,7 @@ class wikiFuzz { * @param $matches * @return string */ - static private function stringEscape( $matches ) { + private static function stringEscape( $matches ) { return sprintf( "\\x%02x", ord( $matches[1] ) ); } @@ -828,7 +828,7 @@ class wikiFuzz { * @param $str string * @return string */ - static public function makeTitleSafe( $str ) { + public static function makeTitleSafe( $str ) { $legalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF"; return preg_replace_callback( "/([^$legalTitleChars])/", 'wikiFuzz::stringEscape', @@ -839,7 +839,7 @@ class wikiFuzz { ** Returns a string of fuzz text. * @return string */ - static private function loop() { + private static function loop() { switch ( wikiFuzz::randnum( 3 ) ) { case 1: // an opening tag, with parameters. $string = ""; @@ -868,7 +868,7 @@ class wikiFuzz { * Returns one of the three styles of random quote: ', ", and nothing. * @return string */ - static private function getRandQuote() { + private static function getRandQuote() { switch ( wikiFuzz::randnum( 3 ) ) { case 1 : return "'"; case 2 : return "\""; @@ -881,7 +881,7 @@ class wikiFuzz { * @param $maxtypes int * @return string */ - static public function makeFuzz( $maxtypes = 2 ) { + public static function makeFuzz( $maxtypes = 2 ) { $page = ""; for ( $k = 0; $k < $maxtypes; $k++ ) { $page .= wikiFuzz::loop(); @@ -1482,24 +1482,6 @@ class watchlistTest extends pageTest { } } - -/** - ** a page test for "Special:Blockme" - */ -class specialBlockmeTest extends pageTest { - function __construct() { - $this->pagePath = "index.php?title=Special:Blockme"; - - $this->params = array ( ); - - // sometimes we specify "ip", and sometimes we don't. - if ( wikiFuzz::randnum( 1 ) == 0 ) { - $this->params["ip"] = wikiFuzz::chooseInput( array( "10.12.41.213", wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) ); - } - } -} - - /** ** a page test for "Special:Movepage" */ @@ -1972,7 +1954,7 @@ class specialChemicalsourcesTest extends pageTest { ** 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). + ** @todo Incomplete / unfinished; Runs too fast (suggests not much testing going on). */ class api extends pageTest { @@ -2041,7 +2023,7 @@ class api extends pageTest { } // Adds all the elements to the array, using the specified prefix. - private static function addListParams( &$array, $prefix, $elements ) { + private static function addListParams( &$array, $prefix, $elements ) { foreach ( $elements as $element ) { $array[$prefix . $element] = self::getParamDetails( $element ); } @@ -2160,7 +2142,7 @@ class GeSHi_Test extends pageTest { /** ** 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|\specialBlockmeTest|\specialBooksourcesTest|\specialCategoryTree|\specialChemicalsourcesTest|\specialCitePageTest|\specialExportTest|\specialFilepathPageTest|\specialImportPageTest|\specialLinksearch|\specialLockdbPageTest|\specialLogTest|\specialMovePage|\specialNewpagesPageTest|\specialRenameuserPageTest|\specialRevisionDeletePageTest|\specialUndeletePageTest|\specialUnlockdbPageTest|\specialUserrights|\successfulUserLoginTest|\thumbTest|\userLoginTest|\viewPageTest|\watchlistTest + * @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 ) { @@ -2196,7 +2178,6 @@ function selectPageTest( $count ) { case 20: return new redirectTest(); case 21: return new confirmEmail(); case 22: return new watchlistTest(); - case 23: return new specialBlockmeTest(); case 24: return new specialUndeletePageTest(); case 25: return new specialMovePage(); case 26: return new specialUnlockdbPageTest(); @@ -2542,7 +2523,7 @@ function runWikiTest( pageTest $test, &$testname, $can_overwrite = false ) { 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-XHTML output. + // 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; } @@ -2709,5 +2690,3 @@ for ( $count = 0; true; $count++ ) { break; } } - - diff --git a/maintenance/generateSitemap.php b/maintenance/generateSitemap.php index f3a5d875..0b21a1fe 100644 --- a/maintenance/generateSitemap.php +++ b/maintenance/generateSitemap.php @@ -26,7 +26,7 @@ * @see http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that generates a sitemap for the site. @@ -44,7 +44,7 @@ class GenerateSitemap extends Maintenance { * * @var int */ - var $url_limit; + public $url_limit; /** * The maximum size of a sitemap file @@ -53,77 +53,77 @@ class GenerateSitemap extends Maintenance { * * @var int */ - var $size_limit; + public $size_limit; /** * The path to prepend to the filename * * @var string */ - var $fspath; + public $fspath; /** * The URL path to prepend to filenames in the index; should resolve to the same directory as $fspath * * @var string */ - var $urlpath; + public $urlpath; /** * Whether or not to use compression * * @var bool */ - var $compress; + public $compress; /** * Whether or not to include redirection pages * * @var bool */ - var $skipRedirects; + public $skipRedirects; /** * The number of entries to save in each sitemap file * * @var array */ - var $limit = array(); + public $limit = array(); /** * Key => value entries of namespaces and their priorities * * @var array */ - var $priorities = array(); + public $priorities = array(); /** * A one-dimensional array of namespaces in the wiki * * @var array */ - var $namespaces = array(); + public $namespaces = array(); /** * When this sitemap batch was generated * * @var string */ - var $timestamp; + public $timestamp; /** * A database slave object * * @var object */ - var $dbr; + public $dbr; /** * A resource pointing to the sitemap index file * * @var resource */ - var $findex; + public $findex; /** @@ -131,7 +131,7 @@ class GenerateSitemap extends Maintenance { * * @var resource */ - var $file; + public $file; /** * Identifier to use in filenames, default $wgDBname @@ -167,7 +167,7 @@ class GenerateSitemap extends Maintenance { } $this->identifier = $this->getOption( 'identifier', wfWikiID() ); $this->compress = $this->getOption( 'compress', 'yes' ) !== 'no'; - $this->skipRedirects = $this->getOption( 'skip-redirects', false ) !== false ; + $this->skipRedirects = $this->getOption( 'skip-redirects', false ) !== false; $this->dbr = wfGetDB( DB_SLAVE ); $this->generateNamespaces(); $this->timestamp = wfTimestamp( TS_ISO_8601, wfTimestampNow() ); @@ -231,7 +231,7 @@ class GenerateSitemap extends Maintenance { wfMkdirParents( $fspath, null, __METHOD__ ) or die( "Can not create directory $fspath.\n" ); } - return realpath( $fspath ) . DIRECTORY_SEPARATOR ; + return realpath( $fspath ) . DIRECTORY_SEPARATOR; } /** @@ -255,8 +255,9 @@ class GenerateSitemap extends Maintenance { ) ); - foreach ( $res as $row ) + foreach ( $res as $row ) { $this->namespaces[] = $row->page_namespace; + } } /** @@ -319,7 +320,7 @@ class GenerateSitemap extends Maintenance { $this->output( "$namespace ($fns)\n" ); $skippedRedirects = 0; // Number of redirects skipped for that namespace foreach ( $res as $row ) { - if ($this->skipRedirects && $row->page_is_redirect ) { + if ( $this->skipRedirects && $row->page_is_redirect ) { $skippedRedirects++; continue; } @@ -346,7 +347,9 @@ class GenerateSitemap extends Maintenance { if ( $wgContLang->hasVariants() ) { $variants = $wgContLang->getVariants(); foreach ( $variants as $vCode ) { - if ( $vCode == $wgContLang->getCode() ) continue; // we don't want default variant + if ( $vCode == $wgContLang->getCode() ) { + continue; // we don't want default variant + } $entry = $this->fileEntry( $title->getCanonicalURL( '', $vCode ), $date, $this->priority( $namespace ) ); $length += strlen( $entry ); $this->write( $this->file, $entry ); @@ -354,7 +357,7 @@ class GenerateSitemap extends Maintenance { } } - if ($this->skipRedirects && $skippedRedirects > 0) { + if ( $this->skipRedirects && $skippedRedirects > 0 ) { $this->output( " skipped $skippedRedirects redirect(s)\n" ); } @@ -374,8 +377,8 @@ class GenerateSitemap extends Maintenance { */ function open( $file, $flags ) { $resource = $this->compress ? gzopen( $file, $flags ) : fopen( $file, $flags ); - if( $resource === false ) { - wfDebugDieBacktrace( __METHOD__ . " error opening file $file with flags $flags. Check permissions?" ); + if ( $resource === false ) { + throw new MWException( __METHOD__ . " error opening file $file with flags $flags. Check permissions?" ); } return $resource; } @@ -384,23 +387,25 @@ class GenerateSitemap extends Maintenance { * gzwrite() / fwrite() wrapper */ function write( &$handle, $str ) { - if( $handle === true || $handle === false ) { - wfDebugDieBacktrace( __METHOD__ . " was passed a boolean as a file handle.\n" ); + if ( $handle === true || $handle === false ) { + throw new MWException( __METHOD__ . " was passed a boolean as a file handle.\n" ); } - if ( $this->compress ) + if ( $this->compress ) { gzwrite( $handle, $str ); - else + } else { fwrite( $handle, $str ); + } } /** * gzclose() / fclose() wrapper */ function close( &$handle ) { - if ( $this->compress ) + if ( $this->compress ) { gzclose( $handle ); - else + } else { fclose( $handle ); + } } /** @@ -485,7 +490,8 @@ class GenerateSitemap extends Maintenance { function fileEntry( $url, $date, $priority ) { return "\t<url>\n" . - "\t\t<loc>$url</loc>\n" . + // bug 34666: $url may contain bad characters such as ampersands. + "\t\t<loc>" . htmlspecialchars( $url ) . "</loc>\n" . "\t\t<lastmod>$date</lastmod>\n" . "\t\t<priority>$priority</priority>\n" . "\t</url>\n"; @@ -516,4 +522,4 @@ class GenerateSitemap extends Maintenance { } $maintClass = "GenerateSitemap"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/getConfiguration.php b/maintenance/getConfiguration.php new file mode 100644 index 00000000..5a5eb587 --- /dev/null +++ b/maintenance/getConfiguration.php @@ -0,0 +1,194 @@ +<?php +/** + * Print serialized output of MediaWiki config vars. + * + * 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 Tim Starling + * @author Antoine Musso <hashar@free.fr> + */ + +require_once __DIR__ . '/Maintenance.php'; + +/** + * Print serialized output of MediaWiki config vars + * + * @ingroup Maintenance + */ +class GetConfiguration extends Maintenance { + + protected $regex = null; + + protected $settings_list = array(); + + /** + * List of format output internally supported. + * Each item MUST be lower case. + */ + protected static $outFormats = array( + 'json', + 'php', + 'serialize', + 'vardump', + ); + + public function __construct() { + parent::__construct(); + $this->mDescription = "Get serialized MediaWiki site configuration"; + $this->addOption( 'regex', 'regex to filter variables with', false, true ); + $this->addOption( 'iregex', 'same as --regex but case insensitive', false, true ); + $this->addOption( 'settings', 'Space-separated list of wg* variables', false, true ); + $this->addOption( 'format', join( ', ', self::$outFormats ), false, true ); + } + + protected function validateParamsAndArgs() { + $error_out = false; + + # Get the format and make sure it is set to a valid default value + $format = strtolower( $this->getOption( 'format', 'PHP' ) ); + + $validFormat = in_array( $format, self::$outFormats ); + if ( ! $validFormat ) { + $this->error( "--format set to an unrecognized format", 0 ); + $error_out = true; + } + + if ( $this->getOption( 'regex' ) && $this->getOption( 'iregex' ) ) { + $this->error( "Can only use either --regex or --iregex" ); + $error_out = true; + } + + parent::validateParamsAndArgs(); + + if ( $error_out ) { + # Force help and quit + $this->maybeHelp( true ); + } + } + + /** + * finalSetup() since we need MWException + */ + public function finalSetup() { + parent::finalSetup(); + + $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 + } + } + + if ( $this->hasOption( 'settings' ) ) { + $this->settings_list = explode( ' ', $this->getOption( 'settings' ) ); + # Values validation + foreach ( $this->settings_list as $name ) { + if ( !preg_match( '/^wg[A-Z]/', $name ) ) { + throw new MWException( "Variable '$name' does start with 'wg'." ); + } elseif ( !isset( $GLOBALS[$name] ) ) { + throw new MWException( "Variable '$name' is not set." ); + } elseif ( !$this->isAllowedVariable( $GLOBALS[$name] ) ) { + throw new MWException( "Variable '$name' includes non-array, non-scalar, items." ); + } + } + } + } + + public function execute() { + // Settings we will display + $res = array(); + + # Sane default: dump any wg / wmg variable + if ( ! $this->regex && ! $this->getOption( 'settings' ) ) { + $this->regex = '/^wm?g/'; + } + + # Filter out globals based on the regex + if ( $this->regex ) { + $res = array(); + foreach ( $GLOBALS as $name => $value ) { + if ( preg_match( $this->regex, $name ) ) { + $res[$name] = $value; + } + } + } + + # Explicitly dumps a list of provided global names + if ( $this->settings_list ) { + foreach ( $this->settings_list as $name ) { + $res[$name] = $GLOBALS[$name]; + } + } + + ksort( $res ); + + $out = null; + switch ( strtolower( $this->getOption( 'format' ) ) ) { + case 'serialize': + case 'php': + $out = serialize( $res ); + break; + case 'vardump': + $out = $this->formatVarDump( $res ); + break; + case 'json': + $out = FormatJson::encode( $res ); + break; + default: + throw new MWException( "Invalid serialization format given." ); + } + if ( !is_string( $out ) ) { + throw new MWException( "Failed to serialize the requested settings." ); + } + + if ( $out ) { + $this->output( $out . "\n" ); + } + } + + protected function formatVarDump( $res ) { + $ret = ''; + foreach ( $res as $key => $value ) { + ob_start(); # intercept var_dump() output + print "\${$key} = "; + var_dump( $value ); + # grab var_dump() output and discard it from the output buffer + $ret .= trim( ob_get_clean() ) . ";\n"; + } + + return trim( $ret, "\n" ); + } + + private function isAllowedVariable( $value ) { + if ( is_array( $value ) ) { + foreach ( $value as $k => $v ) { + if ( !$this->isAllowedVariable( $v ) ) { + return false; + } + } + return true; + } elseif ( is_scalar( $value ) ) { + return true; + } + return false; + } +} + +$maintClass = "GetConfiguration"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/getLagTimes.php b/maintenance/getLagTimes.php index 72b1d48a..7365a2ee 100644 --- a/maintenance/getLagTimes.php +++ b/maintenance/getLagTimes.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that displays replication lag times. @@ -39,7 +39,7 @@ class GetLagTimes extends Maintenance { if ( $lb->getServerCount() == 1 ) { $this->error( "This script dumps replication lag times, but you don't seem to have\n" - . "a multi-host db server configuration." ); + . "a multi-host db server configuration." ); } else { $lags = $lb->getLagTimes(); foreach ( $lags as $n => $lag ) { @@ -59,4 +59,4 @@ class GetLagTimes extends Maintenance { } $maintClass = "GetLagTimes"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/getSlaveServer.php b/maintenance/getSlaveServer.php index ec9ed20a..d618825f 100644 --- a/maintenance/getSlaveServer.php +++ b/maintenance/getSlaveServer.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that reports the hostname of a slave server. @@ -51,4 +51,4 @@ class GetSlaveServer extends Maintenance { } $maintClass = "GetSlaveServer"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/getText.php b/maintenance/getText.php index 3e2f8540..9c4bdfb8 100644 --- a/maintenance/getText.php +++ b/maintenance/getText.php @@ -23,7 +23,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that outputs page text to stdout. @@ -52,14 +52,14 @@ class GetTextMaint extends Maintenance { $titleText = $title->getPrefixedText(); $this->error( "Page $titleText does not exist.\n", true ); } - $text = $rev->getText( $this->hasOption( 'show-private' ) ? Revision::RAW : Revision::FOR_PUBLIC ); - if ( $text === false ) { + $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 ); } - $this->output( $text ); + $this->output( $content->serialize() ); } } $maintClass = "GetTextMaint"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/hiphop/compiler.conf b/maintenance/hiphop/compiler.conf deleted file mode 100644 index 3e01640d..00000000 --- a/maintenance/hiphop/compiler.conf +++ /dev/null @@ -1,5 +0,0 @@ -GenerateSourceInfo = true -EnableEval = 2 -AllDynamic = true -EnableHipHopSyntax = true -EnableHipHopExperimentalSyntax = true diff --git a/maintenance/hiphop/extra-files b/maintenance/hiphop/extra-files deleted file mode 100644 index f07f7c7c..00000000 --- a/maintenance/hiphop/extra-files +++ /dev/null @@ -1,34 +0,0 @@ -img_auth.php -includes/AutoLoader.php -includes/DefaultSettings.php -includes/Defines.php -includes/GlobalFunctions.php -includes/ImageFunctions.php -includes/OutputHandler.php -includes/ProxyTools.php -includes/SeleniumWebSettings.php -includes/Setup.php -includes/StreamFile.php -includes/WebStart.php -includes/filerepo/NullRepo.php -includes/normal/UtfNormalDefines.php -includes/normal/UtfNormalUtil.php -index.php -languages/Names.php -load.php -maintenance/Maintenance.php -maintenance/commandLine.inc -maintenance/doMaintenance.php -maintenance/eval.php -opensearch_desc.php -profileinfo.php -redirect.php -resources/Resources.php -serialized/serialize.php -skins/MonoBook.deps.php -skins/MonoBook.php -skins/Vector.deps.php -skins/Vector.php -thumb.php -trackback.php - diff --git a/maintenance/hiphop/make b/maintenance/hiphop/make deleted file mode 100644 index 2fa70dcb..00000000 --- a/maintenance/hiphop/make +++ /dev/null @@ -1,311 +0,0 @@ -#!/usr/bin/hphpi -f -<?php - -define( 'MW_CONFIG_CALLBACK', 'MakeHipHop::noConfigNeeded' ); -require( __DIR__ . '/../Maintenance.php' ); - -class MakeHipHop extends Maintenance { - function noConfigNeeded() {} - - function execute() { - global $wgHipHopBuildDirectory; - - $startTime = time(); - - $thisDir = realpath( __DIR__ ); - $IP = realpath( "$thisDir/../.." ); - if ( strval( $wgHipHopBuildDirectory ) !== '' ) { - $buildDir = $wgHipHopBuildDirectory; - } else { - $buildDir = "$thisDir/build"; - } - $extensionsDir = realpath( MWInit::getExtensionsDirectory() ); - $outDir = "$buildDir/hiphop-output"; - $persistentDir = "$buildDir/persistent"; - - if ( !is_dir( $buildDir ) ) { - mkdir( $buildDir, 0777, true ); - } - if ( !is_dir( $persistentDir ) ) { - mkdir( $persistentDir, 0777, true ); - } - - if ( realpath( "$IP/../phase3" ) !== $IP - || realpath( "$IP/../extensions" ) !== $extensionsDir ) - { - # Set up a fake source directory with the correct layout - $sourceBase = "$buildDir/source"; - $this->setupFakeSourceBase( $IP, $extensionsDir, $sourceBase ); - } else { - $sourceBase = realpath( "$IP/.." ); - unlink( "$buildDir/source" ); - } - - # With the CentOS RPMs, you just get g++44, no g++, so we have to - # use the environment - if ( isset( $_ENV['CXX'] ) ) { - $cxx = $_ENV['CXX']; - } else { - $cxx = 'g++'; - } - - # Create a function that provides the HipHop compiler version, and - # doesn't exist when MediaWiki is invoked in interpreter mode. - $version = str_replace( PHP_EOL, ' ', trim( `hphp --version` ) ); - file_put_contents( - "$buildDir/HipHopCompilerVersion.php", - "<" . "?php\n" . - "function wfHipHopCompilerVersion() {\n" . - "return " . var_export( $version, true ) . ";\n" . - "}\n" - ); - - # Generate the file list - $files = $this->getFileList(); - file_put_contents( - "$buildDir/file-list", - implode( "\n", $files ) . "\n" ); - - # Generate the C++ - passthru( - 'hphp' . - ' --target=cpp' . - ' --format=file' . - ' --input-dir=' . wfEscapeShellArg( $sourceBase ) . - ' --input-list=' . wfEscapeShellArg( "$buildDir/file-list" ) . - ' --inputs=' . wfEscapeShellArg( "$buildDir/HipHopCompilerVersion.php" ) . - ' -c ' . wfEscapeShellArg( "$thisDir/compiler.conf" ) . - ' --parse-on-demand=false' . - ' --program=mediawiki-hphp' . - ' --output-dir=' . wfEscapeShellArg( $outDir ) . - ' --log=3', $ret ); - - if ( $ret ) { - $this->error( "hphp hit an error. Stopping build.\n" ); - exit( 1 ); - } - - # Sanity check, quickly make sure we've got an output directory - if( !is_dir( $outDir ) ) { - $this->error( "No output directory", true ); - } - - # Warn about volatile classes - $this->checkVolatileClasses( $outDir ); - - # Copy the generated C++ files into the source directory for cmake - $iter = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( $outDir ), - RecursiveIteratorIterator::SELF_FIRST ); - $sourceFiles = array(); - $regenerateMakefile = false; - $numFiles = 0; - $numFilesChanged = 0; - foreach ( $iter as $sourcePath => $file ) { - $name = substr( $sourcePath, strlen( $outDir ) + 1 ); - $sourceFiles[$name] = true; - $destPath = "$persistentDir/$name"; - if ( $file->isDir() ) { - if ( !is_dir( $destPath ) ) { - mkdir( $destPath ); - } - continue; - } - - $numFiles++; - # Remove any files that weren't touched, these may have been removed - # from file-list, we should not compile them - if ( $file->getMTime() < $startTime ) { - if ( file_exists( $destPath ) ) { - unlink( $destPath ); - # Files removed, regenerate the makefile - $regenerateMakefile = true; - } - unlink( $sourcePath ); - $numFilesChanged++; - continue; - } - - if ( file_exists( $destPath ) ) { - $sourceHash = md5( file_get_contents( $sourcePath ) ); - $destHash = md5( file_get_contents( $destPath ) ); - if ( $sourceHash == $destHash ) { - continue; - } - } else { - # New files added, regenerate the makefile - $regenerateMakefile = true; - } - $numFilesChanged++; - copy( $sourcePath, $destPath ); - } - - echo "MediaWiki: $numFilesChanged files changed out of $numFiles\n"; - - if ( !file_exists( "$persistentDir/CMakeLists.txt" ) ) { - # Run cmake for the first time - $regenerateMakefile = true; - } - - # Do our own version of $HPHP_HOME/bin/run.sh, which isn't so broken. - # HipHop's RELEASE mode seems to be stuck always on, so symbols get - # stripped. Also we will try keeping the generated .o files instead of - # throwing away hours of CPU time every time you make a typo. - - chdir( $persistentDir ); - - if ( $regenerateMakefile ) { - copy( $_ENV['HPHP_HOME'] . '/bin/CMakeLists.base.txt', - "$persistentDir/CMakeLists.txt" ); - - if ( file_exists( "$persistentDir/CMakeCache.txt" ) ) { - unlink( "$persistentDir/CMakeCache.txt" ); - } - - $cmd = 'cmake' . - " -D CMAKE_BUILD_TYPE:string=" . wfEscapeShellArg( $GLOBALS['wgHipHopBuildType'] ) . - ' -D PROGRAM_NAME:string=mediawiki-hphp'; - - if ( file_exists( '/usr/bin/ccache' ) ) { - $cmd .= ' -D CMAKE_CXX_COMPILER:string=ccache' . - ' -D CMAKE_CXX_COMPILER_ARG1:string=' . wfEscapeShellArg( $cxx ); - } - - $cmd .= ' .'; - echo "$cmd\n"; - passthru( $cmd ); - } - - # Determine appropriate make concurrency - # Compilation can take a lot of memory, let's assume that that is limiting. - $procs = $this->getNumProcs(); - - # Run make. This is the slow step. - passthru( 'make -j' . wfEscapeShellArg( $procs ) ); - - $elapsed = time() - $startTime; - - echo "Completed in "; - if ( $elapsed >= 3600 ) { - $hours = floor( $elapsed / 3600 ); - echo $hours . 'h '; - $elapsed -= $hours * 3600; - } - if ( $elapsed >= 60 ) { - $minutes = floor( $elapsed / 60 ); - echo $minutes . 'm '; - $elapsed -= $minutes * 60; - } - echo $elapsed . "s\n"; - echo "The MediaWiki executable is at $buildDir/persistent/mediawiki-hphp\n"; - } - - function checkVolatileClasses( $dir ) { - $lines = file( "$dir/sys/dynamic_table_class.cpp" ); - $classes = array(); - foreach ( $lines as $line ) { - if ( preg_match( '/^\s+\(const char \*\)"([^"]*)", \(const char \*\)-1/', $line, $m ) ) { - $classes[] = $m[1]; - } - } - if ( !count( $classes ) ) { - print "No volatile classes found\n"; - return; - } - sort( $classes ); - $classes = array_unique( $classes ); - print "WARNING: The following classes are volatile: " . implode( ', ', $classes ) . "\n"; - } - - function getNumProcs() { - global $wgHipHopCompilerProcs; - if ( $wgHipHopCompilerProcs !== 'detect' ) { - return intval( $wgHipHopCompilerProcs ); - } - - if ( !file_exists( '/proc/meminfo' ) ) { - return 1; - } - $mem = false; - foreach ( file( '/proc/meminfo' ) as $line ) { - if ( preg_match( '/^MemTotal:\s+(\d+)\s+kB/', $line, $m ) ) { - $mem = intval( $m[1] ); - break; - } - } - if ( $mem ) { - // At least one process - return max( 1, floor( $mem / 1000000 ) ); - } else { - return 1; - } - } - - function setupFakeSourceBase( $phase3, $extensions, $dest ) { - if ( !file_exists( $dest ) ) { - mkdir( $dest, 0777, true ); - } - - $this->forceCreateLink( "$dest/phase3", $phase3 ); - $this->forceCreateLink( "$dest/extensions", $extensions ); - } - - function forceCreateLink( $target, $link ) { - if ( file_exists( $target ) ) { - if ( readlink( $target ) === $link ) { - return; - } - unlink( $target ); - } - symlink( $target, $link ); - } - - function getFileList() { - global $wgAutoloadClasses, $wgAutoloadLocalClasses, $wgCompiledFiles; - $inputFiles = array_merge( - array_values( $wgAutoloadClasses ), - array_values( $wgAutoloadLocalClasses ), - $wgCompiledFiles - ); - $processedFiles = array(); - foreach ( $inputFiles as $file ) { - if ( substr( $file, 0, 1 ) === '/' ) { - $processedFiles[] = $this->absoluteToRelative( $file ); - } elseif ( preg_match( '/^extensions/', $file ) ) { - $processedFiles[] = $file; - } else { - $processedFiles[] = "phase3/$file"; - } - } - - $extraCoreFiles = array_map( 'trim', file( __DIR__ . '/extra-files' ) ); - foreach ( $extraCoreFiles as $file ) { - if ( $file === '' ) { - continue; - } - $processedFiles[] = "phase3/$file"; - } - return array_unique( $processedFiles ); - } - - function absoluteToRelative( $file ) { - global $IP; - - $coreBase = realpath( $IP ) . '/'; - $extBase = realpath( MWInit::getExtensionsDirectory() ) . '/'; - $file = realpath( $file ); - - if ( substr( $file, 0, strlen( $extBase ) ) === $extBase ) { - return 'extensions/' . substr( $file, strlen( $extBase ) ); - } elseif ( substr( $file, 0, strlen( $coreBase ) ) === $coreBase ) { - return 'phase3/' . substr( $file, strlen( $coreBase ) ); - } else { - $this->error( "The following file is registered for compilation but is not in \$IP or " . - "\$wgExtensionsDirectory: $file \n" ); - exit( 1 ); - } - } -} - -$maintClass = 'MakeHipHop'; -require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/hiphop/run-server b/maintenance/hiphop/run-server index 1c4b51f4..2d71b871 100644 --- a/maintenance/hiphop/run-server +++ b/maintenance/hiphop/run-server @@ -1,68 +1,21 @@ -#!/usr/bin/hphpi -f +#!/usr/bin/hhvm -f <?php -require( __DIR__ . '/../Maintenance.php' ); +require __DIR__ . '/../Maintenance.php'; class RunHipHopServer extends Maintenance { function __construct() { parent::__construct(); - $this->addOption( 'interpret', 'Run in interpreted mode' ); } function execute() { - if ( $this->hasOption( 'interpret' ) ) { - $this->runInterpreted(); - } else { - $this->runCompiled(); - } - } - - function runCompiled() { - global $wgHipHopBuildDirectory; - $thisDir = realpath( __DIR__ ); - $IP = realpath( "$thisDir/../.." ); - if ( strval( $wgHipHopBuildDirectory ) !== '' ) { - $buildDir = $wgHipHopBuildDirectory; - } else { - $buildDir = "$thisDir/build"; - } - - if ( file_exists( "$buildDir/source" ) ) { - $sourceBase = "$buildDir/source"; - } else { - $sourceBase = realpath( "$IP/.." ); - } - - passthru( - 'cd ' . wfEscapeShellArg( $sourceBase ) . " && " . - 'MW_INSTALL_PATH=' . wfEscapeShellArg( $IP ) . ' ' . - wfEscapeShellArg( - "$buildDir/persistent/mediawiki-hphp", - '-c', "$thisDir/server.conf", - '-v', "Server.SourceRoot=$sourceBase", - '-v', "Server.IncludeSearchPaths.0=$sourceBase", - '-v', 'ServerVariables.MW_COMPILED=1', - '--mode=server', - '--port=8080' - ), - $ret - ); - exit( $ret ); - } - - function runInterpreted() { - $thisDir = realpath( __DIR__ ); - $IP = realpath( "$thisDir/../.." ); - $sourceBase = realpath( "$IP/.." ); + global $IP; passthru( - 'cd ' . wfEscapeShellArg( $sourceBase ) . " && " . - 'MW_INSTALL_PATH=' . wfEscapeShellArg( $IP ) . ' ' . + 'cd ' . wfEscapeShellArg( $IP ) . " && " . wfEscapeShellArg( - 'hphpi', - '-c', "$thisDir/server.conf", - '-v', "Server.SourceRoot=$sourceBase", - '-v', "Server.IncludeSearchPaths.0=$sourceBase", + 'hhvm', + '-c', __DIR__."/server.conf", '--mode=server', '--port=8080' ), @@ -72,4 +25,4 @@ class RunHipHopServer extends Maintenance { } } $maintClass = 'RunHipHopServer'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/hiphop/server.conf b/maintenance/hiphop/server.conf index 16af0f2f..558bdad8 100644 --- a/maintenance/hiphop/server.conf +++ b/maintenance/hiphop/server.conf @@ -12,7 +12,7 @@ Debug { } Server { EnableStaticContentCache = false - EnableStaticContentFromDisk = false + EnableStaticContentFromDisk = true AlwaysUseRelativePath = true } VirtualHost { @@ -22,7 +22,7 @@ VirtualHost { RewriteRules { * { pattern = ^/wiki/(.*)$ - to = /phase3/index.php?title=$1 + to = /index.php?title=$1 qsa = true } } diff --git a/maintenance/ibm_db2/foreignkeys.sql b/maintenance/ibm_db2/foreignkeys.sql deleted file mode 100644 index 4f1450d9..00000000 --- a/maintenance/ibm_db2/foreignkeys.sql +++ /dev/null @@ -1,102 +0,0 @@ --- good -ALTER TABLE user_groups ADD CONSTRAINT USER_GROUPS_FK1 FOREIGN KEY (ug_user) REFERENCES user(user_id) ON DELETE CASCADE -; - --- good -ALTER TABLE user_newtalk ADD CONSTRAINT USER_NEWTALK_FK1 FOREIGN KEY (user_id) REFERENCES user(user_id) ON DELETE CASCADE -; - --- referenced value not found -ALTER TABLE revision ADD CONSTRAINT REVISION_PAGE_FK FOREIGN KEY (rev_page) REFERENCES page(page_id) ON DELETE CASCADE -; --- referenced value not found -ALTER TABLE revision ADD CONSTRAINT REVISION_USER_FK FOREIGN KEY (rev_user) REFERENCES user(user_id) ON DELETE RESTRICT -; - --- good -ALTER TABLE page_restrictions ADD CONSTRAINT PAGE_RESTRICTIONS_PAGE_FK FOREIGN KEY (pr_page) REFERENCES page(page_id) ON DELETE CASCADE -; - --- good -ALTER TABLE page_props ADD CONSTRAINT PAGE_PROPS_PAGE_FK FOREIGN KEY (pp_page) REFERENCES page(page_id) ON DELETE CASCADE -; - --- cannot contain null values --- ALTER TABLE archive ADD CONSTRAINT ARCHIVE_USER_FK FOREIGN KEY (ar_user) REFERENCES user(user_id) ON DELETE SET NULL ---; - --- referenced value not found -ALTER TABLE redirect ADD CONSTRAINT REDIRECT_FROM_FK FOREIGN KEY (rd_from) REFERENCES page(page_id) ON DELETE CASCADE -; - --- referenced value not found -ALTER TABLE pagelinks ADD CONSTRAINT PAGELINKS_FROM_FK FOREIGN KEY (pl_from) REFERENCES page(page_id) ON DELETE CASCADE -; - --- good -ALTER TABLE templatelinks ADD CONSTRAINT TEMPLATELINKS_FROM_FK FOREIGN KEY (tl_from) REFERENCES page(page_id) ON DELETE CASCADE -; - --- good -ALTER TABLE imagelinks ADD CONSTRAINT IMAGELINKS_FROM_FK FOREIGN KEY (il_from) REFERENCES page(page_id) ON DELETE CASCADE -; - --- good -ALTER TABLE categorylinks ADD CONSTRAINT CATEGORYLINKS_FROM_FK FOREIGN KEY (cl_from) REFERENCES page(page_id) ON DELETE CASCADE -; - --- good -ALTER TABLE externallinks ADD CONSTRAINT EXTERNALLINKS_FROM_FK FOREIGN KEY (el_from) REFERENCES page(page_id) ON DELETE CASCADE -; - --- good -ALTER TABLE langlinks ADD CONSTRAINT LANGLINKS_FROM_FK FOREIGN KEY (ll_from) REFERENCES page(page_id) ON DELETE CASCADE -; - --- cannot contain null values --- ALTER TABLE ipblocks ADD CONSTRAINT IPBLOCKS_USER_FK FOREIGN KEY (ipb_user) REFERENCES user(user_id) ON DELETE SET NULL ---; - --- good -ALTER TABLE ipblocks ADD CONSTRAINT IPBLOCKS_BY_FK FOREIGN KEY (ipb_by) REFERENCES user(user_id) ON DELETE CASCADE -; - --- cannot contain null values --- ALTER TABLE image ADD CONSTRAINT IMAGE_USER_FK FOREIGN KEY (img_user) REFERENCES user(user_id) ON DELETE SET NULL ---; - --- cannot contain null values --- ALTER TABLE oldimage ADD CONSTRAINT OLDIMAGE_USER_FK FOREIGN KEY (oi_user) REFERENCES user(user_id) ON DELETE SET NULL ---; - --- good -ALTER TABLE oldimage ADD CONSTRAINT OLDIMAGE_NAME_FK FOREIGN KEY (oi_name) REFERENCES image(img_name) ON DELETE CASCADE -; - --- cannot contain null values --- ALTER TABLE filearchive ADD CONSTRAINT FILEARCHIVE_DELETED_USER_FK FOREIGN KEY (fa_deleted_user) REFERENCES user(user_id) ON DELETE SET NULL ---; - --- cannot contain null values --- ALTER TABLE filearchive ADD CONSTRAINT FILEARCHIVE_USER_FK FOREIGN KEY (fa_user) REFERENCES user(user_id) ON DELETE SET NULL ---; - --- cannot contain null values --- ALTER TABLE recentchanges ADD CONSTRAINT RECENTCHANGES_USER_FK FOREIGN KEY (rc_user) REFERENCES user(user_id) ON DELETE SET NULL ---; - --- cannot contain null values --- ALTER TABLE recentchanges ADD CONSTRAINT RECENTCHANGES_CUR_ID_FK FOREIGN KEY (rc_cur_id) REFERENCES page(page_id) ON DELETE SET NULL ---; - --- good -ALTER TABLE watchlist ADD CONSTRAINT WATCHLIST_USER_FK FOREIGN KEY (wl_user) REFERENCES user(user_id) ON DELETE CASCADE -; - --- cannot contain null values --- ALTER TABLE protected_titles ADD CONSTRAINT PROTECTED_TITLES_USER_FK FOREIGN KEY (pt_user) REFERENCES user(user_id) ON DELETE SET NULL ---; - --- cannot contain null values --- ALTER TABLE logging ADD CONSTRAINT LOGGING_USER_FK FOREIGN KEY (log_user) REFERENCES user(user_id) ON DELETE SET NULL ---;
\ No newline at end of file diff --git a/maintenance/ibm_db2/patch-categorylinks-better-collation.sql b/maintenance/ibm_db2/patch-categorylinks-better-collation.sql deleted file mode 100644 index 312583ac..00000000 --- a/maintenance/ibm_db2/patch-categorylinks-better-collation.sql +++ /dev/null @@ -1,21 +0,0 @@ --- --- patch-categorylinks-better-collation.sql --- --- --- Track category inclusions *used inline* --- This tracks a single level of category membership --- (folksonomic tagging, really). --- -CREATE TABLE categorylinks ( - cl_from BIGINT NOT NULL DEFAULT 0, - -- REFERENCES page(page_id) ON DELETE CASCADE, - cl_to VARCHAR(255) NOT NULL, - -- cl_sortkey has to be at least 86 wide - -- in order to be compatible with the old MySQL schema from MW 1.10 - --cl_sortkey VARCHAR(86), - cl_sortkey VARCHAR(230) FOR BIT DATA NOT NULL , - cl_sortkey_prefix VARCHAR(255) FOR BIT DATA NOT NULL , - cl_timestamp TIMESTAMP(3) NOT NULL, - cl_collation VARCHAR(32) FOR BIT DATA NOT NULL , - cl_type VARCHAR(6) FOR BIT DATA NOT NULL -); diff --git a/maintenance/ibm_db2/patch-change_tag-indexes.sql b/maintenance/ibm_db2/patch-change_tag-indexes.sql deleted file mode 100644 index 1621a038..00000000 --- a/maintenance/ibm_db2/patch-change_tag-indexes.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE UNIQUE INDEX change_tag_rc_tag ON change_tag (ct_rc_id,ct_tag); -CREATE UNIQUE INDEX change_tag_log_tag ON change_tag (ct_log_id,ct_tag); -CREATE UNIQUE INDEX 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 change_tag_tag_id ON change_tag (ct_tag,ct_rc_id,ct_rev_id,ct_log_id); diff --git a/maintenance/ibm_db2/patch-change_tag.sql b/maintenance/ibm_db2/patch-change_tag.sql deleted file mode 100644 index 3b6f9d54..00000000 --- a/maintenance/ibm_db2/patch-change_tag.sql +++ /dev/null @@ -1,8 +0,0 @@ --- A table to track tags for revisions, logs and recent changes. -CREATE TABLE change_tag ( - ct_rc_id INTEGER, - ct_log_id INTEGER, - ct_rev_id INTEGER, - ct_tag varchar(255) NOT NULL, - ct_params CLOB(64K) INLINE LENGTH 4096 -); diff --git a/maintenance/ibm_db2/patch-change_tag_summary.sql b/maintenance/ibm_db2/patch-change_tag_summary.sql deleted file mode 100644 index 768cbfaa..00000000 --- a/maintenance/ibm_db2/patch-change_tag_summary.sql +++ /dev/null @@ -1,7 +0,0 @@ --- Rollup table to pull a LIST of tags simply -CREATE TABLE tag_summary ( - ts_rc_id INTEGER, - ts_log_id INTEGER, - ts_rev_id INTEGER, - ts_tags CLOB(64K) INLINE LENGTH 4096 NOT NULL -); diff --git a/maintenance/ibm_db2/patch-change_valid_tag.sql b/maintenance/ibm_db2/patch-change_valid_tag.sql deleted file mode 100644 index 9bdcbc92..00000000 --- a/maintenance/ibm_db2/patch-change_valid_tag.sql +++ /dev/null @@ -1,3 +0,0 @@ -CREATE TABLE valid_tag ( - vt_tag varchar(255) NOT NULL PRIMARY KEY -); diff --git a/maintenance/ibm_db2/patch-cl_collation-field.sql b/maintenance/ibm_db2/patch-cl_collation-field.sql deleted file mode 100644 index 6999dace..00000000 --- a/maintenance/ibm_db2/patch-cl_collation-field.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE categorylinks ADD cl_collation VARCHAR(32) FOR BIT DATA NOT NULL diff --git a/maintenance/ibm_db2/patch-cl_sortkey_prefix-field.sql b/maintenance/ibm_db2/patch-cl_sortkey_prefix-field.sql deleted file mode 100644 index 58b78147..00000000 --- a/maintenance/ibm_db2/patch-cl_sortkey_prefix-field.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE categorylinks ADD cl_sortkey_prefix VARCHAR(255) FOR BIT DATA NOT NULL diff --git a/maintenance/ibm_db2/patch-cl_type-field.sql b/maintenance/ibm_db2/patch-cl_type-field.sql deleted file mode 100644 index 5952c989..00000000 --- a/maintenance/ibm_db2/patch-cl_type-field.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE categorylinks ADD cl_type VARCHAR(6) FOR BIT DATA NOT NULL diff --git a/maintenance/ibm_db2/patch-external_user.sql b/maintenance/ibm_db2/patch-external_user.sql deleted file mode 100644 index 96cb8237..00000000 --- a/maintenance/ibm_db2/patch-external_user.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE external_user ( - -- Foreign key to user_id - eu_local_id BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - - -- Some opaque identifier provided by the external database - eu_external_id VARCHAR(255) NOT NULL -); diff --git a/maintenance/ibm_db2/patch-ipb_allow_usertalk.sql b/maintenance/ibm_db2/patch-ipb_allow_usertalk.sql deleted file mode 100644 index 6274bb22..00000000 --- a/maintenance/ibm_db2/patch-ipb_allow_usertalk.sql +++ /dev/null @@ -1,23 +0,0 @@ -CREATE TABLE ipblocks ( - ipb_id INTEGER NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - --DEFAULT nextval('ipblocks_ipb_id_val'), - ipb_address VARCHAR(1024), - ipb_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE SET NULL, - ipb_by BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE CASCADE, - ipb_by_text VARCHAR(255) NOT NULL DEFAULT '', - ipb_reason VARCHAR(1024) NOT NULL, - ipb_timestamp TIMESTAMP(3) NOT NULL, - ipb_auto SMALLINT NOT NULL DEFAULT 0, - ipb_anon_only SMALLINT NOT NULL DEFAULT 0, - ipb_create_account SMALLINT NOT NULL DEFAULT 1, - ipb_enable_autoblock SMALLINT NOT NULL DEFAULT 1, - ipb_expiry TIMESTAMP(3) NOT NULL, - ipb_range_start VARCHAR(1024), - ipb_range_end VARCHAR(1024), - ipb_deleted SMALLINT NOT NULL DEFAULT 0, - ipb_block_email SMALLINT NOT NULL DEFAULT 0, - ipb_allow_usertalk SMALLINT NOT NULL DEFAULT 0 - -); diff --git a/maintenance/ibm_db2/patch-iw_api-field.sql b/maintenance/ibm_db2/patch-iw_api-field.sql deleted file mode 100644 index dd732a58..00000000 --- a/maintenance/ibm_db2/patch-iw_api-field.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE interwiki ADD iw_api CLOB(64K) INLINE LENGTH 4096 NOT NULL diff --git a/maintenance/ibm_db2/patch-iw_api_and_wikiid.sql b/maintenance/ibm_db2/patch-iw_api_and_wikiid.sql deleted file mode 100644 index 1b1e3592..00000000 --- a/maintenance/ibm_db2/patch-iw_api_and_wikiid.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE interwiki ( - iw_prefix VARCHAR(32) NOT NULL UNIQUE, - iw_url CLOB(64K) INLINE LENGTH 4096 NOT NULL, - iw_api CLOB(64K) INLINE LENGTH 4096 NOT NULL, - iw_wikiid varchar(64) NOT NULL, - iw_local SMALLINT NOT NULL, - iw_trans SMALLINT NOT NULL DEFAULT 0 -); diff --git a/maintenance/ibm_db2/patch-iw_wikiid-field.sql b/maintenance/ibm_db2/patch-iw_wikiid-field.sql deleted file mode 100644 index fe49e3c0..00000000 --- a/maintenance/ibm_db2/patch-iw_wikiid-field.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE interwiki ADD iw_wikiid varchar(64) NOT NULL diff --git a/maintenance/ibm_db2/patch-iwlinks.sql b/maintenance/ibm_db2/patch-iwlinks.sql deleted file mode 100644 index 2902512f..00000000 --- a/maintenance/ibm_db2/patch-iwlinks.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE "IWLINKS" -( -"IWL_FROM" INT NOT NULL , -"IWL_PREFIX" VARCHAR(20) FOR BIT DATA NOT NULL , -"IWL_TITLE" VARCHAR(255) FOR BIT DATA NOT NULL -) -; diff --git a/maintenance/ibm_db2/patch-l10n_cache.sql b/maintenance/ibm_db2/patch-l10n_cache.sql deleted file mode 100644 index 49ebed2b..00000000 --- a/maintenance/ibm_db2/patch-l10n_cache.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE l10n_cache ( - -- Language code - lc_lang VARCHAR(32) NOT NULL, - -- Cache key - lc_key VARCHAR(255) NOT NULL, - -- Value - lc_value CLOB(16M) INLINE LENGTH 4096 NOT NULL -); diff --git a/maintenance/ibm_db2/patch-log_search-rename-index.sql b/maintenance/ibm_db2/patch-log_search-rename-index.sql deleted file mode 100644 index a6a696e1..00000000 --- a/maintenance/ibm_db2/patch-log_search-rename-index.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE log_search ( - -- The type of ID (rev ID, log ID, rev TIMESTAMP(3), username) - ls_field VARCHAR(32) FOR BIT DATA NOT NULL, - -- The value of the ID - ls_value varchar(255) NOT NULL, - -- Key to log_id - ls_log_id BIGINT NOT NULL default 0 -); diff --git a/maintenance/ibm_db2/patch-log_search.sql b/maintenance/ibm_db2/patch-log_search.sql deleted file mode 100644 index a6a696e1..00000000 --- a/maintenance/ibm_db2/patch-log_search.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE log_search ( - -- The type of ID (rev ID, log ID, rev TIMESTAMP(3), username) - ls_field VARCHAR(32) FOR BIT DATA NOT NULL, - -- The value of the ID - ls_value varchar(255) NOT NULL, - -- Key to log_id - ls_log_id BIGINT NOT NULL default 0 -); diff --git a/maintenance/ibm_db2/patch-log_user_text.sql b/maintenance/ibm_db2/patch-log_user_text.sql deleted file mode 100644 index 3534057a..00000000 --- a/maintenance/ibm_db2/patch-log_user_text.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TABLE logging ( - log_id BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - --PRIMARY KEY DEFAULT nextval('log_log_id_seq'), - log_type VARCHAR(32) NOT NULL, - log_action VARCHAR(32) NOT NULL, - log_timestamp TIMESTAMP(3) NOT NULL, - log_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE SET NULL, - -- Name of the user who performed this action - log_user_text VARCHAR(255) NOT NULL default '', - log_namespace SMALLINT NOT NULL, - log_title VARCHAR(255) NOT NULL, - log_page BIGINT, - log_comment VARCHAR(255), - log_params CLOB(64K) INLINE LENGTH 4096, - log_deleted SMALLINT NOT NULL DEFAULT 0 -); diff --git a/maintenance/ibm_db2/patch-module_deps.sql b/maintenance/ibm_db2/patch-module_deps.sql deleted file mode 100644 index 5058d1f5..00000000 --- a/maintenance/ibm_db2/patch-module_deps.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE "MODULE_DEPS" ( -"MD_MODULE" VARCHAR(255) FOR BIT DATA NOT NULL , -"MD_SKIN" VARCHAR(32) FOR BIT DATA NOT NULL , -"MD_DEPS" CLOB(16M) INLINE LENGTH 4096 NOT NULL -) -; diff --git a/maintenance/ibm_db2/patch-msg_resource.sql b/maintenance/ibm_db2/patch-msg_resource.sql deleted file mode 100644 index 58b3dd6c..00000000 --- a/maintenance/ibm_db2/patch-msg_resource.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE "MSG_RESOURCE" -( -"MR_RESOURCE" VARCHAR(255) FOR BIT DATA NOT NULL , -"MR_LANG" VARCHAR(32) FOR BIT DATA NOT NULL , -"MR_BLOB" BLOB NOT NULL , -"MR_TIMESTAMP" TIMESTAMP(3) NOT NULL -) -; diff --git a/maintenance/ibm_db2/patch-msg_resource_links.sql b/maintenance/ibm_db2/patch-msg_resource_links.sql deleted file mode 100644 index 4c0ff918..00000000 --- a/maintenance/ibm_db2/patch-msg_resource_links.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE "MSG_RESOURCE_LINKS" -( -"MRL_RESOURCE" VARCHAR(255) FOR BIT DATA NOT NULL , -"MRL_MESSAGE" VARCHAR(255) FOR BIT DATA NOT NULL -) -; diff --git a/maintenance/ibm_db2/patch-rd_interwiki.sql b/maintenance/ibm_db2/patch-rd_interwiki.sql deleted file mode 100644 index c162548c..00000000 --- a/maintenance/ibm_db2/patch-rd_interwiki.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE redirect ( - rd_from BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - --REFERENCES page(page_id) ON DELETE CASCADE, - rd_namespace SMALLINT NOT NULL DEFAULT 0, - rd_title VARCHAR(255) NOT NULL DEFAULT '', - rd_interwiki varchar(32), - rd_fragment VARCHAR(255) -); diff --git a/maintenance/ibm_db2/patch-ss_active_users.sql b/maintenance/ibm_db2/patch-ss_active_users.sql deleted file mode 100644 index f0e6d145..00000000 --- a/maintenance/ibm_db2/patch-ss_active_users.sql +++ /dev/null @@ -1,11 +0,0 @@ -CREATE TABLE site_stats ( - ss_row_id BIGINT NOT NULL UNIQUE, - ss_total_views BIGINT DEFAULT 0, - ss_total_edits BIGINT DEFAULT 0, - ss_good_articles BIGINT DEFAULT 0, - ss_total_pages INTEGER DEFAULT -1, - ss_users INTEGER DEFAULT -1, - ss_active_users INTEGER DEFAULT -1, - ss_admins INTEGER DEFAULT -1, - ss_images INTEGER DEFAULT 0 -); diff --git a/maintenance/ibm_db2/patch-ul_value.sql b/maintenance/ibm_db2/patch-ul_value.sql deleted file mode 100644 index cd00f8e0..00000000 --- a/maintenance/ibm_db2/patch-ul_value.sql +++ /dev/null @@ -1,3 +0,0 @@ -CREATE TABLE updatelog ( - ul_key VARCHAR(255) NOT NULL PRIMARY KEY -); diff --git a/maintenance/ibm_db2/patch-uq61_msg_resource_links.sql b/maintenance/ibm_db2/patch-uq61_msg_resource_links.sql deleted file mode 100644 index d9185c0a..00000000 --- a/maintenance/ibm_db2/patch-uq61_msg_resource_links.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE UNIQUE INDEX "UQ61_MSG_RESOURCE_LINKS" ON "MSG_RESOURCE_LINKS" -( -"MRL_MESSAGE", -"MRL_RESOURCE" -) -ALLOW REVERSE SCANS -; diff --git a/maintenance/ibm_db2/patch-uq81_msg_resource.sql b/maintenance/ibm_db2/patch-uq81_msg_resource.sql deleted file mode 100644 index 8ed85379..00000000 --- a/maintenance/ibm_db2/patch-uq81_msg_resource.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE UNIQUE INDEX "UQ81_MSG_RESOURCE" ON "MSG_RESOURCE" -( -"MR_RESOURCE" -,"MR_LANG" -) -ALLOW REVERSE SCANS -; diff --git a/maintenance/ibm_db2/patch-uq96_module_deps.sql b/maintenance/ibm_db2/patch-uq96_module_deps.sql deleted file mode 100644 index e0cc879a..00000000 --- a/maintenance/ibm_db2/patch-uq96_module_deps.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE UNIQUE INDEX "UQ96_MODULE_DEPS" ON "MODULE_DEPS" -( -"MD_MODULE" -,"MD_SKIN" -) -ALLOW REVERSE SCANS -; diff --git a/maintenance/ibm_db2/patch-user_properties.sql b/maintenance/ibm_db2/patch-user_properties.sql deleted file mode 100644 index 72dcd792..00000000 --- a/maintenance/ibm_db2/patch-user_properties.sql +++ /dev/null @@ -1,10 +0,0 @@ -CREATE TABLE user_properties ( - -- Foreign key to user.user_id - up_user BIGINT NOT NULL, - - -- Name of the option being saved. This is indexed for bulk lookup. - up_property VARCHAR(32) FOR BIT DATA NOT NULL, - - -- Property value as a string. - up_value CLOB(64K) INLINE LENGTH 4096 -); diff --git a/maintenance/ibm_db2/tables.sql b/maintenance/ibm_db2/tables.sql deleted file mode 100644 index caad9251..00000000 --- a/maintenance/ibm_db2/tables.sql +++ /dev/null @@ -1,930 +0,0 @@ --- IBM DB2 - --- SQL to create the initial tables for the MediaWiki database. --- This is read and executed by the install script; you should --- not have to run it by itself unless doing a manual install. - --- Notes: --- * DB2 will convert all table and column names to all caps internally. --- * DB2 has a 32k limit on SQL filesize, so it may be necessary --- to split this into two files soon. - - -CREATE TABLE user ( - -- Needs to start with 0 - user_id BIGINT - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 0), - user_name VARCHAR(255) NOT NULL UNIQUE, - user_real_name VARCHAR(255), - user_password VARCHAR(1024), - user_newpassword VARCHAR(1024), - user_newpass_time TIMESTAMP(3), - user_token VARCHAR(255), - user_email VARCHAR(1024), - user_email_token VARCHAR(255), - user_email_token_expires TIMESTAMP(3), - user_email_authenticated TIMESTAMP(3), - -- obsolete, replace by user_properties table - -- user_options CLOB(64K) INLINE LENGTH 4096, - user_touched TIMESTAMP(3), - user_registration TIMESTAMP(3), - user_editcount INTEGER -); -CREATE INDEX user_email_token_idx - ON user (user_email_token); -CREATE UNIQUE INDEX user_include_idx - ON user (user_id) - INCLUDE (user_name, user_real_name, user_password, user_newpassword, - user_newpass_time, user_token, - user_email, user_email_token, user_email_token_expires, - user_email_authenticated, - user_touched, user_registration, user_editcount); -CREATE UNIQUE INDEX user_email - ON user (user_email); - - - --- Create a dummy user to satisfy fk contraints especially with revisions -INSERT INTO user( - user_name, user_real_name, user_password, user_newpassword, user_newpass_time, - user_email, user_email_authenticated, user_token, user_registration, user_editcount -) -VALUES ( - 'Anonymous', '', NULL, NULL, CURRENT_TIMESTAMP, - NULL, NULL, NULL, CURRENT_TIMESTAMP, 0 -); - - - -CREATE TABLE user_groups ( - ug_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE CASCADE, - ug_group VARCHAR(255) NOT NULL -); -CREATE INDEX user_groups_unique - ON user_groups (ug_user, ug_group); - - - -CREATE TABLE user_newtalk ( - -- registered users key - user_id BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE CASCADE, - -- anonymous users key - user_ip VARCHAR(40), - user_last_timestamp TIMESTAMP(3) -); -CREATE INDEX user_newtalk_id_idx - ON user_newtalk (user_id); -CREATE INDEX user_newtalk_ip_idx - ON user_newtalk (user_ip); -CREATE UNIQUE INDEX user_newtalk_include_idx - ON user_newtalk (user_id, user_ip) - INCLUDE (user_last_timestamp); - - - -CREATE TABLE page ( - page_id BIGINT - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - page_namespace SMALLINT NOT NULL, - page_title VARCHAR(255) NOT NULL, - page_restrictions VARCHAR(1024), - page_counter BIGINT NOT NULL DEFAULT 0, - page_is_redirect SMALLINT NOT NULL DEFAULT 0, - page_is_new SMALLINT NOT NULL DEFAULT 0, - page_random NUMERIC(15,14) NOT NULL, - page_touched TIMESTAMP(3), - page_latest BIGINT NOT NULL, -- FK? - page_len BIGINT NOT NULL -); -CREATE UNIQUE INDEX page_unique_name - ON page (page_namespace, page_title); -CREATE INDEX page_random_idx - ON page (page_random); -CREATE INDEX page_len_idx - ON page (page_len); -CREATE UNIQUE INDEX page_id_include - ON page (page_id) - INCLUDE (page_namespace, page_title, page_restrictions, page_counter, page_is_redirect, page_is_new, page_random, page_touched, page_latest, page_len); -CREATE UNIQUE INDEX page_name_include - ON page (page_namespace, page_title) - INCLUDE (page_id, page_restrictions, page_counter, page_is_redirect, page_is_new, page_random, page_touched, page_latest, page_len); - - - -CREATE TABLE revision ( - rev_id BIGINT - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - rev_page BIGINT NOT NULL DEFAULT 0, - -- REFERENCES page (page_id) ON DELETE CASCADE, - rev_text_id BIGINT, -- FK - rev_comment VARCHAR(1024), - rev_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE RESTRICT, - rev_user_text VARCHAR(255) NOT NULL, - rev_timestamp TIMESTAMP(3) NOT NULL, - rev_minor_edit SMALLINT NOT NULL DEFAULT 0, - rev_deleted SMALLINT NOT NULL DEFAULT 0, - rev_len BIGINT, - rev_parent_id BIGINT DEFAULT NULL, - rev_sha1 VARCHAR(255) NOT NULL DEFAULT '' -); -CREATE UNIQUE INDEX revision_unique - ON revision (rev_page, rev_id); -CREATE INDEX rev_text_id_idx - ON revision (rev_text_id); -CREATE INDEX rev_timestamp_idx - ON revision (rev_timestamp); -CREATE INDEX rev_user_idx - ON revision (rev_user); -CREATE INDEX rev_user_text_idx - ON revision (rev_user_text); - - - -CREATE TABLE text ( -- replaces reserved word 'text' - old_id INTEGER - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - old_text CLOB(16M) INLINE LENGTH 4096, - old_flags VARCHAR(1024) -); - - - -CREATE TABLE page_restrictions ( - pr_id BIGINT - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - pr_page INTEGER NOT NULL DEFAULT 0, - --(used to be nullable) - -- REFERENCES page (page_id) ON DELETE CASCADE, - pr_type VARCHAR(60) NOT NULL, - pr_level VARCHAR(60) NOT NULL, - pr_cascade SMALLINT NOT NULL, - pr_user INTEGER, - pr_expiry TIMESTAMP(3) - --PRIMARY KEY (pr_page, pr_type) -); ---ALTER TABLE page_restrictions ADD CONSTRAINT page_restrictions_pk PRIMARY KEY (pr_page, pr_type); -CREATE UNIQUE INDEX pr_pagetype - ON page_restrictions (pr_page, pr_type); -CREATE INDEX pr_typelevel - ON page_restrictions (pr_type, pr_level); -CREATE INDEX pr_level - ON page_restrictions (pr_level); -CREATE INDEX pr_cascade - ON page_restrictions (pr_cascade); - - - -CREATE TABLE page_props ( - pp_page INTEGER NOT NULL DEFAULT 0, - -- REFERENCES page (page_id) ON DELETE CASCADE, - pp_propname VARCHAR(255) NOT NULL, - pp_value CLOB(64K) INLINE LENGTH 4096 NOT NULL, - PRIMARY KEY (pp_page, pp_propname) -); -CREATE INDEX page_props_propname - ON page_props (pp_propname); - - - -CREATE TABLE archive ( - ar_namespace SMALLINT NOT NULL, - ar_title VARCHAR(255) NOT NULL, - ar_text CLOB(16M) INLINE LENGTH 4096, - ar_comment VARCHAR(1024), - ar_user BIGINT NOT NULL, - -- no foreign keys in MySQL - -- REFERENCES user(user_id) ON DELETE SET NULL, - ar_user_text VARCHAR(255) NOT NULL, - ar_timestamp TIMESTAMP(3) NOT NULL, - ar_minor_edit SMALLINT NOT NULL DEFAULT 0, - ar_flags VARCHAR(1024), - ar_rev_id INTEGER, - ar_text_id INTEGER, - ar_deleted SMALLINT NOT NULL DEFAULT 0, - ar_len INTEGER, - ar_page_id INTEGER, - ar_parent_id INTEGER, - ar_sha1 VARCHAR(255) NOT NULL DEFAULT '' -); -CREATE INDEX archive_name_title_timestamp - ON archive (ar_namespace, ar_title, ar_timestamp); -CREATE INDEX archive_user_text - ON archive (ar_user_text); - - - -CREATE TABLE redirect ( - rd_from BIGINT NOT NULL - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - --REFERENCES page(page_id) ON DELETE CASCADE, - rd_namespace SMALLINT NOT NULL DEFAULT 0, - rd_title VARCHAR(255) NOT NULL DEFAULT '', - rd_interwiki VARCHAR(32), - rd_fragment VARCHAR(255) -); -CREATE INDEX redirect_ns_title - ON redirect (rd_namespace, rd_title, rd_from); - - -CREATE TABLE pagelinks ( - pl_from BIGINT NOT NULL DEFAULT 0, - -- REFERENCES page(page_id) ON DELETE CASCADE, - pl_namespace SMALLINT NOT NULL, - pl_title VARCHAR(255) NOT NULL -); -CREATE UNIQUE INDEX pagelink_unique - ON pagelinks (pl_from, pl_namespace, pl_title); - - - -CREATE TABLE templatelinks ( - tl_from BIGINT NOT NULL DEFAULT 0, - -- REFERENCES page(page_id) ON DELETE CASCADE, - tl_namespace SMALLINT NOT NULL, - tl_title VARCHAR(255) NOT NULL -); -CREATE UNIQUE INDEX templatelinks_unique - ON templatelinks (tl_namespace, tl_title, tl_from); -CREATE UNIQUE INDEX tl_from_idx - ON templatelinks (tl_from, tl_namespace, tl_title); - - - -CREATE TABLE imagelinks ( - il_from BIGINT NOT NULL DEFAULT 0, - -- REFERENCES page(page_id) ON DELETE CASCADE, - il_to VARCHAR(255) NOT NULL -); -CREATE UNIQUE INDEX il_from_idx - ON imagelinks (il_to, il_from); -CREATE UNIQUE INDEX il_to_idx - ON imagelinks (il_from, il_to); - - - -CREATE TABLE categorylinks ( - cl_from BIGINT NOT NULL DEFAULT 0, - -- REFERENCES page(page_id) ON DELETE CASCADE, - cl_to VARCHAR(255) NOT NULL, - -- cl_sortkey has to be at least 86 wide - -- in order to be compatible with the old MySQL schema from MW 1.10 - --cl_sortkey VARCHAR(86), - cl_sortkey VARCHAR(230) FOR BIT DATA NOT NULL, - cl_sortkey_prefix VARCHAR(255) FOR BIT DATA NOT NULL, - cl_timestamp TIMESTAMP(3) NOT NULL, - cl_collation VARCHAR(32) FOR BIT DATA NOT NULL, - cl_type VARCHAR(6) FOR BIT DATA NOT NULL -); -CREATE UNIQUE INDEX cl_from - ON categorylinks (cl_from, cl_to); -CREATE INDEX cl_sortkey - ON categorylinks (cl_to, cl_sortkey, cl_from); - - - -CREATE TABLE externallinks ( - el_from BIGINT NOT NULL DEFAULT 0, - -- REFERENCES page(page_id) ON DELETE CASCADE, - el_to VARCHAR(1024) NOT NULL, - el_index VARCHAR(1024) NOT NULL -); -CREATE INDEX externallinks_from_to - ON externallinks (el_from, el_to); -CREATE INDEX externallinks_index - ON externallinks (el_index); - - - --- --- Track external user accounts, if ExternalAuth is used --- -CREATE TABLE external_user ( - -- Foreign key to user_id - eu_local_id BIGINT NOT NULL - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - - -- Some opaque identifier provided by the external database - eu_external_id VARCHAR(255) NOT NULL -); -CREATE UNIQUE INDEX eu_external_id_idx - ON external_user (eu_external_id) - INCLUDE (eu_local_id); -CREATE UNIQUE INDEX eu_local_id_idx - ON external_user (eu_local_id) - INCLUDE (eu_external_id); - - - -CREATE TABLE langlinks ( - ll_from BIGINT NOT NULL DEFAULT 0, - -- REFERENCES page (page_id) ON DELETE CASCADE, - ll_lang VARCHAR(20), - ll_title VARCHAR(255) -); -CREATE UNIQUE INDEX langlinks_unique - ON langlinks (ll_from, ll_lang); -CREATE INDEX langlinks_lang_title - ON langlinks (ll_lang, ll_title); - - - -CREATE TABLE site_stats ( - ss_row_id BIGINT NOT NULL UNIQUE, - ss_total_views BIGINT DEFAULT 0, - ss_total_edits BIGINT DEFAULT 0, - ss_good_articles BIGINT DEFAULT 0, - ss_total_pages INTEGER DEFAULT -1, - ss_users INTEGER DEFAULT -1, - ss_active_users INTEGER DEFAULT -1, - ss_admins INTEGER DEFAULT -1, - ss_images INTEGER DEFAULT 0 -); - - - -CREATE TABLE hitcounter ( - hc_id BIGINT NOT NULL -); - - - -CREATE TABLE ipblocks ( - ipb_id INTEGER NOT NULL - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - ipb_address VARCHAR(1024), - ipb_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE SET NULL, - ipb_by BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE CASCADE, - ipb_by_text VARCHAR(255) NOT NULL DEFAULT '', - ipb_reason VARCHAR(1024) NOT NULL, - ipb_timestamp TIMESTAMP(3) NOT NULL, - ipb_auto SMALLINT NOT NULL DEFAULT 0, - ipb_anon_only SMALLINT NOT NULL DEFAULT 0, - ipb_create_account SMALLINT NOT NULL DEFAULT 1, - ipb_enable_autoblock SMALLINT NOT NULL DEFAULT 1, - ipb_expiry TIMESTAMP(3) NOT NULL, - ipb_range_start VARCHAR(1024), - ipb_range_end VARCHAR(1024), - ipb_deleted SMALLINT NOT NULL DEFAULT 0, - ipb_block_email SMALLINT NOT NULL DEFAULT 0, - ipb_allow_usertalk SMALLINT NOT NULL DEFAULT 0, - ipb_parent_block_id INTEGER DEFAULT NULL - -- REFERENCES ipblocks(ipb_id) ON DELETE SET NULL - -); -CREATE INDEX ipb_address - ON ipblocks (ipb_address); -CREATE INDEX ipb_user - ON ipblocks (ipb_user); -CREATE INDEX ipb_range - ON ipblocks (ipb_range_start, ipb_range_end); - - - -CREATE TABLE image ( - img_name VARCHAR(255) NOT NULL - PRIMARY KEY, - img_size BIGINT NOT NULL, - img_width INTEGER NOT NULL, - img_height INTEGER NOT NULL, - img_metadata CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '', - img_bits SMALLINT, - img_media_type VARCHAR(255), - img_major_mime VARCHAR(255) DEFAULT 'unknown', - img_minor_mime VARCHAR(32) DEFAULT 'unknown', - img_description VARCHAR(1024) NOT NULL DEFAULT '', - img_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE SET NULL, - img_user_text VARCHAR(255) NOT NULL DEFAULT '', - img_timestamp TIMESTAMP(3), - img_sha1 VARCHAR(255) NOT NULL DEFAULT '' -); -CREATE INDEX img_size_idx - ON image (img_size); -CREATE INDEX img_timestamp_idx - ON image (img_timestamp); -CREATE INDEX img_sha1 - ON image (img_sha1); - - -CREATE TABLE oldimage ( - oi_name VARCHAR(255) NOT NULL DEFAULT '', - oi_archive_name VARCHAR(255) NOT NULL, - oi_size BIGINT NOT NULL, - oi_width INTEGER NOT NULL, - oi_height INTEGER NOT NULL, - oi_bits SMALLINT NOT NULL, - oi_description VARCHAR(1024), - oi_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE SET NULL, - oi_user_text VARCHAR(255) NOT NULL, - oi_timestamp TIMESTAMP(3) NOT NULL, - oi_metadata CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '', - oi_media_type VARCHAR(255), - oi_major_mime VARCHAR(255) NOT NULL DEFAULT 'unknown', - oi_minor_mime VARCHAR(255) NOT NULL DEFAULT 'unknown', - oi_deleted SMALLINT NOT NULL DEFAULT 0, - oi_sha1 VARCHAR(255) NOT NULL DEFAULT '' - --FOREIGN KEY (oi_name) REFERENCES image(img_name) ON DELETE CASCADE -); -CREATE INDEX oi_name_timestamp - ON oldimage (oi_name, oi_timestamp); -CREATE INDEX oi_name_archive_name - ON oldimage (oi_name, oi_archive_name); -CREATE INDEX oi_sha1 - ON oldimage (oi_sha1); - - - -CREATE TABLE filearchive ( - fa_id INTEGER NOT NULL - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - fa_name VARCHAR(255) NOT NULL, - fa_archive_name VARCHAR(255), - fa_storage_group VARCHAR(255), - fa_storage_key VARCHAR(64) DEFAULT '', - fa_deleted_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE SET NULL, - fa_deleted_timestamp TIMESTAMP(3) NOT NULL, - fa_deleted_reason VARCHAR(255), - fa_size BIGINT NOT NULL, - fa_width INTEGER NOT NULL, - fa_height INTEGER NOT NULL, - fa_metadata CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '', - fa_bits SMALLINT, - fa_media_type VARCHAR(255), - fa_major_mime VARCHAR(255) DEFAULT 'unknown', - fa_minor_mime VARCHAR(255) DEFAULT 'unknown', - fa_description VARCHAR(1024) NOT NULL, - fa_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE SET NULL, - fa_user_text VARCHAR(255) NOT NULL, - fa_timestamp TIMESTAMP(3), - fa_deleted SMALLINT NOT NULL DEFAULT 0 -); -CREATE INDEX fa_name_time - ON filearchive (fa_name, fa_timestamp); -CREATE INDEX fa_dupe - ON filearchive (fa_storage_group, fa_storage_key); -CREATE INDEX fa_notime - ON filearchive (fa_deleted_timestamp); -CREATE INDEX fa_nouser - ON filearchive (fa_deleted_user); - - - -CREATE TABLE recentchanges ( - rc_id INTEGER NOT NULL - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - rc_timestamp TIMESTAMP(3) NOT NULL, - rc_cur_time TIMESTAMP(3) NOT NULL, - rc_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE SET NULL, - rc_user_text VARCHAR(255) NOT NULL, - rc_namespace SMALLINT NOT NULL, - rc_title VARCHAR(255) NOT NULL, - rc_comment VARCHAR(255), - rc_minor SMALLINT NOT NULL DEFAULT 0, - rc_bot SMALLINT NOT NULL DEFAULT 0, - rc_new SMALLINT NOT NULL DEFAULT 0, - rc_cur_id BIGINT NOT NULL DEFAULT 0, - -- REFERENCES page(page_id) ON DELETE SET NULL, - rc_this_oldid BIGINT NOT NULL, - rc_last_oldid BIGINT NOT NULL, - rc_type SMALLINT NOT NULL DEFAULT 0, - rc_moved_to_ns SMALLINT, - rc_moved_to_title VARCHAR(255), - rc_patrolled SMALLINT NOT NULL DEFAULT 0, - rc_ip VARCHAR(40), -- was CIDR type - rc_old_len INTEGER, - rc_new_len INTEGER, - rc_deleted SMALLINT NOT NULL DEFAULT 0, - rc_logid BIGINT NOT NULL DEFAULT 0, - rc_log_type VARCHAR(255), - rc_log_action VARCHAR(255), - rc_params CLOB(64K) INLINE LENGTH 4096 - -); -CREATE INDEX rc_timestamp - ON recentchanges (rc_timestamp); -CREATE INDEX rc_namespace_title - ON recentchanges (rc_namespace, rc_title); -CREATE INDEX rc_cur_id - ON recentchanges (rc_cur_id); -CREATE INDEX new_name_timestamp - ON recentchanges (rc_new, rc_namespace, rc_timestamp); -CREATE INDEX rc_ip - ON recentchanges (rc_ip); - - - -CREATE TABLE watchlist ( - wl_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE CASCADE, - wl_namespace SMALLINT NOT NULL DEFAULT 0, - wl_title VARCHAR(255) NOT NULL, - wl_notificationtimestamp TIMESTAMP(3) -); -CREATE UNIQUE INDEX wl_user_namespace_title - ON watchlist (wl_namespace, wl_title, wl_user); - - - -CREATE TABLE interwiki ( - iw_prefix VARCHAR(32) NOT NULL UNIQUE, - iw_url CLOB(64K) INLINE LENGTH 4096 NOT NULL, - iw_api CLOB(64K) INLINE LENGTH 4096 NOT NULL, - iw_wikiid VARCHAR(64) NOT NULL, - iw_local SMALLINT NOT NULL, - iw_trans SMALLINT NOT NULL DEFAULT 0 -); - - - -CREATE TABLE querycache ( - qc_type VARCHAR(255) NOT NULL, - qc_value BIGINT NOT NULL, - qc_namespace INTEGER NOT NULL, - qc_title VARCHAR(255) NOT NULL -); -CREATE INDEX querycache_type_value - ON querycache (qc_type, qc_value); - - - -CREATE TABLE querycache_info ( - qci_type VARCHAR(255) UNIQUE NOT NULL, - qci_timestamp TIMESTAMP(3) -); - - - -CREATE TABLE querycachetwo ( - qcc_type VARCHAR(255) NOT NULL, - qcc_value BIGINT NOT NULL DEFAULT 0, - qcc_namespace INTEGER NOT NULL DEFAULT 0, - qcc_title VARCHAR(255) NOT NULL DEFAULT '', - qcc_namespacetwo INTEGER NOT NULL DEFAULT 0, - qcc_titletwo VARCHAR(255) NOT NULL DEFAULT '' -); -CREATE INDEX querycachetwo_type_value - ON querycachetwo (qcc_type, qcc_value); -CREATE INDEX querycachetwo_title - ON querycachetwo (qcc_type, qcc_namespace, qcc_title); -CREATE INDEX querycachetwo_titletwo - ON querycachetwo (qcc_type, qcc_namespacetwo, qcc_titletwo); - - - -CREATE TABLE objectcache ( - keyname VARCHAR(255) NOT NULL UNIQUE, -- was nullable - value CLOB(16M) INLINE LENGTH 4096 NOT NULL DEFAULT '', - exptime TIMESTAMP(3) NOT NULL -); -CREATE INDEX objectcacache_exptime - ON objectcache (exptime); - - - -CREATE TABLE transcache ( - tc_url VARCHAR(255) NOT NULL UNIQUE, - tc_contents CLOB(64K) INLINE LENGTH 4096 NOT NULL, - tc_time TIMESTAMP(3) NOT NULL -); - - - -CREATE TABLE logging ( - log_id BIGINT NOT NULL - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - log_type VARCHAR(32) NOT NULL, - log_action VARCHAR(32) NOT NULL, - log_timestamp TIMESTAMP(3) NOT NULL, - log_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE SET NULL, - -- Name of the user who performed this action - log_user_text VARCHAR(255) NOT NULL DEFAULT '', - log_namespace SMALLINT NOT NULL, - log_title VARCHAR(255) NOT NULL, - log_page BIGINT, - log_comment VARCHAR(255), - log_params CLOB(64K) INLINE LENGTH 4096, - log_deleted SMALLINT NOT NULL DEFAULT 0 -); -CREATE INDEX logging_type_name - ON logging (log_type, log_timestamp); -CREATE INDEX logging_user_time - ON logging (log_timestamp, log_user); -CREATE INDEX logging_page_time - ON logging (log_namespace, log_title, log_timestamp); -CREATE INDEX log_user_type_time - ON logging (log_user, log_type, log_timestamp); -CREATE INDEX log_page_id_time - ON logging (log_page, log_timestamp); -CREATE UNIQUE INDEX type_action - ON logging (log_type, log_action, log_timestamp); - - - -CREATE TABLE trackbacks ( - tb_id INTEGER NOT NULL - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - -- foreign key also in MySQL - tb_page INTEGER, - -- REFERENCES page(page_id) ON DELETE CASCADE, - tb_title VARCHAR(255) NOT NULL, - tb_url CLOB(64K) INLINE LENGTH 4096 NOT NULL, - tb_ex CLOB(64K) INLINE LENGTH 4096, - tb_name VARCHAR(255) -); -CREATE INDEX trackback_page - ON trackbacks (tb_page); - - - -CREATE TABLE job ( - job_id BIGINT NOT NULL - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - job_cmd VARCHAR(255) NOT NULL, - job_namespace SMALLINT NOT NULL, - job_title VARCHAR(255) NOT NULL, - job_params CLOB(64K) INLINE LENGTH 4096 NOT NULL -); -CREATE INDEX job_cmd_namespace_title - ON job (job_cmd, job_namespace, job_title); - - - ---TODO ---CREATE FUNCTION add_interwiki (TEXT, INT, SMALLINT) RETURNS INT LANGUAGE SQL AS ---$mw$ --- INSERT INTO interwiki (iw_prefix, iw_url, iw_local) VALUES ($1,$2,$3); --- SELECT 1; ---$mw$; - - - --- hack implementation --- should be replaced with OmniFind, Contains(), etc -CREATE TABLE searchindex ( - si_page BIGINT NOT NULL, - si_title VARCHAR(255) NOT NULL DEFAULT '', - si_text CLOB NOT NULL -); - - - --- 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_memory NUMERIC(18,10) NOT NULL DEFAULT 0, - pf_name VARCHAR(255) NOT NULL, - pf_server VARCHAR(255) -); -CREATE UNIQUE INDEX pf_name_server - ON profiling (pf_name, pf_server); - - - -CREATE TABLE protected_titles ( - pt_namespace INTEGER NOT NULL, - pt_title VARCHAR(255) NOT NULL, - pt_user BIGINT NOT NULL DEFAULT 0, - -- REFERENCES user(user_id) ON DELETE SET NULL, - pt_reason VARCHAR(1024), - pt_timestamp TIMESTAMP(3) NOT NULL, - pt_expiry TIMESTAMP(3), - pt_create_perm VARCHAR(60) NOT NULL DEFAULT '' -); -CREATE UNIQUE INDEX protected_titles_unique - ON protected_titles (pt_namespace, pt_title); - - - -CREATE TABLE updatelog ( - ul_key VARCHAR(255) NOT NULL - PRIMARY KEY -); - - - -CREATE TABLE category ( - cat_id INTEGER NOT NULL - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - cat_title VARCHAR(255) NOT NULL, - cat_pages INTEGER NOT NULL DEFAULT 0, - cat_subcats INTEGER NOT NULL DEFAULT 0, - cat_files INTEGER NOT NULL DEFAULT 0, - cat_hidden SMALLINT NOT NULL DEFAULT 0 -); -CREATE UNIQUE INDEX category_title - ON category (cat_title); -CREATE INDEX category_pages - ON category (cat_pages); - - - --- A table to track tags for revisions, logs and recent changes. -CREATE TABLE change_tag ( - ct_rc_id INTEGER, - ct_log_id INTEGER, - ct_rev_id INTEGER, - ct_tag VARCHAR(255) NOT NULL, - ct_params CLOB(64K) INLINE LENGTH 4096 -); -CREATE UNIQUE INDEX change_tag_rc_tag - ON change_tag (ct_rc_id, ct_tag); -CREATE UNIQUE INDEX change_tag_log_tag - ON change_tag (ct_log_id, ct_tag); -CREATE UNIQUE INDEX 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 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 -CREATE TABLE tag_summary ( - ts_rc_id INTEGER, - ts_log_id INTEGER, - ts_rev_id INTEGER, - ts_tags CLOB(64K) INLINE LENGTH 4096 NOT NULL -); -CREATE UNIQUE INDEX tag_summary_rc_id - ON tag_summary (ts_rc_id); -CREATE UNIQUE INDEX tag_summary_log_id - ON tag_summary (ts_log_id); -CREATE UNIQUE INDEX tag_summary_rev_id - ON tag_summary (ts_rev_id); - - - -CREATE TABLE valid_tag ( - vt_tag VARCHAR(255) NOT NULL - PRIMARY KEY -); - - - --- --- User preferences and perhaps other fun stuff. :) --- Replaces the old user.user_options blob, with a couple nice properties: --- --- 1) We only store non-default settings, so changes to the DEFAULTs --- are now reflected for everybody, not just new accounts. --- 2) We can more easily do bulk lookups, statistics, or modifications of --- saved options since it's a sane table structure. --- -CREATE TABLE user_properties ( - -- Foreign key to user.user_id - up_user BIGINT NOT NULL, - -- Name of the option being saved. This is indexed for bulk lookup. - up_property VARCHAR(255) FOR BIT DATA NOT NULL, - -- Property value as a string. - up_value CLOB(64K) INLINE LENGTH 4096 -); -CREATE UNIQUE INDEX user_properties_user_property - ON user_properties (up_user, up_property); -CREATE INDEX user_properties_property - ON user_properties (up_property); - -CREATE TABLE log_search ( - -- The type of ID (rev ID, log ID, rev TIMESTAMP(3), username) - ls_field VARCHAR(32) FOR BIT DATA NOT NULL, - -- The value of the ID - ls_value VARCHAR(255) NOT NULL, - -- Key to log_id - ls_log_id BIGINT NOT NULL DEFAULT 0 -); -CREATE UNIQUE INDEX ls_field_val - ON log_search (ls_field, ls_value, ls_log_id); -CREATE INDEX ls_log_id - ON log_search (ls_log_id); - - - --- Table for storing localisation data -CREATE TABLE l10n_cache ( - -- Language code - lc_lang VARCHAR(32) NOT NULL, - -- Cache key - lc_key VARCHAR(255) NOT NULL, - -- Value - lc_value CLOB(16M) INLINE LENGTH 4096 NOT NULL -); -CREATE INDEX lc_lang_key - ON l10n_cache (lc_lang, lc_key); - - - -CREATE TABLE msg_resource_links -( - mrl_resource VARCHAR(255) FOR BIT DATA NOT NULL, - mrl_message VARCHAR(255) FOR BIT DATA NOT NULL -); -CREATE UNIQUE INDEX uq61_msg_resource_links - ON msg_resource_links (mrl_message, mrl_resource); --- All DB2 indexes DEFAULT to allowing reverse scans - - - -CREATE TABLE msg_resource -( - mr_resource VARCHAR(255) FOR BIT DATA NOT NULL, - mr_lang VARCHAR(32) FOR BIT DATA NOT NULL, - mr_blob CLOB(64K) INLINE LENGTH 4096 NOT NULL, - mr_timestamp TIMESTAMP(3) NOT NULL -); -CREATE UNIQUE INDEX uq81_msg_resource - ON msg_resource (mr_resource, mr_lang); --- All DB2 indexes DEFAULT to allowing reverse scans - - - -CREATE TABLE module_deps ( - md_module VARCHAR(255) FOR BIT DATA NOT NULL, - md_skin VARCHAR(32) FOR BIT DATA NOT NULL, - md_deps CLOB(16M) INLINE LENGTH 4096 NOT NULL -); -CREATE UNIQUE INDEX uq96_module_deps - ON module_deps (md_module, md_skin); --- All DB2 indexes DEFAULT to allowing reverse scans - - - -CREATE TABLE iwlinks -( - iwl_from INTEGER NOT NULL, - iwl_prefix VARCHAR(20) FOR BIT DATA NOT NULL, - iwl_title VARCHAR(255) FOR BIT DATA NOT NULL -); - - - --- --- Store information about newly uploaded files before they're --- moved into the actual filestore --- -CREATE TABLE uploadstash ( - us_id BIGINT NOT NULL - PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 1), - -- the user who uploaded the file. - us_user BIGINT NOT NULL, - -- file key. this is how applications actually search for the file. - -- this might go away, or become the primary key. - us_key VARCHAR(255) NOT NULL, - -- the original path - us_orig_path VARCHAR(255) NOT NULL, - -- the temporary path at which the file is actually stored - us_path VARCHAR(255) NOT NULL, - -- which type of upload the file came from (sometimes) - us_source_type VARCHAR(50), - -- the date/time on which the file was added - us_timestamp TIMESTAMP(3) NOT NULL, - us_status VARCHAR(50) NOT NULL, - -- file properties from File::getPropsFromPath. these may prove unnecessary. - -- - us_size BIGINT NOT NULL, - -- this hash comes from File::sha1Base36(), and is 31 characters - us_sha1 VARCHAR(31) NOT NULL, - us_mime VARCHAR(255), - -- Media type as defined by the MEDIATYPE_xxx constants, should duplicate definition in the image table - us_media_type VARCHAR(30) - CONSTRAINT my_constraint - CHECK ( - us_media_type in ( - 'UNKNOWN', 'BITMAP', 'DRAWING', 'AUDIO', 'VIDEO', 'MULTIMEDIA', - 'OFFICE', 'TEXT', 'EXECUTABLE', 'ARCHIVE' - ) - ) DEFAULT NULL, - -- image-specific properties - us_image_width BIGINT, - us_image_height BIGINT, - us_image_bits INTEGER -); --- sometimes there's a delete for all of a user's stuff. -CREATE INDEX us_user - ON uploadstash (us_user); --- pick out files by key, enforce key UNIQUEness -CREATE UNIQUE INDEX us_key - ON uploadstash (us_key); --- the abandoned upload cleanup script needs this -CREATE INDEX us_timestamp - ON uploadstash (us_timestamp); - - - --- Stores the groups the user has once belonged to. --- The user may still belong these groups. Check user_groups. -CREATE TABLE user_former_groups ( - ufg_user BIGINT NOT NULL DEFAULT 0, - ufg_group VARCHAR(16) FOR BIT DATA NOT NULL -); -CREATE UNIQUE INDEX ufg_user_group - ON user_former_groups (ufg_user, ufg_group); diff --git a/maintenance/importDump.php b/maintenance/importDump.php index f51d7ad7..1f47cf12 100644 --- a/maintenance/importDump.php +++ b/maintenance/importDump.php @@ -24,7 +24,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that imports XML dump files into the current wiki. @@ -32,18 +32,18 @@ require_once( __DIR__ . '/Maintenance.php' ); * @ingroup Maintenance */ class BackupReader extends Maintenance { - var $reportingInterval = 100; - var $pageCount = 0; - var $revCount = 0; - var $dryRun = false; - var $uploads = false; - var $imageBasePath = false; - var $nsFilter = false; + public $reportingInterval = 100; + public $pageCount = 0; + public $revCount = 0; + public $dryRun = false; + public $uploads = false; + public $imageBasePath = false; + public $nsFilter = false; 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 @@ -73,7 +73,7 @@ TEXT; } public function execute() { - if( wfReadOnly() ) { + if ( wfReadOnly() ) { $this->error( "Wiki is in read-only mode; you'll need to disable it for import to work.", true ); } @@ -91,7 +91,7 @@ TEXT; $this->setNsfilter( explode( '|', $this->getOption( 'namespaces' ) ) ); } - if( $this->hasArg() ) { + if ( $this->hasArg() ) { $this->importFromFile( $this->getArg() ); } else { $this->importFromStdin(); @@ -247,7 +247,7 @@ TEXT; function importFromStdin() { $file = fopen( 'php://stdin', 'rt' ); - if( self::posix_isatty( $file ) ) { + if ( self::posix_isatty( $file ) ) { $this->maybeHelp( true ); } return $this->importFromHandle( $file ); @@ -259,14 +259,14 @@ TEXT; $source = new ImportStreamSource( $handle ); $importer = new WikiImporter( $source ); - if( $this->hasOption( 'debug' ) ) { + if ( $this->hasOption( 'debug' ) ) { $importer->setDebug( true ); } if ( $this->hasOption( 'no-updates' ) ) { $importer->setNoUpdates( true ); } $importer->setPageCallback( array( &$this, 'reportPage' ) ); - $this->importCallback = $importer->setRevisionCallback( + $this->importCallback = $importer->setRevisionCallback( array( &$this, 'handleRevision' ) ); $this->uploadCallback = $importer->setUploadCallback( array( &$this, 'handleUpload' ) ); @@ -288,4 +288,4 @@ TEXT; } $maintClass = 'BackupReader'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/importImages.inc b/maintenance/importImages.inc index ac5d1443..5ae6d6be 100644 --- a/maintenance/importImages.inc +++ b/maintenance/importImages.inc @@ -28,9 +28,10 @@ * * @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 */ -function findFiles( $dir, $exts ) { +function findFiles( $dir, $exts, $recurse = false ) { if ( is_dir( $dir ) ) { $dhl = opendir( $dir ); if ( $dhl ) { @@ -38,8 +39,11 @@ function findFiles( $dir, $exts ) { while ( ( $file = readdir( $dhl ) ) !== false ) { if ( is_file( $dir . '/' . $file ) ) { list( /* $name */, $ext ) = splitFilename( $dir . '/' . $file ); - if ( array_search( strtolower( $ext ), $exts ) !== false ) + if ( array_search( strtolower( $ext ), $exts ) !== false ) { $files[] = $dir . '/' . $file; + } + } elseif ( $recurse && is_dir( $dir . '/' . $file ) && $file !== '..' && $file !== '.' ) { + $files = array_merge( $files, findFiles( $dir . '/' . $file, $exts, true ) ); } } return $files; @@ -95,7 +99,9 @@ function findAuxFile( $file, $auxExtension, $maxStrip = 1 ) { } $idx = strrpos( $n, '.' ); - if ( !$idx ) break; + if ( !$idx ) { + break; + } $n = substr( $n, 0, $idx ); $maxStrip -= 1; diff --git a/maintenance/importImages.php b/maintenance/importImages.php index 8d92383d..54fd4e2d 100644 --- a/maintenance/importImages.php +++ b/maintenance/importImages.php @@ -31,12 +31,15 @@ * @author Mij <mij@bitchx.it> */ -$optionsWithArgs = array( 'extensions', 'comment', 'comment-file', 'comment-ext', 'user', 'license', 'sleep', 'limit', 'from', 'source-wiki-url' ); -require_once( __DIR__ . '/commandLine.inc' ); -require_once( __DIR__ . '/importImages.inc' ); +$optionsWithArgs = array( + 'extensions', 'comment', 'comment-file', 'comment-ext', 'summary', 'user', + 'license', 'sleep', 'limit', 'from', 'source-wiki-url', 'timestamp', +); +require_once __DIR__ . '/commandLine.inc'; +require_once __DIR__ . '/importImages.inc'; $processed = $added = $ignored = $skipped = $overwritten = $failed = 0; -echo( "Import Images\n\n" ); +echo "Import Images\n\n"; # Need a path if ( count( $args ) == 0 ) { @@ -61,7 +64,7 @@ $extensions = isset( $options['extensions'] ) : $wgFileExtensions; # Search the path provided for candidates for import -$files = findFiles( $dir, $extensions ); +$files = findFiles( $dir, $extensions, isset( $options['search-recursively'] ) ); # Initialise the user for this operation $user = isset( $options['user'] ) @@ -98,20 +101,24 @@ if ( $limit ) { $limit = (int)$limit; } +$timestamp = isset( $options['timestamp'] ) ? $options['timestamp'] : false; + # Get the upload comment. Provide a default one in case there's no comment given. -$comment = 'Importing image file'; +$comment = 'Importing file'; if ( isset( $options['comment-file'] ) ) { - $comment = file_get_contents( $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" ); } } elseif ( isset( $options['comment'] ) ) { - $comment = $options['comment']; + $comment = $options['comment']; } $commentExt = isset( $options['comment-ext'] ) ? $options['comment-ext'] : false; +$summary = isset( $options['summary'] ) ? $options['summary'] : ''; + # Get the license specifier $license = isset( $options['license'] ) ? $options['license'] : ''; @@ -125,7 +132,7 @@ if ( $count > 0 ) { # Validate a title $title = Title::makeTitleSafe( NS_FILE, $base ); if ( !is_object( $title ) ) { - echo( "{$base} could not be imported; a valid title cannot be produced\n" ); + echo "{$base} could not be imported; a valid title cannot be produced\n"; continue; } @@ -141,7 +148,7 @@ if ( $count > 0 ) { if ( $checkUserBlock && ( ( $processed % $checkUserBlock ) == 0 ) ) { $user->clearInstanceCache( 'name' ); // reload from DB! if ( $user->isBlocked() ) { - echo( $user->getName() . " was blocked! Aborting.\n" ); + echo $user->getName() . " was blocked! Aborting.\n"; break; } } @@ -150,10 +157,10 @@ if ( $count > 0 ) { $image = wfLocalFile( $title ); if ( $image->exists() ) { if ( isset( $options['overwrite'] ) ) { - echo( "{$base} exists, overwriting..." ); + echo "{$base} exists, overwriting..."; $svar = 'overwritten'; } else { - echo( "{$base} exists, skipping\n" ); + echo "{$base} exists, skipping\n"; $skipped++; continue; } @@ -165,23 +172,24 @@ if ( $count > 0 ) { $dupes = $repo->findBySha1( $sha1 ); if ( $dupes ) { - echo( "{$base} already exists as " . $dupes[0]->getName() . ", skipping\n" ); + echo "{$base} already exists as " . $dupes[0]->getName() . ", skipping\n"; $skipped++; continue; } } - echo( "Importing {$base}..." ); + echo "Importing {$base}..."; $svar = 'added'; } if ( isset( $options['source-wiki-url'] ) ) { /* find comment text directly from source wiki, through MW's API */ $real_comment = getFileCommentFromSourceWiki( $options['source-wiki-url'], $base ); - if ( $real_comment === false ) + if ( $real_comment === false ) { $commentText = $comment; - else + } else { $commentText = $real_comment; + } /* find user directly from source wiki, through MW's API */ $real_user = getFileUserFromSourceWiki( $options['source-wiki-url'], $base ); @@ -191,7 +199,7 @@ if ( $count > 0 ) { $wgUser = User::newFromName( $real_user ); if ( $wgUser === false ) { # user does not exist in target wiki - echo ( "failed: user '$real_user' does not exist in target wiki." ); + echo "failed: user '$real_user' does not exist in target wiki."; continue; } } @@ -202,11 +210,11 @@ 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 ) { - echo( " Failed to load comment file {$f}, using default comment. " ); + echo " Failed to load comment file {$f}, using default comment. "; } } } @@ -218,23 +226,37 @@ if ( $count > 0 ) { # Import the file if ( isset( $options['dry'] ) ) { - echo( " publishing {$file} by '" . $wgUser->getName() . "', comment '$commentText'... " ); + echo " publishing {$file} by '" . $wgUser->getName() . "', comment '$commentText'... "; } else { - $archive = $image->publish( $file ); + $props = FSFile::getPropsFromPath( $file ); + $flags = 0; + $publishOptions = array(); + $handler = MediaHandler::getHandler( $props['mime'] ); + if ( $handler ) { + $publishOptions['headers'] = $handler->getStreamHeaders( $props['metadata'] ); + } else { + $publishOptions['headers'] = array(); + } + $archive = $image->publish( $file, $flags, $publishOptions ); if ( !$archive->isGood() ) { - echo( "failed. (" . + echo "failed. (" . $archive->getWikiText() . - ")\n" ); + ")\n"; $failed++; continue; } } + $commentText = SpecialUpload::getInitialPageText( $commentText, $license ); + if ( !isset( $options['summary'] ) ) { + $summary = $commentText; + } + if ( isset( $options['dry'] ) ) { - echo( "done.\n" ); - } elseif ( $image->recordUpload( $archive->value, $commentText, $license ) ) { + echo "done.\n"; + } elseif ( $image->recordUpload2( $archive->value, $summary, $commentText, $props, $timestamp ) ) { # We're done! - echo( "done.\n" ); + echo "done.\n"; $doProtect = false; @@ -257,21 +279,21 @@ if ( $count > 0 ) { sleep( 2.0 ); # Why this sleep? wfWaitForSlaves(); - echo( "\nSetting image restrictions ... " ); + echo "\nSetting image restrictions ... "; $cascade = false; $restrictions = array(); - foreach( $title->getRestrictionTypes() as $type ) { + 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" ); + echo ( $status->isOK() ? 'done' : 'failed' ) . "\n"; } } else { - echo( "failed. (at recordUpload stage)\n" ); + echo "failed. (at recordUpload stage)\n"; $svar = 'failed'; } @@ -288,23 +310,24 @@ if ( $count > 0 ) { } # Print out some statistics - echo( "\n" ); + echo "\n"; 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" ); + if ( $$var > 0 ) { + echo "{$desc}: {$$var}\n"; + } } } else { - echo( "No suitable files could be found for import.\n" ); + echo "No suitable files could be found for import.\n"; } exit( 0 ); function showUsage( $reason = false ) { if ( $reason ) { - echo( $reason . "\n" ); + echo $reason . "\n"; } echo <<<TEXT @@ -314,25 +337,28 @@ 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) ---sleep=<sec> Sleep between files. Useful mostly for debugging. ---user=<username> Set username of uploader, default 'Maintenance script' ---check-userblock Check if the user got blocked during import. ---comment=<text> Set upload summary comment, default 'Importing image file'. ---comment-file=<file> Set upload summary comment the the content of <file>. ---comment-ext=<ext> Causes the comment for each file to be loaded from a file with the same name - but the extension <ext>. If a global comment is also given, it is appended. ---license=<code> Use an optional license template ---dry Dry run, don't import anything +--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' +--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/" +--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 e369cb15..fd768b34 100644 --- a/maintenance/importSiteScripts.php +++ b/maintenance/importSiteScripts.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to import all scripts in the MediaWiki namespace from a @@ -62,7 +62,8 @@ class ImportSiteScripts extends Maintenance { $text = Http::get( $url ); $wikiPage = WikiPage::factory( $title ); - $wikiPage->doEdit( $text, "Importing from $url", 0, false, $user ); + $content = ContentHandler::makeContent( $text, $wikiPage->getTitle() ); + $wikiPage->doEditContent( $content, "Importing from $url", 0, false, $user ); } } @@ -104,4 +105,4 @@ class ImportSiteScripts extends Maintenance { } $maintClass = 'ImportSiteScripts'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/importTextFile.php b/maintenance/importTextFile.php index adb50635..e081c20b 100644 --- a/maintenance/importTextFile.php +++ b/maintenance/importTextFile.php @@ -24,15 +24,15 @@ $options = array( 'help', 'nooverwrite', 'norc' ); $optionsWithArgs = array( 'title', 'user', 'comment' ); -require_once( __DIR__ . '/commandLine.inc' ); -echo( "Import Text File\n\n" ); +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}..." ); + echo "Using {$filename}..."; if ( is_file( $filename ) ) { $title = isset( $options['title'] ) ? $options['title'] : titleFromFilename( $filename ); @@ -40,7 +40,7 @@ if ( count( $args ) < 1 || isset( $options['help'] ) ) { if ( is_object( $title ) ) { - echo( "\nUsing title '" . $title->getPrefixedText() . "'..." ); + echo "\nUsing title '" . $title->getPrefixedText() . "'..."; if ( !$title->exists() || !isset( $options['nooverwrite'] ) ) { $text = file_get_contents( $filename ); @@ -49,30 +49,31 @@ if ( count( $args ) < 1 || isset( $options['help'] ) ) { if ( is_object( $user ) ) { - echo( "\nUsing username '" . $user->getName() . "'..." ); + 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..." ); + echo "\nPerforming edit..."; $page = WikiPage::factory( $title ); - $page->doEdit( $text, $comment, $flags, false, $user ); - echo( "done.\n" ); + $content = ContentHandler::makeContent( $text, $title ); + $page->doEditContent( $content, $comment, $flags, false, $user ); + echo "done.\n"; } else { - echo( "invalid username.\n" ); + echo "invalid username.\n"; } } else { - echo( "page exists.\n" ); + echo "page exists.\n"; } } else { - echo( "invalid title.\n" ); + echo "invalid title.\n"; } } else { - echo( "does not exist.\n" ); + echo "does not exist.\n"; } } diff --git a/maintenance/initEditCount.php b/maintenance/initEditCount.php index 3135b4c7..4b046835 100644 --- a/maintenance/initEditCount.php +++ b/maintenance/initEditCount.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; class InitEditCount extends Maintenance { public function __construct() { @@ -107,4 +107,4 @@ in the load balancer, usually indicating a replication environment.' ); } $maintClass = "InitEditCount"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/initStats.php b/maintenance/initSiteStats.php index 5d8b8866..92268b3e 100644 --- a/maintenance/initStats.php +++ b/maintenance/initSiteStats.php @@ -23,14 +23,14 @@ * @author Rob Church <robchur@gmail.com> */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to re-initialise or update the site statistics table * * @ingroup Maintenance */ -class InitStats extends Maintenance { +class InitSiteStats extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Re-initialise the site statistics tables"; @@ -48,7 +48,7 @@ class InitStats extends Maintenance { $edits = $counter->edits(); $this->output( "{$edits}\nCounting number of articles..." ); - $good = $counter->articles(); + $good = $counter->articles(); $this->output( "{$good}\nCounting total pages..." ); $pages = $counter->pages(); @@ -84,5 +84,5 @@ class InitStats extends Maintenance { } } -$maintClass = "InitStats"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +$maintClass = "InitSiteStats"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/install.php b/maintenance/install.php index 762bb94f..d118747a 100644 --- a/maintenance/install.php +++ b/maintenance/install.php @@ -22,15 +22,14 @@ */ if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.3.2' ) < 0 ) ) { - echo "You are using PHP version " . phpversion() . " but MediaWiki needs PHP 5.3.2 or higher. ABORTING.\n" . - "Check if you have a newer php executable with a different name, such as php5.\n"; - die( 1 ); + require_once dirname( __FILE__ ) . '/../includes/PHPVersionError.php'; + wfPHPVersionError( 'cli' ); } define( 'MW_CONFIG_CALLBACK', 'Installer::overrideConfig' ); define( 'MEDIAWIKI_INSTALL', true ); -require_once( dirname( __DIR__ )."/maintenance/Maintenance.php" ); +require_once dirname( __DIR__ ) . "/maintenance/Maintenance.php"; /** * Maintenance script to install and configure MediaWiki @@ -42,10 +41,11 @@ class CommandLineInstaller extends Maintenance { parent::__construct(); global $IP; - $this->addArg( 'name', 'The name of the wiki', true); + $this->addArg( 'name', 'The name of the wiki', true ); $this->addArg( 'admin', 'The username of the wiki administrator (WikiSysop)', true ); - $this->addOption( 'pass', 'The password for the wiki administrator.', true, true ); + $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( '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 ); @@ -77,6 +77,9 @@ class CommandLineInstaller extends Maintenance { $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".' ); + } wfSuppressWarnings(); $dbpass = file_get_contents( $dbpassfile ); wfRestoreWarnings(); @@ -86,17 +89,33 @@ 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".' ); + } + wfSuppressWarnings(); + $pass = file_get_contents( $passfile ); + 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->error( 'You need to provide the option "pass" or "passfile"', true ); + } + $installer = InstallerOverrides::getCliInstaller( $siteName, $adminName, $this->mOptions ); $status = $installer->doEnvironmentChecks(); - if( $status->isGood() ) { + if ( $status->isGood() ) { $installer->showMessage( 'config-env-good' ); } else { $installer->showStatusMessage( $status ); return; } - if( !$this->hasOption( 'env-checks' ) ) { + if ( !$this->hasOption( 'env-checks' ) ) { $installer->execute(); $installer->writeConfigurationFile( $this->getOption( 'confpath', $IP ) ); } @@ -111,4 +130,4 @@ class CommandLineInstaller extends Maintenance { $maintClass = "CommandLineInstaller"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/jsduck/MetaTags.rb b/maintenance/jsduck/MetaTags.rb new file mode 100644 index 00000000..83cc0884 --- /dev/null +++ b/maintenance/jsduck/MetaTags.rb @@ -0,0 +1,69 @@ +# 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 new file mode 100644 index 00000000..f96902d8 --- /dev/null +++ b/maintenance/jsduck/categories.json @@ -0,0 +1,63 @@ +[ + { + "name": "MediaWiki", + "groups": [ + { + "name": "Base", + "classes": [ + "mw", + "mw.Map", + "mw.Message", + "mw.loader", + "mw.log", + "mw.html", + "mw.html.Cdata", + "mw.html.Raw", + "mw.hook" + ] + }, + { + "name": "General", + "classes": [ + "mw.Title", + "mw.inspect", + "mw.inspect.reports", + "mw.notification", + "mw.user", + "mw.util", + "mw.plugin.*" + ] + }, + { + "name": "Actions", + "classes": ["mw.toolbar"] + }, + { + "name": "API", + "classes": ["mw.Api*"] + } + ] + }, + { + "name": "jQuery", + "groups": [ + { + "name": "Plugins", + "classes": ["jQuery.plugin.*"] + } + ] + }, + { + "name": "Upstream", + "groups": [ + { + "name": "jQuery", + "classes": ["jQuery", "jQuery.Event", "jQuery.Callbacks", "jQuery.Promise", "jQuery.Deferred", "jQuery.jqXHR", "QUnit"] + }, + { + "name": "JavaScript", + "classes": ["Array", "Boolean", "Date", "Function", "Number", "Object", "RegExp", "String"] + } + ] + } +] diff --git a/maintenance/jsduck/config.json b/maintenance/jsduck/config.json new file mode 100644 index 00000000..e6e0f658 --- /dev/null +++ b/maintenance/jsduck/config.json @@ -0,0 +1,27 @@ +{ + "--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"], + "--builtin-classes": true, + "--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" + ] +} diff --git a/maintenance/jsduck/eg-iframe.html b/maintenance/jsduck/eg-iframe.html new file mode 100644 index 00000000..86eae4b6 --- /dev/null +++ b/maintenance/jsduck/eg-iframe.html @@ -0,0 +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; + } + + .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: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 ); + }; + }() ); + + /** + * 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/jsduck/external.js b/maintenance/jsduck/external.js new file mode 100644 index 00000000..4bb83694 --- /dev/null +++ b/maintenance/jsduck/external.js @@ -0,0 +1,44 @@ +/** + * @class jQuery + * @source <http://api.jquery.com/> + */ + +/** + * @method ajax + * @static + * @source <http://api.jquery.com/jQuery.ajax/> + * @return {jqXHR} + */ + +/** + * @class jQuery.Event + * @source <http://api.jquery.com/Types/#Event> + */ + +/** + * @class jQuery.Callbacks + * @source <http://api.jquery.com/jQuery.Callbacks/> + */ + +/** + * @class jQuery.Promise + * @source <http://api.jquery.com/Types/#Promise> + */ + +/** + * @class jQuery.Deferred + * @mixins jQuery.Promise + * @source <http://api.jquery.com/jQuery.Deferred/> + */ + +/** + * @class jQuery.jqXHR + * @source <http://api.jquery.com/Types/#jqXHR> + * @alternateClassName jqXHR + */ + + +/** + * @class QUnit + * @source <http://api.qunitjs.com/> + */ diff --git a/maintenance/jsparse.php b/maintenance/jsparse.php index ceafc390..3f0a9ba7 100644 --- a/maintenance/jsparse.php +++ b/maintenance/jsparse.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to do test JavaScript validity parses using jsmin+'s parser @@ -29,7 +29,7 @@ require_once( __DIR__ . '/Maintenance.php' ); * @ingroup Maintenance */ class JSParseHelper extends Maintenance { - var $errs = 0; + public $errs = 0; public function __construct() { parent::__construct(); @@ -50,7 +50,7 @@ class JSParseHelper extends Maintenance { wfSuppressWarnings(); $js = file_get_contents( $filename ); wfRestoreWarnings(); - if ($js === false) { + if ( $js === false ) { $this->output( "$filename ERROR: could not read file\n" ); $this->errs++; continue; @@ -58,7 +58,7 @@ class JSParseHelper extends Maintenance { try { $parser->parse( $js, $filename, 1 ); - } catch (Exception $e) { + } catch ( Exception $e ) { $this->errs++; $this->output( "$filename ERROR: " . $e->getMessage() . "\n" ); continue; @@ -67,11 +67,11 @@ class JSParseHelper extends Maintenance { $this->output( "$filename OK\n" ); } - if ($this->errs > 0) { - exit(1); + if ( $this->errs > 0 ) { + exit( 1 ); } } } $maintClass = "JSParseHelper"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/lag.php b/maintenance/lag.php index 3ad0864f..410bf756 100644 --- a/maintenance/lag.php +++ b/maintenance/lag.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to show database lag. @@ -51,7 +51,7 @@ class DatabaseLag extends Maintenance { unset( $lags[0] ); echo gmdate( 'H:i:s' ) . ' '; foreach ( $lags as $lag ) { - printf( "%-12s " , $lag === false ? 'false' : $lag ); + printf( "%-12s ", $lag === false ? 'false' : $lag ); } echo "\n"; sleep( 5 ); @@ -61,11 +61,11 @@ class DatabaseLag extends Maintenance { $lags = $lb->getLagTimes(); foreach ( $lags as $i => $lag ) { $name = $lb->getServerName( $i ); - $this->output( sprintf( "%-20s %s\n" , $name, $lag === false ? 'false' : $lag ) ); + $this->output( sprintf( "%-20s %s\n", $name, $lag === false ? 'false' : $lag ) ); } } } } $maintClass = "DatabaseLag"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/language/StatOutputs.php b/maintenance/language/StatOutputs.php index d77029e7..e9d8c86d 100644 --- a/maintenance/language/StatOutputs.php +++ b/maintenance/language/StatOutputs.php @@ -1,5 +1,7 @@ <?php -if ( !defined( 'MEDIAWIKI' ) ) die(); +if ( !defined( 'MEDIAWIKI' ) ) { + die(); +} /** * Statistic output classes. * @@ -52,15 +54,15 @@ class wikiStatsOutput extends statsOutput { 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 ) ) { + if ( is_array( $wgDummyLanguageCodes ) ) { $dummyCodes = array(); - foreach( $wgDummyLanguageCodes as $dummyCode => $correctCode ) { + 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 ".\n\n"; # dot to end sentence - echo '{| class="sortable wikitable" border="2" cellpadding="4" cellspacing="0" style="background-color: #F9F9F9; border: 1px #AAAAAA solid; border-collapse: collapse; clear:both;" width="100%"' . "\n"; + 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"; @@ -80,7 +82,9 @@ class wikiStatsOutput extends statsOutput { # Weigh reverse with factor 20 so coloring takes effect more quickly as # this option is used solely for reporting 'bad' percentages. $v = $v * 20; - if ( $v > 255 ) $v = 255; + if ( $v > 255 ) { + $v = 255; + } $v = 255 - $v; } if ( $v < 128 ) { @@ -96,7 +100,7 @@ class wikiStatsOutput extends statsOutput { $color = $red . $green . $blue; $percent = parent::formatPercent( $subset, $total, $revert, $accuracy ); - return 'bgcolor="#' . $color . '"|' . $percent; + return 'style="background-color:#' . $color . ';"|' . $percent; } } diff --git a/maintenance/language/alltrans.php b/maintenance/language/alltrans.php index 8caf8677..d0e6e849 100644 --- a/maintenance/language/alltrans.php +++ b/maintenance/language/alltrans.php @@ -21,7 +21,7 @@ * @ingroup MaintenanceLanguage */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; /** * Maintenance script that gets all messages as defined by the @@ -44,4 +44,4 @@ class AllTrans extends Maintenance { } $maintClass = "AllTrans"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/language/checkDupeMessages.php b/maintenance/language/checkDupeMessages.php index 6abf7b44..381ddae1 100644 --- a/maintenance/language/checkDupeMessages.php +++ b/maintenance/language/checkDupeMessages.php @@ -21,7 +21,7 @@ * @ingroup MaintenanceLanguage */ -require_once( __DIR__ . '/../commandLine.inc' ); +require_once __DIR__ . '/../commandLine.inc'; $messagesDir = __DIR__ . '/../../languages/messages/'; $runTest = false; $run = false; @@ -52,7 +52,7 @@ Options: * mode: Output format, can be either: * text: Text output on the console (default) * wiki: Wiki format, with * at beginning of each line - * php: Output text as PHP syntax in a array $dupeMessages + * php: Output text as PHP syntax in an array named \$dupeMessages * raw: Raw output for duplicates TEXT; } @@ -80,35 +80,37 @@ if ( $run ) { } elseif ( !strcmp( $runMode, 'raw' ) ) { $runMode = 'raw'; } - include( $messagesFile ); + include $messagesFile; $messageExist = isset( $messages ); - if ( $messageExist ) + if ( $messageExist ) { $wgMessages[$langCode] = $messages; - include( $messagesFileC ); + } + include $messagesFileC; $messageCExist = isset( $messages ); - if ( $messageCExist ) + if ( $messageCExist ) { $wgMessages[$langCodeC] = $messages; + } $count = 0; if ( ( $messageExist ) && ( $messageCExist ) ) { if ( !strcmp( $runMode, 'php' ) ) { - print( "<?php\n" ); - print( '$dupeMessages = array(' . "\n" ); + print "<?php\n"; + print '$dupeMessages = array(' . "\n"; } foreach ( $wgMessages[$langCodeC] as $key => $value ) { foreach ( $wgMessages[$langCode] as $ckey => $cvalue ) { if ( !strcmp( $key, $ckey ) ) { if ( ( !strcmp( $key, $ckey ) ) && ( !strcmp( $value, $cvalue ) ) ) { if ( !strcmp( $runMode, 'raw' ) ) { - print( "$key\n" ); + print "$key\n"; } elseif ( !strcmp( $runMode, 'php' ) ) { - print( "'$key' => '',\n" ); + print "'$key' => '',\n"; } elseif ( !strcmp( $runMode, 'wiki' ) ) { $uKey = ucfirst( $key ); - print( "* MediaWiki:$uKey/$langCode\n" ); + print "* MediaWiki:$uKey/$langCode\n"; } else { - print( "* $key\n" ); + print "* $key\n"; } $count++; } @@ -116,7 +118,7 @@ if ( $run ) { } } if ( !strcmp( $runMode, 'php' ) ) { - print( ");\n" ); + print ");\n"; } if ( !strcmp( $runMode, 'text' ) ) { if ( $count == 1 ) { @@ -126,9 +128,11 @@ if ( $run ) { } } } else { - if ( !$messageExist ) + if ( !$messageExist ) { echo "There are no messages defined in $langCode.\n"; - if ( !$messageCExist ) + } + if ( !$messageCExist ) { echo "There are no messages defined in $langCodeC.\n"; + } } } diff --git a/maintenance/language/checkExtensions.php b/maintenance/language/checkExtensions.php index ebc62b60..79a4dd98 100644 --- a/maintenance/language/checkExtensions.php +++ b/maintenance/language/checkExtensions.php @@ -21,14 +21,14 @@ * @ingroup MaintenanceLanguage */ -require_once( __DIR__ . '/../commandLine.inc' ); -require_once( 'languages.inc' ); -require_once( 'checkLanguage.inc' ); +require_once __DIR__ . '/../commandLine.inc'; +require_once 'languages.inc'; +require_once 'checkLanguage.inc'; if ( !class_exists( 'MessageGroups' ) || !class_exists( 'PremadeMediawikiExtensionGroups' ) ) { echo <<<TEXT Please add the Translate extension to LocalSettings.php, and enable the extension groups: - require_once( 'extensions/Translate/Translate.php' ); + require_once 'extensions/Translate/Translate.php'; \$wgTranslateEC = array_keys( \$wgTranslateAC ); If you still get this message, update Translate to its latest version. diff --git a/maintenance/language/checkLanguage.inc b/maintenance/language/checkLanguage.inc index 11b00e14..4b49ada3 100644 --- a/maintenance/language/checkLanguage.inc +++ b/maintenance/language/checkLanguage.inc @@ -25,7 +25,7 @@ * @ingroup MaintenanceLanguage */ class CheckLanguageCLI { - protected $code = null; + protected $code = null; protected $level = 2; protected $doLinks = false; protected $linksPrefix = ''; @@ -43,10 +43,10 @@ class CheckLanguageCLI { * Constructor. * @param $options array Options for script. */ - public function __construct( Array $options ) { + public function __construct( array $options ) { if ( isset( $options['help'] ) ) { echo $this->help(); - exit(1); + exit( 1 ); } if ( isset( $options['lang'] ) ) { @@ -134,24 +134,24 @@ class CheckLanguageCLI { protected function getChecks() { 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', + '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', ); } @@ -163,14 +163,14 @@ class CheckLanguageCLI { */ 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 ), + '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 ), ); } @@ -181,24 +181,24 @@ class CheckLanguageCLI { protected function getDescriptions() { 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:', + '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:', ); } @@ -222,7 +222,7 @@ Parameters: --links: Link the message values (default off). --prefix: prefix to add to links. --wikilang: For the links, what is the content language of the wiki to display the output in (default en). - --noexif: Do not check for EXIF messages (a bit hard and boring to translate), if you know + --noexif: Do not check for Exif messages (a bit hard and boring to translate), if you know that they are currently not translated and want to focus on other problems (default off). --whitelist: Do only the following checks (form: code,code). --blacklist: Do not do the following checks (form: code,code). @@ -299,12 +299,14 @@ ENDS; */ protected function getCheckBlacklist() { global $checkBlacklist; + return $checkBlacklist; } /** * Check a language. * @param $code string The language code. + * @throws MWException * @return array The results. */ protected function checkLanguage( $code ) { @@ -312,6 +314,7 @@ ENDS; $results = array(); if ( $this->level === 0 ) { $this->L->getMessages( $code ); + return $results; } @@ -319,7 +322,8 @@ ENDS; $checkBlacklist = $this->getCheckBlacklist(); foreach ( $this->checks as $check ) { if ( isset( $checkBlacklist[$code] ) && - in_array( $check, $checkBlacklist[$code] ) ) { + in_array( $check, $checkBlacklist[$code] ) + ) { $results[$check] = array(); continue; } @@ -383,7 +387,7 @@ ENDS; echo "[messages are hidden]\n"; } else { foreach ( $messages as $key => $value ) { - if( !in_array( $check, $this->nonMessageChecks() ) ) { + if ( !in_array( $check, $this->nonMessageChecks() ) ) { $key = $this->formatKey( $key, $code ); } if ( $this->level == 2 || empty( $value ) ) { @@ -410,7 +414,7 @@ ENDS; $problems = 0; $detailTextForLangChecks = array(); foreach ( $results as $check => $messages ) { - if( in_array( $check, $this->nonMessageChecks() ) ) { + if ( in_array( $check, $this->nonMessageChecks() ) ) { continue; } $count = count( $messages ); @@ -426,7 +430,6 @@ ENDS; } else { $numbers[] = $count; } - } if ( count( $detailTextForLangChecks ) ) { @@ -462,13 +465,14 @@ EOL; * @return bool True if there are any results, false if not. */ protected function isEmpty() { - foreach( $this->results as $results ) { - foreach( $results as $messages ) { - if( !empty( $messages ) ) { + foreach ( $this->results as $results ) { + foreach ( $results as $messages ) { + if ( !empty( $messages ) ) { return false; } } } + return true; } } @@ -484,10 +488,10 @@ class CheckExtensionsCLI extends CheckLanguageCLI { * @param $options array Options for script. * @param $extension string The extension name (or names). */ - public function __construct( Array $options, $extension ) { + public function __construct( array $options, $extension ) { if ( isset( $options['help'] ) ) { echo $this->help(); - exit(1); + exit( 1 ); } if ( isset( $options['lang'] ) ) { @@ -641,18 +645,19 @@ ENDS; /** * Check a language and show the results. * @param $code string The language code. + * @throws MWException */ protected function checkLanguage( $code ) { - foreach( $this->extensions as $extension ) { + foreach ( $this->extensions as $extension ) { $this->L = $extension; $this->results = array(); $this->results[$code] = parent::checkLanguage( $code ); - if( !$this->isEmpty() ) { + if ( !$this->isEmpty() ) { echo $extension->name() . ":\n"; - if( $this->level > 0 ) { - switch( $this->output ) { + if ( $this->level > 0 ) { + switch ( $this->output ) { case 'plain': $this->outputText(); break; @@ -673,48 +678,49 @@ ENDS; # Blacklist some checks for some languages $checkBlacklist = array( #'code' => array( 'check1', 'check2' ... ) -'az' => array( 'plural' ), -'bo' => 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' ), + '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' ), ); diff --git a/maintenance/language/checkLanguage.php b/maintenance/language/checkLanguage.php index 99ba4e98..ec6e1226 100644 --- a/maintenance/language/checkLanguage.php +++ b/maintenance/language/checkLanguage.php @@ -21,9 +21,9 @@ * @ingroup MaintenanceLanguage */ -require_once( __DIR__ . '/../commandLine.inc' ); -require_once( 'checkLanguage.inc' ); -require_once( 'languages.inc' ); +require_once __DIR__ . '/../commandLine.inc'; +require_once 'checkLanguage.inc'; +require_once 'languages.inc'; $cli = new CheckLanguageCLI( $options ); diff --git a/maintenance/language/countMessages.php b/maintenance/language/countMessages.php index 5058a549..95a7154b 100644 --- a/maintenance/language/countMessages.php +++ b/maintenance/language/countMessages.php @@ -21,7 +21,7 @@ * @ingroup MaintenanceLanguage */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; /** * Maintenance script that counts how many messages we have defined @@ -59,7 +59,7 @@ class CountMessages extends Maintenance { private function getNumMessages( $file ) { // Separate function to limit scope - require( $file ); + require $file; if ( isset( $messages ) ) { return count( $messages ); } else { @@ -69,4 +69,4 @@ class CountMessages extends Maintenance { } $maintClass = "CountMessages"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/language/date-formats.php b/maintenance/language/date-formats.php index ed12b786..14634185 100644 --- a/maintenance/language/date-formats.php +++ b/maintenance/language/date-formats.php @@ -21,7 +21,7 @@ * @ingroup MaintenanceLanguage */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; /** * Maintenance script that tests various language time and date functions. @@ -79,4 +79,4 @@ class DateFormats extends Maintenance { } $maintClass = "DateFormats"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/language/digit2html.php b/maintenance/language/digit2html.php index 9d4cbe7e..a6e0456a 100644 --- a/maintenance/language/digit2html.php +++ b/maintenance/language/digit2html.php @@ -21,7 +21,7 @@ * @ingroup MaintenanceLanguage */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; /** * Maintenance script that check digit transformation. @@ -49,7 +49,7 @@ class Digit2Html extends Maintenance { $filename = Language::getMessagesFileName( $code ); $this->output( "Loading language [$code] ... " ); unset( $digitTransformTable ); - require_once( $filename ); + require_once $filename; if ( !isset( $digitTransformTable ) ) { $this->error( "\$digitTransformTable not found for lang: $code" ); continue; @@ -66,4 +66,4 @@ class Digit2Html extends Maintenance { } $maintClass = "Digit2Html"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/language/dumpMessages.php b/maintenance/language/dumpMessages.php index 0292d314..a72e25b8 100644 --- a/maintenance/language/dumpMessages.php +++ b/maintenance/language/dumpMessages.php @@ -23,7 +23,7 @@ * @todo Make this more useful, right now just dumps $wgContLang */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; /** * Maintenance script that dumps an entire language, using the keys from English. @@ -49,4 +49,4 @@ class DumpMessages extends Maintenance { } $maintClass = "DumpMessages"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/language/generateCollationData.php b/maintenance/language/generateCollationData.php index e34d9a13..fcf2c960 100644 --- a/maintenance/language/generateCollationData.php +++ b/maintenance/language/generateCollationData.php @@ -21,7 +21,7 @@ * @ingroup MaintenanceLanguage */ -require_once( __DIR__ .'/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; /** * Generate first letter data files for Collation.php @@ -30,19 +30,19 @@ require_once( __DIR__ .'/../Maintenance.php' ); */ class GenerateCollationData extends Maintenance { /** The directory with source data files in it */ - var $dataDir; + public $dataDir; /** The primary weights, indexed by codepoint */ - var $weights; + public $weights; /** * A hashtable keyed by codepoint, where presence indicates that a character * has a decomposition mapping. This makes it non-preferred for group header * selection. */ - var $mappedChars; + public $mappedChars; - var $debugOutFile; + public $debugOutFile; /** * Important tertiary weights from UTS #10 section 7.2 @@ -61,18 +61,80 @@ class GenerateCollationData extends Maintenance { public function execute() { $this->dataDir = $this->getOption( 'data-dir', '.' ); - if ( !file_exists( "{$this->dataDir}/allkeys.txt" ) ) { - $this->error( "Unable to find allkeys.txt. Please download it from " . - "http://www.unicode.org/Public/UCA/latest/allkeys.txt and specify " . - "its location with --data-dir=<DIR>" ); - exit( 1 ); - } - if ( !file_exists( "{$this->dataDir}/ucd.all.grouped.xml" ) ) { - $this->error( "Unable to find ucd.all.grouped.xml. Please download it " . - "from http://www.unicode.org/Public/6.0.0/ucdxml/ucd.all.grouped.zip " . - "and specify its location with --data-dir=<DIR>" ); + + $allkeysPresent = file_exists( "{$this->dataDir}/allkeys.txt" ); + $ucdallPresent = file_exists( "{$this->dataDir}/ucd.all.grouped.xml" ); + + // As of January 2013, these links work for all versions of Unicode + // between 5.1 and 6.2, inclusive. + $allkeysURL = "http://www.unicode.org/Public/UCA/<Unicode version>/allkeys.txt"; + $ucdallURL = "http://www.unicode.org/Public/<Unicode version>/ucdxml/ucd.all.grouped.zip"; + + if ( !$allkeysPresent || !$ucdallPresent ) { + $icuVersion = IcuCollation::getICUVersion(); + $unicodeVersion = IcuCollation::getUnicodeVersionForICU(); + + $error = ""; + + if ( !$allkeysPresent ) { + $error .= "Unable to find allkeys.txt. " + . "Download it and specify its location with --data-dir=<DIR>. " + . "\n\n"; + } + if ( !$ucdallPresent ) { + $error .= "Unable to find ucd.all.grouped.xml. " + . "Download it, unzip, and specify its location with --data-dir=<DIR>. " + . "\n\n"; + } + + $versionKnown = false; + if ( !$icuVersion ) { + // Unknown version - either very old intl, + // or PHP < 5.3.7 which does not expose this information + $error .= "As MediaWiki could not determine the version of ICU library used by your PHP's " + . "intl extension it can't suggest which file version to download. " + . "This can be caused by running a very old version of intl or PHP < 5.3.7. " + . "If you are sure everything is all right, find out the ICU version " + . "by running phpinfo(), check what is the Unicode version it is using " + . "at http://site.icu-project.org/download, then try finding appropriate data file(s) at:"; + } elseif ( version_compare( $icuVersion, "4.0", "<" ) ) { + // Extra old version + $error .= "You are using outdated version of ICU ($icuVersion), intended for " + . ( $unicodeVersion ? "Unicode $unicodeVersion" : "an unknown version of Unicode" ) + . "; this file might not be avalaible for it, and it's not supported by MediaWiki. " + . " You are on your own; consider upgrading PHP's intl extension or try " + . "one of the files available at:"; + } elseif ( version_compare( $icuVersion, "51.0", ">=" ) ) { + // Extra recent version + $error .= "You are using ICU $icuVersion, released after this script was last updated. " + . "Check what is the Unicode version it is using at http://site.icu-project.org/download . " + . "It can't be guaranteed everything will work, but appropriate file(s) should " + . "be available at:"; + } else { + // ICU 4.0 to 50.x + $versionKnown = true; + $error .= "You are using ICU $icuVersion, intended for " + . ( $unicodeVersion ? "Unicode $unicodeVersion" : "an unknown version of Unicode" ) + . ". Appropriate file(s) should be available at:"; + } + $error .= "\n"; + + if ( $versionKnown && $unicodeVersion ) { + $allkeysURL = str_replace( "<Unicode version>", "$unicodeVersion.0", $allkeysURL ); + $ucdallURL = str_replace( "<Unicode version>", "$unicodeVersion.0", $ucdallURL ); + } + + if ( !$allkeysPresent ) { + $error .= "* $allkeysURL\n"; + } + if ( !$ucdallPresent ) { + $error .= "* $ucdallURL\n"; + } + + $this->error( $error ); exit( 1 ); } + $debugOutFileName = $this->getOption( 'debug-output' ); if ( $debugOutFileName ) { $this->debugOutFile = fopen( $debugOutFileName, 'w' ); @@ -285,12 +347,12 @@ class GenerateCollationData extends Maintenance { } class UcdXmlReader { - var $fileName; - var $callback; - var $groupAttrs; - var $xml; - var $blocks = array(); - var $currentBlock; + public $fileName; + public $callback; + public $groupAttrs; + public $xml; + public $blocks = array(); + public $currentBlock; function __construct( $fileName ) { $this->fileName = $fileName; @@ -324,7 +386,7 @@ class UcdXmlReader { $this->xml = new XMLReader; $this->xml->open( $this->fileName ); if ( !$this->xml ) { - throw new MWException( __METHOD__.": unable to open {$this->fileName}" ); + throw new MWException( __METHOD__ . ": unable to open {$this->fileName}" ); } while ( $this->xml->name !== 'ucd' && $this->xml->read() ); $this->xml->read(); @@ -404,4 +466,4 @@ class UcdXmlReader { } $maintClass = 'GenerateCollationData'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/language/generateNormalizerData.php b/maintenance/language/generateNormalizerData.php index 54dfa39a..216445e4 100644 --- a/maintenance/language/generateNormalizerData.php +++ b/maintenance/language/generateNormalizerData.php @@ -21,9 +21,9 @@ * @ingroup MaintenanceLanguage */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../../includes/normal/UtfNormalUtil.php'; -require_once( __DIR__ . '/../../includes/normal/UtfNormalUtil.php' ); +require_once __DIR__ . '/../Maintenance.php'; /** * Generates normalizer data files for Arabic and Malayalam. @@ -32,7 +32,7 @@ require_once( __DIR__ . '/../../includes/normal/UtfNormalUtil.php' ); * @ingroup MaintenanceLanguage */ class GenerateNormalizerData extends Maintenance { - var $dataFile; + public $dataFile; public function __construct() { parent::__construct(); @@ -156,4 +156,4 @@ class GenerateNormalizerData extends Maintenance { } $maintClass = 'GenerateNormalizerData'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/language/langmemusage.php b/maintenance/language/langmemusage.php index 2323638e..14485f98 100644 --- a/maintenance/language/langmemusage.php +++ b/maintenance/language/langmemusage.php @@ -1,7 +1,6 @@ <?php /** - * Dumb program that tries to get the memory usage - * for each language file. + * Dumb program that tries to get the memory usage for each language 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 @@ -18,13 +17,19 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup MaintenanceLanguage */ /** This is a command line script */ -require_once( __DIR__ . '/../Maintenance.php' ); -require_once( __DIR__ . '/languages.inc' ); +require_once __DIR__ . '/../Maintenance.php'; +require_once __DIR__ . '/languages.inc'; +/** + * Maintenance script that tries to get the memory usage for each language file. + * + * @ingroup MaintenanceLanguage + */ class LangMemUsage extends Maintenance { public function __construct() { @@ -34,14 +39,15 @@ class LangMemUsage extends Maintenance { } public function execute() { - if ( !function_exists( 'memory_get_usage' ) ) + if ( !function_exists( 'memory_get_usage' ) ) { $this->error( "You must compile PHP with --enable-memory-limit", true ); + } $langtool = new languages(); $memlast = $memstart = memory_get_usage(); $this->output( "Base memory usage: $memstart\n" ); - + foreach ( $langtool->getLanguages() as $langcode ) { Language::factory( $langcode ); $memstep = memory_get_usage(); @@ -56,4 +62,4 @@ class LangMemUsage extends Maintenance { } $maintClass = "LangMemUsage"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/language/languages.inc b/maintenance/language/languages.inc index b76f921d..6070f4ab 100644 --- a/maintenance/language/languages.inc +++ b/maintenance/language/languages.inc @@ -43,10 +43,10 @@ class languages { * Load the list of languages: all the Messages*.php * files in the languages directory. * - * @param $exif bool Treat the EXIF messages? + * @param $exif bool Treat the Exif messages? */ function __construct( $exif = true ) { - require( __DIR__ . '/messageTypes.inc' ); + require __DIR__ . '/messageTypes.inc'; $this->mIgnoredMessages = $wgIgnoredMessages; if ( $exif ) { $this->mOptionalMessages = array_merge( $wgOptionalMessages ); @@ -107,7 +107,7 @@ class languages { $this->mSpecialPageAliases[$code] = array(); $filename = Language::getMessagesFileName( $code ); if ( file_exists( $filename ) ) { - require( $filename ); + require $filename; if ( isset( $messages ) ) { $this->mRawMessages[$code] = $messages; } @@ -154,7 +154,7 @@ class languages { if ( isset( $this->mGeneralMessages['required'][$key] ) ) { $this->mMessages[$code]['required'][$key] = $value; $this->mMessages[$code]['translated'][$key] = $value; - } else if ( isset( $this->mGeneralMessages['optional'][$key] ) ) { + } elseif ( isset( $this->mGeneralMessages['optional'][$key] ) ) { $this->mMessages[$code]['optional'][$key] = $value; $this->mMessages[$code]['translated'][$key] = $value; } else { @@ -184,7 +184,7 @@ class languages { foreach ( $this->mGeneralMessages['all'] as $key => $value ) { if ( in_array( $key, $this->mIgnoredMessages ) ) { $this->mGeneralMessages['ignored'][$key] = $value; - } else if ( in_array( $key, $this->mOptionalMessages ) ) { + } elseif ( in_array( $key, $this->mOptionalMessages ) ) { $this->mGeneralMessages['optional'][$key] = $value; $this->mGeneralMessages['translatable'][$key] = $value; } else { @@ -466,11 +466,11 @@ class languages { '[POP]' => "\xE2\x80\xAC", '[LRO]' => "\xE2\x80\xAD", '[RLO]' => "\xE2\x80\xAB", - '[ZWSP]'=> "\xE2\x80\x8B", - '[NBSP]'=> "\xC2\xA0", - '[WJ]' => "\xE2\x81\xA0", + '[ZWSP]' => "\xE2\x80\x8B", + '[NBSP]' => "\xC2\xA0", + '[WJ]' => "\xE2\x81\xA0", '[BOM]' => "\xEF\xBB\xBF", - '[FFFD]'=> "\xEF\xBF\xBD", + '[FFFD]' => "\xEF\xBF\xBD", ); $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu'; $wrongCharsMessages = array(); @@ -500,15 +500,15 @@ 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++ ) { - if ( preg_match( "/.*project.*/isDu", $matches[1][$i] ) ) { + for ( $i = 0; $i < count( $matches[0] ); $i++ ) { + if ( preg_match( "/.*project.*/isDu", $matches[1][$i] ) ) { $messages[$key][] = $matches[0][$i]; } } if ( isset( $messages[$key] ) ) { - $messages[$key] = implode( $messages[$key],", " ); + $messages[$key] = implode( $messages[$key], ", " ); } } return $messages; @@ -563,7 +563,9 @@ class languages { $this->loadFile( 'en' ); $this->loadFile( $code ); $namespacesDiff = array_diff_key( $this->mNamespaceNames['en'], $this->mNamespaceNames[$code] ); - if ( isset( $namespacesDiff[NS_MAIN] ) ) unset( $namespacesDiff[NS_MAIN] ); + if ( isset( $namespacesDiff[NS_MAIN] ) ) { + unset( $namespacesDiff[NS_MAIN] ); + } return $namespacesDiff; } @@ -579,16 +581,16 @@ class languages { $namespaces = array(); # Check default namespace name - if( isset( $this->mNamespaceNames[$code][NS_PROJECT_TALK] ) ) { + if ( isset( $this->mNamespaceNames[$code][NS_PROJECT_TALK] ) ) { $default = $this->mNamespaceNames[$code][NS_PROJECT_TALK]; - if ( strpos( $default, '$1' ) === FALSE ) { + if ( strpos( $default, '$1' ) === false ) { $namespaces[$default] = 'default'; } } # Check namespace aliases - foreach( $this->mNamespaceAliases[$code] as $key => $value ) { - if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === FALSE ) { + foreach ( $this->mNamespaceAliases[$code] as $key => $value ) { + if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === false ) { $namespaces[$key] = ''; } } @@ -739,9 +741,8 @@ class extensionLanguages extends languages { function __construct( MessageGroup $group ) { $this->mMessageGroup = $group; - $bools = $this->mMessageGroup->getBools(); - $this->mIgnoredMessages = $bools['ignored']; - $this->mOptionalMessages = $bools['optional']; + $this->mIgnoredMessages = $this->mMessageGroup->getIgnored(); + $this->mOptionalMessages = $this->mMessageGroup->getOptional(); } /** @@ -759,9 +760,9 @@ class extensionLanguages extends languages { * @param $code string The language code. */ protected function loadFile( $code ) { - if( !isset( $this->mRawMessages[$code] ) ) { + if ( !isset( $this->mRawMessages[$code] ) ) { $this->mRawMessages[$code] = $this->mMessageGroup->load( $code ); - if( empty( $this->mRawMessages[$code] ) ) { + if ( empty( $this->mRawMessages[$code] ) ) { $this->mRawMessages[$code] = array(); } } diff --git a/maintenance/language/messageTypes.inc b/maintenance/language/messageTypes.inc index ce1dbb9b..0b9b7cb8 100644 --- a/maintenance/language/messageTypes.inc +++ b/maintenance/language/messageTypes.inc @@ -96,7 +96,6 @@ $wgIgnoredMessages = array( 'talkpageheader', 'anonnotice', 'autoblock_whitelist', - 'searchmenu-help', 'searchmenu-new-nocreate', 'googlesearch', 'opensearch-desc', @@ -142,6 +141,7 @@ $wgIgnoredMessages = array( 'statistics-footer', 'talkpagetext', 'uploadfooter', + 'upload-default-description', 'listgrouprights-link', 'search-interwiki-custom', 'allpages-summary', @@ -181,6 +181,7 @@ $wgIgnoredMessages = array( 'deadendpages-summary', 'protectedpages-summary', 'disambiguations-summary', + 'pageswithprop-summary', 'doubleredirects-summary', 'lonelypages-summary', 'unusedtemplates-summary', @@ -214,14 +215,17 @@ $wgIgnoredMessages = array( '1movedto2', '1movedto2_redir', 'move-redirect-suppressed', - // 'newuserlog-byemail', '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', @@ -240,18 +244,36 @@ $wgIgnoredMessages = array( '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', + 'edithelppage', + 'autocomment-prefix', + 'move-redirect-text', ); /** Optional messages, which may be translated only if changed in the target language. */ $wgOptionalMessages = array( 'linkprefix', - 'editsection-brackets', 'feed-atom', 'feed-rss', 'unit-pixel', @@ -295,40 +317,24 @@ $wgOptionalMessages = array( 'resetpass_text', 'image_sample', 'media_sample', - 'skinname-standard', - 'skinname-nostalgia', 'skinname-cologneblue', 'skinname-monobook', - 'skinname-myskin', - 'skinname-chick', - 'skinname-simple', 'skinname-modern', 'skinname-vector', 'common.css', - 'standard.css', - 'nostalgia.css', 'cologneblue.css', 'monobook.css', - 'myskin.css', - 'chick.css', - 'simple.css', 'modern.css', 'vector.css', 'print.css', - 'handheld.css', 'noscript.css', 'group-autoconfirmed.css', 'group-bot.css', 'group-sysop.css', 'group-bureaucrat.css', 'common.js', - 'standard.js', - 'nostalgia.js', 'cologneblue.js', 'monobook.js', - 'myskin.js', - 'chick.js', - 'simple.js', 'modern.js', 'vector.js', 'group-autoconfirmed.js', @@ -365,6 +371,7 @@ $wgOptionalMessages = array( 'exif-maxaperturevalue-value', 'exif-subjectnewscode-value', 'booksources-isbn', + 'protect-summary-desc', 'sp-contributions-explain', 'sorbs', 'video-dims', @@ -457,7 +464,6 @@ $wgOptionalMessages = array( 'percent', 'parentheses', 'brackets', - 'autocomment-prefix', 'listgrouprights-right-display', 'listgrouprights-right-revoked', 'timezone-utc', @@ -467,6 +473,7 @@ $wgOptionalMessages = array( 'backlinksubtitle', 'prefs-registration-date-time', 'prefs-memberingroups-type', + 'userrights-groupsmember-type', 'shared-repo-name-wikimediacommons', 'usermessage-template', 'filepage.css', @@ -479,9 +486,16 @@ $wgOptionalMessages = array( '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 */ +/** Exif messages, which may be set as optional in several checks, but are generally mandatory */ $wgEXIFMessages = array( 'exif-imagewidth', 'exif-imagelength', diff --git a/maintenance/language/messages.inc b/maintenance/language/messages.inc index baa0c96e..de163a61 100644 --- a/maintenance/language/messages.inc +++ b/maintenance/language/messages.inc @@ -56,9 +56,6 @@ $wgMessageStructure = array( 'tog-shownumberswatching', 'tog-oldsig', 'tog-fancysig', - 'tog-externaleditor', - 'tog-externaldiff', - 'tog-showjumplinks', 'tog-uselivepreview', 'tog-forceeditsummary', 'tog-watchlisthideown', @@ -72,6 +69,8 @@ $wgMessageStructure = array( 'tog-showhiddencats', 'tog-noconvertlink', 'tog-norollbackdiff', + 'tog-useeditwarning', + 'tog-prefershttps' ), 'underline' => array( 'underline-always', @@ -136,6 +135,18 @@ $wgMessageStructure = array( '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', @@ -167,6 +178,7 @@ $wgMessageStructure = array( 'newwindow', 'cancel', 'moredotdotdot', + 'morenotlisted', 'mypage', 'mytalk', 'anontalk', @@ -178,7 +190,6 @@ $wgMessageStructure = array( 'qbbrowse', 'qbedit', 'qbpageoptions', - 'qbpageinfo', 'qbmyoptions', 'qbspecialpages', 'faq', @@ -204,6 +215,7 @@ $wgMessageStructure = array( 'variants', ), 'miscellaneous2' => array( + 'navigation-heading', 'errorpagetitle', 'returnto', 'tagline', @@ -225,6 +237,7 @@ $wgMessageStructure = array( 'create-this-page', 'delete', 'deletethispage', + 'undeletethispage', 'undelete_short', 'viewdeleted_short', 'protect', @@ -312,7 +325,6 @@ $wgMessageStructure = array( 'youhavenewmessagesmulti', 'newtalkseparator', 'editsection', - 'editsection-brackets', 'editold', 'viewsourceold', 'editlink', @@ -365,8 +377,11 @@ $wgMessageStructure = array( 'errors' => array( 'error', 'databaseerror', - 'dberrortext', - 'dberrortextcl', + 'databaseerror-text', + 'databaseerror-textcl', + 'databaseerror-query', + 'databaseerror-function', + 'databaseerror-error', 'laggedslavemode', 'readonly', 'enterlockreason', @@ -391,6 +406,7 @@ $wgMessageStructure = array( 'cannotdelete', 'cannotdelete-title', 'delete-hook-aborted', + 'no-null-revision', 'badtitle', 'badtitletext', 'perfcached', @@ -406,11 +422,14 @@ $wgMessageStructure = array( 'viewyourtext', 'protectedinterface', 'editinginterface', - 'sqlhidden', 'cascadeprotected', 'namespaceprotected', 'customcssprotected', 'customjsprotected', + 'mycustomcssprotected', + 'mycustomjsprotected', + 'myprivateinfoprotected', + 'mypreferencesprotected', 'ns-specialprotected', 'titleprotected', 'filereadonlyerror', @@ -426,12 +445,23 @@ $wgMessageStructure = array( ), 'login' => array( 'logouttext', - 'welcomecreation', + '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', - 'securelogin-stick-https', + 'userlogin-remembermypassword', + 'userlogin-signwithsecure', 'yourdomainname', 'password-change-forbidden', 'externaldberror', @@ -444,17 +474,49 @@ $wgMessageStructure = array( 'userlogout', 'userlogout-summary', 'notloggedin', + 'userlogin-noaccount', + 'userlogin-joinproject', 'nologin', 'nologinlink', 'createaccount', 'gotaccount', 'gotaccountlink', 'userlogin-resetlink', + 'userlogin-resetpassword-link', + 'helplogin-url', + 'userlogin-helplink', + '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', @@ -506,12 +568,14 @@ $wgMessageStructure = array( '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', @@ -522,20 +586,22 @@ $wgMessageStructure = array( 'newpassword', 'retypenew', 'resetpass_submit', - 'resetpass_success', + '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', + 'passwordreset-text-one', + 'passwordreset-text-many', 'passwordreset-legend', 'passwordreset-disabled', - 'passwordreset-pretext', + 'passwordreset-emaildisabled', 'passwordreset-username', 'passwordreset-domain', 'passwordreset-capture', @@ -558,9 +624,22 @@ $wgMessageStructure = array( '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', @@ -670,7 +749,6 @@ $wgMessageStructure = array( 'hiddencategories', 'edittools', 'edittools-upload', - 'nocreatetitle', 'nocreatetext', 'nocreate-loggedin', 'sectioneditnotsupported-title', @@ -685,10 +763,21 @@ $wgMessageStructure = array( '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', @@ -713,6 +802,7 @@ $wgMessageStructure = array( 'undo-failure', 'undo-norev', 'undo-summary', + 'undo-summary-username-hidden', ), 'cantcreateaccount' => array( 'cantcreateaccounttitle', @@ -861,6 +951,7 @@ $wgMessageStructure = array( 'compareselectedversions', 'showhideselectedversions', 'editundo', + 'diff-empty', 'diff-multi', 'diff-multi-manyusers', 'difference-missing-revision', @@ -887,9 +978,7 @@ $wgMessageStructure = array( 'searchmenu-exists', 'searchmenu-new', 'searchmenu-new-nocreate', - 'searchhelp-url', 'searchmenu-prefix', - 'searchmenu-help', 'searchprofile-articles', 'searchprofile-project', 'searchprofile-images', @@ -931,19 +1020,11 @@ $wgMessageStructure = array( 'search-external', 'searchdisabled', 'googlesearch', + 'search-error', ), 'opensearch' => array( 'opensearch-desc', ), - 'quickbar' => array( - 'qbsettings', - 'qbsettings-none', - 'qbsettings-fixedleft', - 'qbsettings-fixedright', - 'qbsettings-floatingleft', - 'qbsettings-floatingright', - 'qbsettings-directionality', - ), 'preferences' => array( 'preferences', 'preferences-summary', @@ -978,7 +1059,6 @@ $wgMessageStructure = array( 'resetprefs', 'restoreprefs', 'prefs-editing', - 'prefs-edit-boxsize', 'rows', 'columns', 'searchresultshead', @@ -989,7 +1069,7 @@ $wgMessageStructure = array( 'recentchangesdays-max', 'recentchangescount', 'prefs-help-recentchangescount', - 'prefs-help-watchlist-token', + 'prefs-help-watchlist-token2', 'savedprefs', 'timezonelegend', 'localtime', @@ -1020,7 +1100,6 @@ $wgMessageStructure = array( 'prefs-common-css-js', 'prefs-reset-intro', 'prefs-emailconfirm-label', - 'prefs-textboxsize', 'youremail', 'username', 'uid', @@ -1055,6 +1134,8 @@ $wgMessageStructure = array( 'prefs-dateformat', 'prefs-timeoffset', 'prefs-advancedediting', + 'prefs-editor', + 'prefs-preview', 'prefs-advancedrc', 'prefs-advancedrendering', 'prefs-advancedsearchoptions', @@ -1062,7 +1143,9 @@ $wgMessageStructure = array( 'prefs-displayrc', 'prefs-displaysearchoptions', 'prefs-displaywatchlist', + 'prefs-tokenwatchlist', 'prefs-diffs', + 'prefs-help-prefershttps', ), 'preferences-email' => array( 'email-address-validity-valid', @@ -1079,6 +1162,7 @@ $wgMessageStructure = array( 'saveusergroups', 'userrights-groupsmember', 'userrights-groupsmember-auto', + 'userrights-groupsmember-type', 'userrights-groups-help', 'userrights-reason', 'userrights-no-interwiki', @@ -1088,6 +1172,8 @@ $wgMessageStructure = array( 'userrights-changeable-col', 'userrights-unchangeable-col', 'userrights-irreversible-marker', + 'userrights-conflict', + 'userrights-removed-self', ), 'group' => array( 'group', @@ -1156,10 +1242,18 @@ $wgMessageStructure = array( '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', @@ -1177,12 +1271,13 @@ $wgMessageStructure = array( 'right-sendemail', 'right-passwordreset', ), + 'newuserlog' => array( + 'newuserlogpage', + 'newuserlogpagetext', + ), 'rightslog' => array( 'rightslog', 'rightslogtext', - 'rightslogentry', - 'rightslogentry-autopromote', - 'rightsnone', ), 'action' => array( 'action-read', @@ -1220,14 +1315,21 @@ $wgMessageStructure = array( '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', @@ -1267,7 +1369,6 @@ $wgMessageStructure = array( 'recentchangeslinked-feed', 'recentchangeslinked-toolbox', 'recentchangeslinked-title', - 'recentchangeslinked-noresult', 'recentchangeslinked-summary', 'recentchangeslinked-page', 'recentchangeslinked-to', @@ -1289,6 +1390,7 @@ $wgMessageStructure = array( 'upload-preferred', 'upload-prohibited', 'uploadfooter', + 'upload-default-description', 'uploadlog', 'uploadlogpage', 'uploadlogpagetext', @@ -1387,6 +1489,7 @@ $wgMessageStructure = array( 'backend-fail-notsame', 'backend-fail-invalidpath', 'backend-fail-delete', + 'backend-fail-describe', 'backend-fail-alreadyexists', 'backend-fail-store', 'backend-fail-copy', @@ -1465,7 +1568,6 @@ $wgMessageStructure = array( 'http-read-error', 'http-timed-out', 'http-curl-error', - 'http-host-unreachable', 'http-bad-status', ), @@ -1496,6 +1598,10 @@ $wgMessageStructure = array( 'listfiles_size', 'listfiles_description', 'listfiles_count', + 'listfiles-show-all', + 'listfiles-latestversion', + 'listfiles-latestversion-yes', + 'listfiles-latestversion-no', ), 'filedescription' => array( 'file-anchor-link', @@ -1589,6 +1695,13 @@ $wgMessageStructure = array( 'randompage-nopages', 'randompage-url', ), + 'randomincategory' => array( + 'randomincategory', + 'randomincategory-invalidcategory', + 'randomincategory-nopages', + 'randomincategory-selectcategory', + 'randomincategory-selectcategory-submit', + ), 'randomredirect' => array( 'randomredirect', 'randomredirect-nopages', @@ -1616,11 +1729,15 @@ $wgMessageStructure = array( 'statistics-mostpopular', 'statistics-footer', ), - 'disambiguations' => array( - 'disambiguations', - 'disambiguations-summary', - 'disambiguationspage', - 'disambiguations-text', + 'pageswithprop' => array( + 'pageswithprop', + 'pageswithprop-summary', + 'pageswithprop-legend', + 'pageswithprop-text', + 'pageswithprop-prop', + 'pageswithprop-submit', + 'pageswithprop-prophidden-long', + 'pageswithprop-prophidden-binary', ), 'doubleredirects' => array( 'doubleredirects', @@ -1704,6 +1821,7 @@ $wgMessageStructure = array( 'prefixindex', 'prefixindex-namespace', 'prefixindex-summary', + 'prefixindex-strip', 'shortpages', 'shortpages-summary', 'longpages', @@ -1725,6 +1843,7 @@ $wgMessageStructure = array( 'listusers-summary', 'listusers-editsonly', 'listusers-creationsort', + 'listusers-desc', 'usereditcount', 'usercreated', 'newpages', @@ -1833,10 +1952,6 @@ $wgMessageStructure = array( 'activeusers-submit', 'activeusers-noresult', ), - 'newuserlog' => array( - 'newuserlogpage', - 'newuserlogpagetext', - ), 'listgrouprights' => array( 'listgrouprights', 'listgrouprights-summary', @@ -1914,7 +2029,6 @@ $wgMessageStructure = array( 'unwatchthispage', 'notanarticle', 'notvisiblerev', - 'watchnochange', 'watchlist-details', 'wlheader-enotif', 'wlheader-showupdated', @@ -1934,15 +2048,23 @@ $wgMessageStructure = array( 'enotif' => array( 'enotif_mailer', 'enotif_reset', - 'enotif_newpagetext', 'enotif_impersonal_salutation', - 'changed', - 'created', - 'enotif_subject', + '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', @@ -2000,6 +2122,8 @@ $wgMessageStructure = array( 'prot_1movedto2', 'protect-badnamespace-title', 'protect-badnamespace-text', + 'protect-norestrictiontypes-text', + 'protect-norestrictiontypes-title', 'protect-legend', 'protectcomment', 'protectexpiry', @@ -2015,6 +2139,7 @@ $wgMessageStructure = array( 'protect-fallback', 'protect-level-autoconfirmed', 'protect-level-sysop', + 'protect-summary-desc', 'protect-summary-cascade', 'protect-expiring', 'protect-expiring-local', @@ -2253,14 +2378,12 @@ $wgMessageStructure = array( 'ipb_blocked_as_range', 'ip_range_invalid', 'ip_range_toolarge', - 'blockme', 'proxyblocker', - 'proxyblocker-disabled', 'proxyblockreason', - 'proxyblocksuccess', 'sorbs', 'sorbsreason', 'sorbs_create_account_reason', + 'xffblockreason', 'cant-block-while-blocked', 'cant-see-hidden-user', 'ipbblocked', @@ -2324,6 +2447,7 @@ $wgMessageStructure = array( 'movesubpagetext', 'movenosubpage', 'movereason', + 'move-redirect-text', 'revertmove', 'delete_and_move', 'delete_and_move_text', @@ -2335,6 +2459,7 @@ $wgMessageStructure = array( 'immobile-target-namespace-iw', 'immobile-source-page', 'immobile-target-page', + 'bad-target-model', 'immobile_namespace', 'imagenocrossnamespace', 'nonfile-cannot-move-to-file', @@ -2384,6 +2509,7 @@ $wgMessageStructure = array( 'thumbnail-more', 'filemissing', 'thumbnail_error', + 'thumbnail_error_remote', 'djvu_page_error', 'djvu_no_xml', 'thumbnail-temp-create', @@ -2436,6 +2562,7 @@ $wgMessageStructure = array( 'import-error-interwiki', 'import-error-special', 'import-error-invalid', + 'import-error-unserialize', 'import-options-wrong', 'import-rootpage-invalid', 'import-rootpage-nosubpage', @@ -2451,12 +2578,11 @@ $wgMessageStructure = array( 'javaccripttest' => array( 'javascripttest', 'javascripttest-backlink', - 'javascripttest-disabled', 'javascripttest-title', 'javascripttest-pagetext-noframework', 'javascripttest-pagetext-unknownframework', 'javascripttest-pagetext-frameworks', - 'javascripttest-pagetext-skins' , + 'javascripttest-pagetext-skins', 'javascripttest-qunit-name', 'javascripttest-qunit-intro', 'javascripttest-qunit-heading', @@ -2601,20 +2727,15 @@ $wgMessageStructure = array( 'tooltip-undo', 'tooltip-preferences-save', 'tooltip-summary', + 'interlanguage-link-title', ), 'stylesheets' => array( 'common.css', - 'standard.css', - 'nostalgia.css', 'cologneblue.css', 'monobook.css', - 'myskin.css', - 'chick.css', - 'simple.css', 'modern.css', 'vector.css', 'print.css', - 'handheld.css', 'noscript.css', 'group-autoconfirmed.css', 'group-bot.css', @@ -2623,13 +2744,8 @@ $wgMessageStructure = array( ), 'scripts' => array( 'common.js', - 'standard.js', - 'nostalgia.js', 'cologneblue.js', 'monobook.js', - 'myskin.js', - 'chick.js', - 'simple.js', 'modern.js', 'vector.js', 'group-autoconfirmed.js', @@ -2660,6 +2776,7 @@ $wgMessageStructure = array( 'spam_reverting', 'spam_blanking', 'spam_deleting', + 'simpleantispam-label', ), 'info' => array( 'pageinfo-header', @@ -2673,11 +2790,13 @@ $wgMessageStructure = array( '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', @@ -2693,16 +2812,24 @@ $wgMessageStructure = array( '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-standard', - 'skinname-nostalgia', 'skinname-cologneblue', 'skinname-monobook', - 'skinname-myskin', - 'skinname-chick', - 'skinname-simple', 'skinname-modern', 'skinname-vector', ), @@ -2717,6 +2844,8 @@ $wgMessageStructure = array( 'markedaspatrollederror', 'markedaspatrollederrortext', 'markedaspatrollederror-noautopatrol', + 'markedaspatrollednotify', + 'markedaspatrollederrornotify', ), 'patrol-log' => array( 'patrol-log-page', @@ -2748,6 +2877,7 @@ $wgMessageStructure = array( 'file-nohires', 'svg-long-desc', 'svg-long-desc-animated', + 'svg-long-error', 'show-big-image', 'show-big-image-preview', 'show-big-image-other', @@ -2782,7 +2912,25 @@ $wgMessageStructure = array( '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', @@ -3139,16 +3287,16 @@ $wgMessageStructure = array( '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-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', @@ -3343,6 +3491,7 @@ $wgMessageStructure = array( 'scarytransclusion' => array( 'scarytranscludedisabled', 'scarytranscludefailed', + 'scarytranscludefailed-httpstatus', 'scarytranscludetoolong', ), 'deleteconflict' => array( @@ -3542,7 +3691,6 @@ $wgMessageStructure = array( 'version-other', 'version-mediahandlers', 'version-hooks', - 'version-extension-functions', 'version-parser-extensiontags', 'version-parser-function-hooks', 'version-hook-name', @@ -3552,10 +3700,19 @@ $wgMessageStructure = array( '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', @@ -3565,11 +3722,18 @@ $wgMessageStructure = array( 'version-entrypoints-api-php', 'version-entrypoints-load-php', ), - 'filepath' => array( - 'filepath', - 'filepath-page', - 'filepath-submit', - 'filepath-summary', + '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', @@ -3611,12 +3775,16 @@ $wgMessageStructure = array( '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', ), @@ -3638,6 +3806,7 @@ $wgMessageStructure = array( 'dberr-problems', 'dberr-again', 'dberr-info', + 'dberr-info-hidden', 'dberr-usegoogle', 'dberr-outofdate', 'dberr-cachederror', @@ -3653,6 +3822,9 @@ $wgMessageStructure = array( 'htmlform-submit', 'htmlform-reset', 'htmlform-selectorother-other', + 'htmlform-no', + 'htmlform-yes', + 'htmlform-chosen-placeholder', ), 'sqlite' => array( 'sqlite-has-fts', @@ -3690,8 +3862,12 @@ $wgMessageStructure = array( 'logentry-newusers-newusers', 'logentry-newusers-create', 'logentry-newusers-create2', + 'logentry-newusers-byemail', 'logentry-newusers-autocreate', - 'newuserlog-byemail', + 'logentry-rights-rights', + 'logentry-rights-rights-legacy', + 'logentry-rights-autopromote', + 'rightsnone', ), 'logging-irc' => array( 'revdelete-logentry', @@ -3712,7 +3888,6 @@ $wgMessageStructure = array( '1movedto2', '1movedto2_redir', 'move-redirect-suppressed', - // 'newuserlog-byemail', 'newuserlog-create-entry', 'newuserlog-create2-entry', 'newuserlog-autocreate-entry', @@ -3720,6 +3895,8 @@ $wgMessageStructure = array( 'deletedarticle', // 'uploadedimage', // 'overwroteimage', + 'rightslogentry', + 'rightslogentry-autopromote', ), 'feedback' => array( 'feedback-bugornote', @@ -3772,6 +3949,7 @@ $wgMessageStructure = array( 'api-error-ok-but-empty', 'api-error-overwrite', 'api-error-stashfailed', + 'api-error-publishfailed', 'api-error-timeout', 'api-error-unclassified', 'api-error-unknown-code', @@ -3792,16 +3970,38 @@ $wgMessageStructure = array( '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 behaviour for +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 -XHTML id it should only appear once and include characters that are legal -XHTML id names.", +(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', @@ -3812,7 +4012,7 @@ XHTML id names.", '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) and the disambiguation template definition (see disambiguations).', + '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' => '', @@ -3826,9 +4026,11 @@ XHTML id names.", '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', @@ -3840,7 +4042,6 @@ XHTML id names.", 'diffs' => 'Diffs', 'search' => 'Search results', 'opensearch' => 'OpenSearch description', - 'quickbar' => 'Quickbar', 'preferences' => 'Preferences page', 'preferences-email' => 'User preference: email validation using jQuery', 'userrights' => 'User rights', @@ -3872,9 +4073,10 @@ XHTML id names.", 'listredirects' => 'List redirects', 'unusedtemplates' => 'Unused templates', 'randompage' => 'Random page', + 'randomincategory' => 'Random page in category', 'randomredirect' => 'Random redirect', 'statistics' => 'Statistics', - 'disambiguations' => '', + 'pageswithprop' => '', 'doubleredirects' => '', 'brokenredirects' => '', 'withoutinterwiki' => '', @@ -3929,8 +4131,9 @@ XHTML id names.", 'patrol-log' => 'Patrol log', 'imagedeletion' => 'Image deletion', 'browsediffs' => 'Browsing diffs', - 'newfiles' => 'Special:NewFiles', + '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", @@ -3943,9 +4146,9 @@ Variants for Chinese language", 'variantname-shi' => 'Variants for Tachelhit language', 'media-info' => 'Media information', 'metadata' => 'Metadata', - 'exif' => 'EXIF tags', + '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-compression' => 'Exif attributes', 'exif-copyrighted' => '', 'exif-unknowndate' => '', 'exif-photometricinterpretation' => '', @@ -4014,7 +4217,7 @@ Variants for Chinese language", 'signatures' => 'Signatures', 'CoreParserFunctions' => 'Core parser functions', 'version' => 'Special:Version', - 'filepath' => 'Special:FilePath', + 'redirect' => 'Special:Redirect', 'fileduplicatesearch' => 'Special:FileDuplicateSearch', 'special-specialpages' => 'Special:SpecialPages', 'special-blank' => 'Special:BlankPage', @@ -4031,4 +4234,6 @@ Variants for Chinese language", '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 index ad839054..66948aeb 100644 --- a/maintenance/language/rebuildLanguage.php +++ b/maintenance/language/rebuildLanguage.php @@ -22,9 +22,9 @@ * @defgroup MaintenanceLanguage MaintenanceLanguage */ -require_once( __DIR__ . '/../commandLine.inc' ); -require_once( 'languages.inc' ); -require_once( 'writeMessagesArray.inc' ); +require_once __DIR__ . '/../commandLine.inc'; +require_once 'languages.inc'; +require_once 'writeMessagesArray.inc'; /** * Rewrite a messages array. @@ -56,13 +56,13 @@ function rebuildLanguage( $languages, $code, $write, $listUnknown, $removeUnknow */ function removeDupes( $oldMsgArray, $dupeMsgSource ) { if ( file_exists( $dupeMsgSource ) ) { - include( $dupeMsgSource ); + include $dupeMsgSource; if ( !isset( $dupeMessages ) ) { - echo( "There are no duplicated messages in the source file provided." ); + echo "There are no duplicated messages in the source file provided."; exit( 1 ); } } else { - echo ( "The specified file $dupeMsgSource cannot be found." ); + echo "The specified file $dupeMsgSource cannot be found."; exit( 1 ); } $newMsgArray = $oldMsgArray; diff --git a/maintenance/language/transstat.php b/maintenance/language/transstat.php index ba503224..61b84a07 100644 --- a/maintenance/language/transstat.php +++ b/maintenance/language/transstat.php @@ -28,9 +28,9 @@ */ $optionsWithArgs = array( 'output' ); -require_once( __DIR__ . '/../commandLine.inc' ); -require_once( 'languages.inc' ); -require_once( __DIR__ . '/StatOutputs.php' ); +require_once __DIR__ . '/../commandLine.inc'; +require_once 'languages.inc'; +require_once __DIR__ . '/StatOutputs.php'; if ( isset( $options['help'] ) ) { @@ -96,7 +96,7 @@ $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 ) && + if ( $code == 'en' || $code == 'enRTL' || ( is_array( $wgDummyLanguageCodes ) && isset( $wgDummyLanguageCodes[$code] ) ) ) { continue; } diff --git a/maintenance/language/validate.php b/maintenance/language/validate.php index 751e744d..63d9b847 100644 --- a/maintenance/language/validate.php +++ b/maintenance/language/validate.php @@ -21,6 +21,10 @@ * @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 ); @@ -32,8 +36,8 @@ define( 'NOT_REALLY_MEDIAWIKI', 1 ); $IP = __DIR__ . '/../..'; -require_once( "$IP/includes/Defines.php" ); -require_once( "$IP/languages/Language.php" ); +require_once "$IP/includes/Defines.php"; +require_once "$IP/languages/Language.php"; $files = array(); foreach ( $argv as $arg ) { @@ -53,7 +57,7 @@ foreach ( $files as $filename ) { } function getVars( $filename ) { - require( $filename ); + require $filename; $vars = get_defined_vars(); unset( $vars['filename'] ); return $vars; diff --git a/maintenance/language/writeMessagesArray.inc b/maintenance/language/writeMessagesArray.inc index b2e04c7f..fc0da3f5 100644 --- a/maintenance/language/writeMessagesArray.inc +++ b/maintenance/language/writeMessagesArray.inc @@ -50,25 +50,27 @@ class MessageWriter { $sortedMessages = $messages[1]; # Write to the file - if ( $messagesFolder ) + if ( $messagesFolder ) { $filename = Language::getFileName( "$messagesFolder/Messages", $code ); - else + } else { $filename = Language::getMessagesFileName( $code ); + } - if ( file_exists( $filename ) ) + if ( file_exists( $filename ) ) { $contents = file_get_contents( $filename ); - else + } else { $contents = '<?php $messages = array( ); '; + } - if( strpos( $contents, '$messages' ) !== false ) { + if ( strpos( $contents, '$messages' ) !== false ) { $contents = explode( '$messages', $contents ); - if( $messagesText == '$messages' . $contents[1] ) { + if ( $messagesText == '$messages' . $contents[1] ) { echo "Generated messages for language $code. Same as the current file.\n"; } else { - if( $write ) { + if ( $write ) { $new = $contents[0]; $new .= $messagesText; file_put_contents( $filename, $new ); @@ -77,12 +79,13 @@ $messages = array( 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 ) + if ( $listUnknown && isset( $sortedMessages['unknown'] ) && !empty( $sortedMessages['unknown'] ) ) { + if ( $removeUnknown ) { echo "\nThe following " . count( $sortedMessages['unknown'] ) . " unknown messages have been removed:\n"; - else + } else { echo "\nThere are " . count( $sortedMessages['unknown'] ) . " unknown messages, please check them:\n"; - foreach( $sortedMessages['unknown'] as $key => $value ) { + } + foreach ( $sortedMessages['unknown'] as $key => $value ) { echo "* " . $key . "\n"; } } @@ -107,22 +110,22 @@ $messages = array( # Load messages $dir = $prefix ? $prefix : __DIR__; - require( $dir . '/messages.inc' ); + require $dir . '/messages.inc'; self::$messageStructure = $wgMessageStructure; self::$blockComments = $wgBlockComments; - require( $dir . '/messageTypes.inc' ); + require $dir . '/messageTypes.inc'; self::$ignoredMessages = $wgIgnoredMessages; self::$optionalMessages = $wgOptionalMessages; # Sort messages to blocks $sortedMessages['unknown'] = $messages; - foreach( self::$messageStructure as $blockName => $block ) { + foreach ( self::$messageStructure as $blockName => $block ) { /** * @var $block array */ - foreach( $block as $key ) { - if( array_key_exists( $key, $sortedMessages['unknown'] ) ) { + foreach ( $block as $key ) { + if ( array_key_exists( $key, $sortedMessages['unknown'] ) ) { $sortedMessages[$blockName][$key] = $sortedMessages['unknown'][$key]; unset( $sortedMessages['unknown'][$key] ); } @@ -132,13 +135,13 @@ $messages = array( # Write all the messages $messagesText = "\$messages = array( "; - foreach( $sortedMessages as $block => $messages ) { + foreach ( $sortedMessages as $block => $messages ) { # Skip if it's the block of unknown messages - handle that in the end of file - if( $block == 'unknown' ) { + if ( $block == 'unknown' ) { continue; } - if( $ignoredComments ) { + if ( $ignoredComments ) { $ignored = self::$ignoredMessages; $optional = self::$optionalMessages; } else { @@ -175,10 +178,10 @@ $messages = array( $commentArray = array(); # List of keys only - foreach( $messages as $key ) { - if( in_array( $key, $ignored ) ) { + foreach ( $messages as $key ) { + if ( in_array( $key, $ignored ) ) { $commentArray[$key] = ' # ' . self::$ignoredComment; - } elseif( in_array( $key, $optional ) ) { + } elseif ( in_array( $key, $optional ) ) { $commentArray[$key] = ' # ' . self::$optionalComment; } } @@ -202,13 +205,13 @@ $messages = array( $blockText = ''; # Skip the block if it includes no messages - if( empty( $messages ) ) { + if ( empty( $messages ) ) { return ''; } # Format the block comment (if exists); check for multiple lines comments - if( !empty( $blockComment ) ) { - if( strpos( $blockComment, "\n" ) === false ) { + if ( !empty( $blockComment ) ) { + if ( strpos( $blockComment, "\n" ) === false ) { $blockText .= "$prefix# $blockComment "; } else { @@ -223,7 +226,7 @@ $blockComment $maxKeyLength = max( array_map( 'strlen', array_keys( $messages ) ) ); # Format the messages - foreach( $messages as $key => $value ) { + foreach ( $messages as $key => $value ) { # Add the key name $blockText .= "$prefix'$key'"; @@ -241,16 +244,16 @@ $blockComment $single = "'"; $double = '"'; - if( strpos( $value, $single ) === false ) { + 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) ) { + $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; + $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 ) { + if ( $quote === $double ) { $extra = '$'; } else { $extra = ''; @@ -262,7 +265,7 @@ $blockComment $blockText .= ','; # Add comments, if there is any - if( array_key_exists( $key, $messageComments ) ) { + if ( array_key_exists( $key, $messageComments ) ) { $blockText .= $messageComments[$key]; } diff --git a/maintenance/language/zhtable/Makefile b/maintenance/language/zhtable/Makefile new file mode 100644 index 00000000..9d3637fc --- /dev/null +++ b/maintenance/language/zhtable/Makefile @@ -0,0 +1,2 @@ +../../../includes/ZhConversion.php: Makefile.py $(wildcard *.manual) + ./Makefile.py diff --git a/maintenance/language/zhtable/Makefile.py b/maintenance/language/zhtable/Makefile.py new file mode 100644 index 00000000..7e197945 --- /dev/null +++ b/maintenance/language/zhtable/Makefile.py @@ -0,0 +1,391 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# @author Philip +import tarfile as tf +import zipfile as zf +import os, re, shutil, sys, platform + +pyversion = platform.python_version() +islinux = platform.system().lower() == 'linux' + +if pyversion[:3] in ['2.6', '2.7']: + import urllib as urllib_request + import codecs + open = codecs.open + _unichr = unichr + if sys.maxunicode < 0x10000: + def unichr(i): + if i < 0x10000: + return _unichr(i) + else: + return _unichr( 0xD7C0 + ( i>>10 ) ) + _unichr( 0xDC00 + ( i & 0x3FF ) ) +elif pyversion[:2] == '3.': + import urllib.request as urllib_request + unichr = chr + +def unichr2( *args ): + return [unichr( int( i.split('<')[0][2:], 16 ) ) for i in args] + +def unichr3( *args ): + return [unichr( int( i[2:7], 16 ) ) for i in args if i[2:7]] + +# DEFINE +UNIHAN_VER = '6.2.0' +SF_MIRROR = 'dfn' +SCIM_TABLES_VER = '0.5.11' +SCIM_PINYIN_VER = '0.5.92' +LIBTABE_VER = '0.2.3' +# END OF DEFINE + +def download( url, dest ): + if os.path.isfile( dest ): + print( 'File %s is up to date.' % dest ) + return + global islinux + if islinux: + # we use wget instead urlretrieve under Linux, + # because wget could display details like download progress + os.system( 'wget %s -O %s' % ( url, dest ) ) + else: + print( 'Downloading from [%s] ...' % url ) + urllib_request.urlretrieve( url, dest ) + print( 'Download complete.\n' ) + return + +def uncompress( fp, member, encoding = 'U8' ): + name = member.rsplit( '/', 1 )[-1] + print( 'Extracting %s ...' % name ) + fp.extract( member ) + shutil.move( member, name ) + if '/' in member: + shutil.rmtree( member.split( '/', 1 )[0] ) + return open( name, 'rb', encoding, 'ignore' ) + +unzip = lambda path, member, encoding = 'U8': \ + uncompress( zf.ZipFile( path ), member, encoding ) + +untargz = lambda path, member, encoding = 'U8': \ + uncompress( tf.open( path, 'r:gz' ), member, encoding ) + +def parserCore( fp, pos, beginmark = None, endmark = None ): + if beginmark and endmark: + start = False + else: start = True + mlist = set() + for line in fp: + if beginmark and line.startswith( beginmark ): + start = True + continue + elif endmark and line.startswith( endmark ): + break + if start and not line.startswith( '#' ): + elems = line.split() + if len( elems ) < 2: + continue + elif len( elems[0] ) > 1 and \ + len( elems[pos] ) > 1: # words only + mlist.add( elems[pos] ) + return mlist + +def tablesParser( path, name ): + """ Read file from scim-tables and parse it. """ + global SCIM_TABLES_VER + src = 'scim-tables-%s/tables/zh/%s' % ( SCIM_TABLES_VER, name ) + fp = untargz( path, src, 'U8' ) + return parserCore( fp, 1, 'BEGIN_TABLE', 'END_TABLE' ) + +ezbigParser = lambda path: tablesParser( path, 'EZ-Big.txt.in' ) +wubiParser = lambda path: tablesParser( path, 'Wubi.txt.in' ) +zrmParser = lambda path: tablesParser( path, 'Ziranma.txt.in' ) + +def phraseParser( path ): + """ Read phrase_lib.txt and parse it. """ + global SCIM_PINYIN_VER + src = 'scim-pinyin-%s/data/phrase_lib.txt' % SCIM_PINYIN_VER + dst = 'phrase_lib.txt' + fp = untargz( path, src, 'U8' ) + return parserCore( fp, 0 ) + +def tsiParser( path ): + """ Read tsi.src and parse it. """ + src = 'libtabe/tsi-src/tsi.src' + dst = 'tsi.src' + fp = untargz( path, src, 'big5hkscs' ) + return parserCore( fp, 0 ) + +def unihanParser( path ): + """ Read Unihan_Variants.txt and parse it. """ + fp = unzip( path, 'Unihan_Variants.txt', 'U8' ) + t2s = dict() + s2t = dict() + for line in fp: + if line.startswith( '#' ): + continue + else: + elems = line.split() + if len( elems ) < 3: + continue + type = elems.pop( 1 ) + elems = unichr2( *elems ) + if type == 'kTraditionalVariant': + s2t[elems[0]] = elems[1:] + elif type == 'kSimplifiedVariant': + t2s[elems[0]] = elems[1:] + fp.close() + return ( t2s, s2t ) + +def applyExcludes( mlist, path ): + """ Apply exclude rules from path to mlist. """ + excludes = open( path, 'rb', 'U8' ).read().split() + excludes = [word.split( '#' )[0].strip() for word in excludes] + excludes = '|'.join( excludes ) + excptn = re.compile( '.*(?:%s).*' % excludes ) + diff = [mword for mword in mlist if excptn.search( mword )] + mlist.difference_update( diff ) + return mlist + +def charManualTable( path ): + fp = open( path, 'rb', 'U8' ) + ret = {} + for line in fp: + elems = line.split( '#' )[0].split( '|' ) + elems = unichr3( *elems ) + if len( elems ) > 1: + ret[elems[0]] = elems[1:] + return ret + +def toManyRules( src_table ): + tomany = set() + for ( f, t ) in src_table.iteritems(): + for i in range( 1, len( t ) ): + tomany.add( t[i] ) + return tomany + +def removeRules( path, table ): + fp = open( path, 'rb', 'U8' ) + texc = list() + for line in fp: + elems = line.split( '=>' ) + f = t = elems[0].strip() + if len( elems ) == 2: + t = elems[1].strip() + f = f.strip('"').strip("'") + t = t.strip('"').strip("'") + if f: + try: + table.pop( f ) + except: + pass + 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 ) + return table + +def customRules( path ): + fp = open( path, 'rb', 'U8' ) + ret = dict() + for line in fp: + elems = line.split( '#' )[0].split() + if len( elems ) > 1: + ret[elems[0]] = elems[1] + return ret + +def dictToSortedList( src_table, pos ): + return sorted( src_table.items(), key = lambda m: m[pos] ) + +def translate( text, conv_table ): + i = 0 + while i < len( text ): + for j in range( len( text ) - i, 0, -1 ): + f = text[i:][:j] + t = conv_table.get( f ) + if t: + text = text[:i] + t + text[i:][j:] + i += len(t) - 1 + break + i += 1 + return text + +def manualWordsTable( path, conv_table, reconv_table ): + fp = open( path, 'rb', 'U8' ) + reconv_table = {} + wordlist = [line.split( '#' )[0].strip() for line in fp] + wordlist = list( set( wordlist ) ) + wordlist.sort( key = len, reverse = True ) + while wordlist: + word = wordlist.pop() + new_word = translate( word, conv_table ) + rcv_word = translate( word, reconv_table ) + if word != rcv_word: + reconv_table[word] = word + reconv_table[new_word] = word + return reconv_table + +def defaultWordsTable( src_wordlist, src_tomany, char_conv_table, char_reconv_table ): + wordlist = list( src_wordlist ) + wordlist.sort( key = len, reverse = True ) + word_conv_table = {} + word_reconv_table = {} + conv_table = char_conv_table.copy() + reconv_table = char_reconv_table.copy() + tomanyptn = re.compile( '(?:%s)' % '|'.join( src_tomany ) ) + while wordlist: + conv_table.update( word_conv_table ) + reconv_table.update( word_reconv_table ) + word = wordlist.pop() + new_word_len = word_len = len( word ) + while new_word_len == word_len: + add = False + test_word = translate( word, reconv_table ) + new_word = translate( word, conv_table ) + if not reconv_table.get( new_word ) \ + and ( test_word != word \ + or ( tomanyptn.search( word ) \ + and word != translate( new_word, reconv_table ) ) ): + word_conv_table[word] = new_word + word_reconv_table[new_word] = word + try: + word = wordlist.pop() + except IndexError: + break + new_word_len = len(word) + return word_reconv_table + +def PHPArray( table ): + lines = ['\'%s\' => \'%s\',' % (f, t) for (f, t) in table if f and t] + return '\n'.join(lines) + +def main(): + #Get Unihan.zip: + url = 'http://www.unicode.org/Public/%s/ucd/Unihan.zip' % UNIHAN_VER + han_dest = 'Unihan.zip' + download( url, han_dest ) + + # Get scim-tables-$(SCIM_TABLES_VER).tar.gz: + url = 'http://%s.dl.sourceforge.net/sourceforge/scim/scim-tables-%s.tar.gz' % ( SF_MIRROR, SCIM_TABLES_VER ) + tbe_dest = 'scim-tables-%s.tar.gz' % SCIM_TABLES_VER + download( url, tbe_dest ) + + # Get scim-pinyin-$(SCIM_PINYIN_VER).tar.gz: + url = 'http://%s.dl.sourceforge.net/sourceforge/scim/scim-pinyin-%s.tar.gz' % ( SF_MIRROR, SCIM_PINYIN_VER ) + pyn_dest = 'scim-pinyin-%s.tar.gz' % SCIM_PINYIN_VER + download( url, pyn_dest ) + + # Get libtabe-$(LIBTABE_VER).tgz: + url = 'http://%s.dl.sourceforge.net/sourceforge/libtabe/libtabe-%s.tgz' % ( SF_MIRROR, LIBTABE_VER ) + lbt_dest = 'libtabe-%s.tgz' % LIBTABE_VER + download( url, lbt_dest ) + + # Unihan.txt + ( t2s_1tomany, s2t_1tomany ) = unihanParser( han_dest ) + + 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()] ) + + s_tomany = toManyRules( t2s_1tomany ) + t_tomany = toManyRules( s2t_1tomany ) + + # noconvert rules + t2s_1to1 = removeRules( 'trad2simp_noconvert.manual', t2s_1to1 ) + s2t_1to1 = removeRules( 'simp2trad_noconvert.manual', s2t_1to1 ) + + # the supper set for word to word conversion + t2s_1to1_supp = t2s_1to1.copy() + s2t_1to1_supp = s2t_1to1.copy() + t2s_1to1_supp.update( customRules( 'trad2simp_supp_set.manual' ) ) + s2t_1to1_supp.update( customRules( 'simp2trad_supp_set.manual' ) ) + + # word to word manual rules + t2s_word2word_manual = manualWordsTable( 'simpphrases.manual', s2t_1to1_supp, t2s_1to1_supp ) + t2s_word2word_manual.update( customRules( 'toSimp.manual' ) ) + s2t_word2word_manual = manualWordsTable( 'tradphrases.manual', t2s_1to1_supp, s2t_1to1_supp ) + s2t_word2word_manual.update( customRules( 'toTrad.manual' ) ) + + # word to word rules from input methods + t_wordlist = set() + s_wordlist = set() + t_wordlist.update( ezbigParser( tbe_dest ), + tsiParser( lbt_dest ) ) + s_wordlist.update( wubiParser( tbe_dest ), + zrmParser( tbe_dest ), + phraseParser( pyn_dest ) ) + + # exclude + s_wordlist = applyExcludes( s_wordlist, 'simpphrases_exclude.manual' ) + t_wordlist = applyExcludes( t_wordlist, 'tradphrases_exclude.manual' ) + + s2t_supp = s2t_1to1_supp.copy() + s2t_supp.update( s2t_word2word_manual ) + t2s_supp = t2s_1to1_supp.copy() + t2s_supp.update( t2s_word2word_manual ) + + # parse list to dict + t2s_word2word = defaultWordsTable( s_wordlist, s_tomany, s2t_1to1_supp, t2s_supp ) + t2s_word2word.update( t2s_word2word_manual ) + s2t_word2word = defaultWordsTable( t_wordlist, t_tomany, t2s_1to1_supp, s2t_supp ) + s2t_word2word.update( s2t_word2word_manual ) + + # Final tables + # sorted list toHans + t2s_1to1 = dict( [( f, t ) for ( f, t ) in t2s_1to1.iteritems() 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] ) + toHant = dictToSortedList( s2t_1to1, 0 ) + dictToSortedList( s2t_word2word, 1 ) + # sorted list toCN + toCN = dictToSortedList( customRules( 'toCN.manual' ), 1 ) + # sorted list toHK + toHK = dictToSortedList( customRules( 'toHK.manual' ), 1 ) + # sorted list toSG + toSG = dictToSortedList( customRules( 'toSG.manual' ), 1 ) + # sorted list toTW + toTW = dictToSortedList( customRules( 'toTW.manual' ), 1 ) + + # Get PHP Array + php = '''<?php +/** + * Simplified / Traditional Chinese conversion tables + * + * Automatically generated using code and data in includes/zhtable/ + * Do not modify directly! + * + * @file + */ + +$zh2Hant = array(\n''' + php += PHPArray( toHant ) \ + + '\n);\n\n$zh2Hans = array(\n' \ + + PHPArray( toHans ) \ + + '\n);\n\n$zh2TW = array(\n' \ + + PHPArray( toTW ) \ + + '\n);\n\n$zh2HK = array(\n' \ + + PHPArray( toHK ) \ + + '\n);\n\n$zh2CN = array(\n' \ + + PHPArray( toCN ) \ + + '\n);\n\n$zh2SG = array(\n' \ + + PHPArray( toSG ) \ + + '\n);\n' + + f = open( os.path.join( '..', '..', '..', 'includes', 'ZhConversion.php' ), 'wb', encoding = 'utf8' ) + print ('Writing ZhConversion.php ... ') + f.write( php ) + f.close() + + # Remove temporary files + print ('Deleting temporary files ... ') + os.remove('EZ-Big.txt.in') + os.remove('phrase_lib.txt') + os.remove('tsi.src') + os.remove('Unihan_Variants.txt') + os.remove('Wubi.txt.in') + os.remove('Ziranma.txt.in') + + +if __name__ == '__main__': + main() diff --git a/maintenance/language/zhtable/README b/maintenance/language/zhtable/README new file mode 100644 index 00000000..7e3f87e2 --- /dev/null +++ b/maintenance/language/zhtable/README @@ -0,0 +1,33 @@ +The various .manual files contains special mappings not included in the +unihan database, and phrases not included in the SCIM package. + +- simp2trad.manual: Simplified to Traditional character mapping. Most + data adapted from + + 冯寿忠,“非对称繁简字”对照表, 《语文建设通讯》1997-9第53期. + /http://www.yywzw.com/jt/feng/fengb01.htm + +- trad2simp.manual: Traditional to Simplified character mapping. + +- simp2trad_noconvert.manual: Do not convert the chars as inapporiate. + +- trad2simp_noconvert.manual: Do not convert the chars as inapporiate. + +- tradphrases.manual: Phrases in Traditional Chinese. A portition is obtained + from the TongWen package (http://tongwen.mozdev.org/) + +- simpphrases.manual: Phrases in Simplified Chinese. + +- tradphrases_exclude.manual: Excluding several phrases from + the SCIM phrases as inappoiated. + +- simpphrases_exclude.manual: Excluding several phrases from + the SCIM phrases as inapporated. + +- toTrad.manual, toSimp.manual: Special phrase mappings that + tradphrases.manual or simphrases.manual cannot be handled. + +- toTW.manual, toCN.manual, toSG.manual and toHK.manual: Special phrase + mappings. + +zhengzhu at gmail dot com & shinjiman at gmail dot com diff --git a/maintenance/language/zhtable/simp2trad.manual b/maintenance/language/zhtable/simp2trad.manual new file mode 100644 index 00000000..1b84f8e7 --- /dev/null +++ b/maintenance/language/zhtable/simp2trad.manual @@ -0,0 +1,372 @@ +U+03CE0㳠|U+06FBE澾| +U+0447D䑽|U+26A99𦪙| +U+0497A䥺|U+091FE釾| +U+0497D䥽|U+093FA鏺| +U+04983䦃|U+0942F鐯| +U+04985䦅|U+09425鐥| +U+04B6A䭪|U+297AF𩞯| +U+04C9F䲟|U+09BA3鮣| +U+04CA0䲠|U+09C06鰆| +U+04CA1䲡|U+09C0C鰌| +U+04CA2䲢|U+09C27鰧| +U+04CA3䲣|U+04C77䱷| +U+04DAE䶮|U+09F91龑| +U+04E07万|U+0842C萬|U+04E07万| +U+04E0E与|U+08207與|U+04E0E与| +U+04E11丑|U+04E11丑|U+0919C醜| +U+04E2A个|U+0500B個|U+07B87箇| +U+04E30丰|U+08C50豐|U+04E30丰| +U+04E3A为|U+070BA為|U+07232爲| +U+04E48么|U+04E48么|U+09EBD麽|U+05E7A幺|U+09EBC麼| +U+04E86了|U+04E86了|U+077AD瞭| +U+04E8E于|U+065BC於|U+04E8E于| +U+04E91云|U+096F2雲|U+04E91云| +U+04EA7产|U+07522產|U+07523産| +U+04EC6仆|U+04EC6仆|U+050D5僕| +U+04EC7仇|U+04EC7仇|U+08B8E讎| +U+04ED1仑|U+04F96侖|U+05D19崙| +U+04EF7价|U+050F9價|U+04EF7价| +U+04F17众|U+0773E眾|U+08846衆| +U+04F19伙|U+04F19伙|U+05925夥| +U+04F2A伪|U+0507D偽|U+050DE僞| +U+04F53体|U+09AD4體|U+04F53体| +U+04F59余|U+04F59余|U+09918餘| +U+04F63佣|U+04F63佣|U+050AD傭| +U+0501F借|U+0501F借|U+085C9藉| +U+0513F儿|U+05152兒|U+0513F儿| +U+0514B克|U+0514B克|U+0524B剋| +U+0515A党|U+09EE8黨|U+0515A党| +U+051AC冬|U+051AC冬|U+09F15鼕| +U+051B2冲|U+06C96沖|U+0885D衝| +U+051C6准|U+051C6准|U+06E96準| +U+051E0几|U+05E7E幾|U+051E0几| +U+051EB凫|U+09CE7鳧|U+09CEC鳬| +U+051FA出|U+051FA出|U+09F63齣| +U+05212划|U+05283劃|U+05212划| +U+0522B别|U+05225別|U+05F46彆| +U+0522E刮|U+0522E刮|U+098B3颳| +U+05236制|U+05236制|U+088FD製| +U+05343千|U+05343千|U+097C6韆| +U+05347升|U+05347升|U+06607昇|U+0965E陞| +U+0535C卜|U+0535C卜|U+08514蔔| +U+05360占|U+05360占|U+04F54佔| +U+05364卤|U+09E75鹵|U+06EF7滷| +U+05377卷|U+05377卷|U+06372捲| +U+0537A卺|U+05DF9巹| +U+05382厂|U+05EE0廠|U+05382厂| +U+05386历|U+06B77歷|U+066C6曆|U+053A4厤| +U+05395厕|U+05EC1廁|U+053A0厠| +U+05398厘|U+05398厘|U+091D0釐| +U+053D1发|U+0767C發|U+09AEE髮| +U+053EA只|U+053EA只|U+096BB隻| +U+053F0台|U+053F0台|U+081FA臺|U+06AAF檯|U+098B1颱| +U+053F6叶|U+08449葉|U+053F6叶| +U+05401吁|U+05401吁|U+07C72籲| +U+05408合|U+05408合|U+095A4閤| +U+0540A吊|U+0540A吊|U+05F14弔| +U+0540C同|U+0540C同|U+08855衕| +U+0540E后|U+05F8C後|U+0540E后| +U+05411向|U+05411向|U+056AE嚮|U+066CF曏| +U+0542F启|U+0555F啟|U+05553啓| +U+05446呆|U+05446呆|U+07343獃| +U+054B8咸|U+054B8咸|U+09E79鹹| +U+054C4哄|U+054C4哄|U+09B28鬨| +U+05582喂|U+05582喂|U+09935餵| +U+056DE回|U+056DE回|U+08FF4迴| +U+056E2团|U+05718團|U+07CF0糰| +U+056F0困|U+056F0困|U+0774F睏| +U+05742坂|U+05742坂|U+0962A阪| +U+0574F坏|U+058DE壞|U+0574F坏| +U+0575B坛|U+058C7壇|U+07F48罈| +U+057FC埼|U+057FC埼|U+07895碕| +U+05899墙|U+07246牆|U+058BB墻| +U+058F3壳|U+06BBC殼|U+06BBB殻| +U+0590D复|U+05FA9復|U+08907複| +U+05956奖|U+0734E獎|U+0596C奬| +U+05978奸|U+05978奸|U+059E6姦| +U+059AB妫|U+05AAF媯|U+05B00嬀| +U+059DC姜|U+059DC姜|U+08591薑| +U+05B81宁|U+05BE7寧|U+05B81宁| +U+05BB6家|U+05BB6家|U+050A2傢| +U+05C3D尽|U+076E1盡|U+05118儘| +U+05CB3岳|U+05CB3岳|U+05DBD嶽| +U+05E03布|U+05E03布|U+04F48佈| +U+05E18帘|U+07C3E簾|U+05E18帘| +U+05E5E幞|U+08946襆| +U+05E72干|U+05E72干|U+04E7E乾|U+05E79幹|U+069A6榦| +U+05E76并|U+04E26並|U+04F75併| +U+05E78幸|U+05E78幸|U+05016倖| +U+05E7F广|U+05EE3廣|U+05E7F广| +U+05E84庄|U+05E84庄|U+0838A莊| +U+05EB5庵|U+05EB5庵|U+083F4菴| +U+05F25弥|U+05F4C彌|U+07030瀰| +U+05F53当|U+07576當|U+05679噹| +U+05F55录|U+09304錄|U+09332録| +U+05F69彩|U+05F69彩|U+07DB5綵| +U+05F81征|U+05F81征|U+05FB5徵| +U+05FA1御|U+05FA1御|U+079A6禦| +U+05FD7志|U+05FD7志|U+08A8C誌| +U+06076恶|U+060E1惡|U+05641噁| +U+060AB悫|U+06128愨|U+06164慤| +U+0613F愿|U+09858願|U+0613F愿| +U+0621A戚|U+0621A戚|U+0617C慼|U+093DA鏚| +U+0624D才|U+0624D才|U+07E94纔| +U+0624E扎|U+0624E扎|U+07D2E紮| +U+06258托|U+06258托|U+08A17託| +U+06298折|U+06298折|U+0647A摺| +U+062C5担|U+064D4擔|U+062C5担| +U+062FC拼|U+062FC拼|U+062DA拚| +U+06328挨|U+06328挨|U+06371捱| +U+0633D挽|U+0633D挽|U+08F13輓| +U+0636E据|U+064DA據|U+0636E据| +U+06597斗|U+06597斗|U+09B25鬥| +U+065CB旋|U+065CB旋|U+0955F镟| +U+065D7旗|U+065D7旗|U+065C2旂| +U+066F2曲|U+066F2曲|U+09EAF麯|U+09EB4麯| +U+0672F术|U+08853術|U+0672E朮| +U+06731朱|U+06731朱|U+07843硃| +U+06734朴|U+06734朴|U+06A38樸| +U+0676F杯|U+0676F杯|U+076C3盃| +U+0677E松|U+0677E松|U+09B06鬆| +U+0677F板|U+0677F板|U+095C6闆| +U+06781极|U+06975極|U+06781极| +U+067DC柜|U+06AC3櫃|U+067DC柜| +U+06817栗|U+06817栗|U+06144慄| +U+06881梁|U+06881梁|U+06A11樑| +U+068F1棱|U+068F1棱|U+07A1C稜| +U+06B32欲|U+06B32欲|U+0617E慾| +U+06C47汇|U+0532F匯|U+06ED9滙|U+05F59彙| +U+06C84沄|U+06C84沄|U+06F90澐| +U+06C88沈|U+06C88沈|U+0700B瀋| +U+06CA9沩|U+06E88溈|U+06F59潙| +U+06CE8注|U+06CE8注|U+08A3B註| +U+06D82涂|U+05857塗|U+06D82涂| +U+06D8C涌|U+06D8C涌|U+06E67湧| +U+06DC0淀|U+06DC0淀|U+06FB1澱| +U+06E38游|U+06E38游|U+0904A遊| +U+06EAF溯|U+06EAF溯|U+06CDD泝| +U+06F13漓|U+06F13漓|U+07055灕| +U+070BC炼|U+07149煉|U+0934A鍊| +U+0753B画|U+0756B畫|U+07575畵| +U+075C7症|U+075C7症|U+07665癥| +U+07618瘘|U+0763A瘺|U+0763B瘻| +U+0786E确|U+078BA確|U+0786E确| +U+07877硷|U+07906礆|U+09E7C鹼| +U+079CB秋|U+079CB秋|U+097A6鞦| +U+079CD种|U+07A2E種|U+079CD种| +U+07A57穗|U+07A57穗|U+07E50繐| +U+07AD6竖|U+08C4E豎|U+07AEA竪| +U+07B51筑|U+07BC9築|U+07B51筑| +U+07B7E签|U+07C3D簽|U+07C64籤| +U+07CFB系|U+07CFB系|U+07E6B繫|U+04FC2係| +U+07D2F累|U+07D2F累|U+07E8D纍| +U+07EA4纤|U+07E96纖|U+07E34縴| +U+07EBF线|U+07DDA線|U+07DAB綫| +U+07EDD绝|U+07D55絕|U+07D76絶| +U+07EE3绣|U+07D89綉|U+07E61繡| +U+07EE6绦|U+07D5B絛|U+07E27縧| +U+07EF1绱|U+07DD4緔|U+0979D鞝| +U+07EF7绷|U+07DB3綳|U+07E43繃| +U+07EFF绿|U+07DA0綠|U+07DD1緑| +U+07F30缰|U+097C1韁|U+07E6E繮| +U+07FA1羡|U+07FA8羨| +U+080DC胜|U+052DD勝|U+080DC胜| +U+080E1胡|U+080E1胡|U+09B0D鬍|U+0885A衚| +U+0810F脏|U+081DF臟|U+09AD2髒| +U+0814A腊|U+081D8臘|U+0814A腊| +U+081F4致|U+081F4致|U+07DFB緻| +U+0820D舍|U+0820D舍|U+06368捨| +U+082B8芸|U+082B8芸|U+08553蕓| +U+082CE苎|U+082E7苧| +U+082CF苏|U+08607蘇|U+056CC囌|U+07C64甦| +U+082E7苧|U+085B4薴| +U+082F9苹|U+0860B蘋|U+082F9苹| +U+08303范|U+08303范|U+07BC4範| +U+0836F药|U+0846F葯|U+085E5藥| +U+083B7获|U+07372獲|U+07A6B穫| +U+083BC莼|U+08493蒓|U+084F4蓴| +U+08499蒙|U+08499蒙|U+077C7矇|U+06FDB濛|U+061DE懞| +U+084D1蓑|U+084D1蓑|U+07C11簑| +U+08511蔑|U+08511蔑|U+0884A衊| +U+08574蕴|U+0860A蘊|U+085F4藴| +U+0866B虫|U+087F2蟲|U+0866B虫| +U+08721蜡|U+0881F蠟|U+08721蜡| +U+0874E蝎|U+0880D蠍| +U+08868表|U+08868表|U+09336錶| +U+08BF4说|U+08AAA說|U+08AAC説| +U+08C23谣|U+08B20謠|U+08B21謡| +U+08C2B谫|U+08B7E譾|U+08B2D謭| +U+08C37谷|U+08C37谷|U+07A40穀| +U+08D43赃|U+08D13贓|U+08D1C贜| +U+08D4D赍|U+09F4E齎|U+08CEB賫| +U+08D5D赝|U+08D17贗|U+08D0B贋| +U+08D5E赞|U+08D0A贊|U+08B9A讚| +U+08F9F辟|U+08F9F辟|U+095E2闢| +U+09002适|U+09069適|U+09002适| +U+090C1郁|U+090C1郁|U+09B31鬱| +U+0915D酝|U+0919E醞|U+09196醖| +U+09170酰|U+09170酰|U+091AF醯| +U+09178酸|U+09178酸|U+075E0痠| +U+091C7采|U+091C7采|U+063A1採|U+057F0埰| +U+091CC里|U+091CC里|U+088E1裡|U+088CF裏| +U+093AD鎭|U+093AE鎮| +U+0949F钟|U+0937E鍾|U+09418鐘| +U+094A9钩|U+09264鉤|U+0920E鈎| +U+094B5钵|U+07F3D缽|U+09262鉢| +U+094F2铲|U+093DF鏟|U+05277剷| +U+09508锈|U+092B9銹|U+093FD鏽| +U+09510锐|U+092B3銳|U+092ED鋭| +U+09528锨|U+06774杴|U+09341鍁| +U+0954C镌|U+0942B鐫|U+093B8鎸| +U+09562镢|U+09481钁|U+0941D鐝| +U+09605阅|U+095B1閱|U+095B2閲| +U+096C7雇|U+096C7雇|U+050F1僱| +U+096D5雕|U+096D5雕|U+09D70鵰| +U+09709霉|U+09709霉|U+09EF4黴| +U+09762面|U+09762面|U+09EB5麵|U+09EAA麪|U+09EAB麫| +U+097B2鞲|U+097DD韝| +U+0987B须|U+09808須|U+09B1A鬚| +U+09893颓|U+09839頹|U+0983D頽| +U+0989C颜|U+0984F顏|U+09854顔| +U+09965饥|U+098E2飢|U+09951饑| +U+09980馀|U+09918餘| +U+09986馆|U+09928館|U+08218舘| +U+09A82骂|U+07F75罵|U+099E1駡| +U+09C87鲇|U+09BF0鯰|U+09B8E鮎| +U+09C9E鲞|U+09BD7鯗|U+09B9D鮝| +U+09CC4鳄|U+09C77鱷|U+09C10鰐| +U+09E21鸡|U+096DE雞|U+09DC4鷄| +U+09E5A鹚|U+09DBF鶿|U+09DC0鷀| +U+09E6E鹮|U+04D09䴉| +U+09F44齄|U+09F47齇| +U+20BB6𠮶|U+055F0嗰| +U+26216𦈖|U+04308䌈| +U+28C3E𨰾|U+093B7鎷| +U+28C3F𨰿|U+091F3釳| +U+28C40𨱀|U+2895B𨥛| +U+28C41𨱁|U+09220鈠| +U+28C42𨱂|U+0920B鈋| +U+28C43𨱃|U+09232鈲| +U+28C44𨱄|U+0922F鈯| +U+28C45𨱅|U+09241鉁| +U+28C47𨱇|U+092B6銶| +U+28C48𨱈|U+092C9鋉| +U+28C49𨱉|U+09344鍄| +U+28C4A𨱊|U+289F1𨧱| +U+28C4B𨱋|U+09302錂| +U+28C4C𨱌|U+093C6鏆| +U+28C4D𨱍|U+093AF鎯| +U+28C4E𨱎|U+0936E鍮| +U+28C4F𨱏|U+0939D鎝| +U+28C50𨱐|U+28AD2𨫒| +U+28C52𨱒|U+093C9鏉| +U+28C53𨱓|U+0940E鐎| +U+28C54𨱔|U+0940F鐏| +U+28C55𨱕|U+28B82𨮂| +U+28E02𨸂|U+0958D閍| +U+28E03𨸃|U+09590閐| +U+293FC𩏼|U+04A8F䪏| +U+293FD𩏽|U+293EA𩏪| +U+293FE𩏾|U+293A2𩎢| +U+293FF𩏿|U+04A98䪘| +U+29400𩐀|U+04A97䪗| +U+29595𩖕|U+294E3𩓣| +U+29596𩖖|U+09843顃| +U+29597𩖗|U+04AF4䫴| +U+29665𩙥|U+098B0颰| +U+29666𩙦|U+295C0𩗀| +U+29667𩙧|U+295E1𩗡| +U+29668𩙨|U+29639𩘹| +U+29669𩙩|U+29600𩘀| +U+2966A𩙪|U+098B7颷| +U+2966B𩙫|U+098BE颾| +U+2966C𩙬|U+2963A𩘺| +U+2966D𩙭|U+2961D𩘝| +U+2966E𩙮|U+04B18䬘| +U+2966F𩙯|U+04B1D䬝| +U+29670𩙰|U+29648𩙈| +U+29805𩠅|U+297D0𩟐| +U+29806𩠆|U+29726𩜦| +U+29807𩠇|U+04B40䭀| +U+29808𩠈|U+04B43䭃| +U+2980B𩠋|U+29754𩝔| +U+2980C𩠌|U+09938餸| +U+299E6𩧦|U+2987A𩡺| +U+299E8𩧨|U+099CE駎| +U+299E9𩧩|U+2990A𩤊| +U+299EA𩧪|U+04BBE䮾| +U+299EB𩧫|U+099DA駚| +U+299EC𩧬|U+298A1𩢡| +U+299ED𩧭|U+04B7F䭿| +U+299EE𩧮|U+298BE𩢾| +U+299EF𩧯|U+09A4B驋| +U+299F0𩧰|U+04B9D䮝| +U+299F1𩧱|U+29949𩥉| +U+299F2𩧲|U+099E7駧| +U+299F3𩧳|U+298B8𩢸| +U+299F4𩧴|U+099E9駩| +U+299F5𩧵|U+298B4𩢴| +U+299F6𩧶|U+298CF𩣏| +U+299FA𩧺|U+099F6駶| +U+299FB𩧻|U+298F5𩣵| +U+299FC𩧼|U+298FA𩣺| +U+299FF𩧿|U+04BA0䮠| +U+29A00𩨀|U+09A14騔| +U+29A01𩨁|U+04B9E䮞| +U+29A03𩨃|U+09A1D騝| +U+29A04𩨄|U+09A2A騪| +U+29A05𩨅|U+29938𩤸| +U+29A06𩨆|U+29919𩤙| +U+29A08𩨈|U+09A1F騟| +U+29A09𩨉|U+29932𩤲| +U+29A0A𩨊|U+09A1A騚| +U+29A0B𩨋|U+29944𩥄| +U+29A0C𩨌|U+29951𩥑| +U+29A0D𩨍|U+29947𩥇| +U+29A0F𩨏|U+04BB3䮳| +U+29A10𩨐|U+299C6𩧆| +U+29F79𩽹|U+09B65魥| +U+29F7A𩽺|U+29D69𩵩| +U+29F7B𩽻|U+29D79𩵹| +U+29F7C𩽼|U+09BF6鯶| +U+29F7D𩽽|U+29DB1𩶱| +U+29F7E𩽾|U+09B9F鮟| +U+29F7F𩽿|U+29DB0𩶰| +U+29F80𩾀|U+09B95鮕| +U+29F81𩾁|U+09BC4鯄| +U+29F83𩾃|U+09BB8鮸| +U+29F84𩾄|U+29DF0𩷰| +U+29F85𩾅|U+29E03𩸃| +U+29F86𩾆|U+29E26𩸦| +U+29F87𩾇|U+09BF1鯱| +U+29F88𩾈|U+04C59䱙| +U+29F8A𩾊|U+04C6C䱬| +U+29F8B𩾋|U+04C70䱰| +U+29F8C𩾌|U+09C47鱇| +U+29F8C𩾌|U+09C47鱇| +U+29F8E𩾎|U+29F47𩽇| +U+2A242𪉂|U+04CB0䲰| +U+2A243𪉃|U+09CFC鳼| +U+2A244𪉄|U+29FEA𩿪| +U+2A245𪉅|U+2A026𪀦| +U+2A246𪉆|U+09D32鴲| +U+2A248𪉈|U+09D1C鴜| +U+2A249𪉉|U+2A048𪁈| +U+2A24A𪉊|U+09DE8鷨| +U+2A24B𪉋|U+2A03E𪀾| +U+2A24C𪉌|U+2A056𪁖| +U+2A24D𪉍|U+09D5A鵚| +U+2A24E𪉎|U+2A086𪂆| +U+2A24F𪉏|U+2A0CF𪃏| +U+2A250𪉐|U+2A0CD𪃍| +U+2A251𪉑|U+09DD4鷔| +U+2A252𪉒|U+2A115𪄕| +U+2A254𪉔|U+2A106𪄆| +U+2A255𪉕|U+2A1F3𪇳| +U+2A388𪎈|U+04D2C䴬| +U+2A389𪎉|U+09EB2麲| +U+2A38A𪎊|U+09EA8麨| +U+2A38B𪎋|U+04D34䴴| +U+2A38C𪎌|U+09EB3麳| +U+2A68F𪚏|U+2A600𪘀| +U+2A690𪚐|U+2A62F𪘯| diff --git a/maintenance/language/zhtable/simp2trad_noconvert.manual b/maintenance/language/zhtable/simp2trad_noconvert.manual new file mode 100644 index 00000000..a46560a7 --- /dev/null +++ b/maintenance/language/zhtable/simp2trad_noconvert.manual @@ -0,0 +1,139 @@ +著 +竈 +彞 +=>"余" +=>"𫗭" +=>"𪨧" +=>"𫚭" +=>"𫔀" +=>"𫊻" +=>"𫋌" +=>"蚃" +=>"𩾂" +=>"𫚜" +=>"𫚢" +=>"𧉰" +=>"䙌" +=>"𫊮" +=>"𫋇" +=>"𫉄" +=>"𫘛" +=>"𫘜" +=>"𫘝" +=>"𫘟" +=>"𩧨" +=>"𩧫" +=>"𫘞" +=>"𫘠" +=>"𩧲" +=>"𩧴" +=>"𫘡" +=>"𩧺" +=>"𫘣" +=>"𫘤" +=>"𫘧" +=>"𫘥" +=>"𫘦" +=>"𩨀" +=>"𩨊" +=>"𫘩" +=>"𩨃" +=>"𫘪" +=>"𫘪" +=>"𫘫" +=>"𫘬" +=>"𩨈" +=>"𫘨" +=>"𩨄" +=>"𫘭" +=>"𩧯" +=>"𫘯" +=>"𫘰" +=>"𫘱" +=>"𫘽" +=>"𫚉" +=>"𩽹" +=>"𫚌" +=>"𫚍" +=>"𫚒" +=>"𫚑" +=>"𫚖" +=>"𩽾" +=>"䲟" +=>"𫚓" +=>"𫚗" +=>"𫚔" +=>"𫚛" +=>"𩾃" +=>"𫚚" +=>"𩾁" +=>"𫚙" +=>"𫚡" +=>"𫚞" +=>"𩾇" +=>"𩽼" +=>"𫚣" +=>"䲠" +=>"䲡" +=>"𫚊" +=>"𫚥" +=>"𫚕" +=>"𫚤" +=>"䲢" +=>"𫚦" +=>"𫚧" +=>"𫚋" +=>"𩾌" +=>"𫚪" +=>"𫚫" +=>"𫚈" +=>"𫚭" +=>"𫛛" +=>"𪉃" +=>"𫛚" +=>"𫛜" +=>"𫛞" +=>"𫛝" +=>"𫛤" +=>"𫛡" +=>"𫁡" +=>"𪉈" +=>"𫛣" +=>"𫛦" +=>"𪉆" +=>"𫛩" +=>"𫛪" +=>"𫛥" +=>"𪉍" +=>"𫛭" +=>"𫛨" +=>"𫛳" +=>"𫛱" +=>"𫛲" +=>"𫛵" +=>"𫛶" +=>"𫛸" +=>"𫛷" +=>"𫛯" +=>"𫛫" +=>"𫛽" +=>"𫜀" +=>"𪉑" +=>"𫜃" +=>"𫛴" +=>"𪉊" +=>"𫜁" +=>"𫜄" +=>"𫛢" +=>"𫛟" +=>"𪎊" +=>"𤿲" +=>"𪎉" +=>"𪎌" +=>"𫜑" +=>"𫜩" +=>"𫜪" +=>"𫜭" +=>"𫜬" +=>"𫜮" +=>"𫜰" diff --git a/maintenance/language/zhtable/simp2trad_supp_set.manual b/maintenance/language/zhtable/simp2trad_supp_set.manual new file mode 100644 index 00000000..a5038a5d --- /dev/null +++ b/maintenance/language/zhtable/simp2trad_supp_set.manual @@ -0,0 +1,2 @@ +余 餘 +着 著
\ No newline at end of file diff --git a/maintenance/language/zhtable/simpphrases.manual b/maintenance/language/zhtable/simpphrases.manual new file mode 100644 index 00000000..d8602fec --- /dev/null +++ b/maintenance/language/zhtable/simpphrases.manual @@ -0,0 +1,2239 @@ +乾上乾下 +乾为天 +乾为阳 +乾九 +乾乾 +乾亨 +乾仪 +乾位 +乾健 +乾元 +乾光 +乾兴 +乾冈 +乾刘 +乾刚 +乾化 +乾卦 +乾县 +乾台 +乾吉 +乾启 +乾命 +乾和 +乾嘉 +乾图 +乾坤 +乾城 +乾基 +乾始 +乾姓 +乾宁 +乾宅 +乾宇 +乾安 +乾定 +乾封 +乾居 +乾岗 +乾巛 +乾州 +乾式 +乾录 +乾律 +乾德 +乾心 +乾文 +乾断 +乾方 +乾施 +乾旦 +乾明 +乾昧 +乾晖 +乾景 +乾晷 +乾曜 +乾构 +乾枢 +乾栋 +乾步 +乾氏 +乾泉 +乾清宫 +乾渥 +乾灵 +乾男 +乾皋 +乾盛世 +乾矢 +乾祐 +乾穹 +乾窦 +乾竺 +乾笃 +乾符 +乾策 +乾精 +乾红 +乾纲 +乾纽 +乾络 +乾统 +乾维 +乾罗 +乾花 +乾荫 +乾行 +乾衡 +乾覆 +乾象 +乾象历 +乾贞 +乾贶 +乾车 +乾轴 +乾造 +乾道 +乾鉴 +乾钧 +乾闼 +乾陀 +乾陵 +乾隆 +乾音 +乾顾 +乾风 +乾首 +乾马 +乾鹄 +乾鹊 +乾龙 +乾,健也 +乾,天也 +乾健也 +乾天也 +坤乾 +天道为乾 +尼乾陀 +康乾 +张法乾 +旋乾转坤 +易·乾 +《易乾 +周易乾 +易经·乾 +易经乾 +李乾德 +萧乾 +郭子乾 +雍乾 +乾务 +乾沓和 +乾沓婆 +乾通 +乾忠 +乾淳 +李乾顺 +黄润乾 +男性为乾 +男为乾 +阳为乾 +乾一组 +乾一坛 +陈乾生 +陈公乾生 +字乾生 +不着痕迹 +不着边际 +与着 +与著书 +与著作 +与著名 +与著录 +与著称 +与著者 +与著述 +丑着 +丑著书 +丑著作 +丑著名 +丑著录 +丑著称 +丑著者 +丑著述 +临着 +临著书 +临著作 +临著名 +临著录 +临著称 +临著者 +临著述 +丽着 +丽著书 +丽著作 +丽著名 +丽著录 +丽著称 +丽著者 +丽著述 +乐着 +乐著书 +乐著作 +乐著名 +乐著录 +乐著称 +乐著者 +乐著述 +乘着 +乘著书 +乘著作 +乘著名 +乘著录 +乘著称 +乘著者 +乘著述 +争着 +争著书 +争著作 +争著名 +争著录 +争著称 +争著者 +争著述 +亮着 +亮著书 +亮著作 +亮著名 +亮著录 +亮著称 +亮著者 +亮著述 +仗着 +仗著书 +仗著作 +仗著名 +仗著录 +仗著称 +仗著者 +仗著述 +代表着 +代表著书 +代表著作 +代表著名 +代表著录 +代表著称 +代表著者 +代表著述 +伴着 +伴著书 +伴著作 +伴著名 +伴著录 +伴著称 +伴著者 +伴著述 +低着 +低著书 +低著作 +低著名 +低著录 +低著称 +低著者 +低著述 +住着 +住著书 +住著作 +住著名 +住著录 +住著称 +住著者 +住著述 +侧着 +侧著书 +侧著作 +侧著名 +侧著录 +侧著称 +侧著者 +侧著述 +保障着 +保障著书 +保障著作 +保障著名 +保障著录 +保障著称 +保障著者 +保障著述 +信着 +信著书 +信著作 +信著名 +信著录 +信著称 +信著者 +信著述 +候着 +候著书 +候著作 +候著名 +候著录 +候著称 +候著者 +候著述 +借着 +借著书 +借著作 +借著名 +借著录 +借著称 +借著者 +借著述 +做着 +做著书 +做著作 +做著名 +做著录 +做著称 +做著者 +做著述 +偷着 +偷著书 +偷著作 +偷著名 +偷著录 +偷著称 +偷著者 +偷著述 +光着 +光著书 +光著作 +光著名 +光著录 +光著称 +光著者 +光著述 +关着 +关著书 +关著作 +关著名 +关著录 +关著称 +关著者 +关著述 +冀着 +冀著书 +冀著作 +冀著名 +冀著录 +冀著称 +冀著者 +冀著述 +冒着 +冒著书 +冒著作 +冒著名 +冒著录 +冒著称 +冒著者 +冒著述 +写着 +写著书 +写著作 +写著名 +写著录 +写著称 +写著者 +写著述 +凉着 +凉著书 +凉著作 +凉著名 +凉著录 +凉著称 +凉著者 +凉著述 +制着 +制著书 +制著作 +制著名 +制著录 +制著称 +制著者 +制著述 +刻着 +刻著书 +刻著作 +刻著名 +刻著录 +刻著称 +刻著者 +刻著述 +办着 +办著书 +办著作 +办著名 +办著录 +办著称 +办著者 +办著述 +动着 +动著书 +动著作 +动著名 +动著录 +动著称 +动著者 +动著述 +努力着 +努力著书 +努力著作 +努力著名 +努力著录 +努力著称 +努力著者 +努力著述 +努着 +努著书 +努著作 +努著名 +努著录 +努著称 +努著者 +努著述 +印着 +印著书 +印著作 +印著名 +印著录 +印著称 +印著者 +印著述 +压着 +压著书 +压著作 +压著名 +压著录 +压著称 +压著者 +压著述 +去着 +去著书 +去著作 +去著名 +去著录 +去著称 +去著者 +去著述 +受着 +受著书 +受著作 +受著名 +受著录 +受著称 +受著者 +受著述 +变着 +变著书 +变著作 +变著名 +变著录 +变著称 +变著者 +变著述 +叫着 +叫著书 +叫著作 +叫著名 +叫著录 +叫著称 +叫著者 +叫著述 +向着 +向著书 +向著作 +向著名 +向著录 +向著称 +向著者 +向著述 +含着 +含著书 +含著作 +含著名 +含著录 +含著称 +含著者 +含著述 +听得着 +听不着 +听着 +听著书 +听著作 +听著名 +听著录 +听著称 +听著者 +听著述 +吹着 +吹著书 +吹著作 +吹著名 +吹著录 +吹著称 +吹著者 +吹著述 +味着 +味著书 +味著作 +味著名 +味著录 +味著称 +味著者 +味著述 +响着 +响著书 +响著作 +响著名 +响著录 +响著称 +响著者 +响著述 +哭着 +哭著书 +哭著作 +哭著名 +哭著录 +哭著称 +哭著者 +哭著述 +唱着 +唱著书 +唱著作 +唱著名 +唱著录 +唱著称 +唱著者 +唱著述 +喝着 +喝著书 +喝著作 +喝著名 +喝著录 +喝著称 +喝著者 +喝著述 +嚷着 +嚷著书 +嚷著作 +嚷著名 +嚷著录 +嚷著称 +嚷著者 +嚷著述 +因着 +因著书 +因著作 +因著名 +因著录 +因著称 +因著者 +因著述 +困着 +困著书 +困著作 +困著名 +困著录 +困著称 +困著者 +困著述 +围着 +围著书 +围著作 +围著名 +围著录 +围著称 +围著者 +围著述 +在着 +在著书 +在著作 +在著名 +在著录 +在著称 +在著者 +在著述 +坐着 +坐著书 +坐著作 +坐著名 +坐著录 +坐著称 +坐著者 +坐著述 +备着 +备著书 +备著作 +备著名 +备著录 +备著称 +备著者 +备著述 +夹着 +夹著书 +夹著作 +夹著名 +夹著录 +夹著称 +夹著者 +夹著述 +孤着 +孤著书 +孤著作 +孤著名 +孤著录 +孤著称 +孤著者 +孤著述 +学着 +学著书 +学著作 +学著名 +学著录 +学著称 +学著者 +学著述 +守着 +守著书 +守著作 +守著名 +守著录 +守著称 +守著者 +守著述 +定着 +定著书 +定著作 +定著名 +定著录 +定著称 +定著者 +定著述 +对着 +对著书 +对著作 +对著名 +对著录 +对著称 +对著者 +对著述 +寻着 +寻著书 +寻著作 +寻著名 +寻著录 +寻著称 +寻著者 +寻著述 +展着 +展著书 +展著作 +展著名 +展著录 +展著称 +展著者 +展著述 +带着 +带著书 +带著作 +带著名 +带著录 +带著称 +带著者 +带著述 +帮着 +帮著书 +帮著作 +帮著名 +帮著录 +帮著称 +帮著者 +帮著述 +应着 +应著书 +应著作 +应著名 +应著录 +应著称 +应著者 +应著述 +康着 +康著书 +康著作 +康著名 +康著录 +康著称 +康著者 +康著述 +开着 +开著书 +开著作 +开著名 +开著录 +开著称 +开著者 +开著述 +当着 +当著书 +当著作 +当著名 +当著录 +当著称 +当著者 +当著述 +待着 +待著书 +待著作 +待著名 +待著录 +待著称 +待著者 +待著述 +得着 +得著书 +得著作 +得著名 +得著录 +得著称 +得著者 +得著述 +循着 +循著书 +循著作 +循著名 +循著录 +循著称 +循著者 +循著述 +心着 +心著书 +心著作 +心著名 +心著录 +心著称 +心著者 +心著述 +忍着 +忍著书 +忍著作 +忍著名 +忍著录 +忍著称 +忍著者 +忍著述 +志着 +志著书 +志著作 +志著名 +志著录 +志著称 +志著者 +志著述 +忙着 +忙著书 +忙著作 +忙著名 +忙著录 +忙著称 +忙著者 +忙著述 +怀着 +怀著书 +怀著作 +怀著名 +怀著录 +怀著称 +怀著者 +怀著述 +急着 +急著书 +急著作 +急著名 +急著录 +急著称 +急著者 +急著述 +性着 +性著书 +性著作 +性著名 +性著录 +性著称 +性著者 +性著述 +恋着 +恋著书 +恋著作 +恋著名 +恋著录 +恋著称 +恋著者 +恋著述 +悠着 +悠著书 +悠著作 +悠著名 +悠著录 +悠著称 +悠著者 +悠著述 +惯着 +惯著书 +惯著作 +惯著名 +惯著录 +惯著称 +惯著者 +惯著述 +想着 +想著书 +想著作 +想著名 +想著录 +想著称 +想著者 +想著述 +战着 +战著书 +战著作 +战著名 +战著录 +战著称 +战著者 +战著述 +戴着 +戴著书 +戴著作 +戴著名 +戴著录 +戴著称 +戴著者 +戴著述 +扎着 +扎著书 +扎著作 +扎著名 +扎著录 +扎著称 +扎著者 +扎著述 +打着 +打著书 +打著作 +打著名 +打著录 +打著称 +打著者 +打著述 +扛着 +扛著书 +扛著作 +扛著名 +扛著录 +扛著称 +扛著者 +扛著述 +找得着 +找不着 +抓着 +抓著作 +抓著名 +抓著录 +抓著称 +抓著者 +抓著述 +披着 +披著书 +披著作 +披著名 +披著录 +披著称 +披著者 +披著述 +抬着 +抬著作 +抬著名 +抬著录 +抬著称 +抬著者 +抬著述 +抱着 +抱著作 +抱著名 +抱著录 +抱著称 +抱著者 +抱著述 +拉着 +拉著书 +拉著作 +拉著名 +拉著录 +拉著称 +拉著者 +拉著述 +拎着 +拎著作 +拎著名 +拎著录 +拎著称 +拎著者 +拎著述 +拖着 +拖著作 +拖著名 +拖著录 +拖著称 +拖著者 +拖著述 +拼着 +拼著作 +拼著名 +拼著录 +拼著称 +拼著者 +拼著述 +拿着 +拿著作 +拿著名 +拿著录 +拿著称 +拿著者 +拿著述 +持着 +持著作 +持著名 +持著录 +持著称 +持著者 +持著述 +挑着 +挑著作 +挑著名 +挑著录 +挑著称 +挑著者 +挑著述 +挡着 +挡著作 +挡著名 +挡著录 +挡著称 +挡著者 +挡著述 +挣着 +挣著书 +挣著作 +挣著名 +挣著录 +挣著称 +挣著者 +挣著述 +挥着 +挥著作 +挥著名 +挥著录 +挥著称 +挥著者 +挥著述 +挨着 +挨著作 +挨著名 +挨著录 +挨著称 +挨著者 +挨著述 +捆着 +捆著作 +捆著名 +捆著录 +捆著称 +捆著者 +捆著述 +据着 +据著书 +据著作 +据著名 +据著录 +据著称 +据著者 +据著述 +掖着 +掖著作 +掖著名 +掖著录 +掖著称 +掖著者 +掖著述 +接着 +接著作 +接著名 +接著录 +接著称 +接著者 +接著述 +揉着 +揉著书 +揉著作 +揉著名 +揉著录 +揉著称 +揉著者 +揉著述 +提着 +提著作 +提著名 +提著录 +提著称 +提著者 +提著述 +搂着 +搂著作 +搂著名 +搂著录 +搂著称 +搂著者 +搂著述 +摆着 +摆著作 +摆著名 +摆著录 +摆著称 +摆著者 +摆著述 +撼着 +撼著书 +撼著作 +撼著名 +撼著录 +撼著称 +撼著者 +撼著述 +敞着 +敞著作 +敞著名 +敞著录 +敞著称 +敞著者 +敞著述 +数着 +数著作 +数著名 +数著录 +数著称 +数著者 +数著述 +斗着 +斗著书 +斗著作 +斗著名 +斗著录 +斗著称 +斗著者 +斗著述 +斥着 +斥著书 +斥著作 +斥著名 +斥著录 +斥著称 +斥著者 +斥著述 +昂着 +昂著书 +昂著作 +昂著名 +昂著录 +昂著称 +昂著者 +昂著述 +映着 +映著书 +映著作 +映著名 +映著录 +映著称 +映著者 +映著述 +晃着 +晃著作 +晃著名 +晃著录 +晃著称 +晃著者 +晃著述 +暗着 +暗著书 +暗著作 +暗著名 +暗著录 +暗著称 +暗著者 +暗著述 +有着 +有著书 +有著作 +有著名 +有著录 +有著称 +有著者 +有著述 +望着 +望著作 +望著名 +望著录 +望著称 +望著者 +望著述 +朝着 +朝著作 +朝著名 +朝著录 +朝著称 +朝著者 +朝著述 +本着 +本著书 +本著作 +本著名 +本著录 +本著称 +本著者 +本著述 +杀着 +杀著书 +杀著作 +杀著名 +杀著录 +杀著称 +杀著者 +杀著述 +杂着 +杂著书 +杂著作 +杂著名 +杂著录 +杂著称 +杂著者 +杂著述 +来着 +来著书 +来著作 +来著名 +来著录 +来著称 +来著者 +来著述 +枕着 +枕著作 +枕著名 +枕著录 +枕著称 +枕著者 +枕著述 +梦着 +梦著书 +梦著作 +梦著名 +梦著录 +梦著称 +梦著者 +梦著述 +梳着 +梳著作 +梳著名 +梳著录 +梳著称 +梳著者 +梳著述 +求着 +求著书 +求著作 +求著名 +求著录 +求著称 +求著者 +求著述 +沉着 +沉著书 +沉著作 +沉著名 +沉著录 +沉著称 +沉著者 +沉著述 +沿着 +沿著书 +沿著作 +沿著名 +沿著录 +沿著称 +沿著者 +沿著述 +活着 +活著书 +活著作 +活著名 +活著录 +活著称 +活著者 +活著述 +流着 +流著书 +流著作 +流著名 +流著录 +流著称 +流著者 +流著述 +浮着 +浮著书 +浮著作 +浮著名 +浮著录 +浮著称 +浮著者 +浮著述 +润着 +润著书 +润著作 +润著名 +润著录 +润著称 +润著者 +润著述 +涵着 +涵著书 +涵著作 +涵著名 +涵著录 +涵著称 +涵著者 +涵著述 +渴着 +渴著书 +渴著作 +渴著名 +渴著录 +渴著称 +渴著者 +渴著述 +溢着 +溢著书 +溢著作 +溢著名 +溢著录 +溢著称 +溢著者 +溢著述 +演着 +演著书 +演著作 +演著名 +演著录 +演著称 +演著者 +演著述 +漫着 +漫著书 +漫著作 +漫著名 +漫著录 +漫著称 +漫著者 +漫著述 +点着 +点著作 +点著名 +点著录 +点著称 +点著者 +点著述 +烧着 +烧著作 +烧著名 +烧著录 +烧著称 +烧著者 +烧著述 +照着 +照著书 +照著作 +照著名 +照著录 +照著称 +照著者 +照著述 +爱着 +爱著书 +爱著作 +爱著名 +爱著录 +爱著称 +爱著者 +爱著述 +牵着 +牵著书 +牵著作 +牵著名 +牵著录 +牵著称 +牵著者 +牵著述 +犯得着 +犯不着 +独着 +独著书 +独著作 +独著名 +独著录 +独著称 +独著者 +独著述 +猜着 +猜着书 +猜著作 +猜著名 +猜著录 +猜著称 +猜著者 +猜著述 +甜着 +甜著书 +甜著作 +甜著名 +甜著录 +甜著称 +甜著者 +甜著述 +用得着 +用不着 +用着 +用著书 +用著作 +用著名 +用著录 +用著称 +用著者 +用著述 +留着 +留着书 +留著作 +留著名 +留著录 +留著称 +留著者 +留著述 +疑着 +疑著书 +疑著作 +疑著名 +疑著录 +疑著称 +疑著者 +疑著述 +皱着 +皱著书 +皱著作 +皱著名 +皱著录 +皱著称 +皱著者 +皱著述 +盛着 +盛著书 +盛著作 +盛著名 +盛著录 +盛著称 +盛著者 +盛著述 +盯着 +盯着书 +盯著作 +盯著名 +盯著录 +盯著称 +盯著者 +盯著述 +盾着 +盾著书 +盾著作 +盾著名 +盾著录 +盾著称 +盾著者 +盾著述 +看得着 +看不着 +看着 +看着书 +看著作 +看著名 +看著录 +看著称 +看著者 +看著述 +瞧着 +瞧着书 +瞧著作 +瞧著名 +瞧著录 +瞧著称 +瞧著者 +瞧著述 +着业 +着丝 +着么 +着人 +着什么急 +着他 +着令 +着位 +着体 +着你 +着便 +着凉 +着力 +着劲 +着号 +着呢 +着哩 +着地 +着墨 +着声 +着处 +着她 +着妳 +着姓 +着它 +着定 +着实 +着己 +着帐 +着床 +着庸 +着式 +着录 +着心 +着志 +着忙 +着急 +着恼 +着惊 +着想 +着意 +着慌 +着我 +着手 +着抹 +着摸 +着撰 +着数 +着明 +着末 +着极 +着格 +着棋 +着槁 +着气 +着法 +着浅 +着火 +着然 +着甚 +着生 +着疑 +着白 +着相 +着眼 +着着 +着祂 +着积 +着稿 +着笔 +着籍 +着紧 +着緑 +着绊 +着绩 +着绯 +着绿 +着肉 +着脚 +着舰 +着色 +着节 +着花 +着莫 +着落 +着藁 +着衣 +着装 +着要 +着警 +着趣 +着边 +着迷 +着迹 +着重 +着録 +着闻 +着陆 +着雝 +着鞭 +着题 +着魔 +睡得着 +睡不着 +睡着 +睡著书 +睡著作 +睡著名 +睡著录 +睡著称 +睡著者 +睡著述 +瞒着 +瞒著书 +瞒著作 +瞒著名 +瞒著录 +瞒著称 +瞒著者 +瞒著述 +瞪着 +瞪著书 +瞪著作 +瞪著名 +瞪著录 +瞪著称 +瞪著者 +瞪著述 +福着 +福著书 +福著作 +福著名 +福著录 +福著称 +福著者 +福著述 +空着 +空著书 +空著作 +空著名 +空著录 +空著称 +空著者 +空著述 +穿着 +穿著书 +穿著作 +穿著名 +穿著录 +穿著称 +穿著者 +穿著述 +竖着 +竖著书 +竖著作 +竖著名 +竖著录 +竖著称 +竖著者 +竖著述 +站着 +站著书 +站著作 +站著名 +站著录 +站著称 +站著者 +站著述 +笑着 +笑著书 +笑著作 +笑著名 +笑著录 +笑著称 +笑著者 +笑著述 +管着 +管著书 +管著作 +管著名 +管著录 +管著称 +管著者 +管著述 +绑着 +绑著书 +绑著作 +绑著名 +绑著录 +绑著称 +绑著者 +绑著述 +绕着 +绕著书 +绕著作 +绕著名 +绕著录 +绕著称 +绕著者 +绕著述 +缠着 +缠著书 +缠著作 +缠著名 +缠著录 +缠著称 +缠著者 +缠著述 +罩着 +罩著书 +罩著作 +罩著名 +罩著录 +罩著称 +罩著者 +罩著述 +美着 +美著书 +美著作 +美著名 +美著录 +美著称 +美著者 +美著述 +耀着 +耀著书 +耀著作 +耀著名 +耀著录 +耀著称 +耀著者 +耀著述 +考着 +考著书 +考著作 +考著名 +考著录 +考著称 +考著者 +考著述 +背着 +背著书 +背著作 +背著名 +背著录 +背著称 +背著者 +背著述 +胶着 +胶著书 +胶著作 +胶著名 +胶著录 +胶著称 +胶著者 +胶著述 +艺着 +艺著书 +艺著作 +艺著名 +艺著录 +艺著称 +艺著者 +艺著述 +苦着 +苦著书 +苦著作 +苦著名 +苦著录 +苦著称 +苦著者 +苦著述 +获着 +获著书 +获著作 +获著名 +获著录 +获著称 +获著者 +获著述 +落着 +落著书 +落著作 +落著名 +落著录 +落著称 +落著者 +落著述 +蒙着 +蒙著书 +蒙著作 +蒙著名 +蒙著录 +蒙著称 +蒙著者 +蒙著述 +藏着 +藏著书 +藏著作 +藏著名 +藏著录 +藏著称 +藏著者 +藏著述 +蘸着 +蘸著书 +蘸著作 +蘸著名 +蘸著录 +蘸著称 +蘸著者 +蘸著述 +行着 +行著书 +行著作 +行著名 +行著录 +行著称 +行著者 +行著述 +衣着 +衣著书 +衣著作 +衣著名 +衣著录 +衣著称 +衣著者 +衣著述 +装着 +装著书 +装著作 +装著名 +装著录 +装著称 +装著者 +装著述 +裹着 +裹著书 +裹著作 +裹著名 +裹著录 +裹著称 +裹著者 +裹著述 +见着 +见著书 +见著作 +见著名 +见著录 +见著称 +见著者 +见著述 +记着 +记著书 +记著作 +记著名 +记著录 +记著称 +记著者 +记著述 +试着 +试著书 +试著作 +试著名 +试著录 +试著称 +试著者 +试著述 +语着 +语著书 +语著作 +语著名 +语著录 +语著称 +语著者 +语著述 +豫着 +豫著书 +豫著作 +豫著名 +豫著录 +豫著称 +豫著者 +豫著述 +贞着 +贞著书 +贞著作 +贞著名 +贞著录 +贞著称 +贞著者 +贞著述 +走着 +走著书 +走著作 +走著名 +走著录 +走著称 +走著者 +走著述 +赶着 +赶著书 +赶著作 +赶著名 +赶著录 +赶著称 +赶著者 +赶著述 +趴着 +趴著书 +趴著作 +趴著名 +趴著录 +趴著称 +趴著者 +趴著述 +跃着 +跃著书 +跃著作 +跃著名 +跃著录 +跃著称 +跃著者 +跃著述 +跑着 +跑著书 +跑著作 +跑著名 +跑著录 +跑著称 +跑著者 +跑著述 +跟着 +跟著书 +跟著作 +跟著名 +跟著录 +跟著称 +跟著者 +跟著述 +跪着 +跪著书 +跪著作 +跪著名 +跪著录 +跪著称 +跪著者 +跪著述 +跳着 +跳著书 +跳著作 +跳著名 +跳著录 +跳著称 +跳著者 +跳著述 +踏着 +踏著书 +踏著作 +踏著名 +踏著录 +踏著称 +踏著者 +踏著述 +踩着 +踩著书 +踩著作 +踩著名 +踩著录 +踩著称 +踩著者 +踩著述 +身着 +身著书 +身著作 +身著名 +身著录 +身著称 +身著者 +身著述 +躺着 +躺著书 +躺著作 +躺著名 +躺著录 +躺著称 +躺著者 +躺著述 +转着 +转著书 +转著作 +转著名 +转著录 +转著称 +转著者 +转著述 +载着 +载著书 +载著作 +载著名 +载著录 +载著称 +载著者 +载著述 +达着 +达著书 +达著作 +达著名 +达著录 +达著称 +达著者 +达著述 +远着 +远著书 +远著作 +远著名 +远著录 +远著称 +远著者 +远著述 +连着 +连著书 +连著作 +连著名 +连著录 +连著称 +连著者 +连著述 +追着 +追著书 +追著作 +追著名 +追著录 +追著称 +追著者 +追著述 +逆着 +逆著书 +逆著作 +逆著名 +逆著录 +逆著称 +逆著者 +逆著述 +逼着 +逼著书 +逼著作 +逼著名 +逼著录 +逼著称 +逼著者 +逼著述 +遇着 +遇著书 +遇著作 +遇著名 +遇著录 +遇著称 +遇著者 +遇著述 +配着 +配著书 +配著作 +配著名 +配著录 +配著称 +配著者 +配著述 +酿着 +酿著书 +酿著作 +酿著名 +酿著录 +酿著称 +酿著者 +酿著述 +铺着 +铺著书 +铺著作 +铺著名 +铺著录 +铺著称 +铺著者 +铺著述 +闭着 +闭著书 +闭著作 +闭著名 +闭著录 +闭著称 +闭著者 +闭著述 +闲着 +闲著书 +闲著作 +闲著名 +闲著录 +闲著称 +闲著者 +闲著述 +附着 +附著书 +附著作 +附著名 +附著录 +附著称 +附著者 +附著述 +陋着 +陋著书 +陋著作 +陋著名 +陋著录 +陋著称 +陋著者 +陋著述 +陪着 +陪著书 +陪著作 +陪著名 +陪著录 +陪著称 +陪著者 +陪著述 +随着 +随著书 +随著作 +随著名 +随著录 +随著称 +随著者 +随著述 +隔着 +隔著书 +隔著作 +隔著名 +隔著录 +隔著称 +隔著者 +隔著述 +雅着 +雅著书 +雅著作 +雅著名 +雅著录 +雅著称 +雅著者 +雅著述 +顶着 +顶著书 +顶著作 +顶著名 +顶著录 +顶著称 +顶著者 +顶著述 +顺着 +顺著书 +顺著作 +顺著名 +顺著录 +顺著称 +顺著者 +顺著述 +领着 +领著书 +领著作 +领著名 +领著录 +领著称 +领著者 +领著述 +飘着 +飘著书 +飘著作 +飘著名 +飘著录 +飘著称 +飘著者 +飘著述 +驾着 +驾著书 +驾著作 +驾著名 +驾著录 +驾著称 +驾著者 +驾著述 +骂着 +骂著书 +骂著作 +骂著名 +骂著录 +骂著称 +骂著者 +骂著述 +骑着 +骑著书 +骑著作 +骑著名 +骑著录 +骑著称 +骑著者 +骑著述 +骗着 +骗著书 +骗著作 +骗著名 +骗著录 +骗著称 +骗著者 +骗著述 +高着 +高著书 +高著作 +高著名 +高著录 +高著称 +高著者 +高著述 +髭着 +髭著书 +髭著作 +髭著名 +髭著录 +髭著称 +髭著者 +髭著述 +黏着 +黏著书 +黏著作 +黏著名 +黏著录 +黏著称 +黏著者 +黏著述 +新著龙虎门 +护着 +护著书 +护著作 +护著名 +护著录 +护著称 +护著者 +护著述 +保护着 +爱护着 +庇护着 +传着 +传著书 +传著作 +传著名 +传著录 +传著称 +传著者 +传著述 +标志着 +流露着 +靠着 +靠著作 +靠著名 +靠著录 +靠著称 +靠著者 +靠著述 +玩着 +迫着 +吃得着 +吃不着 +吃着 +闻得着 +闻不着 +闻着 +嗅得着 +嗅不着 +嗅着 +警戒着 +於乎 +於戏 +魏徵 +柳诒徵 +於姓 +於氏 +於夫罗 +於梨华 +卷舌 +樊於期 +於菟 +於潜县 +石碁镇 +因著《 +因著〈 +李泽钜 +於祥玉 +於崇文 +於世成 +於乙宇同 +於宇同 +朴於宇同 +於哲 +於除鞬 +於志贺 +覆蓋 +五箇山 +麽麽 +幺厮 +幺半群 +幺元 +幺爹 +幺叔 +幺舅 +幺爸 +幺妈 +幺姨 +幺娘 +幺妹 +幺小 +幺姓 +姓幺 +幺氏 +麽氏 +幺蛾子 +幺麽 +幺麽小丑 +幺凤 +幺二三 +幺篇 +幺谦 +麴义 +麴英 +麯崇裕 +阿部正瞭 +醯酱 +醯鸡 +醯醋 +醯醢 +醯壶 +苧烯 +近角聪信 +米泽瑠美 +峯岸南 +僧伽吒 +王道乾 +後姓 diff --git a/maintenance/language/zhtable/simpphrases_exclude.manual b/maintenance/language/zhtable/simpphrases_exclude.manual new file mode 100644 index 00000000..3e9d3ecc --- /dev/null +++ b/maintenance/language/zhtable/simpphrases_exclude.manual @@ -0,0 +1,21 @@ +整飭 +後 +谘 +彷佛 +三番四复 +三复 +藉 +关於 +对於 +属於 +至於 +夥计 +薹 +嚇 +醣 +捱 +簑 +樑 +摺叠 +餗 +安甯
\ No newline at end of file diff --git a/maintenance/language/zhtable/toCN.manual b/maintenance/language/zhtable/toCN.manual new file mode 100644 index 00000000..243f61b0 --- /dev/null +++ b/maintenance/language/zhtable/toCN.manual @@ -0,0 +1,275 @@ +」 ” +「 “ +『 ‘ +』 ’ +記憶體 内存 +預設 默认 +串列 串行 +串列加速器 串列加速器 +乙太網 以太网 +點陣圖 位图 +常式 例程 +光碟 光盘 +光碟機 光驱 +全形 全角 +載入 加载 +半形 半角 +變數 变量 +雜訊 噪声 +因數 因子 +功能變數名稱 域名 +音效卡 声卡 +字型大小 字号 +字型檔 字库 +欄位 字段 +字元 字符 +字元济 字元济 +字元濟 字元济 +字元会 字元会 +字元會 字元会 +存檔 存盘 +定址 寻址 +章節附註 尾注 +非同步 异步 +匯流排 总线 +括弧 括号 +介面 接口 +控制項 控件 +許可權 权限 +碟片 盘片 +矽片 硅片 +矽谷 硅谷 +硬碟 硬盘 +磁碟 磁盘 +磁軌 磁道 +程式控制 程控 +遠程控制 远程控制 +远程控制 远程控制 +運算元 算子 +演算法 算法 +晶片 芯片 +晶元 芯片 +片語 词组 +軟碟機 软驱 +快閃記憶體 快闪存储器 +滑鼠 鼠标 +滑鼠蛇 滑鼠蛇 +二進位 二进制 +滿二進位 满二进位 +六進位 六进制 +滿六進位 满六进位 +滿十六進位 满十六进位 +八進位 八进制 +滿八進位 满八进位 +十進位 十进制 +滿十進位 满十进位 +16進位 16进位 +滿16進位 满16进位 +二進位制 二进位制 +六進位制 六进位制 +八進位制 八进位制 +十進位制 十进位制 +16進位制 16进位制 +互動式 交互式 +優先順序 优先级 +感測 传感 +攜帶型 便携式 +資訊理論 信息论 +迴圈 循环 +防寫 写保护 +解析度 分辨率 +伺服器 服务器 +等於 等于 +區域網 局域网 +巨集 宏 +掃瞄器 扫瞄仪 +寬頻 宽带 +資料庫 数据库 +萬曆 万历 +永曆 永历 +辭彙 词汇 +母音 元音 +字母 字母 +頭槌 头球 +進球 入球 +顆進球 粒入球 +射門 打门 +蓋火鍋 火锅盖帽 +印表機 打印机 +打印機 打印机 +位元組 字节 +字節 字节 +列印 打印 +打印 打印 +硬體 硬件 +二極體 二极管 +二極管 二极管 +三極體 三极管 +三極管 三极管 +軟體 软件 +軟件 软件 +網路 网络 +網絡 网络 +人工智慧 人工智能 +太空梭 航天飞机 +穿梭機 航天飞机 +網際網路 互联网 +互聯網 互联网 +機械人 机器人 +機器人 机器人 +行動電話 移动电话 +流動電話 移动电话 +調制解調器 调制解调器 +數據機 调制解调器 +短訊 短信 +簡訊 短信 +烏茲別克 乌兹别克斯坦 +葉門 也门 +伯利茲 伯利兹 +貝里斯 伯利兹 +維德角 佛得角 +克羅埃西亞 克罗地亚 +甘比亞 冈比亚 +幾內亞比索 几内亚比绍 +列支敦斯登 列支敦士登 +賴比瑞亞 利比里亚 +迦納 加纳 +加彭 加蓬 +波札那 博茨瓦纳 +盧安達 卢旺达 +瓜地馬拉 危地马拉 +厄瓜多爾 厄瓜多尔 +厄瓜多尔 厄瓜多尔 +厄瓜多 厄瓜多尔 +厄利垂亞 厄立特里亚 +吉布地 吉布提 +哈薩克 哈萨克斯坦 +哥斯大黎加 哥斯达黎加 +吐瓦魯 图瓦卢 +土庫曼 土库曼斯坦 +聖露西亞 圣卢西亚 +聖吉斯納域斯 圣基茨和尼维斯 +聖克里斯多福及尼維斯 圣基茨和尼维斯 +聖文森及格瑞那丁 圣文森特和格林纳丁斯 +聖馬利諾 圣马力诺 +蓋亞那 圭亚那 +坦尚尼亞 坦桑尼亚 +衣索匹亞 埃塞俄比亚 +衣索比亞 埃塞俄比亚 +吉里巴斯 基里巴斯 +塔吉克 塔吉克斯坦 +塞拉利昂 塞拉利昂 +塞普勒斯 塞浦路斯 +塞席爾 塞舌尔 +多米尼克 多米尼加国 +安地卡及巴布達 安提瓜和巴布达 +尼日利亞 尼日利亚 +尼日利亚 尼日利亚 +奈及利亞 尼日利亚 +尼日爾 尼日尔 +尼日尔 尼日尔 +巴貝多 巴巴多斯 +巴布亞紐幾內亞 巴布亚新几内亚 +布基納法索 布基纳法索 +布吉納法索 布基纳法索 +蒲隆地 布隆迪 +帛琉 帕劳 +義大利 意大利 +索羅門群島 所罗门群岛 +汶萊 文莱 +史瓦濟蘭 斯威士兰 +斯洛維尼亞 斯洛文尼亚 +紐西蘭 新西兰 +格瑞那達 格林纳达 +茅利塔尼亞 毛里塔尼亚 +毛里裘斯 毛里求斯 +模里西斯 毛里求斯 +沙地阿拉伯 沙特阿拉伯 +沙烏地阿拉伯 沙特阿拉伯 +波士尼亞赫塞哥維納 波斯尼亚和黑塞哥维那 +辛巴威 津巴布韦 +宏都拉斯 洪都拉斯 +千里達托貝哥 特立尼达和托巴哥 +諾魯 瑙鲁 +萬那杜 瓦努阿图 +溫納圖 瓦努阿图 +葛摩 科摩罗 +象牙海岸 科特迪瓦 +突尼西亞 突尼斯 +索馬利亞 索马里 +寮國 老挝 +肯雅 肯尼亚 +肯亞 肯尼亚 +蘇利南 苏里南 +莫三比克 莫桑比克 +賴索托 莱索托 +貝南 贝宁 +尚比亞 赞比亚 +亞塞拜然 阿塞拜疆 +阿拉伯聯合大公國 阿拉伯联合酋长国 +南韓 韩国 +馬爾地夫 马尔代夫 +馬爾他 马耳他 +馬利共和國 马里共和国 +即食麵 方便面 +快速面 方便面 +速食麵 方便面 +泡麵 方便面 +笨豬跳 蹦极跳 +绑紧跳 蹦极跳 +冷盤 凉菜 +冷菜 凉菜 +散钱 零钱 +谐星 笑星 +夜学 夜校 +华乐 民乐 +中樂 民乐 +軍中樂園 军中乐园 +华乐街 华乐街 +屋价 房价 +計程車 出租车 +單車 自行车 +節慶 节日 +芝士 乾酪 +狗隻 犬只 +士多啤梨 草莓 +忌廉 奶油 +桌球 台球 +撞球 台球 +衞生 卫生 +衛生 卫生 +賓士 奔驰 +平治 奔驰 +平治之亂 平治之乱 +平治之乱 平治之乱 +積架 捷豹 +福斯 大众 +福士 大众 +萬事得 马自达 +寶獅 标志 +拿破崙 拿破仑 +布殊 布什 +布希 布什 +布希亞 布希亚 +布希亚 布希亚 +柯林頓 克林顿 +海珊 侯赛因 +梵谷 凡高 +大衛碧咸 大卫·贝克汉姆 +米高奧雲 迈克尔·欧文 +卡佩雅蒂 珍妮弗·卡普里亚蒂 +沙芬 马拉特·萨芬 +舒麥加 迈克尔·舒马赫 +希特拉 希特勒 +黛安娜 戴安娜 +榴槤 榴莲 +榴梿 榴莲 +矽 硅 +矽肺 矽肺 +矽塵 矽尘 +矽尘 矽尘 +矽鋼 矽钢 +矽钢 矽钢 +侏儸紀 侏罗纪 +甚麽 什么 +甚麼 什么 diff --git a/maintenance/language/zhtable/toHK.manual b/maintenance/language/zhtable/toHK.manual new file mode 100644 index 00000000..1f7fe7d0 --- /dev/null +++ b/maintenance/language/zhtable/toHK.manual @@ -0,0 +1,2300 @@ +” 」 +“ 「 +‘ 『 +’ 』 +鉤 鈎 +衛 衞 +凶殺 兇殺 +凶殘 兇殘 +緝凶 緝兇 +買凶 買兇 +印表機 打印機 +字节 位元組 +字節 位元組 +列印 打印 +硬件 硬件 +硬體 硬件 +二極體 二極管 +三極體 三極管 +軟體 軟件 +網路 網絡 +人工智慧 人工智能 +航天飞机 穿梭機 +太空梭 穿梭機 +因特网 互聯網 +網際網路 互聯網 +机器人 機械人 +機器人 機械人 +移动电话 流動電話 +行動電話 流動電話 +數據機 調制解調器 +短信 短訊 +簡訊 短訊 +查德 乍得 +葉門 也門 +貝里斯 伯利茲 +維德角 佛得角 +克羅埃西亞 克羅地亞 +甘比亞 岡比亞 +幾內亞比索 幾內亞比紹 +列支敦斯登 列支敦士登 +賴比瑞亞 利比里亞 +迦納 加納 +加彭 加蓬 +波札那 博茨瓦納 +盧安達 盧旺達 +瓜地馬拉 危地馬拉 +厄瓜多尔 厄瓜多爾 +厄瓜多爾 厄瓜多爾 +厄瓜多 厄瓜多爾 +厄利垂亞 厄立特里亞 +吉布地 吉布堤 +哥斯大黎加 哥斯達黎加 +吐瓦魯 圖瓦盧 +聖露西亞 聖盧西亞 +圣基茨和尼维斯 聖吉斯納域斯 +聖克里斯多福及尼維斯 聖吉斯納域斯 +聖文森及格瑞那丁 聖文森特和格林納丁斯 +聖馬利諾 聖馬力諾 +蓋亞那 圭亞那 +坦尚尼亞 坦桑尼亞 +衣索匹亞 埃塞俄比亞 +衣索比亞 埃塞俄比亞 +吉里巴斯 基里巴斯 +塞普勒斯 塞浦路斯 +塞席爾 塞舌爾 +安地卡及巴布達 安提瓜和巴布達 +尼日利亚 尼日利亞 +尼日利亞 尼日利亞 +奈及利亞 尼日利亞 +尼日尔 尼日爾 +尼日爾 尼日爾 +尼日 尼日爾 +巴貝多 巴巴多斯 +巴布亞紐幾內亞 巴布亞新畿內亞 +布吉納法索 布基納法索 +蒲隆地 布隆迪 +帕劳 帛琉 +義大利 意大利 +索羅門群島 所羅門群島 +文莱 汶萊 +史瓦濟蘭 斯威士蘭 +斯洛維尼亞 斯洛文尼亞 +紐西蘭 新西蘭 +格瑞那達 格林納達 +茅利塔尼亞 毛里塔尼亞 +毛里求斯 毛里裘斯 +模里西斯 毛里裘斯 +沙地阿拉伯 沙特阿拉伯 +沙烏地阿拉伯 沙特阿拉伯 +波士尼亞赫塞哥維納 波斯尼亞黑塞哥維那 +辛巴威 津巴布韋 +宏都拉斯 洪都拉斯 +千里達托貝哥 特立尼達和多巴哥 +諾魯 瑙魯 +萬那杜 瓦努阿圖 +葛摩 科摩羅 +索馬利亞 索馬里 +寮國 老撾 +肯尼亚 肯雅 +肯亞 肯雅 +莫三比克 莫桑比克 +賴索托 萊索托 +貝南 貝寧 +尚比亞 贊比亞 +亞塞拜然 阿塞拜疆 +阿拉伯聯合大公國 阿拉伯聯合酋長國 +馬爾地夫 馬爾代夫 +馬利共和國 馬里共和國 +方便面 即食麵 +快速面 即食麵 +速食麵 即食麵 +泡麵 即食麵 +土豆 馬鈴薯 +土豆网 土豆網 +土豆網 土豆網 +华乐 中樂 +民乐 中樂 +計程車 的士 +出租车 的士 +公車 巴士 +公車上書 公車上書 +自行车 單車 +犬只 狗隻 +台球 桌球 +撞球 桌球 +冰淇淋 雪糕 +賓士 平治 +捷豹 積架 +福斯 福士 +雪铁龙 先進 +雪鐵龍 先進 +沃尓沃 富豪 +马自达 萬事得 +馬自達 萬事得 +寶獅 標致 +布什 布殊 +布希 布殊 +布希亞 布希亞 +布希亚 布希亞 +柯林頓 克林頓 +萨达姆 薩達姆 +海珊 侯賽因 +大卫·贝克汉姆 大衛碧咸 +迈克尔·欧文 米高奧雲 +珍妮弗·卡普里亚蒂 卡佩雅蒂 +马拉特·萨芬 沙芬 +迈克尔·舒马赫 舒麥加 +希特勒 希特拉 +狄安娜 戴安娜 +黛安娜 戴安娜 +颁布 頒佈 +頒布 頒佈 +挨著 挨着 +愛著 愛着 +暗著 暗着 +昂著 昂着 +擺著 擺着 +伴著 伴着 +辦著 辦着 +幫著 幫着 +綁著 綁着 +抱著 抱着 +背著 背着 +備著 備着 +本著 本着 +逼著 逼着 +閉著 閉着 +變著 變着 +猜著 猜着 +踩著 踩着 +藏著 藏着 +側著 側着 +纏著 纏着 +敞著 敞着 +唱著 唱着 +朝著 朝着 +沉著 沉着 +乘著 乘着 +持著 持着 +斥著 斥着 +醜著 醜着 +穿著 穿着 +吹著 吹着 +達著 達着 +打著 打着 +待著 待着 +帶著 帶着 +戴著 戴着 +當著 當着 +擋著 擋着 +得著 得着 +瞪著 瞪着 +低著 低着 +點著 點着 +盯著 盯着 +頂著 頂着 +定著 定着 +動著 動着 +鬥著 鬥着 +獨著 獨着 +對著 對着 +盾著 盾着 +犯得著 犯得着 +犯不著 犯不着 +福著 福着 +趕著 趕着 +高著 高着 +隔著 隔着 +跟著 跟着 +孤著 孤着 +關著 關着 +管著 管着 +慣著 慣着 +光著 光着 +跪著 跪着 +裹著 裹着 +撼著 撼着 +喝著 喝着 +候著 候着 +懷著 懷着 +晃著 晃着 +揮著 揮着 +活著 活着 +獲著 獲着 +獲著 獲着 +急著 急着 +記著 記着 +冀著 冀着 +夾著 夾着 +駕著 駕着 +見著 見着 +閑著 閑着 +叫著 叫着 +接著 接着 +借著 借着 +借著 借着 +據著 據着 +開著 開着 +看得著 看得着 +看不著 看不着 +看著 看着 +康著 康着 +扛著 扛着 +考著 考着 +渴著 渴着 +刻著 刻着 +空著 空着 +哭著 哭着 +苦著 苦着 +捆著 捆着 +困著 困着 +拉著 拉着 +來著 來着 +樂著 樂着 +努力著 努力着 +麗著 麗着 +連著 連着 +戀著 戀着 +涼著 涼着 +亮著 亮着 +臨著 臨着 +拎著 拎着 +領著 領着 +流著 流着 +留著 留着 +摟著 摟着 +陋著 陋着 +落著 落着 +罵著 罵着 +瞞著 瞞着 +漫著 漫着 +忙著 忙着 +冒著 冒着 +美著 美着 +夢著 夢着 +蒙著 蒙着 +拿著 拿着 +逆著 逆着 +釀著 釀着 +努著 努着 +趴著 趴着 +跑著 跑着 +陪著 陪着 +配著 配着 +披著 披着 +騙著 騙着 +飄著 飄着 +拼著 拼着 +鋪著 鋪着 +騎著 騎着 +牽著 牽着 +求著 求着 +去著 去着 +嚷著 嚷着 +繞著 繞着 +忍著 忍着 +揉著 揉着 +潤著 潤着 +燒著 燒着 +身著 身着 +沉著 沉着 +盛著 盛着 +試著 試着 +守著 守着 +受著 受着 +梳著 梳着 +豎著 豎着 +數著 數着 +睡得著 睡得着 +睡不著 睡不着 +睡著 睡着 +順著 順着 +隨著 隨着 +踏著 踏着 +抬著 抬着 +躺著 躺着 +提著 提着 +甜著 甜着 +挑著 挑着 +跳著 跳着 +聽得著 聽得着 +聽不著 聽不着 +聽著 聽着 +偷著 偷着 +拖著 拖着 +望著 望着 +圍著 圍着 +味著 味着 +想著 想着 +響著 響着 +向著 向着 +笑著 笑着 +心著 心着 +信著 信着 +行著 行着 +性著 性着 +學著 學着 +尋著 尋着 +循著 循着 +壓著 壓着 +雅著 雅着 +沿著 沿着 +耀著 耀着 +掖著 掖着 +衣著 衣着 +疑著 疑着 +溢著 溢着 +藝著 藝着 +因著 因着 +印著 印着 +應著 應着 +映著 映着 +用得著 用得着 +用不著 用不着 +用著 用着 +悠著 悠着 +有著 有着 +與著 與着 +語著 語着 +豫著 豫着 +遠著 遠着 +躍著 躍着 +雜著 雜着 +載著 載着 +在著 在着 +紮著 紮着 +展著 展着 +站著 站着 +戰著 戰着 +蘸著 蘸着 +仗著 仗着 +找得著 找得着 +找不著 找不着 +照著 照着 +罩著 罩着 +貞著 貞着 +枕著 枕着 +爭著 爭着 +掙著 掙着 +制著 制着 +志著 志着 +皺著 皺着 +住著 住着 +抓著 抓着 +轉著 轉着 +裝著 裝着 +追著 追着 +髭著 髭着 +走著 走着 +坐著 坐着 +做著 做着 +含著 含着 +涵著 涵着 +演著 演着 +保障著 保障着 +黏著 黏着 +膠著 膠着 +附著 附着 +代表著 代表着 +浮著 浮着 +寫著 寫着 +遇著 遇着 +殺著 殺着 +著筆 着筆 +著鞭 着鞭 +著法 着法 +著火 着火 +著急 着急 +著艦 着艦 +著腳 着腳 +著她 着她 +著緊 着緊 +著力 着力 +著涼 着涼 +著陸 着陸 +著錄 着錄 +著落 着落 +著忙 着忙 +著迷 着迷 +著墨 着墨 +著妳 着妳 +著你 着你 +著色 着色 +著什麼急 着什麼急 +著實 着實 +著手 着手 +著數 着數 +著絲 着絲 +著他 着他 +著它 着它 +著祂 着祂 +著我 着我 +著想 着想 +著眼 着眼 +著衣 着衣 +著意 着意 +著重 着重 +著重 着重 +著裝 着裝 +著地 着地 +不著邊際 不着邊際 +不著痕跡 不着痕跡 +挨著作 挨著作 +挨著者 挨著者 +挨著名 挨著名 +挨著述 挨著述 +挨著稱 挨著稱 +挨著錄 挨著錄 +愛著作 愛著作 +愛著者 愛著者 +愛著名 愛著名 +愛著述 愛著述 +愛著稱 愛著稱 +愛著錄 愛著錄 +愛著書 愛著書 +暗著作 暗著作 +暗著者 暗著者 +暗著名 暗著名 +暗著述 暗著述 +暗著稱 暗著稱 +暗著錄 暗著錄 +暗著書 暗著書 +昂著作 昂著作 +昂著者 昂著者 +昂著名 昂著名 +昂著述 昂著述 +昂著稱 昂著稱 +昂著錄 昂著錄 +昂著書 昂著書 +擺著作 擺著作 +擺著者 擺著者 +擺著名 擺著名 +擺著述 擺著述 +擺著稱 擺著稱 +擺著錄 擺著錄 +伴著作 伴著作 +伴著者 伴著者 +伴著名 伴著名 +伴著述 伴著述 +伴著稱 伴著稱 +伴著錄 伴著錄 +伴著書 伴著書 +辦著作 辦著作 +辦著者 辦著者 +辦著名 辦著名 +辦著述 辦著述 +辦著稱 辦著稱 +辦著錄 辦著錄 +辦著書 辦著書 +幫著作 幫著作 +幫著者 幫著者 +幫著名 幫著名 +幫著述 幫著述 +幫著稱 幫著稱 +幫著錄 幫著錄 +幫著書 幫著書 +綁著作 綁著作 +綁著者 綁著者 +綁著名 綁著名 +綁著述 綁著述 +綁著稱 綁著稱 +綁著錄 綁著錄 +綁著書 綁著書 +抱著作 抱著作 +抱著者 抱著者 +抱著名 抱著名 +抱著述 抱著述 +抱著稱 抱著稱 +抱著錄 抱著錄 +背著作 背著作 +背著者 背著者 +背著名 背著名 +背著述 背著述 +背著稱 背著稱 +背著錄 背著錄 +背著書 背著書 +備著作 備著作 +備著者 備著者 +備著名 備著名 +備著述 備著述 +備著稱 備著稱 +備著錄 備著錄 +備著書 備著書 +本著作 本著作 +本著者 本著者 +本著名 本著名 +本著述 本著述 +本著稱 本著稱 +本著錄 本著錄 +本著書 本著書 +逼著作 逼著作 +逼著者 逼著者 +逼著名 逼著名 +逼著述 逼著述 +逼著稱 逼著稱 +逼著錄 逼著錄 +逼著書 逼著書 +閉著作 閉著作 +閉著者 閉著者 +閉著名 閉著名 +閉著述 閉著述 +閉著稱 閉著稱 +閉著錄 閉著錄 +閉著書 閉著書 +變著作 變著作 +變著者 變著者 +變著名 變著名 +變著述 變著述 +變著稱 變著稱 +變著錄 變著錄 +變著書 變著書 +猜著作 猜著作 +猜著者 猜著者 +猜著名 猜著名 +猜著述 猜著述 +猜著稱 猜著稱 +猜著錄 猜著錄 +猜著書 猜著書 +踩著作 踩著作 +踩著者 踩著者 +踩著名 踩著名 +踩著述 踩著述 +踩著稱 踩著稱 +踩著錄 踩著錄 +踩著書 踩著書 +藏著作 藏著作 +藏著者 藏著者 +藏著名 藏著名 +藏著述 藏著述 +藏著稱 藏著稱 +藏著錄 藏著錄 +藏著書 藏著書 +側著作 側著作 +側著者 側著者 +側著名 側著名 +側著述 側著述 +側著稱 側著稱 +側著錄 側著錄 +側著書 側著書 +纏著作 纏著作 +纏著者 纏著者 +纏著名 纏著名 +纏著述 纏著述 +纏著稱 纏著稱 +纏著錄 纏著錄 +纏著書 纏著書 +敞著作 敞著作 +敞著者 敞著者 +敞著名 敞著名 +敞著述 敞著述 +敞著稱 敞著稱 +敞著錄 敞著錄 +唱著作 唱著作 +唱著者 唱著者 +唱著名 唱著名 +唱著述 唱著述 +唱著稱 唱著稱 +唱著錄 唱著錄 +唱著書 唱著書 +朝著作 朝著作 +朝著者 朝著者 +朝著名 朝著名 +朝著述 朝著述 +朝著稱 朝著稱 +朝著錄 朝著錄 +沉著作 沉著作 +沉著者 沉著者 +沉著名 沉著名 +沉著述 沉著述 +沉著稱 沉著稱 +沉著錄 沉著錄 +沉著書 沉著書 +乘著作 乘著作 +乘著者 乘著者 +乘著名 乘著名 +乘著述 乘著述 +乘著稱 乘著稱 +乘著錄 乘著錄 +乘著書 乘著書 +持著作 持著作 +持著者 持著者 +持著名 持著名 +持著述 持著述 +持著稱 持著稱 +持著錄 持著錄 +斥著作 斥著作 +斥著者 斥著者 +斥著名 斥著名 +斥著述 斥著述 +斥著稱 斥著稱 +斥著錄 斥著錄 +斥著書 斥著書 +醜著作 醜著作 +醜著者 醜著者 +醜著名 醜著名 +醜著述 醜著述 +醜著稱 醜著稱 +醜著錄 醜著錄 +醜著書 醜著書 +穿著作 穿著作 +穿著者 穿著者 +穿著名 穿著名 +穿著述 穿著述 +穿著稱 穿著稱 +穿著錄 穿著錄 +穿著書 穿著書 +吹著作 吹著作 +吹著者 吹著者 +吹著名 吹著名 +吹著述 吹著述 +吹著稱 吹著稱 +吹著錄 吹著錄 +吹著書 吹著書 +達著作 達著作 +達著者 達著者 +達著名 達著名 +達著述 達著述 +達著稱 達著稱 +達著錄 達著錄 +達著書 達著書 +打著作 打著作 +打著者 打著者 +打著名 打著名 +打著述 打著述 +打著稱 打著稱 +打著錄 打著錄 +打著書 打著書 +待著作 待著作 +待著者 待著者 +待著名 待著名 +待著述 待著述 +待著稱 待著稱 +待著錄 待著錄 +待著書 待著書 +帶著作 帶著作 +帶著者 帶著者 +帶著名 帶著名 +帶著述 帶著述 +帶著稱 帶著稱 +帶著錄 帶著錄 +帶著書 帶著書 +戴著作 戴著作 +戴著者 戴著者 +戴著名 戴著名 +戴著述 戴著述 +戴著稱 戴著稱 +戴著錄 戴著錄 +戴著書 戴著書 +當著作 當著作 +當著者 當著者 +當著名 當著名 +當著述 當著述 +當著稱 當著稱 +當著錄 當著錄 +當著書 當著書 +擋著作 擋著作 +擋著者 擋著者 +擋著名 擋著名 +擋著述 擋著述 +擋著稱 擋著稱 +擋著錄 擋著錄 +得著作 得著作 +得著者 得著者 +得著名 得著名 +得著述 得著述 +得著稱 得著稱 +得著錄 得著錄 +得著書 得著書 +瞪著作 瞪著作 +瞪著者 瞪著者 +瞪著名 瞪著名 +瞪著述 瞪著述 +瞪著稱 瞪著稱 +瞪著錄 瞪著錄 +瞪著書 瞪著書 +低著作 低著作 +低著者 低著者 +低著名 低著名 +低著述 低著述 +低著稱 低著稱 +低著錄 低著錄 +低著書 低著書 +點著作 點著作 +點著者 點著者 +點著名 點著名 +點著述 點著述 +點著稱 點著稱 +點著錄 點著錄 +點著書 點著書 +盯著作 盯著作 +盯著者 盯著者 +盯著名 盯著名 +盯著述 盯著述 +盯著稱 盯著稱 +盯著錄 盯著錄 +盯著書 盯著書 +頂著作 頂著作 +頂著者 頂著者 +頂著名 頂著名 +頂著述 頂著述 +頂著稱 頂著稱 +頂著錄 頂著錄 +頂著書 頂著書 +定著作 定著作 +定著者 定著者 +定著名 定著名 +定著述 定著述 +定著稱 定著稱 +定著錄 定著錄 +定著書 定著書 +動著作 動著作 +動著者 動著者 +動著名 動著名 +動著述 動著述 +動著稱 動著稱 +動著錄 動著錄 +動著書 動著書 +鬥著作 鬥著作 +鬥著者 鬥著者 +鬥著名 鬥著名 +鬥著述 鬥著述 +鬥著稱 鬥著稱 +鬥著錄 鬥著錄 +鬥著書 鬥著書 +獨著作 獨著作 +獨著者 獨著者 +獨著名 獨著名 +獨著述 獨著述 +獨著稱 獨著稱 +獨著錄 獨著錄 +獨著書 獨著書 +對著作 對著作 +對著者 對著者 +對著名 對著名 +對著述 對著述 +對著稱 對著稱 +對著錄 對著錄 +對著書 對著書 +盾著作 盾著作 +盾著者 盾著者 +盾著名 盾著名 +盾著述 盾著述 +盾著稱 盾著稱 +盾著錄 盾著錄 +盾著書 盾著書 +犯不著作 犯不著作 +犯不著者 犯不著者 +犯不著名 犯不著名 +犯不著述 犯不著述 +犯不著稱 犯不著稱 +犯不著錄 犯不著錄 +犯不著書 犯不著書 +福著作 福著作 +福著者 福著者 +福著名 福著名 +福著述 福著述 +福著稱 福著稱 +福著錄 福著錄 +福著書 福著書 +趕著作 趕著作 +趕著者 趕著者 +趕著名 趕著名 +趕著述 趕著述 +趕著稱 趕著稱 +趕著錄 趕著錄 +趕著書 趕著書 +高著作 高著作 +高著者 高著者 +高著名 高著名 +高著述 高著述 +高著稱 高著稱 +高著錄 高著錄 +高著書 高著書 +隔著作 隔著作 +隔著者 隔著者 +隔著名 隔著名 +隔著述 隔著述 +隔著稱 隔著稱 +隔著錄 隔著錄 +隔著書 隔著書 +跟著作 跟著作 +跟著者 跟著者 +跟著名 跟著名 +跟著述 跟著述 +跟著稱 跟著稱 +跟著錄 跟著錄 +跟著書 跟著書 +孤著作 孤著作 +孤著者 孤著者 +孤著名 孤著名 +孤著述 孤著述 +孤著稱 孤著稱 +孤著錄 孤著錄 +孤著書 孤著書 +關著作 關著作 +關著者 關著者 +關著名 關著名 +關著述 關著述 +關著稱 關著稱 +關著錄 關著錄 +關著書 關著書 +管著作 管著作 +管著者 管著者 +管著名 管著名 +管著述 管著述 +管著稱 管著稱 +管著錄 管著錄 +管著書 管著書 +慣著作 慣著作 +慣著者 慣著者 +慣著名 慣著名 +慣著述 慣著述 +慣著稱 慣著稱 +慣著錄 慣著錄 +慣著書 慣著書 +光著作 光著作 +光著者 光著者 +光著名 光著名 +光著述 光著述 +光著稱 光著稱 +光著錄 光著錄 +光著書 光著書 +跪著作 跪著作 +跪著者 跪著者 +跪著名 跪著名 +跪著述 跪著述 +跪著稱 跪著稱 +跪著錄 跪著錄 +跪著書 跪著書 +裹著作 裹著作 +裹著者 裹著者 +裹著名 裹著名 +裹著述 裹著述 +裹著稱 裹著稱 +裹著錄 裹著錄 +裹著書 裹著書 +撼著作 撼著作 +撼著者 撼著者 +撼著名 撼著名 +撼著述 撼著述 +撼著稱 撼著稱 +撼著錄 撼著錄 +撼著書 撼著書 +喝著作 喝著作 +喝著者 喝著者 +喝著名 喝著名 +喝著述 喝著述 +喝著稱 喝著稱 +喝著錄 喝著錄 +喝著書 喝著書 +候著作 候著作 +候著者 候著者 +候著名 候著名 +候著述 候著述 +候著稱 候著稱 +候著錄 候著錄 +候著書 候著書 +懷著作 懷著作 +懷著者 懷著者 +懷著名 懷著名 +懷著述 懷著述 +懷著稱 懷著稱 +懷著錄 懷著錄 +懷著書 懷著書 +晃著作 晃著作 +晃著者 晃著者 +晃著名 晃著名 +晃著述 晃著述 +晃著稱 晃著稱 +晃著錄 晃著錄 +揮著作 揮著作 +揮著者 揮著者 +揮著名 揮著名 +揮著述 揮著述 +揮著稱 揮著稱 +揮著錄 揮著錄 +活著作 活著作 +活著者 活著者 +活著名 活著名 +活著述 活著述 +活著稱 活著稱 +活著錄 活著錄 +活著書 活著書 +獲著作 獲著作 +獲著者 獲著者 +獲著名 獲著名 +獲著述 獲著述 +獲著稱 獲著稱 +獲著錄 獲著錄 +獲著書 獲著書 +獲著作 獲著作 +獲著者 獲著者 +獲著名 獲著名 +獲著述 獲著述 +獲著稱 獲著稱 +獲著錄 獲著錄 +獲著書 獲著書 +急著作 急著作 +急著者 急著者 +急著名 急著名 +急著述 急著述 +急著稱 急著稱 +急著錄 急著錄 +急著書 急著書 +記著作 記著作 +記著者 記著者 +記著名 記著名 +記著述 記著述 +記著稱 記著稱 +記著錄 記著錄 +記著書 記著書 +冀著作 冀著作 +冀著者 冀著者 +冀著名 冀著名 +冀著述 冀著述 +冀著稱 冀著稱 +冀著錄 冀著錄 +冀著書 冀著書 +夾著作 夾著作 +夾著者 夾著者 +夾著名 夾著名 +夾著述 夾著述 +夾著稱 夾著稱 +夾著錄 夾著錄 +夾著書 夾著書 +駕著作 駕著作 +駕著者 駕著者 +駕著名 駕著名 +駕著述 駕著述 +駕著稱 駕著稱 +駕著錄 駕著錄 +駕著書 駕著書 +見著作 見著作 +見著者 見著者 +見著名 見著名 +見著述 見著述 +見著稱 見著稱 +見著錄 見著錄 +見著書 見著書 +閑著作 閑著作 +閑著者 閑著者 +閑著名 閑著名 +閑著述 閑著述 +閑著稱 閑著稱 +閑著錄 閑著錄 +閑著書 閑著書 +叫著作 叫著作 +叫著者 叫著者 +叫著名 叫著名 +叫著述 叫著述 +叫著稱 叫著稱 +叫著錄 叫著錄 +叫著書 叫著書 +接著作 接著作 +接著者 接著者 +接著名 接著名 +接著述 接著述 +接著稱 接著稱 +接著錄 接著錄 +借著作 借著作 +借著者 借著者 +借著名 借著名 +借著述 借著述 +借著稱 借著稱 +借著錄 借著錄 +借著書 借著書 +借著作 借著作 +借著者 借著者 +借著名 借著名 +借著述 借著述 +借著稱 借著稱 +借著錄 借著錄 +借著書 借著書 +據著作 據著作 +據著者 據著者 +據著名 據著名 +據著述 據著述 +據著稱 據著稱 +據著錄 據著錄 +據著書 據著書 +開著作 開著作 +開著者 開著者 +開著名 開著名 +開著述 開著述 +開著稱 開著稱 +開著錄 開著錄 +開著書 開著書 +看著作 看著作 +看著者 看著者 +看著名 看著名 +看著述 看著述 +看著稱 看著稱 +看著錄 看著錄 +看著書 看著書 +康著作 康著作 +康著者 康著者 +康著名 康著名 +康著述 康著述 +康著稱 康著稱 +康著錄 康著錄 +康著書 康著書 +扛著作 扛著作 +扛著者 扛著者 +扛著名 扛著名 +扛著述 扛著述 +扛著稱 扛著稱 +扛著錄 扛著錄 +扛著書 扛著書 +考著作 考著作 +考著者 考著者 +考著名 考著名 +考著述 考著述 +考著稱 考著稱 +考著錄 考著錄 +考著書 考著書 +渴著作 渴著作 +渴著者 渴著者 +渴著名 渴著名 +渴著述 渴著述 +渴著稱 渴著稱 +渴著錄 渴著錄 +渴著書 渴著書 +刻著作 刻著作 +刻著者 刻著者 +刻著名 刻著名 +刻著述 刻著述 +刻著稱 刻著稱 +刻著錄 刻著錄 +刻著書 刻著書 +空著作 空著作 +空著者 空著者 +空著名 空著名 +空著述 空著述 +空著稱 空著稱 +空著錄 空著錄 +空著書 空著書 +哭著作 哭著作 +哭著者 哭著者 +哭著名 哭著名 +哭著述 哭著述 +哭著稱 哭著稱 +哭著錄 哭著錄 +哭著書 哭著書 +苦著作 苦著作 +苦著者 苦著者 +苦著名 苦著名 +苦著述 苦著述 +苦著稱 苦著稱 +苦著錄 苦著錄 +苦著書 苦著書 +捆著作 捆著作 +捆著者 捆著者 +捆著名 捆著名 +捆著述 捆著述 +捆著稱 捆著稱 +捆著錄 捆著錄 +困著作 困著作 +困著者 困著者 +困著名 困著名 +困著述 困著述 +困著稱 困著稱 +困著錄 困著錄 +困著書 困著書 +拉著作 拉著作 +拉著者 拉著者 +拉著名 拉著名 +拉著述 拉著述 +拉著稱 拉著稱 +拉著錄 拉著錄 +拉著書 拉著書 +來著作 來著作 +來著者 來著者 +來著名 來著名 +來著述 來著述 +來著稱 來著稱 +來著錄 來著錄 +來著書 來著書 +樂著作 樂著作 +樂著者 樂著者 +樂著名 樂著名 +樂著述 樂著述 +樂著稱 樂著稱 +樂著錄 樂著錄 +樂著書 樂著書 +努力著作 努力著作 +努力著者 努力著者 +努力著名 努力著名 +努力著述 努力著述 +努力著稱 努力著稱 +努力著錄 努力著錄 +努力著書 努力著書 +麗著作 麗著作 +麗著者 麗著者 +麗著名 麗著名 +麗著述 麗著述 +麗著稱 麗著稱 +麗著錄 麗著錄 +麗著書 麗著書 +連著作 連著作 +連著者 連著者 +連著名 連著名 +連著述 連著述 +連著稱 連著稱 +連著錄 連著錄 +連著書 連著書 +戀著作 戀著作 +戀著者 戀著者 +戀著名 戀著名 +戀著述 戀著述 +戀著稱 戀著稱 +戀著錄 戀著錄 +戀著書 戀著書 +涼著作 涼著作 +涼著者 涼著者 +涼著名 涼著名 +涼著述 涼著述 +涼著稱 涼著稱 +涼著錄 涼著錄 +涼著書 涼著書 +亮著作 亮著作 +亮著者 亮著者 +亮著名 亮著名 +亮著述 亮著述 +亮著稱 亮著稱 +亮著錄 亮著錄 +亮著書 亮著書 +臨著作 臨著作 +臨著者 臨著者 +臨著名 臨著名 +臨著述 臨著述 +臨著稱 臨著稱 +臨著錄 臨著錄 +臨著書 臨著書 +拎著作 拎著作 +拎著者 拎著者 +拎著名 拎著名 +拎著述 拎著述 +拎著稱 拎著稱 +拎著錄 拎著錄 +領著作 領著作 +領著者 領著者 +領著名 領著名 +領著述 領著述 +領著稱 領著稱 +領著錄 領著錄 +領著書 領著書 +流著作 流著作 +流著者 流著者 +流著名 流著名 +流著述 流著述 +流著稱 流著稱 +流著錄 流著錄 +流著書 流著書 +留著作 留著作 +留著者 留著者 +留著名 留著名 +留著述 留著述 +留著稱 留著稱 +留著錄 留著錄 +留著書 留著書 +摟著作 摟著作 +摟著者 摟著者 +摟著名 摟著名 +摟著述 摟著述 +摟著稱 摟著稱 +摟著錄 摟著錄 +陋著作 陋著作 +陋著者 陋著者 +陋著名 陋著名 +陋著述 陋著述 +陋著稱 陋著稱 +陋著錄 陋著錄 +陋著書 陋著書 +落著作 落著作 +落著者 落著者 +落著名 落著名 +落著述 落著述 +落著稱 落著稱 +落著錄 落著錄 +落著書 落著書 +罵著作 罵著作 +罵著者 罵著者 +罵著名 罵著名 +罵著述 罵著述 +罵著稱 罵著稱 +罵著錄 罵著錄 +罵著書 罵著書 +瞞著作 瞞著作 +瞞著者 瞞著者 +瞞著名 瞞著名 +瞞著述 瞞著述 +瞞著稱 瞞著稱 +瞞著錄 瞞著錄 +瞞著書 瞞著書 +漫著作 漫著作 +漫著者 漫著者 +漫著名 漫著名 +漫著述 漫著述 +漫著稱 漫著稱 +漫著錄 漫著錄 +漫著書 漫著書 +忙著作 忙著作 +忙著者 忙著者 +忙著名 忙著名 +忙著述 忙著述 +忙著稱 忙著稱 +忙著錄 忙著錄 +忙著書 忙著書 +冒著作 冒著作 +冒著者 冒著者 +冒著名 冒著名 +冒著述 冒著述 +冒著稱 冒著稱 +冒著錄 冒著錄 +冒著書 冒著書 +美著作 美著作 +美著者 美著者 +美著名 美著名 +美著述 美著述 +美著稱 美著稱 +美著錄 美著錄 +美著書 美著書 +夢著作 夢著作 +夢著者 夢著者 +夢著名 夢著名 +夢著述 夢著述 +夢著稱 夢著稱 +夢著錄 夢著錄 +夢著書 夢著書 +蒙著作 蒙著作 +蒙著者 蒙著者 +蒙著名 蒙著名 +蒙著述 蒙著述 +蒙著稱 蒙著稱 +蒙著錄 蒙著錄 +蒙著書 蒙著書 +拿著作 拿著作 +拿著者 拿著者 +拿著名 拿著名 +拿著述 拿著述 +拿著稱 拿著稱 +拿著錄 拿著錄 +逆著作 逆著作 +逆著者 逆著者 +逆著名 逆著名 +逆著述 逆著述 +逆著稱 逆著稱 +逆著錄 逆著錄 +逆著書 逆著書 +釀著作 釀著作 +釀著者 釀著者 +釀著名 釀著名 +釀著述 釀著述 +釀著稱 釀著稱 +釀著錄 釀著錄 +釀著書 釀著書 +努著作 努著作 +努著者 努著者 +努著名 努著名 +努著述 努著述 +努著稱 努著稱 +努著錄 努著錄 +努著書 努著書 +趴著作 趴著作 +趴著者 趴著者 +趴著名 趴著名 +趴著述 趴著述 +趴著稱 趴著稱 +趴著錄 趴著錄 +趴著書 趴著書 +跑著作 跑著作 +跑著者 跑著者 +跑著名 跑著名 +跑著述 跑著述 +跑著稱 跑著稱 +跑著錄 跑著錄 +跑著書 跑著書 +陪著作 陪著作 +陪著者 陪著者 +陪著名 陪著名 +陪著述 陪著述 +陪著稱 陪著稱 +陪著錄 陪著錄 +陪著書 陪著書 +配著作 配著作 +配著者 配著者 +配著名 配著名 +配著述 配著述 +配著稱 配著稱 +配著錄 配著錄 +配著書 配著書 +披著作 披著作 +披著者 披著者 +披著名 披著名 +披著述 披著述 +披著稱 披著稱 +披著錄 披著錄 +披著書 披著書 +騙著作 騙著作 +騙著者 騙著者 +騙著名 騙著名 +騙著述 騙著述 +騙著稱 騙著稱 +騙著錄 騙著錄 +騙著書 騙著書 +飄著作 飄著作 +飄著者 飄著者 +飄著名 飄著名 +飄著述 飄著述 +飄著稱 飄著稱 +飄著錄 飄著錄 +飄著書 飄著書 +拼著作 拼著作 +拼著者 拼著者 +拼著名 拼著名 +拼著述 拼著述 +拼著稱 拼著稱 +拼著錄 拼著錄 +鋪著作 鋪著作 +鋪著者 鋪著者 +鋪著名 鋪著名 +鋪著述 鋪著述 +鋪著稱 鋪著稱 +鋪著錄 鋪著錄 +鋪著書 鋪著書 +騎著作 騎著作 +騎著者 騎著者 +騎著名 騎著名 +騎著述 騎著述 +騎著稱 騎著稱 +騎著錄 騎著錄 +騎著書 騎著書 +牽著作 牽著作 +牽著者 牽著者 +牽著名 牽著名 +牽著述 牽著述 +牽著稱 牽著稱 +牽著錄 牽著錄 +牽著書 牽著書 +求著作 求著作 +求著者 求著者 +求著名 求著名 +求著述 求著述 +求著稱 求著稱 +求著錄 求著錄 +求著書 求著書 +去著作 去著作 +去著者 去著者 +去著名 去著名 +去著述 去著述 +去著稱 去著稱 +去著錄 去著錄 +去著書 去著書 +嚷著作 嚷著作 +嚷著者 嚷著者 +嚷著名 嚷著名 +嚷著述 嚷著述 +嚷著稱 嚷著稱 +嚷著錄 嚷著錄 +嚷著書 嚷著書 +繞著作 繞著作 +繞著者 繞著者 +繞著名 繞著名 +繞著述 繞著述 +繞著稱 繞著稱 +繞著錄 繞著錄 +繞著書 繞著書 +忍著作 忍著作 +忍著者 忍著者 +忍著名 忍著名 +忍著述 忍著述 +忍著稱 忍著稱 +忍著錄 忍著錄 +忍著書 忍著書 +揉著作 揉著作 +揉著者 揉著者 +揉著名 揉著名 +揉著述 揉著述 +揉著稱 揉著稱 +揉著錄 揉著錄 +揉著書 揉著書 +潤著作 潤著作 +潤著者 潤著者 +潤著名 潤著名 +潤著述 潤著述 +潤著稱 潤著稱 +潤著錄 潤著錄 +潤著書 潤著書 +燒著作 燒著作 +燒著者 燒著者 +燒著名 燒著名 +燒著述 燒著述 +燒著稱 燒著稱 +燒著錄 燒著錄 +燒著書 燒著書 +身著作 身著作 +身著者 身著者 +身著名 身著名 +身著述 身著述 +身著稱 身著稱 +身著錄 身著錄 +身著書 身著書 +沉著作 沉著作 +沉著者 沉著者 +沉著名 沉著名 +沉著述 沉著述 +沉著稱 沉著稱 +沉著錄 沉著錄 +沉著書 沉著書 +盛著作 盛著作 +盛著者 盛著者 +盛著名 盛著名 +盛著述 盛著述 +盛著稱 盛著稱 +盛著錄 盛著錄 +盛著書 盛著書 +試著作 試著作 +試著者 試著者 +試著名 試著名 +試著述 試著述 +試著稱 試著稱 +試著錄 試著錄 +試著書 試著書 +守著作 守著作 +守著者 守著者 +守著名 守著名 +守著述 守著述 +守著稱 守著稱 +守著錄 守著錄 +守著書 守著書 +受著作 受著作 +受著者 受著者 +受著名 受著名 +受著述 受著述 +受著稱 受著稱 +受著錄 受著錄 +受著書 受著書 +梳著作 梳著作 +梳著者 梳著者 +梳著名 梳著名 +梳著述 梳著述 +梳著稱 梳著稱 +梳著錄 梳著錄 +豎著作 豎著作 +豎著者 豎著者 +豎著名 豎著名 +豎著述 豎著述 +豎著稱 豎著稱 +豎著錄 豎著錄 +豎著書 豎著書 +數著作 數著作 +數著者 數著者 +數著名 數著名 +數著述 數著述 +數著稱 數著稱 +數著錄 數著錄 +睡著作 睡著作 +睡著者 睡著者 +睡著名 睡著名 +睡著述 睡著述 +睡著稱 睡著稱 +睡著錄 睡著錄 +睡著書 睡著書 +順著作 順著作 +順著者 順著者 +順著名 順著名 +順著述 順著述 +順著稱 順著稱 +順著錄 順著錄 +順著書 順著書 +隨著作 隨著作 +隨著者 隨著者 +隨著名 隨著名 +隨著述 隨著述 +隨著稱 隨著稱 +隨著錄 隨著錄 +隨著書 隨著書 +踏著作 踏著作 +踏著者 踏著者 +踏著名 踏著名 +踏著述 踏著述 +踏著稱 踏著稱 +踏著錄 踏著錄 +抬著作 抬著作 +抬著者 抬著者 +抬著名 抬著名 +抬著述 抬著述 +抬著稱 抬著稱 +抬著錄 抬著錄 +躺著作 躺著作 +躺著者 躺著者 +躺著名 躺著名 +躺著述 躺著述 +躺著稱 躺著稱 +躺著錄 躺著錄 +躺著書 躺著書 +提著作 提著作 +提著者 提著者 +提著名 提著名 +提著述 提著述 +提著稱 提著稱 +提著錄 提著錄 +甜著作 甜著作 +甜著者 甜著者 +甜著名 甜著名 +甜著述 甜著述 +甜著稱 甜著稱 +甜著錄 甜著錄 +甜著書 甜著書 +挑著作 挑著作 +挑著者 挑著者 +挑著名 挑著名 +挑著述 挑著述 +挑著稱 挑著稱 +挑著錄 挑著錄 +跳著作 跳著作 +跳著者 跳著者 +跳著名 跳著名 +跳著述 跳著述 +跳著稱 跳著稱 +跳著錄 跳著錄 +跳著書 跳著書 +聽著作 聽著作 +聽著者 聽著者 +聽著名 聽著名 +聽著述 聽著述 +聽著稱 聽著稱 +聽著錄 聽著錄 +聽著書 聽著書 +偷著作 偷著作 +偷著者 偷著者 +偷著名 偷著名 +偷著述 偷著述 +偷著稱 偷著稱 +偷著錄 偷著錄 +偷著書 偷著書 +拖著作 拖著作 +拖著者 拖著者 +拖著名 拖著名 +拖著述 拖著述 +拖著稱 拖著稱 +拖著錄 拖著錄 +望著作 望著作 +望著者 望著者 +望著名 望著名 +望著述 望著述 +望著稱 望著稱 +望著錄 望著錄 +望著書 望著書 +圍著作 圍著作 +圍著者 圍著者 +圍著名 圍著名 +圍著述 圍著述 +圍著稱 圍著稱 +圍著錄 圍著錄 +圍著書 圍著書 +味著作 味著作 +味著者 味著者 +味著名 味著名 +味著述 味著述 +味著稱 味著稱 +味著錄 味著錄 +味著書 味著書 +想著作 想著作 +想著者 想著者 +想著名 想著名 +想著述 想著述 +想著稱 想著稱 +想著錄 想著錄 +想著書 想著書 +響著作 響著作 +響著者 響著者 +響著名 響著名 +響著述 響著述 +響著稱 響著稱 +響著錄 響著錄 +響著書 響著書 +向著作 向著作 +向著者 向著者 +向著名 向著名 +向著述 向著述 +向著稱 向著稱 +向著錄 向著錄 +向著書 向著書 +笑著作 笑著作 +笑著者 笑著者 +笑著名 笑著名 +笑著述 笑著述 +笑著稱 笑著稱 +笑著錄 笑著錄 +笑著書 笑著書 +心著作 心著作 +心著者 心著者 +心著名 心著名 +心著述 心著述 +心著稱 心著稱 +心著錄 心著錄 +心著書 心著書 +信著作 信著作 +信著者 信著者 +信著名 信著名 +信著述 信著述 +信著稱 信著稱 +信著錄 信著錄 +信著書 信著書 +行著作 行著作 +行著者 行著者 +行著名 行著名 +行著述 行著述 +行著稱 行著稱 +行著錄 行著錄 +行著書 行著書 +性著作 性著作 +性著者 性著者 +性著名 性著名 +性著述 性著述 +性著稱 性著稱 +性著錄 性著錄 +性著書 性著書 +學著作 學著作 +學著者 學著者 +學著名 學著名 +學著述 學著述 +學著稱 學著稱 +學著錄 學著錄 +學著書 學著書 +尋著作 尋著作 +尋著者 尋著者 +尋著名 尋著名 +尋著述 尋著述 +尋著稱 尋著稱 +尋著錄 尋著錄 +尋著書 尋著書 +循著作 循著作 +循著者 循著者 +循著名 循著名 +循著述 循著述 +循著稱 循著稱 +循著錄 循著錄 +循著書 循著書 +壓著作 壓著作 +壓著者 壓著者 +壓著名 壓著名 +壓著述 壓著述 +壓著稱 壓著稱 +壓著錄 壓著錄 +壓著書 壓著書 +雅著作 雅著作 +雅著者 雅著者 +雅著名 雅著名 +雅著述 雅著述 +雅著稱 雅著稱 +雅著錄 雅著錄 +雅著書 雅著書 +沿著作 沿著作 +沿著者 沿著者 +沿著名 沿著名 +沿著述 沿著述 +沿著稱 沿著稱 +沿著錄 沿著錄 +沿著書 沿著書 +耀著作 耀著作 +耀著者 耀著者 +耀著名 耀著名 +耀著述 耀著述 +耀著稱 耀著稱 +耀著錄 耀著錄 +耀著書 耀著書 +掖著作 掖著作 +掖著者 掖著者 +掖著名 掖著名 +掖著述 掖著述 +掖著稱 掖著稱 +掖著錄 掖著錄 +衣著作 衣著作 +衣著者 衣著者 +衣著名 衣著名 +衣著述 衣著述 +衣著稱 衣著稱 +衣著錄 衣著錄 +衣著書 衣著書 +疑著作 疑著作 +疑著者 疑著者 +疑著名 疑著名 +疑著述 疑著述 +疑著稱 疑著稱 +疑著錄 疑著錄 +疑著書 疑著書 +溢著作 溢著作 +溢著者 溢著者 +溢著名 溢著名 +溢著述 溢著述 +溢著稱 溢著稱 +溢著錄 溢著錄 +溢著書 溢著書 +藝著作 藝著作 +藝著者 藝著者 +藝著名 藝著名 +藝著述 藝著述 +藝著稱 藝著稱 +藝著錄 藝著錄 +藝著書 藝著書 +因著作 因著作 +因著者 因著者 +因著名 因著名 +因著述 因著述 +因著稱 因著稱 +因著錄 因著錄 +因著書 因著書 +印著作 印著作 +印著者 印著者 +印著名 印著名 +印著述 印著述 +印著稱 印著稱 +印著錄 印著錄 +印著書 印著書 +應著作 應著作 +應著者 應著者 +應著名 應著名 +應著述 應著述 +應著稱 應著稱 +應著錄 應著錄 +應著書 應著書 +映著作 映著作 +映著者 映著者 +映著名 映著名 +映著述 映著述 +映著稱 映著稱 +映著錄 映著錄 +映著書 映著書 +用著作 用著作 +用著者 用著者 +用著名 用著名 +用著述 用著述 +用著稱 用著稱 +用著錄 用著錄 +用著書 用著書 +悠著作 悠著作 +悠著者 悠著者 +悠著名 悠著名 +悠著述 悠著述 +悠著稱 悠著稱 +悠著錄 悠著錄 +悠著書 悠著書 +有著作 有著作 +有著者 有著者 +有著名 有著名 +有著述 有著述 +有著稱 有著稱 +有著錄 有著錄 +有著書 有著書 +與著作 與著作 +與著者 與著者 +與著名 與著名 +與著述 與著述 +與著稱 與著稱 +與著錄 與著錄 +與著書 與著書 +語著作 語著作 +語著者 語著者 +語著名 語著名 +語著述 語著述 +語著稱 語著稱 +語著錄 語著錄 +語著書 語著書 +豫著作 豫著作 +豫著者 豫著者 +豫著名 豫著名 +豫著述 豫著述 +豫著稱 豫著稱 +豫著錄 豫著錄 +豫著書 豫著書 +遠著作 遠著作 +遠著者 遠著者 +遠著名 遠著名 +遠著述 遠著述 +遠著稱 遠著稱 +遠著錄 遠著錄 +遠著書 遠著書 +躍著作 躍著作 +躍著者 躍著者 +躍著名 躍著名 +躍著述 躍著述 +躍著稱 躍著稱 +躍著錄 躍著錄 +躍著書 躍著書 +雜著作 雜著作 +雜著者 雜著者 +雜著名 雜著名 +雜著述 雜著述 +雜著稱 雜著稱 +雜著錄 雜著錄 +雜著書 雜著書 +載著作 載著作 +載著者 載著者 +載著名 載著名 +載著述 載著述 +載著稱 載著稱 +載著錄 載著錄 +載著書 載著書 +在著作 在著作 +在著者 在著者 +在著名 在著名 +在著述 在著述 +在著稱 在著稱 +在著錄 在著錄 +在著書 在著書 +紮著作 紮著作 +紮著者 紮著者 +紮著名 紮著名 +紮著述 紮著述 +紮著稱 紮著稱 +紮著錄 紮著錄 +紮著書 紮著書 +展著作 展著作 +展著者 展著者 +展著名 展著名 +展著述 展著述 +展著稱 展著稱 +展著錄 展著錄 +展著書 展著書 +站著作 站著作 +站著者 站著者 +站著名 站著名 +站著述 站著述 +站著稱 站著稱 +站著錄 站著錄 +站著書 站著書 +戰著作 戰著作 +戰著者 戰著者 +戰著名 戰著名 +戰著述 戰著述 +戰著稱 戰著稱 +戰著錄 戰著錄 +戰著書 戰著書 +蘸著作 蘸著作 +蘸著者 蘸著者 +蘸著名 蘸著名 +蘸著述 蘸著述 +蘸著稱 蘸著稱 +蘸著錄 蘸著錄 +蘸著書 蘸著書 +仗著作 仗著作 +仗著者 仗著者 +仗著名 仗著名 +仗著述 仗著述 +仗著稱 仗著稱 +仗著錄 仗著錄 +仗著書 仗著書 +照著作 照著作 +照著者 照著者 +照著名 照著名 +照著述 照著述 +照著稱 照著稱 +照著錄 照著錄 +照著書 照著書 +罩著作 罩著作 +罩著者 罩著者 +罩著名 罩著名 +罩著述 罩著述 +罩著稱 罩著稱 +罩著錄 罩著錄 +罩著書 罩著書 +貞著作 貞著作 +貞著者 貞著者 +貞著名 貞著名 +貞著述 貞著述 +貞著稱 貞著稱 +貞著錄 貞著錄 +貞著書 貞著書 +枕著作 枕著作 +枕著者 枕著者 +枕著名 枕著名 +枕著述 枕著述 +枕著稱 枕著稱 +枕著錄 枕著錄 +爭著作 爭著作 +爭著者 爭著者 +爭著名 爭著名 +爭著述 爭著述 +爭著稱 爭著稱 +爭著錄 爭著錄 +爭著書 爭著書 +掙著作 掙著作 +掙著者 掙著者 +掙著名 掙著名 +掙著述 掙著述 +掙著稱 掙著稱 +掙著錄 掙著錄 +掙著書 掙著書 +制著作 制著作 +制著者 制著者 +制著名 制著名 +制著述 制著述 +制著稱 制著稱 +制著錄 制著錄 +制著書 制著書 +志著作 志著作 +志著者 志著者 +志著名 志著名 +志著述 志著述 +志著稱 志著稱 +志著錄 志著錄 +志著書 志著書 +皺著作 皺著作 +皺著者 皺著者 +皺著名 皺著名 +皺著述 皺著述 +皺著稱 皺著稱 +皺著錄 皺著錄 +皺著書 皺著書 +住著作 住著作 +住著者 住著者 +住著名 住著名 +住著述 住著述 +住著稱 住著稱 +住著錄 住著錄 +住著書 住著書 +抓著作 抓著作 +抓著者 抓著者 +抓著名 抓著名 +抓著述 抓著述 +抓著稱 抓著稱 +抓著錄 抓著錄 +轉著作 轉著作 +轉著者 轉著者 +轉著名 轉著名 +轉著述 轉著述 +轉著稱 轉著稱 +轉著錄 轉著錄 +轉著書 轉著書 +裝著作 裝著作 +裝著者 裝著者 +裝著名 裝著名 +裝著述 裝著述 +裝著稱 裝著稱 +裝著錄 裝著錄 +裝著書 裝著書 +追著作 追著作 +追著者 追著者 +追著名 追著名 +追著述 追著述 +追著稱 追著稱 +追著錄 追著錄 +追著書 追著書 +髭著作 髭著作 +髭著者 髭著者 +髭著名 髭著名 +髭著述 髭著述 +髭著稱 髭著稱 +髭著錄 髭著錄 +髭著書 髭著書 +走著作 走著作 +走著者 走著者 +走著名 走著名 +走著述 走著述 +走著稱 走著稱 +走著錄 走著錄 +走著書 走著書 +坐著作 坐著作 +坐著者 坐著者 +坐著名 坐著名 +坐著述 坐著述 +坐著稱 坐著稱 +坐著錄 坐著錄 +坐著書 坐著書 +做著作 做著作 +做著者 做著者 +做著名 做著名 +做著述 做著述 +做著稱 做著稱 +做著錄 做著錄 +做著書 做著書 +含著作 含著作 +含著者 含著者 +含著名 含著名 +含著述 含著述 +含著稱 含著稱 +含著錄 含著錄 +含著書 含著書 +涵著作 涵著作 +涵著者 涵著者 +涵著名 涵著名 +涵著述 涵著述 +涵著稱 涵著稱 +涵著錄 涵著錄 +涵著書 涵著書 +演著作 演著作 +演著者 演著者 +演著名 演著名 +演著述 演著述 +演著稱 演著稱 +演著錄 演著錄 +演著書 演著書 +保障著作 保障著作 +保障著者 保障著者 +保障著名 保障著名 +保障著述 保障著述 +保障著稱 保障著稱 +保障著錄 保障著錄 +保障著書 保障著書 +黏著作 黏著作 +黏著者 黏著者 +黏著名 黏著名 +黏著述 黏著述 +黏著稱 黏著稱 +黏著錄 黏著錄 +黏著書 黏著書 +膠著作 膠著作 +膠著者 膠著者 +膠著名 膠著名 +膠著述 膠著述 +膠著稱 膠著稱 +膠著錄 膠著錄 +膠著書 膠著書 +附著作 附著作 +附著者 附著者 +附著名 附著名 +附著述 附著述 +附著稱 附著稱 +附著錄 附著錄 +附著書 附著書 +代表著作 代表著作 +代表著者 代表著者 +代表著名 代表著名 +代表著述 代表著述 +代表著稱 代表著稱 +代表著錄 代表著錄 +代表著書 代表著書 +浮著作 浮著作 +浮著者 浮著者 +浮著名 浮著名 +浮著述 浮著述 +浮著稱 浮著稱 +浮著錄 浮著錄 +浮著書 浮著書 +寫著作 寫著作 +寫著者 寫著者 +寫著名 寫著名 +寫著述 寫著述 +寫著稱 寫著稱 +寫著錄 寫著錄 +寫著書 寫著書 +遇著作 遇著作 +遇著者 遇著者 +遇著名 遇著名 +遇著述 遇著述 +遇著稱 遇著稱 +遇著錄 遇著錄 +遇著書 遇著書 +殺著作 殺著作 +殺著者 殺著者 +殺著名 殺著名 +殺著述 殺著述 +殺著稱 殺著稱 +殺著錄 殺著錄 +殺著書 殺著書 +標誌著 標誌着 +幹著 幹着 +干着 幹着 +干着急 干着急 +流露著 流露着 +靠著 靠着 +靠著作 靠著作 +靠著名 靠著名 +靠著錄 靠著錄 +靠著录 靠著錄 +靠著稱 靠著稱 +靠著称 靠著稱 +靠著者 靠著者 +靠著述 靠著述 +新著龍虎門 新著龍虎門 +迫著 迫着 +心繫著 心繫着 +藉著 藉着 +吃得著 吃得着 +吃不著 吃不着 +吃著 吃着 +聞得著 闻得着 +聞不著 闻不着 +聞著 闻着 +嗅得著 嗅得着 +嗅不著 嗅不着 +嗅著 嗅着 +警戒著 警戒着 +榴莲 榴槤 +榴蓮 榴槤 +发布 發佈 +發布 發佈 +掛鉤 掛鈎 +鉤心鬥角 鈎心鬥角 +咤 咤 +叱吒 叱咤 +叱咤 叱咤 +醯 酰 +醯醬 醯醬 +醯雞 醯雞 +醯酱 醯醬 +醯鸡 醯雞 +醯醋 醯醋 +醯醢 醯醢 +醯壶 醯壺 +醯壺 醯壺 +菸 煙 +雪裡紅 雪裏紅 +雪裡蕻 雪裏蕻 +雪里蕻 雪裏蕻 +雪里红 雪裏紅 +森林裡 森林裏 +森林里 森林裏 +日子裡 日子裏 +日子里 日子裏 +故事裡 故事裏 +故事里 故事裏 +領域裡 領域裏 +领域里 領域裏 +時間裡 時間裏 +时间里 時間裏 +深淵裡 深淵裏 +深渊里 深渊裏 +醫院裡 醫院裏 +医院里 医院裏 +春假裡 春假裏 +春假里 春假裏 +暑假裡 暑假裏 +暑假里 暑假裏 +秋假裡 秋假裏 +秋假里 秋假裏 +寒假裡 寒假裏 +寒假里 寒假裏 +春天裡 春天裏 +春天里 春天裏 +夏天裡 夏天裏 +夏天里 夏天裏 +秋天裡 秋天裏 +秋天里 秋天裏 +冬天裡 冬天裏 +冬天里 冬天裏 +春日裡 春日裏 +夏日裡 夏日裏 +秋日裡 秋日裏 +冬日裡 冬日裏 +春日里 春日裏 +夏日里 夏日裏 +秋日里 秋日裏 +冬日里 冬日裏 +嘴裡 嘴裏 +嘴里 嘴裏 +心裡 心裏 +心里 心裏 +皮裡陽秋 皮裏陽秋 +皮里阳秋 皮裏陽秋 +肚裡 肚裏 +肚里 肚裏 +苦裡 苦裏 +苦里 苦裏 +裡勾外連 裏勾外連 +里勾外连 裏勾外連 +裡面 裏面 +里面 裏面 +這裡 這裏 +這里 這裏 +點裡 點裏 +点里 點裏 +中文裡 中文裏 +中文里 中文裏 +山洞里 山洞裏 +山洞裡 山洞裏 +近角聪信 近角聰信 +近角聰信 近角聰信 +世界里 世界裏 +世界裡 世界裏 +眼睛里 眼睛裏 +眼睛裡 眼睛裏 +百科裡 百科裏 +百科里 百科裏 +歷史裡 歷史裏 +历史里 歷史裏 +戲裡 戲裏 +戏里 戲裏 +作品裡 作品裏 +作品里 作品裏 +專輯裡 專輯裏 +专辑里 專輯裏 +年代裡 年代裏 +年代里 年代裏 +棺材裡 棺材裏 +棺材里 棺材裏 +學裡 學裏 +学里 學裏 +獄裡 獄裏 +狱里 獄裏 +館裡 館裏 +馆里 館裏 +系列裡 系列裏 +系列里 系列裏 +村子裡 村子裏 +村子里 村子裏 +分布 分佈 +分布于 分佈於 +分布於 分佈於 +想象 想像 +無線電視 無綫電視 +无线电视 無綫電視 +無線收費 無綫收費 +无线收费 無綫收費 +無線節目 無綫節目 +无线节目 無綫節目 +無線劇集 無綫劇集 +无线剧集 無綫劇集 +東鐵線 東鐵綫 +东铁线 東鐵綫 +觀塘線 觀塘綫 +观塘线 觀塘綫 +荃灣線 荃灣綫 +荃湾线 荃灣綫 +港島線 港島綫 +港岛线 港島綫 +東涌線 東涌綫 +东涌线 東涌綫 +將軍澳線 將軍澳綫 +将军澳线 將軍澳綫 +西鐵線 西鐵綫 +西铁线 西鐵綫 +馬鞍山線 馬鞍山綫 +马鞍山线 馬鞍山綫 +迪士尼線 迪士尼綫 +迪士尼线 迪士尼綫 +沙田至中環線 沙田至中環綫 +沙田至中环线 沙田至中環綫 +沙中線 沙中綫 +沙中线 沙中綫 +北環線 北環綫 +北环线 北環綫 +機場快線 機場快綫 +机场快线 機場快綫 +505線 505綫 +505线 505綫 +507線 507綫 +507线 507綫 +610線 610綫 +610线 610綫 +614線 614綫 +614线 614綫 +614P線 614P綫 +614P线 614P綫 +615線 615綫 +615线 615綫 +615P線 615P綫 +615P线 615P綫 +705線 705綫 +705线 705綫 +706線 706綫 +706线 706綫 +751線 751綫 +751线 751綫 +751P線 751P綫 +751P线 751P綫 +761P線 761P綫 +761P线 761P綫 diff --git a/maintenance/language/zhtable/toSG.manual b/maintenance/language/zhtable/toSG.manual new file mode 100644 index 00000000..2d39aa35 --- /dev/null +++ b/maintenance/language/zhtable/toSG.manual @@ -0,0 +1,21 @@ +」 ” +「 “ +『 ‘ +』 ’ +方便面 快速面 +速食麵 快速面 +即食麵 快速面 +泡麵 快速面 +蹦极跳 绑紧跳 +笨豬跳 绑紧跳 +凉菜 冷菜 +冷盤 冷菜 +零钱 散钱 +散紙 散钱 +笑星 谐星 +夜校 夜学 +民乐 华乐 +住房 住屋 +房价 屋价 +榴莲 榴梿 +榴蓮 榴梿
\ No newline at end of file diff --git a/maintenance/language/zhtable/toSimp.manual b/maintenance/language/zhtable/toSimp.manual new file mode 100644 index 00000000..e22447a6 --- /dev/null +++ b/maintenance/language/zhtable/toSimp.manual @@ -0,0 +1,166 @@ +乾县 乾县 +萧乾 萧乾 +乾断 乾断 +乾图 乾图 +乾纲 乾纲 +乾红 乾红 +乾清宫 乾清宫 +乾仪 乾仪 +乾兴 乾兴 +乾冈 乾冈 +乾刘 乾刘 +乾刚 乾刚 +乾启 乾启 +乾宁 乾宁 +乾岗 乾岗 +乾录 乾录 +乾晖 乾晖 +乾构 乾构 +乾枢 乾枢 +乾栋 乾栋 +乾灵 乾灵 +乾窦 乾窦 +乾笃 乾笃 +乾纽 乾纽 +乾络 乾络 +乾统 乾统 +乾维 乾维 +乾罗 乾罗 +乾荫 乾荫 +乾象历 乾象历 +乾贞 乾贞 +乾贶 乾贶 +乾车 乾车 +乾轴 乾轴 +乾鉴 乾鉴 +乾钧 乾钧 +乾闼 乾闼 +乾顾 乾顾 +乾风 乾风 +乾马 乾马 +乾鹄 乾鹄 +乾鹊 乾鹊 +乾龙 乾龙 +张法乾 张法乾 +旋乾转坤 旋乾转坤 +天道为乾 天道为乾 +易经·乾 易经·乾 +易经乾 易经乾 +乾务 乾务 +黄润乾 黄润乾 +男性为乾 男性为乾 +男为乾 男为乾 +阳为乾 阳为乾 +男性为乾 男性为乾 +男性爲乾 男性为乾 +男为乾 男为乾 +男爲乾 男为乾 +阳为乾 阳为乾 +陽爲乾 阳为乾 +乾一组 乾一组 +乾一坛 乾一坛 +陈乾生 陈乾生 +陈公乾生 陈公乾生 +柳诒徵 柳诒徵 +於夫罗 於夫罗 +於梨华 於梨华 +於潜县 於潜县 +於志贺 於志贺 +憑藉 凭借 +藉端 借端 +藉故 借故 +藉口 借口 +藉助 借助 +藉手 借手 +藉詞 借词 +藉機 借机 +藉此 借此 +藉由 借由 +藉著 借着 +藉着 借着 +沈積 沉积 +沈船 沉船 +沈默 沉默 +沈沒 沉没 +彷彿 仿佛 +項鍊 项链 +肘手鍊足 肘手链足 +鍊子 链子 +鍊條 链条 +拉鍊 拉链 +鉸鍊 铰链 +鍊鎖 链锁 +鎖鍊 锁链 +鐵鍊 铁链 +金鍊 金链 +銀鍊 银链 +鍊錘 链锤 +洗鍊 洗练 +石碁镇 石碁镇 +反覆 反复 +回覆 回复 +答覆 答复 +反反覆覆 反反复复 +重覆 重复 +覆核 复核 +覆查 复查 +鬱姓 鬱姓 +鬱氏 鬱氏 +侏儸紀 侏罗纪 +夥計 伙计 +吳其濬 吴其濬 +吴其濬 吴其濬 +乾泉水 干泉水 +么半群 幺半群 +么元 幺元 +么爹 幺爹 +么叔 幺叔 +么舅 幺舅 +么爸 幺爸 +么媽 幺妈 +么姨 幺姨 +么娘 幺娘 +么孃 幺娘 +幺孃 幺娘 +么妹 幺妹 +么小 幺小 +么姓 幺姓 +么氏 幺氏 +么蛾子 幺蛾子 +幺厮 幺厮 +睪丸 睾丸 +附睪 附睾 +隱睪 隱睾 +麼麼 麽麽 +么麼 幺麽 +么麼小丑 幺麽小丑 +么鳳 幺凤 +么二三 幺二三 +么篇 幺篇 +么謙 幺谦 +这么 这么 +麴义 麴义 +乾乾淨淨 干干净净 +乾乾脆脆 干干脆脆 +肉乾乾 肉干干 +魚乾乾 鱼干干 +於于同 於于同 +於乙于同 於乙于同 +閻懷禮 闫怀礼 +醯酱 醯酱 +醯鸡 醯鸡 +醯壶 醯壶 +苧烯 苧烯 +李乾顺 李乾顺 +幹著 干着 +氾濫 泛滥 +显著 显著 +顯著 显著 +標誌著 标志着 +近角聪信 近角聪信 +修鍊 修炼 +米泽瑠美 米泽瑠美 +太閤 太阁 +候覆 候复 +待覆 待复 +批覆 批复 diff --git a/maintenance/language/zhtable/toTW.manual b/maintenance/language/zhtable/toTW.manual new file mode 100644 index 00000000..1a14e99a --- /dev/null +++ b/maintenance/language/zhtable/toTW.manual @@ -0,0 +1,411 @@ +” 」 +“ 「 +‘ 『 +’ 』 +着 著 +鈎 鉤 +钩 鉤 +衞 衛 +元凶 元凶 +元兇 元凶 +凶器 凶器 +兇器 凶器 +凶徒 凶徒 +兇徒 凶徒 +凶手 凶手 +兇手 凶手 +凶案 凶案 +兇案 凶案 +凶残 凶殘 +凶殘 凶殘 +兇殘 凶殘 +凶杀 凶殺 +凶殺 凶殺 +兇殺 凶殺 +疑凶 疑凶 +疑兇 疑凶 +真凶 真凶 +真兇 真凶 +缉凶 緝凶 +緝凶 緝凶 +緝兇 緝凶 +行凶 行凶 +行兇 行凶 +行凶后 行凶後 +行凶後 行凶後 +行兇後 行凶後 +买凶 買凶 +買凶 買凶 +買兇 買凶 +追凶 追凶 +追兇 追凶 +逞凶斗狠 逞凶鬥狠 +逞凶鬥狠 逞凶鬥狠 +逞兇鬥狠 逞凶鬥狠 +复苏 復甦 +復蘇 復甦 +缺省 預設 +串行 串列 +串列加速器 串列加速器 +以太网 乙太網 +位图 點陣圖 +例程 常式 +光标 游標 +光盘 光碟 +光驱 光碟機 +全角 全形 +加载 載入 +半角 半形 +变量 變數 +噪声 雜訊 +脱机 離線 +声卡 音效卡 +老字号 老字號 +连字号 連字號 +字号 字型大小 +字库 字型檔 +字段 欄位 +字符 字元 +字符集 字符集 +存盘 存檔 +寻址 定址 +尾注 章節附註 +异步 非同步 +总线 匯流排 +括号 括弧 +接口 介面 +控件 控制項 +权限 許可權 +盘片 碟片 +硅片 矽片 +硅谷 矽谷 +硬盘 硬碟 +磁盘 磁碟 +磁道 磁軌 +程控 程式控制 +远程控制 遠程控制 +遠程控制 遠程控制 +行程控制 行程控制 +流程控制 流程控制 +端口 埠 +算子 運算元 +算法 演算法 +芯片 晶片 +芯片 晶元 +词组 片語 +译码 解碼 +软驱 軟碟機 +快闪存储器 快閃記憶體 +闪存 快閃記憶體 +鼠标 滑鼠 +进制 進位 +交互式 互動式 +仿真 模擬 +优先级 優先順序 +传感 感測 +便携式 攜帶型 +信息论 資訊理論 +写保护 防寫 +分辨率 解析度 +服务器 伺服器 +等于 等於 +局域网 區域網 +扫瞄仪 掃瞄器 +宽带 寬頻 +数据库 資料庫 +奶酪 乳酪 +手电 手電筒 +手电筒 手電筒 +万历 萬曆 +永历 永曆 +词汇 辭彙 +习用 慣用 +元音 母音 +新纪元 新紀元 +新紀元 新紀元 +宋元 宋元 +头球 頭槌 +入球 進球 +粒入球 顆進球 +打门 射門 +火锅盖帽 蓋火鍋 +打印机 印表機 +打印機 印表機 +字节 位元組 +字節 位元組 +打印 列印 +打印 列印 +硬件 硬體 +硬件 硬體 +二极管 二極體 +二極管 二極體 +三极管 三極體 +三極管 三極體 +软件 軟體 +軟件 軟體 +网络 網路 +網絡 網路 +人工智能 人工智慧 +航天飞机 太空梭 +航天大学 航天大學 +穿梭機 太空梭 +因特网 網際網路 +互聯網 網際網路 +机器人 機器人 +機械人 機器人 +移动电话 行動電話 +流動電話 行動電話 +调制解调器 數據機 +調制解調器 數據機 +短信 簡訊 +短訊 簡訊 +乌兹别克斯坦 烏茲別克 +乍得 查德 +乍得 查德 +也门 葉門 +也門 葉門 +伯利兹 貝里斯 +伯利茲 貝里斯 +佛得角 維德角 +克罗地亚 克羅埃西亞 +克羅地亞 克羅埃西亞 +冈比亚 甘比亞 +岡比亞 甘比亞 +几内亚比绍 幾內亞比索 +幾內亞比紹 幾內亞比索 +列支敦士登 列支敦斯登 +列支敦士登 列支敦斯登 +利比里亚 賴比瑞亞 +利比里亞 賴比瑞亞 +加纳 迦納 +加納 迦納 +加蓬 加彭 +加蓬 加彭 +博茨瓦纳 波札那 +博茨瓦納 波札那 +卡塔尔 卡達 +卡塔爾 卡達 +卢旺达 盧安達 +盧旺達 盧安達 +危地马拉 瓜地馬拉 +危地馬拉 瓜地馬拉 +厄瓜多尔 厄瓜多 +厄瓜多爾 厄瓜多 +厄立特里亚 厄利垂亞 +厄立特里亞 厄利垂亞 +吉布提 吉布地 +吉布堤 吉布地 +哈萨克斯坦 哈薩克 +哥斯达黎加 哥斯大黎加 +哥斯達黎加 哥斯大黎加 +图瓦卢 吐瓦魯 +圖瓦盧 吐瓦魯 +土库曼斯坦 土庫曼 +圣卢西亚 聖露西亞 +聖盧西亞 聖露西亞 +圣基茨和尼维斯 聖克里斯多福及尼維斯 +聖吉斯納域斯 聖克里斯多福及尼維斯 +圣文森特和格林纳丁斯 聖文森及格瑞那丁 +聖文森特和格林納丁斯 聖文森及格瑞那丁 +圣马力诺 聖馬利諾 +聖馬力諾 聖馬利諾 +圭亚那 蓋亞那 +圭亞那 蓋亞那 +坦桑尼亚 坦尚尼亞 +坦桑尼亞 坦尚尼亞 +埃塞俄比亚 衣索比亞 +埃塞俄比亞 衣索比亞 +基里巴斯 吉里巴斯 +基里巴斯 吉里巴斯 +塔吉克斯坦 塔吉克 +塞拉利昂 獅子山 +塞拉利昂 獅子山 +塞浦路斯 塞普勒斯 +塞浦路斯 塞普勒斯 +塞舌尔 塞席爾 +塞舌爾 塞席爾 +多米尼加共和国 多明尼加 +多米尼加共和國 多明尼加 +多明尼加共和國 多明尼加 +多米尼加国 多米尼克 +多明尼加國 多米尼克 +安提瓜和巴布达 安地卡及巴布達 +安提瓜和巴布達 安地卡及巴布達 +尼日利亚 奈及利亞 +尼日利亞 奈及利亞 +尼日尔 尼日 +尼日爾 尼日 +巴巴多斯 巴貝多 +巴布亚新几内亚 巴布亞紐幾內亞 +巴布亞新畿內亞 巴布亞紐幾內亞 +布基纳法索 布吉納法索 +布基納法索 布吉納法索 +布隆迪 蒲隆地 +布隆迪 蒲隆地 +帕劳 帛琉 +意大利 義大利 +所罗门群岛 索羅門群島 +所羅門群島 索羅門群島 +文莱 汶萊 +斯威士兰 史瓦濟蘭 +斯威士蘭 史瓦濟蘭 +斯洛文尼亚 斯洛維尼亞 +斯洛文尼亞 斯洛維尼亞 +新西兰 紐西蘭 +新西蘭 紐西蘭 +格林纳达 格瑞那達 +格林納達 格瑞那達 +格鲁吉亚 喬治亞 +格魯吉亞 喬治亞 +佐治亚 喬治亞 +佐治亞 喬治亞 +毛里塔尼亚 茅利塔尼亞 +毛里塔尼亞 茅利塔尼亞 +毛里求斯 模里西斯 +毛里裘斯 模里西斯 +沙特阿拉伯 沙烏地阿拉伯 +沙地阿拉伯 沙烏地阿拉伯 +波斯尼亚和黑塞哥维那 波士尼亞赫塞哥維納 +波斯尼亞黑塞哥維那 波士尼亞赫塞哥維納 +津巴布韦 辛巴威 +津巴布韋 辛巴威 +洪都拉斯 宏都拉斯 +洪都拉斯 宏都拉斯 +特立尼达和托巴哥 千里達托貝哥 +特立尼達和多巴哥 千里達托貝哥 +瑙鲁 諾魯 +瑙魯 諾魯 +瓦努阿图 萬那杜 +瓦努阿圖 萬那杜 +溫納圖萬 那杜 +科摩罗 葛摩 +科摩羅 葛摩 +科特迪瓦 象牙海岸 +突尼斯 突尼西亞 +索马里 索馬利亞 +索馬里 索馬利亞 +老挝 寮國 +老撾 寮國 +肯尼亚 肯亞 +肯雅 肯亞 +苏里南 蘇利南 +莫桑比克 莫三比克 +莱索托 賴索托 +萊索托 賴索托 +贝宁 貝南 +貝寧 貝南 +赞比亚 尚比亞 +贊比亞 尚比亞 +阿塞拜疆 亞塞拜然 +阿拉伯联合酋长国 阿拉伯聯合大公國 +阿拉伯聯合酋長國 阿拉伯聯合大公國 +马尔代夫 馬爾地夫 +馬爾代夫 馬爾地夫 +马耳他 馬爾他 +马里共和国 馬利共和國 +馬里共和國 馬利共和國 +方便面 速食麵 +快速面 速食麵 +即食麵 速食麵 +薯仔 土豆 +土豆网 土豆網 +土豆網 土豆網 +蹦极跳 笨豬跳 +绑紧跳 笨豬跳 +冷菜 冷盤 +凉菜 冷盤 +出租车 計程車 +台球 撞球 +桌球 撞球 +卫生 衛生 +衞生 衛生 +平治之亂 平治之亂 +平治之乱 平治之亂 +平治 賓士 +奔驰 賓士 +積架 捷豹 +雪铁龙 雪鐵龍 +萬事得 馬自達 +拿破仑 拿破崙 +拿破侖 拿破崙 +布什 布希 +布殊 布希 +克林顿 柯林頓 +克林頓 柯林頓 +侯赛因 海珊 +侯賽因 海珊 +凡高 梵谷 +狄安娜 黛安娜 +戴安娜 黛安娜 +颁布 頒布 +頒佈 頒布 +彩带 彩帶 +彩排 彩排 +彩楼 彩樓 +彩牌楼 彩牌樓 +彩球 綵球 +彩绸 綵綢 +彩线 綵線 +彩船 綵船 +彩衣 綵衣 +结彩 結綵 +戏彩娱亲 戲綵娛親 +剪彩 剪綵 +榴莲 榴槤 +榴蓮 榴槤 +掛鈎 掛鉤 +挂钩 掛鉤 +鈎心鬥角 鉤心鬥角 +钩心斗角 鉤心鬥角 +酰 醯 +雪裏紅 雪裡紅 +雪裏蕻 雪裡蕻 +森林裏 森林裡 +日子裏 日子裡 +故事裏 故事裡 +領域裏 領域裡 +時間裏 時間裡 +深淵裏 深淵裡 +醫院裏 醫院裡 +春假裏 春假裡 +暑假裏 暑假裡 +秋假裏 秋假裡 +寒假裏 寒假裡 +春天裏 春天裡 +夏天裏 夏天裡 +秋天裏 秋天裡 +冬天裏 冬天裡 +春日裏 春日裡 +夏日裏 夏日裡 +秋日裏 秋日裡 +冬日裏 冬日裡 +百科裏 百科裡 +歷史裏 歷史裡 +戲裏 戲裡 +作品裏 作品裡 +專輯裏 專輯裡 +年代裏 年代裡 +棺材裏 棺材裡 +嘴裏 嘴裡 +心裏 心裡 +皮裏陽秋 皮裡陽秋 +肚裏 肚裡 +苦裏 苦裡 +裏勾外連 裡勾外連 +裏面 裡面 +這裏 這裡 +點裏 點裡 +中文裏 中文裡 +山洞裏 山洞裡 +世界裏 世界裡 +眼睛裏 眼睛裡 +學裏 學裡 +獄裏 獄裡 +館裏 館裡 +系列裏 系列裡 +村子裏 村子裡 +青霉素 青黴素 +想象 想像 +锎 鉲 +信道 信道 +綫 線 diff --git a/maintenance/language/zhtable/toTrad.manual b/maintenance/language/zhtable/toTrad.manual new file mode 100644 index 00000000..b0efd28e --- /dev/null +++ b/maintenance/language/zhtable/toTrad.manual @@ -0,0 +1,186 @@ +手塚治虫 手塚治虫 +校仇 校讎 +仇校 讎校 +仇夷 讎夷 +仇問 讎問 +無言不仇 無言不讎 +視如寇仇 視如寇讎 +往日無仇 往日無讎 +近日無仇 近日無讎 +李連杰 李連杰 +周杰倫 周杰倫 +寶曆 寶曆 +涂謹申 涂謹申 +涂鴻欽 涂鴻欽 +涂壯勳 涂壯勳 +於姓 於姓 +於氏 於氏 +於夫羅 於夫羅 +於梨華 於梨華 +鄭凱云 鄭凱云 +筑陽 筑陽 +筑後 筑後 +采石磯 采石磯 +采石之戰 采石之戰 +張三丰 張三丰 +丰韻 丰韻 +丰儀 丰儀 +丰標不凡 丰標不凡 +干細胞 幹細胞 +干熱 乾熱 +二里頭 二里頭 +水里鄉 水里鄉 +蒙胧 朦朧 +酒曲 酒麴 +呆里呆气 呆裡呆氣 +拜托 拜託 +委托书 委託書 +委托 委託 +挽詞 輓詞 +挽聯 輓聯 +挽詩 輓詩 +於夫罗 於夫羅 +府干預 府干預 +府干擾 府干擾 +分布圖 分布圖 +頁面 頁面 +面條目 面條目 +黃鈺筑 黃鈺筑 +仿佛 彷彿 +凶殘 兇殘 +凶殺 兇殺 +緝凶 緝兇 +行凶後 行兇後 +買凶 買兇 +逞凶鬥狠 逞兇鬥狠 +合著者 合著者 +答复 答覆 +反复 反覆 +索馬里 索馬里 +洗练 洗鍊 +朝乾夕惕 朝乾夕惕 +乾象曆 乾象曆 +乾象历 乾象曆 +不好干預 不好干預 +不干預 不干預 +不干擾 不干擾 +不干牠 不干牠 +矽谷 矽谷 +范文瀾 范文瀾 +發表 發表 +機械系 機械系 +頂多 頂多 +馬占山 馬占山 +叱咤樂壇 叱咤樂壇 +闫怀礼 閆懷禮 +变髒 變髒 +薴烯 薴烯 +后豐 后豐 +于謙 于謙 +詩云 詩云 +鄭凱云 鄭凱云 +云為 云為 +古書云 古書云 +古語云 古語云 +經有云 經有云 +語有云 語有云 +显著标志 顯著標志 +占領 佔領 +采納 採納 +風采 風采 +于樂 于樂 +于軍 于軍 +于堅 于堅 +于帥 于帥 +于濤 于濤 +于贈 于贈 +于會泳 于會泳 +于偉國 于偉國 +于光遠 于光遠 +于鳳至 于鳳至 +于台煙 于台煙 +于國楨 于國楨 +于大寶 于大寶 +于學忠 于學忠 +于小偉 于小偉 +于山國 于山國 +于幼軍 于幼軍 +于廣洲 于廣洲 +于從濂 于從濂 +于志寧 于志寧 +于成龍 于成龍 +于明濤 于明濤 +于根偉 于根偉 +于樹潔 于樹潔 +于正昇 于正昇 +于漢超 于漢超 +于洪區 于洪區 +于湘蘭 于湘蘭 +于蔭霖 于蔭霖 +于遠偉 于遠偉 +于都縣 于都縣 +于震寰 于震寰 +于震環 于震環 +于非闇 于非闇 +于風政 于風政 +于鳳桐 于鳳桐 +于默奧 于默奧 +于爾岑 于爾岑 +于默奧 于默奧 +于貝爾 于貝爾 +于爾根 于爾根 +于雙戈 于雙戈 +于澤爾 于澤爾 +于斯達爾 于斯達爾 +于爾里克 于爾里克 +于奇庫杜克 于奇庫杜克 +于韋斯屈萊 于韋斯屈萊 +于克-蘭多縣 于克-蘭多縣 +于斯納爾斯貝里 于斯納爾斯貝里 +夏于喬 夏于喬 +涂澤民 涂澤民 +涂長望 涂長望 +涂敏恆 涂敏恆 +台历 枱曆 +艷后 艷后 +廢后 廢后 +后髮座 后髮座 +后髮星系團 后髮星系團 +后髮FK型星 后髮FK型星 +后海灣 后海灣 +賈后 賈后 +賢后 賢后 +呂后 呂后 +蟻后 蟻后 +馬格里布 馬格里布 +佳里鎮 佳里鎮 +埔裡社撫墾局 埔裏社撫墾局 +埔裏社撫墾局 埔裏社撫墾局 +有只採 有只採 +任何表達 任何表達 +會干擾 會干擾 +党項 党項 +余三勝 余三勝 +簡筑翎 簡筑翎 +楊雅筑 楊雅筑 +杰威爾音樂 杰威爾音樂 +尸羅精舍 尸羅精舍 +索馬里 索馬里 +騰格里 騰格里 +村里長 村里長 +進制 進制 +模范三軍 模范三軍 +黃詩杰 黃詩杰 +陳冲 陳冲 +劉佳怜 劉佳怜 +范賢惠 范賢惠 +于國治 于國治 +于楓 于楓 +黎吉雲 黎吉雲 +于飛島 于飛島 +鄉愿 鄉愿 +奇迹 奇蹟 +候复 候覆 +待复 待覆 +批复 批覆 +划槳 划槳 diff --git a/maintenance/language/zhtable/trad2simp.manual b/maintenance/language/zhtable/trad2simp.manual new file mode 100644 index 00000000..747a240a --- /dev/null +++ b/maintenance/language/zhtable/trad2simp.manual @@ -0,0 +1,153 @@ +U+04E99亙|U+04E98亘| +U+04F48佈|U+05E03布| +U+04F48佈|U+05E03布| +U+04F54佔|U+05360占| +U+05016倖|U+05E78幸| +U+050A2傢|U+05BB6家| +U+050F1僱|U+096C7雇| +U+05138儸|U+03469㑩|U+07F57罗| +U+05147兇|U+051F6凶| +U+05277剷|U+094F2铲| +U+052F3勳|U+052CB勋| +U+0537D卽|U+05373即| +U+053A4厤|U+05386历| +U+055AB喫|U+05403吃| +U+05641噁|U+06076恶| +U+05690嚐|U+05C1D尝| +U+056A5嚥|U+054BD咽| +U+056AE嚮|U+05411向| +U+056CC囌|U+082CF苏| +U+0585A塚|U+051A2冢| +U+058B0墰|U+0575B坛| +U+058DC壜|U+0575B坛| +U+05925夥|U+04F19伙| +U+05BC0寀|U+091C7采| +U+05D11崑|U+06606昆| +U+05D19崙|U+04ED1仑| +U+05D57嵗|U+05C81岁| +U+05DBD嶽|U+05CB3岳| +U+05DD6巖|U+05CA9岩| +U+05DF9巹|U+0537A卺| +U+05F14弔|U+0540A吊| +U+05F46彆|U+0522B别| +U+0617C慼|U+0621A戚| +U+0617E慾|U+06B32欲| +U+061DE懞|U+08499蒙| +U+062DA拚|U+062FC拼| +U+06331挱|U+06332挲| +U+06371捱|U+06328挨| +U+06372捲|U+05377卷| +U+0647A摺|U+06298折| +U+065C2旂|U+065D7旗| +U+065E3旣|U+065E2既| +U+06607昇|U+05347升| +U+0672E朮|U+0672F术| +U+068CA棊|U+068CB棋| +U+069A6榦|U+05E72干| +U+069D3槓|U+06760杠| +U+06A11樑|U+06881梁| +U+06B05欅|U+06989榉| +U+06B4E歎|U+053F9叹| +U+06BAD殭|U+050F5僵| +U+06C59汙|U+06C61污| +U+06CDD泝|U+06EAF溯| +U+06D29洩|U+06CC4泄| +U+06DD2淒|U+051C4凄| +U+06DE8淨|U+051C0净| +U+06DE9淩|U+051CC凌| +U+06E67湧|U+06D8C涌| +U+06ED9滙|U+06C47汇| +U+06F90澐|U+06C84沄| +U+06FBE澾|U+03CE0㳠| +U+06FDB濛|U+06FDB濛|U+08499蒙| +U+07030瀰|U+05F25弥| +U+071EC燬|U+06BC1毁| +U+07232爲|U+04E3A为| +U+07343獃|U+05446呆| +U+07515甕|U+074EE瓮| +U+07526甦|U+082CF苏| +U+0752F甯|U+05B81宁| +U+0756B畫|U+0753B画|U+05212划| +U+07575畵|U+0753B画|U+05212划| +U+075E0痠|U+09178酸| +U+07652癒|U+06108愈| +U+07661癡|U+075F4痴| +U+076C3盃|U+0676F杯| +U+0771E眞|U+0771F真| +U+077AD瞭|U+04E86了| +U+077C7矇|U+08499蒙| +U+07843硃|U+06731朱| +U+07895碕|U+057FC埼| +U+07958祘|U+07B97算| +U+07A1C稜|U+068F1棱| +U+07B87箇|U+04E2A个| +U+07C11簑|U+084D1蓑| +U+07C64籤|U+07B7E签| +U+07C72籲|U+05401吁| +U+07CF0糰|U+056E2团| +U+07D2E紮|U+0624E扎| +U+07DAB綫|U+07EBF线| +U+07DB5綵|U+05F69彩|U+0433D䌽| +U+07E34縴|U+07EA4纤| +U+07E50繐|U+07A57穗| +U+07E94纔|U+0624D才| +U+07F4E罎|U+0575B坛| +U+07FA8羨|U+07FA1羡| +U+08123脣|U+05507唇| +U+081E5臥|U+05367卧| +U+08218舘|U+09986馆| +U+083F4菴|U+05EB5庵| +U+08457著|U+08457著|U+07740着| +U+08518蔘|U+053C2参| +U+08591薑|U+059DC姜| +U+085C9藉|U+085C9藉|U+0501F借| +U+0880D蠍|U+0874E蝎| +U+0884A衊|U+08511蔑| +U+088CF裏|U+091CC里| +U+08946襆|U+05E5E幞| +U+08986覆|U+08986覆|U+0590D复| +U+08A17託|U+06258托|U+08BAC讬| +U+08AEE諮|U+054A8咨|U+08C18谘| +U+08B6D譭|U+06BC1毁| +U+08B8E讎|U+04EC7仇| +U+08B9A讚|U+08D5E赞| +U+08C54豔|U+08273艳| +U+08FF4迴|U+056DE回| +U+09031週|U+05468周| +U+0904A遊|U+06E38游| +U+09061遡|U+06EAF溯| +U+091A3醣|U+07CD6糖| +U+091AF醯|U+09170酰| +U+0934A鍊|U+070BC炼|U+094FE链| +U+0938C鎌|U+09570镰| +U+093AD鎭|U+093AE镇| +U+093DA鏚|U+0621A戚| +U+09451鑑|U+09274鉴| +U+0955F镟|U+065CB旋| +U+09592閒|U+095F2闲| +U+095A4閤|U+05408合| +U+095E2闢|U+08F9F辟| +U+0962A阪|U+0962A阪|U+05742坂| +U+0965E陞|U+05347升| +U+097A6鞦|U+079CB秋|U+097A7鞧| +U+097C6韆|U+05343千| +U+097DD韝|U+097B2鞲| +U+09858願|U+0613F愿| +U+098F1飱|U+098E7飧| +U+09918餘|U+04F59余|U+09980馀| +U+09931餱|U+07CC7糇| +U+09935餵|U+05582喂| +U+09B28鬨|U+054C4哄| +U+09D70鵰|U+096D5雕|U+05F6B彫| +U+09E7C鹼|U+078B1碱|U+07877硷| +U+09EAA麪|U+09762面| +U+09EAB麫|U+09762面| +U+09EAF麯|U+066F2曲| +U+09EB4麴|U+066F2曲|U+09EB4麴| +U+09EF4黴|U+09709霉| +U+09F15鼕|U+051AC冬| +U+09F47齇|U+09F44齄| +U+09F63齣|U+051FA出| +U+09F91龑|U+04DAE䶮| +U+21ED5𡻕|U+05C81岁| +U+298F5𩣵|U+299FB𩧻| diff --git a/maintenance/language/zhtable/trad2simp_noconvert.manual b/maintenance/language/zhtable/trad2simp_noconvert.manual new file mode 100644 index 00000000..052bab69 --- /dev/null +++ b/maintenance/language/zhtable/trad2simp_noconvert.manual @@ -0,0 +1,5 @@ +"余"=> +碁 +藉 +=>"獃" +𫚭 diff --git a/maintenance/language/zhtable/trad2simp_supp_set.manual b/maintenance/language/zhtable/trad2simp_supp_set.manual new file mode 100644 index 00000000..d1728f0a --- /dev/null +++ b/maintenance/language/zhtable/trad2simp_supp_set.manual @@ -0,0 +1,3 @@ +著 着 +藉 借 +濛 蒙
\ No newline at end of file diff --git a/maintenance/postgres/archives/patch-ipb_address_unique.sql b/maintenance/language/zhtable/trad2simp_supp_unset.manual index e69de29b..e69de29b 100644 --- a/maintenance/postgres/archives/patch-ipb_address_unique.sql +++ b/maintenance/language/zhtable/trad2simp_supp_unset.manual diff --git a/maintenance/language/zhtable/tradphrases.manual b/maintenance/language/zhtable/tradphrases.manual new file mode 100644 index 00000000..e20ca05b --- /dev/null +++ b/maintenance/language/zhtable/tradphrases.manual @@ -0,0 +1,4311 @@ +零隻 +〇隻 +一隻 +二隻 +兩隻 +三隻 +四隻 +五隻 +六隻 +七隻 +八隻 +九隻 +0隻 +1隻 +2隻 +3隻 +4隻 +5隻 +6隻 +7隻 +8隻 +9隻 +0隻 +1隻 +2隻 +3隻 +4隻 +5隻 +6隻 +7隻 +8隻 +9隻 +0只支援 +1只支援 +2只支援 +3只支援 +4只支援 +5只支援 +6只支援 +7只支援 +8只支援 +9只支援 +0只支持 +1只支持 +2只支持 +3只支持 +4只支持 +5只支持 +6只支持 +7只支持 +8只支持 +9只支持 +百隻 +千隻 +萬隻 +億隻 +最多 +至多 +頂多 +多隻 +0多隻 +0多隻 +零多隻 +十多隻 +百多隻 +千多隻 +萬多隻 +億多隻 +這只能 +這只可 +這只在 +這只是 +這只需 +這只會 +這只用 +那只能 +那只可 +那只在 +那只是 +那只需 +那只會 +那只用 +多只能 +多只可 +多只在 +多只有 +多只是 +多只需 +多只會 +多只用 +大只能 +大只可 +大只在 +大只有 +大只是 +大只需 +大只會 +小只能 +小只可 +小只在 +小只有 +小只是 +小只需 +小只會 +隻身 +形單影隻 +首隻 +數天後 +幾天後 +多天後 +零天後 +一天後 +二天後 +兩天後 +三天後 +四天後 +五天後 +六天後 +七天後 +八天後 +九天後 +十天後 +百天後 +千天後 +萬天後 +億天後 +0天後 +1天後 +2天後 +3天後 +4天後 +5天後 +6天後 +7天後 +8天後 +9天後 +0天後 +1天後 +2天後 +3天後 +4天後 +5天後 +6天後 +7天後 +8天後 +9天後 +天後來 +天後天 +天後半 +後印 +萬象 +並存著 +乾絲 +乾著急 +乾魚 +魚乾 +乾梅 +糕乾 +黃乾黑瘦 +馬乾 +香乾 +趲幹 +謀幹 +詞幹 +蟶乾 +薄幹 +腦幹 +營幹 +老乾 +老幹部 +管幹 +盲幹 +煨乾 +海乾 +乾漆 +淚乾 +沒幹 +沒乾沒淨 +枝不得大於榦 +杯乾 +打幹 +打乾噦 +徐幹 +府幹 +乾館 +乾顙 +幹革命 +乾霍亂 +乾雷 +乾阿奶 +乾量 +乾醋 +乾逼 +乾貨 +乾衣 +幹蠱 +乾虔 +乾落 +幹營生 +乾茶錢 +乾茨臘 +乾苔 +乾花 +乾肥 +乾耗 +幹缺 +乾繃 +乾結 +乾餱 +乾篾片 +乾稿 +乾禮 +乾瞪眼 +乾白兒 +乾疥 +乾生子 +乾生受 +幹父之蠱 +乾熬 +乾燈盞 +乾濕 +乾澀 +幹濟 +乾沒 +乾死 +乾村沙 +乾暖 +乾料 +乾敲梆子不賣油 +乾支支 +乾支剌 +乾擦 +乾撇下 +乾撂台 +乾折 +乾急 +幹當 +乾式 +乾屎橛 +幹家 +乾奴才 +幹頭 +乾塢 +乾圓潔淨 +乾回付 +乾啼 +乾哭 +乾噦 +乾咽 +乾和 +幹吏 +乾吊著下巴 +乾號 +乾颱 +乾卦 +乾剝剝 +乾刻版 +乾芻 +幹人 +乾產 +乾喬 +夯幹 +大目乾連 +國之楨榦 +唇乾 +單幹 +勾幹 +豆乾 +果乾 +如果幹 +乾麵 +乾柴 +枯乾 +晒乾 +顛乾倒坤 +強幹 +乾著 +乾眼 +幹的停當 +乾巴 +偎乾 +眼乾 +偷雞不著 +几絲 +划著 +划著走 +別著 +刮著 +千絲萬縷 +參合 +參考價值 +參與 +參與人員 +參與制 +參與感 +參與者 +參觀團 +參觀團體 +參閱 +吃著不盡 +合著 +吊帶褲 +吊掛著 +吊著 +吊褲 +吊褲帶 +向著 +嚴絲合縫 +回絲 +回著 +塗著 +壟斷價格 +壟斷資產 +壟斷集團 +姜絲 +帶團參加 +干著急 +幾絲 +彆著 +怎麼著 +憑藉著 +憑藉 +接著說 +擔著 +擔負著 +敘說著 +斗轉參橫 +旋繞著 +板著臉 +正當著 +沈著 +沖著 +派團參加 +涂著 +湊合著 +瀰漫著 +為著 +煙斗絲 +率團參加 +畫著 +當著 +發著 +直接參与 +睡著了 +秋褲 +積极參与 +積极參加 +簽著 +系著 +絕對參照 +絲來線去 +絲布 +絲板 +絲瓜布 +絲絨布 +絲線 +絲織廠 +絲蟲 +緊繃著 +繃著 +繃著臉 +繃著臉兒 +繫著 +罵著 +肉絲麵 +背向著 +菌絲體 +著兒 +著書立說 +著色軟體 +著重指出 +著錄 +著錄規則 +薑絲 +藉著 +蘊含著 +蘊涵著 +衝著 +被覆著 +覆著 +覆蓋著 +反覆 +訴說著 +說著 +請參閱 +謝絕參觀 +豎著 +豐濱 +豐濱鄉 +豐度 +象徵著 +這麼著 +那麼著 +配合著 +醞釀著 +錄著 +鍛鍊出 +關係著 +雞絲 +雞絲麵 +面朝著 +面臨著 +颳著 +髮絲 +斷髮 +不斷發 +判斷發 +評斷發 +買斷發 +賣斷發 +打斷發 +披頭散髮 +髮禁 +鬥著 +鬧著玩兒 +鯰魚 +世界盃 +其次辟地 +開闢 +闢地 +精闢 +別闢 +另闢 +闢佛 +闢田 +闢築 +闢謠 +闢辟 +透闢 +墾闢 +翕闢 +軒闢 +闢建 +闢室 +各闢 +增闢 +闢邪以律 +錶盤 +錶板 +錶帶 +錶針 +錶蒙子 +袋錶 +腕錶 +碼錶 +錶冠 +魔錶 +彆口氣 +彆強 +皺彆 +一彆頭 +并州 +併兼 +併產 +併骨 +併網 +併線 +併流 +逼併 +併名 +併當 +併火 +併肩子 +併除 +併疊 +忙併 +打併 +簡併 +並發表 +並發現 +並發展 +並發動 +並發布 +火並非 +舉手表 +揮手表 +併一不二 +連三併四 +相併 +撤併 +數罪併罰 +催併 +狂併潮 +薝蔔 +提摩太後書 +當家纔知柴米價 +剛纔一載 +裏海 +骨頭裡掙出來的錢纔做得肉 +恰纔 +遠縣纔至 +別日南鴻纔北去 +然身死纔數月耳 +纔得兩年 +纔則 +纔此 +你纔子發昏 +纔可容顏十五餘 +不採 +披榛採蘭 +謬採虛聲 +採樵人 +回採 +觀採 +開採 +揪採 +樵採 +採訪 +採辦 +採補 +採買 +採風問俗 +採納 +採獵 +採蓮 +採錄 +採購 +採光 +採礦 +採花 +採集 +採擷 +採掘 +採芹人 +採取 +採選 +採摭 +採摘 +採珠 +採種 +採茶 +採石 +採拾 +採收 +採生折割 +採樹種 +採擇 +採藥 +採薇 +採用 +盜採 +採信 +採行 +採證 +採菊 +博採 +採空採穗 +採挖 +採鐵 +採金 +採氣 +採油 +採煤 +採鹽 +採區 +採運 +採風 +官地為寀 +寮寀 +蔘綏 +個人# “個人參數”不是“個人蔘數” +人蔘 +蕭蔘 +人參與 +人參選 +人參觀 +人參考 +人參展 +人參加 +人參議 +人參謀 +人參酌 +人參照 +人參政 +人參戰 +人參拜 +人參閱 +人參禪 +人參贊 +人參見 +人參透 +人參看 +東衝西突 +天克地衝 +六衝 +撞陣衝軍 +衝波 +衝風 +衝頭陣 +衝堅陷陣 +衝陷 +衝心 +衝州撞府 +衝殺 +衝然 +衝盹 +左衝右突 +虫部 +手塚治虫 +群醜 +百拙千醜 +大醜 +地醜德齊 +丟醜 +亮醜 +揭醜 +倛醜 +嫌好道醜 +醜巴怪 +醜末 +醜婦 +醜地 +醜頭怪臉 +醜女效顰 +醜剌剌 +醜話 +醜媳 +醜吒 +醜聲遠播 +醜夷 +弄醜 +露醜 +摧堅獲醜 +謷醜 +不嫌母醜 +一爭兩醜 +惡直醜正 +很醜 +醜男 +醜斃了 +醜奴兒 +醜言 +醜徒 +醜雜 +醜儕 +醜沮 +醜辭 +醜比 +醜辱 +醜逆 +醜史 +醜賊生 +醜婆子 +出乖弄醜 +出乖露醜 +獲匪其醜 +乙丑 +丁丑 +己丑 +辛丑 +癸丑 +丑時 +丑日 +丑月 +丑年 +文丑 +武丑 +女丑 +小丑 +大丑 +丑婆子 +丑旦 +丑角 +丑三 +丑表功 +公孫丑 +么麼小丑 +齣電影 +齣電視 +齣動畫 +齣節目 +齣卡通 +齣戲 +齣劇 +平平當當 +滿滿當當 +當當丁丁 +丁丁當當 +停停當當 +快快當當 +咯噹 +啷噹 +党參 +党進 +党太尉 +党項 +撲鼕 +洗髮 +牽一髮 +白發其事 +后髮座 +后髮星系團 +后髮FK型星 +波髮藻 +辮髮 +逋髮 +抿髮 +髮漂 +髮匪 +髮腳 +髮癬 +髮釵 +髮飾 +髮紗 +髮上指冠 +髮上沖冠 +髮乳 +髮引千鈞 +髮踴沖冠 +董氏封髮 +胎髮 +禿妃之髮 +捉髮 +綠髮 +括髮 +髡髮 +鵠髮 +截髮 +解髮佯狂 +淨髮 +秋髮 +噙齒戴髮 +青山一髮 +晞髮 +細不容髮 +心細如髮 +祝髮 +擢髮 +齒髮 +齒危髮秀 +沖冠髮怒 +甩髮 +絲髮 +絲恩髮怨 +蒜髮 +算髮 +有髮頭陀寺 +髮箋 +髮屋 +櫛髮工 +鬒髮 +模范棒棒堂 +模范三軍 +模范七棒 +模范14棒 +模范21棒 +顏範 +儀範 +典範 +坤範 +壼範 +容範 +懿範 +明範 +格範 +模範 +樣範 +母範 +洪範 +淑範 +遺範 +科範 +立範 +貽範 +道範 +閨範 +閫範 +雅範 +霽範 +鴻範 +沒樣範 +錢範 +銅範 +金範 +範金 +垂範 +範性形變 +範字 +有事之無範 +置言成範 +吾爲之範我馳驅 +天地為範 +範數 +丰采 +丰標不凡 +丰神 +丰茸 +丰儀 +丰度 +丰情 +丰韵 +子之丰兮 +艸木丰丰 +張三丰 +復始 +複分析 +複輔音 +複元音 +複平面 +複函數 +複流 +反複製 +複對數 +顛覆 +答覆 +覆沒 +覆亡 +覆水難收 +翻雲覆雨 +覆雨翻雲 +覆轍 +覆巢之下無完卵 +覆蓋 +覆命 +天翻地覆 +天覆地載 +撥穀 +扁擬穀盜蟲 +不穀 +辟穀 +米穀 +田穀 +脫穀機 +年穀 +礱穀機 +孤寡不穀 +穀米 +穀旦 +穀圭 +穀貴餓農 +穀食 +穀日 +館穀 +禾穀 +積穀 +嘉穀 +嚼穀 +九穀 +戩穀 +錢穀 +息穀 +殖穀 +川穀 +曬穀 +臧穀亡羊 +種穀 +颳雪 +刮風下雪倒便宜 +广部 +亂鬨不過來 +斗鬨 +亂鬨 +開鬨 +花鬨 +鬨動 +交鬨 +喧鬨 +起鬨 +內鬨 +於後 +猜三划五 +划龍舟 +南迴線 +南迴鐵路 +北迴線 +北迴鐵路 +文匯報 +河流匯集 +品彙 +博彙 +滙豐 +伙頭 +方几 +伏几 +高几 +雪窗螢几 +燕几 +隱几 +饑饉 +乾薑 +毛薑 +薑母 +薑湯 +薑桂 +薑是老的辣 +吃薑 +薑老辣 +野薑 +咬薑呷醋 +薑蓉 +薑黃 +狐藉虎威 +滑藉 +藉寇兵 +藉箸代籌 +藉手 +藉此 +龍捲 +捲舌 +夸父 +夸克 +夸特 +夸毗 +夸麗 +夸姣 +夸人 +夸容 +大言非夸 +言大而夸 +睏覺 +愛睏 +纍堆 +纍紲 +纍臣 +纍瓦結繩 +湘纍 +印纍綬若 +灕湘 +灕然 +澤滲灕而下降 +裏勾外連 +裏手 +水里鄉 +水里溪 +水里濁水溪 +二里頭 +年歷史 +西歷史 +國歷史 +國歷代 +國歷任 +國歷屆 +國歷經 +國歷來 +新歷史 +夏歷史 +百花曆 +寶曆 +穆罕默德曆 +大明曆 +大曆 +台曆 +太初曆 +通曆 +曆本 +曆命 +曆紀 +曆始 +曆室 +曆日 +曆尾 +曆元 +律曆志 +官曆 +回曆 +巧曆 +慶曆 +朱理安曆 +長曆 +藏曆 +四分曆 +三統曆 +額我略曆 +埃及曆 +伊斯蘭教曆 +合曆 +玉曆 +農民曆 +桌曆 +商曆 +周曆 +大衍曆 +皇極曆 +儒略改革曆 +希伯來曆 +格里曆 +格里高利曆 +共和曆 +掛曆 +曆獄 +天文曆表 +日心曆表 +地心曆表 +復活節曆表 +月球曆表 +伊爾汗曆表 +延曆 +共和歷史 +厤物之意 +爰定祥厤 +白黴 +黴黧 +黴黑 +麴黴 +蒙霧露 +懞懞懂懂 +懞直 +老懞 +放懞掙 +矇著 +矇聵 +矇瞍 +矇事 +矇頭轉 +矇松雨 +藏矇歌兒 +矇著鍋兒 +朦朧 +濛濛細雨 +濛汜 +冥濛 +溟濛 +淡濛濛 +凌濛初 +涳濛 +灰濛濛 +澒濛 +瀰山遍野 +瀰瀰 +冷麵 +撈麵 +煮麵 +炆麵 +煎麵 +泡麵 +食麵 +公仔麵 +方便麵 +白粉麵 +棒子麵 +麵缸 +麵坯兒 +麵碼兒 +麵坊 +麵湯 +麵疙瘩 +麵館 +麵漿 +甜水麵 +麵人兒 +麵塑 +捏麵人 +趕麵棍 +擀麵 +過水麵 +蕎麥麵 +巧婦做不得無麵餺飥 +削麵 +小米麵 +壯麵 +吃板刀麵 +吃辣麵 +扯麵 +搋麵 +重羅麵 +雜麵 +雜合麵兒 +溲麵 +索麵 +一鍋麵 +伊府麵 +藥麵兒 +意大利麵 +湯下麵 +茶麵 +麵糰 +冷面相 +糞穢衊面 +湟潦生苹 +食野之苹 +苹縈 +青苹 +青蘋果 +僕僕 +有僕 +冉有僕 +屢顧爾僕 +僕少 +僕雖罷駑 +僕夫 +僕僮 +僕吏 +僕姑 +僕固懷恩 +僕程 +僕使 +僕憎 +僕歐 +僕射 +太僕 +僮僕 +金僕姑 +僕婢 +樸實 +樸訥 +樸念仁 +白樸 +抱素懷樸 +抱朴而長吟兮 +樸鄙 +樸馬 +樸父 +樸陋 +樸魯 +樸厚 +樸學 +樸質 +樸拙 +樸重 +樸素 +樸樕 +樸野 +反樸 +古樸 +胡樸安 +返樸 +渾樸 +儉樸 +簡樸 +拙樸 +斫雕為樸 +斲雕為樸 +質樸 +誠樸 +純樸 +曾樸 +郁樸 +棫樸 +敦樸 +樸鈍 +樸直 +見素抱樸 +掣籤 +標籤 +書籤 +發籤 +粉籤子 +路籤 +更籤 +好籤 +火籤 +籤幐 +籤押 +照入籤 +制籤 +抽公籤 +瑤籤 +藥籤 +萬籤插架 +雲笈七籤 +上簽名 +上簽字 +上簽收 +上簽寫 +下簽名 +下簽字 +下簽收 +下簽寫 +犖确 +磽确 +确瘠 +言辯而确 +數與虜确 +關弓與我确 +拚捨 +廣捨 +齊王捨牛 +捨墮 +捨實 +棄捨 +捨安就危 +施舍之道 +瀋河 +瀋水 +瀋州 +瀋山線 +瀋吉線 +墨沈 +瀋海鐵路 +遼瀋 +胜肽 +胜鍵 +雙胜類 +兀朮 +白朮 +蒼朮 +赤朮 +朮赤 +髼鬆 +皮鬆 +濛鬆雨 +發鬆 +翻鬆 +浮鬆 +弄鬆 +精鬆 +懈鬆 +鬆蛋 +鬆寬 +鬆氣 +鬆一口氣 +鬆元音 +鬆喉 +囉囉囌囌 +囉囌 +骨罈 +罈騞 +餵驢 +剪牡丹喂牛 +鹹粥 +鹹食 +鹹潟 +鹹嘴淡舌 +鹽打怎麼鹹 +鹹派 +鹹批 +錦綉花園 +籲天 +勃鬱 +怫鬱 +氣鬱 +沉鬱 +神荼鬱壘 +躁鬱 +蒼鬱 +漚鬱 +伊鬱 +壹鬱 +悒鬱 +氤鬱 +湮鬱 +陰鬱 +泱鬱 +坱鬱 +滃鬱 +蓊鬱 +紆鬱 +鬱勃 +鬱陶 +鬱律 +鬱壘 +鬱火 +鬱積 +鬱金 +鬱江 +鬱血 +鬱蒸 +鬱症 +鬱沉沉 +鬱熱 +鬱塞 +鬱伊 +鬱邑 +鬱挹 +鬱堙不偶 +鬱泱 +鬱蓊 +鬱紆 +鬱燠 +肝鬱 +鬱卒 +鬱鬱不平 +鬱鬱不樂 +鬱鬱寡歡 +鬱鬱蔥蔥 +鬱鬱而終 +愿樸 +愿而恭 +許愿起經 +北嶽 +嶽麓 +但云 +胡云 +詩云 +注云 +鄭凱云 +云乎 +云然 +云為 +對摺 +網誌 +標標致致 +澄澹精致 +呆緻緻 +光緻緻 +工緻 +功緻 +縝緻 +堅緻 +种放 +种師道 +种師中 +後庄 +舊庄 +正官庄 +龜山庄 +寶山庄 +冬山庄 +員山庄 +松山庄 +厂部 +閤府 +佈道 +剪綵 +衝量 +衝車 +書獃子 +相干 +府干預 +府干涉 +府干政 +府干擾 +府干犯 +府干卿 +一干人 +未乾 +未干涉 +抹乾 +餅乾 +拭乾 +擦乾 +晾乾 +烘乾 +肉乾 +菜乾 +腐乾 +乾脆 +乾淨 +乾燥 +乾旱 +乾涸 +乾洗 +乾女 +乾等 +乾糧 +乾枯 +乾薪 +乾爹 +乾粉 +乾爽 +乾兒 +乾子 +乾渴 +乾股 +乾果 +乾草 +乾菜 +乾笑 +乾餾 +乾電 +乾飯 +乾冰 +乾嘔 +乾材 +乾媽 +乾季 +葡萄乾 +提子乾 +蘿蔔乾 +蘋果乾 +芒果乾 +菠蘿乾 +鳳梨乾 +豆腐乾 +果子乾 +龍眼乾 +乾乾淨淨 +乾柴烈火 +乾乾兒的 +桑乾 +撈乾 +搭乾鋪 +揩乾 +敢幹 +幹探 +幹事 +幹什麼 +幹細胞 +悶著頭兒幹 +配水幹管 +繐幃飄井幹 +站乾岸兒 +秋陰入井幹 +沒梢幹 +楨幹 +據榦而窺井底 +井榦摧敗 +杰特 +李連杰 +周杰倫 +杰倫 +姜文杰 +稜鏡 +稜角 +稜台 +稜錐 +觚稜 +稜子 +稜層 +稜柱 +盧稜伽 +波稜菜 +菠稜菜 +稜縫 +稜等登 +稜稜 +嶒稜 +蹭稜子 +稜體 +二不稜登 +有稜有角 +威稜 +負債纍纍 +傷痕纍纍 +儒略曆 +伊斯蘭曆 +酒麴 +昇平 +爾冬陞 +澹臺 +拜託 +委託 +輓曲 +敬輓 +万俟 +万旗 +鬚鯨 +鬚鯊 +兇手 +兇徒 +兇案 +兇器 +兇殺 +兇殘 +行兇 +緝兇 +追兇 +真兇 +疑兇 +買兇 +元兇 +叶韻 +叶音 +叶恭弘 +叶 恭弘 +叶 恭弘 +於1 +於2 +於3 +於4 +於5 +於6 +於7 +於8 +於9 +於0 +於1 +於2 +於3 +於4 +於5 +於6 +於7 +於8 +於9 +於0 +於一 +於二 +於三 +於四 +於五 +於六 +於七 +於八 +於九 +於十 +於半 +於夫羅 +於梨華 +置於 +佈於 +散於 +播於 +國於 +敗於 +於一役 +畢於 +畢業於 +寒於 +任於 +拘於 +插於 +中於 +於市 +於野 +敏於 +聽於 +短於 +成於 +樊於期 +淡於 +於陸 +於密 +於盡 +禍於 +格於 +猛於 +施於 +於牆 +於物 +於己 +於你 +於我 +於他 +於她 +於它 +於祂 +拒人於 +拒於 +潰於 +窮於 +相於 +形於 +半於 +於始 +於終 +詢於 +美於 +醜於 +好於 +坏於 +強於 +弱於 +差於 +劣於 +於美 +於醜 +於好 +於坏 +於強 +於弱 +於差 +於劣 +於垂 +染指於 +於火 +存十一於千百 +存於 +於勤 +隱於 +藏於 +嚴於 +寬於 +於幕 +給於 +於穆 +於呼哀哉 +於時 +於該 +危於 +於伏 +於何 +於家 +於國 +於潛縣 +於焉 +於徵 +離於 +於畢 +麗於 +下於 +亞於 +同於 +屑於 +絕於 +致於 +於行 +遜於 +任教於 +教於 +自於 +來於 +附於 +於人 +於世 +阻於 +於民 +於盲 +於色 +囿於 +直於 +建於 +都於 +於農 +於樂 +於前 +役於 +於心 +於法 +於事 +助於 +害於 +損於 +益於 +從於 +隨於 +順於 +汲於 +溺於 +迷於 +醉於 +行於 +泥於 +身於 +足於 +溢於 +於衷 +畏於 +視於 +衷於 +狃於 +疲於 +通於 +於途 +老於 +耿於 +於懷 +服於 +臻於 +匿於 +因於 +似於 +遷於 +怒於 +心於 +集於 +容於 +髒詞 +髒心 +新紮 +紙紮 +紮鐵 +紮寨 +一紮 +兩紮 +三紮 +四紮 +五紮 +六紮 +七紮 +八紮 +九紮 +十紮 +百紮 +千紮 +萬紮 +佔1 +佔2 +佔3 +佔4 +佔5 +佔6 +佔7 +佔8 +佔9 +佔0 +佔1 +佔2 +佔3 +佔4 +佔5 +佔6 +佔7 +佔8 +佔9 +佔0 +佔零 +佔〇 +佔一 +佔二 +佔兩 +佔三 +佔四 +佔五 +佔六 +佔七 +佔八 +佔九 +佔十 +佔百 +佔千 +佔万 +佔億 +佔超過 +佔不足 +佔至少 +佔少 +佔至多 +佔半 +佔多 +佔大 +佔小 +佔中 +佔東 +佔西 +佔南 +佔北 +佔平均 +佔總 +獨佔鰲頭 +所佔 +市佔 +佔率 +市佔率 +佔市場 +佔世界 +佔全 +佔國內 +佔美 +佔台 +佔香 +佔澳 +佔加 +佔新 +佔馬 +佔印 +佔英 +佔法 +佔德 +佔葡 +佔俄 +佔蘇 +佔缺 +佔A +佔B +佔C +佔D +佔E +佔F +佔G +佔H +佔I +佔J +佔K +佔L +佔M +佔N +佔O +佔P +佔Q +佔R +佔S +佔T +佔U +佔V +佔W +佔X +佔Y +佔Z +佔a +佔b +佔c +佔d +佔e +佔f +佔g +佔h +佔i +佔j +佔k +佔l +佔m +佔n +佔o +佔p +佔q +佔r +佔s +佔t +佔u +佔v +佔w +佔x +佔y +佔z +佔A +佔B +佔C +佔D +佔E +佔F +佔G +佔H +佔I +佔J +佔K +佔L +佔M +佔N +佔O +佔P +佔Q +佔R +佔S +佔T +佔U +佔V +佔W +佔X +佔Y +佔Z +佔a +佔b +佔c +佔d +佔e +佔f +佔g +佔h +佔i +佔j +佔k +佔l +佔m +佔n +佔o +佔p +佔q +佔r +佔s +佔t +佔u +佔v +佔w +佔x +佔y +佔z +佔不佔 +不佔 +佔了 +佔穩 +佔資源 +佔人便宜 +佔頭 +佔道 +佔屋 +佔網 +佔床 +佔座 +佔分 +佔飯 +佔個位 +佔後 +佔著 +佔山 +馬占山 +佔比 +佔停車 +佔哺乳 +佔下風 +少佔 +多佔 +費佔 +佔查 +佔壓 +佔優 +佔劣 +穩佔 +佔整體 +佔局部 +日佔 +美佔 +英佔 +德佔 +法佔 +俄佔 +葡佔 +西佔 +奧佔 +意佔 +義佔 +地佔 +佔場 +佔耕 +狂佔 +徵佔 +圈佔 +已佔 +佔囁 +佔主 +佔次 +寡佔 +佔去 +將佔 +將占卜 +要佔 +要占卜 +會佔 +會占卜 +占卜 +夢有五不占 +占有五不驗 +誌異 +筑前 +筑後 +筑紫 +筑波 +筑州 +筑肥 +筑西 +筑北 +肥筑方言 +筑邦 +筑陽 +南筑 +批准的 +核准的 +為準 +準直 +擺鐘 +編鐘 +碰鐘 +鳴鐘 +晨鐘 +鐘體 +飯後鐘 +盜鐘 +一天鐘 +撞鐘 +殿鐘自鳴 +天文鐘 +天文學鐘 +洛鐘東應 +亮鐘 +郘鐘 +歌鐘 +鐘不撞不鳴 +毀鐘為鐸 +洪鐘 +擊鐘 +警世鐘 +竊鐘掩耳 +琴鐘 +見鐘不打 +釁鐘 +朝鐘 +木鐘 +鐘不扣不鳴 +鐘鳴 +鐘塔 +鐘漏 +鐘琴 +鐘磬 +鐘形蟲 +鐘乳洞 +鐘乳石 +鐘在寺裡 +詩鐘 +懸鐘 +山崩鐘應 +坐鐘 +宗周鐘 +塞耳盜鐘 +二缶鐘惑 +口鐘 +鐘的 +的鐘 +這鐘 +叩鐘 +音聲如鐘 +應鐘 +原子鐘 +泳氣鐘 +電子鐘 +電子鐘錶 +石英鐘錶 +石英鐘 +鐘錶王 +鐘律 +看鐘 +看錶 +看表面 +鐵鐘 +看下鐘 +看下錶 +瞅下鐘 +瞅下錶 +拿下鐘 +拿下錶 +鐘不敲不響 +對準鐘 +對準鐘錶 +對準錶 +鐘錶快 +鐘快 +錶快 +鐘錶慢 +鐘慢 +錶慢 +響鐘 +鐘敲 +大本鐘敲 +大笨鐘敲 +世紀鐘錶 +世紀鐘 +錶王 +鐘王 +鐘錶 +古鐘 +古鐘錶 +鐘面 +鐘表面 +南京鐘 +南京鐘錶 +造鐘錶 +造鐘 +九龍表行 +鐘錶行 +鐘行 +錶行 +小型鐘表面 +小型鐘面 +小型鐘錶 +小型鐘 +中型鐘表面 +中型鐘面 +中型鐘錶 +中型鐘 +大型鐘表面 +大型鐘面 +大型鐘錶 +大型鐘 +鐘匠 +深山何處鐘 +下課鐘 +上課鐘 +老爺鐘 +萬年曆錶 +個鐘 +個鐘錶 +喜歡鐘 +喜歡鐘錶 +喜歡錶 +大鐘 +佛鐘 +鐘壁 +鐘腰 +鐘口 +鐘身 +鐘模 +鐘頂 +鐘紐 +鐘座 +他鐘 +寺鐘 +座鐘 +盜鐘 +大笨鐘 +大本鐘 +鐘錶歷史 +錶的歷史 +鐘錶的歷史 +點多鐘 +點半鐘 +分多鐘 +刻多鐘 +分半鐘 +刻半鐘 +教學鐘 +操作鐘 +南屏晚鐘 +敲鐘 +瞧著鐘 +瞧著鐘錶 +瞧著錶 +警報鐘 +猶如鐘 +猶如鐘錶 +猶如錶 +舊鐘錶 +繁鐘 +四面鐘 +更鐘 +警示鐘 +鐘差 +任何鐘錶 +任何鐘 +任何錶 +任何表示 +任何表達 +任何表演 +選手表現 +選手表達 +選手表示 +選手表明 +選手表決 +分子鐘 +飛行鐘 +鐘罩 +主鐘差 +花鐘 +磬鐘 +主鐘曲線 +鐘速 +紅鐘 +各類鐘 +打著鐘 +鐘意 +衛星鐘 +該鐘 +錶轉 +鐘調 +調鐘錶 +調錶 +原鐘 +鐘錶速 +件鐘 +鐘發音 +逆鐘 +拂鐘無聲 +鐘不空則啞 +看著鐘錶 +看著鐘 +看著錶 +晚鐘 +潛水鐘錶 +潛水鐘 +潛水錶 +樂器鐘 +鐘左右 +埋頭尋鐘錶 +埋頭尋鐘 +埋頭尋錶 +鐘陳列 +驚鐘 +望著鐘錶 +望著鐘 +望著錶 +鐘錶停 +鐘停 +銫鐘 +數字鐘錶 +數字鐘 +顯示鐘錶 +顯示鐘 +顯示錶 +坐如鐘 +錶停 +西周鐘 +東周鐘 +錶速 +機械鐘錶 +機械鐘 +機械錶 +之鐘 +鐘形 +架鐘 +順鐘向 +逆鐘向 +遺傳鐘 +鬧錶 +華嚴鐘 +懷鐘 +生物鐘 +鐘錶的 +錶的嘀嗒 +的鐘錶 +嘀嗒的錶 +鐘好 +鐘太 +鐘不 +鐘有 +鐘盤 +鐘錶盤 +鐘沒 +鐘被 +制鐘 +布穀鳥鐘 +咕咕鐘 +拉克施爾德鐘 +鐘上 +鐘下 +摸鐘 +舊鐘 +舊錶 +台鐘 +鐘響 +叩鐘 +計時錶 +防水錶 +射鵰 +神鵰 +神雕像 +采石磯 +采石之戰 +采石之役 +聊齋志異 +部落發 +角落發 +村落發 +蛇髮女妖 +畢生發展 +對華發動 +中美發表 +尸魂界 +樹樑 +屋樑 +樑柱 +柱樑 +下樑 +上梁山 +昇陽 +僥倖 +夏遊 +秋遊 +冬遊 +黑奴籲天錄 +林郁方 +讚歌 +編餘 +餘墨 +唾餘 +餘韻 +歸餘 +公餘 +寬餘 +餘糧 +餘慶 +餘殃 +餘燼 +劫餘 +結餘 +燼餘 +淨餘 +餕餘 +餘暉 +餘輝 +羨餘 +餘悸 +心餘 +刑餘 +緒餘 +血餘 +朱慶餘 +諸餘 +餘論 +茶餘 +廚餘 +餘裕 +餘氣 +詩餘 +詞餘 +餘僇 +餘辜 +餘責 +餘罪 +無餘 +耳餘 +餘烈 +餘思 +鹽餘 +嬴餘 +贏餘 +王餘魚 +紆餘 +餘波 +餘杯 +餘步 +餘妙 +餘音 +餘聲 +餘明 +餘風 +餘黨 +餘毒 +餘桃 +餘桶 +餘利 +餘瀝 +餘膏 +餘光 +餘杭 +餘竅 +餘缺 +餘暇 +餘閒 +餘羨 +餘響 +餘興 +餘蓄 +餘緒 +餘珍 +餘眾 +餘酲 +餘喘 +餘食 +餘熱 +餘刃 +餘閏 +餘存 +餘業 +餘姚 +餘蔭 +餘映 +餘外 +餘威 +餘味 +餘溫 +餘勇 +多餘 +剩餘 +餘生 +餘歡 +有餘 +一餘 +二餘 +兩餘 +三餘 +四餘 +五餘 +六餘 +七餘 +八餘 +九餘 +十餘 +百餘 +千餘 +萬餘 +億餘 +兆餘 +0餘 +1餘 +2餘 +3餘 +4餘 +5餘 +6餘 +7餘 +8餘 +9餘 +0餘 +1餘 +2餘 +3餘 +4餘 +5餘 +6餘 +7餘 +8餘 +9餘 +余姓 +余光生 +余光中 +余思敏 +余威德 +余子明 +余三勝 +崑山 +崑曲 +崑腔 +崑調 +崑劇 +崑蘇 +蘇崑 +分布圖 +一干家中 +星期後 +不准你 +不准我 +不准他 +不准她 +不准它 +不准誰 +不准許 +准不准你 +准不准我 +准不准他 +准不准她 +准不准它 +准不准誰 +准不准許 +依依不捨 +戀戀不捨 +窮追不捨 +緊追不捨 +鍥而不捨 +稜登 +前言不答後語 +繃扒弔拷 +不弔 +不通弔慶 +陪弔 +盆弔 +屁股大弔了心 +撇弔 +憑弔 +門弔兒 +伐罪弔民 +打出弔入 +搗鬼弔白 +弔膀子 +弔民 +弔民伐罪 +弔奠 +弔頭 +弔古 +弔古尋幽 +弔詭 +弔詭矜奇 +弔客 +弔拷 +弔拷繃扒 +弔扣 +弔賀迎送 +弔鶴 +弔喉 +弔謊 +弔祭 +弔腳兒事 +弔頸 +弔橋 +弔取 +弔孝 +弔紙 +弔者大悅 +弔場 +弔書 +弔詞 +弔死問孤 +弔死問疾 +弔撒 +弔喪 +弔喪問疾 +弔腰撒跨 +弔唁 +弔宴 +弔喭 +弔影 +弔慰 +弔文 +弔問 +頭巾弔在水裡 +提心弔膽 +弄鬼弔猴 +管人弔腳兒事 +開弔 +鶴弔 +昊天不弔 +花馬弔嘴 +會弔 +吉凶慶弔 +蟣蝨相弔 +祭弔 +祭弔文 +青蠅弔客 +慶弔 +形影相弔 +哀弔 +一弔 +唁弔 +於水 +安於 +迫於 +罷於 +蹪於 +於敝 +於過 +甚於 +等於 +定於 +利於 +對於 +推舟於陸 +退藏於密 +歸於 +難於 +移禍於 +生於 +立於 +多於 +勝於 +傳於 +流於 +過於 +關於 +毀於 +基於 +急於 +嫁禍於 +借聽於聾 +見於 +鑒於 +謹於心 +求道於盲 +始於 +於藍 +出於 +輕於 +行百里者半於九十 +幸於 +怠於 +詢於芻蕘 +止於 +至於 +拙於 +忠於 +終於 +重於 +垂於 +善於 +死於 +屬於 +浮於 +在於 +厝薪於火 +易於 +精於 +由於 +於此 +燕巢於幕 +於菟 +於乎 +於戲 +於邑 +補於 +位於 +於今 +於是 +於是乎 +於斯 +寓於 +月離於畢 +月麗於箕 +源於 +且於 +長於 +短於 +現於 +較於 +於之 +分布於 +分散於 +優於 +早於 +晚於 +感於 +鬼谷子 +于美人 +緊緻 +冗餘 +曰云 +若干 +徵婚 +鬥鬨 +事有鬥巧 +歹鬥 +鬥茶 +鬥鴨 +爭奇鬥妍 +誇能鬥智 +春香鬥學 +鬥引 +鬥彩 +鬥武 +鬥悶 +鬥牙拌齒 +鬥幌子 +鬥腳 +雞吵鵝鬥 +辯鬥 +廝鬥 +誇多鬥靡 +臨潼鬥寶 +鬥趣 +撩鬥 +傲霜鬥雪 +賭鬥 +搬鬥 +鬥爭鬥合 +鬥疊 +鬥文 +耍鬥 +鬥巧 +油鬥 +蚊動牛鬥 +卵與石鬥 +挑鬥 +爭奇鬥異 +鬥葉子 +鬥分子 +爭妍鬥奇 +不鬥 +鬥心眼 +鬥頭 +挌鬥 +好鬥 +鬥合 +拚鬥 +兩虎共鬥 +兩鼠鬥穴 +鬥犀臺 +鬥牙鬥齒 +惡鬥 +鬥勝 +鬥富 +鬥艦 +鬥葉兒 +鬥彆氣 +鬥話 +鬥牌 +鬥百草 +鬥打 +鬥犬 +鬥風 +鬥雪紅 +鬥暴 +鬥閑氣 +龍鬥虎傷 +殷師牛鬥 +二虎相鬥 +鬥力 +爭紅鬥紫 +鬥麗 +鬥狠 +鬥飣 +虎鬥 +引鬥 +爭妍鬥豔 +轉鬥千里 +鬥而鑄兵 +困鬥 +好勇鬥狠 +爭奇鬥豔 +使其鬥 +鬥地主 +石樑 +木樑 +藏歷史 +頁面 +方面 +表面 +面條目 +課餘 +節餘 +盈餘 +病餘 +餘地 +餘力 +餘子 +餘事 +扶餘國 +腐餘 +富餘 +之餘 +餘澤 +流風餘俗 +流風餘韻 +淋餘土 +餘一 +餘二 +餘三 +餘四 +餘五 +餘六 +餘七 +餘八 +餘九 +餘十 +零餘 +〇餘 +餘零 +餘〇 +餘1 +餘2 +餘3 +餘4 +餘5 +餘6 +餘7 +餘8 +餘9 +餘0 +餘1 +餘2 +餘3 +餘4 +餘5 +餘6 +餘7 +餘8 +餘9 +餘0 +餘數 +其餘 +尸居餘氣 +賸餘 +餘孽 +殘餘 +業餘 +餘割 +餘款 +餘角 +餘切 +餘霞 +餘下 +餘弦 +餘震 +餘貾 +餘額 +禹餘糧 +餘人 +編余 +病余 +餘俗 +餘倍 +同餘 +大讚 +唄讚 +褒讚 +謬讚 +誄讚 +祝讚 +詩讚 +賞讚 +讚唄 +飛紮 +紮裹 +紮腳 +紮詐 +紮囮 +住紮 +佔畢 +佔頭籌 +佔高枝兒 +隱佔 +憑摺 +沒摺至 +大摺兒 +大週摺 +火摺子 +裝摺 +變徵 +談徵 +納徵 +流徵 +柳詒徵 +固徵 +貴徵 +考徵 +咎徵 +杞宋無徵 +休徵 +徵辟 +徵名責實 +徵發 +徵風召雨 +徵答 +徵啟 +徵選 +徵招 +徵士 +徵庸 +之徵 +瑞徵 +三徵七辟 +額徵 +有徵 +有征服 +有征戰 +有征伐 +有征討 +無徵不信 +文徵明 +徵跡 +徵車 +徵效 +徵怪 +徵聖 +徵咎 +徵吏 +徵令 +本徵 +船鐘 +黃鈺筑 +齊莊 +鴻案相莊 +項莊 +韋莊 +鍋莊 +鄭莊公 +通莊 +蒙莊 +端莊 +票莊 +矜莊 +楚莊問鼎 +楚莊絕纓 +整莊 +打路莊板 +莊騷 +莊語 +莊舄越吟 +莊房 +莊客 +莊農 +平泉莊 +布莊 +香山庄 +寶莊 +坐莊 +周莊王 +發莊 +卞莊 +包莊 +剔莊貨 +劉克莊 +冷莊子 +石家莊 +卞莊子 +新莊市 +當準 +憑準 +沒準 +蜂準 +推情準理 +寇準 +合準 +準保 +準譜 +準分子 +準點 +一個準 +準擬 +準貨幣 +準軍事 +準式 +認準 +三準 +鵝準 +有準 +崑崙 +鎌倉 +請君入甕 +甕安 +痊癒 +治癒 +病癒 +大病初癒 +癒合 +槓桿 +宣洩 +圖鑑 +諮詢 +勳章 +張勳 +趙治勳 +殭屍 +有栖川 +兇惡 +兇狠 +兇猛 +兇橫 +兇悍 +兇險 +兇相 +兇犯 +嫌兇 +兇嫌 +兇疑 +兇刀 +兇槍 +很兇 +兇巴巴 +行兇前 +凝鍊 +鍊貧 +鍊度 +鍊形 +鍊師 +鍊石 +鍊字 +鍊冶 +細鍊 +陳鍊 +闖鍊 +鍊汞 +淬鍊 +鋼之鍊金術師 +索馬里 +范登堡 +世田谷 +製漿 +三統歷史 +伊斯蘭教歷史 +伊斯蘭歷史 +儒略改革歷史 +儒略歷史 +公歷史 +台歷史 +合歷史 +周歷史 +商歷史 +四分歷史 +回歷史 +埃及歷史 +大明歷史 +大歷史 +大衍歷史 +太初歷史 +官歷史 +寶歷史 +巧歷史 +希伯來歷史 +弘歷史 +慶歷史 +日歷史 +星歷史 +月歷史 +朱理安歷史 +桌歷史 +永歷史 +玉歷史 +百花歷史 +皇歷史 +皇極歷史 +穆罕默德歷史 +算歷史 +紀歷史 +舊歷史 +航海歷史 +萬歷史 +行事歷史 +農歷史 +農民歷史 +通歷史 +長歷史 +陰歷史 +陽歷史 +額我略歷史 +黃歷史 +天曆 +天歷史 +美醜 +獻醜 +出醜 +家醜 +遮醜 +醜八怪 +醜名 +醜詆 +醜態 +醜女 +醜類 +醜陋 +醜虜 +醜化 +醜劇 +醜媳婦 +醜小鴨 +醜行 +醜事 +醜聲 +醜人 +醜惡 +醜丫頭 +醜聞 +醜語 +母醜 +一齣子 +齣兒 +賣獃 +發獃 +大獃 +獃獃 +獃等 +獃頭 +獃腦 +獃根 +獃磕 +獃憨獃 +獃話 +獃氣 +獃想 +獃性 +獃滯 +獃著 +獃痴 +獃串了皮 +獃事 +獃人 +獃子 +好獃 +占便宜的是獃 +阿獃 +丰標 +丰姿 +丰韻 +鵰翎 +鵰心雁爪 +鵰鶚 +雙鵰 +撲鼕鼕 +普鼕鼕 +鼕鼕鼓 +令人髮指 +爆發指數 +開發 +剪其髮 +吐哺捉髮 +吐哺握髮 +含齒戴髮 +大金髮苔 +寸髮千金 +心長髮短 +戴髮含齒 +拔髮 +拔鬚 +揪髮 +揪鬚 +整髮用品 +斷髮文身 +滿頭洋髮 +燙一個髮 +燙一次髮 +燙個髮 +燙完髮 +燙次髮 +理一個髮 +理一次髮 +理個髮 +理完髮 +理次髮 +細如髮 +繫於一髮 +膚髮 +皮膚 +生華髮 +蒼髮 +被髮佯狂 +被髮入山 +被髮左衽 +被髮纓冠 +被髮陽狂 +身體髮膚 +髒髮 +髮光可鑑 +髮已霜白 +髮油 +髮為血之本 +髮網 +髮踊沖冠 +髮際 +黃髮 +齒落髮白 +剷頭 +剷刈 +口燥唇乾 +舌乾唇焦 +花菴詞選 +渾箇 +箇中原因 +箇中理由 +箇中高手 +箇中好手 +箇中強手 +箇中滋味 +箇中奧秘 +箇中奧妙 +箇中玄機 +箇中消息 +箇中資訊 +箇中訊息 +對表達 +對表現 +對表演 +對表揚 +對表中 +對表明 +不準確 +並不準確 +一伙頭 +一伙食 +一半只 +一干弟兄 +一干弟子 +一干部下 +一斗斗 +一面食 +萬一只 +上面糊 +不克自制 +不准沒 +不加自制 +不占凶吉 +不占卜 +不占吉凶 +不占算 +不好干涉 +不好干預 +不干預 +不干涉 +不干休 +不干犯 +不干擾 +不干你 +不干我 +不干他 +不干她 +不干它 +不干事 +不斗膽 +不每只 +不采聲 +專向往 +丰容 +之一只 +之二只 +之八九只 +也斗了膽 +事情干脆 +事都干脆 +二只得 +亦云 +人云 +以自制 +們斗了膽 +你斗了膽 +其一只 +其二只 +其八九只 +內面包 +內面包的 +准保護 +准保釋 +几上 +几淨窗明 +几凳 +几子 +几旁 +几椅 +几榻 +几面上 +出征收 +擊扑 +划一槳 +划了一會 +划到岸 +划到江心 +前面店 +千只可 +千只夠 +千只怕 +千只能 +千只足夠 +半只可 +半只夠 +占了卜 +口干冒 +口干政 +口干涉 +口干犯 +口干預 +古書云 +古語云 +只占卜 +只占吉 +只占神問卜 +只占算 +只身上已 +只身上無 +只身上有 +只身上沒 +只身上的 +只身世 +只身為 +只身份 +只身體 +只身前 +只身受 +只身後 +只身子 +只身形 +只身影 +只身心 +只身旁 +只身材 +只身段 +只身邊 +只身首 +只身高 +只采聲 +可自制 +台子女 +台子孫 +台布景 +台面前 +合府上 +後面店 +向往常 +向往日 +向往時 +向往來 +唯一只 +喂了一聲 +喜向往 +四出徵收 +四面包 +多半只 +好斗大 +好斗室 +好斗笠 +好斗篷 +好斗膽 +好斗蓬 +家具體 +家具備 +家具有 +小几 +尸利 +尸祿 +尸臣 +尸鳩 +已占卜 +已占算 +并迭 +所云 +所云云 +所占卜 +所占星 +所占算 +手表決 +手表態 +手表明 +手表演 +手表現 +手表示 +手表達 +手表露 +手表面 +才干休 +才干戈 +才干擾 +才干政 +才干涉 +才干預 +扎好底子 +扎好根 +扑撻 +打吨 +折向往 +拉面上 +拉面具 +拉面前 +拉面巾 +拉面無 +拉面皮 +拉面罩 +拉面色 +拉面部 +捉奸黨 +捉奸徒 +捉奸細 +捉奸賊 +敢情欲 +敢斗了膽 +敲扑 +方向往 +望了望 +桌几 +每每只 +法自制 +洒滌 +洒淅 +洒濯 +洒然 +灘涂 +特制住 +特制定 +特制止 +特制訂 +百只可 +百只夠 +百只怕 +百只足夠 +皮制服 +相克制 +相克服 +短几 +石几 +秒表明 +秒表示 +窗明几亮 +竹几 +精制伏 +精制住 +精制服 +經有云 +給我干脆 +編制法 +能干休 +能干戈 +能干擾 +能干政 +能干涉 +能干預 +能自制 +自制一下 +自制下來 +自制不 +自制之力 +自制之能 +自制他 +自制伏 +自制你 +自制地 +自制她 +自制情 +自制我 +自制服 +自制的能 +自制能力 +船只得 +船只有 +船只能 +草荐 +荐居 +荐臻 +荐饑 +要自制 +語有云 +跌扑 +轉向往 +酒帘 +裡面包 +金表態 +金表情 +金表揚 +金表明 +金表演 +金表現 +金表示 +金表達 +金表露 +金表面 +長几 +隆准許 +雄斗斗 +面包住 +面包辦 +面包廂 +面包含 +面包圍 +面包容 +面包庇 +面包紮 +面包抄 +面包括 +面包攬 +面包涵 +面包管 +面包羅 +面包著 +面包藏 +面包裝 +面包裹 +面包起 +面店舖 +面粉碎 +面粉紅 +面食麵 +面食飯 +顛顛仆仆 +高干擾 +高干預 +高度自制 +黃金表 +天后宮 +一吊錢 +不食乾腊 +傳位于四太子 +儉确之教 +党懷英 +八蜡 +憑几 +南宮适 +大蜡 +子云 +分子雲 +小价 +歲聿云暮 +崖广 +恕乏价催 +悲筑 +折子戲 +揮杆 +搤肮拊背 +文采郁郁 +木杆 +洪适 +球杆 +腊之以為餌 +腊毒 +蜡月 +蜡祭 +言云 +宜云 +貴价 +郁郁菲菲 +馬杆 +造麯 +麴生 +麴秀才 +麴塵 +麴櫱 +大麴 +黃麴毒素 +酒醴麴櫱 +麴道士 +麴錢 +麴車 +麴院 +鼠麴草 +不乾不淨 +生發生 +必須 +須根據 +·范 +、剋制 +,剋制 +。剋制 +!剋制 +?剋制 +;剋制 +:剋制 +不剋制 +也剋制 +了剋制 +他剋制 +們剋制 +剋制不了 +剋制不住 +力剋制 +力求剋制 +可以剋制 +和剋制 +在剋制 +地剋制 +夠剋制 +她剋制 +你剋制 +您剋制 +就剋制 +彼此剋制 +得剋制 +快剋制 +想剋制 +意剋制 +應剋制 +我剋制 +才剋制 +於剋制 +易剋制 +無法剋制 +的剋制 +盡量剋制 +而剋制 +能剋制 +與剋制 +著剋制 +要剋制 +軍隊剋制 +空投佈雷 +火箭佈雷 +海灣佈雷 +空中佈雷 +海上佈雷 +佈雷的 +佈雷, +佈雷、 +佈雷。 +佈雷; +佈雷艦 +佈雷艇 +佈雷速度 +佈雷封鎖 +滿拚自盡 +拚生盡死 +拚卻 +拚老命 +拚絕 +成於思 +單單於 +積澱 +澱積 +澱北片 +澱解物 +澱謂之滓 +淺澱 +堙澱 +茂都澱 +並曰入澱 +澱乃不耕之地 +藍澱 +皆可作澱 +澱山 +海淀山後 +澱澱 +掛鈎 +薴悴 +絡腮鬍 +落腮鬍 +山羊鬍 +幸運鬍 +刮鬍 +剃鬍 +吹鬍 +蓄鬍 +白鬍 +長鬍 +鬍髯 +髯鬍 +髭鬍 +鬚鬍 +范文瀾 +范文同 +范文正公 +范文程 +范文芳 +范文藤 +范文虎 +范文照 +發表 +乾重 +若干 +鈎心鬥角 +若干 +乾重 +全面包圍 +全面包裹 +機械系 +體系 +心理 +複分解 +鹰鵰 +叱咤903 +叱咤MY903 +叱咤My903 +叱咤樂壇 +叱咤咤 +叱咤叱咤叱咤咤 +叱咤叱叱咤 +正在叱咤 +空餘 +變髒 +天地志狼 +薴烯 +阿斯圖里亞斯 +雙折射 +心繫家 +心繫國 +心繫祖 +心繫北 +心繫京 +心繫南 +心繫西 +心繫東 +心繫四 +心繫川 +心繫浙 +心繫汶 +心繫廣 +心繫湖 +心繫山 +心繫台 +心繫江 +心繫昌 +心繫香 +心繫澳 +心繫港 +心繫泰 +心繫健 +心繫天 +心繫地 +心繫大 +心繫小 +心繫全 +心繫眾 +心繫奧 +心繫世 +心繫中 +心繫高 +心繫災 +心繫非 +心繫群 +心繫新 +心繫沈 +心繫唐 +心繫黃 +心繫乔 +心繫阮 +心繫父 +心繫母 +心繫病 +心繫故 +心繫哪 +心繫中 +心繫英 +心繫美 +心繫日 +心繫德 +心繫功 +心繫曉 +心繫神 +心繫萬 +心繫的 +心繫在 +心繫兩 +心繫社 +心繫曼 +心繫彼 +心繫風 +心繫募 +心繫一 +心繫何 +心繫困 +心繫輸 +心繫人 +心繫民 +心繫十 +心繫百 +心繫千 +心繫和 +心繫選 +心繫囑 +心繫我 +心繫你 +心繫您 +心繫他 +心繫她 +心繫它 +心繫伊 +心繫長 +心繫舞 +心繫蘭 +心繫五 +心繫生 +心繫婦 +心繫幼 +心繫茶 +心繫動 +心繫沙 +心繫林 +心繫摩 +心繫农 +心繫慈 +心繫麥 +心繫貧 +心繫富 +心繫遠 +心繫近 +心繫宣 +心繫傳 +心繫紅 +心繫老 +心繫重 +心繫震 +心繫妻 +心繫夫 +心繫女 +心繫子 +心繫著 +重回 +挑大樑 +扛大樑 +后豐 +製得 +限制 +控制 +製取 +第四出局 +心臟 +肝臟 +脾臟 +肺臟 +腎臟 +參與 +浮誇 +星巴克 +于謙 +于寘 +淳于 +于禁 +于敏中 +註:# 不作“注:” +呆呆獸 +劃為# 不作“划為” +併為一體 +併為一家 +一個# 避免“個裡”的錯誤 +兩個 +二個 +三個 +四個 +五個 +六個 +七個 +八個 +九個 +十個 +百個 +千個 +萬個 +億個 +兆個 +零個 +云:# 不作“雲:” +電子表格 +雪裡紅 +雪裡蕻 +森林裡 +日子裡 +故事裡 +領域裡 +時間裡 +深淵裡 +醫院裡 +春假裡 +暑假裡 +秋假裡 +寒假裡 +春天裡 +夏天裡 +秋天裡 +冬天裡 +春日裡 +夏日裡 +秋日裡 +冬日裡 +嘴裡 +心裡 +皮裡陽秋 +肚裡 +苦裡 +裡勾外連 +裡面 +這裡 +中文裡 +山洞裡 +世界裡 +眼睛裡 +首發 +夸脫 +誰幹的 +鐘螺 +風采 +代碼表 +編碼表 +字碼表 +電碼表 +科斗 +佔領 +灕水 +點裡 +這只是 +這只不 +這只容 +這只允 +這只採 +這只用 +有只是 +有只不 +有只容 +有只允 +有只採 +有只用 +葉叶琹 +胡子昂 +包括 +特别致 +分别致 +會上簽訂 +會上簽署 +周一 # (及以下)避免“周一齣版”的錯誤 +周二 +周三 +周四 +周五 +周六 +韶山沖 +總裁制 +于丹 +于樂 +于冕 +于軍 +于吉 +于堅 +于姓 +于氏 +于娜 +于娟 +于山 +于帥 +于慧 +于振 +于敏 +于斌 +于晴 +于波 +于濤 +于衡 +于贈 +于越 +于靖 +于勒 +于格 +于仁泰 +于會泳 +于偉國 +于佳卉 +于光遠 +于克勒 +于凌奎 +于鳳至 +于化虎 +于占元 +于台煙 +于品海 +于國楨 +于大寶 +于天仁 +于子千 +于孔兼 +于學忠 +于家堡 +于小偉 +于小彤 +于山國 +于幼軍 +于廣洲 +于康震 +于式枚 +于從濂 +于德海 +于志寧 +于慎行 +于成龍 +于振武 +于明濤 +于是之 +于晨楠 +于根偉 +于樹潔 +于欣源 +于正昇 +于正昌 +于永波 +于漢超 +于江震 +于洪區 +于浩威 +于海洋 +于湘蘭 +于特森 +于玉立 +于秀敏 +于素秋 +于若木 +于蔭霖 +于西翰 +于遠偉 +于道泉 +于都縣 +于震寰 +于震環 +于非闇 +于風政 +于鳳桐 +于默奧 +于家堡 +于爾岑 +于默奧 +于貝爾 +于爾根 +于雙戈 +于里察 +于澤爾 +于斯塔德 +于斯達爾 +于爾里克 +于奇庫杜克 +于韋斯屈萊 +于克-蘭多縣 +于斯納爾斯貝里 +夏于喬 +涂姓 +涂坤 +涂天相 +涂序瑄 +涂澤民 +涂紹煃 +涂羽卿 +涂逢年 +涂長望 +涂謹申 +涂鴻欽 +涂壯勳 +涂醒哲 +涂善妮 +涂敏恆 +總裁制 +故云 +強制作用 +鬱南 +西米谷 +一出生 +二出生 +三出生 +四出生 +五出生 +六出生 +七出生 +八出生 +九出生 +十出生 +一出版 +二出版 +三出版 +四出版 +五出版 +六出版 +七出版 +八出版 +九出版 +十出版 +一出刊 +二出刊 +三出刊 +四出刊 +五出刊 +六出刊 +七出刊 +八出刊 +九出刊 +十出刊 +一出逃 +二出逃 +三出逃 +四出逃 +五出逃 +六出逃 +七出逃 +八出逃 +九出逃 +十出逃 +一出口 +二出口 +三出口 +四出口 +五出口 +六出口 +七出口 +八出口 +九出口 +十出口 +一出祁山 +二出祁山 +三出祁山 +四出祁山 +五出祁山 +六出祁山 +七出祁山 +八出祁山 +九出祁山 +十出祁山 +鬱林 +饑荒 +免徵 +亞美尼亞曆 +百科裡 +歷史裡 +戲裡 +作品裡 +專輯裡 +年代裡 +棺材裡 +注釋 +月面 +路面 +修杰楷 +修杰麟 +學裡 +獄裡 +館裡 +系列裡 +村子裡 +艷后 +廢后 +妖后 +后海灣 +仙后 +賈后 +賢后 +蜂后 +皇后 +王后 +王侯后 +母后 +武后 +歌后 +影后 +封后 +太后 +天后 +呂后 +后里 +后街 +后羿 +后稷 +后座 +后平路 +后安路 +后土 +后北街 +后冠 +望后石 +后角 +蟻后 +后妃 +大周后 +小周后 +染殿后 +准三后 +風后 +后母戊 +風後, +人如風後入江雲 +中風後 +屏風後 +颱風後 +颳風後 +整風後 +打風後 +遇風後 +聞風後 +逆風後 +順風後 +大風後 +馬格里布 +伊里布 +劃入 +中庄子 +埔裏社撫墾局 +懸掛 +僱傭 +四捨六入 +宿舍 +會干擾 +代表 +高清愿 +瓷製 +竹製 +絲製 +莜麵 +劃入 +簡筑翎 +楊雅筑 +魔杰座 +杰威爾音樂 +彭于晏 +尸羅精舍 +索馬里 # (及以下)避免里海=>裏海的轉換 +西西里 +騰格里 +阿里 +村里長 +進制 +黃詩杰 +陳冲 +何杰 +劉佳怜 +于小惠 +于品海 +于耘婕 +于洋 +于澄 +于光新 +范賢惠 +于國治 +于楓 +于熙珍 +涂善妮 +邱于庭 +熊杰 +卜云吉 +黎吉雲 +于飛島 +代表 +水無怜奈 +傲遊 # 浏览器名 +夏于喬 +賭后 +后海灣 +立后綜 +甲后路 +劉芸后 +謝華后 +趙惠后 +趙威后 +聖后 +陳有后 +許虬 +網遊 +狄志杰 +伊適杰 +于冠華 +于台煙 +于雲鶴 +于忠肅集 +于友澤 +于和偉 +于來山 +于樂 +于天龍 +于謹 +于榮光 +電波鐘 +余三勝 +掛名 +啟發式 +舞后 +甄后 +郭后 +0年 # 協助分詞 +1年 +2年 +3年 +4年 +5年 +6年 +7年 +8年 +9年 +0年 +1年 +2年 +3年 +4年 +5年 +6年 +7年 +8年 +9年 +〇年 +零年 +一年 +兩年 +二年 +三年 +四年 +五年 +六年 +七年 +八年 +九年 +十年 +百年 +千年 +萬年 +億年 +周后 +0周後 +1周後 +2周後 +3周後 +4周後 +5周後 +6周後 +7周後 +8周後 +9周後 +0周後 +1周後 +2周後 +3周後 +4周後 +5周後 +6周後 +7周後 +8周後 +9周後 +零周後 +〇周後 +一周後 +二周後 +兩周後 +三周後 +四周後 +五周後 +六周後 +七周後 +八周後 +九周後 +十周後 +百周後 +千周後 +萬周後 +億周後 +幾周後 +多周後 +前往 +后瑞站 +帝后臺 +新井里美 +樗里子 +伊達里子 +濱田里佳子 +尊后 +叶志穗 +叶不二子 +于立成 +山谷道 +李志喜 +于欣 +于少保 +于海 +於海邊 +於海上 +于凌辰 +于魁智 +于鬯 +于仲文 +于再清 +于震 +於震前 +於震后 +於震中 +固定制 +毗婆尸佛 +尸棄佛 +划船 +划不來 +划拳 +划槳 +划動 +划艇 +划行 +划算 +總裁制 +恒生 +嚴云農 +手裏劍 +秦莊襄王 +伊東怜 +衛後莊公 +餘量 +並行 +郁郁青青 +協防 +對表格 +對表示 +對表達 +對表演 +對表明 +了然後 +戴表元 +張樂于張徐 +余力為 +葉叶琴 +万俟 +幾個 +澀谷區 +協調 +選手 +併發症 +併發重症 +併發模式 +併發型模式 +金色長髮 +紅色長髮 +一頭長髮 +的長髮 +黑色長髮 +前天 +昨天 +今天 +明天 +後天 +數學家 +科學家 +物理學家 +化學家 +生物學家 +天文學家 +游離 +子晳 +紅后假說 +書面 +不只 +高涌泉 +請求 +考試 +測試 +筆試 +口試 +冰冷 +王田里 +后姓 +台州 +田庄英雄 +計劃 +抑制劑 diff --git a/maintenance/language/zhtable/tradphrases_exclude.manual b/maintenance/language/zhtable/tradphrases_exclude.manual new file mode 100644 index 00000000..e6abb4e1 --- /dev/null +++ b/maintenance/language/zhtable/tradphrases_exclude.manual @@ -0,0 +1,330 @@ +三國誌 +聊齋誌異 +北迴 +南迴 +併排 +併進 +併在 +併成 +衝衝 +臺 +著 +佈 +纔 +采 +着 +借 +甦 +荐 +担 +可憐虫 +一齣 +上弔 +弔車 +弔橋 +弔嗓子 +弔床 +弔架 +弔桶 +弔桿 +弔橋 +弔燈 +弔環 +弔籃 +弔胃口 +弔臂 +弔銷 +形影相弔 +被髮 +散髮 +長髮 +髮毛 +髮端 +周而複始 +答複 +複興 +複舊 +顛複 +修複 +報複 +複活 +反複 +迴首 +彙總 +饑餓 +饑不擇食 +饑荒 +憑藉 +藉故 +藉口 +藉端 +藉詞 +藉酒 +蛋捲 +行李捲 +克裡 +纍纍 +華裡 +裡海 +瞭解 +明瞭 +發黴 +矇蔽 +矇住 +濛濛 +矇矇 +下麵 +白麵 +切麵 +和麵 +過水麵 +復甦 +複蘇 +甦醒 +体 +繫數 +遊擊 +馥鬱 +鬱鬱 +改製 +獃住 +獃氣 +獃子 +獃頭獃腦 +儘量 +希腊 +腊肉 +瞭如 +昇 +武鬆 +赤鬆 +黑鬆 +鬆林 +鬆科 +鬆濤 +鬆毛蟲 +鬆節油 +濕地鬆 +尼克鬆 +紮伊爾 +阿布紮比 +阿紮尼亞 +利比裡亞 +斯裡蘭卡 +烏蘇裡江 +加裡寧 +歐幾裡得 +格裡 +巴裡 +居裡 +卡裡 +墨索裡尼 +底裡 +裡人 +裡加 +裡裡 +馬裡 +裡拉 +阿裡 +裡斯 +鄰裡 +鄉裡 +百裡 +特裡 +海裡 +三元裡 +漏鬥 +春捲 +採邑 +嚮日 +佔城 +水錶 +名錶 +錶面 +彆腳 +併力 +併列 +併為 +豐富多採 +採採 +尼採 +小醜 +辛醜 +整齣 +嚴複 +枯幹 +干著急 +單於 +攻剋 +剋服 +闢邪 +釐米 +後樑 +石樑 +木樑 +舊莊 +介係詞 +介繫詞 +餘年 +大阪 +阪田 +豪杰 +七拚八湊 +一捲 +十捲 +上捲 +下捲 +加捲 +不捨 +不識檯舉 +稜登 +半弔子 +分布圖 +星鬥 +筋鬥 +斗鬨 +料鬥 +煙鬥 +熨鬥 +笆鬥 +箕鬥 +金鬥 +門鬥 +風鬥 +鬥子 +鬥笠 +老板娘 +剋制 +洋麵 +病癥 +製裁 +台製 +石家庄 +酒盃 +積极 +殭尸 +上梁不正 +項鍊 +鍊子 +鍊條 +拉鍊 +鉸鍊 +鍊鎖 +鐵鍊 +鍛鍊 +鍊乳 +鍊丹 +至于 +浮于 +附于 +次于 +于人 +助于 +行于 +于衷 +于事 +低于 +大于 +高于 +等于 +位于 +用于 +答覆 +複蓋 +反覆 +藉藉 +蘊藉 +蹈藉 +醞藉 +氆氌 +慰藉 +文藉 +枕藉 +狼藉 +別隻 +鼕鼕 +矇松雨 +佈雷 +丰度 +剪彩 +脣 +菴 +公裡 +箇中 +樑子 +樑書 +讚成 +讚同 +鐘表店 +精採 +鞭尸 +尸身 +尸首 +行尸走肉 +裹尸 +慼慼 +痠 +簑 +捱 +朝乾夕惕 +大曲酒 +神麴 +便于 +偏于 +勇于 +居于 +常見于 +強加于 +從事于 +忙于 +敢于 +服務于 +服從于 +樂于 +歸罪于 +歸諸于 +活動于 +瀕于 +苦于 +莫過于 +處于 +適于 +乾和 +鉤 +高陞 +大胆 +託福 +繫系 +酰 +醯 +大樑 +光採 +鍾錶 +複原 +參与 +浮夸 +剋日 +羡 +旅游 +穀風 +復讎 +避暑山庄 +遊牧 +烟草 +征 +占領 +入夥 +懸挂 +註釋 +浮遊 +冶鍊 +裡子 +裡外 +單隻 +聯係 +那裏 +殺虫藥 +好家伙 +姦污 +併發 +衚衕 diff --git a/maintenance/locking/LockServerDaemon.php b/maintenance/locking/LockServerDaemon.php index 689c9309..01fbac72 100644 --- a/maintenance/locking/LockServerDaemon.php +++ b/maintenance/locking/LockServerDaemon.php @@ -23,7 +23,7 @@ * @ingroup LockManager Maintenance */ -if ( php_sapi_name() !== 'cli' ) { +if ( PHP_SAPI !== 'cli' ) { die( "This is not a valid entry point.\n" ); } error_reporting( E_ALL ); @@ -39,6 +39,8 @@ LockServerDaemon::init( /** * Simple lock server daemon that accepts lock/unlock requests + * + * @ingroup LockManager Maintenance */ class LockServerDaemon { /** @var resource */ @@ -66,6 +68,8 @@ class LockServerDaemon { /** * @params $config Array + * @param array $config + * @throws Exception * @return LockServerDaemon */ public static function init( array $config ) { @@ -75,9 +79,9 @@ class LockServerDaemon { foreach ( array( 'address', 'port', 'authKey' ) as $par ) { if ( !isset( $config[$par] ) ) { die( "Usage: php LockServerDaemon.php " . - "--address <address> --port <port> --authkey <key> " . + "--address <address> --port <port> --authKey <key> " . "[--lockTimeout <seconds>] " . - "[--maxLocks <integer>] [--maxClients <integer>] [--maxBacklog <integer>]" + "[--maxLocks <integer>] [--maxClients <integer>] [--maxBacklog <integer>]\n" ); } } @@ -111,6 +115,7 @@ class LockServerDaemon { } /** + * @throws Exception * @return void */ protected function setupServerSocket() { @@ -237,7 +242,9 @@ class LockServerDaemon { $m = explode( ':', $data ); // <session, key, command, type, values> if ( count( $m ) == 5 ) { list( $session, $key, $command, $type, $values ) = $m; - if ( sha1( $session . $command . $type . $values . $this->authKey ) !== $key ) { + $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'; diff --git a/maintenance/mcc.php b/maintenance/mcc.php index e07e62db..7b7b7614 100644 --- a/maintenance/mcc.php +++ b/maintenance/mcc.php @@ -23,13 +23,64 @@ */ /** */ -require_once( __DIR__ . '/commandLine.inc' ); +require_once __DIR__ . '/commandLine.inc'; -$mcc = new MWMemcached( array( 'persistent' => true/*, 'debug' => true*/ ) ); -$mcc->set_servers( $wgMemCachedServers ); -# $mcc->set_debug( true ); +$options = getopt( '', array( 'debug', 'help', 'cache:' ) ); -function mccShowHelp( $command ) { +$debug = isset( $options['debug'] ); +$help = isset( $options['help'] ); +$cache = isset( $options['cache'] ) ? $options['cache'] : null; + +if ( $help ) { + mccShowUsage(); + exit( 0 ); +} +$mcc = new MWMemcached( array( + 'persistent' => true, + 'debug' => $debug, +) ); + +if ( $cache ) { + if ( !isset( $wgObjectCaches[$cache] ) ) { + print "MediaWiki isn't configured with a cache named '$cache'"; + exit( 1 ); + } + $servers = $wgObjectCaches[$cache]['servers']; +} elseif ( $wgMainCacheType === CACHE_MEMCACHED ) { + $mcc->set_servers( $wgMemCachedServers ); +} elseif ( isset( $wgObjectCaches[$wgMainCacheType]['servers'] ) ) { + $mcc->set_servers( $wgObjectCaches[$wgMainCacheType]['servers'] ); +} else { + print "MediaWiki isn't configured for Memcached usage\n"; + exit( 1 ); +} + +/** + * Show this command line tool usage. + */ +function mccShowUsage() { + echo <<<EOF +Usage: + mcc.php [--debug] + mcc.php --help + +MemCached Command (mcc) is an interactive command tool that let you interact +with the MediaWiki memcached cache. + +Options: + --debug Set debug mode on the memcached connection. + --help This help screen. + +Interactive commands: + +EOF; + print "\t"; + print str_replace( "\n", "\n\t", mccGetHelp( false ) ); + print "\n"; +} + +function mccGetHelp( $command ) { + $output = ''; $commandList = array( 'get' => 'grabs something', 'getsock' => 'lists sockets', @@ -48,13 +99,15 @@ function mccShowHelp( $command ) { if ( $command === 'fullhelp' ) { $max_cmd_len = max( array_map( 'strlen', array_keys( $commandList ) ) ); foreach ( $commandList as $cmd => $desc ) { - printf( "%-{$max_cmd_len}s: %s\n", $cmd, $desc ); + $output .= sprintf( "%-{$max_cmd_len}s: %s\n", $cmd, $desc ); } } elseif ( isset( $commandList[$command] ) ) { - print "$command: $commandList[$command]\n"; + $output .= "$command: $commandList[$command]\n"; } else { - print "$command: command does not exist or no help for it\n"; + $output .= "$command: command does not exist or no help for it\n"; } + + return $output; } do { @@ -63,7 +116,9 @@ do { $quit = false; $line = Maintenance::readconsole(); - if ( $line === false ) exit; + if ( $line === false ) { + exit; + } $args = explode( ' ', $line ); $command = array_shift( $args ); @@ -72,8 +127,8 @@ do { switch ( $command ) { case 'help': // show an help message - mccShowHelp( array_shift( $args ) ); - break; + print mccGetHelp( array_shift( $args ) ); + break; case 'get': $sub = ''; @@ -93,7 +148,7 @@ do { } else { var_dump( $res ); } - break; + break; case 'getsock': $res = $mcc->get( $args[0] ); diff --git a/maintenance/mctest.php b/maintenance/mctest.php index 691b832b..eda101e7 100644 --- a/maintenance/mctest.php +++ b/maintenance/mctest.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that makes several 'set', 'incr' and 'get' requests @@ -34,21 +34,42 @@ class mcTest extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Makes several 'set', 'incr' and 'get' requests on every" - . " memcached server and shows a report"; + . " memcached server and shows a report"; $this->addOption( 'i', 'Number of iterations', false, true ); + $this->addOption( 'cache', 'Use servers from this $wgObjectCaches store', false, true ); $this->addArg( 'server[:port]', 'Memcached server to test, with optional port', false ); } public function execute() { - global $wgMemCachedServers, $wgMemCachedTimeout; + global $wgMainCacheType, $wgMemCachedTimeout, $wgObjectCaches; + $cache = $this->getOption( 'cache' ); $iterations = $this->getOption( 'i', 100 ); - if ( $this->hasArg() ) { - $wgMemCachedServers = array( $this->getArg() ); + if ( $cache ) { + if ( !isset( $wgObjectCaches[$cache] ) ) { + $this->error( "MediaWiki isn't configured with a cache named '$cache'", 1 ); + } + $servers = $wgObjectCaches[$cache]['servers']; + } elseif ( $this->hasArg() ) { + $servers = array( $this->getArg() ); + } elseif ( $wgMainCacheType === CACHE_MEMCACHED ) { + global $wgMemCachedServers; + $servers = $wgMemCachedServers; + } elseif ( isset( $wgObjectCaches[$wgMainCacheType]['servers'] ) ) { + $servers = $wgObjectCaches[$wgMainCacheType]['servers']; + } else { + $this->error( "MediaWiki isn't configured for Memcached usage", 1 ); } - foreach ( $wgMemCachedServers as $server ) { - $this->output( $server . " ", $server ); + # find out the longest server string to nicely align output later on + $maxSrvLen = $servers ? max( array_map( 'strlen', $servers ) ) : 0; + + foreach ( $servers as $server ) { + $this->output( + str_pad( $server, $maxSrvLen ), + $server # output channel + ); + $mcc = new MemCachedClientforWiki( array( 'persistant' => true, 'timeout' => $wgMemCachedTimeout @@ -59,7 +80,7 @@ class mcTest extends Maintenance { $get = 0; $time_start = $this->microtime_float(); for ( $i = 1; $i <= $iterations; $i++ ) { - if ( !is_null( $mcc->set( "test$i", $i ) ) ) { + if ( $mcc->set( "test$i", $i ) ) { $set++; } } @@ -76,7 +97,7 @@ class mcTest extends Maintenance { } $exectime = $this->microtime_float() - $time_start; - $this->output( "set: $set incr: $incr get: $get time: $exectime", $server ); + $this->output( " set: $set incr: $incr get: $get time: $exectime", $server ); } } @@ -91,4 +112,4 @@ class mcTest extends Maintenance { } $maintClass = "mcTest"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/mergeMessageFileList.php b/maintenance/mergeMessageFileList.php index cea64333..e9183377 100644 --- a/maintenance/mergeMessageFileList.php +++ b/maintenance/mergeMessageFileList.php @@ -25,7 +25,7 @@ # Start from scratch define( 'MW_NO_EXTENSION_MESSAGES', 1 ); -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; $maintClass = 'MergeMessageFileList'; $mmfl = false; @@ -36,10 +36,14 @@ $mmfl = false; * @ingroup Maintenance */ class MergeMessageFileList extends Maintenance { + /** + * @var bool + */ + protected $hasError; function __construct() { parent::__construct(); - $this->addOption( 'list-file', 'A file containing a list of extension setup files, one per line.', true, 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 ' . @@ -47,21 +51,29 @@ class MergeMessageFileList extends Maintenance { } public function execute() { - global $mmfl; + global $mmfl, $wgExtensionEntryPointListFiles; + + if ( !count( $wgExtensionEntryPointListFiles ) + && !$this->hasOption( 'list-file' ) + && !$this->hasOption( 'extensions-dir' ) + ) { + $this->error( "Either --list-file or --extensions-dir must be provided if " . + "\$wgExtensionEntryPointListFiles is not set", 1 ); + } + + $mmfl = array( 'setupFiles' => array() ); # Add setup files contained in file passed to --list-file - $lines = file( $this->getOption( 'list-file' ) ); - if ( $lines === false ) { - $this->error( 'Unable to open list file.' ); + if ( $this->hasOption( 'list-file' ) ) { + $extensionPaths = $this->readFile( $this->getOption( 'list-file' ) ); + $mmfl['setupFiles'] = array_merge( $mmfl['setupFiles'], $extensionPaths ); } - $mmfl = array( 'setupFiles' => array_map( 'trim', $lines ) ); # Now find out files in a directory - $hasError = false; if ( $this->hasOption( 'extensions-dir' ) ) { $extdir = $this->getOption( 'extensions-dir' ); $entries = scandir( $extdir ); - foreach( $entries as $extname ) { + foreach ( $entries as $extname ) { if ( $extname == '.' || $extname == '..' || !is_dir( "$extdir/$extname" ) ) { continue; } @@ -69,31 +81,77 @@ class MergeMessageFileList extends Maintenance { if ( file_exists( $extfile ) ) { $mmfl['setupFiles'][] = $extfile; } else { - $hasError = true; + $this->hasError = true; $this->error( "Extension {$extname} in {$extdir} lacks expected {$extname}.php" ); } } } - if ( $hasError ) { + # Add setup files defined via configuration + foreach ( $wgExtensionEntryPointListFiles as $points ) { + $extensionPaths = $this->readFile( $points ); + $mmfl['setupFiles'] = array_merge( $mmfl['setupFiles'], $extensionPaths ); + } + + if ( $this->hasError ) { $this->error( "Some files are missing (see above). Giving up.", 1 ); } if ( $this->hasOption( 'output' ) ) { $mmfl['output'] = $this->getOption( 'output' ); } + if ( $this->hasOption( 'quiet' ) ) { + $mmfl['quiet'] = true; + } + } + + /** + * @param string $fileName + * @return array List of absolute extension paths + */ + private function readFile( $fileName ) { + global $IP; + + $files = array(); + $fileLines = file( $fileName ); + 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 + # whitespace. Comments start with '#' and extend to the end of the line. + foreach ( $fileLines as $extension ) { + $extension = trim( preg_replace( '/#.*/', '', $extension ) ); + if ( $extension !== '' ) { + # Paths may use the string $IP to be substituted by the actual value + $extension = str_replace( '$IP', $IP, $extension ); + if ( file_exists( $extension ) ) { + $files[] = $extension; + } else { + $this->hasError = true; + $this->error( "Extension {$extension} doesn't exist" ); + } + } + } + return $files; } } -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; foreach ( $mmfl['setupFiles'] as $fileName ) { if ( strval( $fileName ) === '' ) { continue; } - $fileName = str_replace( '$IP', $IP, $fileName ); - fwrite( STDERR, "Loading data from $fileName\n" ); - include_once( $fileName ); + if ( empty( $mmfl['quiet'] ) ) { + fwrite( STDERR, "Loading data from $fileName\n" ); + } + // Include the extension to update $wgExtensionMessagesFiles + if ( !( include_once( $fileName ) ) ) { + fwrite( STDERR, "Unable to read $fileName\n" ); + exit( 1 ); + } } fwrite( STDERR, "\n" ); $s = @@ -109,10 +167,7 @@ $dirs = array( ); foreach ( $dirs as $dir ) { - $s = preg_replace( - "/'" . preg_quote( $dir, '/' ) . "([^']*)'/", - '"$IP\1"', - $s ); + $s = preg_replace( "/'" . preg_quote( $dir, '/' ) . "([^']*)'/", '"$IP\1"', $s ); } if ( isset( $mmfl['output'] ) ) { @@ -120,4 +175,3 @@ if ( isset( $mmfl['output'] ) ) { } else { echo $s; } - diff --git a/maintenance/migrateUserGroup.php b/maintenance/migrateUserGroup.php index 496af723..6903365b 100644 --- a/maintenance/migrateUserGroup.php +++ b/maintenance/migrateUserGroup.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that re-assigns users from an old group to a new one. @@ -55,7 +55,9 @@ class MigrateUserGroup extends Maintenance { $blockEnd = $start + $this->mBatchSize - 1; // Migrate users over in batches... while ( $blockEnd <= $end ) { + $affected = 0; $this->output( "Doing users $blockStart to $blockEnd\n" ); + $dbw->begin( __METHOD__ ); $dbw->update( 'user_groups', array( 'ug_group' => $newGroup ), @@ -64,21 +66,44 @@ class MigrateUserGroup extends Maintenance { __METHOD__, array( 'IGNORE' ) ); - $count += $dbw->affectedRows(); + $affected += $dbw->affectedRows(); + // Delete rows that the UPDATE operation above had to ignore. + // This happens when a user is in both the old and new group. + // Updating the row for the old group membership failed since + // user/group is UNIQUE. $dbw->delete( 'user_groups', array( 'ug_group' => $oldGroup, "ug_user BETWEEN $blockStart AND $blockEnd" ), __METHOD__ ); - $count += $dbw->affectedRows(); + $affected += $dbw->affectedRows(); $dbw->commit( __METHOD__ ); + + // Clear cache for the affected users (bug 40340) + if ( $affected > 0 ) { + // XXX: This also invalidates cache of unaffected users that + // were in the new group and not in the group. + $res = $dbw->select( 'user_groups', 'ug_user', + array( 'ug_group' => $newGroup, + "ug_user BETWEEN $blockStart AND $blockEnd" ), + __METHOD__ + ); + if ( $res !== false ) { + foreach ( $res as $row ) { + $user = User::newFromId( $row->ug_user ); + $user->invalidateCache(); + } + } + } + + $count += $affected; $blockStart += $this->mBatchSize; $blockEnd += $this->mBatchSize; wfWaitForSlaves(); } - $this->output( "Done! $count user(s) in group '$oldGroup' are now in '$newGroup' instead.\n" ); + $this->output( "Done! $count users in group '$oldGroup' are now in '$newGroup' instead.\n" ); } } $maintClass = "MigrateUserGroup"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/minify.php b/maintenance/minify.php index 9f5a909d..ec936c83 100644 --- a/maintenance/minify.php +++ b/maintenance/minify.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that minifies a file or set of files. @@ -29,7 +29,7 @@ require_once( __DIR__ . '/Maintenance.php' ); * @ingroup Maintenance */ class MinifyScript extends Maintenance { - var $outDir; + public $outDir; public function __construct() { parent::__construct(); @@ -144,4 +144,4 @@ class MinifyScript extends Maintenance { } $maintClass = 'MinifyScript'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/moveBatch.php b/maintenance/moveBatch.php index 7d15959c..34e64282 100644 --- a/maintenance/moveBatch.php +++ b/maintenance/moveBatch.php @@ -34,7 +34,7 @@ * e.g. immobile_namespace for namespaces which can't be moved */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to move a batch of pages. @@ -116,4 +116,4 @@ class MoveBatch extends Maintenance { } $maintClass = "MoveBatch"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/mssql/tables.sql b/maintenance/mssql/tables.sql index a0c3d17b..7356c38f 100644 --- a/maintenance/mssql/tables.sql +++ b/maintenance/mssql/tables.sql @@ -76,10 +76,10 @@ CREATE TABLE /*$wgDBprefix*/user_newtalk ( CREATE INDEX /*$wgDBprefix*/user_group_id ON /*$wgDBprefix*/user_newtalk([user_id]); CREATE INDEX /*$wgDBprefix*/user_ip ON /*$wgDBprefix*/user_newtalk(user_ip); --- +-- -- User preferences and other fun stuff -- replaces old user.user_options BLOB --- +-- CREATE TABLE /*$wgDBprefix*/user_properties ( up_user INT NOT NULL, up_property NVARCHAR(32) NOT NULL, @@ -157,8 +157,9 @@ CREATE TABLE /*$wgDBprefix*/text ( -- The fields generally correspond to the page, revision, and text -- fields, with several caveats. -- Cannot reasonably create views on this table, due to the presence of TEXT --- columns. +-- columns. CREATE TABLE /*$wgDBprefix*/archive ( + ar_id NOT NULL PRIMARY KEY clustered IDENTITY, ar_namespace SMALLINT NOT NULL DEFAULT 0, ar_title NVARCHAR(255) NOT NULL DEFAULT '', ar_text NVARCHAR(MAX) NOT NULL, @@ -234,7 +235,7 @@ CREATE INDEX /*$wgDBprefix*/cl_sortkey ON /*$wgDBprefix*/categorylinks(cl_to,c CREATE INDEX /*$wgDBprefix*/cl_timestamp ON /*$wgDBprefix*/categorylinks(cl_to,cl_timestamp); --; --- +-- -- 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. @@ -279,16 +280,16 @@ CREATE TABLE /*$wgDBprefix*/valid_tag ( vt_tag varchar(255) NOT NULL PRIMARY KEY ); --- +-- -- Table for storing localisation data --- +-- CREATE TABLE /*$wgDBprefix*/l10n_cache ( -- language code lc_lang NVARCHAR(32) NOT NULL, - + -- cache key lc_key NVARCHAR(255) NOT NULL, - + -- Value lc_value TEXT NOT NULL DEFAULT '', ); @@ -298,6 +299,7 @@ CREATE INDEX /*$wgDBprefix*/lc_lang_key ON /*$wgDBprefix*/l10n_cache (lc_lang, l -- 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, @@ -305,17 +307,6 @@ CREATE TABLE /*$wgDBprefix*/externallinks ( -- Maximum key length ON SQL Server is 900 bytes CREATE INDEX /*$wgDBprefix*/externallinks_index ON /*$wgDBprefix*/externallinks(el_index); --- --- Track external user accounts, if ExternalAuth is used --- -CREATE TABLE /*$wgDBprefix*/external_user ( - -- Foreign key to user_id - eu_local_id INT NOT NULL PRIMARY KEY, - -- opaque identifier provided by the external database - eu_external_id NVARCHAR(255) NOT NULL, -); -CREATE UNIQUE INDEX /*$wgDBprefix*/eu_external_idx ON /*$wgDBprefix*/external_user(eu_external_id); - -- -- Track INTerlanguage links -- @@ -327,16 +318,16 @@ CREATE TABLE /*$wgDBprefix*/langlinks ( ); 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, - + -- 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 '', ); @@ -516,8 +507,6 @@ CREATE TABLE /*$wgDBprefix*/recentchanges ( rc_this_oldid INT DEFAULT 0, rc_last_oldid INT DEFAULT 0, rc_type tinyint DEFAULT 0, - rc_moved_to_ns BIT DEFAULT 0, - rc_moved_to_title NVARCHAR(255) DEFAULT '', rc_patrolled BIT DEFAULT 0, rc_ip NCHAR(40) DEFAULT '', rc_old_len INT DEFAULT 0, @@ -728,7 +717,7 @@ CREATE TABLE /*$wgDBprefix*/updatelog ( PRIMARY KEY (ul_key) ); --- NOTE To enable full text indexing on SQL 2008 you need to create an account FDH$MSSQLSERVER +-- 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. diff --git a/maintenance/mwdoc-filter.php b/maintenance/mwdoc-filter.php index 6eeb48d3..c80981b5 100644 --- a/maintenance/mwdoc-filter.php +++ b/maintenance/mwdoc-filter.php @@ -18,6 +18,6 @@ if ( PHP_SAPI != 'cli' ) { $source = file_get_contents( $argv[1] ); $regexp = '#\@var\s+([^\s]+)([^/]+)/\s+(var|public|protected|private)\s+(\$[^\s;=]+)#'; $replac = '${2} */ ${3} ${1} ${4}'; -$source = preg_replace($regexp, $replac, $source); +$source = preg_replace( $regexp, $replac, $source ); echo $source; diff --git a/maintenance/mwdocgen.php b/maintenance/mwdocgen.php index 37e626ba..b22dd885 100644 --- a/maintenance/mwdocgen.php +++ b/maintenance/mwdocgen.php @@ -8,12 +8,6 @@ * Usage: * php mwdocgen.php * - * KNOWN BUGS: - * - * - pass_thru seems to always use buffering (even with ob_implicit_flush()), - * that make output slow when doxygen parses language files. - * - the menu doesnt work, got disabled at revision 13740. Need to code it. - * * 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 @@ -39,235 +33,135 @@ * @version first release */ -# -# Variables / Configuration -# - -if ( php_sapi_name() != 'cli' ) { - echo 'Run "' . __FILE__ . '" from the command line.'; - die( -1 ); -} - -/** Figure out the base directory for MediaWiki location */ -$mwPath = dirname( __DIR__ ) . DIRECTORY_SEPARATOR; - -/** doxygen binary script */ -$doxygenBin = 'doxygen'; - -/** doxygen configuration template for mediawiki */ -$doxygenTemplate = $mwPath . 'maintenance/Doxyfile'; - -/** doxygen input filter to tweak source file before they are parsed */ -$doxygenInputFilter = "php {$mwPath}maintenance/mwdoc-filter.php"; - -/** where Phpdoc should output documentation */ -$doxyOutput = $mwPath . 'docs' . DIRECTORY_SEPARATOR ; - -$doxyVersion = 'master'; - -/** MediaWiki subpaths */ -$mwPathI = $mwPath . 'includes/'; -$mwPathL = $mwPath . 'languages/'; -$mwPathM = $mwPath . 'maintenance/'; -$mwPathS = $mwPath . 'skins/'; - -/** Ignored paths relative to $mwPath */ -$mwExcludePaths = array( - 'images', - 'static', -); - -/** Variable to get user input */ -$input = ''; -$excludePatterns = ''; -/** Whether to generates man pages: */ -$doxyGenerateMan = false; - -# -# Functions -# - -define( 'MEDIAWIKI', true ); -require_once( "$mwPath/includes/GlobalFunctions.php" ); +require_once __DIR__ . '/Maintenance.php'; /** - * Read a line from the shell - * @param $prompt String - * @return string - */ -function readaline( $prompt = '' ) { - print $prompt; - $fp = fopen( "php://stdin", "r" ); - $resp = trim( fgets( $fp, 1024 ) ); - fclose( $fp ); - return $resp; -} - -/** - * Generate a configuration file given user parameters and return the temporary filename. - * @param $doxygenTemplate String: full path for the template. - * @param $outputDirectory String: directory where the stuff will be output. - * @param $stripFromPath String: path that should be stripped out (usually mediawiki base path). - * @param $currentVersion String: Version number of the software - * @param $input String: Path to analyze. - * @param $exclude String: Additionals path regex to exclude - * @param $excludePatterns String: Additionals path regex to exclude - * (LocalSettings.php, AdminSettings.php, .svn and .git directories are always excluded) - * @param $doxyGenerateMan Boolean - * @return string + * Maintenance script that builds doxygen documentation. + * @ingroup Maintenance */ -function generateConfigFile( $doxygenTemplate, $outputDirectory, $stripFromPath, $currentVersion, $input, $exclude, $excludePatterns, $doxyGenerateMan ) { - global $doxygenInputFilter; - - $template = file_get_contents( $doxygenTemplate ); - // Replace template placeholders by correct values. - $replacements = array( - '{{OUTPUT_DIRECTORY}}' => $outputDirectory, - '{{STRIP_FROM_PATH}}' => $stripFromPath, - '{{CURRENT_VERSION}}' => $currentVersion, - '{{INPUT}}' => $input, - '{{EXCLUDE}}' => $exclude, - '{{EXCLUDE_PATTERNS}}' => $excludePatterns, - '{{HAVE_DOT}}' => `which dot` ? 'YES' : 'NO', - '{{GENERATE_MAN}}' => $doxyGenerateMan ? 'YES' : 'NO', - '{{INPUT_FILTER}}' => $doxygenInputFilter, - ); - $tmpCfg = str_replace( array_keys( $replacements ), array_values( $replacements ), $template ); - $tmpFileName = tempnam( wfTempDir(), 'mwdocgen-' ); - file_put_contents( $tmpFileName , $tmpCfg ) or die( "Could not write doxygen configuration to file $tmpFileName\n" ); +class MWDocGen extends Maintenance { + + /** + * Prepare Maintenance class + */ + public function __construct() { + parent::__construct(); + $this->mDescription = 'Build doxygen documentation'; + + $this->addOption( 'doxygen', + 'Path to doxygen', + false, true ); + $this->addOption( 'version', + 'Pass a MediaWiki version', + false, true ); + $this->addOption( 'generate-man', + 'Whether to generate man files' ); + $this->addOption( 'file', + "Only process given file or directory. Multiple values " . + "accepted with comma separation. Path relative to \$IP.", + false, true ); + $this->addOption( 'output', + 'Path to write doc to', + false, true ); + $this->addOption( 'no-extensions', + 'Ignore extensions' ); + } - return $tmpFileName; -} + public function getDbType() { + return Maintenance::DB_NONE; + } -# -# Main ! -# + protected function init() { + global $IP; -unset( $file ); + $this->doxygen = $this->getOption( 'doxygen', 'doxygen' ); + $this->mwVersion = $this->getOption( 'version', 'master' ); -if ( is_array( $argv ) ) { - for ($i = 0; $i < count($argv); $i++ ) { - switch( $argv[$i] ) { - case '--all': $input = 0; break; - case '--includes': $input = 1; break; - case '--languages': $input = 2; break; - case '--maintenance': $input = 3; break; - case '--skins': $input = 4; break; - case '--file': - $input = 5; - $i++; - if ( isset( $argv[$i] ) ) { - $file = $argv[$i]; - } - break; - case '--no-extensions': $input = 6; break; - case '--output': - $i++; - if ( isset( $argv[$i] ) ) { - $doxyOutput = realpath( $argv[$i] ); - } - break; - case '--version': - $i++; - if ( isset( $argv[$i] ) ) { - $doxyVersion = $argv[$i]; - } - break; - case '--generate-man': - $doxyGenerateMan = true; - break; - case '--help': - print <<<END -Usage: php mwdocgen.php [<command>] [<options>] + $this->input = ''; + $inputs = explode( ',', $this->getOption( 'file', '' ) ); + foreach ( $inputs as $input ) { + # Doxygen inputs are space separted and double quoted + $this->input .= " \"$IP/$input\""; + } -Commands: - --all Process entire codebase - --includes Process only files in includes/ dir - --languages Process only files in languages/ dir - --maintenance Process only files in maintenance/ dir - --skins Process only files in skins/ dir - --file <file> Process only the given file - --no-extensions Process everything but extensions directorys + $this->output = $this->getOption( 'output', "$IP/docs" ); + + $this->inputFilter = wfShellWikiCmd( + $IP . '/maintenance/mwdoc-filter.php' ); + $this->template = $IP . '/maintenance/Doxyfile'; + $this->excludes = array( + 'vendor', + 'images', + 'static', + ); + $this->excludePatterns = array(); + if ( $this->hasOption( 'no-extensions' ) ) { + $this->excludePatterns[] = 'extensions'; + } -If no command is given, you will be prompted. + $this->doDot = `which dot`; + $this->doMan = $this->hasOption( 'generate-man' ); + } -Other options: - --output <dir> Set output directory (default: $doxyOutput) - --generate-man Generates man page documentation - --version Project version to display in the outut (default: $doxyVersion) - --help Show this help and exit. + public function execute() { + global $IP; + $this->init(); -END; - exit(0); - break; + # Build out directories we want to exclude + $exclude = ''; + foreach ( $this->excludes as $item ) { + $exclude .= " $IP/$item"; } - } -} - -// TODO : generate a list of paths )) -if ( $input === '' ) { - echo <<<OPTIONS -Several documentation possibilities: - 0 : whole documentation (1 + 2 + 3 + 4) - 1 : only includes - 2 : only languages - 3 : only maintenance - 4 : only skins - 5 : only a given file - 6 : all but the extensions directory -OPTIONS; - while ( !is_numeric( $input ) ) - { - $input = readaline( "\nEnter your choice [0]:" ); - if ( $input == '' ) { - $input = 0; + $excludePatterns = implode( ' ', $this->excludePatterns ); + + $conf = strtr( file_get_contents( $this->template ), + array( + '{{OUTPUT_DIRECTORY}}' => $this->output, + '{{STRIP_FROM_PATH}}' => $IP, + '{{CURRENT_VERSION}}' => $this->mwVersion, + '{{INPUT}}' => $this->input, + '{{EXCLUDE}}' => $exclude, + '{{EXCLUDE_PATTERNS}}' => $excludePatterns, + '{{HAVE_DOT}}' => $this->doDot ? 'YES' : 'NO', + '{{GENERATE_MAN}}' => $this->doMan ? 'YES' : 'NO', + '{{INPUT_FILTER}}' => $this->inputFilter, + ) + ); + + $tmpFile = tempnam( wfTempDir(), 'MWDocGen-' ); + if ( file_put_contents( $tmpFile, $conf ) === false ) { + $this->error( "Could not write doxygen configuration to file $tmpFile\n", + /** exit code: */ 1 ); } - } -} -switch ( $input ) { -case 0: $input = $mwPath; break; -case 1: $input = $mwPathI; break; -case 2: $input = $mwPathL; break; -case 3: $input = $mwPathM; break; -case 4: $input = $mwPathS; break; -case 5: - if ( !isset( $file ) ) { - $file = readaline( "Enter file name $mwPath" ); - } - $input = $mwPath . $file; - break; -case 6: - $input = $mwPath; - $excludePatterns = 'extensions'; -} + $command = $this->doxygen . ' ' . $tmpFile; + $this->output( "Executing command:\n$command\n" ); -// Generate path exclusions -$excludedPaths = $mwPath . join( " $mwPath", $mwExcludePaths ); -print "EXCLUDE: $excludedPaths\n\n"; + $exitcode = 1; + system( $command, $exitcode ); -$generatedConf = generateConfigFile( $doxygenTemplate, $doxyOutput, $mwPath, $doxyVersion, $input, $excludedPaths, $excludePatterns, $doxyGenerateMan ); -$command = $doxygenBin . ' ' . $generatedConf; - -echo <<<TEXT + $this->output( <<<TEXT --------------------------------------------------- -Launching the command: - -$command +Doxygen execution finished. +Check above for possible errors. +You might want to delete the temporary file: + $tmpFile --------------------------------------------------- -TEXT; +TEXT + ); -passthru( $command ); + if ( $exitcode !== 0 ) { + $this->error( "Something went wrong (exit: $exitcode)\n", + $exitcode ); + } -echo <<<TEXT ---------------------------------------------------- -Doxygen execution finished. -Check above for possible errors. + } -You might want to delete the temporary file $generatedConf +} -TEXT; +$maintClass = 'MWDocGen'; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/mwjsduck-gen b/maintenance/mwjsduck-gen new file mode 100644 index 00000000..bc10bc2c --- /dev/null +++ b/maintenance/mwjsduck-gen @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +JSDUCK_MWVERSION=master +if [[ "$1" == "--version" && "$2" != "" ]] +then + JSDUCK_MWVERSION="$2" +elif [[ "$*" != "" ]] +then + echo "Usage $0: [--version <mediawiki version>]" + echo + exit 1 +fi + +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.' + +ln -s ../../resources $MWCORE_DIR/docs/js/modules diff --git a/maintenance/namespaceDupes.php b/maintenance/namespaceDupes.php index 4197a355..ff024682 100644 --- a/maintenance/namespaceDupes.php +++ b/maintenance/namespaceDupes.php @@ -24,7 +24,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that checks for articles to fix after @@ -147,14 +147,13 @@ class NamespaceConflictChecker extends Maintenance { /** * Get the interwiki list * - * @todo Needs to respect interwiki cache! * @return Array */ private function getInterwikiList() { - $result = $this->db->select( 'interwiki', array( 'iw_prefix' ) ); + $result = Interwiki::getAllPrefixes(); $prefixes = array(); foreach ( $result as $row ) { - $prefixes[] = $row->iw_prefix; + $prefixes[] = $row['iw_prefix']; } return $prefixes; } @@ -186,7 +185,7 @@ class NamespaceConflictChecker extends Maintenance { } /** - * @todo: do this for reals + * @todo Do this for real * @param $key * @param $prefix * @param $fix @@ -208,10 +207,10 @@ class NamespaceConflictChecker extends Maintenance { * @return array */ private function getConflicts( $ns, $name ) { - $page = 'page'; + $page = 'page'; $table = $this->db->tableName( $page ); - $prefix = $this->db->strencode( $name ); + $prefix = $this->db->strencode( $name ); $encNamespace = $this->db->addQuotes( $ns ); $titleSql = "TRIM(LEADING '$prefix:' FROM {$page}_title)"; @@ -319,12 +318,12 @@ class NamespaceConflictChecker extends Maintenance { $this->db->update( $table, array( "{$prefix}_namespace" => $newTitle->getNamespace(), - "{$prefix}_title" => $newTitle->getDBkey(), + "{$prefix}_title" => $newTitle->getDBkey(), ), array( // "{$prefix}_namespace" => 0, - // "{$prefix}_title" => $row->oldtitle, - "{$prefix}_id" => $row->id, + // "{$prefix}_title" => $row->oldtitle, + "{$prefix}_id" => $row->id, ), __METHOD__ ); $this->output( "ok.\n" ); @@ -333,4 +332,4 @@ class NamespaceConflictChecker extends Maintenance { } $maintClass = "NamespaceConflictChecker"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/nextJobDB.php b/maintenance/nextJobDB.php index e66e981b..219b5d8e 100644 --- a/maintenance/nextJobDB.php +++ b/maintenance/nextJobDB.php @@ -18,11 +18,10 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @todo Make this work on PostgreSQL and maybe other database servers * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that picks a database that has pending jobs. @@ -33,129 +32,88 @@ class nextJobDB extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Pick a database that has pending jobs"; - $this->addOption( 'type', "The type of job to search for", false, true ); + $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 $wgMemc; - $type = $this->getOption( 'type', false ); + global $wgJobTypesExcludedFromDefaultQueue; - $memcKey = 'jobqueue:dbs:v2'; - $pendingDBs = $wgMemc->get( $memcKey ); - - // If the cache entry wasn't present, or in 1% of cases otherwise, - // regenerate the cache. - if ( !$pendingDBs || mt_rand( 0, 100 ) == 0 ) { - $pendingDBs = $this->getPendingDbs(); - $wgMemc->set( $memcKey, $pendingDBs, 300 ); + // 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; } - if ( !$pendingDBs ) { - return; + // 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; - if ( $type === false ) { - $candidates = call_user_func_array( 'array_merge', $pendingDBs ); - } elseif ( isset( $pendingDBs[$type] ) ) { - $candidates = $pendingDBs[$type]; - } else { - $candidates = array(); - } - if ( !$candidates ) { - return; - } - - $candidates = array_values( $candidates ); - $db = $candidates[ mt_rand( 0, count( $candidates ) - 1 ) ]; - if ( !$this->checkJob( $type, $db ) ) { - // This job is not available in the current database. Remove it from - // the cache. - if ( $type === false ) { - foreach ( $pendingDBs as $type2 => $dbs ) { - $pendingDBs[$type2] = array_diff( $pendingDBs[$type2], array( $db ) ); + $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 ); } - } else { - $pendingDBs[$type] = array_diff( $pendingDBs[$type], array( $db ) ); } + } + if ( !count( $candidates ) ) { + return; // no jobs for this type + } - $wgMemc->set( $memcKey, $pendingDBs, 300 ); + 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 ); - $this->output( $db . "\n" ); - } - - /** - * Check if the specified database has a job of the specified type in it. - * The type may be false to indicate "all". - * @param $type string - * @param $dbName string - * @return bool - */ - function checkJob( $type, $dbName ) { - $lb = wfGetLB( $dbName ); - $db = $lb->getConnection( DB_MASTER, array(), $dbName ); - if ( $type === false ) { - $conds = Job::defaultQueueConditions( ); + if ( $this->hasOption( 'types' ) ) { + $this->output( $db . " " . $type . "\n" ); } else { - $conds = array( 'job_cmd' => $type ); + $this->output( $db . "\n" ); } - - - $exists = (bool) $db->selectField( 'job', '1', $conds, __METHOD__ ); - $lb->reuseConnection( $db ); - return $exists; } /** - * Get all databases that have a pending job - * @return array + * Do all ready periodic jobs for all databases every 5 minutes (and .1% of the time) + * @return integer */ - private function getPendingDbs() { - global $wgLocalDatabases; - $pendingDBs = array(); - # Cross-reference DBs by master DB server - $dbsByMaster = array(); - foreach ( $wgLocalDatabases as $db ) { - $lb = wfGetLB( $db ); - $dbsByMaster[$lb->getServerName( 0 )][] = $db; - } - - foreach ( $dbsByMaster as $dbs ) { - $dbConn = wfGetDB( DB_MASTER, array(), $dbs[0] ); - - # Padding row for MySQL bug - $pad = str_repeat( '-', 40 ); - $sql = "(SELECT '$pad' as db, '$pad' as job_cmd)"; - foreach ( $dbs as $wikiId ) { - if ( $sql != '' ) { - $sql .= ' UNION '; + 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(); } - - list( $dbName, $tablePrefix ) = wfSplitWikiID( $wikiId ); - $dbConn->tablePrefix( $tablePrefix ); - $jobTable = $dbConn->tableName( 'job' ); - - $sql .= "(SELECT DISTINCT '$wikiId' as db, job_cmd FROM $dbName.$jobTable GROUP BY job_cmd)"; - } - $res = $dbConn->query( $sql, __METHOD__ ); - $first = true; - foreach ( $res as $row ) { - if ( $first ) { - // discard padding row - $first = false; - continue; - } - $pendingDBs[$row->job_cmd][] = $row->db; + $wgMemc->set( $memcKey, time() ); + $wgMemc->delete( "$memcKey:rebuild" ); // unlock } } - return $pendingDBs; + + return $count; } } $maintClass = "nextJobDb"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/nukeNS.php b/maintenance/nukeNS.php index c471a441..479dcf76 100644 --- a/maintenance/nukeNS.php +++ b/maintenance/nukeNS.php @@ -33,7 +33,7 @@ * based on nukePage by Rob Church */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that removes pages with only one revision from the @@ -66,7 +66,7 @@ class NukeNS extends Maintenance { foreach ( $res as $row ) { // echo "$ns_name:".$row->page_title, "\n"; $title = Title::makeTitle( $ns, $row->page_title ); - $id = $title->getArticleID(); + $id = $title->getArticleID(); // Get corresponding revisions $res2 = $dbw->query( "SELECT rev_id FROM $tbl_rev WHERE rev_page = $id" ); @@ -94,7 +94,7 @@ class NukeNS extends Maintenance { $n_deleted ++; } } else { - $this->output( "skip: " . $title->getPrefixedText() . "\n" ); + $this->output( "skip: " . $title->getPrefixedText() . "\n" ); } } $dbw->commit( __METHOD__ ); @@ -119,4 +119,4 @@ class NukeNS extends Maintenance { } $maintClass = "NukeNS"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/nukePage.php b/maintenance/nukePage.php index 89dffe0c..1870273e 100644 --- a/maintenance/nukePage.php +++ b/maintenance/nukePage.php @@ -23,7 +23,7 @@ * @author Rob Church <robchur@gmail.com> */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that erases a page record from the database. @@ -54,7 +54,7 @@ class NukePage extends Maintenance { $this->output( "Searching for \"$name\"..." ); $title = Title::newFromText( $name ); if ( $title ) { - $id = $title->getArticleID(); + $id = $title->getArticleID(); $real = $title->getPrefixedText(); $isGoodArticle = $title->isContentPage(); $this->output( "found \"$real\" with ID $id.\n" ); @@ -117,4 +117,4 @@ class NukePage extends Maintenance { } $maintClass = "NukePage"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/oracle/alterSharedConstraints.php b/maintenance/oracle/alterSharedConstraints.php index e222314d..435625d5 100644 --- a/maintenance/oracle/alterSharedConstraints.php +++ b/maintenance/oracle/alterSharedConstraints.php @@ -15,18 +15,19 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance */ /** * When using shared tables that are referenced by foreign keys on local * tables you have to change the constraints on local tables. - * + * * The shared tables have to have GRANT REFERENCE on shared tables to local schema * i.e.: GRANT REFERENCES (user_id) ON mwuser TO hubclient; */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; class AlterSharedConstraints extends Maintenance { public function __construct() { @@ -40,45 +41,45 @@ class AlterSharedConstraints extends Maintenance { public function execute() { global $wgSharedDB, $wgSharedTables, $wgSharedPrefix, $wgDBprefix; - + if ( $wgSharedDB == null ) { $this->output( "Database sharing is not enabled\n" ); return; } - + $dbw = wfGetDB( DB_MASTER ); foreach ( $wgSharedTables as $table ) { - $stable = $dbw->tableNameInternal($table); + $stable = $dbw->tableNameInternal( $table ); if ( $wgSharedPrefix != null ) { $ltable = preg_replace( "/^$wgSharedPrefix(.*)/i", "$wgDBprefix\\1", $stable ); } else { - $ltable = "{$wgDBprefix}{$stable}" ; + $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'" ); - while (($row = $result->fetchRow()) !== false) { - - $this->output( "Altering {$row['constraint_name']} ..."); - + while ( ( $row = $result->fetchRow() ) !== false ) { + + $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) { + } 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']} - FOREIGN KEY ({$row['column_name']}) - REFERENCES {$wgSharedDB}.$stable({$row['pk_column_name']}) + $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" ); } } @@ -87,4 +88,4 @@ class AlterSharedConstraints extends Maintenance { } $maintClass = "AlterSharedConstraints"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/oracle/archives/patch-archive-ar_content_format.sql b/maintenance/oracle/archives/patch-archive-ar_content_format.sql new file mode 100644 index 00000000..0c0c0d94 --- /dev/null +++ b/maintenance/oracle/archives/patch-archive-ar_content_format.sql @@ -0,0 +1,3 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.archive ADD ar_content_format VARCHAR2(64); diff --git a/maintenance/oracle/archives/patch-archive-ar_content_model.sql b/maintenance/oracle/archives/patch-archive-ar_content_model.sql new file mode 100644 index 00000000..d18fc9e4 --- /dev/null +++ b/maintenance/oracle/archives/patch-archive-ar_content_model.sql @@ -0,0 +1,3 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.archive ADD ar_content_model VARCHAR2(32); diff --git a/maintenance/oracle/archives/patch-archive-ar_id.sql b/maintenance/oracle/archives/patch-archive-ar_id.sql new file mode 100644 index 00000000..a43f7602 --- /dev/null +++ b/maintenance/oracle/archives/patch-archive-ar_id.sql @@ -0,0 +1,6 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.archive ADD ( +ar_id NUMBER NOT NULL, +); +ALTER TABLE &mw_prefix.archive ADD CONSTRAINT &mw_prefix.archive_pk PRIMARY KEY (ar_id); diff --git a/maintenance/oracle/archives/patch-cat_hidden.sql b/maintenance/oracle/archives/patch-cat_hidden.sql new file mode 100644 index 00000000..d1649c7c --- /dev/null +++ b/maintenance/oracle/archives/patch-cat_hidden.sql @@ -0,0 +1,4 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.category DROP COLUMN cat_hidden; + diff --git a/maintenance/oracle/archives/patch-externallinks-el_id.sql b/maintenance/oracle/archives/patch-externallinks-el_id.sql new file mode 100644 index 00000000..a8c443f4 --- /dev/null +++ b/maintenance/oracle/archives/patch-externallinks-el_id.sql @@ -0,0 +1,4 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.externallinks ADD el_id NUMBER NOT NULL; +ALTER TABLE &mw_prefix.externallinks ADD CONSTRAINT &mw_prefix.externallinks_pk PRIMARY KEY (el_id);
\ No newline at end of file diff --git a/maintenance/oracle/archives/patch-fa_sha1.sql b/maintenance/oracle/archives/patch-fa_sha1.sql new file mode 100644 index 00000000..70c9e60c --- /dev/null +++ b/maintenance/oracle/archives/patch-fa_sha1.sql @@ -0,0 +1,5 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.filearchive ADD fa_sha1 VARCHAR2(32); +CREATE INDEX &mw_prefix.filearchive_i05 ON &mw_prefix.filearchive (fa_sha1); + diff --git a/maintenance/oracle/archives/patch-job_attempts.sql b/maintenance/oracle/archives/patch-job_attempts.sql new file mode 100644 index 00000000..b05c8779 --- /dev/null +++ b/maintenance/oracle/archives/patch-job_attempts.sql @@ -0,0 +1,4 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.job ADD job_attempts NUMBER DEFAULT 0 NOT NULL; +CREATE INDEX &mw_prefix.job_i05 ON &mw_prefix.job (job_attempts); diff --git a/maintenance/oracle/archives/patch-job_token.sql b/maintenance/oracle/archives/patch-job_token.sql new file mode 100644 index 00000000..1a730e95 --- /dev/null +++ b/maintenance/oracle/archives/patch-job_token.sql @@ -0,0 +1,12 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.job ADD ( + job_random NUMBER DEFAULT 0 NOT NULL, + job_token VARCHAR2(32), + job_token_timestamp TIMESTAMP(6) WITH TIME ZONE, + job_sha1 VARCHAR2(32) +); + +CREATE INDEX &mw_prefix.job_i03 ON &mw_prefix.job (job_sha1); +CREATE INDEX &mw_prefix.job_i04 ON &mw_prefix.job (job_cmd,job_token,job_random); + diff --git a/maintenance/oracle/archives/patch-page-page_content_model.sql b/maintenance/oracle/archives/patch-page-page_content_model.sql new file mode 100644 index 00000000..e5839d9a --- /dev/null +++ b/maintenance/oracle/archives/patch-page-page_content_model.sql @@ -0,0 +1,3 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.page ADD page_content_model VARCHAR2(32); diff --git a/maintenance/oracle/archives/patch-rc_moved.sql b/maintenance/oracle/archives/patch-rc_moved.sql new file mode 100644 index 00000000..2a71315d --- /dev/null +++ b/maintenance/oracle/archives/patch-rc_moved.sql @@ -0,0 +1,4 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.recentchanges DROP ( rc_moved_to_ns, rc_moved_to_title ); + diff --git a/maintenance/oracle/archives/patch-revision-rev_content_format.sql b/maintenance/oracle/archives/patch-revision-rev_content_format.sql new file mode 100644 index 00000000..ebde71c9 --- /dev/null +++ b/maintenance/oracle/archives/patch-revision-rev_content_format.sql @@ -0,0 +1,3 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.revision ADD rev_content_format VARCHAR2(64); diff --git a/maintenance/oracle/archives/patch-revision-rev_content_model.sql b/maintenance/oracle/archives/patch-revision-rev_content_model.sql new file mode 100644 index 00000000..dd226423 --- /dev/null +++ b/maintenance/oracle/archives/patch-revision-rev_content_model.sql @@ -0,0 +1,3 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.revision ADD rev_content_model VARCHAR2(32); diff --git a/maintenance/oracle/archives/patch-sites.sql b/maintenance/oracle/archives/patch-sites.sql new file mode 100644 index 00000000..868b210f --- /dev/null +++ b/maintenance/oracle/archives/patch-sites.sql @@ -0,0 +1,34 @@ +define mw_prefix='{$wgDBprefix}'; + +CREATE SEQUENCE sites_site_id_seq MINVALUE 0 START WITH 0; +CREATE TABLE &mw_prefix.sites ( + site_id NUMBER NOT NULL, + site_global_key VARCHAR2(32) NOT NULL, + site_type VARCHAR2(32) NOT NULL, + site_group VARCHAR2(32) NOT NULL, + site_source VARCHAR2(32) NOT NULL, + site_language VARCHAR2(32) NOT NULL, + site_protocol VARCHAR2(32) NOT NULL, + site_domain VARCHAR2(255) NOT NULL, + site_data BLOB NOT NULL, + site_forward NUMBER(1) NOT NULL, + site_config BLOB NOT NULL +); +ALTER TABLE &mw_prefix.sites ADD CONSTRAINT &mw_prefix.sites_pk PRIMARY KEY (site_id); +CREATE UNIQUE INDEX &mw_prefix.sites_u01 ON &mw_prefix.sites (site_global_key); +CREATE INDEX &mw_prefix.sites_i01 ON &mw_prefix.sites (site_type); +CREATE INDEX &mw_prefix.sites_i02 ON &mw_prefix.sites (site_group); +CREATE INDEX &mw_prefix.sites_i03 ON &mw_prefix.sites (site_source); +CREATE INDEX &mw_prefix.sites_i04 ON &mw_prefix.sites (site_language); +CREATE INDEX &mw_prefix.sites_i05 ON &mw_prefix.sites (site_protocol); +CREATE INDEX &mw_prefix.sites_i06 ON &mw_prefix.sites (site_domain); +CREATE INDEX &mw_prefix.sites_i07 ON &mw_prefix.sites (site_forward); + +CREATE TABLE &mw_prefix.site_identifiers ( + si_site NUMBER NOT NULL, + si_type VARCHAR2(32) NOT NULL, + si_key VARCHAR2(32) NOT NULL +); +CREATE UNIQUE INDEX &mw_prefix.site_identifiers_u01 ON &mw_prefix.site_identifiers (si_type, si_key); +CREATE INDEX &mw_prefix.site_identifiers_i01 ON &mw_prefix.site_identifiers (si_site); +CREATE INDEX &mw_prefix.site_identifiers_i02 ON &mw_prefix.site_identifiers (si_key); diff --git a/maintenance/oracle/archives/patch-ss_admins.sql b/maintenance/oracle/archives/patch-ss_admins.sql new file mode 100644 index 00000000..c2e9242e --- /dev/null +++ b/maintenance/oracle/archives/patch-ss_admins.sql @@ -0,0 +1,4 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.site_stats DROP COLUMN ss_admins; + diff --git a/maintenance/oracle/archives/patch-testrun.sql b/maintenance/oracle/archives/patch-testrun.sql index 6e3e1b7c..84facabc 100644 --- a/maintenance/oracle/archives/patch-testrun.sql +++ b/maintenance/oracle/archives/patch-testrun.sql @@ -25,7 +25,7 @@ BEFORE UPDATE FOR EACH ROW ON &mw_prefix.testrun BEGIN SELECT testrun_tr_id_seq.NEXTVAL into :NEW.tr_id FROM dual; -END; +END; CREATE TABLE /*$wgDBprefix*/testitem ( ti_run NUMBER NOT NULL REFERENCES &mw_prefix.testrun (tr_id) ON DELETE CASCADE, diff --git a/maintenance/oracle/archives/patch-ufg_group-length-increase.sql b/maintenance/oracle/archives/patch-ufg_group-length-increase-255.sql index a48b8bff..6a4a7517 100644 --- a/maintenance/oracle/archives/patch-ufg_group-length-increase.sql +++ b/maintenance/oracle/archives/patch-ufg_group-length-increase-255.sql @@ -2,7 +2,7 @@ define mw_prefix='{$wgDBprefix}'; /*$mw$*/ BEGIN - EXECUTE IMMEDIATE 'ALTER TABLE &mw_prefix.user_former_groups MODIFY ufg_group VARCHAR2(32) NOT NULL'; + EXECUTE IMMEDIATE 'ALTER TABLE &mw_prefix.user_former_groups MODIFY ufg_group VARCHAR2(255) NOT NULL'; EXCEPTION WHEN OTHERS THEN IF (SQLCODE = -01442) THEN NULL; ELSE RAISE; END IF; END; diff --git a/maintenance/oracle/archives/patch-ug_group-length-increase.sql b/maintenance/oracle/archives/patch-ug_group-length-increase-255.sql index 89e55329..00a5e7b2 100644 --- a/maintenance/oracle/archives/patch-ug_group-length-increase.sql +++ b/maintenance/oracle/archives/patch-ug_group-length-increase-255.sql @@ -2,7 +2,7 @@ define mw_prefix='{$wgDBprefix}'; /*$mw$*/ BEGIN - EXECUTE IMMEDIATE 'ALTER TABLE &mw_prefix.user_groups MODIFY ug_group VARCHAR2(32) NOT NULL'; + EXECUTE IMMEDIATE 'ALTER TABLE &mw_prefix.user_groups MODIFY ug_group VARCHAR2(255) NOT NULL'; EXCEPTION WHEN OTHERS THEN IF (SQLCODE = -01442) THEN NULL; ELSE RAISE; END IF; END; diff --git a/maintenance/oracle/archives/patch-uploadstash-us_props.sql b/maintenance/oracle/archives/patch-uploadstash-us_props.sql new file mode 100644 index 00000000..8962dc7c --- /dev/null +++ b/maintenance/oracle/archives/patch-uploadstash-us_props.sql @@ -0,0 +1,4 @@ +define mw_prefix='{$wgDBprefix}'; + +ALTER TABLE &mw_prefix.uploadstash ADD us_props BLOB; + diff --git a/maintenance/oracle/archives/patch-user_former_groups.sql b/maintenance/oracle/archives/patch-user_former_groups.sql index 59147eb2..c14824eb 100644 --- a/maintenance/oracle/archives/patch-user_former_groups.sql +++ b/maintenance/oracle/archives/patch-user_former_groups.sql @@ -2,7 +2,7 @@ define mw_prefix='{$wgDBprefix}'; CREATE TABLE &mw_prefix.user_former_groups ( ufg_user NUMBER DEFAULT 0 NOT NULL, - ufg_group VARCHAR2(16) NOT NULL + ufg_group VARCHAR2(255) NOT NULL ); ALTER TABLE &mw_prefix.user_former_groups ADD CONSTRAINT &mw_prefix.user_former_groups_fk1 FOREIGN KEY (ufg_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED; CREATE UNIQUE INDEX &mw_prefix.user_former_groups_u01 ON &mw_prefix.user_former_groups (ufg_user,ufg_group); diff --git a/maintenance/oracle/tables.sql b/maintenance/oracle/tables.sql index 26600eba..acfabc33 100644 --- a/maintenance/oracle/tables.sql +++ b/maintenance/oracle/tables.sql @@ -31,7 +31,7 @@ INSERT INTO &mw_prefix.mwuser CREATE TABLE &mw_prefix.user_groups ( ug_user NUMBER DEFAULT 0 NOT NULL, - ug_group VARCHAR2(32) NOT NULL + ug_group VARCHAR2(255) NOT NULL ); ALTER TABLE &mw_prefix.user_groups ADD CONSTRAINT &mw_prefix.user_groups_fk1 FOREIGN KEY (ug_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED; CREATE UNIQUE INDEX &mw_prefix.user_groups_u01 ON &mw_prefix.user_groups (ug_user,ug_group); @@ -39,7 +39,7 @@ CREATE INDEX &mw_prefix.user_groups_i01 ON &mw_prefix.user_groups (ug_group); CREATE TABLE &mw_prefix.user_former_groups ( ufg_user NUMBER DEFAULT 0 NOT NULL, - ufg_group VARCHAR2(16) NOT NULL + ufg_group VARCHAR2(255) NOT NULL ); ALTER TABLE &mw_prefix.user_former_groups ADD CONSTRAINT &mw_prefix.user_former_groups_fk1 FOREIGN KEY (ufg_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED; CREATE UNIQUE INDEX &mw_prefix.user_former_groups_u01 ON &mw_prefix.user_former_groups (ufg_user,ufg_group); @@ -73,7 +73,8 @@ CREATE TABLE &mw_prefix.page ( page_random NUMBER(15,14) NOT NULL, page_touched TIMESTAMP(6) WITH TIME ZONE, page_latest NUMBER DEFAULT 0 NOT NULL, -- FK? - page_len NUMBER DEFAULT 0 NOT NULL + page_len NUMBER DEFAULT 0 NOT NULL, + page_content_model VARCHAR2(32) ); 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); @@ -83,7 +84,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); + VALUES (0, 0, ' ', NULL, 0, 0, 0, 0, current_timestamp, 0, 0, NULL); /*$mw$*/ CREATE TRIGGER &mw_prefix.page_set_random BEFORE INSERT ON &mw_prefix.page @@ -106,7 +107,9 @@ CREATE TABLE &mw_prefix.revision ( rev_deleted CHAR(1) DEFAULT '0' NOT NULL, rev_len NUMBER NULL, rev_parent_id NUMBER DEFAULT NULL, - rev_sha1 VARCHAR2(32) NULL + rev_sha1 VARCHAR2(32) NULL, + rev_content_model VARCHAR2(32), + rev_content_format VARCHAR2(64) ); ALTER TABLE &mw_prefix.revision ADD CONSTRAINT &mw_prefix.revision_pk PRIMARY KEY (rev_id); ALTER TABLE &mw_prefix.revision ADD CONSTRAINT &mw_prefix.revision_fk1 FOREIGN KEY (rev_page) REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED; @@ -126,7 +129,9 @@ CREATE TABLE &mw_prefix.pagecontent ( -- replaces reserved word 'text' ); ALTER TABLE &mw_prefix.pagecontent ADD CONSTRAINT &mw_prefix.pagecontent_pk PRIMARY KEY (old_id); +CREATE SEQUENCE archive_ar_id_seq; CREATE TABLE &mw_prefix.archive ( + ar_id NUMBER NOT NULL, ar_namespace NUMBER DEFAULT 0 NOT NULL, ar_title VARCHAR2(255) NOT NULL, ar_text CLOB, @@ -142,8 +147,11 @@ CREATE TABLE &mw_prefix.archive ( ar_len NUMBER, ar_page_id NUMBER, ar_parent_id NUMBER, - ar_sha1 VARCHAR2(32) NULL + ar_sha1 VARCHAR2(32), + ar_content_model VARCHAR2(32), + ar_content_format VARCHAR2(64) ); +ALTER TABLE &mw_prefix.archive ADD CONSTRAINT &mw_prefix.archive_pk PRIMARY KEY (ar_id); ALTER TABLE &mw_prefix.archive ADD CONSTRAINT &mw_prefix.archive_fk1 FOREIGN KEY (ar_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED; CREATE INDEX &mw_prefix.archive_i01 ON &mw_prefix.archive (ar_namespace,ar_title,ar_timestamp); CREATE INDEX &mw_prefix.archive_i02 ON &mw_prefix.archive (ar_user_text,ar_timestamp); @@ -197,30 +205,25 @@ CREATE TABLE &mw_prefix.category ( cat_title VARCHAR2(255) NOT NULL, cat_pages NUMBER DEFAULT 0 NOT NULL, cat_subcats NUMBER DEFAULT 0 NOT NULL, - cat_files NUMBER DEFAULT 0 NOT NULL, - cat_hidden NUMBER DEFAULT 0 NOT NULL + cat_files NUMBER DEFAULT 0 NOT NULL ); ALTER TABLE &mw_prefix.category ADD CONSTRAINT &mw_prefix.category_pk PRIMARY KEY (cat_id); CREATE UNIQUE INDEX &mw_prefix.category_u01 ON &mw_prefix.category (cat_title); CREATE INDEX &mw_prefix.category_i01 ON &mw_prefix.category (cat_pages); +CREATE SEQUENCE externallinks_el_id_seq; CREATE TABLE &mw_prefix.externallinks ( + el_id NUMBER NOT NULL, el_from NUMBER NOT NULL, el_to VARCHAR2(2048) NOT NULL, el_index VARCHAR2(2048) NOT NULL ); +ALTER TABLE &mw_prefix.externallinks ADD CONSTRAINT &mw_prefix.externallinks_pk PRIMARY KEY (el_id); ALTER TABLE &mw_prefix.externallinks ADD CONSTRAINT &mw_prefix.externallinks_fk1 FOREIGN KEY (el_from) REFERENCES &mw_prefix.page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED; CREATE INDEX &mw_prefix.externallinks_i01 ON &mw_prefix.externallinks (el_from, el_to); CREATE INDEX &mw_prefix.externallinks_i02 ON &mw_prefix.externallinks (el_to, el_from); CREATE INDEX &mw_prefix.externallinks_i03 ON &mw_prefix.externallinks (el_index); -CREATE TABLE &mw_prefix.external_user ( - eu_local_id NUMBER NOT NULL, - eu_external_id varchar2(255) NOT NULL -); -ALTER TABLE &mw_prefix.external_user ADD CONSTRAINT &mw_prefix.external_user_pk PRIMARY KEY (eu_local_id); -CREATE UNIQUE INDEX &mw_prefix.external_user_u01 ON &mw_prefix.external_user (eu_external_id); - CREATE TABLE &mw_prefix.langlinks ( ll_from NUMBER NOT NULL, ll_lang VARCHAR2(20), @@ -246,7 +249,6 @@ CREATE TABLE &mw_prefix.site_stats ( ss_total_pages NUMBER DEFAULT -1, ss_users NUMBER DEFAULT -1, ss_active_users NUMBER DEFAULT -1, - ss_admins NUMBER DEFAULT -1, ss_images NUMBER DEFAULT 0 ); CREATE UNIQUE INDEX &mw_prefix.site_stats_u01 ON &mw_prefix.site_stats (ss_row_id); @@ -358,7 +360,8 @@ CREATE TABLE &mw_prefix.filearchive ( fa_user NUMBER DEFAULT 0 NOT NULL, fa_user_text VARCHAR2(255) NOT NULL, fa_timestamp TIMESTAMP(6) WITH TIME ZONE, - fa_deleted NUMBER DEFAULT 0 NOT NULL + fa_deleted NUMBER DEFAULT 0 NOT NULL, + fa_sha1 VARCHAR2(32) ); ALTER TABLE &mw_prefix.filearchive ADD CONSTRAINT &mw_prefix.filearchive_pk PRIMARY KEY (fa_id); ALTER TABLE &mw_prefix.filearchive ADD CONSTRAINT &mw_prefix.filearchive_fk1 FOREIGN KEY (fa_deleted_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED; @@ -367,6 +370,7 @@ CREATE INDEX &mw_prefix.filearchive_i01 ON &mw_prefix.filearchive (fa_name, fa_t CREATE INDEX &mw_prefix.filearchive_i02 ON &mw_prefix.filearchive (fa_storage_group, fa_storage_key); CREATE INDEX &mw_prefix.filearchive_i03 ON &mw_prefix.filearchive (fa_deleted_timestamp); CREATE INDEX &mw_prefix.filearchive_i04 ON &mw_prefix.filearchive (fa_user_text,fa_timestamp); +CREATE INDEX &mw_prefix.filearchive_i05 ON &mw_prefix.filearchive (fa_sha1); CREATE SEQUENCE uploadstash_us_id_seq; CREATE TABLE &mw_prefix.uploadstash ( @@ -385,7 +389,8 @@ CREATE TABLE &mw_prefix.uploadstash ( us_media_type VARCHAR2(32) DEFAULT NULL, us_image_width NUMBER, us_image_height NUMBER, - us_image_bits NUMBER + us_image_bits NUMBER, + us_props BLOB ); ALTER TABLE &mw_prefix.uploadstash ADD CONSTRAINT &mw_prefix.uploadstash_pk PRIMARY KEY (us_id); ALTER TABLE &mw_prefix.uploadstash ADD CONSTRAINT &mw_prefix.uploadstash_fk1 FOREIGN KEY (us_user) REFERENCES &mw_prefix.mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED; @@ -410,8 +415,6 @@ 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_moved_to_ns NUMBER DEFAULT 0 NOT NULL, - rc_moved_to_title VARCHAR2(255), rc_patrolled CHAR(1) DEFAULT '0' NOT NULL, rc_ip VARCHAR2(15), rc_old_len NUMBER, @@ -523,11 +526,19 @@ CREATE TABLE &mw_prefix.job ( job_namespace NUMBER DEFAULT 0 NOT NULL, job_title VARCHAR2(255) NOT NULL, job_timestamp TIMESTAMP(6) WITH TIME ZONE NULL, - job_params CLOB NOT NULL + job_params CLOB NOT NULL, + job_random NUMBER DEFAULT 0 NOT NULL, + job_token VARCHAR2(32), + job_token_timestamp TIMESTAMP(6) WITH TIME ZONE, + job_sha1 VARCHAR2(32), + job_attempts NUMBER DEFAULT 0 NOT NULL ); ALTER TABLE &mw_prefix.job ADD CONSTRAINT &mw_prefix.job_pk PRIMARY KEY (job_id); CREATE INDEX &mw_prefix.job_i01 ON &mw_prefix.job (job_cmd, job_namespace, job_title); CREATE INDEX &mw_prefix.job_i02 ON &mw_prefix.job (job_timestamp); +CREATE INDEX &mw_prefix.job_i03 ON &mw_prefix.job (job_sha1); +CREATE INDEX &mw_prefix.job_i04 ON &mw_prefix.job (job_cmd,job_token,job_random); +CREATE INDEX &mw_prefix.job_i05 ON &mw_prefix.job (job_attempts); CREATE TABLE &mw_prefix.querycache_info ( qci_type VARCHAR2(32) NOT NULL, @@ -629,10 +640,11 @@ ALTER TABLE &mw_prefix.valid_tag ADD CONSTRAINT &mw_prefix.valid_tag_pk PRIMARY -- This table is not used unless profiling is turned on --CREATE TABLE &mw_prefix.profiling ( --- pf_count NUMBER DEFAULT 0 NOT NULL, --- pf_time NUMERIC(18,10) DEFAULT 0 NOT NULL, --- pf_name CLOB NOT NULL, --- pf_server CLOB NULL +-- pf_count NUMBER DEFAULT 0 NOT NULL, +-- pf_time NUMBER(18,10) DEFAULT 0 NOT NULL, +-- pf_memory NUMBER(18,10) DEFAULT 0 NOT NULL, +-- pf_name VARCHAR2(255), +-- pf_server VARCHAR2(30) --); --CREATE UNIQUE INDEX &mw_prefix.profiling_u01 ON &mw_prefix.profiling (pf_name, pf_server); @@ -667,6 +679,39 @@ CREATE TABLE &mw_prefix.module_deps ( ); CREATE UNIQUE INDEX &mw_prefix.module_deps_u01 ON &mw_prefix.module_deps (md_module, md_skin); +CREATE SEQUENCE sites_site_id_seq MINVALUE 0 START WITH 0; +CREATE TABLE &mw_prefix.sites ( + site_id NUMBER NOT NULL, + site_global_key VARCHAR2(32) NOT NULL, + site_type VARCHAR2(32) NOT NULL, + site_group VARCHAR2(32) NOT NULL, + site_source VARCHAR2(32) NOT NULL, + site_language VARCHAR2(32) NOT NULL, + site_protocol VARCHAR2(32) NOT NULL, + site_domain VARCHAR2(255) NOT NULL, + site_data BLOB NOT NULL, + site_forward NUMBER(1) NOT NULL, + site_config BLOB NOT NULL +); +ALTER TABLE &mw_prefix.sites ADD CONSTRAINT &mw_prefix.sites_pk PRIMARY KEY (site_id); +CREATE UNIQUE INDEX &mw_prefix.sites_u01 ON &mw_prefix.sites (site_global_key); +CREATE INDEX &mw_prefix.sites_i01 ON &mw_prefix.sites (site_type); +CREATE INDEX &mw_prefix.sites_i02 ON &mw_prefix.sites (site_group); +CREATE INDEX &mw_prefix.sites_i03 ON &mw_prefix.sites (site_source); +CREATE INDEX &mw_prefix.sites_i04 ON &mw_prefix.sites (site_language); +CREATE INDEX &mw_prefix.sites_i05 ON &mw_prefix.sites (site_protocol); +CREATE INDEX &mw_prefix.sites_i06 ON &mw_prefix.sites (site_domain); +CREATE INDEX &mw_prefix.sites_i07 ON &mw_prefix.sites (site_forward); + +CREATE TABLE &mw_prefix.site_identifiers ( + si_site NUMBER NOT NULL, + si_type VARCHAR2(32) NOT NULL, + si_key VARCHAR2(32) NOT NULL +); +CREATE UNIQUE INDEX &mw_prefix.site_identifiers_u01 ON &mw_prefix.site_identifiers (si_type, si_key); +CREATE INDEX &mw_prefix.site_identifiers_i01 ON &mw_prefix.site_identifiers (si_site); +CREATE INDEX &mw_prefix.site_identifiers_i02 ON &mw_prefix.site_identifiers (si_key); + -- do not prefix this table as it breaks parserTests CREATE TABLE wiki_field_info_full ( table_name VARCHAR2(35) NOT NULL, diff --git a/maintenance/orphans.php b/maintenance/orphans.php index 78f98f5a..b4d255ab 100644 --- a/maintenance/orphans.php +++ b/maintenance/orphans.php @@ -28,7 +28,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that looks for 'orphan' revisions hooked to pages which @@ -87,7 +87,7 @@ class Orphans extends Maintenance { FROM $revision LEFT OUTER JOIN $page ON rev_page=page_id WHERE page_id IS NULL " ); - $orphans = $dbw->numRows( $result ); + $orphans = $result->numRows(); if ( $orphans > 0 ) { global $wgContLang; $this->output( "$orphans orphan revisions...\n" ); @@ -139,7 +139,7 @@ class Orphans extends Maintenance { FROM $page LEFT OUTER JOIN $revision ON page_latest=rev_id WHERE rev_id IS NULL " ); - $widows = $dbw->numRows( $result ); + $widows = $result->numRows(); if ( $widows > 0 ) { $this->output( "$widows childless pages...\n" ); $this->output( sprintf( "%10s %11s %2s %s\n", 'page_id', 'page_latest', 'ns', 'page_title' ) ); @@ -171,7 +171,7 @@ class Orphans extends Maintenance { */ private function checkSeparation( $fix ) { $dbw = wfGetDB( DB_MASTER ); - $page = $dbw->tableName( 'page' ); + $page = $dbw->tableName( 'page' ); $revision = $dbw->tableName( 'revision' ); if ( $fix ) { @@ -209,7 +209,7 @@ class Orphans extends Maintenance { 'revision', 'rev_id', array( - 'rev_page' => $row->page_id, + 'rev_page' => $row->page_id, 'rev_timestamp' => $row2->max_timestamp ) ); $this->output( "... updating to revision $maxId\n" ); $maxRev = Revision::newFromId( $maxId ); @@ -239,4 +239,4 @@ class Orphans extends Maintenance { } $maintClass = "Orphans"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/parse.php b/maintenance/parse.php index b0ab6244..3ac7a281 100644 --- a/maintenance/parse.php +++ b/maintenance/parse.php @@ -49,7 +49,7 @@ * @license GNU General Public License 2.0 or later */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to parse some wikitext. @@ -85,12 +85,12 @@ class CLIParser extends Maintenance { */ protected function Wikitext() { - $php_stdin = 'php://stdin'; + $php_stdin = 'php://stdin'; $input_file = $this->getArg( 0, $php_stdin ); - if( $input_file === $php_stdin ) { + 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 ); @@ -109,11 +109,11 @@ class CLIParser extends Maintenance { * * @return Title object */ - protected function getTitle( ) { + protected function getTitle() { $title = $this->getOption( 'title' ) ? $this->getOption( 'title' ) - : 'CLIParser' ; + : 'CLIParser'; return Title::newFromText( $title ); } @@ -131,4 +131,4 @@ class CLIParser extends Maintenance { } $maintClass = "CLIParser"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/patchSql.php b/maintenance/patchSql.php index 1f393556..31ce1566 100644 --- a/maintenance/patchSql.php +++ b/maintenance/patchSql.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that manually runs an SQL patch outside of the general updaters. @@ -62,4 +62,4 @@ class PatchSql extends Maintenance { } $maintClass = "PatchSql"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/populateCategory.php b/maintenance/populateCategory.php index ae54d698..4c8cdaa1 100644 --- a/maintenance/populateCategory.php +++ b/maintenance/populateCategory.php @@ -22,7 +22,7 @@ * @author Simetrical */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Mainteance script to populate the category table. @@ -142,4 +142,4 @@ TEXT; } $maintClass = "PopulateCategory"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/populateFilearchiveSha1.php b/maintenance/populateFilearchiveSha1.php new file mode 100644 index 00000000..c579d4fc --- /dev/null +++ b/maintenance/populateFilearchiveSha1.php @@ -0,0 +1,107 @@ +<?php +/** + * Optional upgrade script to populate the fa_sha1 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 dirname( __FILE__ ) . '/Maintenance.php'; + +/** + * Maintenance script to populate the fa_sha1 field. + * + * @ingroup Maintenance + * @since 1.21 + */ +class PopulateFilearchiveSha1 extends LoggedUpdateMaintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = "Populate the fa_sha1 field from fa_storage_key"; + } + + protected function getUpdateKey() { + return 'populate fa_sha1'; + } + + protected function updateSkippedMessage() { + return 'fa_sha1 column of filearchive table already populated.'; + } + + public function doDBUpdates() { + $startTime = microtime( true ); + $dbw = wfGetDB( DB_MASTER ); + $table = 'filearchive'; + $conds = array( 'fa_sha1' => '', 'fa_storage_key IS NOT NULL' ); + + if ( !$dbw->fieldExists( $table, 'fa_sha1', __METHOD__ ) ) { + $this->output( "fa_sha1 column does not exist\n\n", true ); + return false; + } + + $this->output( "Populating fa_sha1 field from fa_storage_key\n" ); + $endId = $dbw->selectField( $table, 'MAX(fa_id)', false, __METHOD__ ); + + $batchSize = $this->mBatchSize; + $done = 0; + + do { + $res = $dbw->select( + $table, + array( 'fa_id', 'fa_storage_key' ), + $conds, + __METHOD__, + array( 'LIMIT' => $batchSize ) + ); + + $i = 0; + foreach ( $res as $row ) { + if ( $row->fa_storage_key == '' ) { + // Revision was missing pre-deletion + continue; + } + $sha1 = LocalRepo::getHashFromKey( $row->fa_storage_key ); + $dbw->update( $table, + array( 'fa_sha1' => $sha1 ), + array( 'fa_id' => $row->fa_id ), + __METHOD__ + ); + $lastId = $row->fa_id; + $i++; + } + + $done += $i; + if ( $i !== $batchSize ) { + break; + } + + // print status and let slaves catch up + $this->output( sprintf( + "id %d done (up to %d), %5.3f%% \r", $lastId, $endId, $lastId / $endId * 100 ) ); + wfWaitForSlaves(); + } while ( true ); + + $processingTime = microtime( true ) - $startTime; + $this->output( sprintf( "\nDone %d files in %.1f seconds\n", $done, $processingTime ) ); + + return true; // we only updated *some* files, don't log + } +} + +$maintClass = "PopulateFilearchiveSha1"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/populateImageSha1.php b/maintenance/populateImageSha1.php index 37429a34..126d22d9 100644 --- a/maintenance/populateImageSha1.php +++ b/maintenance/populateImageSha1.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to populate the img_sha1 field. @@ -164,4 +164,4 @@ class PopulateImageSha1 extends LoggedUpdateMaintenance { } $maintClass = "PopulateImageSha1"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/populateLogSearch.php b/maintenance/populateLogSearch.php index 99d81557..d65635e5 100644 --- a/maintenance/populateLogSearch.php +++ b/maintenance/populateLogSearch.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that makes the required database updates for populating the @@ -75,7 +75,9 @@ class PopulateLogSearch extends LoggedUpdateMaintenance { if ( LogEventsList::typeAction( $row, $delTypes, 'revision' ) ) { $params = LogPage::extractParams( $row->log_params ); // Param format: <urlparam> <item CSV> [<ofield> <nfield>] - if ( count( $params ) < 2 ) continue; // bad row? + if ( count( $params ) < 2 ) { + continue; // bad row? + } $field = RevisionDeleter::getRelationType( $params[0] ); // B/C, the params may start with a title key (<title> <urlparam> <CSV>) if ( $field == null ) { @@ -97,8 +99,9 @@ class PopulateLogSearch extends LoggedUpdateMaintenance { $log->addRelations( $field, $items, $row->log_id ); // Determine what table to query... $prefix = substr( $field, 0, strpos( $field, '_' ) ); // db prefix - if ( !isset( self::$tableMap[$prefix] ) ) + if ( !isset( self::$tableMap[$prefix] ) ) { continue; // bad row? + } $table = self::$tableMap[$prefix]; $userField = $prefix . '_user'; $userTextField = $prefix . '_user_text'; @@ -109,10 +112,11 @@ class PopulateLogSearch extends LoggedUpdateMaintenance { array( $field => $items ) ); foreach ( $sres as $srow ) { - if ( $srow->$userField > 0 ) + if ( $srow->$userField > 0 ) { $userIds[] = intval( $srow->$userField ); - elseif ( $srow->$userTextField != '' ) + } elseif ( $srow->$userTextField != '' ) { $userIPs[] = $srow->$userTextField; + } } // Add item author relations... $log->addRelations( 'target_author_id', $userIds, $row->log_id ); @@ -121,7 +125,9 @@ class PopulateLogSearch extends LoggedUpdateMaintenance { } elseif ( LogEventsList::typeAction( $row, $delTypes, 'event' ) ) { $params = LogPage::extractParams( $row->log_params ); // Param format: <item CSV> [<ofield> <nfield>] - if ( count( $params ) < 1 ) continue; // bad row + if ( count( $params ) < 1 ) { + continue; // bad row + } $items = explode( ',', $params[0] ); $log = new LogPage( $row->log_type ); // Add item relations... @@ -133,10 +139,11 @@ class PopulateLogSearch extends LoggedUpdateMaintenance { array( 'log_id' => $items ) ); foreach ( $sres as $srow ) { - if ( $srow->log_user > 0 ) + if ( $srow->log_user > 0 ) { $userIds[] = intval( $srow->log_user ); - elseif ( IP::isIPAddress( $srow->log_user_text ) ) + } elseif ( IP::isIPAddress( $srow->log_user_text ) ) { $userIPs[] = $srow->log_user_text; + } } $log->addRelations( 'target_author_id', $userIds, $row->log_id ); $log->addRelations( 'target_author_ip', $userIPs, $row->log_id ); @@ -152,4 +159,4 @@ class PopulateLogSearch extends LoggedUpdateMaintenance { } $maintClass = "PopulateLogSearch"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/populateLogUsertext.php b/maintenance/populateLogUsertext.php index 059b6fe2..e579e522 100644 --- a/maintenance/populateLogUsertext.php +++ b/maintenance/populateLogUsertext.php @@ -24,7 +24,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that makes the required database updates for @@ -82,5 +82,4 @@ class PopulateLogUsertext extends LoggedUpdateMaintenance { } $maintClass = "PopulateLogUsertext"; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/populateParentId.php b/maintenance/populateParentId.php index e81d4ffb..e29fa5f1 100644 --- a/maintenance/populateParentId.php +++ b/maintenance/populateParentId.php @@ -23,7 +23,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that makes the required database updates for rev_parent_id @@ -98,8 +98,9 @@ class PopulateParentId extends LoggedUpdateMaintenance { } } $previousID = intval( $previousID ); - if ( $previousID != $row->rev_parent_id ) + if ( $previousID != $row->rev_parent_id ) { $changed++; + } # Update the row... $db->update( 'revision', array( 'rev_parent_id' => $previousID ), @@ -117,4 +118,4 @@ class PopulateParentId extends LoggedUpdateMaintenance { } $maintClass = "PopulateParentId"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/populateRevisionLength.php b/maintenance/populateRevisionLength.php index 6c835f4e..3c69125a 100644 --- a/maintenance/populateRevisionLength.php +++ b/maintenance/populateRevisionLength.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that populates the rev_len field for old revisions @@ -48,7 +48,11 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance { $db = $this->getDB( DB_MASTER ); if ( !$db->tableExists( 'revision' ) ) { $this->error( "revision 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" ); $start = $db->selectField( 'revision', 'MIN(rev_id)', false, __METHOD__ ); @@ -63,27 +67,32 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance { $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" ); - $res = $db->select( 'revision', - Revision::selectFields(), - array( "rev_id >= $blockStart", - "rev_id <= $blockEnd", - "rev_len IS NULL" ), - __METHOD__ ); + $res = $db->select( + 'revision', + $fields, + array( + "rev_id >= $blockStart", + "rev_id <= $blockEnd", + "rev_len IS NULL" + ), + __METHOD__ + ); # Go through and update rev_len from these rows. foreach ( $res as $row ) { $rev = new Revision( $row ); - $text = $rev->getRawText(); - if ( !is_string( $text ) ) { + $content = $rev->getContent(); + if ( !$content ) { # This should not happen, but sometimes does (bug 20757) - $this->output( "Text of revision {$row->rev_id} unavailable!\n" ); + $this->output( "Content of revision {$row->rev_id} unavailable!\n" ); $missing++; } else { # Update the row... $db->update( 'revision', - array( 'rev_len' => strlen( $text ) ), + array( 'rev_len' => $content->getSize() ), array( 'rev_id' => $row->rev_id ), __METHOD__ ); $count++; @@ -100,4 +109,4 @@ class PopulateRevisionLength extends LoggedUpdateMaintenance { } $maintClass = "PopulateRevisionLength"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/populateRevisionSha1.php b/maintenance/populateRevisionSha1.php index 2e14d31e..89bfb85b 100644 --- a/maintenance/populateRevisionSha1.php +++ b/maintenance/populateRevisionSha1.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that fills the rev_sha1 and ar_sha1 columns of revision @@ -48,6 +48,9 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { $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_sha1', __METHOD__ ) ) { + $this->output( "rev_sha1 column does not exist\n\n", true ); + return false; } $this->output( "Populating rev_sha1 column\n" ); @@ -143,14 +146,14 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { $rev = ( $table === 'archive' ) ? Revision::newFromArchiveRow( $row ) : new Revision( $row ); - $text = $rev->getRawText(); + $text = $rev->getSerializedData(); } catch ( MWException $e ) { - $this->output( "Text of revision with {$idCol}={$row->$idCol} unavailable!\n" ); + $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( "Text of revision with {$idCol}={$row->$idCol} unavailable!\n" ); + $this->output( "Data of revision with {$idCol}={$row->$idCol} unavailable!\n" ); return false; } else { $db->update( $table, @@ -174,10 +177,10 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { $this->output( "Text of revision with timestamp {$row->ar_timestamp} unavailable!\n" ); return false; // bug 22624? } - $text = $rev->getRawText(); + $text = $rev->getSerializedData(); if ( !is_string( $text ) ) { # This should not happen, but sometimes does (bug 20757) - $this->output( "Text of revision with timestamp {$row->ar_timestamp} unavailable!\n" ); + $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. @@ -186,9 +189,9 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { array( 'ar_sha1' => Revision::base36Sha1( $text ) ), array( 'ar_namespace' => $row->ar_namespace, - 'ar_title' => $row->ar_title, + 'ar_title' => $row->ar_title, 'ar_timestamp' => $row->ar_timestamp, - 'ar_len' => $row->ar_len // extra sanity + 'ar_len' => $row->ar_len // extra sanity ), __METHOD__ ); @@ -198,4 +201,4 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance { } $maintClass = "PopulateRevisionSha1"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/postgres/archives/patch-external_user.sql b/maintenance/postgres/archives/patch-external_user.sql deleted file mode 100644 index 6058a706..00000000 --- a/maintenance/postgres/archives/patch-external_user.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE external_user ( - eu_local_id INTEGER NOT NULL PRIMARY KEY, - eu_external_id TEXT -); - -CREATE UNIQUE INDEX eu_external_id ON external_user (eu_external_id); diff --git a/maintenance/postgres/archives/patch-kill-iwl_pft.sql b/maintenance/postgres/archives/patch-kill-iwl_pft.sql deleted file mode 100644 index 4419d9e9..00000000 --- a/maintenance/postgres/archives/patch-kill-iwl_pft.sql +++ /dev/null @@ -1,7 +0,0 @@ --- --- Kill the old iwl_prefix_from_title index, which may be present on some --- installs if they ran update.php between it being added and being renamed --- - -DROP INDEX iwl_prefix_from_title; - diff --git a/maintenance/postgres/archives/patch-profiling.sql b/maintenance/postgres/archives/patch-profiling.sql index 1c4dce4e..5a2710a8 100644 --- a/maintenance/postgres/archives/patch-profiling.sql +++ b/maintenance/postgres/archives/patch-profiling.sql @@ -1,6 +1,7 @@ CREATE TABLE profiling ( pf_count INTEGER NOT NULL DEFAULT 0, - pf_time NUMERIC(18,10) NOT NULL DEFAULT 0, + pf_time FLOAT NOT NULL DEFAULT 0, + pf_memory FLOAT NOT NULL DEFAULT 0, pf_name TEXT NOT NULL, pf_server TEXT NULL ); diff --git a/maintenance/postgres/archives/patch-rename-iwl_prefix.sql b/maintenance/postgres/archives/patch-rename-iwl_prefix.sql index a4bdb6a9..0eb792ea 100644 --- a/maintenance/postgres/archives/patch-rename-iwl_prefix.sql +++ b/maintenance/postgres/archives/patch-rename-iwl_prefix.sql @@ -1,2 +1,2 @@ DROP INDEX iwl_prefix; -CREATE UNIQUE INDEX iwl_prefix_title_from ON iwlinks (iwl_prefix, iwl_from, iwl_title); +CREATE UNIQUE INDEX iwl_prefix_title_from ON iwlinks (iwl_prefix, iwl_title, iwl_from); diff --git a/maintenance/postgres/archives/patch-sites.sql b/maintenance/postgres/archives/patch-sites.sql new file mode 100644 index 00000000..a4f9ed9e --- /dev/null +++ b/maintenance/postgres/archives/patch-sites.sql @@ -0,0 +1,31 @@ +CREATE SEQUENCE sites_site_id_seq; +CREATE TABLE sites ( + site_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('sites_site_id_seq'), + site_global_key TEXT NOT NULL, + site_type TEXT NOT NULL, + site_group TEXT NOT NULL, + site_source TEXT NOT NULL, + site_language TEXT NOT NULL, + site_protocol TEXT NOT NULL, + site_domain TEXT NOT NULL, + site_data TEXT NOT NULL, + site_forward SMALLINT NOT NULL, + site_config TEXT NOT NULL +); +CREATE UNIQUE INDEX site_global_key ON sites (site_global_key); +CREATE INDEX site_type ON sites (site_type); +CREATE INDEX site_group ON sites (site_group); +CREATE INDEX site_source ON sites (site_source); +CREATE INDEX site_language ON sites (site_language); +CREATE INDEX site_protocol ON sites (site_protocol); +CREATE INDEX site_domain ON sites (site_domain); +CREATE INDEX site_forward ON sites (site_forward); + +CREATE TABLE site_identifiers ( + si_site INTEGER NOT NULL, + si_type TEXT NOT NULL, + si_key TEXT NOT NULL +); +CREATE UNIQUE INDEX si_type_key ON site_identifiers (si_type, si_key); +CREATE INDEX si_site ON site_identifiers (si_site); +CREATE INDEX si_key ON site_identifiers (si_key); diff --git a/maintenance/postgres/archives/patch-testrun.sql b/maintenance/postgres/archives/patch-testrun.sql index c15300b5..a131b5da 100644 --- a/maintenance/postgres/archives/patch-testrun.sql +++ b/maintenance/postgres/archives/patch-testrun.sql @@ -26,5 +26,5 @@ CREATE TABLE testitem ( ti_run INTEGER NOT NULL REFERENCES testrun(tr_id) ON DELETE CASCADE, ti_name TEXT NOT NULL, ti_success SMALLINT NOT NULL -); +); CREATE UNIQUE INDEX testitem_uniq ON testitem(ti_run, ti_name); diff --git a/maintenance/postgres/tables.sql b/maintenance/postgres/tables.sql index 3ac19cb4..bc2428e4 100644 --- a/maintenance/postgres/tables.sql +++ b/maintenance/postgres/tables.sql @@ -18,6 +18,8 @@ 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 FUNCTION IF EXISTS page_deleted() CASCADE; DROP FUNCTION IF EXISTS ts2_page_title() CASCADE; DROP FUNCTION IF EXISTS ts2_page_text() CASCADE; @@ -79,7 +81,8 @@ CREATE TABLE page ( page_random NUMERIC(15,14) NOT NULL DEFAULT RANDOM(), page_touched TIMESTAMPTZ, page_latest INTEGER NOT NULL, -- FK? - page_len INTEGER NOT NULL + page_len INTEGER NOT NULL, + page_content_model TEXT ); 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; @@ -104,18 +107,20 @@ CREATE TRIGGER page_deleted AFTER DELETE ON page CREATE SEQUENCE revision_rev_id_seq; CREATE TABLE revision ( - rev_id INTEGER NOT NULL UNIQUE DEFAULT nextval('revision_rev_id_seq'), - rev_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, - rev_text_id INTEGER NULL, -- FK - rev_comment TEXT, - rev_user INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED, - rev_user_text TEXT NOT NULL, - rev_timestamp TIMESTAMPTZ NOT NULL, - rev_minor_edit SMALLINT NOT NULL DEFAULT 0, - rev_deleted SMALLINT NOT NULL DEFAULT 0, - rev_len INTEGER NULL, - rev_parent_id INTEGER NULL, - rev_sha1 TEXT NOT NULL DEFAULT '' + rev_id INTEGER NOT NULL UNIQUE DEFAULT nextval('revision_rev_id_seq'), + rev_page INTEGER NULL REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, + rev_text_id INTEGER NULL, -- FK + rev_comment TEXT, + rev_user INTEGER NOT NULL REFERENCES mwuser(user_id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED, + rev_user_text TEXT NOT NULL, + rev_timestamp TIMESTAMPTZ NOT NULL, + rev_minor_edit SMALLINT NOT NULL DEFAULT 0, + rev_deleted SMALLINT NOT NULL DEFAULT 0, + rev_len INTEGER NULL, + rev_parent_id INTEGER NULL, + rev_sha1 TEXT NOT NULL DEFAULT '', + rev_content_model TEXT, + rev_content_format TEXT ); CREATE UNIQUE INDEX revision_unique ON revision (rev_page, rev_id); CREATE INDEX rev_text_id_idx ON revision (rev_text_id); @@ -151,24 +156,29 @@ CREATE TABLE page_props ( ); 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 SEQUENCE archive_ar_id_seq; CREATE TABLE archive ( - ar_namespace SMALLINT NOT NULL, - ar_title TEXT NOT NULL, - ar_text TEXT, -- technically should be bytea, but not used anymore - ar_page_id INTEGER NULL, - ar_parent_id INTEGER NULL, - ar_sha1 TEXT NOT NULL DEFAULT '', - ar_comment TEXT, - ar_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED, - ar_user_text TEXT NOT NULL, - ar_timestamp TIMESTAMPTZ NOT NULL, - ar_minor_edit SMALLINT NOT NULL DEFAULT 0, - ar_flags TEXT, - ar_rev_id INTEGER, - ar_text_id INTEGER, - ar_deleted SMALLINT NOT NULL DEFAULT 0, - ar_len INTEGER NULL + ar_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('archive_ar_id_seq'), + ar_namespace SMALLINT NOT NULL, + ar_title TEXT NOT NULL, + ar_text TEXT, -- technically should be bytea, but not used anymore + ar_page_id INTEGER NULL, + ar_parent_id INTEGER NULL, + ar_sha1 TEXT NOT NULL DEFAULT '', + ar_comment TEXT, + ar_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED, + ar_user_text TEXT NOT NULL, + ar_timestamp TIMESTAMPTZ NOT NULL, + ar_minor_edit SMALLINT NOT NULL DEFAULT 0, + ar_flags TEXT, + ar_rev_id INTEGER, + ar_text_id INTEGER, + ar_deleted SMALLINT NOT NULL DEFAULT 0, + ar_len INTEGER NULL, + ar_content_model TEXT, + ar_content_format TEXT ); CREATE INDEX archive_name_title_timestamp ON archive (ar_namespace,ar_title,ar_timestamp); CREATE INDEX archive_user_text ON archive (ar_user_text); @@ -218,7 +228,9 @@ CREATE TABLE categorylinks ( CREATE UNIQUE INDEX cl_from ON categorylinks (cl_from, cl_to); CREATE INDEX cl_sortkey ON categorylinks (cl_to, cl_sortkey, cl_from); +CREATE SEQUENCE externallinks_id_seq; CREATE TABLE externallinks ( + el_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('externallinks_id_seq'), el_from INTEGER NOT NULL REFERENCES page(page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, el_to TEXT NOT NULL, el_index TEXT NOT NULL @@ -226,13 +238,6 @@ CREATE TABLE externallinks ( CREATE INDEX externallinks_from_to ON externallinks (el_from,el_to); CREATE INDEX externallinks_index ON externallinks (el_index); -CREATE TABLE external_user ( - eu_local_id INTEGER NOT NULL PRIMARY KEY, - eu_external_id TEXT -); - -CREATE UNIQUE INDEX eu_external_id ON external_user (eu_external_id); - CREATE TABLE langlinks ( ll_from INTEGER NOT NULL REFERENCES page (page_id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, ll_lang TEXT, @@ -353,12 +358,14 @@ CREATE TABLE filearchive ( fa_user INTEGER NULL REFERENCES mwuser(user_id) ON DELETE SET NULL DEFERRABLE INITIALLY DEFERRED, fa_user_text TEXT NOT NULL, fa_timestamp TIMESTAMPTZ, - fa_deleted SMALLINT NOT NULL DEFAULT 0 + fa_deleted SMALLINT NOT NULL DEFAULT 0, + fa_sha1 TEXT NOT NULL DEFAULT '' ); CREATE INDEX fa_name_time ON filearchive (fa_name, fa_timestamp); CREATE INDEX fa_dupe ON filearchive (fa_storage_group, fa_storage_key); CREATE INDEX fa_notime ON filearchive (fa_deleted_timestamp); CREATE INDEX fa_nouser ON filearchive (fa_deleted_user); +CREATE INDEX fa_sha1 ON filearchive (fa_sha1); CREATE SEQUENCE uploadstash_us_id_seq; CREATE TYPE media_type AS ENUM ('UNKNOWN','BITMAP','DRAWING','AUDIO','VIDEO','MULTIMEDIA','OFFICE','TEXT','EXECUTABLE','ARCHIVE'); @@ -404,8 +411,6 @@ CREATE TABLE recentchanges ( rc_this_oldid INTEGER NOT NULL, rc_last_oldid INTEGER NOT NULL, rc_type SMALLINT NOT NULL DEFAULT 0, - rc_moved_to_ns SMALLINT, - rc_moved_to_title TEXT, rc_patrolled SMALLINT NOT NULL DEFAULT 0, rc_ip CIDR, rc_old_len INTEGER, @@ -516,13 +521,21 @@ CREATE INDEX ls_log_id ON log_search (ls_log_id); CREATE SEQUENCE job_job_id_seq; CREATE TABLE job ( - job_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('job_job_id_seq'), - job_cmd TEXT NOT NULL, - job_namespace SMALLINT NOT NULL, - job_title TEXT NOT NULL, - job_timestamp TIMESTAMPTZ, - job_params TEXT NOT NULL -); + job_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('job_job_id_seq'), + job_cmd TEXT NOT NULL, + job_namespace SMALLINT NOT NULL, + job_title TEXT NOT NULL, + job_timestamp TIMESTAMPTZ, + job_params TEXT NOT NULL, + job_random INTEGER NOT NULL DEFAULT 0, + job_attempts INTEGER NOT NULL DEFAULT 0, + job_token TEXT NOT NULL DEFAULT '', + job_token_timestamp TIMESTAMPTZ, + job_sha1 TEXT NOT NULL DEFAULT '' +); +CREATE INDEX job_sha1 ON job (job_sha1); +CREATE INDEX job_cmd_token ON job (job_cmd, job_token, job_random); +CREATE INDEX job_cmd_token_id ON job (job_cmd, job_token, job_id); CREATE INDEX job_cmd_namespace_title ON job (job_cmd, job_namespace, job_title); CREATE INDEX job_timestamp_idx ON job (job_timestamp); @@ -578,8 +591,8 @@ $mw$; -- 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_memory NUMERIC(18,10) NOT NULL DEFAULT 0, + pf_time FLOAT NOT NULL DEFAULT 0, + pf_memory FLOAT NOT NULL DEFAULT 0, pf_name TEXT NOT NULL, pf_server TEXT NULL ); @@ -663,6 +676,7 @@ CREATE TABLE iwlinks ( ); CREATE UNIQUE INDEX iwl_from ON iwlinks (iwl_from, iwl_prefix, iwl_title); CREATE UNIQUE INDEX iwl_prefix_title_from ON iwlinks (iwl_prefix, iwl_title, iwl_from); +CREATE UNIQUE INDEX iwl_prefix_from_title ON iwlinks (iwl_prefix, iwl_from, iwl_title); CREATE TABLE msg_resource ( mr_resource TEXT NOT NULL, @@ -684,3 +698,35 @@ CREATE TABLE module_deps ( md_deps TEXT NOT NULL ); CREATE UNIQUE INDEX md_module_skin ON module_deps (md_module, md_skin); + +CREATE SEQUENCE sites_site_id_seq; +CREATE TABLE sites ( + site_id INTEGER NOT NULL PRIMARY KEY DEFAULT nextval('sites_site_id_seq'), + site_global_key TEXT NOT NULL, + site_type TEXT NOT NULL, + site_group TEXT NOT NULL, + site_source TEXT NOT NULL, + site_language TEXT NOT NULL, + site_protocol TEXT NOT NULL, + site_domain TEXT NOT NULL, + site_data TEXT NOT NULL, + site_forward SMALLINT NOT NULL, + site_config TEXT NOT NULL +); +CREATE UNIQUE INDEX site_global_key ON sites (site_global_key); +CREATE INDEX site_type ON sites (site_type); +CREATE INDEX site_group ON sites (site_group); +CREATE INDEX site_source ON sites (site_source); +CREATE INDEX site_language ON sites (site_language); +CREATE INDEX site_protocol ON sites (site_protocol); +CREATE INDEX site_domain ON sites (site_domain); +CREATE INDEX site_forward ON sites (site_forward); + +CREATE TABLE site_identifiers ( + si_site INTEGER NOT NULL, + si_type TEXT NOT NULL, + si_key TEXT NOT NULL +); +CREATE UNIQUE INDEX si_type_key ON site_identifiers (si_type, si_key); +CREATE INDEX si_site ON site_identifiers (si_site); +CREATE INDEX si_key ON site_identifiers (si_key); diff --git a/maintenance/preprocessDump.php b/maintenance/preprocessDump.php index 5952fd96..0dc19e28 100644 --- a/maintenance/preprocessDump.php +++ b/maintenance/preprocessDump.php @@ -25,7 +25,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/dumpIterator.php' ); +require_once __DIR__ . '/dumpIterator.php'; /** * Maintenance script that takes page text out of an XML dump file and @@ -78,15 +78,19 @@ class PreprocessDump extends DumpIterator { * @param $rev Revision */ public function processRevision( $rev ) { - try { - $this->mPreprocessor->preprocessToObj( $rev->getText(), 0 ); + $content = $rev->getContent( Revision::RAW ); + + if ( $content->getModel() !== CONTENT_MODEL_WIKITEXT ) { + return; } - catch(Exception $e) { - $this->error("Caught exception " . $e->getMessage() . " in " . $rev->getTitle()->getPrefixedText() ); + + try { + $this->mPreprocessor->preprocessToObj( strval( $content->getNativeData() ), 0 ); + } catch ( Exception $e ) { + $this->error( "Caught exception " . $e->getMessage() . " in " . $rev->getTitle()->getPrefixedText() ); } } } $maintClass = "PreprocessDump"; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/preprocessorFuzzTest.php b/maintenance/preprocessorFuzzTest.php index a53bc88c..563ea459 100644 --- a/maintenance/preprocessorFuzzTest.php +++ b/maintenance/preprocessorFuzzTest.php @@ -21,15 +21,15 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/commandLine.inc' ); +require_once __DIR__ . '/commandLine.inc'; $wgHooks['BeforeParserFetchTemplateAndtitle'][] = 'PPFuzzTester::templateHook'; class PPFuzzTester { - var $hairs = array( + public $hairs = array( '[[', ']]', '{{', '{{', '}}', '}}', '{{{', '}}}', '<', '>', '<nowiki', '<gallery', '</nowiki>', '</gallery>', '<nOwIkI>', '</NoWiKi>', - '<!--' , '-->', + '<!--', '-->', "\n==", "==\n", '|', '=', "\n", ' ', "\t", "\x7f", '~~', '~~~', '~~~~', 'subst:', @@ -39,12 +39,12 @@ class PPFuzzTester { // extensions // '<ref>', '</ref>', '<references/>', ); - var $minLength = 0; - var $maxLength = 20; - var $maxTemplates = 5; - // var $outputTypes = array( 'OT_HTML', 'OT_WIKI', 'OT_PREPROCESS' ); - var $entryPoints = array( 'testSrvus', 'testPst', 'testPreprocess' ); - var $verbose = false; + public $minLength = 0; + public $maxLength = 20; + public $maxTemplates = 5; + // public $outputTypes = array( 'OT_HTML', 'OT_WIKI', 'OT_PREPROCESS' ); + public $entryPoints = array( 'testSrvus', 'testPst', 'testPreprocess' ); + public $verbose = false; static $currentTest = false; function execute() { @@ -140,7 +140,7 @@ class PPFuzzTester { } class PPFuzzTest { - var $templates, $mainText, $title, $entryPoint, $output; + public $templates, $mainText, $title, $entryPoint, $output; function __construct( $tester ) { global $wgMaxSigChars; @@ -219,7 +219,7 @@ class PPFuzzTest { } class PPFuzzUser extends User { - var $ppfz_test, $mDataLoaded; + public $ppfz_test, $mDataLoaded; function load() { if ( $this->mDataLoaded ) { diff --git a/maintenance/protect.php b/maintenance/protect.php index 2f6aa1ae..ec03f934 100644 --- a/maintenance/protect.php +++ b/maintenance/protect.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that protects or unprotects a page. @@ -58,6 +58,7 @@ class Protect extends Maintenance { $this->error( "Invalid username", true ); } + // @todo FIXME: This is reset 7 lines down. $restrictions = array( 'edit' => $protection, 'move' => $protection ); $t = Title::newFromText( $this->getArg() ); @@ -66,7 +67,7 @@ class Protect extends Maintenance { } $restrictions = array(); - foreach( $t->getRestrictionTypes() as $type ) { + foreach ( $t->getRestrictionTypes() as $type ) { $restrictions[$type] = $protection; } @@ -85,4 +86,4 @@ class Protect extends Maintenance { } $maintClass = "Protect"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/proxy_check.php b/maintenance/proxy_check.php deleted file mode 100644 index 10892c42..00000000 --- a/maintenance/proxy_check.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -/** - * Command line script to check for an open proxy at a specified location. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * http://www.gnu.org/copyleft/gpl.html - * - * @file - * @ingroup Maintenance - */ - -if( php_sapi_name() != 'cli' ) { - die( 1 ); -} - -/** - * - */ -$output = ''; - -/** - * Exit if there are not enough parameters, or if it's not command line mode - */ -if ( ( isset( $_REQUEST ) && array_key_exists( 'argv', $_REQUEST ) ) || count( $argv ) < 4 ) { - $output .= "Incorrect parameters\n"; -} else { - /** - * Get parameters - */ - $ip = $argv[1]; - $port = $argv[2]; - $url = $argv[3]; - $host = trim(`hostname`); - $output = "Connecting to $ip:$port, target $url, this hostname $host\n"; - - # Open socket - $sock = @fsockopen($ip, $port, $errno, $errstr, 5); - if ($errno == 0 ) { - $output .= "Connected\n"; - # Send payload - $request = "GET $url HTTP/1.0\r\n"; -# $request .= "Proxy-Connection: Keep-Alive\r\n"; -# $request .= "Pragma: no-cache\r\n"; -# $request .= "Host: ".$url."\r\n"; -# $request .= "User-Agent: MediaWiki open proxy check\r\n"; - $request .= "\r\n"; - @fputs($sock, $request); - $response = fgets($sock, 65536); - $output .= $response; - @fclose($sock); - } else { - $output .= "No connection\n"; - } -} - -$output = escapeshellarg( $output ); - -#`echo $output >> /home/tstarling/open/proxy.log`; diff --git a/maintenance/pruneFileCache.php b/maintenance/pruneFileCache.php index e058e3ec..48d38977 100644 --- a/maintenance/pruneFileCache.php +++ b/maintenance/pruneFileCache.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that prunes file cache for pages, objects, resources, etc. @@ -108,4 +108,4 @@ class PruneFileCache extends Maintenance { } $maintClass = "PruneFileCache"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/purgeChangedFiles.php b/maintenance/purgeChangedFiles.php new file mode 100644 index 00000000..9f83ee7f --- /dev/null +++ b/maintenance/purgeChangedFiles.php @@ -0,0 +1,255 @@ +<?php +/** + * Scan the logging table and purge affected files within a timeframe. + * + * @section LICENSE + * 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 scans the deletion log and purges affected files + * within a timeframe. + * + * @ingroup Maintenance + */ +class PurgeChangedFiles extends Maintenance { + /** + * Mapping from type option to log type and actions. + * @var array + */ + private static $typeMappings = array( + 'created' => array( + 'upload' => array( 'upload' ), + 'import' => array( 'upload', 'interwiki' ), + ), + 'deleted' => array( + 'delete' => array( 'delete', 'revision' ), + 'suppress' => array( 'delete', 'revision' ), + ), + 'modified' => array( + 'upload' => array( 'overwrite', 'revert' ), + 'move' => array( 'move', 'move_redir' ), + ), + ); + + /** + * @var string + */ + private $startTimestamp; + + /** + * @var string + */ + private $endTimestamp; + + public function __construct() { + parent::__construct(); + $this->mDescription = "Scan the logging table and purge files and thumbnails."; + $this->addOption( 'starttime', 'Starting timestamp', true, true ); + $this->addOption( 'endtime', 'Ending timestamp', true, true ); + $this->addOption( 'type', 'Comma-separated list of types of changes to send purges for (' . + 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( 'verbose', 'Show more output', false, false, 'v' ); + } + + public function execute() { + global $wgHTCPRouting; + + if ( $this->hasOption( 'htcp-dest' ) ) { + $parts = explode( ':', $this->getOption( 'htcp-dest' ) ); + if ( count( $parts ) < 2 ) { + // Add default htcp port + $parts[] = '4827'; + } + + // Route all HTCP messages to provided host:port + $wgHTCPRouting = array( + '' => array( 'host' => $parts[0], 'port' => $parts[1] ), + ); + $this->verbose( "HTCP broadcasts to {$parts[0]}:{$parts[1]}\n" ); + } + + // Find out which actions we should be concerned with + $typeOpt = $this->getOption( 'type', 'all' ); + $validTypes = array_keys( self::$typeMappings ); + if ( $typeOpt === 'all' ) { + // Convert 'all' to all registered types + $typeOpt = implode( ',', $validTypes ); + } + $typeList = explode( ',', $typeOpt ); + foreach ( $typeList as $type ) { + if ( !in_array( $type, $validTypes ) ) { + $this->error( "\nERROR: Unknown type: {$type}\n" ); + $this->maybeHelp( true ); + } + } + + // Validate the timestamps + $dbr = $this->getDB( DB_SLAVE ); + $this->startTimestamp = $dbr->timestamp( $this->getOption( 'starttime' ) ); + $this->endTimestamp = $dbr->timestamp( $this->getOption( 'endtime' ) ); + + if ( $this->startTimestamp > $this->endTimestamp ) { + $this->error( "\nERROR: starttime after endtime\n" ); + $this->maybeHelp( true ); + } + + // Turn on verbose when dry-run is enabled + if ( $this->hasOption( 'dry-run' ) ) { + $this->mOptions['verbose'] = 1; + } + + $this->verbose( 'Purging files that were: ' . implode( ', ', $typeList ) . "\n"); + foreach ( $typeList as $type ) { + $this->verbose( "Checking for {$type} files...\n" ); + $this->purgeFromLogType( $type ); + if ( !$this->hasOption( 'dry-run' ) ) { + $this->verbose( "...{$type} files purged.\n\n" ); + } + } + } + + /** + * Purge cache and thumbnails for changes of the given type. + * + * @param string $type Type of change to find + */ + protected function purgeFromLogType( $type ) { + $repo = RepoGroup::singleton()->getLocalRepo(); + $dbr = $this->getDB( DB_SLAVE ); + + foreach ( self::$typeMappings[$type] as $logType => $logActions ) { + $this->verbose( "Scanning for {$logType}/" . implode( ',', $logActions ) . "\n" ); + + $res = $dbr->select( + 'logging', + array( 'log_title', 'log_timestamp', 'log_params' ), + array( + 'log_namespace' => NS_FILE, + 'log_type' => $logType, + 'log_action' => $logActions, + 'log_timestamp >= ' . $dbr->addQuotes( $this->startTimestamp ), + 'log_timestamp <= ' . $dbr->addQuotes( $this->endTimestamp ), + ), + __METHOD__ + ); + + foreach ( $res as $row ) { + $file = $repo->newFile( Title::makeTitle( NS_FILE, $row->log_title ) ); + + if ( $this->hasOption( 'dry-run' ) ) { + $this->verbose( "{$type}[{$row->log_timestamp}]: {$row->log_title}\n" ); + continue; + } + + // Purge current version and any versions in oldimage table + $file->purgeCache(); + $file->purgeHistory(); + + if ( $logType === 'delete' ) { + // If there is an orphaned storage file... delete it + if ( !$file->exists() && $repo->fileExists( $file->getPath() ) ) { + $dpath = $this->getDeletedPath( $repo, $file ); + if ( $repo->fileExists( $dpath ) ) { + // 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" ); + } + } + + // Purge items from fileachive table (rows are likely here) + $this->purgeFromArchiveTable( $repo, $file ); + + } else if ( $logType === 'move' ) { + // Purge the target file as well + + $params = unserialize( $row->log_params ); + if ( isset( $params['4::target'] ) ) { + $target = $params['4::target']; + $targetFile = $repo->newFile( Title::makeTitle( NS_FILE, $target ) ); + $targetFile->purgeCache(); + $targetFile->purgeHistory(); + $this->verbose( "Purged file {$target}; move target @{$row->log_timestamp}.\n" ); + } + } + + $this->verbose( "Purged file {$row->log_title}; {$type} @{$row->log_timestamp}.\n" ); + } + } + } + + protected function purgeFromArchiveTable( LocalRepo $repo, LocalFile $file ) { + $dbr = $repo->getSlaveDB(); + $res = $dbr->select( + 'filearchive', + array( 'fa_archive_name' ), + array( 'fa_name' => $file->getName() ), + __METHOD__ + ); + + foreach ( $res as $row ) { + if ( $row->fa_archive_name === null ) { + // Was not an old version (current version names checked already) + continue; + } + $ofile = $repo->newFromArchiveName( $file->getTitle(), $row->fa_archive_name ); + // If there is an orphaned storage file still there...delete it + if ( !$file->exists() && $repo->fileExists( $ofile->getPath() ) ) { + $dpath = $this->getDeletedPath( $repo, $ofile ); + if ( $repo->fileExists( $dpath ) ) { + // 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" ); + } + } + $file->purgeOldThumbnails( $row->fa_archive_name ); + } + } + + protected function getDeletedPath( LocalRepo $repo, LocalFile $file ) { + $hash = $repo->getFileSha1( $file->getPath() ); + $key = "{$hash}.{$file->getExtension()}"; + return $repo->getDeletedHashPath( $key ) . $key; + } + + /** + * Send an output message iff the 'verbose' option has been provided. + * + * @param string $msg Message to output + */ + protected function verbose( $msg ) { + if ( $this->hasOption( 'verbose' ) ) { + $this->output( $msg ); + } + } + +} + +$maintClass = "PurgeChangedFiles"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/purgeChangedPages.php b/maintenance/purgeChangedPages.php new file mode 100644 index 00000000..071ac09c --- /dev/null +++ b/maintenance/purgeChangedPages.php @@ -0,0 +1,191 @@ +<?php +/** + * Send purge requests for pages edited in date range to squid/varnish. + * + * @section LICENSE + * 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 sends purge requests for pages edited in a date + * range to squid/varnish. + * + * Can be used to recover from an HTCP message partition or other major cache + * layer interruption. + * + * @ingroup Maintenance + */ +class PurgeChangedPages extends Maintenance { + + public function __construct() { + parent::__construct(); + $this->mDescription = 'Send purge requests for edits in date range to squid/varnish'; + $this->addOption( 'starttime', 'Starting timestamp', true, true ); + $this->addOption( 'endtime', 'Ending timestamp', true, true ); + $this->addOption( 'htcp-dest', 'HTCP announcement destination (IP:port)', false, true ); + $this->addOption( 'sleep-per-batch', 'Milliseconds to sleep between batches', false, true ); + $this->addOption( 'dry-run', 'Do not send purge requests' ); + $this->addOption( 'verbose', 'Show more output', false, false, 'v' ); + $this->setBatchSize( 100 ); + } + + public function execute() { + global $wgHTCPRouting; + + if ( $this->hasOption( 'htcp-dest' ) ) { + $parts = explode( ':', $this->getOption( 'htcp-dest' ) ); + if ( count( $parts ) < 2 ) { + // Add default htcp port + $parts[] = '4827'; + } + + // Route all HTCP messages to provided host:port + $wgHTCPRouting = array( + '' => array( 'host' => $parts[0], 'port' => $parts[1] ), + ); + if ( $this->hasOption( 'verbose' ) ) { + $this->output( "HTCP broadcasts to {$parts[0]}:{$parts[1]}\n" ); + } + } + + $dbr = $this->getDB( DB_SLAVE ); + $minTime = $dbr->timestamp( $this->getOption( 'starttime' ) ); + $maxTime = $dbr->timestamp( $this->getOption( 'endtime' ) ); + + if ( $maxTime < $minTime ) { + $this->error( "\nERROR: starttime after endtime\n" ); + $this->maybeHelp( true ); + } + + $stuckCount = 0; // loop breaker + while ( true ) { + // Adjust bach size if we are stuck in a second that had many changes + $bSize = $this->mBatchSize + ( $stuckCount * $this->mBatchSize ); + + $res = $dbr->select( + array( 'page', 'revision' ), + array( + 'rev_timestamp', + 'page_namespace', + 'page_title', + ), + array( + "rev_timestamp > " . $dbr->addQuotes( $minTime ), + "rev_timestamp <= " . $dbr->addQuotes( $maxTime ), + // Only get rows where the revision is the latest for the page. + // Other revisions would be duplicate and we don't need to purge if + // there has been an edit after the interesting time window. + "page_latest = rev_id", + ), + __METHOD__, + array( 'ORDER BY' => 'rev_timestamp', 'LIMIT' => $bSize ), + array( + 'page' => array( 'INNER JOIN', 'rev_page=page_id' ), + ) + ); + + if ( !$res->numRows() ) { + // nothing more found so we are done + break; + } + + // Kludge to not get stuck in loops for batches with the same timestamp + list( $rows, $lastTime ) = $this->pageableSortedRows( $res, 'rev_timestamp', $bSize ); + if ( !count( $rows ) ) { + ++$stuckCount; + continue; + } + // Reset suck counter + $stuckCount = 0; + + $this->output( "Processing changes from {$minTime} to {$lastTime}.\n" ); + + // Advance past the last row next time + $minTime = $lastTime; + + // Create list of URLs from page_namespace + page_title + $urls = array(); + foreach ( $rows as $row ) { + $title = Title::makeTitle( $row->page_namespace, $row->page_title ); + $urls[] = $title->getInternalURL(); + } + + if ( $this->hasOption( 'dry-run' ) || $this->hasOption( 'verbose' ) ) { + $this->output( implode( "\n", $urls ) . "\n" ); + if ( $this->hasOption( 'dry-run' ) ) { + continue; + } + } + + // Send batch of purge requests out to squids + $squid = new SquidUpdate( $urls, count( $urls ) ); + $squid->doUpdate(); + + if ( $this->hasOption( 'sleep-per-batch' ) ) { + // sleep-per-batch is milliseconds, usleep wants micro seconds. + usleep( 1000 * (int)$this->getOption( 'sleep-per-batch' ) ); + } + } + + $this->output( "Done!\n" ); + } + + /** + * Remove all the rows in a result set with the highest value for column + * $column unless the number of rows is less $limit. This returns the new + * array of rows and the highest value of column $column for the rows left. + * The ordering of rows is maintained. + * + * This is useful for paging on mostly-unique values that may sometimes + * have large clumps of identical values. It should be safe to do the next + * query on items with a value higher than the highest of the rows returned here. + * 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 + * + * @param ResultWrapper $res Query result sorted by $column (ascending) + * @param string $column + * @return array (array of rows, string column value) + */ + protected function pageableSortedRows( ResultWrapper $res, $column, $limit ) { + $rows = iterator_to_array( $res, false ); + $count = count( $rows ); + if ( !$count ) { + return array( array(), null ); // nothing to do + } elseif ( $count < $limit ) { + return array( $rows, $rows[$count - 1]->$column ); // no more rows left + } + $lastValue = $rows[$count - 1]->$column; // should be the highest + for ( $i = $count - 1; $i >= 0; --$i ) { + if ( $rows[$i]->$column === $lastValue ) { + unset( $rows[$i] ); + } else { + break; + } + } + $lastValueLeft = count( $rows ) ? $rows[count( $rows ) - 1]->$column : null; + return array( $rows, $lastValueLeft ); + } +} + +$maintClass = "PurgeChangedPages"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/purgeDeletedFiles.php b/maintenance/purgeDeletedFiles.php deleted file mode 100644 index cd62716b..00000000 --- a/maintenance/purgeDeletedFiles.php +++ /dev/null @@ -1,96 +0,0 @@ -<?php -/** - * Scan the deletion log and purges affected files within a timeframe. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * 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 scans the deletion log and purges affected files - * within a timeframe. - * - * @ingroup Maintenance - */ -class PurgeDeletedFiles extends Maintenance { - public function __construct() { - parent::__construct(); - $this->mDescription = "Scan the logging table and purge files that where deleted."; - $this->addOption( 'starttime', 'Starting timestamp', false, true ); - $this->addOption( 'endtime', 'Ending timestamp', false, true ); - } - - public function execute() { - $this->output( "Purging cache and thumbnails for deleted files...\n" ); - $this->purgeFromLogType( 'delete' ); - $this->output( "...deleted files purged.\n\n" ); - - $this->output( "Purging cache and thumbnails for suppressed files...\n" ); - $this->purgeFromLogType( 'suppress' ); - $this->output( "...suppressed files purged.\n" ); - } - - protected function purgeFromLogType( $logType ) { - $repo = RepoGroup::singleton()->getLocalRepo(); - $db = $repo->getSlaveDB(); - - $conds = array( - 'log_namespace' => NS_FILE, - 'log_type' => $logType, - 'log_action' => array( 'delete', 'revision' ) - ); - $start = $this->getOption( 'starttime' ); - if ( $start ) { - $conds[] = 'log_timestamp >= ' . $db->addQuotes( $db->timestamp( $start ) ); - } - $end = $this->getOption( 'endtime' ); - if ( $end ) { - $conds[] = 'log_timestamp <= ' . $db->addQuotes( $db->timestamp( $end ) ); - } - - $res = $db->select( 'logging', array( 'log_title', 'log_timestamp' ), $conds, __METHOD__ ); - foreach ( $res as $row ) { - $file = $repo->newFile( Title::makeTitle( NS_FILE, $row->log_title ) ); - - // Purge current version and any versions in oldimage table - $file->purgeCache(); - $file->purgeHistory(); - // Purge items from fileachive table (rows are likely here) - $this->purgeFromArchiveTable( $file ); - - $this->output( "Purged file {$row->log_title}; deleted on {$row->log_timestamp}.\n" ); - } - } - - protected function purgeFromArchiveTable( LocalFile $file ) { - $db = $file->getRepo()->getSlaveDB(); - $res = $db->select( 'filearchive', - array( 'fa_archive_name' ), - array( 'fa_name' => $file->getName() ), - __METHOD__ - ); - foreach ( $res as $row ) { - $file->purgeOldThumbnails( $row->fa_archive_name ); - } - } -} - -$maintClass = "PurgeDeletedFiles"; -require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/purgeList.php b/maintenance/purgeList.php index 4b3c3821..2f895201 100644 --- a/maintenance/purgeList.php +++ b/maintenance/purgeList.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that sends purge requests for listed pages to squid. @@ -32,22 +32,27 @@ class PurgeList extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Send purge requests for listed pages to squid"; - $this->addOption( 'purge', 'Whether to update page_touched.' , false, false ); + $this->addOption( 'purge', 'Whether to update page_touched.', false, false ); $this->addOption( 'namespace', 'Namespace number', false, true ); + $this->addOption( 'all', 'Purge all pages', false, false ); + $this->addOption( 'delay', 'Number of seconds to delay between each purge', false, true ); + $this->addOption( 'verbose', 'Show more output', false, false, 'v' ); $this->setBatchSize( 100 ); } public function execute() { - if( $this->hasOption( 'namespace' ) ) { - $this->purgeNamespace(); + if ( $this->hasOption( 'all' ) ) { + $this->purgeNamespace( false ); + } elseif ( $this->hasOption( 'namespace' ) ) { + $this->purgeNamespace( intval( $this->getOption( 'namespace' ) ) ); } else { - $this->purgeList(); + $this->doPurge(); } $this->output( "Done!\n" ); } /** Purge URL coming from stdin */ - private function purgeList() { + private function doPurge() { $stdin = $this->getStdin(); $urls = array(); @@ -58,7 +63,7 @@ class PurgeList extends Maintenance { } elseif ( $page !== '' ) { $title = Title::newFromText( $page ); if ( $title ) { - $url = $title->getInternalUrl(); + $url = $title->getInternalURL(); $this->output( "$url\n" ); $urls[] = $url; if ( $this->getOption( 'purge' ) ) { @@ -69,56 +74,41 @@ class PurgeList extends Maintenance { } } } + $this->output( "Purging " . count( $urls ) . " urls\n" ); $this->sendPurgeRequest( $urls ); } - /** Purge a namespace given by --namespace */ - private function purgeNamespace() { + /** Purge a namespace or all pages */ + private function purgeNamespace( $namespace = false ) { $dbr = wfGetDB( DB_SLAVE ); - $ns = $dbr->addQuotes( $this->getOption( 'namespace') ); - - $result = $dbr->select( - array( 'page' ), - array( 'page_namespace', 'page_title' ), - array( "page_namespace = $ns" ), - __METHOD__, - array( 'ORDER BY' => 'page_id' ) - ); - - $start = 0; - $end = $dbr->numRows( $result ); - $this->output( "Will purge $end pages from namespace $ns\n" ); - - # Do remaining chunk - $end += $this->mBatchSize - 1; - $blockStart = $start; - $blockEnd = $start + $this->mBatchSize - 1; - - while( $blockEnd <= $end ) { - # Select pages we will purge: - $result = $dbr->select( - array( 'page' ), - array( 'page_namespace', 'page_title' ), - array( "page_namespace = $ns" ), + $startId = 0; + if ( $namespace === false ) { + $conds = array(); + } else { + $conds = array( 'page_namespace' => $namespace ); + } + while ( true ) { + $res = $dbr->select( 'page', + array( 'page_id', 'page_namespace', 'page_title' ), + $conds + array( 'page_id > ' . $dbr->addQuotes( $startId ) ), __METHOD__, - array( # conditions - 'ORDER BY' => 'page_id', - 'LIMIT' => $this->mBatchSize, - 'OFFSET' => $blockStart, + array( + 'LIMIT' => $this->mBatchSize, + 'ORDER BY' => 'page_id' + ) ); - # Initialize/reset URLs to be purged + if ( !$res->numRows() ) { + break; + } $urls = array(); - foreach( $result as $row ) { + foreach ( $res as $row ) { $title = Title::makeTitle( $row->page_namespace, $row->page_title ); - $url = $title->getInternalUrl(); + $url = $title->getInternalURL(); $urls[] = $url; + $startId = $row->page_id; } - $this->sendPurgeRequest( $urls ); - - $blockStart += $this->mBatchSize; - $blockEnd += $this->mBatchSize; } } @@ -127,12 +117,26 @@ class PurgeList extends Maintenance { * @param $urls array List of URLS to purge from squids */ private function sendPurgeRequest( $urls ) { - $this->output( "Purging " . count( $urls ). " urls\n" ); - $u = new SquidUpdate( $urls ); - $u->doUpdate(); + if ( $this->hasOption( 'delay' ) ) { + $delay = floatval( $this->getOption( 'delay' ) ); + foreach ( $urls as $url ) { + if ( $this->hasOption( 'verbose' ) ) { + $this->output( $url . "\n" ); + } + $u = new SquidUpdate( array( $url ) ); + $u->doUpdate(); + usleep( $delay * 1e6 ); + } + } else { + if ( $this->hasOption( 'verbose' ) ) { + $this->output( implode( "\n", $urls ) . "\n" ); + } + $u = new SquidUpdate( $urls ); + $u->doUpdate(); + } } } $maintClass = "PurgeList"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/purgeOldText.inc b/maintenance/purgeOldText.inc index 111c786a..db961d81 100644 --- a/maintenance/purgeOldText.inc +++ b/maintenance/purgeOldText.inc @@ -34,42 +34,42 @@ function PurgeRedundantText( $delete = false ) { $tbl_txt = $dbw->tableName( 'text' ); # Get "active" text records from the revisions table - echo( "Searching for active text records in 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" ); + echo "done.\n"; # Get "active" text records from the archive table - echo( "Searching for active text records in 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" ); + echo "done.\n"; # Get the IDs of all text records not in these sets - echo( "Searching for inactive text records..." ); + 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" ); + echo "done.\n"; # Inform the user of what we're going to do $count = count( $old ); - echo( "$count inactive items found.\n" ); + echo "$count inactive items found.\n"; # Delete as appropriate if ( $delete && $count ) { - echo( "Deleting..." ); + echo "Deleting..."; $set = implode( ', ', $old ); $dbw->query( "DELETE FROM $tbl_txt WHERE old_id IN ( $set )" ); - echo( "done.\n" ); + echo "done.\n"; } # Done diff --git a/maintenance/purgeOldText.php b/maintenance/purgeOldText.php index 1f0b063b..3d81e2df 100644 --- a/maintenance/purgeOldText.php +++ b/maintenance/purgeOldText.php @@ -22,7 +22,7 @@ * @author Rob Church <robchur@gmail.com> */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that purges old text records from the database. @@ -42,4 +42,4 @@ class PurgeOldText extends Maintenance { } $maintClass = "PurgeOldText"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/purgeParserCache.php b/maintenance/purgeParserCache.php index 1c417980..ca2a0414 100644 --- a/maintenance/purgeParserCache.php +++ b/maintenance/purgeParserCache.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require( __DIR__ . '/Maintenance.php' ); +require __DIR__ . '/Maintenance.php'; /** * Maintenance script to remove old objects from the parser cache. @@ -30,7 +30,7 @@ require( __DIR__ . '/Maintenance.php' ); * @ingroup Maintenance */ class PurgeParserCache extends Maintenance { - var $lastProgress; + public $lastProgress; function __construct() { parent::__construct(); @@ -52,21 +52,19 @@ class PurgeParserCache extends Maintenance { global $wgParserCacheExpireTime; $date = wfTimestamp( TS_MW, time() + $wgParserCacheExpireTime - intval( $inputAge ) ); } else { - echo "Must specify either --expiredate or --age\n"; - exit( 1 ); + $this->error( "Must specify either --expiredate or --age", 1 ); } $english = Language::factory( 'en' ); - echo "Deleting objects expiring before " . $english->timeanddate( $date ) . "\n"; + $this->output( "Deleting objects expiring before " . $english->timeanddate( $date ) . "\n" ); $pc = wfGetParserCacheStorage(); $success = $pc->deleteObjectsExpiringBefore( $date, array( $this, 'showProgress' ) ); if ( !$success ) { - echo "\nCannot purge this kind of parser cache.\n"; - exit( 1 ); + $this->error( "\nCannot purge this kind of parser cache.", 1 ); } $this->showProgress( 100 ); - echo "\nDone\n"; + $this->output( "\nDone\n" ); } function showProgress( $percent ) { @@ -77,10 +75,10 @@ class PurgeParserCache extends Maintenance { $this->lastProgress = $percentString; $stars = floor( $percent / 2 ); - echo '[' . str_repeat( '*', $stars ), str_repeat( '.', 50 - $stars ) . '] ' . - "$percentString%\r"; + $this->output( '[' . str_repeat( '*', $stars ) . str_repeat( '.', 50 - $stars ) . '] ' . + "$percentString%\r" ); } } $maintClass = 'PurgeParserCache'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/reassignEdits.php b/maintenance/reassignEdits.php index a91abf93..7e15c09e 100644 --- a/maintenance/reassignEdits.php +++ b/maintenance/reassignEdits.php @@ -23,7 +23,7 @@ * @licence GNU General Public Licence 2.0 or later */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that reassigns edits from a user or IP address @@ -46,7 +46,7 @@ class ReassignEdits extends Maintenance { if ( $this->hasArg( 0 ) && $this->hasArg( 1 ) ) { # Set up the users involved $from = $this->initialiseUser( $this->getArg( 0 ) ); - $to = $this->initialiseUser( $this->getArg( 1 ) ); + $to = $this->initialiseUser( $this->getArg( 1 ) ); # If the target doesn't exist, and --force is not set, stop here if ( $to->getId() || $this->hasOption( 'force' ) ) { @@ -179,5 +179,4 @@ class ReassignEdits extends Maintenance { } $maintClass = "ReassignEdits"; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/rebuildFileCache.php b/maintenance/rebuildFileCache.php index 3165b97f..12ed9fac 100644 --- a/maintenance/rebuildFileCache.php +++ b/maintenance/rebuildFileCache.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that builds file cache for content pages. @@ -153,10 +153,11 @@ class RebuildFileCache extends Maintenance { $this->output( "Done!\n" ); // Remove these to be safe - if ( isset( $wgTitle ) ) + if ( isset( $wgTitle ) ) { unset( $wgTitle ); + } } } $maintClass = "RebuildFileCache"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/rebuildImages.php b/maintenance/rebuildImages.php index 2842b402..53bf823f 100644 --- a/maintenance/rebuildImages.php +++ b/maintenance/rebuildImages.php @@ -30,7 +30,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to update image metadata records. @@ -217,4 +217,4 @@ class ImageBuilder extends Maintenance { } $maintClass = 'ImageBuilder'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/rebuildLocalisationCache.php b/maintenance/rebuildLocalisationCache.php index 83849de6..b7f306b1 100644 --- a/maintenance/rebuildLocalisationCache.php +++ b/maintenance/rebuildLocalisationCache.php @@ -29,7 +29,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to rebuild the localisation cache. @@ -44,6 +44,8 @@ class RebuildLocalisationCache extends Maintenance { $this->addOption( 'threads', 'Fork more than one thread', false, true ); $this->addOption( 'outdir', 'Override the output directory (normally $wgCacheDirectory)', false, true ); + $this->addOption( 'lang', 'Only rebuild these languages, comma separated.', + false, true ); } public function memoryLimit() { @@ -53,6 +55,15 @@ class RebuildLocalisationCache extends Maintenance { return '1000M'; } + public function finalSetup() { + # This script needs to be run to build the inital l10n cache. But if + # $wgLanguageCode is not 'en', it won't be able to run because there is + # no l10n cache. Break the cycle by forcing $wgLanguageCode = 'en'. + global $wgLanguageCode; + $wgLanguageCode = 'en'; + parent::finalSetup(); + } + public function execute() { global $wgLocalisationCacheConf; @@ -81,7 +92,19 @@ class RebuildLocalisationCache extends Maintenance { } $lc = new LocalisationCache_BulkLoad( $conf ); - $codes = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) ); + $allCodes = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) ); + if ( $this->hasOption( 'lang' ) ) { + # Validate requested languages + $codes = array_intersect( $allCodes, + explode( ',', $this->getOption( 'lang' ) ) ); + # Bailed out if nothing is left + if ( count( $codes ) == 0 ) { + $this->error( 'None of the languages specified exists.', 1 ); + } + } else { + # By default get all languages + $codes = $allCodes; + } sort( $codes ); // Initialise and split into chunks @@ -153,4 +176,4 @@ class RebuildLocalisationCache extends Maintenance { } $maintClass = "RebuildLocalisationCache"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/rebuildall.php b/maintenance/rebuildall.php index 882ae1b3..1268d209 100644 --- a/maintenance/rebuildall.php +++ b/maintenance/rebuildall.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that rebuilds link tracking tables from scratch. @@ -35,6 +35,10 @@ class RebuildAll extends Maintenance { $this->mDescription = "Rebuild links, text index and recent changes"; } + public function getDbType() { + return Maintenance::DB_ADMIN; + } + public function execute() { // Rebuild the text index if ( wfGetDB( DB_SLAVE )->getType() != 'postgres' ) { @@ -58,4 +62,4 @@ class RebuildAll extends Maintenance { } $maintClass = "RebuildAll"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/rebuildmessages.php b/maintenance/rebuildmessages.php index a70e591f..f223f1ab 100644 --- a/maintenance/rebuildmessages.php +++ b/maintenance/rebuildmessages.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that purges all languages from the message cache. @@ -45,12 +45,13 @@ class RebuildMessages extends Maintenance { foreach ( $databases as $db ) { $this->output( "Deleting message cache for {$db}... " ); $messageMemc->delete( "{$db}:messages" ); - if ( $wgEnableSidebarCache ) + if ( $wgEnableSidebarCache ) { $messageMemc->delete( "{$db}:sidebar" ); + } $this->output( "Deleted\n" ); } } } $maintClass = "RebuildMessages"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/rebuildrecentchanges.php b/maintenance/rebuildrecentchanges.php index 0278f72c..18348258 100644 --- a/maintenance/rebuildrecentchanges.php +++ b/maintenance/rebuildrecentchanges.php @@ -23,7 +23,7 @@ * @todo Document */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that rebuilds recent changes from scratch. @@ -61,9 +61,9 @@ class RebuildRecentchanges extends Maintenance { $this->output( '$wgRCMaxAge=' . $wgRCMaxAge ); $days = $wgRCMaxAge / 24 / 3600; if ( intval( $days ) == $days ) { - $this->output( " (" . $days . " days)\n" ); + $this->output( " (" . $days . " days)\n" ); } else { - $this->output( " (approx. " . intval( $days ) . " days)\n" ); + $this->output( " (approx. " . intval( $days ) . " days)\n" ); } $cutoff = time() - $wgRCMaxAge; @@ -99,13 +99,13 @@ class RebuildRecentchanges extends Maintenance { */ private function rebuildRecentChangesTablePass2() { $dbw = wfGetDB( DB_MASTER ); - list ( $recentchanges, $revision ) = $dbw->tableNamesN( 'recentchanges', 'revision' ); + list( $recentchanges, $revision ) = $dbw->tableNamesN( 'recentchanges', 'revision' ); $this->output( "Updating links and size differences...\n" ); # Fill in the rc_last_oldid field, which points to the previous edit $sql = "SELECT rc_cur_id,rc_this_oldid,rc_timestamp FROM $recentchanges " . - "ORDER BY rc_cur_id,rc_timestamp"; + "ORDER BY rc_cur_id,rc_timestamp"; $res = $dbw->query( $sql, DB_MASTER ); $lastCurId = 0; @@ -142,12 +142,12 @@ class RebuildRecentchanges extends Maintenance { $dbw->update( 'recentchanges', array( 'rc_last_oldid' => $lastOldId, - 'rc_new' => $new, - 'rc_type' => $new, - 'rc_old_len' => $lastSize, - 'rc_new_len' => $size, + 'rc_new' => $new, + 'rc_type' => $new, + 'rc_old_len' => $lastSize, + 'rc_new_len' => $size, ), array( - 'rc_cur_id' => $lastCurId, + 'rc_cur_id' => $lastCurId, 'rc_this_oldid' => $obj->rc_this_oldid, ), __METHOD__ @@ -218,24 +218,17 @@ class RebuildRecentchanges extends Maintenance { * DOCUMENT ME! */ private function rebuildRecentChangesTablePass4() { - global $wgGroupPermissions, $wgUseRCPatrol; + global $wgUseRCPatrol; $dbw = wfGetDB( DB_MASTER ); list( $recentchanges, $usergroups, $user ) = $dbw->tableNamesN( 'recentchanges', 'user_groups', 'user' ); - $botgroups = $autopatrolgroups = array(); - foreach ( $wgGroupPermissions as $group => $rights ) { - if ( isset( $rights['bot'] ) && $rights['bot'] ) { - $botgroups[] = $dbw->addQuotes( $group ); - } - if ( $wgUseRCPatrol && isset( $rights['autopatrol'] ) && $rights['autopatrol'] ) { - $autopatrolgroups[] = $dbw->addQuotes( $group ); - } - } + $botgroups = User::getGroupsWithPermission( 'bot' ); + $autopatrolgroups = $wgUseRCPatrol ? User::getGroupsWithPermission( 'autopatrol' ) : array(); # Flag our recent bot edits if ( !empty( $botgroups ) ) { - $botwhere = implode( ',', $botgroups ); + $botwhere = $dbw->makeList( $botgroups ); $botusers = array(); $this->output( "Flagging bot account edits...\n" ); @@ -259,7 +252,7 @@ class RebuildRecentchanges extends Maintenance { global $wgMiserMode; # Flag our recent autopatrolled edits if ( !$wgMiserMode && !empty( $autopatrolgroups ) ) { - $patrolwhere = implode( ',', $autopatrolgroups ); + $patrolwhere = $dbw->makeList( $autopatrolgroups ); $patrolusers = array(); $this->output( "Flagging auto-patrolled edits...\n" ); @@ -299,4 +292,4 @@ class RebuildRecentchanges extends Maintenance { } $maintClass = "RebuildRecentchanges"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/rebuildtextindex.php b/maintenance/rebuildtextindex.php index 41b245f8..c651f720 100644 --- a/maintenance/rebuildtextindex.php +++ b/maintenance/rebuildtextindex.php @@ -25,7 +25,7 @@ * @todo document */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that rebuilds search index table from scratch. @@ -92,22 +92,36 @@ class RebuildTextIndex extends Maintenance { $this->output( "Rebuilding index fields for {$count} pages...\n" ); $n = 0; + $fields = array_merge( + Revision::selectPageFields(), + Revision::selectFields(), + Revision::selectTextFields() + ); + while ( $n < $count ) { if ( $n ) { $this->output( $n . "\n" ); } $end = $n + self::RTI_CHUNK_SIZE - 1; - $res = $this->db->select( array( 'page', 'revision', 'text' ), - array( 'page_id', 'page_namespace', 'page_title', 'old_flags', 'old_text' ), + $res = $this->db->select( array( 'page', 'revision', 'text' ), $fields, array( "page_id BETWEEN $n AND $end", 'page_latest = rev_id', 'rev_text_id = old_id' ), __METHOD__ - ); + ); foreach ( $res as $s ) { - $revtext = Revision::getRevisionText( $s ); - $u = new SearchUpdate( $s->page_id, $s->page_title, $revtext ); - $u->doUpdate(); + try { + $title = Title::makeTitle( $s->page_namespace, $s->page_title ); + + $rev = new Revision( $s ); + $content = $rev->getContent(); + + $u = new SearchUpdate( $s->page_id, $title, $content ); + $u->doUpdate(); + } catch ( MWContentSerializationException $ex ) { + $this->output( "Failed to deserialize content of revision {$s->rev_id} of page " + . "`" . $title->getPrefixedDBkey() . "`!\n" ); + } } $n += self::RTI_CHUNK_SIZE; } @@ -132,7 +146,7 @@ class RebuildTextIndex extends Maintenance { $searchindex = $this->db->tableName( 'searchindex' ); $this->output( "\nRebuild the index...\n" ); $sql = "ALTER TABLE $searchindex ADD FULLTEXT si_title (si_title), " . - "ADD FULLTEXT si_text (si_text)"; + "ADD FULLTEXT si_text (si_text)"; $this->db->query( $sql, __METHOD__ ); } @@ -147,4 +161,4 @@ class RebuildTextIndex extends Maintenance { } $maintClass = "RebuildTextIndex"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/refreshFileHeaders.php b/maintenance/refreshFileHeaders.php new file mode 100644 index 00000000..8b852e39 --- /dev/null +++ b/maintenance/refreshFileHeaders.php @@ -0,0 +1,93 @@ +<?php +/** + * Refresh file headers from metadata. + * + * Usage: php refreshFileHeaders.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 + * @ingroup Maintenance + */ + +require_once __DIR__ . '/Maintenance.php'; + +/** + * Maintenance script to refresh file headers from metadata + * + * @ingroup Maintenance + */ +class RefreshFileHeaders extends Maintenance { + function __construct() { + parent::__construct(); + $this->mDescription = 'Script to update file HTTP headers'; + $this->addOption( 'verbose', 'Output information about each 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->setBatchSize( 200 ); + } + + public function execute() { + $repo = RepoGroup::singleton()->getLocalRepo(); + $start = str_replace( ' ', '_', $this->getOption( 'start', '' ) ); // page on img_name + $end = str_replace( ' ', '_', $this->getOption( 'end', '' ) ); // page on img_name + + $count = 0; + $dbr = wfGetDB( DB_SLAVE ); + do { + $conds = array( "img_name > {$dbr->addQuotes( $start )}" ); + if ( strlen( $end ) ) { + $conds[] = "img_name <= {$dbr->addQuotes( $end )}"; + } + $res = $dbr->select( 'image', '*', $conds, + __METHOD__, array( 'LIMIT' => $this->mBatchSize, 'ORDER BY' => 'img_name ASC' ) ); + foreach ( $res as $row ) { + $file = $repo->newFileFromRow( $row ); + $headers = $file->getStreamHeaders(); + if ( count( $headers ) ) { + $this->updateFileHeaders( $file, $headers ); + } + // Do all of the older file versions... + foreach ( $file->getHistory() as $oldFile ) { + $headers = $oldFile->getStreamHeaders(); + if ( count( $headers ) ) { + $this->updateFileHeaders( $oldFile, $headers ); + } + } + if ( $this->hasOption( 'verbose' ) ) { + $this->output( "Updated headers for file '{$row->img_name}'.\n" ); + } + ++$count; + $start = $row->img_name; // advance + } + } while ( $res->numRows() > 0 ); + + $this->output( "Done. Updated headers for $count file(s).\n" ); + } + + protected function updateFileHeaders( File $file, array $headers ) { + $status = $file->getRepo()->getBackend()->describe( array( + 'src' => $file->getPath(), 'headers' => $headers + ) ); + if ( !$status->isGood() ) { + $this->error( "Encountered error: " . print_r( $status, true ) ); + } + } +} + +$maintClass = 'RefreshFileHeaders'; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/refreshImageMetadata.php b/maintenance/refreshImageMetadata.php index 12da7a8b..7fe5c4c1 100644 --- a/maintenance/refreshImageMetadata.php +++ b/maintenance/refreshImageMetadata.php @@ -27,7 +27,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to refresh image metadata fields. @@ -53,7 +53,7 @@ class RefreshImageMetadata extends Maintenance { $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( '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 ); } @@ -99,7 +99,7 @@ class RefreshImageMetadata extends Maintenance { if ( $res->numRows() > 0 ) { $row1 = $res->current(); - $this->output( "Processing next {$this->mBatchSize} rows starting with {$row1->img_name}.\n"); + $this->output( "Processing next {$this->mBatchSize} rows starting with {$row1->img_name}.\n" ); $res->rewind(); } else { $this->error( "No images to process.", 4 ); @@ -123,7 +123,7 @@ class RefreshImageMetadata extends Maintenance { $this->output( "Warning: File:{$row->img_name} used to have " . "$oldLength bytes of metadata but now has $newLength bytes.\n" ); } elseif ( $verbose ) { - $this->output("Refreshed File:{$row->img_name}.\n" ); + $this->output( "Refreshed File:{$row->img_name}.\n" ); } } else { $leftAlone++; @@ -138,7 +138,7 @@ class RefreshImageMetadata extends Maintenance { } if ( $verbose ) { - $this->output("Forcibly refreshed File:{$row->img_name}.\n" ); + $this->output( "Forcibly refreshed File:{$row->img_name}.\n" ); } } else { @@ -151,7 +151,7 @@ class RefreshImageMetadata extends Maintenance { } $conds2 = array( 'img_name > ' . $dbw->addQuotes( $row->img_name ) ); wfWaitForSlaves(); - } while( $res->numRows() === $this->mBatchSize ); + } while ( $res->numRows() === $this->mBatchSize ); $total = $upgraded + $leftAlone; if ( $force ) { @@ -173,7 +173,7 @@ class RefreshImageMetadata extends Maintenance { $like = $this->getOption( 'metadata-contains', false ); if ( $end !== false ) { - $conds[] = 'img_name <= ' . $dbw->addQuotes( $end ) ; + $conds[] = 'img_name <= ' . $dbw->addQuotes( $end ); } if ( $mime !== false ) { list( $major, $minor ) = File::splitMime( $mime ); @@ -209,4 +209,4 @@ class RefreshImageMetadata extends Maintenance { $maintClass = 'RefreshImageMetadata'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/refreshLinks.php b/maintenance/refreshLinks.php index 3d9270b8..98ea9301 100644 --- a/maintenance/refreshLinks.php +++ b/maintenance/refreshLinks.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to refresh link tables. @@ -105,7 +105,7 @@ class RefreshLinks extends Maintenance { array(), array( 'redirect' => array( "LEFT JOIN", "page_id=rd_from" ) ) ); - $num = $dbr->numRows( $res ); + $num = $res->numRows(); $this->output( "Refreshing $num old redirects from $start...\n" ); $i = 0; @@ -126,7 +126,7 @@ class RefreshLinks extends Maintenance { "page_id >= $start" ), __METHOD__ ); - $num = $dbr->numRows( $res ); + $num = $res->numRows(); $this->output( "$num new articles...\n" ); $i = 0; @@ -160,7 +160,7 @@ class RefreshLinks extends Maintenance { } if ( !$redirectsOnly ) { - $this->output( "Refreshing links table.\n" ); + $this->output( "Refreshing links tables.\n" ); $this->output( "Starting from page_id $start of $end.\n" ); for ( $id = $start; $id <= $end; $id++ ) { @@ -176,8 +176,16 @@ class RefreshLinks extends Maintenance { } /** - * Update the redirect entry for a given page - * @param $id int The page_id of the redirect + * Update the redirect entry for a given page. + * + * This methods bypasses the "redirect" table to get the redirect target, + * and parses the page's content to fetch it. This allows to be sure that + * the redirect target is up to date and valid. + * This is particularly useful when modifying namespaces to be sure the + * entry in the "redirect" table points to the correct page and not to an + * invalid one. + * + * @param $id int The page ID to check */ private function fixRedirect( $id ) { $page = WikiPage::newFromID( $id ); @@ -191,14 +199,25 @@ class RefreshLinks extends Maintenance { return; } - $rt = $page->getRedirectTarget(); + $rt = null; + $content = $page->getContent( Revision::RAW ); + if ( $content !== null ) { + $rt = $content->getUltimateRedirectTarget(); + } if ( $rt === null ) { // The page is not a redirect // Delete any redirect table entry for it - $dbw->delete( 'redirect', array( 'rd_from' => $id ), - __METHOD__ ); + $dbw->delete( 'redirect', array( 'rd_from' => $id ), __METHOD__ ); + $fieldValue = 0; + } else { + $page->insertRedirectEntry( $rt ); + $fieldValue = 1; } + + // Update the page table to be sure it is an a consistent state + $dbw->update( 'page', array( 'page_is_redirect' => $fieldValue ), + array( 'page_id' => $id ), __METHOD__ ); } /** @@ -206,8 +225,6 @@ class RefreshLinks extends Maintenance { * @param $id int The page_id */ public static function fixLinksFromArticle( $id ) { - global $wgParser, $wgContLang; - $page = WikiPage::newFromID( $id ); LinkCache::singleton()->clear(); @@ -216,18 +233,16 @@ class RefreshLinks extends Maintenance { return; } - $text = $page->getRawText(); - if ( $text === false ) { + $content = $page->getContent( Revision::RAW ); + if ( $content === null ) { return; } $dbw = wfGetDB( DB_MASTER ); $dbw->begin( __METHOD__ ); - $options = ParserOptions::newFromUserAndLang( new User, $wgContLang ); - $parserOutput = $wgParser->parse( $text, $page->getTitle(), $options, true, true, $page->getLatest() ); - $update = new LinksUpdate( $page->getTitle(), $parserOutput, false ); - $update->doUpdate(); + $updates = $content->getSecondaryDataUpdates( $page->getTitle() ); + DataUpdate::runUpdates( $updates ); $dbw->commit( __METHOD__ ); } @@ -266,12 +281,13 @@ class RefreshLinks extends Maintenance { $this->output( "Retrieving illegal entries from $table... " ); // SELECT DISTINCT( $field ) FROM $table LEFT JOIN page ON $field=page_id WHERE page_id IS NULL; - $results = $dbr->select( array( $table, 'page' ), - $field, - array( 'page_id' => null ), - __METHOD__, - 'DISTINCT', - array( 'page' => array( 'LEFT JOIN', "$field=page_id" ) ) + $results = $dbr->select( + array( $table, 'page' ), + $field, + array( 'page_id' => null ), + __METHOD__, + 'DISTINCT', + array( 'page' => array( 'LEFT JOIN', "$field=page_id" ) ) ); $counter = 0; @@ -300,4 +316,4 @@ class RefreshLinks extends Maintenance { } $maintClass = 'RefreshLinks'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/removeUnusedAccounts.php b/maintenance/removeUnusedAccounts.php index 8bc27c18..16cb17ab 100644 --- a/maintenance/removeUnusedAccounts.php +++ b/maintenance/removeUnusedAccounts.php @@ -23,7 +23,7 @@ * @author Rob Church <robchur@gmail.com> */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that removes unused user accounts from the database. @@ -74,9 +74,14 @@ class RemoveUnusedAccounts extends Maintenance { # If required, go back and delete each marked account if ( $count > 0 && $this->hasOption( 'delete' ) ) { - $this->output( "\nDeleting inactive accounts..." ); + $this->output( "\nDeleting unused accounts..." ); $dbw = wfGetDB( DB_MASTER ); $dbw->delete( 'user', array( 'user_id' => $del ), __METHOD__ ); + $dbw->delete( 'user_groups', array( 'ug_user' => $del ), __METHOD__ ); + $dbw->delete( 'user_former_groups', array( 'ufg_user' => $del ), __METHOD__ ); + $dbw->delete( 'user_properties', array( 'up_user' => $del ), __METHOD__ ); + $dbw->delete( 'logging', array( 'log_user' => $del ), __METHOD__ ); + $dbw->delete( 'recentchanges', array( 'rc_user' => $del ), __METHOD__ ); $this->output( "done.\n" ); # Update the site_stats.ss_users field $users = $dbw->selectField( 'user', 'COUNT(*)', array(), __METHOD__ ); @@ -97,8 +102,13 @@ class RemoveUnusedAccounts extends Maintenance { */ private function isInactiveAccount( $id, $master = false ) { $dbo = wfGetDB( $master ? DB_MASTER : DB_SLAVE ); - $checks = array( 'revision' => 'rev', 'archive' => 'ar', 'logging' => 'log', - 'image' => 'img', 'oldimage' => 'oi', 'filearchive' => 'fa' ); + $checks = array( + 'revision' => 'rev', + 'archive' => 'ar', + 'image' => 'img', + 'oldimage' => 'oi', + 'filearchive' => 'fa' + ); $count = 0; $dbo->begin( __METHOD__ ); @@ -106,6 +116,10 @@ class RemoveUnusedAccounts extends Maintenance { $conds = array( $fprefix . '_user' => $id ); $count += (int)$dbo->selectField( $table, 'COUNT(*)', $conds, __METHOD__ ); } + + $conds = array( 'log_user' => $id, 'log_type != ' . $dbo->addQuotes( 'newusers' ) ); + $count += (int)$dbo->selectField( 'logging', 'COUNT(*)', $conds, __METHOD__ ); + $dbo->commit( __METHOD__ ); return $count == 0; @@ -113,4 +127,4 @@ class RemoveUnusedAccounts extends Maintenance { } $maintClass = "RemoveUnusedAccounts"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/renameDbPrefix.php b/maintenance/renameDbPrefix.php index 6f244791..ed9d1f5d 100644 --- a/maintenance/renameDbPrefix.php +++ b/maintenance/renameDbPrefix.php @@ -23,7 +23,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that changes the prefix of database tables. @@ -91,4 +91,4 @@ class RenameDbPrefix extends Maintenance { } $maintClass = "RenameDbPrefix"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/renderDump.php b/maintenance/renderDump.php index 24bedfa4..0cde28c5 100644 --- a/maintenance/renderDump.php +++ b/maintenance/renderDump.php @@ -28,7 +28,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that takes page text out of an XML dump file @@ -69,9 +69,10 @@ class DumpRenderer extends Maintenance { $importer->doImport(); $delta = microtime( true ) - $this->startTime; - $this->error( "Rendered {$this->count} pages in " . round($delta, 2) . " seconds " ); - if ($delta > 0) - $this->error( round($this->count / $delta, 2) . " pages/sec" ); + $this->error( "Rendered {$this->count} pages in " . round( $delta, 2 ) . " seconds " ); + if ( $delta > 0 ) { + $this->error( round( $this->count / $delta, 2 ) . " pages/sec" ); + } $this->error( "\n" ); } @@ -80,8 +81,6 @@ class DumpRenderer extends Maintenance { * @param $rev Revision */ public function handleRevision( $rev ) { - global $wgParserConf; - $title = $rev->getTitle(); if ( !$title ) { $this->error( "Got bogus revision with null title!" ); @@ -100,17 +99,16 @@ class DumpRenderer extends Maintenance { $this->output( sprintf( "%s\n", $filename, $display ) ); $user = new User(); - $parser = new $wgParserConf['class'](); $options = ParserOptions::newFromUser( $user ); - $output = $parser->parse( $rev->getText(), $title, $options ); + $content = $rev->getContent(); + $output = $content->getParserOutput( $title, null, $options ); file_put_contents( $filename, - "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" " . - "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" . - "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" . + "<!DOCTYPE html>\n" . + "<html lang=\"en\" dir=\"ltr\">\n" . "<head>\n" . - "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n" . + "<meta charset=\"UTF-8\" />\n" . "<title>" . htmlspecialchars( $display ) . "</title>\n" . "</head>\n" . "<body>\n" . @@ -121,4 +119,4 @@ class DumpRenderer extends Maintenance { } $maintClass = "DumpRenderer"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/resetUserTokens.php b/maintenance/resetUserTokens.php index d7f8c6d0..bfe04d79 100644 --- a/maintenance/resetUserTokens.php +++ b/maintenance/resetUserTokens.php @@ -21,9 +21,10 @@ * @file * @ingroup Maintenance * @author Daniel Friesen <mediawiki@danielfriesen.name> + * @author Chris Steipp <csteipp@wikimedia.org> */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to reset the user_token for all users on the wiki. @@ -35,14 +36,21 @@ class ResetUserTokens extends Maintenance { parent::__construct(); $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->setBatchSize( 1000 ); } public function execute() { + $this->nullsOnly = $this->getOption( 'nulls' ); if ( !$this->getOption( 'nowarn' ) ) { - $this->output( "The script is about to reset the user_token for ALL USERS in the database.\n" ); - $this->output( "This may log some of them out and is not necessary unless you believe your\n" ); - $this->output( "user table has been compromised.\n" ); + if ( $this->nullsOnly ) { + $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) ... " ); wfCountDown( 5 ); @@ -50,29 +58,53 @@ class ResetUserTokens extends Maintenance { // We list user by user_id from one of the slave database $dbr = wfGetDB( DB_SLAVE ); - $result = $dbr->select( 'user', - array( 'user_id' ), - array(), - __METHOD__ - ); - foreach ( $result as $id ) { - $user = User::newFromId( $id->user_id ); + $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) . '\'' ); + } - $username = $user->getName(); + $maxid = $dbr->selectField( 'user', 'MAX(user_id)', array(), __METHOD__ ); - $this->output( "Resetting user_token for $username: " ); + $min = 0; + $max = $this->mBatchSize; - // Change value - $user->setToken(); - $user->saveSettings(); + do { + $result = $dbr->select( 'user', + array( 'user_id' ), + array_merge( + $where, + array( 'user_id > ' . $dbr->addQuotes( $min ), + 'user_id <= ' . $dbr->addQuotes( $max ) + ) + ), + __METHOD__ + ); - $this->output( " OK\n" ); + foreach ( $result as $user ) { + $this->updateUser( $user->user_id ); + } - } + $min = $max; + $max = $min + $this->mBatchSize; + + wfWaitForSlaves(); + + } while ( $max <= $maxid ); + + } + private function updateUser( $userid ) { + $user = User::newFromId( $userid ); + $username = $user->getName(); + $this->output( 'Resetting user_token for "' . $username . '": ' ); + // Change value + $user->setToken(); + $user->saveSettings(); + $this->output( " OK\n" ); } } $maintClass = "ResetUserTokens"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/rollbackEdits.php b/maintenance/rollbackEdits.php index 4660bcef..e5e33c02 100644 --- a/maintenance/rollbackEdits.php +++ b/maintenance/rollbackEdits.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to rollback all edits by a given user or IP provided @@ -104,4 +104,4 @@ class RollbackEdits extends Maintenance { } $maintClass = 'RollbackEdits'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/runBatchedQuery.php b/maintenance/runBatchedQuery.php index e1139164..93ba24a9 100644 --- a/maintenance/runBatchedQuery.php +++ b/maintenance/runBatchedQuery.php @@ -23,7 +23,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to run a database query in batches and wait for slaves. @@ -38,8 +38,9 @@ class BatchedQueryRunner extends Maintenance { } public function execute() { - if ( !$this->hasArg() ) + if ( !$this->hasArg() ) { $this->error( "No query specified. Specify the query as a command line parameter.", true ); + } $query = $this->getArg(); $n = 1; @@ -61,4 +62,4 @@ class BatchedQueryRunner extends Maintenance { $maintClass = "BatchedQueryRunner"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/runJobs.php b/maintenance/runJobs.php index e909bc06..429edf42 100644 --- a/maintenance/runJobs.php +++ b/maintenance/runJobs.php @@ -25,7 +25,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that runs pending jobs. @@ -52,14 +52,20 @@ class RunJobs extends Maintenance { public function execute() { global $wgTitle; + + if ( wfReadOnly() ) { + $this->error( "Unable to run jobs; the wiki is in read-only mode.", 1 ); // die + } + if ( $this->hasOption( 'procs' ) ) { $procs = intval( $this->getOption( 'procs' ) ); if ( $procs < 1 || $procs > 1000 ) { $this->error( "Invalid argument to --procs", true ); - } - $fc = new ForkController( $procs ); - if ( $fc->start() != 'child' ) { - exit( 0 ); + } elseif ( $procs != 1 ) { + $fc = new ForkController( $procs ); + if ( $fc->start() != 'child' ) { + exit( 0 ); + } } } $maxJobs = $this->getOption( 'maxjobs', false ); @@ -67,44 +73,97 @@ class RunJobs extends Maintenance { $startTime = time(); $type = $this->getOption( 'type', false ); $wgTitle = Title::newFromText( 'RunJobs.php' ); - $dbw = wfGetDB( DB_MASTER ); - $n = 0; + $jobsRun = 0; // counter - if ( $type === false ) { - $conds = Job::defaultQueueConditions( ); - } else { - $conds = array( 'job_cmd' => $type ); + $group = JobQueueGroup::singleton(); + // Handle any required periodic queue maintenance + $count = $group->executeReadyPeriodicTasks(); + if ( $count > 0 ) { + $this->runJobsLog( "Executed $count periodic queue task(s)." ); } - while ( $dbw->selectField( 'job', 'job_id', $conds, 'runJobs.php' ) ) { - $offset = 0; - for ( ; ; ) { - $job = !$type ? Job::pop( $offset ) : Job::pop_type( $type ); + $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 ); - if ( !$job ) { - break; + // Mark the job as done on success or when the job cannot be retried + if ( $status !== false || !$job->allowRetries() ) { + $group->ack( $job ); // done } - wfWaitForSlaves(); - $t = microtime( true ); - $offset = $job->id; - $this->runJobsLog( $job->toString() . " STARTING" ); - $status = $job->run(); - $t = microtime( true ) - $t; - $timeMs = intval( $t * 1000 ); - if ( !$status ) { - $this->runJobsLog( $job->toString() . " t=$timeMs error={$job->error}" ); + if ( $status === false ) { + $this->runJobsLog( $job->toString() . " t=$timeMs error={$error}" ); } else { $this->runJobsLog( $job->toString() . " t=$timeMs good" ); } - if ( $maxJobs && ++$n > $maxJobs ) { - break 2; + // 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(); } - if ( $maxTime && time() - $startTime > $maxTime ) { - break 2; + // Don't let any queue slaves/backups fall behind + if ( $jobsRun > 0 && ( $jobsRun % 100 ) == 0 ) { + $group->waitForBackups(); } + + // 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; + } + } + $usedBytes = memory_get_usage(); + if ( $maxBytes && $usedBytes >= 0.95 * $maxBytes ) { + throw new MWException( "Detected excessive memory usage ($usedBytes/$maxBytes)." ); } } @@ -119,4 +178,4 @@ class RunJobs extends Maintenance { } $maintClass = "RunJobs"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/stats.php b/maintenance/showCacheStats.php index be448f99..cd9768d4 100644 --- a/maintenance/stats.php +++ b/maintenance/showCacheStats.php @@ -21,14 +21,14 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that shows statistics from the cache. * * @ingroup Maintenance */ -class CacheStats extends Maintenance { +class ShowCacheStats extends Maintenance { public function __construct() { $this->mDescription = "Show statistics from the cache"; @@ -102,5 +102,5 @@ class CacheStats extends Maintenance { } } -$maintClass = "CacheStats"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +$maintClass = "ShowCacheStats"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/showJobs.php b/maintenance/showJobs.php index 1dceb790..afd7c745 100644 --- a/maintenance/showJobs.php +++ b/maintenance/showJobs.php @@ -25,7 +25,7 @@ * @author Antoine Musso */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that reports the number of jobs currently waiting @@ -38,25 +38,44 @@ 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' ); } + public function execute() { - $dbw = wfGetDB( DB_MASTER ); - if ( $this->hasOption( 'group' ) ) { - $res = $dbw->select( - 'job', - array( 'job_cmd', 'count(*) as count' ), - array(), - __METHOD__, - array( 'GROUP BY' => 'job_cmd' ) - ); - foreach ( $res as $row ) { - $this->output( $row->job_cmd . ': ' . $row->count . "\n" ); + $group = JobQueueGroup::singleton(); + if ( $this->hasOption( 'list' ) ) { + foreach ( $group->getQueueTypes() as $type ) { + $queue = $group->get( $type ); + foreach ( $queue->getAllQueuedJobs() as $job ) { + $this->output( $job->toString() . " status=unclaimed\n" ); + } + foreach ( $queue->getAllDelayedJobs() as $job ) { + $this->output( $job->toString() . " status=delayed\n" ); + } + } + } elseif ( $this->hasOption( 'group' ) ) { + foreach ( $group->getQueueTypes() as $type ) { + $queue = $group->get( $type ); + $pending = $queue->getSize(); + $claimed = $queue->getAcquiredCount(); + $abandoned = $queue->getAbandonedCount(); + $active = max( 0, $claimed - $abandoned ); + if ( ( $pending + $claimed ) > 0 ) { + $this->output( + "{$type}: $pending queued; " . + "$claimed claimed ($active active, $abandoned abandoned)\n" + ); + } } } else { - $this->output( $dbw->selectField( 'job', 'count(*)', '', __METHOD__ ) . "\n" ); + $count = 0; + foreach ( $group->getQueueTypes() as $type ) { + $count += $group->get( $type )->getSize(); + } + $this->output( "$count\n" ); } } } $maintClass = "ShowJobs"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/showStats.php b/maintenance/showSiteStats.php index 982c7cbb..49148b33 100644 --- a/maintenance/showStats.php +++ b/maintenance/showSiteStats.php @@ -22,21 +22,21 @@ * @file * @ingroup Maintenance * @author Antoine Musso <hashar at free dot fr> - * Based on initStats.php by: + * Based on initSiteStats.php by: * @author Brion Vibber * @author Rob Church <robchur@gmail.com> * * @license GNU General Public License 2.0 or later */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to show the cached statistics. * * @ingroup Maintenance */ -class ShowStats extends Maintenance { +class ShowSiteStats extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Show the cached statistics"; @@ -48,6 +48,7 @@ class ShowStats extends Maintenance { 'ss_good_articles' => 'Number of articles', 'ss_total_pages' => 'Total pages', 'ss_users' => 'Number of users', + 'ss_active_users' => 'Active users', 'ss_images' => 'Number of images', ); @@ -59,7 +60,7 @@ class ShowStats extends Maintenance { $max_length_value = $max_length_desc = 0; foreach ( $fields as $field => $desc ) { $max_length_value = max( $max_length_value, strlen( $stats->$field ) ); - $max_length_desc = max( $max_length_desc , strlen( $desc ) ) ; + $max_length_desc = max( $max_length_desc, strlen( $desc ) ); } // Show them @@ -69,6 +70,5 @@ class ShowStats extends Maintenance { } } -$maintClass = "ShowStats"; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +$maintClass = "ShowSiteStats"; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/sql.php b/maintenance/sql.php index 04e98d91..a628b0bc 100644 --- a/maintenance/sql.php +++ b/maintenance/sql.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that sends SQL queries from the specified file to the database. @@ -33,13 +33,45 @@ class MwSql extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = "Send SQL queries to a MediaWiki database"; + $this->addOption( 'cluster', 'Use an external cluster by name', false, true ); + $this->addOption( 'slave', 'Use a slave server (either "any" or by name)', false, true ); } public function execute() { - $dbw = wfGetDB( DB_MASTER ); - if ( $this->hasArg() ) { - $fileName = $this->getArg(); - $file = fopen( $fileName, 'r' ); + // Get the appropriate load balancer (for this wiki) + if ( $this->hasOption( 'cluster' ) ) { + $lb = wfGetLBFactory()->getExternalLB( $this->getOption( 'cluster' ) ); + } else { + $lb = wfGetLB(); + } + // Figure out which server to use + if ( $this->hasOption( 'slave' ) ) { + $server = $this->getOption( 'slave' ); + if ( $server === 'any' ) { + $index = DB_SLAVE; + } else { + $index = null; + for ( $i = 0; $i < $lb->getServerCount(); ++$i ) { + if ( $lb->getServerName( $i ) === $server ) { + $index = $i; + break; + } + } + if ( $index === null ) { + $this->error( "No slave server configured with the name '$server'.", 1 ); + } + } + } else { + $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 ); + } + + if ( $this->hasArg( 0 ) ) { + $file = fopen( $this->getArg( 0 ), 'r' ); if ( !$file ) { $this->error( "Unable to open input file", true ); } @@ -63,26 +95,39 @@ class MwSql extends Maintenance { } $wholeLine = ''; - while ( ( $line = Maintenance::readconsole() ) !== false ) { + $newPrompt = '> '; + $prompt = $newPrompt; + while ( ( $line = Maintenance::readconsole( $prompt ) ) !== false ) { + if ( !$line ) { + # User simply pressed return key + continue; + } $done = $dbw->streamStatementEnd( $wholeLine, $line ); $wholeLine .= $line; if ( !$done ) { + $wholeLine .= ' '; + $prompt = ' -> '; continue; } if ( $useReadline ) { - readline_add_history( $wholeLine ); + # Delimiter is eated by streamStatementEnd, we add it + # up in the history (bug 37020) + readline_add_history( $wholeLine . $dbw->getDelimiter() ); readline_write_history( $historyFile ); } - try{ + try { $res = $dbw->query( $wholeLine ); $this->sqlPrintResult( $res, $dbw ); + $prompt = $newPrompt; $wholeLine = ''; - } catch (DBQueryError $e) { - $this->error( $e, true ); + } catch ( DBQueryError $e ) { + $doDie = ! Maintenance::posix_isatty( 0 ); + $this->error( $e, $doDie ); } } + wfWaitForSlaves(); } /** @@ -93,6 +138,7 @@ class MwSql extends Maintenance { public function sqlPrintResult( $res, $db ) { if ( !$res ) { // Do nothing + return; } elseif ( is_object( $res ) && $res->numRows() ) { foreach ( $res as $row ) { $this->output( print_r( $row, true ) ); @@ -112,4 +158,4 @@ class MwSql extends Maintenance { } $maintClass = "MwSql"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/sqlite.inc b/maintenance/sqlite.inc index a8a1fce6..08188cad 100644 --- a/maintenance/sqlite.inc +++ b/maintenance/sqlite.inc @@ -33,16 +33,15 @@ class Sqlite { * @return bool */ public static function isPresent() { - wfSuppressWarnings(); - $compiled = wfDl( 'pdo_sqlite' ); - wfRestoreWarnings(); - return $compiled; + return extension_loaded( 'pdo_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 + * @throws MWException * @return mixed true if no error or error string in case of errors */ public static function checkSqlSyntax( $files ) { @@ -71,7 +70,9 @@ class Sqlite { $tables = $db->query( "SELECT name FROM sqlite_master WHERE type='table'", __METHOD__ ); foreach ( $tables as $table ) { - if ( strpos( $table->name, 'sqlite_' ) === 0 ) continue; + if ( strpos( $table->name, 'sqlite_' ) === 0 ) { + continue; + } $columns = $db->query( "PRAGMA table_info({$table->name})", __METHOD__ ); foreach ( $columns as $col ) { @@ -87,4 +88,4 @@ class Sqlite { $db->close(); return true; } - }; +}; diff --git a/maintenance/sqlite.php b/maintenance/sqlite.php index 4085c59b..8a785245 100644 --- a/maintenance/sqlite.php +++ b/maintenance/sqlite.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that performs some operations specific to SQLite database backend. @@ -137,4 +137,4 @@ class SqliteMaintenance extends Maintenance { } $maintClass = "SqliteMaintenance"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/sqlite/archives/initial-indexes.sql b/maintenance/sqlite/archives/initial-indexes.sql index 73b008cc..1a59be5a 100644 --- a/maintenance/sqlite/archives/initial-indexes.sql +++ b/maintenance/sqlite/archives/initial-indexes.sql @@ -28,6 +28,8 @@ DROP TABLE IF EXISTS /*_*/interwiki_tmp; DROP TABLE IF EXISTS /*_*/page_restrictions_tmp; DROP TABLE IF EXISTS /*_*/protected_titles_tmp; DROP TABLE IF EXISTS /*_*/page_props_tmp; +DROP TABLE IF EXISTS /*_*/archive_tmp; +DROP TABLE IF EXISTS /*_*/externallinks_tmp; -------------------------------------------------------------------------------- -- Create new tables @@ -268,6 +270,47 @@ CREATE TABLE /*_*/page_props_tmp ( ); CREATE UNIQUE INDEX /*i*/pp_page_propname ON /*_*/page_props_tmp (pp_page,pp_propname); +-- +-- Holding area for deleted articles, which may be viewed +-- or restored by admins through the Special:Undelete interface. +-- The fields generally correspond to the page, revision, and text +-- fields, with several caveats. +-- Cannot reasonably create views on this table, due to the presence of TEXT +-- columns. +CREATE TABLE /*$wgDBprefix*/archive_tmp ( + ar_id NOT NULL PRIMARY KEY clustered 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_text NVARCHAR(255) NOT NULL, + ar_timestamp DATETIME NOT NULL DEFAULT GETDATE(), + 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 +); +CREATE INDEX /*$wgDBprefix*/ar_name_title_timestamp ON /*$wgDBprefix*/archive_tmp(ar_namespace,ar_title,ar_timestamp); +CREATE INDEX /*$wgDBprefix*/ar_usertext_timestamp ON /*$wgDBprefix*/archive_tmp(ar_user_text,ar_timestamp); +CREATE INDEX /*$wgDBprefix*/ar_user_text ON /*$wgDBprefix*/archive_tmp(ar_user_text); + +-- +-- Track links to external URLs +-- IE >= 4 supports no more than 2083 characters in a URL +CREATE TABLE /*$wgDBprefix*/externallinks_tmp ( + 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_tmp(el_index); + -------------------------------------------------------------------------------- -- Populate the new tables using INSERT SELECT -------------------------------------------------------------------------------- @@ -290,6 +333,8 @@ INSERT OR IGNORE INTO /*_*/interwiki_tmp SELECT * FROM /*_*/interwiki; INSERT OR IGNORE INTO /*_*/page_restrictions_tmp SELECT * FROM /*_*/page_restrictions; INSERT OR IGNORE INTO /*_*/protected_titles_tmp SELECT * FROM /*_*/protected_titles; INSERT OR IGNORE INTO /*_*/page_props_tmp SELECT * FROM /*_*/page_props; +INSERT OR IGNORE INTO /*_*/archive_tmp SELECT * FROM /*_*/archive; +INSERT OR IGNORE INTO /*_*/externallinks_tmp SELECT * FROM /*_*/externallinks; -------------------------------------------------------------------------------- -- Do the table renames @@ -331,6 +376,10 @@ DROP TABLE /*_*/protected_titles; ALTER TABLE /*_*/protected_titles_tmp RENAME TO /*_*/protected_titles; DROP TABLE /*_*/page_props; ALTER TABLE /*_*/page_props_tmp RENAME TO /*_*/page_props; +DROP TABLE /*_*/archive; +ALTER TABLE /*_*/archive_tmp RENAME TO /*_*/archive; +DROP TABLE /*_*/externalllinks; +ALTER TABLE /*_*/externallinks_tmp RENAME TO /*_*/externallinks; -------------------------------------------------------------------------------- -- Drop and create tables with unique indexes but no valuable data diff --git a/maintenance/sqlite/archives/patch-archive-ar_id.sql b/maintenance/sqlite/archives/patch-archive-ar_id.sql new file mode 100644 index 00000000..00a9b071 --- /dev/null +++ b/maintenance/sqlite/archives/patch-archive-ar_id.sql @@ -0,0 +1,39 @@ +DROP TABLE IF EXISTS /*_*/archive_tmp; + +CREATE TABLE /*$wgDBprefix*/archive_tmp ( + ar_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, + ar_namespace int NOT NULL default 0, + ar_title varchar(255) binary NOT NULL default '', + ar_text mediumblob NOT NULL, + ar_comment tinyblob NOT NULL, + ar_user int unsigned NOT NULL default 0, + ar_user_text varchar(255) binary NOT NULL, + ar_timestamp binary(14) NOT NULL default '', + ar_minor_edit tinyint NOT NULL default 0, + ar_flags tinyblob NOT NULL, + ar_rev_id int unsigned, + ar_text_id int unsigned, + ar_deleted tinyint unsigned NOT NULL default 0, + ar_len int unsigned, + ar_page_id int unsigned, + ar_parent_id int unsigned default NULL, + ar_sha1 varbinary(32) NOT NULL default '', + ar_content_model varbinary(32) DEFAULT NULL, + ar_content_format varbinary(64) DEFAULT NULL +); + +INSERT OR IGNORE INTO /*_*/archive_tmp ( + ar_namespace, ar_title, ar_title, ar_text, ar_comment, ar_user, ar_user_text, ar_timestamp, + ar_minor_edit, ar_flags, ar_rev_id, ar_text_id, ar_deleted, ar_len, ar_page_id, ar_parent_id ) + SELECT + ar_namespace, ar_title, ar_title, ar_text, ar_comment, ar_user, ar_user_text, ar_timestamp, + ar_minor_edit, ar_flags, ar_rev_id, ar_text_id, ar_deleted, ar_len, ar_page_id, ar_parent_id + FROM /*_*/archive; + +DROP TABLE /*_*/archive; + +ALTER TABLE /*_*/archive_tmp RENAME TO /*_*/archive; + +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); diff --git a/maintenance/sqlite/archives/patch-drop-ss_admins.sql b/maintenance/sqlite/archives/patch-drop-ss_admins.sql new file mode 100644 index 00000000..9951e17e --- /dev/null +++ b/maintenance/sqlite/archives/patch-drop-ss_admins.sql @@ -0,0 +1,22 @@ +-- field is deprecated and no longer updated as of 1.5 +CREATE TABLE /*_*/site_stats_tmp ( + ss_row_id int unsigned NOT NULL, + ss_total_views bigint unsigned default 0, + ss_total_edits bigint unsigned default 0, + ss_good_articles bigint unsigned default 0, + ss_total_pages bigint default '-1', + ss_users bigint default '-1', + ss_active_users bigint default '-1', + ss_images int default 0 +) /*$wgDBTableOptions*/; + +INSERT INTO /*_*/site_stats_tmp + SELECT ss_row_id, ss_total_views, ss_total_edits, ss_good_articles, + ss_total_pages, ss_users, ss_active_users, ss_images + FROM /*_*/site_stats; + +DROP TABLE /*_*/site_stats; + +ALTER TABLE /*_*/site_stats_tmp RENAME TO /*_*/site_stats; + +CREATE UNIQUE INDEX /*i*/ss_row_id ON /*_*/site_stats (ss_row_id);
\ No newline at end of file diff --git a/maintenance/sqlite/archives/patch-externallinks-el_id.sql b/maintenance/sqlite/archives/patch-externallinks-el_id.sql new file mode 100644 index 00000000..0aad4071 --- /dev/null +++ b/maintenance/sqlite/archives/patch-externallinks-el_id.sql @@ -0,0 +1,19 @@ +DROP TABLE IF EXISTS /*_*/externallinks_tmp; + +CREATE TABLE /*$wgDBprefix*/externallinks_tmp ( + el_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, + el_from int unsigned NOT NULL default 0, + el_to blob NOT NULL, + el_index blob NOT NULL +); + +INSERT OR IGNORE INTO /*_*/externallinks_tmp (el_from, el_to, el_index) SELECT + el_from, el_to, el_index FROM /*_*/externallinks; + +DROP TABLE /*_*/externallinks; + +ALTER TABLE /*_*/externallinks_tmp RENAME TO /*_*/externallinks; + +CREATE INDEX /*i*/el_from ON /*_*/externallinks (el_from, el_to(40)); +CREATE INDEX /*i*/el_to ON /*_*/externallinks (el_to(60), el_from); +CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index(60));
\ No newline at end of file diff --git a/maintenance/sqlite/archives/patch-job_token.sql b/maintenance/sqlite/archives/patch-job_token.sql new file mode 100644 index 00000000..4e4d28fd --- /dev/null +++ b/maintenance/sqlite/archives/patch-job_token.sql @@ -0,0 +1,8 @@ +ALTER TABLE /*_*/job ADD COLUMN job_random integer unsigned NOT NULL default 0; +ALTER TABLE /*_*/job ADD COLUMN job_token varbinary(32) NOT NULL default ''; +ALTER TABLE /*_*/job ADD COLUMN job_sha1 varbinary(32) NOT NULL default ''; +ALTER TABLE /*_*/job ADD COLUMN job_token_timestamp varbinary(14) NULL default NULL; + +CREATE INDEX /*i*/job_sha1 ON /*_*/job (job_sha1); +CREATE INDEX /*i*/job_cmd_token ON /*_*/job (job_cmd,job_token,job_random); + diff --git a/maintenance/sqlite/archives/patch-kill-iwl_pft.sql b/maintenance/sqlite/archives/patch-kill-iwl_pft.sql deleted file mode 100644 index 8fc4b5cd..00000000 --- a/maintenance/sqlite/archives/patch-kill-iwl_pft.sql +++ /dev/null @@ -1,7 +0,0 @@ --- --- Kill the old iwl_prefix_from_title index, which may be present on some --- installs if they ran update.php between it being added and being renamed --- - -DROP INDEX IF EXISTS /*i*/iwl_prefix; - diff --git a/maintenance/sqlite/archives/patch-profiling.sql b/maintenance/sqlite/archives/patch-profiling.sql new file mode 100644 index 00000000..4a07283c --- /dev/null +++ b/maintenance/sqlite/archives/patch-profiling.sql @@ -0,0 +1,12 @@ +-- profiling table +-- This is optional + +CREATE TABLE /*_*/profiling ( + pf_count int NOT NULL default 0, + pf_time float NOT NULL default 0, + pf_memory float NOT NULL default 0, + pf_name varchar(255) NOT NULL default '', + pf_server varchar(30) NOT NULL default '' +); + +CREATE UNIQUE INDEX /*i*/pf_name_server ON /*_*/profiling (pf_name, pf_server); diff --git a/maintenance/sqlite/archives/patch-rc_moved.sql b/maintenance/sqlite/archives/patch-rc_moved.sql new file mode 100644 index 00000000..70248d54 --- /dev/null +++ b/maintenance/sqlite/archives/patch-rc_moved.sql @@ -0,0 +1,46 @@ +-- rc_moved_to_ns and rc_moved_to_title is no longer used, delete the fields + +CREATE TABLE /*_*/recentchanges_tmp ( + rc_id int NOT NULL PRIMARY KEY AUTO_INCREMENT, + rc_timestamp varbinary(14) NOT NULL default '', + rc_cur_time 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_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_cur_time, 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_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); diff --git a/maintenance/sqlite/archives/patch-rename-iwl_prefix.sql b/maintenance/sqlite/archives/patch-rename-iwl_prefix.sql index 851a6b37..6d5b1bfa 100644 --- a/maintenance/sqlite/archives/patch-rename-iwl_prefix.sql +++ b/maintenance/sqlite/archives/patch-rename-iwl_prefix.sql @@ -1,5 +1,5 @@ --- +-- -- Recreates the iwl_prefix for the iwlinks table -- DROP INDEX IF EXISTS /*i*/iwl_prefix; -CREATE INDEX IF NOT EXISTS /*i*/iwl_prefix_from_title ON /*_*/iwlinks (iwl_prefix, iwl_from, iwl_title); +CREATE INDEX IF NOT EXISTS /*i*/iwl_prefix_title_from ON /*_*/iwlinks (iwl_prefix, iwl_title, iwl_from); diff --git a/maintenance/sqlite/archives/patch-sites.sql b/maintenance/sqlite/archives/patch-sites.sql new file mode 100644 index 00000000..88392748 --- /dev/null +++ b/maintenance/sqlite/archives/patch-sites.sql @@ -0,0 +1,71 @@ +-- Patch to add the sites and site_identifiers tables. +-- Licence: GNU GPL v2+ +-- Author: Jeroen De Dauw < jeroendedauw@gmail.com > + + +-- Holds all the sites known to the wiki. +CREATE TABLE IF NOT EXISTS /*_*/sites ( +-- Numeric id of the site + site_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + + -- Global identifier for the site, ie 'enwiktionary' + site_global_key varbinary(32) NOT NULL, + + -- Type of the site, ie 'mediawiki' + site_type varbinary(32) NOT NULL, + + -- Group of the site, ie 'wikipedia' + site_group varbinary(32) NOT NULL, + + -- Source of the site data, ie 'local', 'wikidata', 'my-magical-repo' + site_source varbinary(32) NOT NULL, + + -- Language code of the sites primary language. + site_language varbinary(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 varbinary(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 VARCHAR(255) NOT NULL, + + -- Type dependent site data. + site_data BLOB 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 bool NOT NULL, + + -- Type dependent site config. + -- For instance if template transclusion should be allowed if it's a MediaWiki. + site_config BLOB NOT NULL +) /*$wgDBTableOptions*/; + +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 IF NOT EXISTS /*_*/site_identifiers ( + -- Key on site.site_id + si_site INT UNSIGNED NOT NULL, + + -- local key type, ie 'interwiki' or 'langlink' + si_type varbinary(32) NOT NULL, + + -- local key value, ie 'en' or 'wiktionary' + si_key varbinary(32) NOT NULL +) /*$wgDBTableOptions*/; + +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);
\ No newline at end of file diff --git a/maintenance/sqlite/archives/patch-ufg_group-length-increase.sql b/maintenance/sqlite/archives/patch-ufg_group-length-increase-255.sql index c6dcea5e..edd0a3dc 100644 --- a/maintenance/sqlite/archives/patch-ufg_group-length-increase.sql +++ b/maintenance/sqlite/archives/patch-ufg_group-length-increase-255.sql @@ -1,11 +1,11 @@ -CREATE TABLE /*_*/user_former_groups_tmp ( - ug_user int unsigned NOT NULL default 0, - ug_group varbinary(32) NOT NULL default '' + CREATE TABLE /*_*/user_former_groups_tmp ( + ufg_user int unsigned NOT NULL default 0, + ufg_group varbinary(255) NOT NULL default '' ) /*$wgDBTableOptions*/; INSERT INTO /*_*/user_former_groups_tmp - SELECT ug_user, ug_group - FROM /*_*/user_groups; + SELECT ufg_user, ufg_group + FROM /*_*/user_former_groups; DROP TABLE /*_*/user_former_groups; diff --git a/maintenance/sqlite/archives/patch-ug_group-length-increase.sql b/maintenance/sqlite/archives/patch-ug_group-length-increase-255.sql index 5e810937..3daeb7c6 100644 --- a/maintenance/sqlite/archives/patch-ug_group-length-increase.sql +++ b/maintenance/sqlite/archives/patch-ug_group-length-increase-255.sql @@ -1,6 +1,6 @@ CREATE TABLE /*_*/user_groups_tmp ( ug_user int unsigned NOT NULL default 0, - ug_group varbinary(32) NOT NULL default '' + ug_group varbinary(255) NOT NULL default '' ) /*$wgDBTableOptions*/; INSERT INTO /*_*/user_groups_tmp diff --git a/maintenance/sqlite/archives/searchindex-fts3.sql b/maintenance/sqlite/archives/searchindex-fts3.sql index 28554c02..2a370940 100644 --- a/maintenance/sqlite/archives/searchindex-fts3.sql +++ b/maintenance/sqlite/archives/searchindex-fts3.sql @@ -1,7 +1,7 @@ -- Patch that introduces fulltext search capabilities to SQLite schema -- Requires that SQLite must be compiled with FTS3 module (comes with core amalgamation). -- See http://sqlite.org/fts3.html for details of syntax. --- Will fail if FTS3 is not present, +-- Will fail if FTS3 is not present, DROP TABLE IF EXISTS /*_*/searchindex; CREATE VIRTUAL TABLE /*_*/searchindex USING FTS3( -- Key to page_id @@ -10,7 +10,7 @@ CREATE VIRTUAL TABLE /*_*/searchindex USING FTS3( -- Munged version of title si_title, - + -- Munged version of body text si_text ); diff --git a/maintenance/sqlite/archives/searchindex-no-fts.sql b/maintenance/sqlite/archives/searchindex-no-fts.sql index bc014b3d..16247ffe 100644 --- a/maintenance/sqlite/archives/searchindex-no-fts.sql +++ b/maintenance/sqlite/archives/searchindex-no-fts.sql @@ -17,7 +17,7 @@ CREATE TABLE /*_*/searchindex ( -- Munged version of title si_title TEXT, - + -- Munged version of body text si_text TEXT ); diff --git a/maintenance/storage/blobs.sql b/maintenance/storage/blobs.sql index 623dd7bf..979e68a9 100644 --- a/maintenance/storage/blobs.sql +++ b/maintenance/storage/blobs.sql @@ -4,5 +4,4 @@ CREATE TABLE /*$wgDBprefix*/blobs ( blob_id integer UNSIGNED NOT NULL AUTO_INCREMENT, blob_text longblob, PRIMARY KEY (blob_id) -) ENGINE=MyISAM MAX_ROWS=100000000 AVG_ROW_LENGTH=100000; - +) ENGINE=InnoDB; diff --git a/maintenance/storage/checkStorage.php b/maintenance/storage/checkStorage.php index 6c669bfa..03dc113a 100644 --- a/maintenance/storage/checkStorage.php +++ b/maintenance/storage/checkStorage.php @@ -22,7 +22,7 @@ */ if ( !defined( 'MEDIAWIKI' ) ) { - require_once( __DIR__ . '/../commandLine.inc' ); + require_once __DIR__ . '/../commandLine.inc'; $cs = new CheckStorage; $fix = isset( $options['fix'] ); @@ -38,14 +38,16 @@ if ( !defined( 'MEDIAWIKI' ) ) { // ---------------------------------------------------------------------------------- /** + * Maintenance script to do various checks on external storage. + * * @ingroup Maintenance ExternalStorage */ class CheckStorage { const CONCAT_HEADER = 'O:27:"concatenatedgziphistoryblob"'; - var $oldIdMap, $errors; - var $dbStore = null; + public $oldIdMap, $errors; + public $dbStore = null; - var $errorDescriptions = array( + public $errorDescriptions = array( 'restore text' => 'Damaged text, need to be restored from a backup', 'restore revision' => 'Damaged revision row, need to be restored from a backup', 'unfixable' => 'Unexpected errors with no automated fixing method', @@ -73,7 +75,7 @@ class CheckStorage { 'fixable' => array(), ); - for ( $chunkStart = 1 ; $chunkStart < $maxRevId; $chunkStart += $chunkSize ) { + for ( $chunkStart = 1; $chunkStart < $maxRevId; $chunkStart += $chunkSize ) { $chunkEnd = $chunkStart + $chunkSize - 1; // print "$chunkStart of $maxRevId\n"; @@ -441,18 +443,26 @@ class CheckStorage { function importRevision( &$revision, &$importer ) { $id = $revision->getID(); - $text = $revision->getText(); + $content = $revision->getContent( Revision::RAW ); + $id = $id ? $id : ''; + + if ( $content === null ) { + echo "Revision $id is broken, we have no content available\n"; + return; + } + + $text = $content->serialize(); if ( $text === '' ) { // This is what happens if the revision was broken at the time the // dump was made. Unfortunately, it also happens if the revision was // legitimately blank, so there's no way to tell the difference. To // be safe, we'll skip it and leave it broken - $id = $id ? $id : ''; + echo "Revision $id is blank in the dump, may have been broken before export\n"; return; } - if ( !$id ) { + if ( !$id ) { // No ID, can't import echo "No id tag in revision, can't import\n"; return; diff --git a/maintenance/storage/compressOld.php b/maintenance/storage/compressOld.php index 4594db71..8cb55487 100644 --- a/maintenance/storage/compressOld.php +++ b/maintenance/storage/compressOld.php @@ -41,14 +41,19 @@ * @ingroup Maintenance ExternalStorage */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; +/** + * Maintenance script that compress the text of a wiki. + * + * @ingroup Maintenance ExternalStorage + */ class CompressOld extends Maintenance { /** * @todo document */ const LS_INDIVIDUAL = 0; - const LS_CHUNKED = 1; + const LS_CHUNKED = 1; public function __construct() { parent::__construct(); @@ -108,9 +113,9 @@ class CompressOld extends Maintenance { $this->output( "Starting from old_id $start...\n" ); $dbw = wfGetDB( DB_MASTER ); do { - $res = $dbw->select( 'text', array( 'old_id','old_flags','old_text' ), + $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( $dbw->numRows( $res ) == 0 ) { + if ( $res->numRows() == 0 ) { break; } $last = $start; @@ -121,7 +126,7 @@ class CompressOld extends Maintenance { } $start = $last + 1; # Deletion may leave long empty stretches $this->output( "$start...\n" ); - } while( true ); + } while ( true ); } /** @@ -218,7 +223,7 @@ class CompressOld extends Maintenance { } $conds[] = "rev_timestamp>'" . $beginDate . "'"; } - if ( $endDate ) { + if ( $endDate ) { if ( !preg_match( '/^\d{14}$/', $endDate ) ) { $this->error( "Invalid end date \"$endDate\"\n" ); return false; @@ -249,9 +254,9 @@ class CompressOld extends Maintenance { # Get the page row $pageRes = $dbr->select( 'page', - array('page_id', 'page_namespace', 'page_title','page_latest'), - $pageConds + array('page_id' => $pageId), __METHOD__ ); - if ( $dbr->numRows( $pageRes ) == 0 ) { + array( 'page_id', 'page_namespace', 'page_title', 'page_latest' ), + $pageConds + array( 'page_id' => $pageId ), __METHOD__ ); + if ( $pageRes->numRows() == 0 ) { continue; } $pageRow = $dbr->fetchObject( $pageRes ); @@ -277,7 +282,7 @@ class CompressOld extends Maintenance { $revs[] = $revRow; } - if ( count( $revs ) < 2) { + if ( count( $revs ) < 2 ) { # No revisions matching, no further processing $this->output( "\n" ); continue; @@ -346,21 +351,22 @@ class CompressOld extends Maintenance { if ( $extdb != "" ) { # Move blob objects to External Storage $stored = $storeObj->store( $extdb, serialize( $chunk )); - if ($stored === false) { - $this->error( "Unable to store object" ); + if ( $stored === false ) { + $this->error( "Unable to store object" ); return false; } # Store External Storage URLs instead of Stub placeholders - foreach ($stubs as $stub) { - if ($stub===false) + foreach ( $stubs as $stub ) { + if ( $stub === false ) { continue; + } # $stored should provide base path to a BLOB - $url = $stored."/".$stub->getHash(); + $url = $stored . "/" . $stub->getHash(); $dbw->update( 'text', array( /* SET */ 'old_text' => $url, 'old_flags' => 'external,utf-8', - ), array ( /* WHERE */ + ), array( /* WHERE */ 'old_id' => $stub->getReferrer(), ) ); @@ -382,7 +388,7 @@ class CompressOld extends Maintenance { if ( $stubs[$j] !== false && $revs[$i + $j]->rev_text_id != $primaryOldid ) { $dbw->update( 'text', array( /* SET */ - 'old_text' => serialize($stubs[$j]), + 'old_text' => serialize( $stubs[$j] ), 'old_flags' => 'object,utf-8', ), array( /* WHERE */ 'old_id' => $revs[$i + $j]->rev_text_id @@ -406,4 +412,4 @@ class CompressOld extends Maintenance { } $maintClass = 'CompressOld'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/storage/drop_content_model_info.sql b/maintenance/storage/drop_content_model_info.sql new file mode 100644 index 00000000..7bd9aba9 --- /dev/null +++ b/maintenance/storage/drop_content_model_info.sql @@ -0,0 +1,7 @@ +ALTER TABLE /*$wgDBprefix*/archive DROP COLUMN ar_content_model; +ALTER TABLE /*$wgDBprefix*/archive DROP COLUMN ar_content_format; + +ALTER TABLE /*$wgDBprefix*/revision DROP COLUMN rev_content_model; +ALTER TABLE /*$wgDBprefix*/revision DROP COLUMN rev_content_format; + +ALTER TABLE /*$wgDBprefix*/page DROP COLUMN page_content_model; diff --git a/maintenance/storage/dumpRev.php b/maintenance/storage/dumpRev.php index 6020f22e..f12bbd1b 100644 --- a/maintenance/storage/dumpRev.php +++ b/maintenance/storage/dumpRev.php @@ -1,5 +1,7 @@ <?php /** + * Get the text of a revision, resolving external storage if needed. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -15,11 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance ExternalStorage */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; +/** + * Maintenance script that gets the text of a revision, + * resolving external storage if needed. + * + * @ingroup Maintenance ExternalStorage + */ class DumpRev extends Maintenance { public function __construct() { parent::__construct(); @@ -37,7 +46,7 @@ class DumpRev extends Maintenance { $this->error( "Row not found", true ); } - $flags = explode( ',', $row->old_flags ); + $flags = explode( ',', $row->old_flags ); $text = $row->old_text; if ( in_array( 'external', $flags ) ) { $this->output( "External $text\n" ); @@ -76,4 +85,4 @@ class DumpRev extends Maintenance { } $maintClass = "DumpRev"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/storage/fixBug20757.php b/maintenance/storage/fixBug20757.php index 52ee825c..101aa068 100644 --- a/maintenance/storage/fixBug20757.php +++ b/maintenance/storage/fixBug20757.php @@ -21,13 +21,18 @@ * @ingroup Maintenance ExternalStorage */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; +/** + * Maintenance script to fix bug 20757. + * + * @ingroup Maintenance ExternalStorage + */ class FixBug20757 extends Maintenance { - var $batchSize = 10000; - var $mapCache = array(); - var $mapCacheSize = 0; - var $maxMapCacheSize = 1000000; + public $batchSize = 10000; + public $mapCache = array(); + public $mapCacheSize = 0; + public $maxMapCacheSize = 1000000; function __construct() { parent::__construct(); @@ -343,5 +348,4 @@ class FixBug20757 extends Maintenance { } $maintClass = 'FixBug20757'; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/storage/make-blobs b/maintenance/storage/make-blobs index 36cf9ced..16dcb672 100755 --- a/maintenance/storage/make-blobs +++ b/maintenance/storage/make-blobs @@ -6,11 +6,9 @@ if [ -z $2 ];then fi if [ -z $3 ]; then table=blobs -else +else table=$3 fi echo "CREATE DATABASE $2" | mysql -u wikiadmin -p`wikiadmin_pass` -h $1 && \ sed "s/blobs\>/$table/" blobs.sql | mysql -u wikiadmin -p`wikiadmin_pass` -h $1 $2 - - diff --git a/maintenance/storage/moveToExternal.php b/maintenance/storage/moveToExternal.php index 2dcc25c2..348fb773 100644 --- a/maintenance/storage/moveToExternal.php +++ b/maintenance/storage/moveToExternal.php @@ -24,9 +24,9 @@ define( 'REPORTING_INTERVAL', 1 ); if ( !defined( 'MEDIAWIKI' ) ) { - require_once( __DIR__ . '/../commandLine.inc' ); - require_once( __DIR__ . '/../../includes/ExternalStoreDB.php' ); - require_once( 'resolveStubs.php' ); + require_once __DIR__ . '/../commandLine.inc'; + require_once __DIR__ . '/../../includes/externalstore/ExternalStoreDB.php'; + require_once 'resolveStubs.php'; $fname = 'moveToExternal'; @@ -124,5 +124,3 @@ function moveToExternal( $cluster, $maxID, $minID = 1 ) { } } } - - diff --git a/maintenance/storage/orphanStats.php b/maintenance/storage/orphanStats.php index 82ee135b..1df1501e 100644 --- a/maintenance/storage/orphanStats.php +++ b/maintenance/storage/orphanStats.php @@ -1,7 +1,6 @@ <?php - /** - * Show some statistics on the blob_orphans table, created with trackBlobs.php + * Show some statistics on the blob_orphans table, created with trackBlobs.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 @@ -18,10 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * + * @file * @ingroup Maintenance ExternalStorage */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; + +/** + * Maintenance script that shows some statistics on the blob_orphans table, + * created with trackBlobs.php. + * + * @ingroup Maintenance ExternalStorage + */ class OrphanStats extends Maintenance { public function __construct() { parent::__construct(); @@ -67,4 +74,4 @@ class OrphanStats extends Maintenance { } $maintClass = "OrphanStats"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/storage/recompressTracked.php b/maintenance/storage/recompressTracked.php index 4098077f..b2663165 100644 --- a/maintenance/storage/recompressTracked.php +++ b/maintenance/storage/recompressTracked.php @@ -23,7 +23,7 @@ */ $optionsWithArgs = RecompressTracked::getOptionsWithArgs(); -require( __DIR__ . '/../commandLine.inc' ); +require __DIR__ . '/../commandLine.inc'; if ( count( $args ) < 1 ) { echo "Usage: php recompressTracked.php [options] <cluster> [... <cluster>...] @@ -42,20 +42,26 @@ Options: $job = RecompressTracked::newFromCommandLine( $args, $options ); $job->execute(); +/** + * Maintenance script that moves blobs indexed by trackBlobs.php to a specified + * list of destination clusters, and recompresses them in the process. + * + * @ingroup Maintenance ExternalStorage + */ class RecompressTracked { - var $destClusters; - var $batchSize = 1000; - var $orphanBatchSize = 1000; - var $reportingInterval = 10; - var $numProcs = 1; - var $useDiff, $pageBlobClass, $orphanBlobClass; - var $slavePipes, $slaveProcs, $prevSlaveId; - var $copyOnly = false; - var $isChild = false; - var $slaveId = false; - var $noCount = false; - var $debugLog, $infoLog, $criticalLog; - var $store; + public $destClusters; + public $batchSize = 1000; + public $orphanBatchSize = 1000; + public $reportingInterval = 10; + public $numProcs = 1; + public $useDiff, $pageBlobClass, $orphanBlobClass; + public $slavePipes, $slaveProcs, $prevSlaveId; + public $copyOnly = false; + public $isChild = false; + public $slaveId = false; + public $noCount = false; + public $debugLog, $infoLog, $criticalLog; + public $store; static $optionsWithArgs = array( 'procs', 'slave-id', 'debug-log', 'info-log', 'critical-log' ); static $cmdLineOptionMap = array( @@ -273,7 +279,7 @@ class RecompressTracked { */ function dispatchToSlave( $slaveId, $args ) { $args = (array)$args; - $cmd = implode( ' ', $args ); + $cmd = implode( ' ', $args ); fwrite( $this->slavePipes[$slaveId], "$cmd\n" ); } @@ -517,7 +523,7 @@ class RecompressTracked { * * Write the new URL to the text table and set the bt_moved flag. * - * This is done in a single transaction to provide restartable behaviour + * This is done in a single transaction to provide restartable behavior * without data loss. * * The transaction is kept short to reduce locking. @@ -670,10 +676,10 @@ class RecompressTracked { * Class to represent a recompression operation for a single CGZ blob */ class CgzCopyTransaction { - var $parent; - var $blobClass; - var $cgz; - var $referrers; + public $parent; + public $blobClass; + public $cgz; + public $referrers; /** * Create a transaction from a RecompressTracked object @@ -803,4 +809,3 @@ class CgzCopyTransaction { } } } - diff --git a/maintenance/storage/resolveStubs.php b/maintenance/storage/resolveStubs.php index 7e288e13..e47d6407 100644 --- a/maintenance/storage/resolveStubs.php +++ b/maintenance/storage/resolveStubs.php @@ -1,7 +1,7 @@ <?php /** - * Script to convert history stubs that point to an external row to direct - * external pointers. + * Convert history stubs that point to an external row to direct external + * pointers. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ define( 'REPORTING_INTERVAL', 100 ); if ( !defined( 'MEDIAWIKI' ) ) { $optionsWithArgs = array( 'm' ); - require_once( __DIR__ . '/../commandLine.inc' ); + require_once __DIR__ . '/../commandLine.inc'; resolveStubs(); } @@ -110,4 +110,3 @@ function resolveStub( $id, $stubText, $flags ) { ), $fname ); } - diff --git a/maintenance/storage/storageTypeStats.php b/maintenance/storage/storageTypeStats.php index 1afecc4e..e33057f6 100644 --- a/maintenance/storage/storageTypeStats.php +++ b/maintenance/storage/storageTypeStats.php @@ -19,7 +19,7 @@ * @ingroup Maintenance ExternalStorage */ -require_once( __DIR__ . '/../Maintenance.php' ); +require_once __DIR__ . '/../Maintenance.php'; class StorageTypeStats extends Maintenance { function execute() { @@ -112,5 +112,4 @@ SQL; } $maintClass = 'StorageTypeStats'; -require_once( RUN_MAINTENANCE_IF_MAIN ); - +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/storage/testCompression.php b/maintenance/storage/testCompression.php index 998ebe48..fdc28d9b 100644 --- a/maintenance/storage/testCompression.php +++ b/maintenance/storage/testCompression.php @@ -1,5 +1,7 @@ <?php /** + * Test revision text compression and decompression. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,12 +18,11 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @ingroup Maintenance - * @see wfWaitForSlaves() + * @ingroup Maintenance ExternalStorage */ $optionsWithArgs = array( 'start', 'limit', 'type' ); -require( __DIR__ . '/../commandLine.inc' ); +require __DIR__ . '/../commandLine.inc'; if ( !isset( $args[0] ) ) { echo "Usage: php testCompression.php [--type=<type>] [--start=<start-date>] [--limit=<num-revs>] <page-title>\n"; @@ -65,7 +66,7 @@ $uncompressedSize = 0; $t = -microtime( true ); foreach ( $res as $row ) { $revision = new Revision( $row ); - $text = $revision->getText(); + $text = $revision->getSerializedData(); $uncompressedSize += strlen( $text ); $hashes[$row->rev_id] = md5( $text ); $keys[$row->rev_id] = $blob->addItem( $text ); @@ -98,4 +99,3 @@ foreach ( $keys as $id => $key ) { } $t += microtime( true ); printf( "Decompression time: %5.2f ms\n", $t * 1000 ); - diff --git a/maintenance/storage/trackBlobs.php b/maintenance/storage/trackBlobs.php index 214168a8..7857dd95 100644 --- a/maintenance/storage/trackBlobs.php +++ b/maintenance/storage/trackBlobs.php @@ -22,7 +22,7 @@ * @see wfWaitForSlaves() */ -require( __DIR__ . '/../commandLine.inc' ); +require __DIR__ . '/../commandLine.inc'; if ( count( $args ) < 1 ) { @@ -37,12 +37,12 @@ $tracker->run(); echo "All done.\n"; class TrackBlobs { - var $clusters, $textClause; - var $doBlobOrphans; - var $trackedBlobs = array(); + public $clusters, $textClause; + public $doBlobOrphans; + public $trackedBlobs = array(); - var $batchSize = 1000; - var $reportingInterval = 10; + public $batchSize = 1000; + public $reportingInterval = 10; function __construct( $clusters ) { $this->clusters = $clusters; diff --git a/maintenance/syncFileBackend.php b/maintenance/syncFileBackend.php index a29647b5..f0be709f 100644 --- a/maintenance/syncFileBackend.php +++ b/maintenance/syncFileBackend.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that syncs one file backend to another based on @@ -34,21 +34,51 @@ class SyncFileBackend extends Maintenance { parent::__construct(); $this->mDescription = "Sync one file backend with another using the journal"; $this->addOption( 'src', 'Name of backend to sync from', true, true ); - $this->addOption( 'dst', 'Name of destination backend to sync', true, true ); + $this->addOption( 'dst', 'Name of destination backend to sync', false, true ); $this->addOption( 'start', 'Starting journal ID', false, true ); $this->addOption( 'end', 'Ending journal ID', false, true ); $this->addOption( 'posdir', 'Directory to read/record journal positions', false, true ); + $this->addOption( 'posdump', 'Just dump current journal position into the position dir.' ); + $this->addOption( 'postime', 'For position dumps, get the ID at this time', false, true ); + $this->addOption( 'backoff', 'Stop at entries younger than this age (sec).', false, true ); $this->addOption( 'verbose', 'Verbose mode', false, false, 'v' ); $this->setBatchSize( 50 ); } public function execute() { $src = FileBackendGroup::singleton()->get( $this->getOption( 'src' ) ); - $dst = FileBackendGroup::singleton()->get( $this->getOption( 'dst' ) ); $posDir = $this->getOption( 'posdir' ); $posFile = $posDir ? $posDir . '/' . wfWikiID() : false; + if ( $this->hasOption( 'posdump' ) ) { + // Just dump the current position into the specified position dir + if ( !$this->hasOption( 'posdir' ) ) { + $this->error( "Param posdir required!", 1 ); + } + if ( $this->hasOption( 'postime' ) ) { + $id = (int)$src->getJournal()->getPositionAtTime( $this->getOption( 'postime' ) ); + $this->output( "Requested journal position is $id.\n" ); + } else { + $id = (int)$src->getJournal()->getCurrentPosition(); + $this->output( "Current journal position is $id.\n" ); + } + if ( file_put_contents( $posFile, $id, LOCK_EX ) !== false ) { + $this->output( "Saved journal position file.\n" ); + } else { + $this->output( "Could not save journal position file.\n" ); + } + if ( $this->isQuiet() ) { + print $id; // give a single machine-readable number + } + return; + } + + if ( !$this->hasOption( 'dst' ) ) { + $this->error( "Param dst required!", 1 ); + } + $dst = FileBackendGroup::singleton()->get( $this->getOption( 'dst' ) ); + $start = $this->getOption( 'start', 0 ); if ( !$start && $posFile && is_dir( $posDir ) ) { $start = is_file( $posFile ) @@ -59,7 +89,13 @@ class SyncFileBackend extends Maintenance { } else { $startFromPosFile = false; } - $end = $this->getOption( 'end', INF ); + + if ( $this->hasOption( 'backoff' ) ) { + $time = time() - $this->getOption( 'backoff', 0 ); + $end = (int)$src->getJournal()->getPositionAtTime( $time ); + } else { + $end = $this->getOption( 'end', INF ); + } $this->output( "Synchronizing backend '{$dst->getName()}' to '{$src->getName()}'...\n" ); $this->output( "Starting journal position is $start.\n" ); @@ -67,8 +103,15 @@ class SyncFileBackend extends Maintenance { $this->output( "Ending journal position is $end.\n" ); } + // Periodically update the position file + $callback = function( $pos ) use ( $startFromPosFile, $posFile, $start ) { + if ( $startFromPosFile && $pos >= $start ) { // successfully advanced + file_put_contents( $posFile, $pos, LOCK_EX ); + } + }; + // Actually sync the dest backend with the reference backend - $lastOKPos = $this->syncBackends( $src, $dst, $start, $end ); + $lastOKPos = $this->syncBackends( $src, $dst, $start, $end, $callback ); // Update the sync position file if ( $startFromPosFile && $lastOKPos >= $start ) { // successfully advanced @@ -102,9 +145,12 @@ class SyncFileBackend extends Maintenance { * @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 */ - protected function syncBackends( FileBackend $src, FileBackend $dst, $start, $end ) { + protected function syncBackends( + FileBackend $src, FileBackend $dst, $start, $end, Closure $callback + ) { $lastOKPos = 0; // failed $first = true; // first batch @@ -135,6 +181,7 @@ class SyncFileBackend extends Maintenance { $status = $this->syncFileBatch( array_keys( $pathsInBatch ), $src, $dst ); if ( $status->isOK() ) { $lastOKPos = max( $lastOKPos, $lastPosInBatch ); + $callback( $lastOKPos ); // update position file } else { $this->error( print_r( $status->getErrorsArray(), true ) ); break; // no gaps; everything up to $lastPos must be OK @@ -249,4 +296,4 @@ class SyncFileBackend extends Maintenance { } $maintClass = "SyncFileBackend"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/tables.sql b/maintenance/tables.sql index 52b835fd..de92ef53 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -86,10 +86,12 @@ CREATE TABLE /*_*/user ( -- Same with passwords. user_email tinytext NOT NULL, - -- This is a timestamp which is updated when a user - -- logs in, logs out, changes preferences, or performs - -- some other action requiring HTML cache invalidation - -- to ensure that the UI is updated. + -- If the browser sends an If-Modified-Since header, a 304 response is + -- suppressed if the value in this field for the current user is later than + -- the value in the IMS header. That is, this field is an invalidation timestamp + -- for the browser cache of logged-in users. Among other things, it is used + -- to prevent pages generated for a previously logged in user from being + -- displayed after a session expiry followed by a fresh login. user_touched binary(14) NOT NULL default '', -- A pseudorandomly generated value that is stored in @@ -152,7 +154,7 @@ CREATE TABLE /*_*/user_groups ( -- with particular permissions. A user will have the combined -- permissions of any group they're explicitly in, plus -- the implicit '*' and 'user' groups. - ug_group varbinary(32) NOT NULL default '' + ug_group varbinary(255) NOT NULL default '' ) /*$wgDBTableOptions*/; CREATE UNIQUE INDEX /*i*/ug_user_group ON /*_*/user_groups (ug_user,ug_group); @@ -164,7 +166,7 @@ CREATE INDEX /*i*/ug_group ON /*_*/user_groups (ug_group); CREATE TABLE /*_*/user_former_groups ( -- Key to user_id ufg_user int unsigned NOT NULL default 0, - ufg_group varbinary(32) NOT NULL default '' + ufg_group varbinary(255) NOT NULL default '' ) /*$wgDBTableOptions*/; CREATE UNIQUE INDEX /*i*/ufg_user_group ON /*_*/user_former_groups (ufg_user,ufg_group); @@ -260,7 +262,10 @@ CREATE TABLE /*_*/page ( page_latest int unsigned NOT NULL, -- Uncompressed length in bytes of the page's current source text. - page_len int unsigned NOT NULL + page_len int unsigned NOT NULL, + + -- content model, see CONTENT_MODEL_XXX constants + page_content_model varbinary(32) DEFAULT NULL ) /*$wgDBTableOptions*/; CREATE UNIQUE INDEX /*i*/name_title ON /*_*/page (page_namespace,page_title); @@ -316,7 +321,13 @@ CREATE TABLE /*_*/revision ( rev_parent_id int unsigned default NULL, -- SHA-1 text content hash in base-36 - rev_sha1 varbinary(32) NOT NULL default '' + rev_sha1 varbinary(32) NOT NULL default '', + + -- content model, see CONTENT_MODEL_XXX constants + rev_content_model varbinary(32) DEFAULT NULL, + + -- content format, see CONTENT_FORMAT_XXX constants + rev_content_format varbinary(64) DEFAULT NULL ) /*$wgDBTableOptions*/ MAX_ROWS=10000000 AVG_ROW_LENGTH=1024; -- In case tables are created as MyISAM, use row hints for MySQL <5.0 to avoid 4GB limit @@ -369,6 +380,8 @@ CREATE TABLE /*_*/text ( -- fields, with several caveats. -- CREATE TABLE /*_*/archive ( + -- Primary key + ar_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, ar_namespace int NOT NULL default 0, ar_title varchar(255) binary NOT NULL default '', @@ -427,7 +440,13 @@ CREATE TABLE /*_*/archive ( ar_parent_id int unsigned default NULL, -- SHA-1 text content hash in base-36 - ar_sha1 varbinary(32) NOT NULL default '' + ar_sha1 varbinary(32) NOT NULL default '', + + -- content model, see CONTENT_MODEL_XXX constants + ar_content_model varbinary(32) DEFAULT NULL, + + -- content format, see CONTENT_FORMAT_XXX constants + ar_content_format varbinary(64) DEFAULT NULL ) /*$wgDBTableOptions*/; CREATE INDEX /*i*/name_title_timestamp ON /*_*/archive (ar_namespace,ar_title,ar_timestamp); @@ -544,10 +563,10 @@ CREATE UNIQUE INDEX /*i*/cl_from ON /*_*/categorylinks (cl_from,cl_to); -- callers won't be using an index: fix this? CREATE INDEX /*i*/cl_sortkey ON /*_*/categorylinks (cl_to,cl_type,cl_sortkey,cl_from); --- Not really used? +-- Used by the API (and some extensions) CREATE INDEX /*i*/cl_timestamp ON /*_*/categorylinks (cl_to,cl_timestamp); --- For finding rows with outdated collation +-- FIXME: Not used, delete this CREATE INDEX /*i*/cl_collation ON /*_*/categorylinks (cl_collation); -- @@ -584,6 +603,9 @@ CREATE INDEX /*i*/cat_pages ON /*_*/category (cat_pages); -- Track links to external URLs -- CREATE TABLE /*_*/externallinks ( + -- Primary key + el_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, + -- page_id of the referring page el_from int unsigned NOT NULL default 0, @@ -608,21 +630,6 @@ CREATE INDEX /*i*/el_from ON /*_*/externallinks (el_from, el_to(40)); CREATE INDEX /*i*/el_to ON /*_*/externallinks (el_to(60), el_from); CREATE INDEX /*i*/el_index ON /*_*/externallinks (el_index(60)); - --- --- Track external user accounts, if ExternalAuth is used --- -CREATE TABLE /*_*/external_user ( - -- Foreign key to user_id - eu_local_id int unsigned NOT NULL PRIMARY KEY, - - -- Some opaque identifier provided by the external database - eu_external_id varchar(255) binary NOT NULL -) /*$wgDBTableOptions*/; - -CREATE UNIQUE INDEX /*i*/eu_external_id ON /*_*/external_user (eu_external_id); - - -- -- Track interlanguage links -- @@ -656,7 +663,8 @@ CREATE TABLE /*_*/iwlinks ( ) /*$wgDBTableOptions*/; CREATE UNIQUE INDEX /*i*/iwl_from ON /*_*/iwlinks (iwl_from, iwl_prefix, iwl_title); -CREATE UNIQUE INDEX /*i*/iwl_prefix_title_from ON /*_*/iwlinks (iwl_prefix, iwl_title, iwl_from); +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); -- @@ -689,9 +697,6 @@ CREATE TABLE /*_*/site_stats ( -- Number of users that still edit ss_active_users bigint default '-1', - -- Deprecated, no longer updated as of 1.5 - ss_admins int default '-1', - -- Number of images, equivalent to SELECT COUNT(*) FROM image ss_images int default 0 ) /*$wgDBTableOptions*/; @@ -759,6 +764,9 @@ CREATE TABLE /*_*/ipblocks ( -- 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 tinyblob NOT NULL, ipb_range_end tinyblob NOT NULL, @@ -806,7 +814,7 @@ CREATE TABLE /*_*/image ( img_width int NOT NULL default 0, img_height int NOT NULL default 0, - -- Extracted EXIF metadata stored as a serialized PHP array. + -- Extracted Exif metadata stored as a serialized PHP array. img_metadata mediumblob NOT NULL, -- For images, bits per pixel if known. @@ -846,7 +854,9 @@ 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); +CREATE INDEX /*i*/img_sha1 ON /*_*/image (img_sha1(10)); +-- Used to get media of one type +CREATE INDEX /*i*/img_media_mime ON /*_*/image (img_media_type,img_major_mime,img_minor_mime); -- @@ -884,7 +894,7 @@ CREATE INDEX /*i*/oi_usertext_timestamp ON /*_*/oldimage (oi_user_text,oi_timest 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(14)); -CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1); +CREATE INDEX /*i*/oi_sha1 ON /*_*/oldimage (oi_sha1(10)); -- @@ -932,7 +942,10 @@ CREATE TABLE /*_*/filearchive ( fa_timestamp binary(14) default '', -- Visibility of deleted revisions, bitfield - fa_deleted tinyint unsigned NOT NULL default 0 + fa_deleted tinyint unsigned NOT NULL default 0, + + -- sha1 hash of file content + fa_sha1 varbinary(32) NOT NULL default '' ) /*$wgDBTableOptions*/; -- pick out by image name @@ -943,6 +956,8 @@ CREATE INDEX /*i*/fa_storage_group ON /*_*/filearchive (fa_storage_group, fa_sto 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(10)); -- @@ -976,8 +991,10 @@ CREATE TABLE /*_*/uploadstash ( -- chunk counter starts at 0, current offset is stored in us_size us_chunk_inx int unsigned NULL, - -- file properties from File::getPropsFromPath. these may prove unnecessary. - -- + -- Serialized file properties from File::getPropsFromPath + us_props blob, + + -- file size in bytes us_size int unsigned NOT NULL, -- this hash comes from File::sha1Base36(), and is 31 characters us_sha1 varchar(31) NOT NULL, @@ -1042,13 +1059,9 @@ CREATE TABLE /*_*/recentchanges ( -- rev_id of the prior revision, for generating diff links. rc_last_oldid int unsigned NOT NULL default 0, - -- The type of change entry (RC_EDIT,RC_NEW,RC_LOG) + -- The type of change entry (RC_EDIT,RC_NEW,RC_LOG,RC_EXTERNAL) rc_type tinyint unsigned NOT NULL default 0, - -- These may no longer be used, with the new move log. - rc_moved_to_ns tinyint unsigned NOT NULL default 0, - rc_moved_to_title varchar(255) 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. @@ -1067,7 +1080,7 @@ CREATE TABLE /*_*/recentchanges ( -- Visibility of recent changes items, bitfield rc_deleted tinyint unsigned NOT NULL default 0, - -- Value corresonding to log_id, specific log entries + -- Value corresponding to log_id, specific log entries rc_logid int unsigned NOT NULL default 0, -- Store log type info here, or null rc_log_type varbinary(255) NULL default NULL, @@ -1123,7 +1136,7 @@ CREATE TABLE /*_*/searchindex ( -- Munged version of body text si_text mediumtext NOT NULL -) ENGINE=MyISAM; +) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE UNIQUE INDEX /*i*/si_page ON /*_*/searchindex (si_page); CREATE FULLTEXT INDEX /*i*/si_title ON /*_*/searchindex (si_title); @@ -1228,7 +1241,8 @@ CREATE TABLE /*_*/logging ( -- Freeform text. Interpreted as edit history comments. log_comment varchar(255) NOT NULL default '', - -- LF separated list of miscellaneous parameters + -- miscellaneous parameters: + -- LF separated list (old system) or serialized PHP array (new system) log_params blob NOT NULL, -- rev_deleted for logs @@ -1275,9 +1289,27 @@ CREATE TABLE /*_*/job ( -- Any other parameters to the command -- Stored as a PHP serialized array, or an empty string if there are no parameters - job_params blob NOT NULL + job_params blob NOT NULL, + + -- Random, non-unique, number used for job acquisition (for lock concurrency) + job_random integer unsigned NOT NULL default 0, + + -- The number of times this job has been locked + job_attempts integer unsigned NOT NULL default 0, + + -- Field that conveys process locks on rows via process UUIDs + job_token varbinary(32) NOT NULL default '', + + -- Timestamp when the job was locked + job_token_timestamp varbinary(14) NULL default NULL, + + -- Base 36 SHA1 of the job parameters relevant to detecting duplicates + job_sha1 varbinary(32) NOT NULL default '' ) /*$wgDBTableOptions*/; +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, job_params(128)); CREATE INDEX /*i*/job_timestamp ON /*_*/job (job_timestamp); @@ -1382,6 +1414,7 @@ CREATE TABLE /*_*/page_props ( ) /*$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); -- A table to log updates, one text key row per update. @@ -1479,4 +1512,69 @@ CREATE TABLE /*_*/module_deps ( ) /*$wgDBTableOptions*/; 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 UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + + -- Global identifier for the site, ie 'enwiktionary' + site_global_key varbinary(32) NOT NULL, + + -- Type of the site, ie 'mediawiki' + site_type varbinary(32) NOT NULL, + + -- Group of the site, ie 'wikipedia' + site_group varbinary(32) NOT NULL, + + -- Source of the site data, ie 'local', 'wikidata', 'my-magical-repo' + site_source varbinary(32) NOT NULL, + + -- Language code of the sites primary language. + site_language varbinary(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 varbinary(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 VARCHAR(255) NOT NULL, + + -- Type dependent site data. + site_data BLOB 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 bool NOT NULL, + + -- Type dependent site config. + -- For instance if template transclusion should be allowed if it's a MediaWiki. + site_config BLOB NOT NULL +) /*$wgDBTableOptions*/; + +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 UNSIGNED NOT NULL, + + -- local key type, ie 'interwiki' or 'langlink' + si_type varbinary(32) NOT NULL, + + -- local key value, ie 'en' or 'wiktionary' + si_key varbinary(32) NOT NULL +) /*$wgDBTableOptions*/; + +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); + -- vim: sw=2 sts=2 et diff --git a/maintenance/term/MWTerm.php b/maintenance/term/MWTerm.php index ca0f95d2..c52f07cc 100644 --- a/maintenance/term/MWTerm.php +++ b/maintenance/term/MWTerm.php @@ -19,12 +19,14 @@ * http://www.gnu.org/copyleft/gpl.html * * @file - * @ingroup Testing + * @ingroup Maintenance Testing * @todo Fixme: Make this more generic */ /** * Terminal that supports ANSI escape sequences. + * + * @ingroup Maintenance Testing */ class AnsiTermColorer { function __construct() { @@ -56,6 +58,8 @@ class AnsiTermColorer { /** * A colour-less terminal + * + * @ingroup Maintenance Testing */ class DummyTermColorer { public function color( $color ) { @@ -66,4 +70,3 @@ class DummyTermColorer { return ''; } } - diff --git a/maintenance/tidyUpBug37714.php b/maintenance/tidyUpBug37714.php new file mode 100644 index 00000000..1ad9c7ee --- /dev/null +++ b/maintenance/tidyUpBug37714.php @@ -0,0 +1,49 @@ +<?php +require_once __DIR__ . '/Maintenance.php'; + +/** + * Fixes all rows affected by https://bugzilla.wikimedia.org/show_bug.cgi?id=37714 + */ +class TidyUpBug37714 extends Maintenance { + public function execute() { + // Search for all log entries which are about changing the visability of other log entries. + $result = wfGetDB( DB_SLAVE )->select( + 'logging', + array( 'log_id', 'log_params' ), + array( + 'log_type' => array( 'suppress', 'delete' ), + 'log_action' => 'event', + 'log_namespace' => NS_SPECIAL, + 'log_title' => SpecialPage::getTitleFor( 'Log' )->getText() + ), + __METHOD__ + ); + + foreach ( $result as $row ) { + $paramLines = explode( "\n", $row->log_params ); + $ids = explode( ',', $paramLines[0] ); // Array dereferencing is PHP >= 5.4 :( + $result = wfGetDB( DB_SLAVE )->select( // Work out what log entries were changed here. + 'logging', + 'log_type', + array( 'log_id' => $ids ), + __METHOD__, + 'DISTINCT' + ); + if ( $result->numRows() === 1 ) { + // If there's only one type, the target title can be set to include it. + $logTitle = SpecialPage::getTitleFor( 'Log', $result->current()->log_type )->getText(); + $this->output( 'Set log_title to "' . $logTitle . '" for log entry ' . $row->log_id . ".\n" ); + wfGetDB( DB_MASTER )->update( + 'logging', + array( 'log_title' => $logTitle ), + array( 'log_id' => $row->log_id ), + __METHOD__ + ); + wfWaitForSlaves(); + } + } + } +} + +$maintClass = 'TidyUpBug37714'; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/undelete.php b/maintenance/undelete.php index ea8b0c4b..c890c69b 100644 --- a/maintenance/undelete.php +++ b/maintenance/undelete.php @@ -21,7 +21,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; class Undelete extends Maintenance { public function __construct() { @@ -55,4 +55,4 @@ class Undelete extends Maintenance { } $maintClass = "Undelete"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/update.php b/maintenance/update.php index 877f1366..378217fd 100644 --- a/maintenance/update.php +++ b/maintenance/update.php @@ -26,13 +26,12 @@ */ if ( !function_exists( 'version_compare' ) || ( version_compare( phpversion(), '5.3.2' ) < 0 ) ) { - echo "You are using PHP version " . phpversion() . " but MediaWiki needs PHP 5.3.2 or higher. ABORTING.\n" . - "Check if you have a newer php executable with a different name, such as php5.\n"; - die( 1 ); + require dirname( __FILE__ ) . '/../includes/PHPVersionError.php'; + wfPHPVersionError( 'cli' ); } $wgUseMasterForMaintenance = true; -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to run database schema updates. @@ -40,7 +39,6 @@ require_once( __DIR__ . '/Maintenance.php' ); * @ingroup Maintenance */ class UpdateMediaWiki extends Maintenance { - function __construct() { parent::__construct(); $this->mDescription = "MediaWiki database updater"; @@ -48,6 +46,8 @@ class UpdateMediaWiki extends Maintenance { $this->addOption( 'quick', 'Skip 5 second countdown before starting' ); $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( 'force', 'Override when $wgAllowSchemaUpdates disables this script' ); } @@ -83,10 +83,24 @@ class UpdateMediaWiki extends Maintenance { function execute() { global $wgVersion, $wgTitle, $wgLang, $wgAllowSchemaUpdates; - if( !$wgAllowSchemaUpdates && !$this->hasOption( 'force' ) ) { + 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.\n\n" - . "If you know what you are doing, you can continue with --force", true ); + . "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" + . "else to inspect and run.\n\n" + . "If you know what you are doing, you can continue with --force\n", true ); + } + + $this->fileHandle = null; + if ( substr( $this->getOption( 'schema' ), 0, 2 ) === "--" ) { + $this->error( "The --schema option requires a file as an argument.\n", true ); + } elseif ( $this->hasOption( 'schema' ) ) { + $file = $this->getOption( 'schema' ); + $this->fileHandle = fopen( $file, "w" ); + if ( $this->fileHandle === false ) { + $err = error_get_last(); + $this->error( "Problem opening the schema file for writing: $file\n\t{$err['message']}", true ); + } } $wgLang = Language::factory( 'en' ); @@ -108,6 +122,9 @@ class UpdateMediaWiki extends Maintenance { $db = wfGetDB( DB_MASTER ); $this->output( "Going to run database updates for " . wfWikiID() . "\n" ); + if ( $db->getType() === 'sqlite' ) { + $this->output( "Using SQLite file: '{$db->mDatabaseFile}'\n" ); + } $this->output( "Depending on the size of your database this may take a while!\n" ); if ( !$this->hasOption( 'quick' ) ) { @@ -117,21 +134,35 @@ class UpdateMediaWiki extends Maintenance { $shared = $this->hasOption( 'doshared' ); - $updates = array( 'core', 'extensions', 'stats' ); - if( !$this->hasOption('nopurge') ) { - $updates[] = 'purge'; + $updates = array( 'core', 'extensions' ); + if ( !$this->hasOption( 'schema' ) ) { + if ( $this->hasOption( 'noschema' ) ) { + $updates[] = 'noschema'; + } + $updates[] = 'stats'; } $updater = DatabaseUpdater::newForDb( $db, $shared, $this ); $updater->doUpdates( $updates ); - foreach( $updater->getPostDatabaseUpdateMaintenance() as $maint ) { - if ( $updater->updateRowExists( $maint ) ) { + foreach ( $updater->getPostDatabaseUpdateMaintenance() as $maint ) { + $child = $this->runChild( $maint ); + + // LoggedUpdateMaintenance is checking the updatelog itself + $isLoggedUpdate = is_a( $child, 'LoggedUpdateMaintenance' ); + + if ( !$isLoggedUpdate && $updater->updateRowExists( $maint ) ) { continue; } - $child = $this->runChild( $maint ); + $child->execute(); - $updater->insertUpdateRow( $maint ); + if ( !$isLoggedUpdate ) { + $updater->insertUpdateRow( $maint ); + } + } + + if ( !$this->hasOption( 'nopurge' ) ) { + $updater->purgeCache(); } $this->output( "\nDone.\n" ); @@ -153,4 +184,4 @@ class UpdateMediaWiki extends Maintenance { } $maintClass = 'UpdateMediaWiki'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/updateArticleCount.php b/maintenance/updateArticleCount.php index 4d49dd2d..7964a21f 100644 --- a/maintenance/updateArticleCount.php +++ b/maintenance/updateArticleCount.php @@ -23,7 +23,7 @@ * @author Rob Church <robchur@gmail.com> */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to provide a better count of the number of articles @@ -58,4 +58,4 @@ class UpdateArticleCount extends Maintenance { } $maintClass = "UpdateArticleCount"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/updateCollation.php b/maintenance/updateCollation.php index b732508f..964b3138 100644 --- a/maintenance/updateCollation.php +++ b/maintenance/updateCollation.php @@ -26,7 +26,7 @@ #$optionsWithArgs = array( 'begin', 'max-slave-lag' ); -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that will find all rows in the categorylinks table @@ -35,10 +35,10 @@ require_once( __DIR__ . '/Maintenance.php' ); * @ingroup Maintenance */ class UpdateCollation extends Maintenance { - const BATCH_SIZE = 50; // Number of rows to process in one batch + const BATCH_SIZE = 10000; // Number of rows to process in one batch const SYNC_INTERVAL = 20; // Wait for slaves after this many batches - var $sizeHistogram = array(); + public $sizeHistogram = array(); public function __construct() { parent::__construct(); @@ -68,7 +68,7 @@ TEXT; } public function execute() { - global $wgCategoryCollation, $wgMiserMode; + global $wgCategoryCollation; $dbw = $this->getDB( DB_MASTER ); $force = $this->getOption( 'force' ); @@ -82,10 +82,17 @@ TEXT; $collation = Collation::singleton(); } - $options = array( 'LIMIT' => self::BATCH_SIZE, 'STRAIGHT_JOIN' ); + // Collation sanity check: in some cases the constructor will work, + // but this will raise an exception, breaking all category pages + $collation->getFirstLetter( 'MediaWiki' ); + + $options = array( + 'LIMIT' => self::BATCH_SIZE, + 'ORDER BY' => 'cl_to, cl_type, cl_from', + 'STRAIGHT_JOIN', + ); if ( $force || $dryRun ) { - $options['ORDER BY'] = 'cl_from, cl_to'; $collationConds = array(); } else { if ( $this->hasOption( 'previous-collation' ) ) { @@ -96,20 +103,20 @@ TEXT; ); } - if ( !$wgMiserMode ) { + $count = $dbw->estimateRowCount( + 'categorylinks', + '*', + $collationConds, + __METHOD__ + ); + // Improve estimate if feasible + if ( $count < 1000000 ) { $count = $dbw->selectField( 'categorylinks', 'COUNT(*)', $collationConds, __METHOD__ ); - } else { - $count = $dbw->estimateRowCount( - 'categorylinks', - '*', - $collationConds, - __METHOD__ - ); } if ( $count == 0 ) { $this->output( "Collations up-to-date.\n" ); @@ -126,7 +133,7 @@ TEXT; $res = $dbw->select( array( 'categorylinks', 'page' ), array( 'cl_from', 'cl_to', 'cl_sortkey_prefix', 'cl_collation', - 'cl_sortkey', 'page_namespace', 'page_title' + 'cl_sortkey', 'cl_type', 'page_namespace', 'page_title' ), array_merge( $collationConds, $batchConds, array( 'cl_from = page_id' ) ), __METHOD__, @@ -186,12 +193,8 @@ TEXT; $dbw->commit( __METHOD__ ); } - if ( ( $force || $dryRun ) && $row ) { - $encFrom = $dbw->addQuotes( $row->cl_from ); - $encTo = $dbw->addQuotes( $row->cl_to ); - $batchConds = array( - "(cl_from = $encFrom AND cl_to > $encTo) " . - " OR cl_from > $encFrom" ); + if ( $row ) { + $batchConds = array( $this->getBatchCondition( $row ) ); } $count += $res->numRows(); @@ -212,6 +215,32 @@ TEXT; } } + /** + * Return an SQL expression selecting rows which sort above the given row, + * assuming an ordering of cl_to, cl_type, cl_from + */ + function getBatchCondition( $row ) { + $dbw = $this->getDB( DB_MASTER ); + $fields = array( 'cl_to', 'cl_type', 'cl_from' ); + $first = true; + $cond = false; + $prefix = false; + foreach ( $fields as $field ) { + $encValue = $dbw->addQuotes( $row->$field ); + $inequality = "$field > $encValue"; + $equality = "$field = $encValue"; + if ( $first ) { + $cond = $inequality; + $prefix = $equality; + $first = false; + } else { + $cond .= " OR ($prefix AND $inequality)"; + $prefix .= " AND $equality"; + } + } + return $cond; + } + function updateSortKeySizeHistogram( $key ) { $length = strlen( $key ); if ( !isset( $this->sizeHistogram[$length] ) ) { @@ -278,4 +307,4 @@ TEXT; } $maintClass = "UpdateCollation"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/updateDoubleWidthSearch.php b/maintenance/updateDoubleWidthSearch.php index dc7398ad..41988d1b 100644 --- a/maintenance/updateDoubleWidthSearch.php +++ b/maintenance/updateDoubleWidthSearch.php @@ -23,7 +23,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to normalize double-byte latin UTF-8 characters. @@ -72,4 +72,4 @@ class UpdateDoubleWidthSearch extends Maintenance { } $maintClass = "UpdateDoubleWidthSearch"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/updateRestrictions.php b/maintenance/updateRestrictions.php index 8699dc26..175447e7 100644 --- a/maintenance/updateRestrictions.php +++ b/maintenance/updateRestrictions.php @@ -24,7 +24,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script that updates page_restrictions table from @@ -114,4 +114,4 @@ class UpdateRestrictions extends Maintenance { } $maintClass = "UpdateRestrictions"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/updateSearchIndex.php b/maintenance/updateSearchIndex.php index 2a71e7ed..0691bee8 100644 --- a/maintenance/updateSearchIndex.php +++ b/maintenance/updateSearchIndex.php @@ -28,7 +28,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script for periodic off-peak updating of the search index. @@ -60,7 +60,7 @@ class UpdateSearchIndex extends Maintenance { # We can safely delete the file when we're done though. $start = file_get_contents( 'searchUpdate.pos' ); unlink( 'searchUpdate.pos' ); - } elseif( is_readable( $posFile ) ) { + } elseif ( is_readable( $posFile ) ) { $start = file_get_contents( $posFile ); } else { $start = wfTimestamp( TS_MW, time() - 86400 ); @@ -96,10 +96,9 @@ class UpdateSearchIndex extends Maintenance { $end = $dbw->timestamp( $end ); $page = $dbw->tableName( 'page' ); - $sql = "SELECT rc_cur_id,rc_type,rc_moved_to_ns,rc_moved_to_title FROM $recentchanges - JOIN $page ON rc_cur_id=page_id AND rc_this_oldid=page_latest - WHERE rc_timestamp BETWEEN '$start' AND '$end' - "; + $sql = "SELECT rc_cur_id FROM $recentchanges + JOIN $page ON rc_cur_id=page_id AND rc_this_oldid=page_latest + WHERE rc_type != " . RC_LOG . " AND rc_timestamp BETWEEN '$start' AND '$end'"; $res = $dbw->query( $sql, __METHOD__ ); $this->updateSearchIndex( $maxLockTime, array( $this, 'searchIndexUpdateCallback' ), $dbw, $res ); @@ -108,19 +107,9 @@ class UpdateSearchIndex extends Maintenance { } public function searchIndexUpdateCallback( $dbw, $row ) { - if ( $row->rc_type == RC_MOVE || $row->rc_type == RC_MOVE_OVER_REDIRECT ) { - # Rename searchindex entry - $titleObj = Title::makeTitle( $row->rc_moved_to_ns, $row->rc_moved_to_title ); - $title = $titleObj->getPrefixedDBkey(); - $this->output( "$title..." ); - $u = new SearchUpdate( $row->rc_cur_id, $title, false ); - $u->doUpdate(); - $this->output( "\n" ); - } elseif ( $row->rc_type !== RC_LOG ) { - $this->updateSearchIndexForPage( $dbw, $row->rc_cur_id ); - } + $this->updateSearchIndexForPage( $dbw, $row->rc_cur_id ); } } $maintClass = "UpdateSearchIndex"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/updateSpecialPages.php b/maintenance/updateSpecialPages.php index 3f1a90bb..3432cb20 100644 --- a/maintenance/updateSpecialPages.php +++ b/maintenance/updateSpecialPages.php @@ -22,7 +22,7 @@ * @ingroup Maintenance */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to update cached special pages. @@ -33,41 +33,22 @@ class UpdateSpecialPages extends Maintenance { public function __construct() { parent::__construct(); $this->addOption( 'list', 'List special page names' ); - $this->addOption( 'only', 'Only update "page". Ex: --only=BrokenRedirects', false, true ); + $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 ); $this->addOption( 'override', 'Also update pages that have updates disabled' ); } public function execute() { - global $IP, $wgSpecialPageCacheUpdates, $wgQueryPages, $wgQueryCacheLimit, $wgDisableQueryPageUpdate; + global $IP, $wgQueryPages, $wgQueryCacheLimit, $wgDisableQueryPageUpdate; - $dbw = wfGetDB( DB_MASTER ); - - foreach ( $wgSpecialPageCacheUpdates as $special => $call ) { - if ( !is_callable( $call ) ) { - $this->error( "Uncallable function $call!" ); - continue; - } - $t1 = explode( ' ', microtime() ); - call_user_func( $call, $dbw ); - $t2 = explode( ' ', microtime() ); - $this->output( sprintf( '%-30s ', $special ) ); - $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( "completed in %.2fs\n", $seconds ) ); - # Wait for the slave to catch up - wfWaitForSlaves(); + 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" ); + require_once "$IP/includes/QueryPage.php"; foreach ( $wgQueryPages as $page ) { list( $class, $special ) = $page; @@ -94,13 +75,13 @@ class UpdateSpecialPages extends Maintenance { } else { if ( !class_exists( $class ) ) { $file = $specialObj->getFile(); - require_once( $file ); + require_once $file; } $queryPage = new $class; } if ( !$this->hasOption( 'only' ) || $this->getOption( 'only' ) == $queryPage->getName() ) { - $this->output( sprintf( '%-30s ', $special ) ); + $this->output( sprintf( '%-30s ', $special ) ); if ( $queryPage->isExpensive() ) { $t1 = explode( ' ', microtime() ); # Do the query @@ -124,7 +105,7 @@ class UpdateSpecialPages extends Maintenance { $this->output( sprintf( "%.2fs\n", $seconds ) ); } # Reopen any connections that have closed - if ( !wfGetLB()->pingAll() ) { + if ( !wfGetLB()->pingAll() ) { $this->output( "\n" ); do { $this->error( "Connection failed, reconnecting in 10 seconds..." ); @@ -140,10 +121,42 @@ class UpdateSpecialPages extends Maintenance { } else { $this->output( "cheap, skipped\n" ); } + if ( $this->hasOption( 'only' ) ) { + break; + } } } } + + public function doSpecialPageCacheUpdates() { + global $wgSpecialPageCacheUpdates; + $dbw = wfGetDB( DB_MASTER ); + + foreach ( $wgSpecialPageCacheUpdates as $special => $call ) { + if ( !is_callable( $call ) ) { + $this->error( "Uncallable function $call!" ); + 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 ' ); + } + $this->output( sprintf( "completed in %.2fs\n", $seconds ) ); + # Wait for the slave to catch up + wfWaitForSlaves(); + } + } } $maintClass = "UpdateSpecialPages"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/upgrade1_5.php b/maintenance/upgrade1_5.php deleted file mode 100644 index 1e268de3..00000000 --- a/maintenance/upgrade1_5.php +++ /dev/null @@ -1,1337 +0,0 @@ -<?php -/** - * Alternate 1.4 -> 1.5 schema upgrade. - * This does only the main tables + UTF-8 and is designed to allow upgrades to - * interleave with other updates on the replication stream so that large wikis - * can be upgraded without disrupting other services. - * - * Note: this script DOES NOT apply every update, nor will it probably handle - * much older versions, etc. - * Run this, FOLLOWED BY update.php, for upgrading from 1.4.5 release to 1.5. - * - * 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' ); - -define( 'MW_UPGRADE_COPY', false ); -define( 'MW_UPGRADE_ENCODE', true ); -define( 'MW_UPGRADE_NULL', null ); -define( 'MW_UPGRADE_CALLBACK', null ); // for self-documentation only - -/** - * @ingroup Maintenance - */ -class FiveUpgrade extends Maintenance { - - /** - * @var DatabaseBase - */ - protected $db; - - function __construct() { - parent::__construct(); - - $this->mDescription = 'Script for upgrades from 1.4 to 1.5 (NOT 1.15) in very special cases.'; - - $this->addOption( 'upgrade', 'Really run the script' ); - $this->addOption( 'noimage', '' ); - $this->addOption( 'step', 'Only do a specific step', false, true ); - } - - public function getDbType() { - return Maintenance::DB_ADMIN; - } - - public function execute() { - $this->output( "ATTENTION: This script is for upgrades from 1.4 to 1.5 (NOT 1.15) in very special cases.\n" ); - $this->output( "Use update.php for usual updates.\n" ); - - if ( !$this->hasOption( 'upgrade' ) ) { - $this->output( "Please run this script with --upgrade key to actually run the updater.\n" ); - return; - } - - $this->setMembers(); - - $tables = array( - 'page', - 'links', - 'user', - 'image', - 'oldimage', - 'watchlist', - 'logging', - 'archive', - 'imagelinks', - 'categorylinks', - 'ipblocks', - 'recentchanges', - 'querycache' - ); - - foreach ( $tables as $table ) { - if ( $this->doing( $table ) ) { - $method = 'upgrade' . ucfirst( $table ); - $this->$method(); - } - } - - if ( $this->doing( 'cleanup' ) ) { - $this->upgradeCleanup(); - } - } - - protected function setMembers() { - $this->conversionTables = $this->prepareWindows1252(); - - $this->loadBalancers = array(); - $this->dbw = wfGetDB( DB_MASTER ); - $this->dbr = $this->streamConnection(); - - $this->cleanupSwaps = array(); - $this->emailAuth = false; # don't preauthenticate emails - $this->step = $this->getOption( 'step', null ); - } - - function doing( $step ) { - return is_null( $this->step ) || $step == $this->step; - } - - /** - * Open a connection to the master server with the admin rights. - * @return DatabaseBase - * @access private - */ - 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. - * This will let us stream large datasets in and write in chunks on the - * other end. - * @return DatabaseBase - * @access private - */ - function streamConnection() { - $timeout = 3600 * 24; - $db = $this->newConnection(); - $db->bufferResults( false ); - if ( $db->getType() == 'mysql' ) { - $db->query( "SET net_read_timeout=$timeout" ); - $db->query( "SET net_write_timeout=$timeout" ); - } - return $db; - } - - /** - * Prepare a conversion array for converting Windows Code Page 1252 to - * UTF-8. This should provide proper conversion of text that was miscoded - * as Windows-1252 by naughty user-agents, and doesn't rely on an outside - * iconv library. - * - * @return array - * @access private - */ - function prepareWindows1252() { - # Mappings from: - # http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT - static $cp1252 = array( - 0x80 => 0x20AC, # EURO SIGN - 0x81 => 0xFFFD, # REPLACEMENT CHARACTER (no mapping) - 0x82 => 0x201A, # SINGLE LOW-9 QUOTATION MARK - 0x83 => 0x0192, # LATIN SMALL LETTER F WITH HOOK - 0x84 => 0x201E, # DOUBLE LOW-9 QUOTATION MARK - 0x85 => 0x2026, # HORIZONTAL ELLIPSIS - 0x86 => 0x2020, # DAGGER - 0x87 => 0x2021, # DOUBLE DAGGER - 0x88 => 0x02C6, # MODIFIER LETTER CIRCUMFLEX ACCENT - 0x89 => 0x2030, # PER MILLE SIGN - 0x8A => 0x0160, # LATIN CAPITAL LETTER S WITH CARON - 0x8B => 0x2039, # SINGLE LEFT-POINTING ANGLE QUOTATION MARK - 0x8C => 0x0152, # LATIN CAPITAL LIGATURE OE - 0x8D => 0xFFFD, # REPLACEMENT CHARACTER (no mapping) - 0x8E => 0x017D, # LATIN CAPITAL LETTER Z WITH CARON - 0x8F => 0xFFFD, # REPLACEMENT CHARACTER (no mapping) - 0x90 => 0xFFFD, # REPLACEMENT CHARACTER (no mapping) - 0x91 => 0x2018, # LEFT SINGLE QUOTATION MARK - 0x92 => 0x2019, # RIGHT SINGLE QUOTATION MARK - 0x93 => 0x201C, # LEFT DOUBLE QUOTATION MARK - 0x94 => 0x201D, # RIGHT DOUBLE QUOTATION MARK - 0x95 => 0x2022, # BULLET - 0x96 => 0x2013, # EN DASH - 0x97 => 0x2014, # EM DASH - 0x98 => 0x02DC, # SMALL TILDE - 0x99 => 0x2122, # TRADE MARK SIGN - 0x9A => 0x0161, # LATIN SMALL LETTER S WITH CARON - 0x9B => 0x203A, # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - 0x9C => 0x0153, # LATIN SMALL LIGATURE OE - 0x9D => 0xFFFD, # REPLACEMENT CHARACTER (no mapping) - 0x9E => 0x017E, # LATIN SMALL LETTER Z WITH CARON - 0x9F => 0x0178, # LATIN CAPITAL LETTER Y WITH DIAERESIS - ); - $pairs = array(); - for ( $i = 0; $i < 0x100; $i++ ) { - $unicode = isset( $cp1252[$i] ) ? $cp1252[$i] : $i; - $pairs[chr( $i )] = codepointToUtf8( $unicode ); - } - return $pairs; - } - - /** - * Convert from 8-bit Windows-1252 to UTF-8 if necessary. - * @param string $text - * @return string - * @access private - */ - function conv( $text ) { - global $wgUseLatin1; - return is_null( $text ) - ? null - : ( $wgUseLatin1 - ? strtr( $text, $this->conversionTables ) - : $text ); - } - - /** - * Dump timestamp and message to output - * @param $message String - * @access private - */ - function log( $message ) { - $this->output( wfWikiID() . ' ' . wfTimestamp( TS_DB ) . ': ' . $message . "\n" ); - } - - /** - * Initialize the chunked-insert system. - * Rows will be inserted in chunks of the given number, rather - * than in a giant INSERT...SELECT query, to keep the serialized - * MySQL database replication from getting hung up. This way other - * things can be going on during conversion without waiting for - * slaves to catch up as badly. - * - * @param int $chunksize Number of rows to insert at once - * @param int $final Total expected number of rows / id of last row, - * used for progress reports. - * @param string $table to insert on - * @param string $fname function name to report in SQL - * @access private - */ - function setChunkScale( $chunksize, $final, $table, $fname ) { - $this->chunkSize = $chunksize; - $this->chunkFinal = $final; - $this->chunkCount = 0; - $this->chunkStartTime = microtime( true ); - $this->chunkOptions = array( 'IGNORE' ); - $this->chunkTable = $table; - $this->chunkFunction = $fname; - } - - /** - * Chunked inserts: perform an insert if we've reached the chunk limit. - * Prints a progress report with estimated completion time. - * @param array &$chunk -- This will be emptied if an insert is done. - * @param int $key A key identifier to use in progress estimation in - * place of the number of rows inserted. Use this if - * you provided a max key number instead of a count - * as the final chunk number in setChunkScale() - * @access private - */ - function addChunk( &$chunk, $key = null ) { - if ( count( $chunk ) >= $this->chunkSize ) { - $this->insertChunk( $chunk ); - - $this->chunkCount += count( $chunk ); - $now = microtime( true ); - $delta = $now - $this->chunkStartTime; - $rate = $this->chunkCount / $delta; - - if ( is_null( $key ) ) { - $completed = $this->chunkCount; - } else { - $completed = $key; - } - $portion = $completed / $this->chunkFinal; - - $estimatedTotalTime = $delta / $portion; - $eta = $this->chunkStartTime + $estimatedTotalTime; - - printf( "%s: %6.2f%% done on %s; ETA %s [%d/%d] %.2f/sec\n", - wfTimestamp( TS_DB, intval( $now ) ), - $portion * 100.0, - $this->chunkTable, - wfTimestamp( TS_DB, intval( $eta ) ), - $completed, - $this->chunkFinal, - $rate ); - flush(); - - $chunk = array(); - } - } - - /** - * Chunked inserts: perform an insert unconditionally, at the end, and log. - * @param array &$chunk -- This will be emptied if an insert is done. - * @access private - */ - function lastChunk( &$chunk ) { - $n = count( $chunk ); - if ( $n > 0 ) { - $this->insertChunk( $chunk ); - } - $this->log( "100.00% done on $this->chunkTable (last chunk $n rows)." ); - } - - /** - * Chunked inserts: perform an insert. - * @param array &$chunk -- This will be emptied if an insert is done. - * @access private - */ - function insertChunk( &$chunk ) { - // Give slaves a chance to catch up - wfWaitForSlaves(); - $this->dbw->insert( $this->chunkTable, $chunk, $this->chunkFunction, $this->chunkOptions ); - } - - /** - * Helper function for copyTable array_filter - * @param $x - * @return bool - */ - static private function notUpgradeNull( $x ) { - return $x !== MW_UPGRADE_NULL; - } - - /** - * Copy and transcode a table to table_temp. - * @param string $name Base name of the source table - * @param string $tabledef CREATE TABLE definition, w/ $1 for the name - * @param array $fields set of destination fields to these constants: - * MW_UPGRADE_COPY - straight copy - * MW_UPGRADE_ENCODE - for old Latin1 wikis, conv to UTF-8 - * MW_UPGRADE_NULL - just put NULL - * @param $callback callback An optional callback to modify the data - * or perform other processing. Func should be - * ( object $row, array $copy ) and return $copy - * @access private - */ - function copyTable( $name, $tabledef, $fields, $callback = null ) { - $name_temp = $name . '_temp'; - $this->log( "Migrating $name table to $name_temp..." ); - - $table_temp = $this->dbw->tableName( $name_temp ); - - // Create temporary table; we're going to copy everything in there, - // then at the end rename the final tables into place. - $def = str_replace( '$1', $table_temp, $tabledef ); - $this->dbw->query( $def, __METHOD__ ); - - $numRecords = $this->dbw->selectField( $name, 'COUNT(*)', '', __METHOD__ ); - $this->setChunkScale( 100, $numRecords, $name_temp, __METHOD__ ); - - // Pull all records from the second, streaming database connection. - $sourceFields = array_keys( array_filter( $fields, 'FiveUpgrade::notUpgradeNull' ) ); - $result = $this->dbr->select( $name, - $sourceFields, - '', - __METHOD__ ); - - $add = array(); - foreach ( $result as $row ) { - $copy = array(); - foreach ( $fields as $field => $source ) { - if ( $source === MW_UPGRADE_COPY ) { - $copy[$field] = $row->$field; - } elseif ( $source === MW_UPGRADE_ENCODE ) { - $copy[$field] = $this->conv( $row->$field ); - } elseif ( $source === MW_UPGRADE_NULL ) { - $copy[$field] = null; - } else { - $this->log( "Unknown field copy type: $field => $source" ); - } - } - if ( is_callable( $callback ) ) { - $copy = call_user_func( $callback, $row, $copy ); - } - $add[] = $copy; - $this->addChunk( $add ); - } - $this->lastChunk( $add ); - - $this->log( "Done converting $name." ); - $this->cleanupSwaps[] = $name; - } - - function upgradePage() { - $chunksize = 100; - - if ( $this->dbw->tableExists( 'page' ) ) { - $this->error( 'Page table already exists.', true ); - } - - $this->log( "Checking cur table for unique title index and applying if necessary" ); - $this->checkDupes(); - - $this->log( "...converting from cur/old to page/revision/text DB structure." ); - - list ( $cur, $old, $page, $revision, $text ) = $this->dbw->tableNamesN( 'cur', 'old', 'page', 'revision', 'text' ); - - $this->log( "Creating page and revision tables..." ); - $this->dbw->query( "CREATE TABLE $page ( - page_id int(8) unsigned NOT NULL auto_increment, - page_namespace int NOT NULL, - page_title varchar(255) binary NOT NULL, - page_restrictions tinyblob NOT NULL default '', - page_counter bigint(20) unsigned NOT NULL default '0', - page_is_redirect tinyint(1) unsigned NOT NULL default '0', - page_is_new tinyint(1) unsigned NOT NULL default '0', - page_random real unsigned NOT NULL, - page_touched char(14) binary NOT NULL default '', - page_latest int(8) unsigned NOT NULL, - page_len int(8) unsigned NOT NULL, - - PRIMARY KEY page_id (page_id), - UNIQUE INDEX name_title (page_namespace,page_title), - INDEX (page_random), - INDEX (page_len) - ) TYPE=InnoDB", __METHOD__ ); - $this->dbw->query( "CREATE TABLE $revision ( - rev_id int(8) unsigned NOT NULL auto_increment, - rev_page int(8) unsigned NOT NULL, - rev_text_id int(8) unsigned NOT NULL, - rev_comment tinyblob NOT NULL default '', - rev_user int(5) unsigned NOT NULL default '0', - rev_user_text varchar(255) binary NOT NULL default '', - rev_timestamp char(14) binary NOT NULL default '', - rev_minor_edit tinyint(1) unsigned NOT NULL default '0', - rev_deleted tinyint(1) unsigned NOT NULL default '0', - - 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) - ) TYPE=InnoDB", __METHOD__ ); - - $maxold = intval( $this->dbw->selectField( 'old', 'max(old_id)', '', __METHOD__ ) ); - $this->log( "Last old record is {$maxold}" ); - - global $wgLegacySchemaConversion; - if ( $wgLegacySchemaConversion ) { - // Create HistoryBlobCurStub entries. - // Text will be pulled from the leftover 'cur' table at runtime. - echo "......Moving metadata from cur; using blob references to text in cur table.\n"; - $cur_text = "concat('O:18:\"historyblobcurstub\":1:{s:6:\"mCurId\";i:',cur_id,';}')"; - $cur_flags = "'object'"; - } else { - // Copy all cur text in immediately: this may take longer but avoids - // having to keep an extra table around. - echo "......Moving text from cur.\n"; - $cur_text = 'cur_text'; - $cur_flags = "''"; - } - - $maxcur = $this->dbw->selectField( 'cur', 'max(cur_id)', '', __METHOD__ ); - $this->log( "Last cur entry is $maxcur" ); - - /** - * Copy placeholder records for each page's current version into old - * Don't do any conversion here; text records are converted at runtime - * based on the flags (and may be originally binary!) while the meta - * fields will be converted in the old -> rev and cur -> page steps. - */ - $this->setChunkScale( $chunksize, $maxcur, 'old', __METHOD__ ); - $result = $this->dbr->query( - "SELECT cur_id, cur_namespace, cur_title, $cur_text AS text, cur_comment, - cur_user, cur_user_text, cur_timestamp, cur_minor_edit, $cur_flags AS flags - FROM $cur - ORDER BY cur_id", __METHOD__ ); - $add = array(); - foreach ( $result as $row ) { - $add[] = array( - 'old_namespace' => $row->cur_namespace, - 'old_title' => $row->cur_title, - 'old_text' => $row->text, - 'old_comment' => $row->cur_comment, - 'old_user' => $row->cur_user, - 'old_user_text' => $row->cur_user_text, - 'old_timestamp' => $row->cur_timestamp, - 'old_minor_edit' => $row->cur_minor_edit, - 'old_flags' => $row->flags ); - $this->addChunk( $add, $row->cur_id ); - } - $this->lastChunk( $add ); - - /** - * Copy revision metadata from old into revision. - * We'll also do UTF-8 conversion of usernames and comments. - */ - # $newmaxold = $this->dbw->selectField( 'old', 'max(old_id)', '', __METHOD__ ); - # $this->setChunkScale( $chunksize, $newmaxold, 'revision', __METHOD__ ); - # $countold = $this->dbw->selectField( 'old', 'count(old_id)', '', __METHOD__ ); - $countold = $this->dbw->selectField( 'old', 'max(old_id)', '', __METHOD__ ); - $this->setChunkScale( $chunksize, $countold, 'revision', __METHOD__ ); - - $this->log( "......Setting up revision table." ); - $result = $this->dbr->query( - "SELECT old_id, cur_id, old_comment, old_user, old_user_text, - old_timestamp, old_minor_edit - FROM $old,$cur WHERE old_namespace=cur_namespace AND old_title=cur_title", - __METHOD__ ); - - $add = array(); - foreach ( $result as $row ) { - $add[] = array( - 'rev_id' => $row->old_id, - 'rev_page' => $row->cur_id, - 'rev_text_id' => $row->old_id, - 'rev_comment' => $this->conv( $row->old_comment ), - 'rev_user' => $row->old_user, - 'rev_user_text' => $this->conv( $row->old_user_text ), - 'rev_timestamp' => $row->old_timestamp, - 'rev_minor_edit' => $row->old_minor_edit ); - $this->addChunk( $add ); - } - $this->lastChunk( $add ); - - - /** - * Copy page metadata from cur into page. - * We'll also do UTF-8 conversion of titles. - */ - $this->log( "......Setting up page table." ); - $this->setChunkScale( $chunksize, $maxcur, 'page', __METHOD__ ); - $result = $this->dbr->query( " - SELECT cur_id, cur_namespace, cur_title, cur_restrictions, cur_counter, cur_is_redirect, cur_is_new, - cur_random, cur_touched, rev_id, LENGTH(cur_text) AS len - FROM $cur,$revision - WHERE cur_id=rev_page AND rev_timestamp=cur_timestamp AND rev_id > {$maxold} - ORDER BY cur_id", __METHOD__ ); - $add = array(); - foreach ( $result as $row ) { - $add[] = array( - 'page_id' => $row->cur_id, - 'page_namespace' => $row->cur_namespace, - 'page_title' => $this->conv( $row->cur_title ), - 'page_restrictions' => $row->cur_restrictions, - 'page_counter' => $row->cur_counter, - 'page_is_redirect' => $row->cur_is_redirect, - 'page_is_new' => $row->cur_is_new, - 'page_random' => $row->cur_random, - 'page_touched' => $this->dbw->timestamp(), - 'page_latest' => $row->rev_id, - 'page_len' => $row->len ); - # $this->addChunk( $add, $row->cur_id ); - $this->addChunk( $add ); - } - $this->lastChunk( $add ); - - $this->log( "...done with cur/old -> page/revision." ); - } - - function upgradeLinks() { - $chunksize = 200; - list ( $links, $brokenlinks, $pagelinks, $cur ) = $this->dbw->tableNamesN( 'links', 'brokenlinks', 'pagelinks', 'cur' ); - - $this->log( 'Checking for interwiki table change in case of bogus items...' ); - if ( $this->dbw->fieldExists( 'interwiki', 'iw_trans' ) ) { - $this->log( 'interwiki has iw_trans.' ); - } else { - global $IP; - $this->log( 'adding iw_trans...' ); - $this->dbw->sourceFile( $IP . '/maintenance/archives/patch-interwiki-trans.sql' ); - $this->log( 'added iw_trans.' ); - } - - $this->log( 'Creating pagelinks table...' ); - $this->dbw->query( " -CREATE TABLE $pagelinks ( - -- Key to the page_id of the page containing the link. - pl_from int(8) unsigned 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 - -- and deletions may refer to different page records as time - -- goes by. - pl_namespace int NOT NULL default '0', - pl_title varchar(255) binary NOT NULL default '', - - UNIQUE KEY pl_from(pl_from,pl_namespace,pl_title), - KEY (pl_namespace,pl_title) - -) TYPE=InnoDB" ); - - $this->log( 'Importing live links -> pagelinks' ); - $nlinks = $this->dbw->selectField( 'links', 'count(*)', '', __METHOD__ ); - if ( $nlinks ) { - $this->setChunkScale( $chunksize, $nlinks, 'pagelinks', __METHOD__ ); - $result = $this->dbr->query( " - SELECT l_from,cur_namespace,cur_title - FROM $links, $cur - WHERE l_to=cur_id", __METHOD__ ); - $add = array(); - foreach ( $result as $row ) { - $add[] = array( - 'pl_from' => $row->l_from, - 'pl_namespace' => $row->cur_namespace, - 'pl_title' => $this->conv( $row->cur_title ) ); - $this->addChunk( $add ); - } - $this->lastChunk( $add ); - } else { - $this->log( 'no links!' ); - } - - $this->log( 'Importing brokenlinks -> pagelinks' ); - $nbrokenlinks = $this->dbw->selectField( 'brokenlinks', 'count(*)', '', __METHOD__ ); - if ( $nbrokenlinks ) { - $this->setChunkScale( $chunksize, $nbrokenlinks, 'pagelinks', __METHOD__ ); - $result = $this->dbr->query( - "SELECT bl_from, bl_to FROM $brokenlinks", - __METHOD__ ); - $add = array(); - foreach ( $result as $row ) { - $pagename = $this->conv( $row->bl_to ); - $title = Title::newFromText( $pagename ); - if ( is_null( $title ) ) { - $this->log( "** invalid brokenlink: $row->bl_from -> '$pagename' (converted from '$row->bl_to')" ); - } else { - $add[] = array( - 'pl_from' => $row->bl_from, - 'pl_namespace' => $title->getNamespace(), - 'pl_title' => $title->getDBkey() ); - $this->addChunk( $add ); - } - } - $this->lastChunk( $add ); - } else { - $this->log( 'no brokenlinks!' ); - } - - $this->log( 'Done with links.' ); - } - - function userDupeCallback( $str ) { - echo $str; - } - - function upgradeUser() { - // Apply unique index, if necessary: - $duper = new UserDupes( $this->dbw, array( $this, 'userDupeCallback' ) ); - if ( $duper->hasUniqueIndex() ) { - $this->log( "Already have unique user_name index." ); - } else { - $this->log( "Clearing user duplicates..." ); - if ( !$duper->clearDupes() ) { - $this->log( "WARNING: Duplicate user accounts, may explode!" ); - } - } - - $tabledef = <<<END -CREATE TABLE $1 ( - user_id int(5) unsigned NOT NULL auto_increment, - user_name varchar(255) binary NOT NULL default '', - user_real_name varchar(255) binary NOT NULL default '', - user_password tinyblob NOT NULL default '', - user_newpassword tinyblob NOT NULL default '', - user_email tinytext NOT NULL default '', - user_options blob NOT NULL default '', - user_touched char(14) binary NOT NULL default '', - user_token char(32) binary NOT NULL default '', - user_email_authenticated CHAR(14) BINARY, - user_email_token CHAR(32) BINARY, - user_email_token_expires CHAR(14) BINARY, - - PRIMARY KEY user_id (user_id), - UNIQUE INDEX user_name (user_name), - INDEX (user_email_token) - -) TYPE=InnoDB -END; - $fields = array( - 'user_id' => MW_UPGRADE_COPY, - 'user_name' => MW_UPGRADE_ENCODE, - 'user_real_name' => MW_UPGRADE_ENCODE, - 'user_password' => MW_UPGRADE_COPY, - 'user_newpassword' => MW_UPGRADE_COPY, - 'user_email' => MW_UPGRADE_ENCODE, - 'user_options' => MW_UPGRADE_ENCODE, - 'user_touched' => MW_UPGRADE_CALLBACK, - 'user_token' => MW_UPGRADE_COPY, - 'user_email_authenticated' => MW_UPGRADE_CALLBACK, - 'user_email_token' => MW_UPGRADE_NULL, - 'user_email_token_expires' => MW_UPGRADE_NULL ); - $this->copyTable( 'user', $tabledef, $fields, - array( &$this, 'userCallback' ) ); - } - - function userCallback( $row, $copy ) { - $now = $this->dbw->timestamp(); - $copy['user_touched'] = $now; - $copy['user_email_authenticated'] = $this->emailAuth ? $now : null; - return $copy; - } - - function upgradeImage() { - $tabledef = <<<END -CREATE TABLE $1 ( - img_name varchar(255) binary NOT NULL default '', - img_size int(8) unsigned NOT NULL default '0', - img_width int(5) NOT NULL default '0', - img_height int(5) NOT NULL default '0', - img_metadata mediumblob NOT NULL, - img_bits int(3) NOT NULL default '0', - img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, - img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown", - img_minor_mime varchar(32) NOT NULL default "unknown", - img_description tinyblob NOT NULL default '', - img_user int(5) unsigned NOT NULL default '0', - img_user_text varchar(255) binary NOT NULL default '', - img_timestamp char(14) binary NOT NULL default '', - - PRIMARY KEY img_name (img_name), - INDEX img_size (img_size), - INDEX img_timestamp (img_timestamp) -) TYPE=InnoDB -END; - $fields = array( - 'img_name' => MW_UPGRADE_ENCODE, - 'img_size' => MW_UPGRADE_COPY, - 'img_width' => MW_UPGRADE_CALLBACK, - 'img_height' => MW_UPGRADE_CALLBACK, - 'img_metadata' => MW_UPGRADE_CALLBACK, - 'img_bits' => MW_UPGRADE_CALLBACK, - 'img_media_type' => MW_UPGRADE_CALLBACK, - 'img_major_mime' => MW_UPGRADE_CALLBACK, - 'img_minor_mime' => MW_UPGRADE_CALLBACK, - 'img_description' => MW_UPGRADE_ENCODE, - 'img_user' => MW_UPGRADE_COPY, - 'img_user_text' => MW_UPGRADE_ENCODE, - 'img_timestamp' => MW_UPGRADE_COPY ); - $this->copyTable( 'image', $tabledef, $fields, - array( &$this, 'imageCallback' ) ); - } - - function imageCallback( $row, $copy ) { - if ( !$this->hasOption( 'noimage' ) ) { - // Fill in the new image info fields - $info = $this->imageInfo( $row->img_name ); - - $copy['img_width' ] = $info['width']; - $copy['img_height' ] = $info['height']; - $copy['img_metadata' ] = ""; // loaded on-demand - $copy['img_bits' ] = $info['bits']; - $copy['img_media_type'] = $info['media']; - $copy['img_major_mime'] = $info['major']; - $copy['img_minor_mime'] = $info['minor']; - } - - // If doing UTF8 conversion the file must be renamed - $this->renameFile( $row->img_name, 'wfImageDir' ); - - return $copy; - } - - function imageInfo( $filename ) { - $info = array( - 'width' => 0, - 'height' => 0, - 'bits' => 0, - 'media' => '', - 'major' => '', - 'minor' => '' ); - - $magic = MimeMagic::singleton(); - $mime = $magic->guessMimeType( $filename, true ); - list( $info['major'], $info['minor'] ) = explode( '/', $mime ); - - $info['media'] = $magic->getMediaType( $filename, $mime ); - - $image = UnregisteredLocalFile::newFromPath( $filename, $mime ); - - $info['width'] = $image->getWidth(); - $info['height'] = $image->getHeight(); - - $gis = $image->getImageSize( $filename ); - if ( isset( $gis['bits'] ) ) { - $info['bits'] = $gis['bits']; - } - - return $info; - } - - - /** - * Truncate a table. - * @param string $table The table name to be truncated - */ - function clearTable( $table ) { - print "Clearing $table...\n"; - $tableName = $this->db->tableName( $table ); - $this->db->query( "TRUNCATE $tableName" ); - } - - /** - * Rename a given image or archived image file to the converted filename, - * leaving a symlink for URL compatibility. - * - * @param $oldname string pre-conversion filename - * @param $subdirCallback string - * @param $basename string pre-conversion base filename for dir hashing, if an archive - * @return bool|string - * @access private - */ - function renameFile( $oldname, $subdirCallback = 'wfImageDir', $basename = null ) { - $newname = $this->conv( $oldname ); - if ( $newname == $oldname ) { - // No need to rename; another field triggered this row. - return false; - } - - if ( is_null( $basename ) ) $basename = $oldname; - $ubasename = $this->conv( $basename ); - $oldpath = call_user_func( $subdirCallback, $basename ) . '/' . $oldname; - $newpath = call_user_func( $subdirCallback, $ubasename ) . '/' . $newname; - - $this->log( "$oldpath -> $newpath" ); - if ( rename( $oldpath, $newpath ) ) { - $relpath = wfRelativePath( $newpath, dirname( $oldpath ) ); - if ( !symlink( $relpath, $oldpath ) ) { - $this->log( "... symlink failed!" ); - } - return $newname; - } else { - $this->log( "... rename failed!" ); - return false; - } - } - - function upgradeOldImage() { - $tabledef = <<<END -CREATE TABLE $1 ( - -- Base filename: key to image.img_name - oi_name varchar(255) binary NOT NULL default '', - - -- Filename of the archived file. - -- This is generally a timestamp and '!' prepended to the base name. - oi_archive_name varchar(255) binary NOT NULL default '', - - -- Other fields as in image... - oi_size int(8) unsigned NOT NULL default 0, - oi_width int(5) NOT NULL default 0, - oi_height int(5) NOT NULL default 0, - oi_bits int(3) NOT NULL default 0, - oi_description tinyblob NOT NULL default '', - oi_user int(5) unsigned NOT NULL default '0', - oi_user_text varchar(255) binary NOT NULL default '', - oi_timestamp char(14) binary NOT NULL default '', - - INDEX oi_name (oi_name(10)) - -) TYPE=InnoDB; -END; - $fields = array( - 'oi_name' => MW_UPGRADE_ENCODE, - 'oi_archive_name' => MW_UPGRADE_ENCODE, - 'oi_size' => MW_UPGRADE_COPY, - 'oi_width' => MW_UPGRADE_CALLBACK, - 'oi_height' => MW_UPGRADE_CALLBACK, - 'oi_bits' => MW_UPGRADE_CALLBACK, - 'oi_description' => MW_UPGRADE_ENCODE, - 'oi_user' => MW_UPGRADE_COPY, - 'oi_user_text' => MW_UPGRADE_ENCODE, - 'oi_timestamp' => MW_UPGRADE_COPY ); - $this->copyTable( 'oldimage', $tabledef, $fields, - array( &$this, 'oldimageCallback' ) ); - } - - function oldimageCallback( $row, $copy ) { - global $options; - if ( !isset( $options['noimage'] ) ) { - // Fill in the new image info fields - $info = $this->imageInfo( $row->oi_archive_name, 'wfImageArchiveDir', $row->oi_name ); - $copy['oi_width' ] = $info['width' ]; - $copy['oi_height'] = $info['height']; - $copy['oi_bits' ] = $info['bits' ]; - } - - // If doing UTF8 conversion the file must be renamed - $this->renameFile( $row->oi_archive_name, 'wfImageArchiveDir', $row->oi_name ); - - return $copy; - } - - - function upgradeWatchlist() { - $chunksize = 100; - - list ( $watchlist, $watchlist_temp ) = $this->dbw->tableNamesN( 'watchlist', 'watchlist_temp' ); - - $this->log( 'Migrating watchlist table to watchlist_temp...' ); - $this->dbw->query( -"CREATE TABLE $watchlist_temp ( - -- Key to user_id - wl_user int(5) unsigned NOT NULL, - - -- Key to page_namespace/page_title - -- Note that users may watch patches which do not exist yet, - -- or existed in the past but have been deleted. - 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. - -- FIXME: add proper null support etc - wl_notificationtimestamp varchar(14) binary NOT NULL default '0', - - UNIQUE KEY (wl_user, wl_namespace, wl_title), - KEY namespace_title (wl_namespace,wl_title) - -) TYPE=InnoDB;", __METHOD__ ); - - // Fix encoding for Latin-1 upgrades, add some fields, - // and double article to article+talk pairs - $numwatched = $this->dbw->selectField( 'watchlist', 'count(*)', '', __METHOD__ ); - - $this->setChunkScale( $chunksize, $numwatched * 2, 'watchlist_temp', __METHOD__ ); - $result = $this->dbr->select( 'watchlist', - array( - 'wl_user', - 'wl_namespace', - 'wl_title' ), - '', - __METHOD__ ); - - $add = array(); - foreach ( $result as $row ) { - $add[] = array( - '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' => MWNamespace::getTalk( $row->wl_namespace ), - 'wl_title' => $this->conv( $row->wl_title ), - 'wl_notificationtimestamp' => '0' ); - $this->addChunk( $add ); - } - $this->lastChunk( $add ); - - $this->log( 'Done converting watchlist.' ); - $this->cleanupSwaps[] = 'watchlist'; - } - - function upgradeLogging() { - $tabledef = <<<ENDS -CREATE TABLE $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 char(10) NOT NULL default '', - log_action char(10) NOT NULL default '', - - -- Timestamp. Duh. - log_timestamp char(14) NOT NULL default '19700101000000', - - -- The user who performed this action; key to user_id - log_user int unsigned NOT NULL default 0, - - -- Key to the page affected. Where a user is the target, - -- this will point to the user page. - log_namespace int NOT NULL default 0, - log_title varchar(255) binary NOT NULL default '', - - -- Freeform text. Interpreted as edit history comments. - log_comment varchar(255) NOT NULL default '', - - -- LF separated list of miscellaneous parameters - log_params blob NOT NULL default '', - - KEY type_time (log_type, log_timestamp), - KEY user_time (log_user, log_timestamp), - KEY page_time (log_namespace, log_title, log_timestamp) - -) TYPE=InnoDB -ENDS; - $fields = array( - 'log_type' => MW_UPGRADE_COPY, - 'log_action' => MW_UPGRADE_COPY, - 'log_timestamp' => MW_UPGRADE_COPY, - 'log_user' => MW_UPGRADE_COPY, - 'log_namespace' => MW_UPGRADE_COPY, - 'log_title' => MW_UPGRADE_ENCODE, - 'log_comment' => MW_UPGRADE_ENCODE, - 'log_params' => MW_UPGRADE_ENCODE ); - $this->copyTable( 'logging', $tabledef, $fields ); - } - - function upgradeArchive() { - $tabledef = <<<ENDS -CREATE TABLE $1 ( - ar_namespace int NOT NULL default '0', - ar_title varchar(255) binary NOT NULL default '', - ar_text mediumblob NOT NULL default '', - - ar_comment tinyblob NOT NULL default '', - ar_user int(5) unsigned NOT NULL default '0', - ar_user_text varchar(255) binary NOT NULL, - ar_timestamp char(14) binary NOT NULL default '', - ar_minor_edit tinyint(1) NOT NULL default '0', - - ar_flags tinyblob NOT NULL default '', - - ar_rev_id int(8) unsigned, - ar_text_id int(8) unsigned, - - KEY name_title_timestamp (ar_namespace,ar_title,ar_timestamp) - -) TYPE=InnoDB -ENDS; - $fields = array( - 'ar_namespace' => MW_UPGRADE_COPY, - 'ar_title' => MW_UPGRADE_ENCODE, - 'ar_text' => MW_UPGRADE_COPY, - 'ar_comment' => MW_UPGRADE_ENCODE, - 'ar_user' => MW_UPGRADE_COPY, - 'ar_user_text' => MW_UPGRADE_ENCODE, - 'ar_timestamp' => MW_UPGRADE_COPY, - 'ar_minor_edit' => MW_UPGRADE_COPY, - 'ar_flags' => MW_UPGRADE_COPY, - 'ar_rev_id' => MW_UPGRADE_NULL, - 'ar_text_id' => MW_UPGRADE_NULL ); - $this->copyTable( 'archive', $tabledef, $fields ); - } - - function upgradeImagelinks() { - global $wgUseLatin1; - if ( $wgUseLatin1 ) { - $tabledef = <<<ENDS -CREATE TABLE $1 ( - -- Key to page_id of the page containing the image / media link. - il_from int(8) unsigned NOT NULL default '0', - - -- 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 varchar(255) binary NOT NULL default '', - - UNIQUE KEY il_from(il_from,il_to), - KEY (il_to) - -) TYPE=InnoDB -ENDS; - $fields = array( - 'il_from' => MW_UPGRADE_COPY, - 'il_to' => MW_UPGRADE_ENCODE ); - $this->copyTable( 'imagelinks', $tabledef, $fields ); - } - } - - function upgradeCategorylinks() { - global $wgUseLatin1; - if ( $wgUseLatin1 ) { - $tabledef = <<<ENDS -CREATE TABLE $1 ( - cl_from int(8) unsigned NOT NULL default '0', - cl_to varchar(255) binary NOT NULL default '', - cl_sortkey varchar(86) binary NOT NULL default '', - cl_timestamp timestamp NOT NULL, - - UNIQUE KEY cl_from(cl_from,cl_to), - KEY cl_sortkey(cl_to,cl_sortkey), - KEY cl_timestamp(cl_to,cl_timestamp) -) TYPE=InnoDB -ENDS; - $fields = array( - 'cl_from' => MW_UPGRADE_COPY, - 'cl_to' => MW_UPGRADE_ENCODE, - 'cl_sortkey' => MW_UPGRADE_ENCODE, - 'cl_timestamp' => MW_UPGRADE_COPY ); - $this->copyTable( 'categorylinks', $tabledef, $fields ); - } - } - - function upgradeIpblocks() { - global $wgUseLatin1; - if ( $wgUseLatin1 ) { - $tabledef = <<<ENDS -CREATE TABLE $1 ( - ipb_id int(8) NOT NULL auto_increment, - ipb_address varchar(40) binary NOT NULL default '', - ipb_user int(8) unsigned NOT NULL default '0', - ipb_by int(8) unsigned NOT NULL default '0', - ipb_reason tinyblob NOT NULL default '', - ipb_timestamp char(14) binary NOT NULL default '', - ipb_auto tinyint(1) NOT NULL default '0', - ipb_expiry char(14) binary NOT NULL default '', - - PRIMARY KEY ipb_id (ipb_id), - INDEX ipb_address (ipb_address), - INDEX ipb_user (ipb_user) - -) TYPE=InnoDB -ENDS; - $fields = array( - 'ipb_id' => MW_UPGRADE_COPY, - 'ipb_address' => MW_UPGRADE_COPY, - 'ipb_user' => MW_UPGRADE_COPY, - 'ipb_by' => MW_UPGRADE_COPY, - 'ipb_reason' => MW_UPGRADE_ENCODE, - 'ipb_timestamp' => MW_UPGRADE_COPY, - 'ipb_auto' => MW_UPGRADE_COPY, - 'ipb_expiry' => MW_UPGRADE_COPY ); - $this->copyTable( 'ipblocks', $tabledef, $fields ); - } - } - - function upgradeRecentchanges() { - // There's a format change in the namespace field - $tabledef = <<<ENDS -CREATE TABLE $1 ( - rc_id int(8) NOT NULL auto_increment, - rc_timestamp varchar(14) binary NOT NULL default '', - rc_cur_time varchar(14) binary NOT NULL default '', - - rc_user int(10) unsigned NOT NULL default '0', - rc_user_text varchar(255) binary NOT NULL default '', - - 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(3) unsigned NOT NULL default '0', - - rc_bot tinyint(3) unsigned NOT NULL default '0', - rc_new tinyint(3) unsigned NOT NULL default '0', - - rc_cur_id int(10) unsigned NOT NULL default '0', - rc_this_oldid int(10) unsigned NOT NULL default '0', - rc_last_oldid int(10) unsigned NOT NULL default '0', - - rc_type tinyint(3) unsigned NOT NULL default '0', - rc_moved_to_ns tinyint(3) unsigned NOT NULL default '0', - rc_moved_to_title varchar(255) binary NOT NULL default '', - - rc_patrolled tinyint(3) unsigned NOT NULL default '0', - - rc_ip char(15) NOT NULL default '', - - PRIMARY KEY rc_id (rc_id), - INDEX rc_timestamp (rc_timestamp), - INDEX rc_namespace_title (rc_namespace, rc_title), - INDEX rc_cur_id (rc_cur_id), - INDEX new_name_timestamp(rc_new,rc_namespace,rc_timestamp), - INDEX rc_ip (rc_ip) - -) TYPE=InnoDB -ENDS; - $fields = array( - 'rc_id' => MW_UPGRADE_COPY, - 'rc_timestamp' => MW_UPGRADE_COPY, - 'rc_cur_time' => MW_UPGRADE_COPY, - 'rc_user' => MW_UPGRADE_COPY, - 'rc_user_text' => MW_UPGRADE_ENCODE, - 'rc_namespace' => MW_UPGRADE_COPY, - 'rc_title' => MW_UPGRADE_ENCODE, - 'rc_comment' => MW_UPGRADE_ENCODE, - 'rc_minor' => MW_UPGRADE_COPY, - 'rc_bot' => MW_UPGRADE_COPY, - 'rc_new' => MW_UPGRADE_COPY, - 'rc_cur_id' => MW_UPGRADE_COPY, - 'rc_this_oldid' => MW_UPGRADE_COPY, - 'rc_last_oldid' => MW_UPGRADE_COPY, - 'rc_type' => MW_UPGRADE_COPY, - 'rc_moved_to_ns' => MW_UPGRADE_COPY, - 'rc_moved_to_title' => MW_UPGRADE_ENCODE, - 'rc_patrolled' => MW_UPGRADE_COPY, - 'rc_ip' => MW_UPGRADE_COPY ); - $this->copyTable( 'recentchanges', $tabledef, $fields ); - } - - function upgradeQuerycache() { - // There's a format change in the namespace field - $tabledef = <<<ENDS -CREATE TABLE $1 ( - -- A key name, generally the base name of of the special page. - qc_type char(32) NOT NULL, - - -- Some sort of stored value. Sizes, counts... - qc_value int(5) unsigned NOT NULL default '0', - - -- Target namespace+title - qc_namespace int NOT NULL default '0', - qc_title char(255) binary NOT NULL default '', - - KEY (qc_type,qc_value) - -) TYPE=InnoDB -ENDS; - $fields = array( - 'qc_type' => MW_UPGRADE_COPY, - 'qc_value' => MW_UPGRADE_COPY, - 'qc_namespace' => MW_UPGRADE_COPY, - 'qc_title' => MW_UPGRADE_ENCODE ); - $this->copyTable( 'querycache', $tabledef, $fields ); - } - - /** - * Check for duplicate rows in "cur" table and move duplicates entries in - * "old" table. - * - * This was in cleanupDupes.inc before. - */ - function checkDupes() { - $dbw = wfGetDB( DB_MASTER ); - if ( $dbw->indexExists( 'cur', 'name_title' ) && - $dbw->indexUnique( 'cur', 'name_title' ) ) { - echo wfWikiID() . ": cur table has the current unique index; no duplicate entries.\n"; - return; - } elseif ( $dbw->indexExists( 'cur', 'name_title_dup_prevention' ) ) { - echo wfWikiID() . ": cur table has a temporary name_title_dup_prevention unique index; no duplicate entries.\n"; - return; - } - - echo wfWikiID() . ": cur table has the old non-unique index and may have duplicate entries.\n"; - - $dbw = wfGetDB( DB_MASTER ); - $cur = $dbw->tableName( 'cur' ); - $old = $dbw->tableName( 'old' ); - $dbw->query( "LOCK TABLES $cur WRITE, $old WRITE" ); - echo "Checking for duplicate cur table entries... (this may take a while on a large wiki)\n"; - $res = $dbw->query( <<<END -SELECT cur_namespace,cur_title,count(*) as c,min(cur_id) as id - FROM $cur - GROUP BY cur_namespace,cur_title -HAVING c > 1 -END - ); - $n = $dbw->numRows( $res ); - echo "Found $n titles with duplicate entries.\n"; - if ( $n > 0 ) { - echo "Correcting...\n"; - foreach ( $res as $row ) { - $ns = intval( $row->cur_namespace ); - $title = $dbw->addQuotes( $row->cur_title ); - - # Get the first responding ID; that'll be the one we keep. - $id = $dbw->selectField( 'cur', 'cur_id', array( - 'cur_namespace' => $row->cur_namespace, - 'cur_title' => $row->cur_title ) ); - - echo "$ns:$row->cur_title (canonical ID $id)\n"; - if ( $id != $row->id ) { - echo " ** minimum ID $row->id; "; - $timeMin = $dbw->selectField( 'cur', 'cur_timestamp', array( - 'cur_id' => $row->id ) ); - $timeFirst = $dbw->selectField( 'cur', 'cur_timestamp', array( - 'cur_id' => $id ) ); - if ( $timeMin == $timeFirst ) { - echo "timestamps match at $timeFirst; ok\n"; - } else { - echo "timestamps don't match! min: $timeMin, first: $timeFirst; "; - if ( $timeMin > $timeFirst ) { - $id = $row->id; - echo "keeping minimum: $id\n"; - } else { - echo "keeping first: $id\n"; - } - } - } - - $dbw->query( <<<END -INSERT - INTO $old - (old_namespace, old_title, old_text, - old_comment, old_user, old_user_text, - old_timestamp, old_minor_edit, old_flags, - inverse_timestamp) -SELECT cur_namespace, cur_title, cur_text, - cur_comment, cur_user, cur_user_text, - cur_timestamp, cur_minor_edit, '', - inverse_timestamp - FROM $cur - WHERE cur_namespace=$ns - AND cur_title=$title - AND cur_id != $id -END - ); - $dbw->query( <<<END -DELETE - FROM $cur - WHERE cur_namespace=$ns - AND cur_title=$title - AND cur_id != $id -END - ); - } - } - $dbw->query( 'UNLOCK TABLES' ); - echo "Done.\n"; - } - - /** - * Rename all our temporary tables into final place. - * We've left things in place so a read-only wiki can continue running - * on the old code during all this. - */ - function upgradeCleanup() { - $this->renameTable( 'old', 'text' ); - - foreach ( $this->cleanupSwaps as $table ) { - $this->swap( $table ); - } - } - - function renameTable( $from, $to ) { - $this->log( "Renaming $from to $to..." ); - - $fromtable = $this->dbw->tableName( $from ); - $totable = $this->dbw->tableName( $to ); - $this->dbw->query( "ALTER TABLE $fromtable RENAME TO $totable" ); - } - - function swap( $base ) { - $this->renameTable( $base, "{$base}_old" ); - $this->renameTable( "{$base}_temp", $base ); - } - -} - -$maintClass = 'FiveUpgrade'; -require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/userDupes.inc b/maintenance/userDupes.inc index 31bae8ed..8bd80c97 100644 --- a/maintenance/userDupes.inc +++ b/maintenance/userDupes.inc @@ -1,6 +1,6 @@ <?php /** - * Helper class for update.php and upgrade1_5.php. + * Helper class for update.php. * * Copyright © 2005 Brion Vibber <brion@pobox.com> * http://www.mediawiki.org/ @@ -26,13 +26,17 @@ /** * Look for duplicate user table entries and optionally prune them. + * + * This is still used by our MysqlUpdater at: + * includes/installer/MysqlUpdater.php + * * @ingroup Maintenance */ class UserDupes { - var $db; - var $reassigned; - var $trimmed; - var $failed; + private $db; + private $reassigned; + private $trimmed; + private $failed; private $outputCallback; function __construct( &$database, $outputCallback ) { @@ -108,9 +112,9 @@ class UserDupes { $count = count( $dupes ); $this->out( "Found $count accounts with duplicate records on " . wfWikiID() . ".\n" ); - $this->trimmed = 0; + $this->trimmed = 0; $this->reassigned = 0; - $this->failed = 0; + $this->failed = 0; foreach ( $dupes as $name ) { $this->examine( $name, $doDelete ); } @@ -154,11 +158,7 @@ class UserDupes { * @access private */ function lock() { - if ( $this->newSchema() ) { - $set = array( 'user', 'revision' ); - } else { - $set = array( 'user', 'cur', 'old' ); - } + $set = array( 'user', 'revision' ); $names = array_map( array( $this, 'lockTable' ), $set ); $tables = implode( ',', $names ); @@ -170,14 +170,6 @@ class UserDupes { } /** - * @return bool - * @access private - */ - function newSchema() { - return MWInit::classExists( 'Revision' ); - } - - /** * @access private */ function unlock() { @@ -219,7 +211,7 @@ class UserDupes { __METHOD__ ); $firstRow = $this->db->fetchObject( $result ); - $firstId = $firstRow->user_id; + $firstId = $firstRow->user_id; $this->out( "Record that will be used for '$name' is user_id=$firstId\n" ); foreach ( $result as $row ) { @@ -262,27 +254,10 @@ class UserDupes { * @access private */ function editCount( $userid ) { - if ( $this->newSchema() ) { - return $this->editCountOn( 'revision', 'rev_user', $userid ); - } else { - return $this->editCountOn( 'cur', 'cur_user', $userid ) + - $this->editCountOn( 'old', 'old_user', $userid ); - } - } - - /** - * Count the number of hits on a given table for this account. - * @param $table string - * @param $field string - * @param $userid int - * @return int - * @access private - */ - function editCountOn( $table, $field, $userid ) { return intval( $this->db->selectField( - $table, + 'revision', 'COUNT(*)', - array( $field => $userid ), + array( 'rev_user' => $userid ), __METHOD__ ) ); } @@ -292,26 +267,10 @@ class UserDupes { * @access private */ function reassignEdits( $from, $to ) { - $set = $this->newSchema() - ? array( 'revision' => 'rev_user' ) - : array( 'cur' => 'cur_user', 'old' => 'old_user' ); - foreach ( $set as $table => $field ) { - $this->reassignEditsOn( $table, $field, $from, $to ); - } - } - - /** - * @param $table string - * @param $field string - * @param $from int - * @param $to int - * @access private - */ - function reassignEditsOn( $table, $field, $from, $to ) { - $this->out( "reassigning on $table... " ); - $this->db->update( $table, - array( $field => $to ), - array( $field => $from ), + $this->out( 'reassigning... ' ); + $this->db->update( 'revision', + array( 'rev_user' => $to ), + array( 'rev_user' => $from ), __METHOD__ ); $this->out( "ok. " ); } diff --git a/maintenance/userOptions.inc b/maintenance/userOptions.inc index 2a066579..51da80d3 100644 --- a/maintenance/userOptions.inc +++ b/maintenance/userOptions.inc @@ -25,7 +25,7 @@ $options = array( 'list', 'nowarn', 'quiet', 'usage', 'dry' ); $optionsWithArgs = array( 'old', 'new' ); -require_once( __DIR__ . '/commandLine.inc' ); +require_once __DIR__ . '/commandLine.inc'; /** * @ingroup Maintenance @@ -38,7 +38,7 @@ class userOptions { public $mOldValue; public $mNewValue; - private $mMode, $mReady ; + private $mMode, $mReady; /** Constructor. Will show usage and exit if script options are not correct */ function __construct( $opts, $args ) { @@ -60,9 +60,9 @@ class userOptions { */ private function checkOpts( $opts, $args ) { // The three possible ways to run the script: - $list = isset( $opts['list'] ); - $usage = isset( $opts['usage'] ) && ( count( $args ) <= 1 ); - $change = isset( $opts['old'] ) && isset( $opts['new'] ) && ( count( $args ) <= 1 ) ; + $list = isset( $opts['list'] ); + $usage = isset( $opts['usage'] ) && ( count( $args ) <= 1 ); + $change = isset( $opts['old'] ) && isset( $opts['new'] ) && ( count( $args ) <= 1 ); // We want only one of them $isValid = ( ( $list + $usage + $change ) == 1 ); @@ -82,18 +82,18 @@ class userOptions { $this->mQuick = isset( $opts['nowarn'] ); $this->mQuiet = isset( $opts['quiet'] ); - $this->mDry = isset( $opts['dry'] ); + $this->mDry = isset( $opts['dry'] ); // Set object properties, specially 'mMode' used by run() if ( isset( $opts['list'] ) ) { - $this->mMode = 'LISTER' ; + $this->mMode = 'LISTER'; } elseif ( isset( $opts['usage'] ) ) { - $this->mMode = 'USAGER' ; - $this->mAnOption = isset( $args[0] ) ? $args[0] : false ; + $this->mMode = 'USAGER'; + $this->mAnOption = isset( $args[0] ) ? $args[0] : false; } elseif ( isset( $opts['old'] ) && isset( $opts['new'] ) ) { - $this->mMode = 'CHANGER' ; - $this->mOldValue = $opts['old'] ; - $this->mNewValue = $opts['new'] ; + $this->mMode = 'CHANGER'; + $this->mOldValue = $opts['old']; + $this->mNewValue = $opts['new']; $this->mAnOption = $args[0]; } else { die( "There is a bug in the software, this should never happen\n" ); @@ -108,7 +108,7 @@ class userOptions { return false; } - $this->{ $this->mMode } ( ); + $this->{ $this->mMode } (); return true; } @@ -117,7 +117,7 @@ class userOptions { # /** List default options and their value */ - private function LISTER( ) { + private function LISTER() { $def = User::getDefaultOptions(); ksort( $def ); $maxOpt = 0; @@ -130,7 +130,7 @@ class userOptions { } /** List options usage */ - private function USAGER( ) { + private function USAGER() { $ret = array(); $defaultOptions = User::getDefaultOptions(); @@ -181,7 +181,7 @@ class userOptions { /** Change our users options */ - private function CHANGER( ) { + private function CHANGER() { $this->warn(); // We list user by user_id from one of the slave database @@ -212,7 +212,9 @@ class userOptions { if ( !$this->mDry ) { $user->saveSettings(); } - if ( !$this->mQuiet ) { print " OK\n"; } + if ( !$this->mQuiet ) { + print " OK\n"; + } } elseif ( !$this->mQuiet ) { print "Not changing '$username' using <{$this->mAnOption}> = '$curValue'\n"; diff --git a/maintenance/userOptions.php b/maintenance/userOptions.php index 2181e44d..e0de3574 100644 --- a/maintenance/userOptions.php +++ b/maintenance/userOptions.php @@ -25,7 +25,7 @@ */ // This is a command line script, load tools and parse args -require_once( 'userOptions.inc' ); +require_once 'userOptions.inc'; // Load up our tool system, exit with usage() if options are not fine $uo = new userOptions( $options, $args ); @@ -33,4 +33,3 @@ $uo = new userOptions( $options, $args ); $uo->run(); print "Done.\n"; - diff --git a/maintenance/waitForSlave.php b/maintenance/waitForSlave.php index 655be43d..a62d1618 100644 --- a/maintenance/waitForSlave.php +++ b/maintenance/waitForSlave.php @@ -22,7 +22,7 @@ * @see wfWaitForSlaves() */ -require_once( __DIR__ . '/Maintenance.php' ); +require_once __DIR__ . '/Maintenance.php'; /** * Maintenance script to wait until slave lag goes under a certain value. @@ -31,6 +31,7 @@ require_once( __DIR__ . '/Maintenance.php' ); */ class WaitForSlave extends Maintenance { public function __construct() { + parent::__construct(); $this->addArg( 'maxlag', 'How long to wait for the slaves, default 10 seconds', false ); } public function execute() { @@ -39,4 +40,4 @@ class WaitForSlave extends Maintenance { } $maintClass = "WaitForSlave"; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; |