diff options
Diffstat (limited to 'maintenance')
89 files changed, 1887 insertions, 1509 deletions
diff --git a/maintenance/Maintenance.php b/maintenance/Maintenance.php index 5dafdfc0..04aa3a5e 100644 --- a/maintenance/Maintenance.php +++ b/maintenance/Maintenance.php @@ -36,6 +36,8 @@ define( 'DO_MAINTENANCE', RUN_MAINTENANCE_IF_MAIN ); // original name, harmless $maintClass = false; +use MediaWiki\Logger\LoggerFactory; + /** * Abstract maintenance class for quickly writing and churning out * maintenance scripts with minimal effort. All that _must_ be defined @@ -599,17 +601,27 @@ abstract class Maintenance { * Activate the profiler (assuming $wgProfiler is set) */ protected function activateProfiler() { - global $wgProfiler; + global $wgProfiler, $wgProfileLimit, $wgTrxProfilerLimits; $output = $this->getOption( 'profiler' ); - if ( $output && is_array( $wgProfiler ) && isset( $wgProfiler['class'] ) ) { + if ( !$output ) { + return; + } + + if ( is_array( $wgProfiler ) && isset( $wgProfiler['class'] ) ) { $class = $wgProfiler['class']; $profiler = new $class( - array( 'sampling' => 1, 'output' => $output ) + $wgProfiler + array( 'sampling' => 1, 'output' => array( $output ) ) + + $wgProfiler + + array( 'threshold' => $wgProfileLimit ) ); $profiler->setTemplated( true ); Profiler::replaceStubInstance( $profiler ); } + + $trxProfiler = Profiler::instance()->getTransactionProfiler(); + $trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) ); + $trxProfiler->setExpectations( $wgTrxProfilerLimits['Maintenance'], __METHOD__ ); } /** @@ -945,10 +957,9 @@ abstract class Maintenance { $wgShowSQLErrors = true; - // @codingStandardsIgnoreStart Allow error suppression. wfSuppressWarnings() - // is not available. - @set_time_limit( 0 ); - // @codingStandardsIgnoreStart + MediaWiki\suppressWarnings(); + set_time_limit( 0 ); + MediaWiki\restoreWarnings(); $this->adjustMemoryLimit(); } diff --git a/maintenance/archives/patch-il_from_namespace.sql b/maintenance/archives/patch-il_from_namespace.sql index 4c858f44..2a2d361b 100644 --- a/maintenance/archives/patch-il_from_namespace.sql +++ b/maintenance/archives/patch-il_from_namespace.sql @@ -1,4 +1,4 @@ ALTER TABLE /*_*/imagelinks ADD COLUMN il_from_namespace int NOT NULL default 0; -CREATE INDEX /*i*/il_backlinks_namespace ON /*_*/imagelinks (il_to,il_from_namespace,il_from);
\ No newline at end of file +CREATE INDEX /*i*/il_backlinks_namespace ON /*_*/imagelinks (il_from_namespace,il_to,il_from);
\ No newline at end of file diff --git a/maintenance/archives/patch-pl_from_namespace.sql b/maintenance/archives/patch-pl_from_namespace.sql index 2f7ff046..dcf2b60a 100644 --- a/maintenance/archives/patch-pl_from_namespace.sql +++ b/maintenance/archives/patch-pl_from_namespace.sql @@ -1,4 +1,4 @@ ALTER TABLE /*_*/pagelinks ADD COLUMN pl_from_namespace int NOT NULL default 0; -CREATE INDEX /*i*/pl_backlinks_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from_namespace,pl_from); +CREATE INDEX /*i*/pl_backlinks_namespace ON /*_*/pagelinks (pl_from_namespace,pl_namespace,pl_title,pl_from); diff --git a/maintenance/archives/patch-tl_from_namespace.sql b/maintenance/archives/patch-tl_from_namespace.sql index 8d6c76b8..edfb7a52 100644 --- a/maintenance/archives/patch-tl_from_namespace.sql +++ b/maintenance/archives/patch-tl_from_namespace.sql @@ -1,4 +1,4 @@ ALTER TABLE /*_*/templatelinks ADD COLUMN tl_from_namespace int NOT NULL default 0; -CREATE INDEX /*i*/tl_backlinks_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from_namespace,tl_from); +CREATE INDEX /*i*/tl_backlinks_namespace ON /*_*/templatelinks (tl_from_namespace,tl_namespace,tl_title,tl_from); diff --git a/maintenance/backup.inc b/maintenance/backup.inc index 222c538b..6e1ddb4e 100644 --- a/maintenance/backup.inc +++ b/maintenance/backup.inc @@ -135,9 +135,9 @@ class BackupDumper { foreach ( $args as $arg ) { $matches = array(); if ( preg_match( '/^--(.+?)(?:=(.+?)(?::(.+?))?)?$/', $arg, $matches ) ) { - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); list( /* $full */, $opt, $val, $param ) = $matches; - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); switch ( $opt ) { case "plugin": diff --git a/maintenance/backupTextPass.inc b/maintenance/backupTextPass.inc index d83f1fcc..27be5fd6 100644 --- a/maintenance/backupTextPass.inc +++ b/maintenance/backupTextPass.inc @@ -659,13 +659,13 @@ class TextPassDumper extends BackupDumper { } private function getTextSpawned( $id ) { - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); if ( !$this->spawnProc ) { // First time? $this->openSpawn(); } $text = $this->getTextSpawnedOnce( $id ); - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); return $text; } @@ -712,7 +712,7 @@ class TextPassDumper extends BackupDumper { } private function closeSpawn() { - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); if ( $this->spawnRead ) { fclose( $this->spawnRead ); } @@ -729,7 +729,7 @@ class TextPassDumper extends BackupDumper { pclose( $this->spawnProc ); } $this->spawnProc = false; - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); } private function getTextSpawnedOnce( $id ) { diff --git a/maintenance/benchmarks/benchmarkHooks.php b/maintenance/benchmarks/benchmarkHooks.php index fb25b9d9..14468719 100644 --- a/maintenance/benchmarks/benchmarkHooks.php +++ b/maintenance/benchmarks/benchmarkHooks.php @@ -66,7 +66,7 @@ class BenchmarkHooks extends Benchmarker { private function benchHooks( $trials = 10 ) { $start = microtime( true ); for ( $i = 0; $i < $trials; $i++ ) { - wfRunHooks( 'Test' ); + Hooks::run( 'Test' ); } $delta = microtime( true ) - $start; $pertrial = $delta / $trials; diff --git a/maintenance/checkComposerLockUpToDate.php b/maintenance/checkComposerLockUpToDate.php index 0b77578d..47720710 100644 --- a/maintenance/checkComposerLockUpToDate.php +++ b/maintenance/checkComposerLockUpToDate.php @@ -60,4 +60,4 @@ class CheckComposerLockUpToDate extends Maintenance { } $maintClass = 'CheckComposerLockUpToDate'; -require_once RUN_MAINTENANCE_IF_MAIN;
\ No newline at end of file +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/checkImages.php b/maintenance/checkImages.php index 3921c079..0364db20 100644 --- a/maintenance/checkImages.php +++ b/maintenance/checkImages.php @@ -42,39 +42,33 @@ class CheckImages extends Maintenance { $numImages = 0; $numGood = 0; + $repo = RepoGroup::singleton()->getLocalRepo(); do { $res = $dbr->select( 'image', '*', array( 'img_name > ' . $dbr->addQuotes( $start ) ), __METHOD__, array( 'LIMIT' => $this->mBatchSize ) ); foreach ( $res as $row ) { $numImages++; $start = $row->img_name; - $file = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row ); + $file = $repo->newFileFromRow( $row ); $path = $file->getPath(); if ( !$path ) { $this->output( "{$row->img_name}: not locally accessible\n" ); continue; } - wfSuppressWarnings(); - $stat = stat( $file->getPath() ); - wfRestoreWarnings(); - if ( !$stat ) { + $size = $repo->getFileSize( $file->getPath() ); + if ( $size === false ) { $this->output( "{$row->img_name}: missing\n" ); continue; } - if ( $stat['mode'] & 040000 ) { - $this->output( "{$row->img_name}: is a directory\n" ); - continue; - } - - if ( $stat['size'] == 0 && $row->img_size != 0 ) { + if ( $size == 0 && $row->img_size != 0 ) { $this->output( "{$row->img_name}: truncated, was {$row->img_size}\n" ); continue; } - if ( $stat['size'] != $row->img_size ) { + if ( $size != $row->img_size ) { $this->output( "{$row->img_name}: size mismatch DB={$row->img_size}, " - . "actual={$stat['size']}\n" ); + . "actual={$size}\n" ); continue; } diff --git a/maintenance/checkSyntax.php b/maintenance/checkSyntax.php index d1c2edd0..30a23d30 100644 --- a/maintenance/checkSyntax.php +++ b/maintenance/checkSyntax.php @@ -121,9 +121,9 @@ class CheckSyntax extends Maintenance { return; // process only this path } elseif ( $this->hasOption( 'list-file' ) ) { $file = $this->getOption( 'list-file' ); - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); $f = fopen( $file, 'r' ); - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); if ( !$f ) { $this->error( "Can't open file $file\n", true ); } diff --git a/maintenance/checkUsernames.php b/maintenance/checkUsernames.php index 777c8334..a64bc498 100644 --- a/maintenance/checkUsernames.php +++ b/maintenance/checkUsernames.php @@ -56,7 +56,7 @@ class CheckUsernames extends Maintenance { foreach ( $res as $row ) { if ( !User::isValidUserName( $row->user_name ) ) { - $this->error( sprintf( "%s: %6d: '%s'\n", wfWikiID(), $row->user_id, $row->user_name ) ); + $this->output( sprintf( "Found: %6d: '%s'\n", $row->user_id, $row->user_name ) ); wfDebugLog( 'checkUsernames', $row->user_name ); } } diff --git a/maintenance/cleanupRemovedModules.php b/maintenance/cleanupRemovedModules.php index e1d0ed6e..a4e66ca6 100644 --- a/maintenance/cleanupRemovedModules.php +++ b/maintenance/cleanupRemovedModules.php @@ -36,13 +36,6 @@ class CleanupRemovedModules extends Maintenance { parent::__construct(); $this->mDescription = 'Remove cache entries for removed ResourceLoader modules from the database'; $this->addOption( 'batchsize', 'Delete rows in batches of this size. Default: 500', false, true ); - $this->addOption( - 'max-slave-lag', - 'If the slave lag exceeds this many seconds, wait until it drops below this value. ' - . 'Default: 5', - false, - true - ); } public function execute() { @@ -51,7 +44,6 @@ class CleanupRemovedModules extends Maintenance { $moduleNames = $rl->getModuleNames(); $moduleList = implode( ', ', array_map( array( $dbw, 'addQuotes' ), $moduleNames ) ); $limit = max( 1, intval( $this->getOption( 'batchsize', 500 ) ) ); - $maxlag = intval( $this->getOption( 'max-slave-lag', 5 ) ); $this->output( "Cleaning up module_deps table...\n" ); $i = 1; @@ -63,7 +55,7 @@ class CleanupRemovedModules extends Maintenance { $numRows = $dbw->affectedRows(); $this->output( "Batch $i: $numRows rows\n" ); $i++; - wfWaitForSlaves( $maxlag ); + wfWaitForSlaves(); } while ( $numRows > 0 ); $this->output( "done\n" ); @@ -77,7 +69,7 @@ class CleanupRemovedModules extends Maintenance { $numRows = $dbw->affectedRows(); $this->output( "Batch $i: $numRows rows\n" ); $i++; - wfWaitForSlaves( $maxlag ); + wfWaitForSlaves(); } while ( $numRows > 0 ); $this->output( "done\n" ); @@ -90,7 +82,7 @@ class CleanupRemovedModules extends Maintenance { $numRows = $dbw->affectedRows(); $this->output( "Batch $i: $numRows rows\n" ); $i++; - wfWaitForSlaves( $maxlag ); + wfWaitForSlaves(); } while ( $numRows > 0 ); $this->output( "done\n" ); } diff --git a/maintenance/cleanupTable.inc b/maintenance/cleanupTable.inc index cbd1be6b..f6259e95 100644 --- a/maintenance/cleanupTable.inc +++ b/maintenance/cleanupTable.inc @@ -37,7 +37,6 @@ class TableCleanup extends Maintenance { ); protected $dryrun = false; - protected $maxLag = 10; # if slaves are lagged more than 10 secs, wait public $batchSize = 100; public $reportInterval = 100; diff --git a/maintenance/cleanupUploadStash.php b/maintenance/cleanupUploadStash.php index 24b63a8b..70490e1b 100644 --- a/maintenance/cleanupUploadStash.php +++ b/maintenance/cleanupUploadStash.php @@ -87,6 +87,7 @@ class UploadStashCleanup extends Maintenance { $this->output( "Failed removing stashed upload with key: $key ($type)\n" ); } if ( $i % 100 == 0 ) { + wfWaitForSlaves(); $this->output( "$i\n" ); } } diff --git a/maintenance/convertExtensionToRegistration.php b/maintenance/convertExtensionToRegistration.php index acb8d3aa..3e86d8a6 100644 --- a/maintenance/convertExtensionToRegistration.php +++ b/maintenance/convertExtensionToRegistration.php @@ -6,7 +6,7 @@ class ConvertExtensionToRegistration extends Maintenance { protected $custom = array( 'MessagesDirs' => 'handleMessagesDirs', - 'ExtensionMessagesFiles' => 'removeAbsolutePath', + 'ExtensionMessagesFiles' => 'handleExtensionMessagesFiles', 'AutoloadClasses' => 'removeAbsolutePath', 'ExtensionCredits' => 'handleCredits', 'ResourceModules' => 'handleResourceModules', @@ -31,7 +31,7 @@ class ConvertExtensionToRegistration extends Maintenance { * @var array */ protected $noLongerSupportedGlobals = array( - 'SpecialPageGroups' => 'deprecated', + 'SpecialPageGroups' => 'deprecated', // Deprecated 1.21, removed in 1.26 ); /** @@ -56,7 +56,8 @@ class ConvertExtensionToRegistration extends Maintenance { public function __construct() { parent::__construct(); $this->mDescription = 'Converts extension entry points to the new JSON registration format'; - $this->addArg( 'path', 'Location to the PHP entry point you wish to convert', /* $required = */ true ); + $this->addArg( 'path', 'Location to the PHP entry point you wish to convert', + /* $required = */ true ); $this->addOption( 'skin', 'Whether to write to skin.json', false, false ); } @@ -95,7 +96,8 @@ class ConvertExtensionToRegistration extends Maintenance { } if ( isset( $this->custom[$realName] ) ) { - call_user_func_array( array( $this, $this->custom[$realName] ), array( $realName, $value ) ); + call_user_func_array( array( $this, $this->custom[$realName] ), + array( $realName, $value, $vars ) ); } elseif ( in_array( $realName, $globalSettings ) ) { $this->json[$realName] = $value; } elseif ( array_key_exists( $realName, $this->noLongerSupportedGlobals ) ) { @@ -118,7 +120,8 @@ class ConvertExtensionToRegistration extends Maintenance { } } $out += $this->json; - + // Put this at the bottom + $out['manifest_version'] = ExtensionRegistry::MANIFEST_VERSION; $type = $this->hasOption( 'skin' ) ? 'skin' : 'extension'; $fname = "{$this->dir}/$type.json"; $prettyJSON = FormatJson::encode( $out, "\t", FormatJson::ALL_OK ); @@ -132,7 +135,9 @@ class ConvertExtensionToRegistration extends Maintenance { protected function handleExtensionFunctions( $realName, $value ) { foreach ( $value as $func ) { if ( $func instanceof Closure ) { - $this->error( "Error: Closures cannot be converted to JSON. Please move your extension function somewhere else.", 1 ); + $this->error( "Error: Closures cannot be converted to JSON. " . + "Please move your extension function somewhere else.", 1 + ); } } @@ -147,6 +152,21 @@ class ConvertExtensionToRegistration extends Maintenance { } } + protected function handleExtensionMessagesFiles( $realName, $value, $vars ) { + foreach ( $value as $key => $file ) { + $strippedFile = $this->stripPath( $file, $this->dir ); + if ( isset( $vars['wgMessagesDirs'][$key] ) ) { + $this->output( + "Note: Ignoring PHP shim $strippedFile. " . + "If your extension no longer supports versions of MediaWiki " . + "older than 1.23.0, you can safely delete it.\n" + ); + } else { + $this->json[$realName][$key] = $strippedFile; + } + } + } + private function stripPath( $val, $dir ) { if ( $val === $dir ) { $val = ''; @@ -166,7 +186,7 @@ class ConvertExtensionToRegistration extends Maintenance { $this->json[$realName] = $out; } - protected function handleCredits( $realName, $value) { + protected function handleCredits( $realName, $value ) { $keys = array_keys( $value ); $this->json['type'] = $keys[0]; $values = array_values( $value ); @@ -181,7 +201,9 @@ class ConvertExtensionToRegistration extends Maintenance { foreach ( $value as $hookName => $handlers ) { foreach ( $handlers as $func ) { if ( $func instanceof Closure ) { - $this->error( "Error: Closures cannot be converted to JSON. Please move the handler for $hookName somewhere else.", 1 ); + $this->error( "Error: Closures cannot be converted to JSON. " . + "Please move the handler for $hookName somewhere else.", 1 + ); } } } @@ -213,7 +235,6 @@ class ConvertExtensionToRegistration extends Maintenance { } } - $this->json[$realName][$name] = $data; } if ( $defaults ) { diff --git a/maintenance/copyFileBackend.php b/maintenance/copyFileBackend.php index 9ed63c3c..b39ff55e 100644 --- a/maintenance/copyFileBackend.php +++ b/maintenance/copyFileBackend.php @@ -226,8 +226,8 @@ class CopyFileBackend extends Maintenance { } $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" . + $elapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); + $this->output( "\n\tDownloaded these file(s) [{$elapsed_ms}ms]:\n\t" . implode( "\n\t", $srcPaths ) . "\n\n" ); } @@ -281,12 +281,12 @@ class CopyFileBackend extends Maintenance { sleep( 10 ); // wait and retry copy again $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); } - $ellapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); + $elapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); if ( !$status->isOK() ) { $this->error( print_r( $status->getErrorsArray(), true ) ); $this->error( "$wikiId: Could not copy file batch.", 1 ); // die } elseif ( count( $copiedRel ) ) { - $this->output( "\n\tCopied these file(s) [{$ellapsed_ms}ms]:\n\t" . + $this->output( "\n\tCopied these file(s) [{$elapsed_ms}ms]:\n\t" . implode( "\n\t", $copiedRel ) . "\n\n" ); } } @@ -318,12 +318,12 @@ class CopyFileBackend extends Maintenance { sleep( 10 ); // wait and retry copy again $status = $dst->doQuickOperations( $ops, array( 'bypassReadOnly' => 1 ) ); } - $ellapsed_ms = floor( ( microtime( true ) - $t_start ) * 1000 ); + $elapsed_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" . + $this->output( "\n\tDeleted these file(s) [{$elapsed_ms}ms]:\n\t" . implode( "\n\t", $deletedRel ) . "\n\n" ); } } diff --git a/maintenance/createAndPromote.php b/maintenance/createAndPromote.php index 79f72542..861b364b 100644 --- a/maintenance/createAndPromote.php +++ b/maintenance/createAndPromote.php @@ -43,6 +43,14 @@ class CreateAndPromote extends Maintenance { foreach ( self::$permitRoles as $role ) { $this->addOption( $role, "Add the account to the {$role} group" ); } + + $this->addOption( + 'custom-groups', + 'Comma-separated list of groups to add the user to', + false, + true + ); + $this->addArg( "username", "Username of new user" ); $this->addArg( "password", "Password to set (not required if --force is used)", false ); } @@ -69,8 +77,19 @@ class CreateAndPromote extends Maintenance { $inGroups = $user->getGroups(); } + $groups = array_filter( self::$permitRoles, array( $this, 'hasOption' ) ); + if ( $this->hasOption( 'custom-groups' ) ) { + $customGroupsText = $this->getOption( 'custom-groups' ); + if ( $customGroupsText !== '' ) { + $customGroups = explode( ',', $customGroupsText ); + foreach ( $customGroups as $customGroup ) { + $groups[] = trim( $customGroup ); + } + } + } + $promotions = array_diff( - array_filter( self::$permitRoles, array( $this, 'hasOption' ) ), + $groups, $inGroups ); diff --git a/maintenance/deleteArchivedFiles.inc b/maintenance/deleteArchivedFiles.inc deleted file mode 100644 index 0c0b34a3..00000000 --- a/maintenance/deleteArchivedFiles.inc +++ /dev/null @@ -1,84 +0,0 @@ -<?php -/** - * Core functions for deleteArchivedFiles.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 - */ - -/** - * Core functions for deleteArchivedFiles.php - * - * @ingroup Maintenance - */ -class DeleteArchivedFilesImplementation { - public static function doDelete( $output, $force ) { - # Data should come off the master, wrapped in a transaction - $dbw = wfGetDB( DB_MASTER ); - $dbw->begin( __METHOD__ ); - $tbl_arch = $dbw->tableName( 'filearchive' ); - $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,fa_sha1 FROM $tbl_arch" ); - $count = 0; - foreach ( $res as $row ) { - $key = $row->fa_storage_key; - if ( !strlen( $key ) ) { - $output->handleOutput( "Entry with ID {$row->fa_id} has empty key, skipping\n" ); - continue; - } - $group = $row->fa_storage_group; - $id = $row->fa_id; - $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key; - 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, - 'oi_deleted & ' . File::DELETED_FILE => File::DELETED_FILE - ), - __METHOD__, - array( 'FOR UPDATE' ) - ); - if ( $path && $repo->fileExists( $path ) && !$inuse ) { - if ( $repo->quickPurge( $path ) ) { - $count++; - $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" ); - } else { - $output->handleOutput( "Unable to remove file $path, skipping\n" ); - } - } else { - $output->handleOutput( "Notice - file '$key' not found in group '$group'\n" ); - if ( $force ) { - $output->handleOutput( "Got --force, deleting DB entry\n" ); - $dbw->query( "DELETE FROM $tbl_arch WHERE fa_id = $id" ); - } - } - } - $dbw->commit( __METHOD__ ); - $output->handleOutput( "Done! [$count file(s)]\n" ); - } -} diff --git a/maintenance/deleteArchivedFiles.php b/maintenance/deleteArchivedFiles.php index 286b1f24..bd8ca109 100644 --- a/maintenance/deleteArchivedFiles.php +++ b/maintenance/deleteArchivedFiles.php @@ -25,7 +25,6 @@ */ require_once __DIR__ . '/Maintenance.php'; -require_once __DIR__ . '/deleteArchivedFiles.inc'; /** * Maintenance script to delete archived (non-current) files from the database. @@ -40,18 +39,82 @@ class DeleteArchivedFiles extends Maintenance { $this->addOption( 'force', 'Force deletion of rows from filearchive' ); } - public function handleOutput( $str ) { - return $this->output( $str ); - } - public function execute() { if ( !$this->hasOption( 'delete' ) ) { $this->output( "Use --delete to actually confirm this script\n" ); - return; } - $force = $this->hasOption( 'force' ); - DeleteArchivedFilesImplementation::doDelete( $this, $force ); + + # Data should come off the master, wrapped in a transaction + $dbw = $this->getDB( DB_MASTER ); + $dbw->begin( __METHOD__ ); + $repo = RepoGroup::singleton()->getLocalRepo(); + + # Get "active" revisions from the filearchive table + $this->output( "Searching for and deleting archived files...\n" ); + $res = $dbw->select( + 'filearchive', + array( 'fa_id', 'fa_storage_group', 'fa_storage_key', 'fa_sha1' ), + '', + __METHOD__ + ); + + $count = 0; + foreach ( $res as $row ) { + $key = $row->fa_storage_key; + if ( !strlen( $key ) ) { + $this->output( "Entry with ID {$row->fa_id} has empty key, skipping\n" ); + continue; + } + + $group = $row->fa_storage_group; + $id = $row->fa_id; + $path = $repo->getZonePath( 'deleted' ) . '/' . $repo->getDeletedHashPath( $key ) . $key; + 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, + $dbw->bitAnd( 'oi_deleted', File::DELETED_FILE ) => File::DELETED_FILE + ), + __METHOD__, + array( 'FOR UPDATE' ) + ); + + $needForce = true; + if ( !$repo->fileExists( $path ) ) { + $this->output( "Notice - file '$key' not found in group '$group'\n" ); + } elseif ( $inuse ) { + $this->output( "Notice - file '$key' is still in use\n" ); + } elseif ( !$repo->quickPurge( $path ) ) { + $this->output( "Unable to remove file $path, skipping\n" ); + continue; // don't delete even with --force + } else { + $needForce = false; + } + + if ( $needForce ) { + if ( $this->hasOption( 'force' ) ) { + $this->output( "Got --force, deleting DB entry\n" ); + } else { + continue; + } + } + + $count++; + $dbw->delete( 'filearchive', array( 'fa_id' => $id ), __METHOD__ ); + } + + $dbw->commit( __METHOD__ ); + $this->output( "Done! [$count file(s)]\n" ); } } diff --git a/maintenance/deleteArchivedRevisions.inc b/maintenance/deleteArchivedRevisions.inc deleted file mode 100644 index ed620ee3..00000000 --- a/maintenance/deleteArchivedRevisions.inc +++ /dev/null @@ -1,61 +0,0 @@ -<?php -/** - * Helper methods for the deleteArchivedRevisions.php maintenance script. - * - * 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 - */ - -/** - * Helper methods for the deleteArchivedRevisions.php maintenance script. - * - * @ingroup Maintenance - */ -class DeleteArchivedRevisionsImplementation { - - /** - * Perform the delete on archived revisions. - * @param object $maint An object (typically of class Maintenance) - * that implements two methods: handleOutput() and - * purgeRedundantText(). See Maintenance for a description of - * those methods. - */ - public static function doDelete( $maint ) { - $dbw = wfGetDB( DB_MASTER ); - - $dbw->begin( __METHOD__ ); - - $tbl_arch = $dbw->tableName( 'archive' ); - - # Delete as appropriate - $maint->handleOutput( "Deleting archived revisions... " ); - $dbw->query( "DELETE FROM $tbl_arch" ); - - $count = $dbw->affectedRows(); - $deletedRows = $count != 0; - - $maint->handleOutput( "done. $count revisions deleted.\n" ); - - # This bit's done - # Purge redundant text records - $dbw->commit( __METHOD__ ); - if ( $deletedRows ) { - $maint->purgeRedundantText( true ); - } - } -} diff --git a/maintenance/deleteArchivedRevisions.php b/maintenance/deleteArchivedRevisions.php index 30883ba4..9924eb0c 100644 --- a/maintenance/deleteArchivedRevisions.php +++ b/maintenance/deleteArchivedRevisions.php @@ -25,7 +25,6 @@ */ require_once __DIR__ . '/Maintenance.php'; -require_once __DIR__ . '/deleteArchivedRevisions.inc'; /** * Maintenance script to delete archived (deleted from public) revisions @@ -41,21 +40,24 @@ class DeleteArchivedRevisions extends Maintenance { $this->addOption( 'delete', 'Performs the deletion' ); } - public function handleOutput( $str ) { - $this->output( $str ); - } - public function execute() { - $this->output( "Delete archived revisions\n\n" ); - # Data should come off the master, wrapped in a transaction - if ( $this->hasOption( 'delete' ) ) { - DeleteArchivedRevisionsImplementation::doDelete( $this ); - } else { - $dbw = wfGetDB( DB_MASTER ); - $res = $dbw->selectRow( 'archive', 'COUNT(*) as count', array(), __FUNCTION__ ); - $this->output( "Found {$res->count} revisions to delete.\n" ); + $dbw = $this->getDB( DB_MASTER ); + + if ( !$this->hasOption( 'delete' ) ) { + $count = $dbw->selectField( 'archive', 'COUNT(*)', '', __METHOD__ ); + $this->output( "Found $count revisions to delete.\n" ); $this->output( "Please run the script again with the --delete option " . "to really delete the revisions.\n" ); + return; + } + + $this->output( "Deleting archived revisions... " ); + $dbw->delete( 'archive', '*', __METHOD__ ); + $count = $dbw->affectedRows(); + $this->output( "done. $count revisions deleted.\n" ); + + if ( $count ) { + $this->purgeRedundantText( true ); } } } diff --git a/maintenance/deleteBatch.php b/maintenance/deleteBatch.php index 93507b34..e6321e1f 100644 --- a/maintenance/deleteBatch.php +++ b/maintenance/deleteBatch.php @@ -97,7 +97,6 @@ class DeleteBatch extends Maintenance { } $this->output( $title->getPrefixedText() ); - $dbw->begin( __METHOD__ ); if ( $title->getNamespace() == NS_FILE ) { $img = wfFindFile( $title, array( 'ignoreRedirect' => true ) ); if ( $img && $img->isLocal() && !$img->delete( $reason ) ) { @@ -106,8 +105,7 @@ class DeleteBatch extends Maintenance { } $page = WikiPage::factory( $title ); $error = ''; - $success = $page->doDeleteArticle( $reason, false, 0, false, $error, $user ); - $dbw->commit( __METHOD__ ); + $success = $page->doDeleteArticle( $reason, false, 0, true, $error, $user ); if ( $success ) { $this->output( " Deleted!\n" ); } else { diff --git a/maintenance/deleteDefaultMessages.php b/maintenance/deleteDefaultMessages.php index 5aeeb8e1..a1c0f616 100644 --- a/maintenance/deleteDefaultMessages.php +++ b/maintenance/deleteDefaultMessages.php @@ -76,10 +76,9 @@ class DeleteDefaultMessages extends Maintenance { $dbw->ping(); $title = Title::makeTitle( $row->page_namespace, $row->page_title ); $page = WikiPage::factory( $title ); - $dbw->begin( __METHOD__ ); $error = ''; // Passed by ref - $page->doDeleteArticle( 'No longer required', false, 0, false, $error, $user ); - $dbw->commit( __METHOD__ ); + // FIXME: Deletion failures should be reported, not silently ignored. + $page->doDeleteArticle( 'No longer required', false, 0, true, $error, $user ); } $this->output( "done!\n", 'msg' ); diff --git a/maintenance/deleteEqualMessages.php b/maintenance/deleteEqualMessages.php index dbe96982..478e0d70 100644 --- a/maintenance/deleteEqualMessages.php +++ b/maintenance/deleteEqualMessages.php @@ -182,14 +182,20 @@ class DeleteEqualMessages extends Maintenance { $this->output( "\n* [[$title]]" ); $page = WikiPage::factory( $title ); $error = ''; // Passed by ref - $page->doDeleteArticle( 'No longer required', false, 0, false, $error, $user ); + $success = $page->doDeleteArticle( 'No longer required', false, 0, true, $error, $user ); + if ( !$success ) { + $this->output( " (Failed!)" ); + } 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 ); + $success = $page->doDeleteArticle( 'Orphaned talk page of no longer required message', + false, 0, true, $error, $user ); + if ( !$success ) { + $this->output( " (Failed!)" ); + } } } $this->output( "\n\ndone!\n" ); diff --git a/maintenance/deleteImageMemcached.php b/maintenance/deleteImageMemcached.php deleted file mode 100644 index 4799e5e0..00000000 --- a/maintenance/deleteImageMemcached.php +++ /dev/null @@ -1,89 +0,0 @@ -<?php -/** - * Delete image information from the object cache. - * - * Usage example: - * php deleteImageMemcached.php --until "2005-09-05 00:00:00" --sleep 0 - * - * 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 image information from the object cache. - * - * @ingroup Maintenance - */ -class DeleteImageCache extends Maintenance { - public function __construct() { - parent::__construct(); - $this->mDescription = "Delete image information from the cache"; - $this->addOption( 'sleep', 'How many seconds to sleep between deletions', true, true ); - $this->addOption( 'until', 'Timestamp to delete all entries prior to', true, true ); - } - - public function execute() { - global $wgMemc; - - $until = preg_replace( "/[^\d]/", '', $this->getOption( 'until' ) ); - $sleep = (int)$this->getOption( 'sleep' ) * 1000; // milliseconds - - ini_set( 'display_errors', false ); - - $dbr = wfGetDB( DB_SLAVE ); - - $res = $dbr->select( 'image', - array( 'img_name' ), - array( "img_timestamp < {$until}" ), - __METHOD__ - ); - - $i = 0; - $total = $this->getImageCount(); - - foreach ( $res as $row ) { - 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 ) { - usleep( $sleep ); - } - - ++$i; - } - } - - private function getImageCount() { - $dbr = wfGetDB( DB_SLAVE ); - - return $dbr->selectField( 'image', 'COUNT(*)', array(), __METHOD__ ); - } -} - -$maintClass = "DeleteImageCache"; -require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/dictionary/mediawiki.dic b/maintenance/dictionary/mediawiki.dic index ad19a1ce..8e4e5314 100644 --- a/maintenance/dictionary/mediawiki.dic +++ b/maintenance/dictionary/mediawiki.dic @@ -1434,6 +1434,7 @@ excludepage excludeuser executables exempt +exiftool existingwiki exists exiv @@ -3000,9 +3001,6 @@ outreachwiki over overridable override -oversight -oversighted -oversighter overwrite overwroteimage own @@ -4243,8 +4241,6 @@ unmakesafe unmark unmerge unmodified -unoversight -unoversighted unpadded unpatrolled unpatrolledletter diff --git a/maintenance/eraseArchivedFile.php b/maintenance/eraseArchivedFile.php index 94ca604d..8fdcef3a 100644 --- a/maintenance/eraseArchivedFile.php +++ b/maintenance/eraseArchivedFile.php @@ -73,7 +73,6 @@ class EraseArchivedFile extends Maintenance { $this->output( "Purging all thumbnails for file '$filename'..." ); $file->purgeCache(); - $file->purgeHistory(); $this->output( "done.\n" ); if ( $afile instanceof ArchivedFile ) { diff --git a/maintenance/exportSites.php b/maintenance/exportSites.php index 1c71dc0e..145c9249 100644 --- a/maintenance/exportSites.php +++ b/maintenance/exportSites.php @@ -17,7 +17,9 @@ class ExportSites extends Maintenance { public function __construct() { $this->mDescription = 'Exports site definitions the sites table to XML file'; - $this->addArg( 'file', 'A file to write the XML to (see docs/sitelist.txt). Use "php://stdout" to write to stdout.', true ); + $this->addArg( 'file', 'A file to write the XML to (see docs/sitelist.txt). ' . + 'Use "php://stdout" to write to stdout.', true + ); parent::__construct(); } @@ -34,7 +36,7 @@ class ExportSites extends Maintenance { $handle = fopen( $file, 'w' ); - if ( !$handle ) { + if ( !$handle ) { $this->error( "Failed to open $file for writing.\n", 1 ); } @@ -51,4 +53,4 @@ class ExportSites extends Maintenance { } $maintClass = 'ExportSites'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/findHooks.php b/maintenance/findHooks.php index 5cf45367..114366bc 100644 --- a/maintenance/findHooks.php +++ b/maintenance/findHooks.php @@ -72,6 +72,7 @@ class FindHooks extends Maintenance { $IP . '/includes/api/', $IP . '/includes/cache/', $IP . '/includes/changes/', + $IP . '/includes/changetags/', $IP . '/includes/clientpool/', $IP . '/includes/content/', $IP . '/includes/context/', @@ -80,6 +81,7 @@ class FindHooks extends Maintenance { $IP . '/includes/debug/', $IP . '/includes/deferred/', $IP . '/includes/diff/', + $IP . '/includes/exception/', $IP . '/includes/externalstore/', $IP . '/includes/filebackend/', $IP . '/includes/filerepo/', @@ -95,6 +97,7 @@ class FindHooks extends Maintenance { $IP . '/includes/media/', $IP . '/includes/page/', $IP . '/includes/parser/', + $IP . '/includes/password/', $IP . '/includes/rcfeed/', $IP . '/includes/resourceloader/', $IP . '/includes/revisiondelete/', @@ -119,9 +122,9 @@ class FindHooks extends Maintenance { } $potential = array_unique( $potential ); - $bad = array_unique( $bad ); - $todo = array_diff( $potential, $documented ); - $deprecated = array_diff( $documented, $potential ); + $bad = array_diff( array_unique( $bad ), self::$ignore ); + $todo = array_diff( $potential, $documented, self::$ignore ); + $deprecated = array_diff( $documented, $potential, self::$ignore ); // let's show the results: $this->printArray( 'Undocumented', $todo ); @@ -130,6 +133,8 @@ class FindHooks extends Maintenance { if ( count( $todo ) == 0 && count( $deprecated ) == 0 && count( $bad ) == 0 ) { $this->output( "Looks good!\n" ); + } else { + $this->error( 'The script finished with errors.', 1 ); } } @@ -287,9 +292,7 @@ class FindHooks extends Maintenance { } foreach ( $arr as $v ) { - if ( !in_array( $v, self::$ignore ) ) { - $this->output( "$msg: $v\n" ); - } + $this->output( "$msg: $v\n" ); } } } diff --git a/maintenance/fixDefaultJsonContentPages.php b/maintenance/fixDefaultJsonContentPages.php new file mode 100644 index 00000000..12658910 --- /dev/null +++ b/maintenance/fixDefaultJsonContentPages.php @@ -0,0 +1,128 @@ +<?php +/** + * Fix instances of pre-existing JSON pages + * + * 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'; + +/** + * Usage: + * fixDefaultJsonContentPages.php + * + * It is automatically run by update.php + */ +class FixDefaultJsonContentPages extends LoggedUpdateMaintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = + 'Fix instances of JSON pages prior to them being the ContentHandler default'; + $this->setBatchSize( 100 ); + } + + protected function getUpdateKey() { + return __CLASS__; + } + + protected function doDBUpdates() { + if ( !$this->getConfig()->get( 'ContentHandlerUseDB' ) ) { + $this->output( "\$wgContentHandlerUseDB is not enabled, nothing to do.\n" ); + return true; + } + + $dbr = wfGetDB( DB_SLAVE ); + $namespaces = array( + NS_MEDIAWIKI => $dbr->buildLike( $dbr->anyString(), '.json' ), + NS_USER => $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString(), '.json' ), + ); + foreach ( $namespaces as $ns => $like ) { + $lastPage = 0; + do { + $rows = $dbr->select( + 'page', + array( 'page_id', 'page_title', 'page_namespace', 'page_content_model' ), + array( + 'page_namespace' => $ns, + 'page_title ' . $like, + 'page_id > ' . $dbr->addQuotes( $lastPage ) + ), + __METHOD__, + array( 'ORDER BY' => 'page_id', 'LIMIT' => $this->mBatchSize ) + ); + foreach ( $rows as $row ) { + $this->handleRow( $row ); + } + } while ( $rows->numRows() >= $this->mBatchSize ); + } + + return true; + } + + protected function handleRow( stdClass $row ) { + $title = Title::makeTitle( $row->page_namespace, $row->page_title ); + $this->output( "Processing {$title} ({$row->page_id})...\n" ); + $rev = Revision::newFromTitle( $title ); + $content = $rev->getContent( Revision::RAW ); + $dbw = wfGetDB( DB_MASTER ); + if ( $content instanceof JsonContent ) { + if ( $content->isValid() ) { + // Yay, actually JSON. We need to just change the + // page_content_model because revision will automatically + // use the default, which is *now* JSON. + $this->output( "Setting page_content_model to json..." ); + $dbw->update( + 'page', + array( 'page_content_model' => CONTENT_MODEL_JSON ), + array( 'page_id' => $row->page_id ), + __METHOD__ + ); + $this->output( "done.\n" ); + wfWaitForSlaves(); + } else { + // Not JSON...force it to wikitext. We need to update the + // revision table so that these revisions are always processed + // as wikitext in the future. page_content_model is already + // set to "wikitext". + $this->output( "Setting rev_content_model to wikitext..." ); + // Grab all the ids for batching + $ids = $dbw->selectFieldValues( + 'revision', + 'rev_id', + array( 'rev_page' => $row->page_id ), + __METHOD__ + ); + foreach ( array_chunk( $ids, 50 ) as $chunk ) { + $dbw->update( + 'revision', + array( 'rev_content_model' => CONTENT_MODEL_WIKITEXT ), + array( 'rev_page' => $row->page_id, 'rev_id' => $chunk ) + ); + wfWaitForSlaves(); + } + $this->output( "done.\n" ); + } + } else { + $this->output( "not a JSON page? Skipping\n" ); + } + } +} + +$maintClass = 'FixDefaultJsonContentPages'; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/fixSlaveDesync.php b/maintenance/fixSlaveDesync.php deleted file mode 100644 index a5418ced..00000000 --- a/maintenance/fixSlaveDesync.php +++ /dev/null @@ -1,246 +0,0 @@ -<?php -/** - * Fix erroneous page_latest values due to slave desynchronisation. - * - * 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 fixes erroneous page_latest values - * due to slave desynchronisation. - * - * @ingroup Maintenance - */ -class FixSlaveDesync extends Maintenance { - /** @var array */ - private $slaveIndexes; - - public function __construct() { - parent::__construct(); - $this->mDescription = ""; - } - - public function getDbType() { - return Maintenance::DB_ADMIN; - } - - public function execute() { - $this->slaveIndexes = array(); - $serverCount = wfGetLB()->getServerCount(); - for ( $i = 1; $i < $serverCount; $i++ ) { - if ( wfGetLB()->isNonZeroLoad( $i ) ) { - $this->slaveIndexes[] = $i; - } - } - - if ( $this->hasArg() ) { - $this->desyncFixPage( $this->getArg() ); - } else { - $corrupt = $this->findPageLatestCorruption(); - foreach ( $corrupt as $id => $dummy ) { - $this->desyncFixPage( $id ); - } - } - } - - /** - * Find all pages that have a corrupted page_latest - * @return array - */ - private function findPageLatestCorruption() { - $desync = array(); - $n = 0; - $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: " . $res->numRows() . "\n" ); - foreach ( $res as $row ) { - $masterIDs[$row->page_id] = $row->page_latest; - if ( !( ++$n % 10000 ) ) { - $this->output( "$n\r" ); - } - } - $this->output( "\n" ); - - foreach ( $this->slaveIndexes as $i ) { - $db = wfGetDB( $i ); - $res = $db->select( - 'page', - array( 'page_id', 'page_latest' ), - array( 'page_id<6054123' ), - __METHOD__ - ); - foreach ( $res as $row ) { - if ( isset( $masterIDs[$row->page_id] ) && $masterIDs[$row->page_id] != $row->page_latest ) { - $desync[$row->page_id] = true; - $this->output( $row->page_id . "\t" ); - } - } - } - $this->output( "\n" ); - - return $desync; - } - - /** - * Fix a broken page entry - * @param int $pageID The page_id to fix - */ - private function desyncFixPage( $pageID ) { - # Check for a corrupted page_latest - $dbw = wfGetDB( DB_MASTER ); - $dbw->begin( __METHOD__ ); - $realLatest = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), - __METHOD__, 'FOR UPDATE' ); - # list( $masterFile, $masterPos ) = $dbw->getMasterPos(); - $found = false; - foreach ( $this->slaveIndexes as $i ) { - $db = wfGetDB( $i ); - /* - if ( !$db->masterPosWait( $masterFile, $masterPos, 10 ) ) { - $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__ ); - if ( $latest != $realLatest && $realLatest < $max ) { - $this->output( "page_latest corrupted in page $pageID, server $i\n" ); - $found = true; - break; - } - } - if ( !$found ) { - $this->output( "page_id $pageID seems fine\n" ); - $dbw->commit( __METHOD__ ); - - return; - } - - # Find the missing revisions - $res = $dbw->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), - __METHOD__, 'FOR UPDATE' ); - $masterIDs = array(); - foreach ( $res as $row ) { - $masterIDs[] = $row->rev_id; - } - - $res = $dbw->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), __METHOD__ ); - $slaveIDs = array(); - foreach ( $res as $row ) { - $slaveIDs[] = $row->rev_id; - } - if ( count( $masterIDs ) < count( $slaveIDs ) ) { - $missingIDs = array_diff( $slaveIDs, $masterIDs ); - if ( count( $missingIDs ) ) { - $this->output( "Found " . count( $missingIDs ) - . " lost in master, copying from slave... " ); - $dbFrom = $dbw; - $found = true; - $toMaster = true; - } else { - $found = false; - } - } else { - $missingIDs = array_diff( $masterIDs, $slaveIDs ); - if ( count( $missingIDs ) ) { - $this->output( "Found " . count( $missingIDs ) - . " missing revision(s), copying from master... " ); - $dbFrom = $dbw; - $found = true; - $toMaster = false; - } else { - $found = false; - } - } - - if ( $found ) { - foreach ( $missingIDs as $rid ) { - $this->output( "$rid " ); - # Revision - $row = $dbFrom->selectRow( 'revision', '*', array( 'rev_id' => $rid ), __METHOD__ ); - if ( $toMaster ) { - $id = $dbw->selectField( 'revision', 'rev_id', array( 'rev_id' => $rid ), - __METHOD__, 'FOR UPDATE' ); - if ( $id ) { - $this->output( "Revision already exists\n" ); - $found = false; - break; - } else { - $dbw->insert( 'revision', get_object_vars( $row ), __METHOD__, 'IGNORE' ); - } - } else { - foreach ( $this->slaveIndexes as $i ) { - $db = wfGetDB( $i ); - $db->insert( 'revision', get_object_vars( $row ), __METHOD__, 'IGNORE' ); - } - } - - # Text - $row = $dbFrom->selectRow( 'text', '*', array( 'old_id' => $row->rev_text_id ), __METHOD__ ); - if ( $toMaster ) { - $dbw->insert( 'text', get_object_vars( $row ), __METHOD__, 'IGNORE' ); - } else { - foreach ( $this->slaveIndexes as $i ) { - $db = wfGetDB( $i ); - $db->insert( 'text', get_object_vars( $row ), __METHOD__, 'IGNORE' ); - } - } - } - $this->output( "done\n" ); - } - - if ( $found ) { - $this->output( "Fixing page_latest... " ); - if ( $toMaster ) { - /* - $dbw->update( - 'page', - array( 'page_latest' => $realLatest ), - array( 'page_id' => $pageID ), - __METHOD__ - ); - */ - } else { - foreach ( $this->slaveIndexes as $i ) { - $db = wfGetDB( $i ); - $db->update( - 'page', - array( 'page_latest' => $realLatest ), - array( 'page_id' => $pageID ), - __METHOD__ - ); - } - } - $this->output( "done\n" ); - } - $dbw->commit( __METHOD__ ); - } -} - -$maintClass = "FixSlaveDesync"; -require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/generateJsonI18n.php b/maintenance/generateJsonI18n.php index 22d99405..b9c07fbe 100644 --- a/maintenance/generateJsonI18n.php +++ b/maintenance/generateJsonI18n.php @@ -39,11 +39,8 @@ class GenerateJsonI18n extends Maintenance { $this->addArg( 'phpfile', 'PHP file defining a $messages array', false ); $this->addArg( 'jsondir', 'Directory to write JSON files to', false ); - $this->addOption( 'langcode', 'Language code; only needed for converting core i18n files', - false, true ); $this->addOption( 'extension', 'Perform default conversion on an extension', false, true ); - $this->addOption( 'shim-only', 'Only create or update the backward-compatibility shim' ); $this->addOption( 'supplementary', 'Find supplementary i18n files in subdirs and convert those', false, false ); } @@ -58,13 +55,13 @@ class GenerateJsonI18n extends Maintenance { if ( $extension ) { if ( $phpfile ) { - $this->error( "The phpfile is already specified, conflicts with --extension.\n", 1 ); + $this->error( "The phpfile is already specified, conflicts with --extension.", 1 ); } $phpfile = "$IP/extensions/$extension/$extension.i18n.php"; } if ( !$phpfile ) { - $this->error( "I'm here for an argument!\n" ); + $this->error( "I'm here for an argument!" ); $this->maybeHelp( true ); // dies. } @@ -104,47 +101,32 @@ class GenerateJsonI18n extends Maintenance { $this->output( "Creating directory $jsondir.\n" ); $success = mkdir( $jsondir ); if ( !$success ) { - $this->error( "Could not create directory $jsondir\n", 1 ); + $this->error( "Could not create directory $jsondir", 1 ); } } - if ( $this->hasOption( 'shim-only' ) ) { - $this->shimOnly( $phpfile, $jsondir ); - - return; - } - - if ( $jsondir === null ) { - $this->error( 'Argument [jsondir] is required unless --shim-only is specified.' ); - $this->maybeHelp( true ); - } - if ( !is_readable( $phpfile ) ) { - $this->error( "Error reading $phpfile\n", 1 ); + $this->error( "Error reading $phpfile", 1 ); } include $phpfile; $phpfileContents = file_get_contents( $phpfile ); if ( !isset( $messages ) ) { - $this->error( "PHP file $phpfile does not define \$messages array\n", 1 ); + $this->error( "PHP file $phpfile does not define \$messages array", 1 ); + } + + if ( !$messages ) { + $this->error( "PHP file $phpfile contains an empty \$messages array. " . + "Maybe it was already converted?", 1 ); } - $extensionStyle = true; if ( !isset( $messages['en'] ) || !is_array( $messages['en'] ) ) { - if ( !$this->hasOption( 'langcode' ) ) { - $this->error( "PHP file $phpfile does not set language codes, --langcode " . - "is required.\n", 1 ); - } - $extensionStyle = false; - $langcode = $this->getOption( 'langcode' ); - $messages = array( $langcode => $messages ); - } elseif ( $this->hasOption( 'langcode' ) ) { - $this->output( "Warning: --langcode option set but will not be used.\n" ); + $this->error( "PHP file $phpfile does not set language codes", 1 ); } foreach ( $messages as $langcode => $langmsgs ) { $authors = $this->getAuthorsFromComment( $this->findCommentBefore( - $extensionStyle ? "\$messages['$langcode'] =" : '$messages =', + "\$messages['$langcode'] =", $phpfileContents ) ); // Make sure the @metadata key is the first key in the output @@ -164,89 +146,15 @@ class GenerateJsonI18n extends Maintenance { $this->output( "$jsonfile\n" ); } - if ( !$this->hasOption( 'langcode' ) ) { - $shim = $this->doShim( $jsondir ); - file_put_contents( $phpfile, $shim ); - } - - $this->output( "All done.\n" ); - $this->output( "Also add \$wgMessagesDirs['YourExtension'] = __DIR__ . '/i18n';\n" ); - } - - protected function shimOnly( $phpfile, $jsondir ) { - if ( file_exists( $phpfile ) ) { - if ( !is_readable( $phpfile ) ) { - $this->error( "Error reading $phpfile\n", 1 ); - } - - $phpfileContents = file_get_contents( $phpfile ); - $m = array(); - if ( !preg_match( '!"/([^"$]+)/\$csCode.json";!', $phpfileContents, $m ) ) { - $this->error( "Cannot recognize $phpfile as a shim.\n", 1 ); - } - - if ( $jsondir === null ) { - $jsondir = $m[1]; - } - - $this->output( "Updating existing shim $phpfile\n" ); - } elseif ( $jsondir === null ) { - $this->error( "$phpfile does not exist.\n" . - "Argument [jsondir] is required in order to create a new shim.\n", 1 ); - } else { - $this->output( "Creating new shim $phpfile\n" ); - } - - $shim = $this->doShim( $jsondir ); - file_put_contents( $phpfile, $shim ); - $this->output( "All done.\n" ); - } - - protected function doShim( $jsondir ) { - $shim = <<<'PHP' -<?php -/** - * This is a backwards-compatibility shim, generated by: - * https://git.wikimedia.org/blob/mediawiki%2Fcore.git/HEAD/maintenance%2FgenerateJsonI18n.php - * - * Beginning with MediaWiki 1.23, translation strings are stored in json files, - * and the EXTENSION.i18n.php file only exists to provide compatibility with - * older releases of MediaWiki. For more information about this migration, see: - * https://www.mediawiki.org/wiki/Requests_for_comment/Localisation_format - * - * This shim maintains compatibility back to MediaWiki 1.17. - */ -$messages = array(); -if ( !function_exists( '{{FUNC}}' ) ) { - function {{FUNC}}( $cache, $code, &$cachedData ) { - $codeSequence = array_merge( array( $code ), $cachedData['fallbackSequence'] ); - foreach ( $codeSequence as $csCode ) { - $fileName = dirname( __FILE__ ) . "/{{OUT}}/$csCode.json"; - if ( is_readable( $fileName ) ) { - $data = FormatJson::decode( file_get_contents( $fileName ), true ); - foreach ( array_keys( $data ) as $key ) { - if ( $key === '' || $key[0] === '@' ) { - unset( $data[$key] ); - } - } - $cachedData['messages'] = array_merge( $data, $cachedData['messages'] ); - } - - $cachedData['deps'][] = new FileDependency( $fileName ); - } - return true; - } - - $GLOBALS['wgHooks']['LocalisationCacheRecache'][] = '{{FUNC}}'; -} - -PHP; - - $jsondir = str_replace( '\\', '/', $jsondir ); - $shim = str_replace( '{{OUT}}', $jsondir, $shim ); - $shim = str_replace( '{{FUNC}}', 'wfJsonI18nShim' . wfRandomString( 16 ), $shim ); - - return $shim; + $this->output( + "All done. To complete the conversion, please do the following:\n" . + "* Add \$wgMessagesDirs['YourExtension'] = __DIR__ . '/i18n';\n" . + "* Remove \$wgExtensionMessagesFiles['YourExtension']\n" . + "* Delete the old PHP message file\n" . + "This script no longer generates backward compatibility shims! If you need\n" . + "compatibility with MediaWiki 1.22 and older, use the MediaWiki 1.23 version\n" . + "of this script instead, or create a shim manually.\n" + ); } /** diff --git a/maintenance/getConfiguration.php b/maintenance/getConfiguration.php index d5f68346..58382014 100644 --- a/maintenance/getConfiguration.php +++ b/maintenance/getConfiguration.php @@ -184,7 +184,7 @@ class GetConfiguration extends Maintenance { } return true; - } elseif ( is_scalar( $value ) ) { + } elseif ( is_scalar( $value ) || $value === null ) { return true; } diff --git a/maintenance/importImages.php b/maintenance/importImages.php index ae70441f..ad385e57 100644 --- a/maintenance/importImages.php +++ b/maintenance/importImages.php @@ -88,23 +88,23 @@ if ( isset( $options['check-userblock'] ) ) { } # Get --from -wfSuppressWarnings(); +MediaWiki\suppressWarnings(); $from = $options['from']; -wfRestoreWarnings(); +MediaWiki\restoreWarnings(); # Get sleep time. -wfSuppressWarnings(); +MediaWiki\suppressWarnings(); $sleep = $options['sleep']; -wfRestoreWarnings(); +MediaWiki\restoreWarnings(); if ( $sleep ) { $sleep = (int)$sleep; } # Get limit number -wfSuppressWarnings(); +MediaWiki\suppressWarnings(); $limit = $options['limit']; -wfRestoreWarnings(); +MediaWiki\restoreWarnings(); if ( $limit ) { $limit = (int)$limit; diff --git a/maintenance/importSites.php b/maintenance/importSites.php index 7abb8d72..7cd20008 100644 --- a/maintenance/importSites.php +++ b/maintenance/importSites.php @@ -17,7 +17,9 @@ class ImportSites extends Maintenance { public function __construct() { $this->mDescription = 'Imports site definitions from XML into the sites table.'; - $this->addArg( 'file', 'An XML file containing site definitions (see docs/sitelist.txt). Use "php://stdin" to read from stdin.', true ); + $this->addArg( 'file', 'An XML file containing site definitions (see docs/sitelist.txt). ' . + 'Use "php://stdin" to read from stdin.', true + ); parent::__construct(); } @@ -49,4 +51,4 @@ class ImportSites extends Maintenance { } $maintClass = 'ImportSites'; -require_once( RUN_MAINTENANCE_IF_MAIN ); +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/install.php b/maintenance/install.php index b948b674..0037ea80 100644 --- a/maintenance/install.php +++ b/maintenance/install.php @@ -104,9 +104,9 @@ class CommandLineInstaller extends Maintenance { $this->error( 'WARNING: You have provided the options "dbpass" and "dbpassfile". ' . 'The content of "dbpassfile" overrides "dbpass".' ); } - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); $dbpass = file_get_contents( $dbpassfile ); // returns false on failure - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); if ( $dbpass === false ) { $this->error( "Couldn't open $dbpassfile", true ); } @@ -119,9 +119,9 @@ class CommandLineInstaller extends Maintenance { $this->error( 'WARNING: You have provided the options "pass" and "passfile". ' . 'The content of "passfile" overrides "pass".' ); } - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); $pass = file_get_contents( $passfile ); // returns false on failure - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); if ( $pass === false ) { $this->error( "Couldn't open $passfile", true ); } diff --git a/maintenance/interwiki.list b/maintenance/interwiki.list index 91c60c1c..48991434 100644 --- a/maintenance/interwiki.list +++ b/maintenance/interwiki.list @@ -46,7 +46,6 @@ s23wiki|http://s23.org/wiki/$1|0|http://s23.org/w/api.php seattlewireless|http://seattlewireless.net/$1|0| senseislibrary|http://senseis.xmp.net/?$1|0| shoutwiki|http://www.shoutwiki.com/wiki/$1|0|http://www.shoutwiki.com/w/api.php -sourceforge|http://sourceforge.net/$1|0| sourcewatch|http://www.sourcewatch.org/index.php?title=$1|0|http://www.sourcewatch.org/api.php squeak|http://wiki.squeak.org/squeak/$1|0| tejo|http://www.tejo.org/vikio/$1|0| diff --git a/maintenance/interwiki.sql b/maintenance/interwiki.sql index 0628773e..12352e7c 100644 --- a/maintenance/interwiki.sql +++ b/maintenance/interwiki.sql @@ -48,7 +48,6 @@ REPLACE INTO /*$wgDBprefix*/interwiki (iw_prefix,iw_url,iw_local,iw_api) VALUES ('seattlewireless','http://seattlewireless.net/$1',0,''), ('senseislibrary','http://senseis.xmp.net/?$1',0,''), ('shoutwiki','http://www.shoutwiki.com/wiki/$1',0,'http://www.shoutwiki.com/w/api.php'), -('sourceforge','http://sourceforge.net/$1',0,''), ('sourcewatch','http://www.sourcewatch.org/index.php?title=$1',0,'http://www.sourcewatch.org/api.php'), ('squeak','http://wiki.squeak.org/squeak/$1',0,''), ('tejo','http://www.tejo.org/vikio/$1',0,''), diff --git a/maintenance/jsduck/categories.json b/maintenance/jsduck/categories.json index eab2b632..ef264c32 100644 --- a/maintenance/jsduck/categories.json +++ b/maintenance/jsduck/categories.json @@ -23,13 +23,16 @@ "classes": [ "mw.Title", "mw.Uri", + "mw.RegExp", "mw.messagePoster.*", "mw.notification", "mw.Notification_", + "mw.storage", "mw.user", "mw.util", "mw.plugin.*", - "mw.cookie" + "mw.cookie", + "mw.experiments" ] }, { @@ -38,7 +41,7 @@ }, { "name": "API", - "classes": ["mw.Api*"] + "classes": ["mw.Api*", "mw.ForeignApi*"] }, { "name": "Language", @@ -57,8 +60,16 @@ { "name": "Interfaces", "classes": [ - "mw.Feedback", - "mw.Feedback.Dialog" + "mw.Feedback*", + "mw.Upload*", + "mw.ForeignUpload", + "mw.ForeignStructuredUpload*" + ] + }, + { + "name": "Widgets", + "classes": [ + "mw.widgets*" ] }, { diff --git a/maintenance/jsduck/custom_tags.rb b/maintenance/jsduck/custom_tags.rb index 39589a06..cc8069d4 100644 --- a/maintenance/jsduck/custom_tags.rb +++ b/maintenance/jsduck/custom_tags.rb @@ -66,7 +66,7 @@ class SeeTag < CommonTag <<-EOHTML <h3 class="pa">Related</h3> <ul> - #{ context[@tagname].map { |tag| tag[:doc] }.join("\n") } + #{context[@tagname].map { |tag| tag[:doc] }.join("\n")} </ul> EOHTML end @@ -102,7 +102,7 @@ class ContextTag < CommonTag def to_html(context) <<-EOHTML <h3 class="pa">Context</h3> - #{ context[@tagname].last[:doc] } + #{context[@tagname].last[:doc]} EOHTML end diff --git a/maintenance/jsduck/eg-iframe.html b/maintenance/jsduck/eg-iframe.html index fca839d9..2c42364a 100644 --- a/maintenance/jsduck/eg-iframe.html +++ b/maintenance/jsduck/eg-iframe.html @@ -33,13 +33,13 @@ log( error + '\n' + filePath + ':' + linerNr ); }; </script> - <script src="modules/src/startup.js"></script> <script> function startUp() { mw.config = new mw.Map(); } </script> <script src="modules/lib/jquery/jquery.js"></script> + <script src="modules/lib/phpjs-sha1/sha1.js"></script> <script src="modules/src/mediawiki/mediawiki.js"></script> <script src="modules/src/mediawiki/mediawiki.errorLogger.js"></script> <script src="modules/src/mediawiki/mediawiki.startUp.js"></script> diff --git a/maintenance/jsduck/external.js b/maintenance/jsduck/external.js index 4bb83694..c9012407 100644 --- a/maintenance/jsduck/external.js +++ b/maintenance/jsduck/external.js @@ -37,7 +37,6 @@ * @alternateClassName jqXHR */ - /** * @class QUnit * @source <http://api.qunitjs.com/> diff --git a/maintenance/jsparse.php b/maintenance/jsparse.php index 3f0a9ba7..fddfc024 100644 --- a/maintenance/jsparse.php +++ b/maintenance/jsparse.php @@ -47,9 +47,9 @@ class JSParseHelper extends Maintenance { $parser = new JSParser(); foreach ( $files as $filename ) { - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); $js = file_get_contents( $filename ); - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); if ( $js === false ) { $this->output( "$filename ERROR: could not read file\n" ); $this->errs++; diff --git a/maintenance/language/StatOutputs.php b/maintenance/language/StatOutputs.php index 257fe146..534a8b48 100644 --- a/maintenance/language/StatOutputs.php +++ b/maintenance/language/StatOutputs.php @@ -26,9 +26,9 @@ /** A general output object. Need to be overridden */ class StatsOutput { function formatPercent( $subset, $total, $revert = false, $accuracy = 2 ) { - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); $return = sprintf( '%.' . $accuracy . 'f%%', 100 * $subset / $total ); - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); return $return; } @@ -92,9 +92,9 @@ class WikiStatsOutput extends StatsOutput { } function formatPercent( $subset, $total, $revert = false, $accuracy = 2 ) { - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); $v = round( 255 * $subset / $total ); - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); if ( $revert ) { # Weigh reverse with factor 20 so coloring takes effect more quickly as diff --git a/maintenance/language/checkLanguage.inc b/maintenance/language/checkLanguage.inc index 990f2585..0c3ea671 100644 --- a/maintenance/language/checkLanguage.inc +++ b/maintenance/language/checkLanguage.inc @@ -339,7 +339,7 @@ ENDS; $blacklist = $checkBlacklist; - wfRunHooks( 'LocalisationChecksBlacklist', array( &$blacklist ) ); + Hooks::run( 'LocalisationChecksBlacklist', array( &$blacklist ) ); return $blacklist; } diff --git a/maintenance/language/generateNormalizerDataAr.php b/maintenance/language/generateNormalizerDataAr.php index ac50d291..52ed81fb 100644 --- a/maintenance/language/generateNormalizerDataAr.php +++ b/maintenance/language/generateNormalizerDataAr.php @@ -25,7 +25,8 @@ require_once __DIR__ . '/../Maintenance.php'; /** * Generates the normalizer data file for Arabic. - * For NFC see includes/libs/normal. + * + * This data file is used after normalizing to NFC. * * @ingroup MaintenanceLanguage */ diff --git a/maintenance/language/generateNormalizerDataMl.php b/maintenance/language/generateNormalizerDataMl.php index 8580187d..cb6ae698 100644 --- a/maintenance/language/generateNormalizerDataMl.php +++ b/maintenance/language/generateNormalizerDataMl.php @@ -25,7 +25,8 @@ require_once __DIR__ . '/../Maintenance.php'; /** * Generates the normalizer data file for Malayalam. - * For NFC see includes/libs/normal. + * + * This data file is used after normalizing to NFC. * * @ingroup MaintenanceLanguage */ diff --git a/maintenance/language/languages.inc b/maintenance/language/languages.inc index fb496cbc..9affb9e6 100644 --- a/maintenance/language/languages.inc +++ b/maintenance/language/languages.inc @@ -63,7 +63,7 @@ class Languages { * files in the languages directory. */ function __construct() { - wfRunHooks( 'LocalisationIgnoredOptionalMessages', + Hooks::run( 'LocalisationIgnoredOptionalMessages', array( &$this->mIgnoredMessages, &$this->mOptionalMessages ) ); $this->mLanguages = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) ); diff --git a/maintenance/language/zhtable/Makefile.py b/maintenance/language/zhtable/Makefile.py index 71641ef1..4ab57d40 100644 --- a/maintenance/language/zhtable/Makefile.py +++ b/maintenance/language/zhtable/Makefile.py @@ -203,13 +203,16 @@ def customRules( path ): fp = open( path, 'r', encoding = 'U8' ) ret = dict() for line in fp: - elems = line.split( '#' )[0].split() + line = line.rstrip( '\r\n' ) + if '#' in line: + line = line.split( '#' )[0].rstrip() + elems = line.split( '\t' ) 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] ) + return sorted( src_table.items(), key = lambda m: ( m[pos], m[1 - pos] ) ) def translate( text, conv_table ): i = 0 @@ -229,7 +232,7 @@ def manualWordsTable( path, conv_table, reconv_table ): reconv_table = {} wordlist = [line.split( '#' )[0].strip() for line in fp] wordlist = list( set( wordlist ) ) - wordlist.sort( key = len, reverse = True ) + wordlist.sort( key = lambda w: ( len(w), w ), reverse = True ) while wordlist: word = wordlist.pop() new_word = translate( word, conv_table ) @@ -241,7 +244,7 @@ def manualWordsTable( path, conv_table, reconv_table ): def defaultWordsTable( src_wordlist, src_tomany, char_conv_table, char_reconv_table ): wordlist = list( src_wordlist ) - wordlist.sort( key = len, reverse = True ) + wordlist.sort( key = lambda w: ( len(w), w ), reverse = True ) word_conv_table = {} word_reconv_table = {} conv_table = char_conv_table.copy() @@ -276,7 +279,7 @@ def PHPArray( table ): def main(): #Get Unihan.zip: url = 'http://www.unicode.org/Public/%s/ucd/Unihan.zip' % UNIHAN_VER - han_dest = 'Unihan.zip' + han_dest = 'Unihan-%s.zip' % UNIHAN_VER download( url, han_dest ) # Get scim-tables-$(SCIM_TABLES_VER).tar.gz: diff --git a/maintenance/language/zhtable/simp2trad.manual b/maintenance/language/zhtable/simp2trad.manual index da75c446..5518a88d 100644 --- a/maintenance/language/zhtable/simp2trad.manual +++ b/maintenance/language/zhtable/simp2trad.manual @@ -59,7 +59,7 @@ U+05446呆|U+05446呆|U+07343獃| U+054B8咸|U+054B8咸|U+09E79鹹| U+054C4哄|U+054C4哄|U+09B28鬨| U+0556E啮|U+09F67齧|U+056D3囓|U+05699嚙| -U+05582喂|U+05582喂|U+09935餵| +U+05582喂|U+09935餵|U+05582喂| U+056DE回|U+056DE回|U+08FF4迴| U+056E2团|U+05718團|U+07CF0糰| U+056F0困|U+056F0困|U+0774F睏| @@ -168,6 +168,7 @@ U+080DC胜|U+052DD勝|U+080DC胜| U+080E1胡|U+080E1胡|U+09B0D鬍|U+0885A衚| U+0810F脏|U+09AD2髒|U+081DF臟| U+0814A腊|U+081D8臘|U+0814A腊| +U+0814C腌|U+09183醃| U+081F4致|U+081F4致|U+07DFB緻| U+0820D舍|U+0820D舍|U+06368捨| U+082B8芸|U+082B8芸|U+08553蕓| @@ -230,4 +231,4 @@ U+09CC4鳄|U+09C77鱷|U+09C10鰐| U+09E21鸡|U+096DE雞|U+09DC4鷄| U+09E5A鹚|U+09DBF鶿|U+09DC0鷀| U+09EB9麹|U+09EB4麴| -U+080C4胄|U+080C4胄|U+05191冑|
\ No newline at end of file +U+080C4胄|U+080C4胄|U+05191冑| diff --git a/maintenance/language/zhtable/simp2trad_noconvert.manual b/maintenance/language/zhtable/simp2trad_noconvert.manual index 3266168d..d9326f28 100644 --- a/maintenance/language/zhtable/simp2trad_noconvert.manual +++ b/maintenance/language/zhtable/simp2trad_noconvert.manual @@ -7,4 +7,9 @@ 桿 錶 蘋 -詑
\ No newline at end of file +詑 +堖 +嶴 +灡 +薳 +虯 diff --git a/maintenance/language/zhtable/simpphrases.manual b/maintenance/language/zhtable/simpphrases.manual index 3b149823..3477c0a9 100644 --- a/maintenance/language/zhtable/simpphrases.manual +++ b/maintenance/language/zhtable/simpphrases.manual @@ -38,7 +38,6 @@ 乾岗 乾巛 乾州 -乾式 乾录 乾律 乾德 @@ -146,6 +145,7 @@ 字乾生 乾神 乾西 +乾东 象乾 陈遇乾 曾运乾 @@ -153,6 +153,9 @@ 孙乾 乾潭 乾贵士 +承乾 +乾生元 +蔡孝乾 於乎 於戏 魏徵 @@ -161,7 +164,6 @@ 於氏 於夫罗 於梨华 -卷舌 樊於期 於菟 於潜县 @@ -176,7 +178,7 @@ 於哲 於除鞬 於志贺 -覆蓋 +覆盖 五箇山 麽麽 幺厮 @@ -227,11 +229,12 @@ 石碁 碁圣 暗闇 +闇公 +山崎闇斋 繙㠾 惏慄 惏悷 目劄 -橡椀 谢肇淛 朱淛 諲譔 @@ -264,6 +267,21 @@ 庆馀 馀庆 子馀 -郭行馀 +行馀 王馀鱼 -馀年无多
\ No newline at end of file +傒倖 +倖田 +倖一郎 +兒宽 +穀旦 +不穀 +穀水 +穀阳 +岳讬 +硕讬 +讬庸 +讬恩多 +博和讬 +讬麻 +饱讬 +蔡絛 diff --git a/maintenance/language/zhtable/simpphrases_exclude.manual b/maintenance/language/zhtable/simpphrases_exclude.manual index b4dd3e01..7985a89a 100644 --- a/maintenance/language/zhtable/simpphrases_exclude.manual +++ b/maintenance/language/zhtable/simpphrases_exclude.manual @@ -26,5 +26,6 @@ 硷淡 悽恻 鲇鱼 -和尚撞一天钟 -余
\ No newline at end of file +钟 +余 +老么 diff --git a/maintenance/language/zhtable/symme_supp.manual b/maintenance/language/zhtable/symme_supp.manual index 09e14155..7470a381 100644 --- a/maintenance/language/zhtable/symme_supp.manual +++ b/maintenance/language/zhtable/symme_supp.manual @@ -18,10 +18,10 @@ U+08600蘀|U+0841A萚| U+08AE1諡|U+08C25谥| U+09746靆|U+053C7叇| U+09749靉|U+053C6叆| -U+09A44驄|U+29A02𩨂| +U+09A44驄|U+09AA2骢| U+09C1B鰛|U+09CC1鳁| U+09EB3麳|U+2A38C𪎌| U+295E1𩗡|U+29667𩙧| U+298F5𩣵|U+299FB𩧻| U+29F47𩽇|U+29F8E𩾎| -U+2A23C𪈼|U+2A253𪉓|
\ No newline at end of file +U+2A23C𪈼|U+2A253𪉓| diff --git a/maintenance/language/zhtable/toCN.manual b/maintenance/language/zhtable/toCN.manual index a678ac93..3a00bd45 100644 --- a/maintenance/language/zhtable/toCN.manual +++ b/maintenance/language/zhtable/toCN.manual @@ -20,6 +20,7 @@ 胺基酸 氨基酸 水氣 水汽 計畫 计划 +規畫 规划 天份 天分 名份 名分 職份 职分 @@ -31,7 +32,7 @@ 投機份子 投机分子 一份子 一分子 水份 水分 -氧份 养分 +氧份 氧分 糖份 糖分 鹽份 盐分 組份 组分 @@ -57,7 +58,10 @@ 堂姊 堂姐 學姊 学姐 乾姊 干姐 +清澈 清澈 #分詞用 澈底 彻底 +仲介 中介 +卯足 铆足 逕庭 径庭 逕到 径到 逕取 径取 @@ -130,7 +134,6 @@ 帳外 账外 帳務 账务 螢光棒 荧光棒 -辭彙 词汇 著業 着业 著絲 着丝 著麼 着么 @@ -285,6 +288,7 @@ 乘著名 乘著名 乘著錄 乘著录 乘著稱 乘著称 +乘著称 乘著称 乘著者 乘著者 乘著述 乘著述 爭著 争着 @@ -301,6 +305,7 @@ 亮著名 亮著名 亮著錄 亮著录 亮著稱 亮著称 +亮著称 亮著称 亮著者 亮著者 亮著述 亮著述 仗著 仗着 @@ -333,6 +338,7 @@ 低著名 低著名 低著錄 低著录 低著稱 低著称 +低著称 低著称 低著者 低著者 低著述 低著述 住著 住着 @@ -341,6 +347,7 @@ 住著名 住著名 住著錄 住著录 住著稱 住著称 +住著称 住著称 住著者 住著者 住著述 住著述 側著 侧着 @@ -357,6 +364,7 @@ 保障著名 保障著名 保障著錄 保障著录 保障著稱 保障著称 +保障著称 保障著称 保障著者 保障著者 保障著述 保障著述 信著 信着 @@ -365,6 +373,7 @@ 信著名 信著名 信著錄 信著录 信著稱 信著称 +信著称 信著称 信著者 信著者 信著述 信著述 候著 候着 @@ -405,6 +414,7 @@ 光著名 光著名 光著錄 光著录 光著稱 光著称 +光著称 光著称 光著者 光著者 光著述 光著述 關著 关着 @@ -415,14 +425,7 @@ 關著稱 关著称 關著者 关著者 關著述 关著述 -冀著 冀着 -冀著書 冀著书 -冀著作 冀著作 -冀著名 冀著名 -冀著錄 冀著录 -冀著稱 冀著称 -冀著者 冀著者 -冀著述 冀著述 +希冀著 希冀着 冒著 冒着 冒著書 冒著书 冒著作 冒著作 @@ -461,6 +464,7 @@ 刻著名 刻著名 刻著錄 刻著录 刻著稱 刻著称 +刻著称 刻著称 刻著者 刻著者 刻著述 刻著述 辦著 办着 @@ -485,16 +489,9 @@ 努力著名 努力著名 努力著錄 努力著录 努力著稱 努力著称 +努力著称 努力著称 努力著者 努力著者 努力著述 努力著述 -努著 努着 -努著書 努著书 -努著作 努著作 -努著名 努著名 -努著錄 努著录 -努著稱 努著称 -努著者 努著者 -努著述 努著述 印著 印着 印著書 印著书 印著作 印著作 @@ -511,14 +508,6 @@ 壓著稱 压著称 壓著者 压著者 壓著述 压著述 -去著 去着 -去著書 去著书 -去著作 去著作 -去著名 去著名 -去著錄 去著录 -去著稱 去著称 -去著者 去著者 -去著述 去著述 受著 受着 受著書 受著书 受著作 受著作 @@ -581,6 +570,7 @@ 味著名 味著名 味著錄 味著录 味著稱 味著称 +味著称 味著称 味著者 味著者 味著述 味著述 響著 响着 @@ -650,14 +640,7 @@ 圍著稱 围著称 圍著者 围著者 圍著述 围著述 -在著 在着 -在著書 在著书 -在著作 在著作 -在著名 在著名 -在著錄 在著录 -在著稱 在著称 -在著者 在著者 -在著述 在著述 +存在著 存在着 坐著 坐着 坐著書 坐著书 坐著作 坐著作 @@ -682,14 +665,6 @@ 夾著稱 夹著称 夾著者 夹著者 夾著述 夹著述 -孤著 孤着 -孤著書 孤著书 -孤著作 孤著作 -孤著名 孤著名 -孤著錄 孤著录 -孤著稱 孤著称 -孤著者 孤著者 -孤著述 孤著述 學著 学着 學著書 学著书 學著作 学著作 @@ -704,6 +679,7 @@ 守著名 守著名 守著錄 守著录 守著稱 守著称 +守著称 守著称 守著者 守著者 守著述 守著述 定著 定着 @@ -712,6 +688,7 @@ 定著名 定著名 定著錄 定著录 定著稱 定著称 +定著称 定著称 定著者 定著者 定著述 定著述 對著 对着 @@ -762,14 +739,6 @@ 應著稱 应著称 應著者 应著者 應著述 应著述 -康著 康着 -康著書 康著书 -康著作 康著作 -康著名 康著名 -康著錄 康著录 -康著稱 康著称 -康著者 康著者 -康著述 康著述 開著 开着 開著書 开著书 開著作 开著作 @@ -816,6 +785,7 @@ 心著名 心著名 心著錄 心著录 心著稱 心著称 +心著称 心著称 心著者 心著者 心著述 心著述 忍著 忍着 @@ -826,14 +796,7 @@ 忍著稱 忍著称 忍著者 忍著者 忍著述 忍著述 -志著 志着 -志著書 志著书 -志著作 志著作 -志著名 志著名 -志著錄 志著录 -志著稱 志著称 -志著者 志著者 -志著述 志著述 +標志著 标志着 忙著 忙着 忙著書 忙著书 忙著作 忙著作 @@ -858,14 +821,6 @@ 急著稱 急著称 急著者 急著者 急著述 急著述 -性著 性着 -性著書 性著书 -性著作 性著作 -性著名 性著名 -性著錄 性著录 -性著稱 性著称 -性著者 性著者 -性著述 性著述 戀著 恋着 戀著書 恋著书 戀著作 恋著作 @@ -896,6 +851,7 @@ 想著名 想著名 想著錄 想著录 想著稱 想著称 +想著称 想著称 想著者 想著者 想著述 想著述 戰著 战着 @@ -1305,14 +1261,7 @@ 潤著稱 润著称 潤著者 润著者 潤著述 润著述 -涵著 涵着 -涵著書 涵著书 -涵著作 涵著作 -涵著名 涵著名 -涵著錄 涵著录 -涵著稱 涵著称 -涵著者 涵著者 -涵著述 涵著述 +蘊涵著 蕴涵着 渴著 渴着 渴著書 渴著书 渴著作 渴著作 @@ -1383,14 +1332,6 @@ 牽著稱 牵著称 牽著者 牵著者 牽著述 牵著述 -獨著 独着 -獨著書 独著书 -獨著作 独著作 -獨著名 独著名 -獨著錄 独著录 -獨著稱 独著称 -獨著者 独著者 -獨著述 独著述 猜著 猜着 猜著書 猜着书 猜著作 猜著作 @@ -1455,14 +1396,7 @@ 盯著稱 盯著称 盯著者 盯著者 盯著述 盯著述 -盾著 盾着 -盾著書 盾著书 -盾著作 盾著作 -盾著名 盾著名 -盾著錄 盾著录 -盾著稱 盾著称 -盾著者 盾著者 -盾著述 盾著述 +矛盾著 矛盾着 看著 看着 看著書 看着书 看著作 看著作 @@ -1481,6 +1415,7 @@ 瞧著述 瞧著述 存著 存着 存著名 存著名 +存著作 存著作 劃著 划着 別著 别着 刮著 刮着 @@ -1653,6 +1588,7 @@ 美著名 美著名 美著錄 美著录 美著稱 美著称 +美著称 美著称 美著者 美著者 美著述 美著述 耀著 耀着 @@ -1687,14 +1623,6 @@ 膠著稱 胶著称 膠著者 胶著者 膠著述 胶著述 -藝著 艺着 -藝著書 艺著书 -藝著作 艺著作 -藝著名 艺著名 -藝著錄 艺著录 -藝著稱 艺著称 -藝著者 艺著者 -藝著述 艺著述 苦著 苦着 苦著書 苦著书 苦著作 苦著作 @@ -1756,6 +1684,7 @@ 衣著名 衣著名 衣著錄 衣著录 衣著稱 衣著称 +衣著称 衣著称 衣著者 衣著者 衣著述 衣著述 裝著 装着 @@ -1806,22 +1735,9 @@ 語著稱 语著称 語著者 语著者 語著述 语著述 -豫著 豫着 -豫著書 豫著书 -豫著作 豫著作 -豫著名 豫著名 -豫著錄 豫著录 -豫著稱 豫著称 -豫著者 豫著者 -豫著述 豫著述 -貞著 贞着 -貞著書 贞著书 -貞著作 贞著作 -貞著名 贞著名 -貞著錄 贞著录 -貞著稱 贞著称 -貞著者 贞著者 -貞著述 贞著述 +猶豫著 犹豫着 +堅貞著 坚贞着 +忠貞著 忠贞着 走著 走着 走著書 走著书 走著作 走著作 @@ -1942,14 +1858,6 @@ 達著稱 达著称 達著者 达著者 達著述 达著述 -遠著 远着 -遠著書 远著书 -遠著作 远著作 -遠著名 远著名 -遠著錄 远著录 -遠著稱 远著称 -遠著者 远著者 -遠著述 远著述 連著 连着 連著書 连著书 連著作 连著作 @@ -1988,6 +1896,7 @@ 遇著名 遇著名 遇著錄 遇著录 遇著稱 遇著称 +遇著称 遇著称 遇著者 遇著者 遇著述 遇著述 配著 配着 @@ -2076,6 +1985,7 @@ 雅著名 雅著名 雅著錄 雅著录 雅著稱 雅著称 +雅著称 雅著称 雅著者 雅著者 雅著述 雅著述 頂著 顶着 @@ -2148,16 +2058,9 @@ 高著名 高著名 高著錄 高著录 高著稱 高著称 +高著称 高著称 高著者 高著者 高著述 高著述 -髭著 髭着 -髭著書 髭著书 -髭著作 髭著作 -髭著名 髭著名 -髭著錄 髭著录 -髭著稱 髭著称 -髭著者 髭著者 -髭著述 髭著述 黏著 黏着 黏著書 黏著书 黏著作 黏著作 @@ -2242,13 +2145,40 @@ 衝著 冲着 沖著 冲着 沖著《 冲著《 +沖著( 冲著( 沖著。 冲著。 沖著, 冲著, +立著 立着 +立著名 立著名 +立著作 立著作 +立著者 立著者 +立著稱 立著称 +立著称 立著称 +立著有 立著有 +立著《 立著《 +立著( 立著( 繫著 系着 颳著 刮着 鬥著 斗着 +縱著 纵着 +伏著 伏着 +視著 视着 +視著名 视著名 +蓋著 盖着 +蓋著名 盖著名 +蓋著稱 盖著称 +蓋著作 盖著作 +覆蓋著 覆盖着 #分词用 象徵著 象征着 象徵著名 象征著名 +固著 固着 +班固著 班固著 +分布著 分布着 +分佈著 分布着 +散布著 散布着 +散佈著 散布着 +遍佈著 遍布着 +遍布著 遍布着 三十六著 三十六着 走為上著 走为上着 記憶體 内存 @@ -2276,6 +2206,8 @@ 晶片 芯片 晶元 芯片 片語 词组 +隻字片語 只字片语 +隻言片語 只言片语 軟碟機 软驱 快閃記憶體 闪存 滑鼠 鼠标 @@ -2296,10 +2228,10 @@ 八進位制 八进位制 十進位制 十进位制 16進位制 16进位制 -互動式 交互式 優先順序 优先级 攜帶型 便携式 資訊理論 信息论 +資訊時代 信息时代 迴圈 循环 解析度 分辨率 伺服器 服务器 @@ -2327,7 +2259,6 @@ 行動電話 移动电话 流動電話 移动电话 數據機 调制解调器 -烏茲別克 乌兹别克斯坦 葉門 也门 貝里斯 伯利兹 維德角 佛得角 @@ -2346,10 +2277,8 @@ 厄瓜多 厄瓜多尔 厄利垂亞 厄立特里亚 吉布地 吉布提 -哈薩克 哈萨克斯坦 哥斯大黎加 哥斯达黎加 吐瓦魯 图瓦卢 -土庫曼 土库曼斯坦 聖露西亞 圣卢西亚 聖吉斯納域斯 圣基茨和尼维斯 聖克里斯多福及尼維斯 圣基茨和尼维斯 @@ -2360,8 +2289,6 @@ 衣索匹亞 埃塞俄比亚 衣索比亞 埃塞俄比亚 吉里巴斯 基里巴斯 -塔吉克 塔吉克斯坦 -塔吉克斯坦 塔吉克斯坦 塞拉利昂 塞拉利昂 塞普勒斯 塞浦路斯 塞席爾 塞舌尔 @@ -2395,6 +2322,7 @@ 象牙海岸 科特迪瓦 突尼西亞 突尼斯 寮國 老挝 +貢寮 贡寮 #分詞用 蘇利南 苏里南 莫三比克 莫桑比克 賴索托 莱索托 @@ -2552,8 +2480,10 @@ 多明尼加 多米尼加 頻寬 带宽 數位相機 数码相机 +數位照相機 数码照相机 單眼相機 单反相机 單鏡反光機 单反相机 +桌上型電腦 台式电脑 韌體 固件 唯讀 只读 作業系統 操作系统 @@ -2567,7 +2497,6 @@ 螢屏 荧屏 解像度 分辨率 IP位址 IP地址 -IP 位址 IP 地址 程式設計師 程序员 公尺 米 公升 升 @@ -2586,6 +2515,7 @@ IP 位址 IP 地址 結他 吉他 了結他 了结他 連結他 连结他 +鏈結 链接 已開發國家 发达国家 太空飛行員 宇航员 太空衣 宇航服 @@ -2608,7 +2538,6 @@ A型肝炎 甲型肝炎 金氏世界紀錄 吉尼斯世界纪录 祖雲達斯 尤文图斯 若且唯若 当且仅当 -山葉 雅马哈 複製人 克隆人 白朗寧 勃朗宁 形上學 形而上学 @@ -2650,6 +2579,8 @@ A型肝炎 甲型肝炎 電腦程式 计算机程序 應用程式 应用程序 雷射 激光 +鱼雷 鱼雷 #分詞用 +魚雷 鱼雷 尖峰時間 高峰时间 尖峰時段 高峰时段 咖哩 咖喱 @@ -2659,7 +2590,7 @@ A型肝炎 甲型肝炎 共和联邦 英联邦 阿布達比 阿布扎比 蓋曼群島 开曼群岛 -柴契爾 撒切尔 +柴契爾 撒切尔 戴卓爾 撒切尔 凱薩琳 凯瑟琳 嘉芙蓮 凯瑟琳 @@ -2706,4 +2637,17 @@ A型肝炎 甲型肝炎 翁山蘇姬 昂山素季 昂山素姬 昂山素季 西洋棋 囯际象棋 -私隱 隐私
\ No newline at end of file +私隱 隐私 +格林美獎 格莱美奖 +葛萊美獎 格莱美奖 +史丹福大學 斯坦福大学 +賈伯斯 乔布斯 +波里活 宝莱坞 +庫德族 库尔德族 +庫德人 库尔德人 +希拉蕊 希拉里 +希拉莉 希拉里 +麻薩諸塞 马萨诸塞 +東南亞國家協會 东南亚国家联盟 +獨立國協 独联体 +獨立國家國協 独立国家联合体 diff --git a/maintenance/language/zhtable/toHK.manual b/maintenance/language/zhtable/toHK.manual index c31d2320..525100e0 100644 --- a/maintenance/language/zhtable/toHK.manual +++ b/maintenance/language/zhtable/toHK.manual @@ -19,7 +19,9 @@ 写字台 寫字枱 工作台 工作枱 弹子台 彈子枱 +上台面 上枱面 台面上 枱面上 +台面化 枱面化 柜台 櫃枱 球台 球枱 赌台 賭枱 @@ -35,9 +37,11 @@ 发布 發佈 發布 發佈 秀发布 秀發佈 -并发布 並發佈 +并发布 並發佈 分布 分佈 +分布于 分佈於 宣布 宣佈 +承宣布政 承宣布政 公布 公佈 摆布 擺佈 擺布 擺佈 @@ -237,7 +241,8 @@ 占國 佔國 占国桥 占國橋 占國橋 占國橋 -占美 佔美 +占美国 佔美國 +占美國 佔美國 占台 佔台 占臺 佔臺 占香 佔香 @@ -401,7 +406,9 @@ 屋里 屋裏 屯里 屯裏 巷里 巷裏 -市里 市裏 +城市里 城市裏 +都市里 都市裏 +市里的 市裏的 年代里 年代裏 年里 年裏 店里 店裏 @@ -493,7 +500,7 @@ 袖里 袖裏 被里 被裏 里勾外连 裏勾外連 -里手 裏手 +行家里手 行家裏手 里海 裏海 里屋 裏屋 里层 裏層 @@ -507,13 +514,13 @@ 里边 裏邊 里间 裏間 里面 裏面 -里面包 裏面包 里头 裏頭 衬里 襯裏 角落里 角落裏 话里有话 話裏有話 车库里 車庫裏 车站里 車站裏 +网站里 網站裏 车里 車裏 车里雅宾斯克 車里雅賓斯克 这里 這裏 @@ -529,6 +536,7 @@ 鸡蛋里挑骨头 雞蛋裏挑骨頭 雪里 雪裏 雾里 霧裏 +云里雾里 雲裏霧裏 鞋里 鞋裏 鞭辟入里 鞭辟入裏 头里 頭裏 @@ -567,12 +575,21 @@ 山里有 山裏有 棉里 棉裏 语里 語裏 +言里 言裏 +境里 境裏 方法里 方法裏 语法里 語法裏 看法里 看法裏 宪法里 憲法裏 用法里 用法裏 法里, 法裏, +框里 框裏 +碗里 碗裏 +电梯里 電梯裏 +个月里 個月裏 +月裡来 月裏來 +分钟里 分鐘裏 +小时里 小時裏 苑裡 苑裡 霄裡 霄裡 岸裡 岸裡 @@ -625,9 +642,8 @@ 動著 動着 鬥著 鬥着 斗着 鬥着 -獨著 獨着 對著 對着 -盾著 盾着 +矛盾著 矛盾着 犯得著 犯得着 犯不著 犯不着 福著 福着 @@ -635,7 +651,6 @@ 高著 高着 隔著 隔着 跟著 跟着 -孤著 孤着 關著 關着 管著 管着 慣著 慣着 @@ -652,7 +667,7 @@ 獲著 獲着 急著 急着 記著 記着 -冀著 冀着 +希冀著 希冀着 夾著 夾着 駕著 駕着 見著 見着 @@ -665,7 +680,6 @@ 看得著 看得着 看不著 看不着 看著 看着 -康著 康着 扛著 扛着 考著 考着 渴著 渴着 @@ -703,7 +717,6 @@ 拿著 拿着 逆著 逆着 釀著 釀着 -努著 努着 趴著 趴着 跑著 跑着 陪著 陪着 @@ -716,7 +729,6 @@ 騎著 騎着 牽著 牽着 求著 求着 -去著 去着 嚷著 嚷着 繞著 繞着 忍著 忍着 @@ -758,7 +770,6 @@ 心著 心着 信著 信着 行著 行着 -性著 性着 學著 學着 尋著 尋着 循著 循着 @@ -770,7 +781,6 @@ 衣著 衣着 疑著 疑着 溢著 溢着 -藝著 藝着 因著 因着 印著 印着 應著 應着 @@ -782,12 +792,11 @@ 有著 有着 與著 與着 語著 語着 -豫著 豫着 -遠著 遠着 +猶豫著 猶豫着 躍著 躍着 雜著 雜着 載著 載着 -在著 在着 +存在著 存在着 紮著 紮着 展著 展着 占着 佔着 @@ -806,7 +815,8 @@ 找不著 找不着 照著 照着 罩著 罩着 -貞著 貞着 +堅貞著 堅貞着 +忠貞著 忠貞着 枕著 枕着 爭著 爭着 掙著 掙着 @@ -818,12 +828,11 @@ 轉著 轉着 裝著 裝着 追著 追着 -髭著 髭着 走著 走着 坐著 坐着 做著 做着 含著 含着 -涵著 涵着 +蘊涵著 蘊涵着 演著 演着 保障著 保障着 黏著 黏着 @@ -1048,6 +1057,7 @@ 乘著名 乘著名 乘著述 乘著述 乘著稱 乘著稱 +乘著称 乘著稱 乘著錄 乘著錄 乘著書 乘著書 持著作 持著作 @@ -1151,6 +1161,7 @@ 低著名 低著名 低著述 低著述 低著稱 低著稱 +低著称 低著稱 低著錄 低著錄 低著書 低著書 點著作 點著作 @@ -1179,6 +1190,7 @@ 定著名 定著名 定著述 定著述 定著稱 定著稱 +定著称 定著稱 定著錄 定著錄 定著書 定著書 動著作 動著作 @@ -1195,13 +1207,6 @@ 鬥著稱 鬥著稱 鬥著錄 鬥著錄 鬥著書 鬥著書 -獨著作 獨著作 -獨著者 獨著者 -獨著名 獨著名 -獨著述 獨著述 -獨著稱 獨著稱 -獨著錄 獨著錄 -獨著書 獨著書 對著作 對著作 對著者 對著者 對著名 對著名 @@ -1209,13 +1214,6 @@ 對著稱 對著稱 對著錄 對著錄 對著書 對著書 -盾著作 盾著作 -盾著者 盾著者 -盾著名 盾著名 -盾著述 盾著述 -盾著稱 盾著稱 -盾著錄 盾著錄 -盾著書 盾著書 犯不著作 犯不著作 犯不著者 犯不著者 犯不著名 犯不著名 @@ -1242,6 +1240,7 @@ 高著名 高著名 高著述 高著述 高著稱 高著稱 +高著称 高著稱 高著錄 高著錄 高著書 高著書 隔著作 隔著作 @@ -1258,13 +1257,6 @@ 跟著稱 跟著稱 跟著錄 跟著錄 跟著書 跟著書 -孤著作 孤著作 -孤著者 孤著者 -孤著名 孤著名 -孤著述 孤著述 -孤著稱 孤著稱 -孤著錄 孤著錄 -孤著書 孤著書 關著作 關著作 關著者 關著者 關著名 關著名 @@ -1291,6 +1283,7 @@ 光著名 光著名 光著述 光著述 光著稱 光著稱 +光著称 光著稱 光著錄 光著錄 光著書 光著書 跪著作 跪著作 @@ -1375,13 +1368,6 @@ 記著稱 記著稱 記著錄 記著錄 記著書 記著書 -冀著作 冀著作 -冀著者 冀著者 -冀著名 冀著名 -冀著述 冀著述 -冀著稱 冀著稱 -冀著錄 冀著錄 -冀著書 冀著書 夾著作 夾著作 夾著者 夾著者 夾著名 夾著名 @@ -1451,13 +1437,6 @@ 看著稱 看著稱 看著錄 看著錄 看著書 看著書 -康著作 康著作 -康著者 康著者 -康著名 康著名 -康著述 康著述 -康著稱 康著稱 -康著錄 康著錄 -康著書 康著書 扛著作 扛著作 扛著者 扛著者 扛著名 扛著名 @@ -1484,6 +1463,7 @@ 刻著名 刻著名 刻著述 刻著述 刻著稱 刻著稱 +刻著称 刻著稱 刻著錄 刻著錄 刻著書 刻著書 空著作 空著作 @@ -1546,6 +1526,7 @@ 努力著名 努力著名 努力著述 努力著述 努力著稱 努力著稱 +努力著称 努力著稱 努力著錄 努力著錄 努力著書 努力著書 麗著作 麗著作 @@ -1581,6 +1562,7 @@ 亮著名 亮著名 亮著述 亮著述 亮著稱 亮著稱 +亮著称 亮著稱 亮著錄 亮著錄 亮著書 亮著書 臨著作 臨著作 @@ -1677,6 +1659,7 @@ 美著名 美著名 美著述 美著述 美著稱 美著稱 +美著称 美著稱 美著錄 美著錄 美著書 美著書 夢著作 夢著作 @@ -1713,13 +1696,6 @@ 釀著稱 釀著稱 釀著錄 釀著錄 釀著書 釀著書 -努著作 努著作 -努著者 努著者 -努著名 努著名 -努著述 努著述 -努著稱 努著稱 -努著錄 努著錄 -努著書 努著書 趴著作 趴著作 趴著者 趴著者 趴著名 趴著名 @@ -1803,13 +1779,6 @@ 求著稱 求著稱 求著錄 求著錄 求著書 求著書 -去著作 去著作 -去著者 去著者 -去著名 去著名 -去著述 去著述 -去著稱 去著稱 -去著錄 去著錄 -去著書 去著書 嚷著作 嚷著作 嚷著者 嚷著者 嚷著名 嚷著名 @@ -1878,6 +1847,7 @@ 守著名 守著名 守著述 守著述 守著稱 守著稱 +守著称 守著稱 守著錄 守著錄 守著書 守著書 受著作 受著作 @@ -2011,6 +1981,7 @@ 味著名 味著名 味著述 味著述 味著稱 味著稱 +味著称 味著稱 味著錄 味著錄 味著書 味著書 想著作 想著作 @@ -2018,6 +1989,7 @@ 想著名 想著名 想著述 想著述 想著稱 想著稱 +想著称 想著稱 想著錄 想著錄 想著書 想著書 響著作 響著作 @@ -2046,6 +2018,7 @@ 心著名 心著名 心著述 心著述 心著稱 心著稱 +心著称 心著稱 心著錄 心著錄 心著書 心著書 信著作 信著作 @@ -2053,6 +2026,7 @@ 信著名 信著名 信著述 信著述 信著稱 信著稱 +信著称 信著稱 信著錄 信著錄 信著書 信著書 行著作 行著作 @@ -2062,13 +2036,6 @@ 行著稱 行著稱 行著錄 行著錄 行著書 行著書 -性著作 性著作 -性著者 性著者 -性著名 性著名 -性著述 性著述 -性著稱 性著稱 -性著錄 性著錄 -性著書 性著書 學著作 學著作 學著者 學著者 學著名 學著名 @@ -2102,6 +2069,7 @@ 雅著名 雅著名 雅著述 雅著述 雅著稱 雅著稱 +雅著称 雅著稱 雅著錄 雅著錄 雅著書 雅著書 沿著作 沿著作 @@ -2129,6 +2097,7 @@ 衣著名 衣著名 衣著述 衣著述 衣著稱 衣著稱 +衣著稱 衣著稱 衣著錄 衣著錄 衣著書 衣著書 疑著作 疑著作 @@ -2145,13 +2114,6 @@ 溢著稱 溢著稱 溢著錄 溢著錄 溢著書 溢著書 -藝著作 藝著作 -藝著者 藝著者 -藝著名 藝著名 -藝著述 藝著述 -藝著稱 藝著稱 -藝著錄 藝著錄 -藝著書 藝著書 因著作 因著作 因著者 因著者 因著名 因著名 @@ -2217,20 +2179,6 @@ 語著稱 語著稱 語著錄 語著錄 語著書 語著書 -豫著作 豫著作 -豫著者 豫著者 -豫著名 豫著名 -豫著述 豫著述 -豫著稱 豫著稱 -豫著錄 豫著錄 -豫著書 豫著書 -遠著作 遠著作 -遠著者 遠著者 -遠著名 遠著名 -遠著述 遠著述 -遠著稱 遠著稱 -遠著錄 遠著錄 -遠著書 遠著書 躍著作 躍著作 躍著者 躍著者 躍著名 躍著名 @@ -2252,13 +2200,6 @@ 載著稱 載著稱 載著錄 載著錄 載著書 載著書 -在著作 在著作 -在著者 在著者 -在著名 在著名 -在著述 在著述 -在著稱 在著稱 -在著錄 在著錄 -在著書 在著書 紮著作 紮著作 紮著者 紮著者 紮著名 紮著名 @@ -2315,13 +2256,6 @@ 罩著稱 罩著稱 罩著錄 罩著錄 罩著書 罩著書 -貞著作 貞著作 -貞著者 貞著者 -貞著名 貞著名 -貞著述 貞著述 -貞著稱 貞著稱 -貞著錄 貞著錄 -貞著書 貞著書 枕著作 枕著作 枕著者 枕著者 枕著名 枕著名 @@ -2349,13 +2283,6 @@ 制著稱 制著稱 制著錄 制著錄 制著書 制著書 -志著作 志著作 -志著者 志著者 -志著名 志著名 -志著述 志著述 -志著稱 志著稱 -志著錄 志著錄 -志著書 志著書 皺著作 皺著作 皺著者 皺著者 皺著名 皺著名 @@ -2397,13 +2324,6 @@ 追著稱 追著稱 追著錄 追著錄 追著書 追著書 -髭著作 髭著作 -髭著者 髭著者 -髭著名 髭著名 -髭著述 髭著述 -髭著稱 髭著稱 -髭著錄 髭著錄 -髭著書 髭著書 走著作 走著作 走著者 走著者 走著名 走著名 @@ -2432,13 +2352,6 @@ 含著稱 含著稱 含著錄 含著錄 含著書 含著書 -涵著作 涵著作 -涵著者 涵著者 -涵著名 涵著名 -涵著述 涵著述 -涵著稱 涵著稱 -涵著錄 涵著錄 -涵著書 涵著書 演著作 演著作 演著者 演著者 演著名 演著名 @@ -2500,6 +2413,7 @@ 遇著名 遇著名 遇著述 遇著述 遇著稱 遇著稱 +遇著称 遇著稱 遇著錄 遇著錄 遇著書 遇著書 殺著作 殺著作 @@ -2560,6 +2474,7 @@ 著甚麽 着甚麽 存著 存着 存著名 存著名 +存著作 存著作 劃著 劃着 別著 別着 刮著 刮着 @@ -2621,6 +2536,33 @@ 放著名 放著名 放著稱 放著稱 放著称 放著稱 +縱著 縱着 +伏著 伏着 +視著 視着 +視著名 視著名 +蓋著 蓋着 +蓋著名 蓋著名 +蓋著稱 蓋著稱 +蓋著作 蓋著作 +覆蓋著 覆蓋着 +立著 立着 +立著名 立著名 +立著作 立著作 +立著者 立著者 +立著稱 立著稱 +立著称 立著稱 +立著有 立著有 +立著《 立著《 +立著( 立著( +固著 固着 +班固著 班固著 +面包著 面包着 +分布著 分佈着 +分佈著 分佈着 +散布著 散佈着 +散佈著 散佈着 +遍佈著 遍佈着 +遍布著 遍佈着 三十六著 三十六着 走為上著 走為上着 鬧著 鬧着 @@ -2739,6 +2681,7 @@ 萬那杜 瓦努阿圖 葛摩 科摩羅 寮國 老撾 +貢寮 貢寮 #分詞用 肯尼亚 肯雅 莫三比克 莫桑比克 賴索托 萊索托 @@ -2762,7 +2705,7 @@ 柯林頓 克林頓 萨达姆 薩達姆 贝克汉姆 碧咸 -贝克漢 碧咸 +貝克漢 碧咸 迈克尔·欧文 米高·奧雲 卡普里亚蒂 卡佩雅蒂 马拉特·萨芬 馬拉特·沙芬 @@ -2777,7 +2720,6 @@ 莱特湾 雷伊泰灣 萊特灣 雷伊泰灣 蘭卡威 浮羅交怡 -吉尔吉斯斯坦 吉爾吉斯 撒马尔罕 撒馬爾罕 伊斯蘭瑪巴德 伊斯蘭堡 喀拉蚩 卡拉奇 @@ -2900,7 +2842,7 @@ 史匹柏 史匹堡 戈巴契夫 戈爾巴喬夫 席哈克 希拉克 -希拉蕊 希拉里 +希拉蕊 希拉莉 布莱尔 貝理雅 尼克松 尼克遜 奧黛麗·赫本 柯德莉·夏萍 @@ -2930,10 +2872,10 @@ C型肝炎 丙型肝炎 晶体管 電晶體 源代码 原始碼 IP地址 IP位址 -IP 地址 IP 位址 屏幕 螢幕 荧屏 螢屏 版权信息 版權資訊 +信息时代 資訊時代 蹦床 彈床 擊劍 劍擊 击剑 劍擊 @@ -2941,8 +2883,11 @@ IP 地址 IP 位址 牛轧 鳥結 牛軋 鳥結 數位相機 數碼相機 +數位照相機 数碼照相機 +数字照相机 数碼照相機 單眼相機 單鏡反光機 单反相机 單鏡反光機 +台式电脑 桌上型電腦 形上學 形而上學 吉尼斯世界纪录 健力士世界紀錄 吉他 結他 @@ -2951,7 +2896,6 @@ IP 地址 IP 位址 泰坦尼克号 鐵達尼號 自行火炮 自走炮 冰激凌 雪糕 -奥斯曼 鄂圖曼 里氏0 黎克特制0 里氏1 黎克特制1 里氏2 黎克特制2 @@ -2982,6 +2926,7 @@ IP 地址 IP 位址 正體中文 繁體中文 板球 木球 籃板球 籃板球 +篮板球 籃板球 智慧財產權 知識產權 智財權 知識產權 首席执行官 行政總裁 @@ -3007,7 +2952,6 @@ IP 地址 IP 位址 肖斯塔科维奇 蕭士達高維契 蕭士塔高維奇 蕭士達高維契 工具機 機床 -伊斯坦堡 伊斯坦布爾 空气质量 空氣質素 空氣品質 空氣質素 俯卧撑 掌上壓 @@ -3041,4 +2985,15 @@ IP 地址 IP 位址 西洋棋 國際象棋 隐私 私隱 隱私 私隱 -硅藻 硅藻
\ No newline at end of file +硅藻 硅藻 +格莱美奖 格林美獎 +葛萊美獎 格林美獎 +斯坦福大学 史丹福大學 +賈伯斯 喬布斯 +宝莱坞 波里活 +寶萊塢 波里活 +庫德族 库爾德族 +庫德人 库爾德人 +東南亞國家協會 東南亞國家聯盟 +獨立國協 獨聯體 +獨立國家國協 獨立國家聯合體 diff --git a/maintenance/language/zhtable/toSimp.manual b/maintenance/language/zhtable/toSimp.manual index b857e5f4..9674aae9 100644 --- a/maintenance/language/zhtable/toSimp.manual +++ b/maintenance/language/zhtable/toSimp.manual @@ -57,9 +57,9 @@ 男性为乾 男性为乾 男为乾 男为乾 阳为乾 阳为乾 -男性爲乾 男性为乾 -男爲乾 男为乾 -陽爲乾 阳为乾 +男性為乾 男性为乾 +男為乾 男为乾 +陽為乾 阳为乾 乾一组 乾一组 乾一坛 乾一坛 陈乾生 陈乾生 @@ -68,12 +68,12 @@ 孙乾 孙乾 陈遇乾 陈遇乾 曾运乾 曾运乾 -象乾 象乾 乾贵士 乾贵士 +乾东 乾东 柳诒徵 柳诒徵 於夫罗 於夫罗 於梨华 於梨华 -於潜县 於潜县 +於潜 於潜 於志贺 於志贺 憑藉 凭借 藉端 借端 @@ -144,7 +144,16 @@ 么篇 幺篇 么謙 幺谦 六么 六幺 +老么 老幺 +么正 幺正 +么女 幺女 +么九 幺九 +么子 幺子 这么 这么 +那么 那么 +什么 什么 +怎么 怎么 +多么 多么 乾乾淨淨 干干净净 乾乾脆脆 干干脆脆 肉乾乾 肉干干 @@ -206,9 +215,6 @@ 獨鍾 独钟 鍾靈 钟灵 龍鍾 龙钟 -鍾山 钟山 -一鍾 一钟 -千鍾 千钟 薰心 熏心 薰習 熏习 薰陶 熏陶 @@ -265,4 +271,14 @@ 麴黴 曲霉 造麴 造曲 大麴 大曲 -黃麴毒素 黄曲毒素
\ No newline at end of file +黃麴毒素 黄曲毒素 +硃砂 朱砂 +硃紅 朱红 +硃色 朱色 +銀硃 银朱 +遶境 绕境 +侷促 局促 +侷限 局限 +馬鞌 马鞍 +觔斗 斤斗 +穀阳 穀阳 diff --git a/maintenance/language/zhtable/toTW.manual b/maintenance/language/zhtable/toTW.manual index 14f7eaeb..22456a78 100644 --- a/maintenance/language/zhtable/toTW.manual +++ b/maintenance/language/zhtable/toTW.manual @@ -17,45 +17,84 @@ 钚 鈽 硅 矽 煙草 菸草 +烟草 菸草 煙蒂 菸蒂 +烟蒂 菸蒂 煙斗 菸斗 +烟斗 菸斗 煙鬼 菸鬼 +烟鬼 菸鬼 煙灰 菸灰 +烟灰 菸灰 煙具 菸具 +烟具 菸具 煙民 菸民 +烟民 菸民 煙農 菸農 +烟农 菸農 煙絲 菸絲 +烟丝 菸絲 煙頭 菸頭 +烟头 菸頭 煙葉 菸葉 +烟叶 菸葉 煙癮 菸癮 +烟瘾 菸癮 煙嘴 菸嘴 +烟嘴 菸嘴 煙酒 菸酒 +烟酒 菸酒 煙袋 菸袋 +烟袋 菸袋 煙品 菸品 +烟品 菸品 煙鹼 菸鹼 +烟碱 菸鹼 煙捲 菸捲 +烟卷 菸捲 香煙 香菸 +香烟 香菸 捲煙 捲菸 +卷烟 捲菸 旱煙 旱菸 +旱烟 旱菸 烤煙 烤菸 +烤烟 烤菸 禁煙 禁菸 +禁烟 禁菸 戒煙 戒菸 +戒烟 戒菸 拒煙 拒菸 +拒烟 拒菸 紙煙 紙菸 +纸烟 紙菸 抽煙 抽菸 +抽烟 抽菸 吸煙 吸菸 +吸烟 吸菸 反煙 反菸 +反烟 反菸 私煙 私菸 +私烟 私菸 點煙 點菸 +点烟 點菸 洋煙 洋菸 +洋烟 洋菸 二手煙 二手菸 +二手烟 二手菸 電子煙 電子菸 +电子烟 電子菸 呂宋煙 呂宋菸 +吕宋烟 呂宋菸 雪茄煙 雪茄菸 +雪茄烟 雪茄菸 無煙日 無菸日 +无烟日 無菸日 無煙環境 無菸環境 +无烟环境 無菸環境 榴莲 榴槤 榴蓮 榴槤 +铆足 卯足 霉素 黴素 想象 想像 迭代 疊代 @@ -126,9 +165,17 @@ 冲着 衝著 干着 幹著 干着急 干著急 +对着干 對著幹 斗着 鬥著 +面包着 面包著 徵狀 症狀 系数 係數 +汇编 彙編 +报道 報導 +划着船 划著船 +划着竹筏 划著竹筏 +划着独木舟 划著獨木舟 +着眼于 著眼於 缺省 預設 以太网 乙太網 光盘 光碟 @@ -144,7 +191,6 @@ 磁盘 磁碟 磁道 磁軌 端口 埠 -算子 運算元 芯片 晶片 译码 解碼 软驱 軟碟機 @@ -153,6 +199,7 @@ 鼠标 滑鼠 进制 進位 信息论 資訊理論 +信息时代 資訊時代 写保护 防寫 分辨率 解析度 服务器 伺服器 @@ -161,10 +208,9 @@ 数据库 資料庫 打印机 印表機 打印機 印表機 -字节 位元組 -字節 位元組 打印 列印 -攻打印 攻打印 +攻打 攻打 #分詞用 +打印度 打印度 硬件 硬體 二极管 二極體 二極管 二極體 @@ -184,7 +230,6 @@ 调制解调器 數據機 調制解調器 數據機 短信 簡訊 -乌兹别克斯坦 烏茲別克 乍得 查德 也门 葉門 也門 葉門 @@ -215,12 +260,10 @@ 厄立特里亞 厄利垂亞 吉布提 吉布地 吉布堤 吉布地 -哈萨克斯坦 哈薩克 哥斯达黎加 哥斯大黎加 哥斯達黎加 哥斯大黎加 图瓦卢 吐瓦魯 圖瓦盧 吐瓦魯 -土库曼斯坦 土庫曼 圣卢西亚 聖露西亞 聖盧西亞 聖露西亞 圣基茨和尼维斯 聖克里斯多福及尼維斯 @@ -236,7 +279,6 @@ 埃塞俄比亚 衣索比亞 埃塞俄比亞 衣索比亞 基里巴斯 吉里巴斯 -塔吉克斯坦 塔吉克 塞拉利昂 獅子山 塞浦路斯 塞普勒斯 塞舌尔 塞席爾 @@ -335,7 +377,6 @@ 莱特湾 雷伊泰灣 萊特灣 雷伊泰灣 耶加達 雅加達 -吉尔吉斯斯坦 吉爾吉斯 伊斯兰堡 伊斯蘭瑪巴德 伊斯蘭堡 伊斯蘭瑪巴德 卡拉奇 喀拉蚩 @@ -504,7 +545,7 @@ 索贊尼辛 索忍尼辛 瓦格纳 華格納 毕加索 畢卡索 -碧咸 贝克漢 +碧咸 貝克漢 梅尔·吉布森 梅爾·吉勃遜 查韦斯 查維茲 本杰明 班傑明 @@ -516,7 +557,7 @@ 斯皮尔伯格 史匹柏 斯特劳斯 史特勞斯 斯大林 史達林 -斯坦福 史丹福 +斯坦福大学 史丹福大學 撒切尔 柴契爾 戴卓爾 柴契爾 摩根士丹利 摩根史坦利 @@ -528,6 +569,7 @@ 德里达 德希達 帕特里克 派屈克 希拉里 希拉蕊 +希拉莉 希拉蕊 希拉克 席哈克 尼克松 尼克森 威廉姆斯 威廉士 @@ -571,7 +613,6 @@ 晶體管 電晶體 晶体管 電晶體 IP地址 IP位址 -IP 地址 IP 位址 解像度 解析度 屏幕 螢幕 荧屏 螢屏 @@ -582,8 +623,11 @@ IP 地址 IP 位址 宇航员 太空人 太空飛行員 太空人 独联体 獨立國協 +獨聯體 獨立國協 独立国家联合体 獨立國家國協 -东南亚国家联盟 東南亞國協 +獨立國家聯合體 獨立國家國協 +东南亚国家联盟 東南亞國家協會 +東南亞國家聯盟 東南亞國家協會 发达国家 已開發國家 哥特式 哥德式 落車 下車 @@ -600,7 +644,11 @@ IP 地址 IP 位址 數碼相機 數位相機 單鏡反光機 單眼相機 数码相机 數位相機 +数字照相机 數位照相機 +数码照相机 數位照相機 +數碼照相機 數位照相機 单反相机 單眼相機 +台式电脑 桌上型電腦 形而上學 形上學 形而上学 形上學 当且仅当 若且唯若 @@ -614,7 +662,6 @@ IP 地址 IP 位址 沙律 沙拉 忌廉 奶油 味美思 苦艾酒 -奥斯曼 鄂圖曼 埃博拉 伊波拉 克隆人 複製人 荧光 螢光 @@ -655,6 +702,7 @@ IP 地址 IP 位址 高峰时间 尖峰時間 高峰时段 尖峰時段 东盟 東協 +東盟 東協 亚细安 東協 英联邦 大英國協 英聯邦 大英國協 @@ -672,7 +720,7 @@ IP 地址 IP 位址 自由泳 自由式 机床 工具機 機床 工具機 -空气质量 空氣品質 +空气质量 空氣品質 空氣質素 空氣品質 俯卧撑 伏地挺身 掌上壓 伏地挺身 @@ -684,6 +732,8 @@ IP 地址 IP 位址 數碼訊號 數位訊號 移动网络 行動網路 流動網絡 行動網路 +网络游戏 網路遊戲 +網絡遊戲 網路遊戲 咪高峰 麥克風 電單車 機車 搜索引擎 搜尋引擎 @@ -701,4 +751,10 @@ IP 地址 IP 位址 囯际象棋 西洋棋 國際象棋 西洋棋 私隱 隱私 -硅藻 硅藻
\ No newline at end of file +硅藻 硅藻 +格林美獎 葛萊美獎 +格莱美奖 葛萊美獎 +乔布斯 賈伯斯 +波里活 寶萊塢 +库尔德族 庫德族 +库尔德人 庫德人 diff --git a/maintenance/language/zhtable/toTrad.manual b/maintenance/language/zhtable/toTrad.manual index 7fc60c74..13a0b989 100644 --- a/maintenance/language/zhtable/toTrad.manual +++ b/maintenance/language/zhtable/toTrad.manual @@ -2,22 +2,28 @@ “ 「 ‘ 『 ’ 』 -’s ’s +’s ’s 手塚治虫 手塚治虫 無言不仇 無言不讎 視如寇仇 視如寇讎 往日無仇 往日無讎 近日無仇 近日無讎 李連杰 李連杰 -周杰倫 周杰倫 +杰倫 杰倫 +杰威爾 杰威爾 +黃詩杰 黃詩杰 +陳士杰 陳士杰 +林杰樑 林杰樑 +許聖杰 許聖杰 +張杰 張杰 +孫杰 孫杰 +陳杰 陳杰 +黃杰 黃杰 +謝杰 謝杰 寶曆 寶曆 涂謹申 涂謹申 涂鴻欽 涂鴻欽 涂壯勳 涂壯勳 -於姓 於姓 -於氏 於氏 -於夫羅 於夫羅 -於梨華 於梨華 鄭凱云 鄭凱云 筑陽 筑陽 筑後 筑後 @@ -35,7 +41,6 @@ 拜托 拜託 委托书 委託書 委托 委託 -於夫罗 於夫羅 府干預 府干預 府干擾 府干擾 頁面 頁面 @@ -64,9 +69,6 @@ 乾象曆 乾象曆 乾象历 乾象曆 不好干預 不好干預 -不干預 不干預 -不干擾 不干擾 -不干牠 不干牠 范文瀾 范文瀾 機械系 機械系 頂多 頂多 @@ -107,7 +109,6 @@ 于明濤 于明濤 于根偉 于根偉 于樹潔 于樹潔 -于正昇 于正昇 于漢超 于漢超 于洪區 于洪區 于湘蘭 于湘蘭 @@ -153,20 +154,18 @@ 余三勝 余三勝 簡筑翎 簡筑翎 楊雅筑 楊雅筑 -杰威爾音樂 杰威爾音樂 尸羅精舍 尸羅精舍 騰格里 騰格里 村里長 村里長 進制 進制 模范三軍 模范三軍 -黃詩杰 黃詩杰 陳冲 陳冲 劉佳怜 劉佳怜 范賢惠 范賢惠 于國治 于國治 于楓 于楓 黎吉雲 黎吉雲 -于飛島 于飛島 +于飛 于飛 鄉愿 鄉愿 愿樸 愿樸 謹愿 謹愿 @@ -192,16 +191,14 @@ 苹果 蘋果 苹果干 蘋果乾 后庄 后庄 +後庄 後庄 龜山庄 龜山庄 寶山庄 寶山庄 員山庄 員山庄 昵称 暱稱 單于 單于 -鮮于樞 鮮于樞 -鳳凰于飛 鳳凰于飛 +鮮于 鮮于 賦范 賦范 -陳士杰 陳士杰 -林杰樑 林杰樑 茅于軾 茅于軾 陳有后 陳有后 天神之后 天神之后 @@ -214,11 +211,13 @@ 水里高級商工 水里高級商工 水里鳳林 水里鳳林 水里濁水溪 水里濁水溪 +洞里薩 洞里薩 划不來 划不來 划來划去 划來划去 划動 划動 划得來 划得來 划著 划著 +划著 劃著名 划進 划進 划過 划過 划龍舟 划龍舟 @@ -226,6 +225,11 @@ 么弟 么弟 六么 六么 么雞 么雞 +么正 么正 +么女 么女 +么九 么九 +么子 么子 +么半 么半 義联 義联 杠轂 杠轂 局促 侷促 @@ -450,6 +454,7 @@ 万余 萬餘 亿余 億餘 兆余 兆餘 +仅余 僅餘 0余 0餘 1余 1餘 2余 2餘 @@ -460,6 +465,9 @@ 7余 7餘 8余 8餘 9余 9餘 +带余 帶餘 +余干 餘干 +余江 餘江 于余曲折 于餘曲折 尸居余气 尸居餘氣 余光生 余光生 @@ -479,7 +487,43 @@ 曲钱 麴錢 曲车 麴車 鼠曲草 鼠麴草 -大曲酒 大麴酒 +曲酒 麯酒 泸州大曲 瀘州大麯 #商標名 -洋河大曲 洋河大麴 -双沟大曲 雙溝大麯 #商標名
\ No newline at end of file +洋河大曲 洋河大麯 +沟大曲 溝大麯 +朱砂 硃砂 +银朱 銀硃 +喲喂 喲喂 +鳥栖 鳥栖 +澄江县 澂江縣 #以下為含異體字地名 +横峰县 橫峯縣 +鹤峰县 鶴峯縣 +五峰县 五峯縣 +兰溪市 蘭谿市 +金溪县 金谿縣 +竹溪县 竹谿縣 +辰溪县 辰谿縣 +松溪县 松谿縣 +慈溪 慈谿 +浚州 濬州 +浚县 濬縣 +穆棱 穆稜 +绥棱 綏稜 +丹棱 丹稜 +仙游 仙遊 +麟游 麟遊 +乐游原 樂遊原 +托克逊 託克遜 +托里县 託里縣 +沾化 霑化 +沾益 霑益 +岫岩 岫巖 +黄岩县 黃巖縣 +黄岩区 黃巖區 +北仑河 北崙河 +昆嵛 崑嵛 +昆承湖 崑承湖 +灵昆 靈崑 +龙岩 龍巖 +扑冬 撲鼕 +冬冬鼓 鼕鼕鼓 diff --git a/maintenance/language/zhtable/trad2simp.manual b/maintenance/language/zhtable/trad2simp.manual index f76a9498..c479f35d 100644 --- a/maintenance/language/zhtable/trad2simp.manual +++ b/maintenance/language/zhtable/trad2simp.manual @@ -1,4 +1,3 @@ -U+0347A㑺|U+04FCA俊| U+034BA㒺|U+07F54罔| U+034C2㓂|U+05BC7寇| U+03541㕁|U+05374却| @@ -15,8 +14,6 @@ U+0384C㡌|U+05E3D帽| U+03898㢘|U+05EC9廉| U+03919㤙|U+06069恩| U+03966㥦|U+060EC惬| -U+0396B㥫|U+060C7惇| -U+039F1㧱|U+062FF拿| U+03A17㨗|U+06377捷| U+03A2A㨪|U+06643晃| U+03A3F㨿|U+0636E据| @@ -61,7 +58,6 @@ U+04EB7亷|U+05EC9廉| U+04EBE亾|U+04EA1亡| U+04F48佈|U+05E03布| U+04F54佔|U+05360占| -U+04FB7侷|U+05C40局| U+04FFB俻|U+05907备| U+05010倐|U+0500F倏| U+05016倖|U+05E78幸| @@ -138,7 +134,6 @@ U+056D9囙|U+056E0因| U+05705圅|U+051FD函| U+0577F坿|U+09644附| U+0579C垜|U+0579B垛| -U+0585A塚|U+051A2冢| U+0585F塟|U+0846C葬| U+05872塲|U+0573A场| U+05896墖|U+05854塔| @@ -227,7 +222,7 @@ U+0617C慼|U+0621A戚| U+0617D慽|U+0621A戚| U+0617E慾|U+06B32欲| U+06187憇|U+061A9憩| -U+061DE懞|U+08499蒙| +U+061DE懞|U+061DE懞|U+08499蒙| U+0621E戞|U+0621B戛| U+0622F戯|U+0620F戏| U+06239戹|U+05384厄| @@ -275,7 +270,6 @@ U+0671E朞|U+0671F期| U+06722朢|U+0671B望| U+0672E朮|U+0672F术| U+06736朶|U+06735朵| -U+06792枒|U+04E2B桠| U+067B1枱|U+053F0台| U+067FA柺|U+062D0拐| U+067FB査|U+067E5查| @@ -287,8 +281,6 @@ U+06852桒|U+06851桑| U+0686E桮|U+0676F杯| U+0687A桺|U+067F3柳| U+068CA棊|U+068CB棋| -U+06900椀|U+07897碗| -U+06909椉|U+04E58乘| U+06917椗|U+07887碇| U+06936椶|U+068D5棕| U+06937椷|U+07F04缄| @@ -324,7 +316,6 @@ U+06DDB淛|U+06D59浙| U+06DE8淨|U+051C0净| U+06DE9淩|U+051CC凌| U+06E67湧|U+06D8C涌| -U+06E7B湻|U+06DF3淳| U+06E7C湼|U+06D85涅| U+06EBC溼|U+06E7F湿| U+06ED9滙|U+06C47汇| @@ -417,7 +408,6 @@ U+077C1矁|U+07785瞅| U+077C7矇|U+08499蒙|U+077C7矇| U+077D9矙|U+077B0瞰| U+07832砲|U+070AE炮| -U+07843硃|U+06731朱| U+07881碁|U+068CB棋| U+078AA碪|U+07827砧| U+078DF磟|U+0788C碌| @@ -446,7 +436,7 @@ U+07AE2竢|U+04FDF俟| U+07AEA竪|U+07AD6竖| U+07B5E筞|U+07B56策| U+07B69筩|U+07B52筒| -U+07B6F筯|U+07BB8箸| +U+07B6F筯|U+07BB8箸| U+07B87箇|U+04E2A个| U+07B92箒|U+05E1A帚| U+07BA0箠|U+068F0棰| @@ -567,7 +557,6 @@ U+08842衂|U+08844衄| U+08846衆|U+04F17众| U+08847衇|U+08109脉| U+0884A衊|U+08511蔑| -U+08856衖|U+05F04弄| U+0885E衞|U+0536B卫| U+0887A衺|U+090AA邪| U+0889F袟|U+05E19帙| @@ -584,7 +573,6 @@ U+08988覈|U+06838核| U+0898A覊|U+07F81羁| U+08994覔|U+089C5觅| U+089A9覩|U+07779睹| -U+089D4觔|U+065A4斤| U+089DD觝|U+062B5抵| U+08A17託|U+06258托|U+08BAC讬| U+08A3C証|U+08BC1证| @@ -649,7 +637,6 @@ U+09049遉|U+04FA6侦| U+0904A遊|U+06E38游| U+09061遡|U+06EAF溯| U+0906F遯|U+09041遁| -U+09076遶|U+07ED5绕| U+09156酖|U+09E29鸩| U+09167酧|U+0916C酬| U+09183醃|U+0814C腌| @@ -663,6 +650,7 @@ U+091E6釦|U+06263扣| U+091EC釬|U+0710A焊| U+09205鈅|U+094A5钥| U+0920E鈎|U+094A9钩| +U+09244鉄|U+094C1铁| U+09246鉆|U+094BB钻| U+09262鉢|U+094B5钵| U+092B2銲|U+0710A焊| @@ -711,7 +699,6 @@ U+096A3隣|U+090BB邻| U+096B7隷|U+096B6隶| U+0976D靭|U+097E7韧| U+09771靱|U+097E7韧| -U+0978C鞌|U+0978D鞍| U+097A6鞦|U+079CB秋|U+097A7鞧| U+097B5鞵|U+0978B鞋| U+097BE鞾|U+09774靴| @@ -734,6 +721,7 @@ U+098F1飱|U+098E7飧| U+09901餁|U+0996A饪| U+09908餈|U+07CCD糍| U+09918餘|U+09980馀|U+04F59余| +U+09935餵|U+05582喂| U+09939餹|U+07CD6糖| U+0993B餻|U+07CD5糕| U+0993D餽|U+09988馈| @@ -742,22 +730,18 @@ U+09951饑|U+09965饥| U+0995D饝|U+0998D馍| U+099C8駈|U+09A71驱| U+099E1駡|U+09A82骂| -U+099EE駮|U+09A73驳| U+09A10騐|U+09A8C验| U+09A23騣|U+09B03鬃| U+09A58驘|U+09AA1骡| U+09ABD骽|U+0817F腿| U+09ABE骾|U+09CA0鲠| U+09AC8髈|U+08180膀| -U+09AE3髣|U+04EFF仿| U+09AE5髥|U+09AEF髯| -U+09AF4髴|U+04F5B佛| U+09B00鬀|U+05243剃| U+09B09鬉|U+09B03鬃| U+09B26鬦|U+06597斗| U+09B28鬨|U+054C4哄| U+09B2A鬪|U+06597斗| -U+09B2D鬭|U+06597斗| U+09B30鬰|U+090C1郁| U+09B8E鮎|U+09C87鲇| U+09B9D鮝|U+09C9E鲞| @@ -786,47 +770,25 @@ U+09EF4黴|U+09709霉| U+09F03鼃|U+086D9蛙| U+09F07鼇|U+09CCC鳌| U+09F08鼈|U+09CD6鳖| -U+09F15鼕|U+051AC冬| +U+09F15鼕|U+0549A咚| U+09F63齣|U+051FA出| U+09F67齧|U+0556E啮| U+09F69齩|U+054AC咬| -U+201EE𠇮|U+0547D命| -U+20302𠌂|U+04F1E伞| U+20542𠕂|U+0518D再| U+20545𠕅|U+0518D再| -U+20587𠖇|U+051A5冥| U+207B0𠞰|U+0527F剿| -U+20ABE𠪾|U+05386历| -U+20D1F𠴟|U+054A9咩| -U+20EF3𠻳|U+055FD嗽| -U+21428𡐨|U+091CE野| U+21681𡚁|U+05F0A弊| -U+21A18𡨘|U+051A4冤| U+21A25𡨥|U+05BC7寇| -U+21B36𡬶|U+05BFB寻| U+21ED5𡻕|U+05C81岁| -U+22B38𢬸|U+062EC括| -U+22B4F𢭏|U+06363捣| -U+22BA5𢮥|U+064CD操| -U+22DEC𢷬|U+06363捣| U+2365C𣙜|U+069B7榷| U+242EE𤋮|U+07199熙| U+24A0F𤨏|U+07410琐| -U+24C1C𤰜|U+04EA9亩| U+24C48𤱈|U+04EA9亩| -U+24C4A𤱊|U+07559留| U+24EA5𤺥|U+07629瘩| -U+25128𥄨|U+07785瞅| -U+25997𥦗|U+07A97窗| -U+25CBB𥲻|U+07E82纂| -U+260B3𦂳|U+07D27紧| -U+260C2𦃂|U+07D27紧| -U+26246𦉆|U+078B4碴| U+262B1𦊱|U+06302挂| U+26351𦍑|U+07F8C羌| U+26548𦕈|U+07707眇| -U+26A99𦪙|U+0447D䑽| U+26D4F𦵏|U+0846C葬| U+28F7B𨽻|U+096B6隶| U+294D0𩓐|U+08116脖| -U+295D7𩗗|U+098D3飓|
\ No newline at end of file +U+295D7𩗗|U+098D3飓| diff --git a/maintenance/language/zhtable/trad2simp_noconvert.manual b/maintenance/language/zhtable/trad2simp_noconvert.manual index 15192eaf..25be79e4 100644 --- a/maintenance/language/zhtable/trad2simp_noconvert.manual +++ b/maintenance/language/zhtable/trad2simp_noconvert.manual @@ -11,4 +11,8 @@ 幺 苹 厘 -𫍟
\ No newline at end of file +𫍟 +垴 +岙 +㳕 +䓕 diff --git a/maintenance/language/zhtable/tradphrases.manual b/maintenance/language/zhtable/tradphrases.manual index 4d313b42..b97ca6e4 100644 --- a/maintenance/language/zhtable/tradphrases.manual +++ b/maintenance/language/zhtable/tradphrases.manual @@ -230,7 +230,6 @@ 乾村沙 乾暖 乾料 -乾敲梆子不賣油 乾支支 乾支剌 乾擦 @@ -259,10 +258,8 @@ 乾剝剝 乾刻版 乾芻 -幹人 乾產 乾喬 -夯幹 大目乾連 國之楨榦 唇乾 @@ -278,11 +275,12 @@ 顛乾倒坤 強幹 乾眼 -幹的停當 井幹 乾巴 偎乾 眼乾 +瀝乾 +白乾兒 肉絲麵 薑絲 反覆 @@ -424,6 +422,7 @@ 採區 採運 採風 +採血 官地為寀 寮寀 蔘綏 @@ -488,7 +487,7 @@ 醜逆 醜史 醜賊生 -醜婆子 +真醜 出乖弄醜 出乖露醜 獲匪其醜 @@ -506,7 +505,6 @@ 女丑 小丑 大丑 -丑婆子 丑旦 丑角 丑三 @@ -579,7 +577,7 @@ 髮屋 櫛髮工 鬒髮 -令人髮指 +人髮指 爆發指數 開發 剪其髮 @@ -682,6 +680,7 @@ 吾爲之範我馳驅 天地為範 範數 +範亭 丰采 丰標不凡 丰神 @@ -702,6 +701,9 @@ 複流 反複製 複對數 +複分解 +複合 #因複合詞頻遠高於復合 +複方 撥穀 扁擬穀盜蟲 不穀 @@ -711,7 +713,6 @@ 脫穀機 年穀 礱穀機 -孤寡不穀 穀米 穀旦 穀圭 @@ -733,11 +734,9 @@ 臧穀亡羊 種穀 颳雪 -刮風下雪倒便宜 广部 -亂鬨不過來 +亂鬨鬨 斗鬨 -亂鬨 開鬨 花鬨 鬨動 @@ -752,13 +751,15 @@ 南迴鐵路 北迴線 北迴鐵路 -文匯報 -河流匯集 -品彙 -博彙 +迴文詩 +迴文數 +迴文錦 +迴文聯 +迴文序列 +迴文結構 +迴文構詞 滙豐 伙頭 -方几 伏几 高几 雪窗螢几 @@ -806,9 +807,8 @@ 印纍綬若 灕湘 灕然 -澤滲灕而下降 +滲灕 裏勾外連 -裏手 水里溪 二里頭 年歷史 @@ -929,7 +929,6 @@ 擀麵 過水麵 蕎麥麵 -巧婦做不得無麵餺飥 削麵 小米麵 壯麵 @@ -959,7 +958,15 @@ 辣麵 肉麵 燴麵 -雲吞麵 +蝦麵 +雲吞 +一碗麵 +吃碗麵 +吃麵 +麵點師 +麵點、 +、麵點 +麵製品 冷面相 糞穢衊面 僕僕 @@ -1085,11 +1092,21 @@ 瀋河 瀋水 瀋州 +瀋北 +瀋吉 瀋山線 -瀋吉線 -墨沈 +瀋山鐵路 瀋海鐵路 +瀋海高速 +瀋丹線 +瀋丹鐵路 +瀋丹客運 +瀋大線 +瀋大鐵路 +瀋大高速 +秦瀋客運 遼瀋 +京瀋 胜肽 胜鍵 雙胜類 @@ -1115,13 +1132,16 @@ 鬆元音 鬆喉 鬆化 +很鬆 +寬鬆鬆 +蓬鬆鬆 +輕鬆鬆 +鬆鬆地 囉囉囌囌 囉囌 骨罈 菜罈 罈騞 -餵驢 -剪牡丹喂牛 鹹粥 鹹食 鹹潟 @@ -1129,6 +1149,8 @@ 鹽打怎麼鹹 鹹派 鹹批 +鹹濕 +鹹豬 錦綉花園 籲天 勃鬱 @@ -1209,6 +1231,10 @@ 正官庄 冬山庄 松山庄 +香山庄 +中庄子 +田庄英雄 +本庄 厂部 衝量 衝車 @@ -1272,7 +1298,6 @@ 龍眼乾 乾乾淨淨 乾柴烈火 -乾乾兒的 桑乾 撈乾 搭乾鋪 @@ -1282,20 +1307,56 @@ 幹事 幹什麼 幹細胞 -頭兒幹 -配水幹管 -繐幃飄井幹 -站乾岸兒 -秋陰入井幹 -沒梢幹 +樹幹 +口燥唇乾 +舌乾唇焦 +不食乾腊 +不乾不淨 +乾重 +蒸乾 +乾物 +乾食 +乾鍋 +自乾五 +不乾膠 +老白乾 +乾姐 +乾紅葡萄酒 +乾白葡萄酒 楨幹 -據榦而窺井底 -井榦摧敗 -杰特 +新幹縣 +誰幹的 +他幹的 +們幹的 +人幹的 +幹的事 +幹的好事 +得力幹將 +黑幹將 +的幹將 +幹大事 +對着幹 +怎麼幹 +這麼幹 +幹這 +幹仗 李連杰 -周杰倫 +周杰 杰倫 -姜文杰 +文杰 +杰威爾 +黃詩杰 +何杰 +狄志杰 +伊適杰 +張杰 +孫杰 +胡杰 +陳杰 +黃杰 +謝杰 +正杰 +柳斌杰 稜鏡 稜角 稜台 @@ -1351,35 +1412,11 @@ 叶韻 叶音 叶恭弘 -於1 -於2 -於3 -於4 -於5 -於6 -於7 -於8 -於9 -於0 -於一 -於二 -於三 -於四 -於五 -於六 -於七 -於八 -於九 -於十 -於半 -於夫羅 -於梨華 置於 散於 播於 國於 敗於 -於一役 畢於 畢業於 寒於 @@ -1387,30 +1424,16 @@ 拘於 插於 中於 -於市 -於野 敏於 聽於 短於 成於 樊於期 淡於 -於陸 -於密 -於盡 禍於 格於 猛於 施於 -於牆 -於物 -於己 -於你 -於我 -於他 -於她 -於它 -於祂 拒人於 拒於 潰於 @@ -1418,8 +1441,6 @@ 相於 形於 半於 -於始 -於終 詢於 美於 醜於 @@ -1429,40 +1450,16 @@ 弱於 差於 劣於 -於美 -於醜 -於好 -於坏 -於強 -於弱 -於差 -於劣 -於垂 染指於 -於火 -存十一於千百 存於 -於勤 隱於 藏於 嚴於 寬於 -於幕 給於 -於穆 -於呼哀哉 -於時 -於該 危於 -於伏 -於何 -於家 -於國 -於潛縣 -於焉 於徵 離於 -於畢 麗於 下於 亞於 @@ -1470,30 +1467,18 @@ 屑於 絕於 致於 -於行 遜於 任教於 教於 自於 來於 附於 -於人 -於世 阻於 -於民 -於盲 -於色 囿於 直於 建於 都於 -於農 -於樂 -於前 役於 -於心 -於法 -於事 助於 害於 損於 @@ -1510,17 +1495,14 @@ 身於 足於 溢於 -於衷 畏於 視於 衷於 狃於 疲於 通於 -於途 老於 耿於 -於懷 服於 臻於 匿於 @@ -1561,6 +1543,7 @@ 筑邦 筑陽 南筑 +悲筑 批准的 核准的 為準 @@ -1804,6 +1787,13 @@ 舊錶 台鐘 鐘響 +船鐘 +電波鐘 +石鐘 +自由鐘 +鐘螺 +鐘花 +馬德鐘 計時錶 防水錶 顯示表格 @@ -1847,6 +1837,7 @@ 遊牧 遊蕩 遊刃 +遊美學務 黑奴籲天錄 林郁方 讚歌 @@ -1920,20 +1911,15 @@ 影相弔 哀弔 唁弔 -於水 安於 迫於 罷於 蹪於 -於敝 -於過 甚於 等於 定於 利於 對於 -推舟於陸 -退藏於密 歸於 難於 移禍於 @@ -1949,19 +1935,13 @@ 基於 急於 嫁禍於 -借聽於聾 見於 鑒於 -謹於心 -求道於盲 始於 -於藍 出於 輕於 -行百里者半於九十 幸於 怠於 -詢於芻蕘 止於 至於 拙於 @@ -1974,40 +1954,46 @@ 屬於 浮於 在於 -厝薪於火 易於 精於 由於 -於此 -燕巢於幕 -於菟 -於乎 -於戲 -於邑 補於 位於 -於今 -於是 -於是乎 -於斯 寓於 -月離於畢 -月麗於箕 源於 且於 長於 現於 較於 -於之 分布於 -分散於 +散於 優於 早於 晚於 感於 +用於 +處於 +助於 +便於 +戰於 +葬於 +困於 +適於 +苦於 +落於 +取決於 +着眼於 鬼谷子 谷子敬 洪谷子 +西米谷 +世田谷 +聖馬爾谷日 +澀谷區 +開山闢谷 +山谷 #分詞用 +溝谷 +曼谷 于美人 緊緻 曰云 @@ -2095,11 +2081,22 @@ 爭奇鬥豔 使其鬥 鬥地主 +鈎心鬥角 +鬥劍 +激鬥 +政鬥 +鬥獸 +鬥龍 +鬥勇 +鬥狗 +鬥蛐 +鬥垮 +鬥敗 +鬥戰 石樑 木樑 藏歷史 頁面 -方面 面條目 大讚 唄讚 @@ -2110,6 +2107,8 @@ 詩讚 賞讚 讚唄 +點讚 +點個讚 飛紮 紮裹 紮腳 @@ -2167,9 +2166,7 @@ 徵吏 徵令 本徵 -船鐘 黃鈺筑 -香山庄 當準 憑準 沒準 @@ -2238,6 +2235,8 @@ 趙治勳 殭屍 有栖川 +栗栖溪 +鳥栖市 兇惡 兇狠 兇猛 @@ -2272,7 +2271,6 @@ 鋼之鍊金術師 索馬里 范登堡 -世田谷 製漿 三統歷史 伊斯蘭教歷史 @@ -2352,8 +2350,6 @@ 母醜 一齣子 齣兒 -獃串了皮 -占便宜的是獃 丰標 丰姿 丰韻 @@ -2366,8 +2362,6 @@ 鼕鼕鼓 剷頭 剷刈 -口燥唇乾 -舌乾唇焦 花菴詞選 渾箇 箇中原因 @@ -2376,12 +2370,13 @@ 箇中好手 箇中強手 箇中滋味 -箇中奧秘 -箇中奧妙 +箇中奧 +箇中道理 箇中玄機 -箇中消息 -箇中資訊 -箇中訊息 +箇中翹楚 +,箇中 +。箇中 +的箇中 對表達 對表現 對表演 @@ -2406,17 +2401,6 @@ 不占算 不好干涉 不好干預 -不干預 -不干涉 -不干休 -不干犯 -不干擾 -不干你 -不干我 -不干他 -不干她 -不干它 -不干事 不斗膽 不每只 不采聲 @@ -2425,15 +2409,10 @@ 之一只 之二只 之八九只 -也斗了膽 -事情干脆 -事都干脆 二只得 亦云 人云 以自制 -們斗了膽 -你斗了膽 其一只 其二只 其八九只 @@ -2506,6 +2485,9 @@ 台風穩健 穩健的台風 台風獎 +電視台風 +足球台 +網球台 合府上 後面店 向往常 @@ -2524,11 +2506,17 @@ 好斗篷 好斗膽 好斗蓬 +墨斗 小几 尸利 尸祿 尸臣 尸鳩 +尸佼 +尸子 +尸羅精舍 +毗婆尸佛 +尸棄佛 已占卜 已占算 并迭 @@ -2604,7 +2592,6 @@ 精制住 精制服 經有云 -給我干脆 編制法 能干休 能干戈 @@ -2672,10 +2659,11 @@ 面包裝 面包裹 面包起 +面包着 +面包著 面店鋪 面粉碎 面粉紅 -面食麵 面食飯 顛顛仆仆 高干擾 @@ -2684,13 +2672,14 @@ 黃金表 天后宮 一吊錢 -不食乾腊 傳位于四太子 儉确之教 党懷英 八蜡 憑几 南宮适 +洪适 +李适 大蜡 子云 分子雲 @@ -2702,7 +2691,6 @@ 折子戲 搤肮拊背 文采郁郁 -洪适 腊之以為餌 腊毒 蜡月 @@ -2711,12 +2699,14 @@ 宜云 貴价 郁郁菲菲 -不乾不淨 生發生 必須 須根據 ·范 剋剝 +休克期 +克期間 +溫洛克期 科尼亞克期 馬斯垂克期 滿拚自盡 @@ -2726,6 +2716,7 @@ 拚絕 成於思 單單於 +名單於 積澱 澱積 澱北片 @@ -2765,14 +2756,9 @@ 范文藤 范文虎 范文照 -乾重 -鈎心鬥角 -全面包圍 -全面包裹 機械系 體系 心理 -複分解 鹰鵰 天地志狼 薴烯 @@ -2916,7 +2902,6 @@ 于禁 于敏中 註:# 不作“注:” -呆呆獸 劃為# 不作“划為” 併為一體 併為一家 @@ -2964,6 +2949,7 @@ 這裡 中文裡 洞裡 +洞里薩 界裡 眼睛裡 百科裡 @@ -3060,16 +3046,31 @@ 山裡有 棉裡 語裡 +言裡 +境裡 +境里程 +中境里 方法裡 語法裡 看法裡 憲法裡 用法裡 法裡, +框裡 +碗裡 +電梯裡 +網站裡 +行家裡手 +雲裡霧裡 +城市裡 +都市裡 +市裡的 +個月裡 +月裡來 +分鐘裡 +小時裡 首發 夸脫 -誰幹的 -鐘螺 風采 代碼表 編碼表 @@ -3089,14 +3090,13 @@ 有只用 葉叶琹 胡子昂 +胡子嬰 包括 特别致 分别致 韶山沖 于丹 -于樂 于冕 -于軍 于吉 于堅 于姓 @@ -3118,6 +3118,7 @@ 于靖 于勒 于格 +于飛 于仁泰 于會泳 于偉國 @@ -3213,7 +3214,6 @@ 故云 強制作用 鬱南 -西米谷 鬱林 饑荒 免徵 @@ -3233,6 +3233,8 @@ 歌后 影后 封后 +查封後 +解封後 太后 天后 呂后 @@ -3273,8 +3275,10 @@ 馬格里布 伊里布 劃入 -中庄子 埔裏社 +手裏劍 +裏水鎮 +裏運河 懸掛 僱傭 四捨六入 @@ -3288,13 +3292,8 @@ 莜麵 簡筑翎 楊雅筑 -魔杰座 -杰威爾音樂 彭于晏 -尸羅精舍 進制 -黃詩杰 -何杰 劉佳怜 于小惠 于耘婕 @@ -3309,7 +3308,6 @@ 熊杰 卜云吉 黎吉雲 -于飛島 代表 水無怜奈 賭后 @@ -3318,12 +3316,12 @@ 劉芸后 謝華后 趙惠后 +昭惠后 +周惠后 +孝惠后 趙威后 聖后 陳有后 -許虬 -狄志杰 -伊適杰 于冠華 于雲鶴 于忠肅集 @@ -3333,12 +3331,13 @@ 于天龍 于謹 于榮光 -電波鐘 掛名 -啟發式 舞后 甄后 郭后 +高后 +升高後 +提高後 0年 # 協助分詞 1年 2年 @@ -3403,11 +3402,13 @@ 樗里子 伊達里子 濱田里佳子 +王田里 +小井里 +西井里 尊后 叶志穗 叶不二子 于立成 -山谷道 李志喜 于欣 于少保 @@ -3421,15 +3422,14 @@ 于再清 茅于軾 張樂于張徐 -鮮于樞 +鮮于 +朝鮮於 于寶軒 于震 於震前 -於震后 +於震後 於震中 固定制 -毗婆尸佛 -尸棄佛 划船 划不來 划拳 @@ -3438,12 +3438,16 @@ 划艇 划行 划算 +划着船 +划着竹筏 +划着獨木舟 總裁制 仲裁制 獨裁制 恒生 +恒基 +恒隆 嚴云農 -手裏劍 伊東怜 衛後莊公 並行 @@ -3454,24 +3458,30 @@ 余力為 葉叶琴 幾個 -澀谷區 併發症 併發重症 併發模式 併發型模式 +啟發式 +連發式 色長髮 頭長髮 的長髮 +黑長髮 +留長髮 +髮披肩 +髮及腰 +飄髮自由女神 後天 學家 游離 紅后假說 書面 不只 +湧水 高涌泉 -王田里 +涌水塘 后姓 -田庄英雄 計劃 抑制劑 党姓 @@ -3517,10 +3527,6 @@ 功勳 蝎虎 磨蝎 -鬥劍 -激鬥 -政鬥 -沈海蓉 方志恒 古蹟 瀋撫 @@ -3528,21 +3534,21 @@ 騰衝 沖天 豐臺 +煙臺 陽穀 -蒸乾 太醜 御製 合併 聖人曆 -电影後 +電影後 封為后 皮托管 白面包青天 天神之后 -栗栖溪 羅馬曆 羅馬歷史 羅馬歷代 +曆數書 你誇 誇你 誇我 @@ -3573,8 +3579,7 @@ 自誇 誇稱 誇讚 -更加注 -繼承制 +讚嘆 布穀鳥 黎克特制 筆桿 @@ -3594,7 +3599,6 @@ 墨瀋 米瀋 拾瀋 -乾物 姦污 託兒 同人誌 @@ -3602,7 +3606,6 @@ 衝着 確係 乃係 -開山辟谷 穀祿 製衣 巨製 @@ -3643,12 +3646,9 @@ 錦滷 汤滷 浸滷 -石鐘 -石鐘山 花葯 聚葯雄蕊 遺蹟 -開山闢谷 受僱 僱請 僱車 @@ -3690,6 +3690,7 @@ 辦公檯 檯面上 上檯面 +檯面化 牴觸 牴牾 角牴 @@ -3698,7 +3699,6 @@ 嫩薑 酸薑 薑啤 -鹹濕 騰湧 草蓆 竹蓆 @@ -3706,9 +3706,13 @@ 涼蓆 灘蓆 麻將蓆 -裏水鎮 被廢後 蒸製 +烹製 +醃製 +和製漢 +壓製機 +壓製出 體徵 綜合徵 价川 @@ -3777,6 +3781,7 @@ 被繫上 繫上, 繫上。 +繫舟 亂發生 亂發脾氣 秀發村 @@ -3786,4 +3791,30 @@ 秀發現 秀發生 秀發起 -秀發展
\ No newline at end of file +秀發展 +縮短發 +簡短發 +短發生 +古人有云 +昔人有云 +云敞 +喂, +喂! +喂喲 +喲喂 +啊喂 +呵喂 +呦喂 +水表面 +表面包 +松口鎮 +沙瑯 +琺瑯 +菜餚 +梁啓超 +改制成 +王添灯 +腌臢 +風颳 +颳大風 +黃白術 diff --git a/maintenance/language/zhtable/tradphrases_exclude.manual b/maintenance/language/zhtable/tradphrases_exclude.manual index 4a3613b6..1f8a6e06 100644 --- a/maintenance/language/zhtable/tradphrases_exclude.manual +++ b/maintenance/language/zhtable/tradphrases_exclude.manual @@ -662,4 +662,45 @@ 複流 複畝珍 起複 -餘
\ No newline at end of file +餘 +旋乾轉坤 +乾坤 +乾卦 +乾隆 +乾掉 +讚嘆不已 +讚歎 +好乾 +加註 +幹將 +鼕 +彙報 +彙整 +彙編 +彙集 +快幹 +快乾 +瀋海 +迴文 +迴向 +迴音 +美製 +麵灰 +麵價 +承製 +樹榦 +白乾 +白干兒 +市裡 +于飛 +髮指 +鬆鬆 +于是 +于七 +于今 +曆數 +發矇 +不幹 +作姦犯科 +游牧民族 +穀道 diff --git a/maintenance/migrateFileRepoLayout.php b/maintenance/migrateFileRepoLayout.php new file mode 100644 index 00000000..78587ce5 --- /dev/null +++ b/maintenance/migrateFileRepoLayout.php @@ -0,0 +1,232 @@ +<?php +/** + * Copy all files in FileRepo to an originals container using SHA1 paths. + * + * 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 files in FileRepo to an originals container using SHA1 paths. + * + * This script should be run while the repo is still set to the old layout. + * + * @ingroup Maintenance + */ +class MigrateFileRepoLayout extends Maintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = "Copy files in repo to a different layout."; + $this->addOption( 'oldlayout', "Old layout; one of 'name' or 'sha1'", true, true ); + $this->addOption( 'newlayout', "New layout; one of 'name' or 'sha1'", true, true ); + $this->addOption( 'since', "Copy only files from after this timestamp", false, true ); + $this->setBatchSize( 50 ); + } + + public function execute() { + $oldLayout = $this->getOption( 'oldlayout' ); + if ( !in_array( $oldLayout, array( 'name', 'sha1' ) ) ) { + $this->error( "Invalid old layout.", 1 ); + } + $newLayout = $this->getOption( 'newlayout' ); + if ( !in_array( $newLayout, array( 'name', 'sha1' ) ) ) { + $this->error( "Invalid new layout.", 1 ); + } + $since = $this->getOption( 'since' ); + + $repo = $this->getRepo(); + + $be = $repo->getBackend(); + if ( $be instanceof FileBackendDBRepoWrapper ) { + $be = $be->getInternalBackend(); // avoid path translations for this script + } + + $dbw = $repo->getMasterDB(); + + $origBase = $be->getContainerStoragePath( "{$repo->getName()}-original" ); + $startTime = wfTimestampNow(); + + // Do current and archived versions... + $conds = array(); + if ( $since ) { + $conds[] = 'img_timestamp >= ' . $dbw->addQuotes( $dbw->timestamp( $since ) ); + } + + $batch = array(); + $lastName = ''; + do { + $res = $dbw->select( 'image', array( 'img_name', 'img_sha1' ), + array_merge( array( 'img_name > ' . $dbw->addQuotes( $lastName ) ), $conds ), + __METHOD__, + array( 'LIMIT' => $this->mBatchSize, 'ORDER BY' => 'img_name' ) + ); + + foreach ( $res as $row ) { + $lastName = $row->img_name; + $sha1 = $row->img_sha1; + if ( !strlen( $sha1 ) ) { + $this->error( "Image SHA-1 not set for {$row->img_name}." ); + } else { + $file = $repo->newFile( $row->img_name ); + + if ( $oldLayout === 'sha1' ) { + $spath = "{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}"; + } else { + $spath = $file->getPath(); + } + + if ( $newLayout === 'sha1' ) { + $dpath = "{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}"; + } else { + $dpath = $file->getPath(); + } + + $status = $be->prepare( array( 'dir' => dirname( $dpath ) ) ); + if ( !$status->isOK() ) { + $this->error( print_r( $status->getErrorsArray(), true ) ); + } + + $batch[] = array( 'op' => 'copy', 'overwrite' => true, + 'src' => $spath, 'dst' => $dpath, 'img' => $row->img_name ); + } + + foreach ( $file->getHistory() as $ofile ) { + $sha1 = $ofile->getSha1(); + if ( !strlen( $sha1 ) ) { + $this->error( "Image SHA-1 not set for {$ofile->getArchiveName()}." ); + continue; + } + + if ( $oldLayout === 'sha1' ) { + $spath = "{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}"; + } elseif ( $ofile->isDeleted( File::DELETED_FILE ) ) { + $spath = $be->getContainerStoragePath( "{$repo->getName()}-deleted" ) . + '/' . $repo->getDeletedHashPath( $sha1 ) . + $sha1 . '.' . $ofile->getExtension(); + } else { + $spath = $ofile->getPath(); + } + + if ( $newLayout === 'sha1' ) { + $dpath = "{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}"; + } else { + $dpath = $ofile->getPath(); + } + + $status = $be->prepare( array( 'dir' => dirname( $dpath ) ) ); + if ( !$status->isOK() ) { + $this->error( print_r( $status->getErrorsArray(), true ) ); + } + $batch[] = array( 'op' => 'copy', 'overwrite' => true, + 'src' => $spath, 'dst' => $dpath, 'img' => $ofile->getArchiveName() ); + } + + if ( count( $batch ) >= $this->mBatchSize ) { + $this->runBatch( $batch, $be ); + $batch = array(); + } + } + } while ( $res->numRows() ); + + if ( count( $batch ) ) { + $this->runBatch( $batch, $be ); + } + + // Do deleted versions... + $conds = array(); + if ( $since ) { + $conds[] = 'fa_deleted_timestamp >= ' . $dbw->addQuotes( $dbw->timestamp( $since ) ); + } + + $batch = array(); + $lastId = 0; + do { + $res = $dbw->select( 'filearchive', array( 'fa_storage_key', 'fa_id', 'fa_name' ), + array_merge( array( 'fa_id > ' . $dbw->addQuotes( $lastId ) ), $conds ), + __METHOD__, + array( 'LIMIT' => $this->mBatchSize, 'ORDER BY' => 'fa_id' ) + ); + + foreach ( $res as $row ) { + $lastId = $row->fa_id; + $sha1Key = $row->fa_storage_key; + if ( !strlen( $sha1Key ) ) { + $this->error( "Image SHA-1 not set for file #{$row->fa_id} (deleted)." ); + continue; + } + $sha1 = substr( $sha1Key, 0, strpos( $sha1Key, '.' ) ); + + if ( $oldLayout === 'sha1' ) { + $spath = "{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}"; + } else { + $spath = $be->getContainerStoragePath( "{$repo->getName()}-deleted" ) . + '/' . $repo->getDeletedHashPath( $sha1Key ) . $sha1Key; + } + + if ( $newLayout === 'sha1' ) { + $dpath = "{$origBase}/{$sha1[0]}/{$sha1[1]}/{$sha1[2]}/{$sha1}"; + } else { + $dpath = $be->getContainerStoragePath( "{$repo->getName()}-deleted" ) . + '/' . $repo->getDeletedHashPath( $sha1Key ) . $sha1Key; + } + + $status = $be->prepare( array( 'dir' => dirname( $dpath ) ) ); + if ( !$status->isOK() ) { + $this->error( print_r( $status->getErrorsArray(), true ) ); + } + + $batch[] = array( 'op' => 'copy', 'src' => $spath, 'dst' => $dpath, + 'overwriteSame' => true, 'img' => "(ID {$row->fa_id}) {$row->fa_name}" ); + + if ( count( $batch ) >= $this->mBatchSize ) { + $this->runBatch( $batch, $be ); + $batch = array(); + } + } + } while ( $res->numRows() ); + + if ( count( $batch ) ) { + $this->runBatch( $batch, $be ); + } + + $this->output( "Done (started $startTime)\n" ); + } + + protected function getRepo() { + return RepoGroup::singleton()->getLocalRepo(); + } + + protected function runBatch( array $ops, FileBackend $be ) { + $this->output( "Migrating file batch:\n" ); + foreach ( $ops as $op ) { + $this->output( "\"{$op['img']}\" (dest: {$op['dst']})\n" ); + } + + $status = $be->doOperations( $ops ); + if ( !$status->isOK() ) { + $this->output( print_r( $status->getErrorsArray(), true ) ); + } + + $this->output( "Batch done\n\n" ); + } +} + +$maintClass = 'MigrateFileRepoLayout'; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/namespaceDupes.php b/maintenance/namespaceDupes.php index 96e01fe4..088f6776 100644 --- a/maintenance/namespaceDupes.php +++ b/maintenance/namespaceDupes.php @@ -39,9 +39,12 @@ class NamespaceConflictChecker extends Maintenance { */ protected $db; - private $resolvableCount = 0; + private $resolvablePages = 0; private $totalPages = 0; + private $resolvableLinks = 0; + private $totalLinks = 0; + public function __construct() { parent::__construct(); $this->mDescription = ""; @@ -172,7 +175,43 @@ class NamespaceConflictChecker extends Maintenance { } $this->output( "{$this->totalPages} pages to fix, " . - "{$this->resolvableCount} were resolvable.\n" ); + "{$this->resolvablePages} were resolvable.\n\n" ); + + foreach ( $spaces as $name => $ns ) { + if ( $ns != 0 ) { + // Fix up link destinations for non-interwiki links only. + // + // For example if a page has [[Foo:Bar]] and then a Foo namespace + // is introduced, pagelinks needs to be updated to have + // page_namespace = NS_FOO. + // + // If instead an interwiki prefix was introduced called "Foo", + // the link should instead be moved to the iwlinks table. If a new + // language is introduced called "Foo", or if there is a pagelink + // [[fr:Bar]] when interlanguage magic links are turned on, the + // link would have to be moved to the langlinks table. Let's put + // those cases in the too-hard basket for now. The consequences are + // not especially severe. + // + // @fixme Handle interwiki links, and pagelinks to Category:, File: + // which probably need reparsing. + + $this->checkLinkTable( 'pagelinks', 'pl', $ns, $name, $options ); + $this->checkLinkTable( 'templatelinks', 'tl', $ns, $name, $options ); + + // The redirect table has interwiki links randomly mixed in, we + // need to filter those out. For example [[w:Foo:Bar]] would + // have rd_interwiki=w and rd_namespace=0, which would match the + // query for a conflicting namespace "Foo" if filtering wasn't done. + $this->checkLinkTable( 'redirect', 'rd', $ns, $name, $options, + array( 'rd_interwiki' => null ) ); + $this->checkLinkTable( 'redirect', 'rd', $ns, $name, $options, + array( 'rd_interwiki' => '' ) ); + } + } + + $this->output( "{$this->totalLinks} links to fix, " . + "{$this->resolvableLinks} were resolvable.\n" ); return $ok; } @@ -215,7 +254,8 @@ class NamespaceConflictChecker extends Maintenance { // Find the new title and determine the action to take - $newTitle = $this->getDestinationTitle( $ns, $name, $row, $options ); + $newTitle = $this->getDestinationTitle( $ns, $name, + $row->page_namespace, $row->page_title, $options ); $logStatus = false; if ( !$newTitle ) { $logStatus = 'invalid title'; @@ -271,27 +311,102 @@ class NamespaceConflictChecker extends Maintenance { $newTitle->getPrefixedDBkey() . " (merge)$dryRunNote\n" ); if ( $options['fix'] ) { - $pageOK = $this->mergePage( $row->page_id, $newTitle ); + $pageOK = $this->mergePage( $row, $newTitle ); } break; } if ( $pageOK ) { - $this->resolvableCount++; + $this->resolvablePages++; } else { $ok = false; } } - // @fixme Also needs to do like self::getTargetList() on the - // *_namespace and *_title fields of pagelinks, templatelinks, and - // redirects, and schedule a LinksUpdate job or similar for each found - // *_from. - return $ok; } /** + * Check and repair the destination fields in a link table + * @param string $table The link table name + * @param string $fieldPrefix The field prefix in the link table + * @param int $ns Destination namespace id + * @param string $name + * @param array $options Associative array of validated command-line options + * @param array $extraConds Extra conditions for the SQL query + */ + private function checkLinkTable( $table, $fieldPrefix, $ns, $name, $options, + $extraConds = array() + ) { + $batchConds = array(); + $fromField = "{$fieldPrefix}_from"; + $namespaceField = "{$fieldPrefix}_namespace"; + $titleField = "{$fieldPrefix}_title"; + $batchSize = 500; + while ( true ) { + $res = $this->db->select( + $table, + array( $fromField, $namespaceField, $titleField ), + array_merge( $batchConds, $extraConds, array( + $namespaceField => 0, + $titleField . $this->db->buildLike( "$name:", $this->db->anyString() ) + ) ), + __METHOD__, + array( + 'ORDER BY' => array( $titleField, $fromField ), + 'LIMIT' => $batchSize + ) + ); + + if ( $res->numRows() == 0 ) { + break; + } + foreach ( $res as $row ) { + $logTitle = "from={$row->$fromField} ns={$row->$namespaceField} " . + "dbk={$row->$titleField}"; + $destTitle = $this->getDestinationTitle( $ns, $name, + $row->$namespaceField, $row->$titleField, $options ); + $this->totalLinks++; + if ( !$destTitle ) { + $this->output( "$table $logTitle *** INVALID\n" ); + continue; + } + $this->resolvableLinks++; + if ( !$options['fix'] ) { + $this->output( "$table $logTitle -> " . + $destTitle->getPrefixedDBkey() . " DRY RUN\n" ); + continue; + } + + $this->db->update( $table, + // SET + array( + $namespaceField => $destTitle->getNamespace(), + $titleField => $destTitle->getDBkey() + ), + // WHERE + array( + $namespaceField => 0, + $titleField => $row->$titleField, + $fromField => $row->$fromField + ), + __METHOD__ + ); + $this->output( "$table $logTitle -> " . + $destTitle->getPrefixedDBkey() . "\n" ); + } + $encLastTitle = $this->db->addQuotes( $row->$titleField ); + $encLastFrom = $this->db->addQuotes( $row->$fromField ); + + $batchConds = array( + "$titleField > $encLastTitle " . + "OR ($titleField = $encLastTitle AND $fromField > $encLastFrom)" ); + + wfWaitForSlaves(); + } + } + + /** * Move the given pseudo-namespace, either replacing the colon with a hyphen * (useful for pseudo-namespaces that conflict with interwiki links) or move * them to another namespace if specified. @@ -338,21 +453,22 @@ class NamespaceConflictChecker extends Maintenance { } /** - * Get the preferred destination title for a given target page row. + * Get the preferred destination title for a given target page. * @param integer $ns The destination namespace ID * @param string $name The conflicting prefix - * @param stdClass $row + * @param integer $sourceNs The source namespace + * @param integer $sourceDbk The source DB key (i.e. page_title) * @param array $options Associative array of validated command-line options * @return Title|false */ - private function getDestinationTitle( $ns, $name, $row, $options ) { - $dbk = substr( $row->page_title, strlen( "$name:" ) ); + private function getDestinationTitle( $ns, $name, $sourceNs, $sourceDbk, $options ) { + $dbk = substr( $sourceDbk, strlen( "$name:" ) ); if ( $ns == 0 ) { // An interwiki; try an alternate encoding with '-' for ':' $dbk = "$name-" . $dbk; } $destNS = $ns; - if ( $row->page_namespace == NS_TALK && MWNamespace::isSubject( $ns ) ) { + if ( $sourceNs == NS_TALK && MWNamespace::isSubject( $ns ) ) { // This is an associated talk page moved with the --move-talk feature. $destNS = MWNamespace::getTalk( $destNS ); } @@ -392,8 +508,6 @@ class NamespaceConflictChecker extends Maintenance { /** * Move a page * - * @fixme Update pl_from_namespace etc. - * * @param integer $id The page_id * @param Title $newTitle The new title * @return bool @@ -409,8 +523,20 @@ class NamespaceConflictChecker extends Maintenance { ), __METHOD__ ); - // @fixme Needs updating the *_from_namespace fields in categorylinks, - // pagelinks, templatelinks and imagelinks. + // Update *_from_namespace in links tables + $fromNamespaceTables = array( + array( 'pagelinks', 'pl' ), + array( 'templatelinks', 'tl' ), + array( 'imagelinks', 'il' ) ); + foreach ( $fromNamespaceTables as $tableInfo ) { + list( $table, $fieldPrefix ) = $tableInfo; + $this->db->update( $table, + // SET + array( "{$fieldPrefix}_from_namespace" => $newTitle->getNamespace() ), + // WHERE + array( "{$fieldPrefix}_from" => $id ), + __METHOD__ ); + } return true; } @@ -444,7 +570,17 @@ class NamespaceConflictChecker extends Maintenance { * @param integer $id The page_id * @param Title $newTitle The new title */ - private function mergePage( $id, Title $newTitle ) { + private function mergePage( $row, Title $newTitle ) { + $id = $row->page_id; + + // Construct the WikiPage object we will need later, while the + // page_id still exists. Note that this cannot use makeTitleSafe(), + // we are deliberately constructing an invalid title. + $sourceTitle = Title::makeTitle( $row->page_namespace, $row->page_title ); + $sourceTitle->resetArticleID( $id ); + $wikiPage = new WikiPage( $sourceTitle ); + $wikiPage->loadPageData( 'fromdbmaster' ); + $destId = $newTitle->getArticleId(); $this->db->begin( __METHOD__ ); $this->db->update( 'revision', @@ -456,10 +592,18 @@ class NamespaceConflictChecker extends Maintenance { $this->db->delete( 'page', array( 'page_id' => $id ), __METHOD__ ); - // @fixme Need WikiPage::doDeleteUpdates() or similar to avoid orphan - // rows in the links tables. - + // Call LinksDeletionUpdate to delete outgoing links from the old title, + // and update category counts. + // + // Calling external code with a fake broken Title is a fairly dubious + // idea. It's necessary because it's quite a lot of code to duplicate, + // but that also makes it fragile since it would be easy for someone to + // accidentally introduce an assumption of title validity to the code we + // are calling. + $update = new LinksDeletionUpdate( $wikiPage ); + $update->doUpdate(); $this->db->commit( __METHOD__ ); + return true; } } diff --git a/maintenance/parse.php b/maintenance/parse.php index 7b05cb7b..d6559657 100644 --- a/maintenance/parse.php +++ b/maintenance/parse.php @@ -89,11 +89,10 @@ class CLIParser extends Maintenance { * @return string Wikitext */ protected function Wikitext() { - $php_stdin = 'php://stdin'; $input_file = $this->getArg( 0, $php_stdin ); - if ( $input_file === $php_stdin ) { + if ( $input_file === $php_stdin && !$this->mQuiet ) { $ctrl = wfIsWindows() ? 'CTRL+Z' : 'CTRL+D'; $this->error( basename( __FILE__ ) . ": warning: reading wikitext from STDIN. Press $ctrl to parse.\n" ); diff --git a/maintenance/populateCategory.php b/maintenance/populateCategory.php index ab0ca1ed..66553bc6 100644 --- a/maintenance/populateCategory.php +++ b/maintenance/populateCategory.php @@ -58,12 +58,6 @@ TEXT; true ); $this->addOption( - 'max-slave-lag', - 'If slave lag exceeds this many seconds, wait until it drops before continuing. Default: 10', - false, - true - ); - $this->addOption( 'throttle', 'Wait this many milliseconds after each category. Default: 0', false, @@ -74,13 +68,9 @@ TEXT; public function execute() { $begin = $this->getOption( 'begin', '' ); - $maxSlaveLag = $this->getOption( 'max-slave-lag', 10 ); $throttle = $this->getOption( 'throttle', 0 ); $force = $this->getOption( 'force', false ); - $this->doPopulateCategory( $begin, $maxSlaveLag, $throttle, $force ); - } - private function doPopulateCategory( $begin, $maxlag, $throttle, $force ) { $dbw = wfGetDB( DB_MASTER ); if ( !$force ) { diff --git a/maintenance/populateContentModel.php b/maintenance/populateContentModel.php new file mode 100644 index 00000000..3f5d6b69 --- /dev/null +++ b/maintenance/populateContentModel.php @@ -0,0 +1,207 @@ +<?php +/** + * Populate the page_content_model and {rev,ar}_content_{model,format} fields. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Maintenance + */ + +require_once __DIR__ . '/Maintenance.php'; + +/** + * Usage: + * populateContentModel.php --ns=1 --table=page + */ +class PopulateContentModel extends Maintenance { + public function __construct() { + parent::__construct(); + $this->mDescription = 'Populate the various content_* fields'; + $this->addOption( 'ns', 'Namespace to run in, or "all" for all namespaces', true, true ); + $this->addOption( 'table', 'Table to run in', true, true ); + $this->setBatchSize( 100 ); + } + + public function execute() { + $dbw = wfGetDB( DB_MASTER ); + $ns = $this->getOption( 'ns' ); + if ( !ctype_digit( $ns ) && $ns !== 'all' ) { + $this->error( 'Invalid namespace', 1 ); + } + $ns = $ns === 'all' ? 'all' : (int)$ns; + $table = $this->getOption( 'table' ); + switch ( $table ) { + case 'revision': + case 'archive': + $this->populateRevisionOrArchive( $dbw, $table, $ns ); + break; + case 'page': + $this->populatePage( $dbw, $ns ); + break; + default: + $this->error( "Invalid table name: $table", 1 ); + } + } + + private function updatePageRows( DatabaseBase $dbw, $pageIds, $model ) { + $count = count( $pageIds ); + $this->output( "Setting $count rows to $model..." ); + $dbw->update( + 'page', + array( 'page_content_model' => $model ), + array( 'page_id' => $pageIds ), + __METHOD__ + ); + wfWaitForSlaves(); + $this->output( "done.\n" ); + } + + protected function populatePage( DatabaseBase $dbw, $ns ) { + $toSave = array(); + $lastId = 0; + $nsCondition = $ns === 'all' ? array() : array( 'page_namespace' => $ns ); + do { + $rows = $dbw->select( + 'page', + array( 'page_namespace', 'page_title', 'page_id' ), + array( + 'page_content_model' => null, + 'page_id > ' . $dbw->addQuotes( $lastId ), + ) + $nsCondition, + __METHOD__, + array( 'LIMIT' => $this->mBatchSize, 'ORDER BY' => 'page_id ASC' ) + ); + $this->output( "Fetched {$rows->numRows()} rows.\n" ); + foreach ( $rows as $row ) { + $title = Title::newFromRow( $row ); + $model = ContentHandler::getDefaultModelFor( $title ); + $toSave[$model][] = $row->page_id; + if ( count( $toSave[$model] ) >= $this->mBatchSize ) { + $this->updatePageRows( $dbw, $toSave[$model], $model ); + unset( $toSave[$model] ); + } + $lastId = $row->page_id; + } + } while ( $rows->numRows() >= $this->mBatchSize ); + foreach ( $toSave as $model => $pages ) { + $this->updatePageRows( $dbw, $pages, $model ); + } + } + + private function updateRevisionOrArchiveRows( DatabaseBase $dbw, $ids, $model, $table ) { + $prefix = $table === 'archive' ? 'ar' : 'rev'; + $model_column = "{$prefix}_content_model"; + $format_column = "{$prefix}_content_format"; + $key = "{$prefix}_id"; + + $count = count( $ids ); + $format = ContentHandler::getForModelID( $model )->getDefaultFormat(); + $this->output( "Setting $count rows to $model / $format..." ); + $dbw->update( + $table, + array( $model_column => $model, $format_column => $format ), + array( $key => $ids ), + __METHOD__ + ); + $this->output( "done.\n" ); + } + + protected function populateRevisionOrArchive( DatabaseBase $dbw, $table, $ns ) { + $prefix = $table === 'archive' ? 'ar' : 'rev'; + $model_column = "{$prefix}_content_model"; + $format_column = "{$prefix}_content_format"; + $key = "{$prefix}_id"; + if ( $table === 'archive' ) { + $selectTables = 'archive'; + $fields = array( 'ar_namespace', 'ar_title' ); + $join_conds = array(); + $where = $ns === 'all' ? array() : array( 'ar_namespace' => $ns ); + } else { // revision + $selectTables = array( 'revision', 'page' ); + $fields = array( 'page_title', 'page_namespace' ); + $join_conds = array( 'page' => array( 'INNER JOIN', 'rev_page=page_id' ) ); + $where = $ns === 'all' ? array() : array( 'page_namespace' => $ns ); + } + + $toSave = array(); + $lastId = 0; + do { + $rows = $dbw->select( + $selectTables, + array_merge( $fields, array( $model_column, $format_column, $key ) ), + // @todo support populating format if model is already set + array( + $model_column => null, + "$key > " . $dbw->addQuotes( $lastId ), + ) + $where, + __METHOD__, + array( 'LIMIT' => $this->mBatchSize, 'ORDER BY' => "$key ASC" ), + $join_conds + ); + $this->output( "Fetched {$rows->numRows()} rows.\n" ); + foreach ( $rows as $row ) { + if ( $table === 'archive' ) { + $title = Title::makeTitle( $row->ar_namespace, $row->ar_title ); + } else { + $title = Title::newFromRow( $row ); + } + $lastId = $row->{$key}; + try { + $handler = ContentHandler::getForTitle( $title ); + } catch ( MWException $e ) { + $this->error( "Invalid content model for $title" ); + continue; + } + $defaultModel = $handler->getModelID(); + $defaultFormat = $handler->getDefaultFormat(); + $dbModel = $row->{$model_column}; + $dbFormat = $row->{$format_column}; + $id = $row->{$key}; + if ( $dbModel === null && $dbFormat === null ) { + // Set the defaults + $toSave[$defaultModel][] = $row->{$key}; + } else { // $dbModel === null, $dbFormat set. + if ( $dbFormat === $defaultFormat ) { + $toSave[$defaultModel][] = $row->{$key}; + } else { // non-default format, just update now + $this->output( "Updating model to match format for $table $id of $title... "); + $dbw->update( + $table, + array( $model_column => $defaultModel ), + array( $key => $id ), + __METHOD__ + ); + wfWaitForSlaves(); + $this->output( "done.\n" ); + continue; + } + } + + if ( count( $toSave[$defaultModel] ) >= $this->mBatchSize ) { + $this->updateRevisionOrArchiveRows( $dbw, $toSave[$defaultModel], $defaultModel, $table ); + unset( $toSave[$defaultModel] ); + } + } + } while ( $rows->numRows() >= $this->mBatchSize ); + foreach ( $toSave as $model => $ids ) { + $this->updateRevisionOrArchiveRows( $dbw, $ids, $model, $table ); + } + } +} + +$maintClass = 'PopulateContentModel'; +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/maintenance/postgres/archives/patch-textsearch_bug66650.sql b/maintenance/postgres/archives/patch-textsearch_bug66650.sql new file mode 100644 index 00000000..e4f5681c --- /dev/null +++ b/maintenance/postgres/archives/patch-textsearch_bug66650.sql @@ -0,0 +1,5 @@ +UPDATE /*_*/pagecontent SET textvector=to_tsvector(old_text) +WHERE textvector IS NULL AND old_id IN +(SELECT max(rev_text_id) FROM revision GROUP BY rev_page); + +INSERT INTO /*_*/updatelog(ul_key) VALUES ('patch-textsearch_bug66650.sql'); diff --git a/maintenance/postgres/update-keys.sql b/maintenance/postgres/update-keys.sql index 7761d0c5..b8585515 100644 --- a/maintenance/postgres/update-keys.sql +++ b/maintenance/postgres/update-keys.sql @@ -27,3 +27,8 @@ INSERT INTO /*_*/updatelog (ul_key, ul_value) VALUES( 'user_former_groups-ufg_group-patch-ufg_group-length-increase-255.sql', null ); INSERT INTO /*_*/updatelog (ul_key, ul_value) VALUES( 'user_properties-up_property-patch-up_property.sql', null ); + +-- PostgreSQL-specific patches. + +INSERT INTO /*_*/updatelog (ul_key, ul_value) + VALUES( 'patch-textsearch_bug66650.sql', null ); diff --git a/maintenance/purgeChangedFiles.php b/maintenance/purgeChangedFiles.php index d21a296d..b98e95f4 100644 --- a/maintenance/purgeChangedFiles.php +++ b/maintenance/purgeChangedFiles.php @@ -166,7 +166,6 @@ class PurgeChangedFiles extends Maintenance { // 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 @@ -191,7 +190,6 @@ class PurgeChangedFiles extends Maintenance { $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" ); } } diff --git a/maintenance/rebuildFileCache.php b/maintenance/rebuildFileCache.php index 6ce54b9f..924457ae 100644 --- a/maintenance/rebuildFileCache.php +++ b/maintenance/rebuildFileCache.php @@ -131,9 +131,9 @@ class RebuildFileCache extends Maintenance { ob_start( array( &$cache, 'saveToFileCache' ) ); // save on ob_end_clean() $wgUseFileCache = false; // hack, we don't want $article fiddling with filecache $article->view(); - wfSuppressWarnings(); // header notices + MediaWiki\suppressWarnings(); // header notices $wgOut->output(); - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); $wgUseFileCache = true; ob_end_clean(); // clear buffer if ( $rebuilt ) { diff --git a/maintenance/rebuildImages.php b/maintenance/rebuildImages.php index 5a149678..8e399787 100644 --- a/maintenance/rebuildImages.php +++ b/maintenance/rebuildImages.php @@ -59,7 +59,6 @@ class ImageBuilder extends Maintenance { public function execute() { $this->dbw = wfGetDB( DB_MASTER ); - $this->maxLag = 10; # if slaves are lagged more than 10 secs, wait $this->dryrun = $this->hasOption( 'dry-run' ); if ( $this->dryrun ) { $GLOBALS['wgReadOnly'] = 'Dry run mode, image upgrades are suppressed'; diff --git a/maintenance/rebuildLocalisationCache.php b/maintenance/rebuildLocalisationCache.php index 47866dc0..f89877ea 100644 --- a/maintenance/rebuildLocalisationCache.php +++ b/maintenance/rebuildLocalisationCache.php @@ -48,14 +48,6 @@ class RebuildLocalisationCache extends Maintenance { false, true ); } - public function memoryLimit() { - if ( $this->hasOption( 'memory-limit' ) ) { - return parent::memoryLimit(); - } - - 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 diff --git a/maintenance/refreshLinks.php b/maintenance/refreshLinks.php index a2484aa3..06e1449e 100644 --- a/maintenance/refreshLinks.php +++ b/maintenance/refreshLinks.php @@ -73,7 +73,7 @@ class RefreshLinks extends Maintenance { private function doRefreshLinks( $start, $newOnly = false, $end = null, $redirectsOnly = false, $oldRedirectsOnly = false ) { - global $wgParser, $wgUseTidy; + global $wgParser; $reportingInterval = 100; $dbr = wfGetDB( DB_SLAVE ); @@ -83,14 +83,11 @@ class RefreshLinks extends Maintenance { } // Give extensions a chance to optimize settings - wfRunHooks( 'MaintenanceRefreshLinksInit', array( $this ) ); + Hooks::run( 'MaintenanceRefreshLinksInit', array( $this ) ); # Don't generate extension images (e.g. Timeline) $wgParser->clearTagHooks(); - # Don't use HTML tidy - $wgUseTidy = false; - $what = $redirectsOnly ? "redirects" : "links"; if ( $oldRedirectsOnly ) { @@ -344,17 +341,15 @@ class RefreshLinks extends Maintenance { $numIds = count( $ids ); if ( $numIds ) { $counter += $numIds; - wfWaitForSlaves(); $dbw->delete( $table, array( $field => $ids ), __METHOD__ ); $this->output( ", $counter" ); $tableStart = $ids[$numIds - 1] + 1; + wfWaitForSlaves(); } } while ( $numIds >= $batchSize && ( $end === null || $tableStart <= $end ) ); $this->output( " deleted.\n" ); - - wfWaitForSlaves(); } } diff --git a/maintenance/resources/update-oojs-ui.sh b/maintenance/resources/update-oojs-ui.sh index f6245f27..831e2dca 100644 --- a/maintenance/resources/update-oojs-ui.sh +++ b/maintenance/resources/update-oojs-ui.sh @@ -1,8 +1,8 @@ -#!/usr/bin/env bash +#!/bin/bash -eu # This script generates a commit that updates our copy of OOjs UI -if [ -n "$2" ] +if [ -n "${2:-}" ] then # Too many parameters echo >&2 "Usage: $0 [<version>]" @@ -14,18 +14,21 @@ TARGET_DIR="resources/lib/oojs-ui" # Destination relative to the root of the rep NPM_DIR=$(mktemp -d 2>/dev/null || mktemp -d -t 'update-oojs-ui') # e.g. /tmp/update-oojs-ui.rI0I5Vir # Prepare working tree -cd "$REPO_DIR" && -git reset composer.json && git checkout composer.json && -git reset $TARGET_DIR && git checkout $TARGET_DIR && git fetch origin && -git checkout -B upstream-oojs-ui origin/master || exit 1 +cd "$REPO_DIR" +git reset composer.json +git checkout composer.json +git reset -- $TARGET_DIR +git checkout -- $TARGET_DIR +git fetch origin +git checkout -B upstream-oojs-ui origin/master # Fetch upstream version cd $NPM_DIR -if [ -n "$1" ] +if [ -n "${1:-}" ] then - npm install "oojs-ui@$1" || exit 1 + npm install "oojs-ui@$1" else - npm install oojs-ui || exit 1 + npm install oojs-ui fi OOJSUI_VERSION=$(node -e 'console.log(require("./node_modules/oojs-ui/package.json").version);') @@ -35,24 +38,27 @@ then exit 1 fi -# Copy files, excluding: -# * the Apex theme files, -# * the minimised distribution files, and -# * the RTL sheets for non-CSSJanus environments -# * the raster- and vector-only distribution sheets -rsync --force --recursive --delete \ - --exclude '*apex*' \ - --exclude 'oojs-ui*.min.*' \ - --exclude 'oojs-ui*.rtl.css' \ - --exclude 'oojs-ui*.raster.css' \ - --exclude 'oojs-ui*.vector.css' \ - ./node_modules/oojs-ui/dist/ "$REPO_DIR/$TARGET_DIR" || exit 1 +# Copy files, picking the necessary ones from source and distribution +rm -r "$REPO_DIR/$TARGET_DIR" +mkdir -p "$REPO_DIR/$TARGET_DIR/i18n" +mkdir -p "$REPO_DIR/$TARGET_DIR/images" +mkdir -p "$REPO_DIR/$TARGET_DIR/themes/mediawiki/images" +mkdir -p "$REPO_DIR/$TARGET_DIR/themes/apex/images" +cp ./node_modules/oojs-ui/dist/oojs-ui.js "$REPO_DIR/$TARGET_DIR" +cp ./node_modules/oojs-ui/dist/{oojs-ui-mediawiki-noimages.css,oojs-ui-mediawiki.js} "$REPO_DIR/$TARGET_DIR" +cp ./node_modules/oojs-ui/dist/{oojs-ui-apex-noimages.css,oojs-ui-apex.js} "$REPO_DIR/$TARGET_DIR" +cp -R ./node_modules/oojs-ui/dist/i18n "$REPO_DIR/$TARGET_DIR" +cp -R ./node_modules/oojs-ui/dist/images "$REPO_DIR/$TARGET_DIR" +cp -R ./node_modules/oojs-ui/dist/themes/mediawiki/images "$REPO_DIR/$TARGET_DIR/themes/mediawiki" +cp ./node_modules/oojs-ui/src/themes/mediawiki/*.json "$REPO_DIR/$TARGET_DIR/themes/mediawiki" +cp -R ./node_modules/oojs-ui/dist/themes/apex/images "$REPO_DIR/$TARGET_DIR/themes/apex" +cp ./node_modules/oojs-ui/src/themes/apex/*.json "$REPO_DIR/$TARGET_DIR/themes/apex" # Clean up temporary area rm -rf "$NPM_DIR" # Generate commit -cd $REPO_DIR || exit 1 +cd $REPO_DIR COMMITMSG=$(cat <<END Update OOjs UI to v$OOJSUI_VERSION @@ -66,4 +72,7 @@ END composer require oojs/oojs-ui $OOJSUI_VERSION --no-update # Stage deletion, modification and creation of files. Then commit. -git add --update $TARGET_DIR && git add $TARGET_DIR && git add composer.json && git commit -m "$COMMITMSG" || exit 1 +git add --update $TARGET_DIR +git add $TARGET_DIR +git add composer.json +git commit -m "$COMMITMSG" diff --git a/maintenance/resources/update-oojs.sh b/maintenance/resources/update-oojs.sh index 1d5c2b17..b91cb281 100644 --- a/maintenance/resources/update-oojs.sh +++ b/maintenance/resources/update-oojs.sh @@ -1,8 +1,8 @@ -#!/usr/bin/env bash +#!/bin/bash -eu # This script generates a commit that updates our copy of OOjs -if [ -n "$2" ] +if [ -n "${2:-}" ] then # Too many parameters echo >&2 "Usage: $0 [<version>]" @@ -14,17 +14,19 @@ TARGET_DIR="resources/lib/oojs" # Destination relative to the root of the repo NPM_DIR=$(mktemp -d 2>/dev/null || mktemp -d -t 'update-oojs') # e.g. /tmp/update-oojs.rI0I5Vir # Prepare working tree -cd "$REPO_DIR" && -git reset $TARGET_DIR && git checkout $TARGET_DIR && git fetch origin && -git checkout -B upstream-oojs origin/master || exit 1 +cd "$REPO_DIR" +git reset -- $TARGET_DIR +git checkout -- $TARGET_DIR +git fetch origin +git checkout -B upstream-oojs origin/master # Fetch upstream version cd $NPM_DIR -if [ -n "$1" ] +if [ -n "${1:-}" ] then - npm install "oojs@$1" || exit 1 + npm install "oojs@$1" else - npm install oojs || exit 1 + npm install oojs fi OOJS_VERSION=$(node -e 'console.log(require("./node_modules/oojs/package.json").version);') @@ -35,13 +37,13 @@ then fi # Copy file(s) -rsync --force ./node_modules/oojs/dist/oojs.jquery.js "$REPO_DIR/$TARGET_DIR" || exit 1 +rsync --force ./node_modules/oojs/dist/oojs.jquery.js "$REPO_DIR/$TARGET_DIR" # Clean up temporary area rm -rf "$NPM_DIR" # Generate commit -cd $REPO_DIR || exit 1 +cd $REPO_DIR COMMITMSG=$(cat <<END Update OOjs to v$OOJS_VERSION @@ -52,4 +54,6 @@ END ) # Stage deletion, modification and creation of files. Then commit. -git add --update $TARGET_DIR && git add $TARGET_DIR && git commit -m "$COMMITMSG" || exit 1 +git add --update $TARGET_DIR +git add $TARGET_DIR +git commit -m "$COMMITMSG" diff --git a/maintenance/runJobs.php b/maintenance/runJobs.php index 3864e3c6..3c5d28be 100644 --- a/maintenance/runJobs.php +++ b/maintenance/runJobs.php @@ -52,9 +52,7 @@ class RunJobs extends Maintenance { } public function execute() { - if ( wfReadOnly() ) { - $this->error( "Unable to run jobs; the wiki is in read-only mode.", 1 ); // die - } + global $wgCommandLineMode; if ( $this->hasOption( 'procs' ) ) { $procs = intval( $this->getOption( 'procs' ) ); @@ -68,21 +66,29 @@ class RunJobs extends Maintenance { } } - $json = ( $this->getOption( 'result' ) === 'json' ); + $outputJSON = ( $this->getOption( 'result' ) === 'json' ); + + // Enable DBO_TRX for atomicity; JobRunner manages transactions + // and works well in web server mode already (@TODO: this is a hack) + $wgCommandLineMode = false; $runner = new JobRunner( LoggerFactory::getInstance( 'runJobs' ) ); - if ( !$json ) { + if ( !$outputJSON ) { $runner->setDebugHandler( array( $this, 'debugInternal' ) ); } + $response = $runner->run( array( 'type' => $this->getOption( 'type', false ), 'maxJobs' => $this->getOption( 'maxjobs', false ), 'maxTime' => $this->getOption( 'maxtime', false ), 'throttle' => $this->hasOption( 'nothrottle' ) ? false : true, ) ); - if ( $json ) { + + if ( $outputJSON ) { $this->output( FormatJson::encode( $response, true ) ); } + + $wgCommandLineMode = true; } /** diff --git a/maintenance/showJobs.php b/maintenance/showJobs.php index 9e9ad327..25a096c0 100644 --- a/maintenance/showJobs.php +++ b/maintenance/showJobs.php @@ -34,39 +34,53 @@ require_once __DIR__ . '/Maintenance.php'; * @ingroup Maintenance */ class ShowJobs extends Maintenance { + protected static $stateMethods = array( + 'unclaimed' => 'getAllQueuedJobs', + 'delayed' => 'getAllDelayedJobs', + 'claimed' => 'getAllAcquiredJobs', + 'abandoned' => 'getAllAbandonedJobs', + ); + public function __construct() { 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 list of all jobs in a machine-readable format, instead of statistics' ); + $this->addOption( 'list', 'Show a list of all jobs instead of counts' ); $this->addOption( 'type', 'Only show/count jobs of a given type', false, true ); + $this->addOption( 'status', 'Filter list by state (unclaimed,delayed,claimed,abandoned)' ); + $this->addOption( 'limit', 'Limit of jobs listed' ); } public function execute() { - $filterType = $this->getOption( 'type', '' ); + $typeFilter = $this->getOption( 'type', '' ); + $stateFilter = $this->getOption( 'status', '' ); + $stateLimit = (float)$this->getOption( 'limit', INF ); + $group = JobQueueGroup::singleton(); + + $filteredTypes = $typeFilter + ? array( $typeFilter ) + : $group->getQueueTypes(); + $filteredStates = $stateFilter + ? array_intersect_key( self::$stateMethods, array( $stateFilter => 1 ) ) + : self::$stateMethods; + if ( $this->hasOption( 'list' ) ) { - foreach ( $group->getQueueTypes() as $type ) { - if ( $filterType != '' && $type != $filterType ) { - continue; - } + $count = 0; + foreach ( $filteredTypes 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" ); - } - foreach ( $queue->getAllAbandonedJobs() as $job ) { - $this->output( $job->toString() . " status=abandoned\n" ); + foreach ( $filteredStates as $state => $method ) { + foreach ( $queue->$method() as $job ) { + /** @var Job $job */ + $this->output( $job->toString() . " status=$state\n" ); + if ( ++$count >= $stateLimit ) { + return; + } + } } } } elseif ( $this->hasOption( 'group' ) ) { - foreach ( $group->getQueueTypes() as $type ) { - if ( $filterType != '' && $type != $filterType ) { - continue; - } + foreach ( $filteredTypes as $type ) { $queue = $group->get( $type ); $delayed = $queue->getDelayedCount(); $pending = $queue->getSize(); @@ -83,10 +97,7 @@ class ShowJobs extends Maintenance { } } else { $count = 0; - foreach ( $group->getQueueTypes() as $type ) { - if ( $filterType != '' && $type != $filterType ) { - continue; - } + foreach ( $filteredTypes as $type ) { $count += $group->get( $type )->getSize(); } $this->output( "$count\n" ); diff --git a/maintenance/sql.php b/maintenance/sql.php index 886e3f10..a93e51fe 100644 --- a/maintenance/sql.php +++ b/maintenance/sql.php @@ -32,7 +32,9 @@ require_once __DIR__ . '/Maintenance.php'; class MwSql extends Maintenance { public function __construct() { parent::__construct(); - $this->mDescription = "Send SQL queries to a MediaWiki database"; + $this->mDescription = "Send SQL queries to a MediaWiki database. " . + "Takes a file name containing SQL as argument or runs interactively."; + $this->addOption( 'query', 'Run a single query instead of running interactively', false, true ); $this->addOption( 'cluster', 'Use an external cluster by name', false, true ); $this->addOption( 'wikidb', 'The database wiki ID to use if not the current one', false, true ); $this->addOption( 'slave', 'Use a slave server (either "any" or by name)', false, true ); @@ -88,6 +90,13 @@ class MwSql extends Maintenance { } } + if ( $this->hasOption( 'query' ) ) { + $query = $this->getOption( 'query' ); + $this->sqlDoQuery( $db, $query, /* dieOnError */ true ); + wfWaitForSlaves(); + return; + } + $useReadline = function_exists( 'readline_add_history' ) && Maintenance::posix_isatty( 0 /*STDIN*/ ); @@ -101,6 +110,7 @@ class MwSql extends Maintenance { $wholeLine = ''; $newPrompt = '> '; $prompt = $newPrompt; + $doDie = !Maintenance::posix_isatty( 0 ); while ( ( $line = Maintenance::readconsole( $prompt ) ) !== false ) { if ( !$line ) { # User simply pressed return key @@ -121,19 +131,22 @@ class MwSql extends Maintenance { readline_add_history( $wholeLine . $db->getDelimiter() ); readline_write_history( $historyFile ); } - try { - $res = $db->query( $wholeLine ); - $this->sqlPrintResult( $res, $db ); - $prompt = $newPrompt; - $wholeLine = ''; - } catch ( DBQueryError $e ) { - $doDie = !Maintenance::posix_isatty( 0 ); - $this->error( $e, $doDie ); - } + $this->sqlDoQuery( $db, $wholeLine, $doDie ); + $prompt = $newPrompt; + $wholeLine = ''; } wfWaitForSlaves(); } + protected function sqlDoQuery( $db, $line, $dieOnError ) { + try { + $res = $db->query( $line ); + $this->sqlPrintResult( $res, $db ); + } catch ( DBQueryError $e ) { + $this->error( $e, $dieOnError ); + } + } + /** * Print the results, callback for $db->sourceStream() * @param ResultWrapper $res The results object diff --git a/maintenance/sqlite.php b/maintenance/sqlite.php index 7e02a4b2..b11f1c8b 100644 --- a/maintenance/sqlite.php +++ b/maintenance/sqlite.php @@ -117,12 +117,12 @@ class SqliteMaintenance extends Maintenance { $this->db->query( 'BEGIN IMMEDIATE TRANSACTION', __METHOD__ ); $ourFile = $this->db->getDbFilePath(); $this->output( " Copying database file $ourFile to $fileName... " ); - wfSuppressWarnings( false ); + MediaWiki\suppressWarnings( false ); if ( !copy( $ourFile, $fileName ) ) { $err = error_get_last(); $this->error( " {$err['message']}" ); } - wfSuppressWarnings( true ); + MediaWiki\suppressWarnings( true ); $this->output( " Releasing lock...\n" ); $this->db->query( 'COMMIT TRANSACTION', __METHOD__ ); } diff --git a/maintenance/storage/fixBug20757.php b/maintenance/storage/fixBug20757.php index d2fe3b42..dd4cd54b 100644 --- a/maintenance/storage/fixBug20757.php +++ b/maintenance/storage/fixBug20757.php @@ -312,9 +312,9 @@ class FixBug20757 extends Maintenance { $text = $secondaryRow->old_text; if ( in_array( 'external', $flags ) ) { $url = $text; - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); list( /* $proto */, $path ) = explode( '://', $url, 2 ); - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); if ( $path == "" ) { return false; diff --git a/maintenance/storage/recompressTracked.php b/maintenance/storage/recompressTracked.php index 3562df62..b2139294 100644 --- a/maintenance/storage/recompressTracked.php +++ b/maintenance/storage/recompressTracked.php @@ -234,9 +234,9 @@ class RecompressTracked { array( 'file', 'php://stdout', 'w' ), array( 'file', 'php://stderr', 'w' ) ); - wfSuppressWarnings(); + MediaWiki\suppressWarnings(); $proc = proc_open( "$cmd --slave-id $i", $spec, $pipes ); - wfRestoreWarnings(); + MediaWiki\restoreWarnings(); if ( !$proc ) { $this->critical( "Error opening slave process: $cmd" ); exit( 1 ); diff --git a/maintenance/syncFileBackend.php b/maintenance/syncFileBackend.php index 14a1502f..63d5e9f8 100644 --- a/maintenance/syncFileBackend.php +++ b/maintenance/syncFileBackend.php @@ -159,6 +159,7 @@ class SyncFileBackend extends Maintenance { $this->error( "Error: given starting ID greater than ending ID.", 1 ); } + $next = null; do { $limit = min( $this->mBatchSize, $end - $start + 1 ); // don't go pass ending ID $this->output( "Doing id $start to " . ( $start + $limit - 1 ) . "...\n" ); diff --git a/maintenance/tables.sql b/maintenance/tables.sql index bf93a232..aa0c7ea9 100644 --- a/maintenance/tables.sql +++ b/maintenance/tables.sql @@ -3,7 +3,9 @@ -- not have to run it by itself unless doing a manual install. -- This is a shared schema file used for both MySQL and SQLite installs. - +-- +-- For more documentation on the database schema, see +-- https://www.mediawiki.org/wiki/Manual:Database_layout -- -- General notes: -- @@ -490,7 +492,7 @@ CREATE TABLE /*_*/pagelinks ( CREATE UNIQUE INDEX /*i*/pl_from ON /*_*/pagelinks (pl_from,pl_namespace,pl_title); CREATE INDEX /*i*/pl_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from); -CREATE INDEX /*i*/pl_backlinks_namespace ON /*_*/pagelinks (pl_namespace,pl_title,pl_from_namespace,pl_from); +CREATE INDEX /*i*/pl_backlinks_namespace ON /*_*/pagelinks (pl_from_namespace,pl_namespace,pl_title,pl_from); -- @@ -512,7 +514,7 @@ CREATE TABLE /*_*/templatelinks ( CREATE UNIQUE INDEX /*i*/tl_from ON /*_*/templatelinks (tl_from,tl_namespace,tl_title); CREATE INDEX /*i*/tl_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from); -CREATE INDEX /*i*/tl_backlinks_namespace ON /*_*/templatelinks (tl_namespace,tl_title,tl_from_namespace,tl_from); +CREATE INDEX /*i*/tl_backlinks_namespace ON /*_*/templatelinks (tl_from_namespace,tl_namespace,tl_title,tl_from); -- @@ -534,7 +536,7 @@ CREATE TABLE /*_*/imagelinks ( CREATE UNIQUE INDEX /*i*/il_from ON /*_*/imagelinks (il_from,il_to); CREATE INDEX /*i*/il_to ON /*_*/imagelinks (il_to,il_from); -CREATE INDEX /*i*/il_backlinks_namespace ON /*_*/imagelinks (il_to,il_from_namespace,il_from); +CREATE INDEX /*i*/il_backlinks_namespace ON /*_*/imagelinks (il_from_namespace,il_to,il_from); -- diff --git a/maintenance/update.php b/maintenance/update.php index 7e0748be..452b53cd 100644 --- a/maintenance/update.php +++ b/maintenance/update.php @@ -4,7 +4,6 @@ * Run all updaters. * * This is used when the database schema is modified and we need to apply patches. - * It is kept compatible with php 4 parsing so that it can give out a meaningful error. * * 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 @@ -58,13 +57,11 @@ class UpdateMediaWiki extends Maintenance { } function getDbType() { - /* If we used the class constant PHP4 would give a parser error here */ - return 2; /* Maintenance::DB_ADMIN */ + return Maintenance::DB_ADMIN; } function compatChecks() { - // Avoid syntax error in PHP4 - $minimumPcreVersion = constant( 'Installer::MINIMUM_PCRE_VERSION' ); + $minimumPcreVersion = Installer::MINIMUM_PCRE_VERSION; list( $pcreVersion ) = explode( ' ', PCRE_VERSION, 2 ); if ( version_compare( $pcreVersion, $minimumPcreVersion, '<' ) ) { @@ -121,7 +118,7 @@ class UpdateMediaWiki extends Maintenance { $this->output( "MediaWiki {$wgVersion} Updater\n\n" ); - wfWaitForSlaves( 5 ); // let's not kill databases, shall we? ;) --tor + wfWaitForSlaves(); if ( !$this->hasOption( 'skip-compat-checks' ) ) { $this->compatChecks(); @@ -156,7 +153,7 @@ class UpdateMediaWiki extends Maintenance { wfCountDown( 5 ); } - $time1 = new MWTimestamp(); + $time1 = microtime( true ); $shared = $this->hasOption( 'doshared' ); @@ -175,7 +172,7 @@ class UpdateMediaWiki extends Maintenance { $child = $this->runChild( $maint ); // LoggedUpdateMaintenance is checking the updatelog itself - $isLoggedUpdate = is_a( $child, 'LoggedUpdateMaintenance' ); + $isLoggedUpdate = $child instanceof LoggedUpdateMaintenance; if ( !$isLoggedUpdate && $updater->updateRowExists( $maint ) ) { continue; @@ -192,9 +189,10 @@ class UpdateMediaWiki extends Maintenance { $updater->purgeCache(); } - $time2 = new MWTimestamp(); - $timeDiff = $time2->diff( $time1 ); - $this->output( "\nDone in " . $timeDiff->format( "%i:%S" ) . ".\n" ); + $time2 = microtime( true ); + + $timeDiff = $wgLang->formatTimePeriod( $time2 - $time1 ); + $this->output( "\nDone in $timeDiff.\n" ); } function afterFinalSetup() { diff --git a/maintenance/updateCollation.php b/maintenance/updateCollation.php index 342ffbad..5cf8afa9 100644 --- a/maintenance/updateCollation.php +++ b/maintenance/updateCollation.php @@ -24,8 +24,6 @@ * @author Aryeh Gregor (Simetrical) */ -#$optionsWithArgs = array( 'begin', 'max-slave-lag' ); - require_once __DIR__ . '/Maintenance.php'; /** diff --git a/maintenance/validateRegistrationFile.php b/maintenance/validateRegistrationFile.php index e7646610..9cf7b2bd 100644 --- a/maintenance/validateRegistrationFile.php +++ b/maintenance/validateRegistrationFile.php @@ -12,18 +12,39 @@ class ValidateRegistrationFile extends Maintenance { $this->error( 'The JsonSchema library cannot be found, please install it through composer.', 1 ); } - $retriever = new JsonSchema\Uri\UriRetriever(); - $schema = $retriever->retrieve('file://' . dirname( __DIR__ ) . '/docs/extension.schema.json' ); $path = $this->getArg( 0 ); $data = json_decode( file_get_contents( $path ) ); if ( !is_object( $data ) ) { $this->error( "$path is not a valid JSON file.", 1 ); } + if ( !isset( $data->manifest_version ) ) { + $this->output( "Warning: No manifest_version set, assuming 1.\n" ); + // For backwards-compatability assume 1 + $data->manifest_version = 1; + } + $version = $data->manifest_version; + if ( $version !== ExtensionRegistry::MANIFEST_VERSION ) { + $schemaPath = dirname( __DIR__ ) . "/docs/extension.schema.v$version.json"; + } else { + $schemaPath = dirname( __DIR__ ) . '/docs/extension.schema.json'; + } + + if ( $version < ExtensionRegistry::OLDEST_MANIFEST_VERSION + || $version > ExtensionRegistry::MANIFEST_VERSION + ) { + $this->error( "Error: $path is using a non-supported schema version, it should use " + . ExtensionRegistry::MANIFEST_VERSION, 1 ); + } elseif ( $version < ExtensionRegistry::MANIFEST_VERSION ) { + $this->output( "Warning: $path is using a deprecated schema, and should be updated to " + . ExtensionRegistry::MANIFEST_VERSION . "\n" ); + } + $retriever = new JsonSchema\Uri\UriRetriever(); + $schema = $retriever->retrieve( 'file://' . $schemaPath ); $validator = new JsonSchema\Validator(); $validator->check( $data, $schema ); if ( $validator->isValid() ) { - $this->output( "$path validates against the schema!\n" ); + $this->output( "$path validates against the version $version schema!\n" ); } else { foreach ( $validator->getErrors() as $error ) { $this->output( "[{$error['property']}] {$error['message']}\n" ); diff --git a/maintenance/waitForSlave.php b/maintenance/waitForSlave.php index c9b1abba..50665ef2 100644 --- a/maintenance/waitForSlave.php +++ b/maintenance/waitForSlave.php @@ -1,6 +1,6 @@ <?php /** - * Wait until slave lag goes under a certain value. + * Wait for the slaves to catch up to the master position. * * 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 @@ -25,18 +25,13 @@ require_once __DIR__ . '/Maintenance.php'; /** - * Maintenance script to wait until slave lag goes under a certain value. + * Maintenance script to wait for the slaves to catch up to the master position. * * @ingroup Maintenance */ 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() { - wfWaitForSlaves( $this->getArg( 0, 10 ) ); + wfWaitForSlaves(); } } |