summaryrefslogtreecommitdiff
path: root/maintenance
diff options
context:
space:
mode:
Diffstat (limited to 'maintenance')
-rw-r--r--maintenance/Maintenance.php25
-rw-r--r--maintenance/archives/patch-il_from_namespace.sql2
-rw-r--r--maintenance/archives/patch-pl_from_namespace.sql2
-rw-r--r--maintenance/archives/patch-tl_from_namespace.sql2
-rw-r--r--maintenance/backup.inc4
-rw-r--r--maintenance/backupTextPass.inc8
-rw-r--r--maintenance/benchmarks/benchmarkHooks.php2
-rw-r--r--maintenance/checkComposerLockUpToDate.php2
-rw-r--r--maintenance/checkImages.php20
-rw-r--r--maintenance/checkSyntax.php4
-rw-r--r--maintenance/checkUsernames.php2
-rw-r--r--maintenance/cleanupRemovedModules.php14
-rw-r--r--maintenance/cleanupTable.inc1
-rw-r--r--maintenance/cleanupUploadStash.php1
-rw-r--r--maintenance/convertExtensionToRegistration.php39
-rw-r--r--maintenance/copyFileBackend.php12
-rw-r--r--maintenance/createAndPromote.php21
-rw-r--r--maintenance/deleteArchivedFiles.inc84
-rw-r--r--maintenance/deleteArchivedFiles.php79
-rw-r--r--maintenance/deleteArchivedRevisions.inc61
-rw-r--r--maintenance/deleteArchivedRevisions.php28
-rw-r--r--maintenance/deleteBatch.php4
-rw-r--r--maintenance/deleteDefaultMessages.php5
-rw-r--r--maintenance/deleteEqualMessages.php12
-rw-r--r--maintenance/deleteImageMemcached.php89
-rw-r--r--maintenance/dictionary/mediawiki.dic6
-rw-r--r--maintenance/eraseArchivedFile.php1
-rw-r--r--maintenance/exportSites.php8
-rw-r--r--maintenance/findHooks.php15
-rw-r--r--maintenance/fixDefaultJsonContentPages.php128
-rw-r--r--maintenance/fixSlaveDesync.php246
-rw-r--r--maintenance/generateJsonI18n.php134
-rw-r--r--maintenance/getConfiguration.php2
-rw-r--r--maintenance/importImages.php12
-rw-r--r--maintenance/importSites.php6
-rw-r--r--maintenance/install.php8
-rw-r--r--maintenance/interwiki.list1
-rw-r--r--maintenance/interwiki.sql1
-rw-r--r--maintenance/jsduck/categories.json19
-rw-r--r--maintenance/jsduck/custom_tags.rb4
-rw-r--r--maintenance/jsduck/eg-iframe.html2
-rw-r--r--maintenance/jsduck/external.js1
-rw-r--r--maintenance/jsparse.php4
-rw-r--r--maintenance/language/StatOutputs.php8
-rw-r--r--maintenance/language/checkLanguage.inc2
-rw-r--r--maintenance/language/generateNormalizerDataAr.php3
-rw-r--r--maintenance/language/generateNormalizerDataMl.php3
-rw-r--r--maintenance/language/languages.inc2
-rw-r--r--maintenance/language/zhtable/Makefile.py13
-rw-r--r--maintenance/language/zhtable/simp2trad.manual5
-rw-r--r--maintenance/language/zhtable/simp2trad_noconvert.manual7
-rw-r--r--maintenance/language/zhtable/simpphrases.manual30
-rw-r--r--maintenance/language/zhtable/simpphrases_exclude.manual5
-rw-r--r--maintenance/language/zhtable/symme_supp.manual4
-rw-r--r--maintenance/language/zhtable/toCN.manual224
-rw-r--r--maintenance/language/zhtable/toHK.manual233
-rw-r--r--maintenance/language/zhtable/toSimp.manual34
-rw-r--r--maintenance/language/zhtable/toTW.manual88
-rw-r--r--maintenance/language/zhtable/toTrad.manual86
-rw-r--r--maintenance/language/zhtable/trad2simp.manual50
-rw-r--r--maintenance/language/zhtable/trad2simp_noconvert.manual6
-rw-r--r--maintenance/language/zhtable/tradphrases.manual479
-rw-r--r--maintenance/language/zhtable/tradphrases_exclude.manual43
-rw-r--r--maintenance/migrateFileRepoLayout.php232
-rw-r--r--maintenance/namespaceDupes.php190
-rw-r--r--maintenance/parse.php3
-rw-r--r--maintenance/populateCategory.php10
-rw-r--r--maintenance/populateContentModel.php207
-rw-r--r--maintenance/postgres/archives/patch-textsearch_bug66650.sql5
-rw-r--r--maintenance/postgres/update-keys.sql5
-rw-r--r--maintenance/purgeChangedFiles.php2
-rw-r--r--maintenance/rebuildFileCache.php4
-rw-r--r--maintenance/rebuildImages.php1
-rw-r--r--maintenance/rebuildLocalisationCache.php8
-rw-r--r--maintenance/refreshLinks.php11
-rw-r--r--maintenance/resources/update-oojs-ui.sh55
-rw-r--r--maintenance/resources/update-oojs.sh26
-rw-r--r--maintenance/runJobs.php18
-rw-r--r--maintenance/showJobs.php57
-rw-r--r--maintenance/sql.php33
-rw-r--r--maintenance/sqlite.php4
-rw-r--r--maintenance/storage/fixBug20757.php4
-rw-r--r--maintenance/storage/recompressTracked.php4
-rw-r--r--maintenance/syncFileBackend.php1
-rw-r--r--maintenance/tables.sql10
-rw-r--r--maintenance/update.php20
-rw-r--r--maintenance/updateCollation.php2
-rw-r--r--maintenance/validateRegistrationFile.php27
-rw-r--r--maintenance/waitForSlave.php11
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();
}
}