From: jenkins-bot Date: Tue, 7 Apr 2015 20:33:43 +0000 (+0000) Subject: Merge "mime.types: allow bzip2 upload" X-Git-Tag: 1.31.0-rc.0~11792 X-Git-Url: http://git.cyclocoop.org/%27.parametre_url%28%20%20%20generer_action_auteur%28%27charger_plugin%27%2C%20%27update_flux%27%29%2C%27update_flux%27%2C%20%27oui%27%29.%27?a=commitdiff_plain;h=6dae212c2e8e5eab4340144a7097e075af4dbf8a;hp=f42f08060f2e4aba16422f95889790db228920af;p=lhc%2Fweb%2Fwiklou.git Merge "mime.types: allow bzip2 upload" --- diff --git a/.jshintrc b/.jshintrc index d77ffb81f7..4bb244030c 100644 --- a/.jshintrc +++ b/.jshintrc @@ -22,6 +22,7 @@ "mediaWiki": true, "JSON": true, "jQuery": false, - "QUnit": false + "QUnit": false, + "sinon": false } } diff --git a/.rubocop.yml b/.rubocop.yml index 3f1af395be..61ffc1a044 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,13 +1,9 @@ -inherit_from: .rubocop_todo.yml - -AllCops: - Exclude: - - 'extensions/**/*' - - 'skins/**/*' - - 'tests/frontend/node_modules/**/*' - - 'vendor/**/*' - AllCops: + Exclude: + - 'extensions/**/*' + - 'skins/**/*' + - 'tests/frontend/node_modules/**/*' + - 'vendor/**/*' StyleGuideCopsOnly: true Metrics/LineLength: diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml deleted file mode 100644 index 58cee0c18f..0000000000 --- a/.rubocop_todo.yml +++ /dev/null @@ -1,33 +0,0 @@ -# This configuration was generated by `rubocop --auto-gen-config` -# on 2015-03-06 17:05:39 +0100 using RuboCop version 0.29.1. -# The point is for the user to remove these configuration records -# one by one as the offenses are removed from the code base. -# Note that changes in the inspected code, or installation of new -# versions of RuboCop, may require this file to be generated again. - -# Offense count: 2 -# Cop supports --auto-correct. -Lint/UnusedMethodArgument: - Enabled: false - -# Offense count: 1 -# Configuration parameters: Exclude. -Style/FileName: - Enabled: false - -# Offense count: 8 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -Style/HashSyntax: - Enabled: false - -# Offense count: 4 -# Cop supports --auto-correct. -Style/PerlBackrefs: - Enabled: false - -# Offense count: 81 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -Style/StringLiterals: - Enabled: false diff --git a/CREDITS b/CREDITS index f58fabb15e..54890fe32b 100644 --- a/CREDITS +++ b/CREDITS @@ -56,6 +56,7 @@ following names for their contribution to the product. * Marius Hoch * Matěj Grabovský * Matt Johnston +* Matthew Flaschen * Max Semenik * Meno25 * MinuteElectron diff --git a/Gemfile b/Gemfile index 4373b7f9de..6f9c0539e0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ # ruby=ruby-2.1.2 # ruby-gemset=core -source "https://rubygems.org" +source 'https://rubygems.org' -gem "mediawiki_selenium", "~> 1.0.1" -gem "rubocop", require: false +gem 'mediawiki_selenium', '~> 1.0.1' +gem 'rubocop', require: false diff --git a/Gruntfile.js b/Gruntfile.js index a292d0b377..573db69afb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -76,7 +76,9 @@ module.exports = function ( grunt ) { frameworks: [ 'qunit' ], reporters: [ 'dots' ], singleRun: true, - autoWatch: false + autoWatch: false, + // Some tests in extensions don't yield for more than the default 10s (T89075) + browserNoActivityTimeout: 60 * 1000 }, main: { browsers: [ 'Chrome' ] @@ -97,8 +99,21 @@ module.exports = function ( grunt ) { } } ); + grunt.registerTask( 'assert-mw-env', function () { + if ( !process.env.MW_SERVER ) { + grunt.log.error( 'Environment variable MW_SERVER must be set.\n' + + 'Set this like $wgServer, e.g. "http://localhost"' + ); + } + if ( !process.env.MW_SCRIPT_PATH ) { + grunt.log.error( 'Environment variable MW_SCRIPT_PATH must be set.\n' + + 'Set this like $wgScriptPath, e.g. "/w"'); + } + return !!( process.env.MW_SERVER && process.env.MW_SCRIPT_PATH ); + } ); + grunt.registerTask( 'lint', ['jshint', 'jscs', 'jsonlint', 'banana'] ); - grunt.registerTask( 'qunit', 'karma:main' ); + grunt.registerTask( 'qunit', [ 'assert-mw-env', 'karma:main' ] ); grunt.registerTask( 'test', ['lint'] ); grunt.registerTask( 'default', 'test' ); diff --git a/HISTORY b/HISTORY index e5864fd670..6ea5c2e0a8 100644 --- a/HISTORY +++ b/HISTORY @@ -190,6 +190,10 @@ Change notes from older releases. For current info see RELEASE-NOTES-1.25. to multiple Config instances. * Update CSSJanus to v1.1.0. * Added FormatJson::parse() returning status with result or localized error message +* Added DeletedContribsPager::reallyDoQuery hook allowing extensions to data to + Special:DeletedContributions +* Added DeletedContributionsLineEnding hook allowing extensions to format + Special:DeletedContributions lines === Bug fixes in 1.24 === * (bug 50572) MediaWiki:Blockip should support gender diff --git a/INSTALL b/INSTALL index 70d8d53071..2054a57e83 100644 --- a/INSTALL +++ b/INSTALL @@ -8,10 +8,11 @@ Starting with MediaWiki 1.2.0, it's possible to install and configure the wiki Required software: * Web server with PHP 5.3.3 or higher. * A SQL server, the following types are supported -** MySQL 5.0.2 or higher +** MySQL 5.0.3 or higher ** PostgreSQL 8.3 or higher ** SQLite 3.3.7 or higher ** Oracle 9.0.1 or higher +** Microsoft SQL Server 2005 (9.00.1399) MediaWiki is developed and tested mainly on Unix/Linux platforms, but should work on Windows as well. diff --git a/RELEASE-NOTES-1.25 b/RELEASE-NOTES-1.25 index 5e08efdd0e..4612c4519f 100644 --- a/RELEASE-NOTES-1.25 +++ b/RELEASE-NOTES-1.25 @@ -45,6 +45,8 @@ production. * The 'daemonized' flag must be set to true in $wgJobTypeConf for any redis job queues. This means that mediawiki/services/jobrunner service has to be installed and running for any such queues to work. +* $wgAutopromoteOnce no longer supports the 'view' event. For keeping some + compatibility, any 'view' event triggers will still trigger on 'edit'. === New features in 1.25 === * (T64861) Updated plural rules to CLDR 26. Includes incompatible changes @@ -115,6 +117,11 @@ production. interface, reachable via IContextSource::getStats(). * Move the jQuery Client library from being mastered in MediaWiki as v0.1.0 to a proper, published library, which is now tagged as v1.0.0. +* A new message (defaulting to blank), 'editnotice-notext', can be shown to users + when they are editing if no edit notices apply to the page being edited. +* (T94536) You can now make the sitenotice appear to logged-in users only by + editing MediaWiki:Anonnotice and replacing its content with "". Setting it to + "-" (default) will continue disable it and fallback to MediaWiki:Sitenotice. ==== External libraries ==== * MediaWiki now requires certain external libraries to be installed. In the past @@ -128,7 +135,8 @@ production. * The following libraries are now required: ** psr/log This library provides the interfaces set by the PSR-3 standard (http://www.php-fig.org/psr/psr-3/) - which are used by MediaWiki internally via the MWLoggerFactory class. + which are used by MediaWiki internally via the + MediaWiki\Logger\LoggerFactory class. See the structured logging RfC (https://www.mediawiki.org/wiki/Requests_for_comment/Structured_logging) for more background information. ** cssjanus/cssjanus @@ -174,6 +182,8 @@ production. This requires the fa_sha1 field being populated. * Removed rel="archives" from the "View history" link, as it did not pass HTML validation. +* $wgUseTidy is now set when parserTests are run with the tidy option to match + output on wiki. === Action API changes in 1.25 === * (T67403) XML tag highlighting is now only performed for formats @@ -402,9 +412,23 @@ changes to languages because of Bugzilla reports. addSecondaryDataUpdate throwing an exception. These functions will be removed in 1.26, since they interfere with caching of ParserOutput objects. * Introduced new hook 'SecondaryDataUpdates' that allows extensions to inject custom updates. +* Introduced new hook 'OpportunisticLinksUpdate' that allows extensions to perform + updates when a page is re-rendered. * EditPage::attemptSave has been modified not to call handleStatus itself and instead just returns the Status object. Extension calling it should be aware of this. +* Removed class DBObject. (unused since 1.10) +* wfDiff() is deprecated. +* The -m (maximum replication lag) option of refreshLinks.php was removed. + It had no effect since MediaWiki 1.18 and should be removed from any cron + jobs or similar scripts you may have set up. +* (T85864) The following messages no longer support raw html: redirectto, + thisisdeleted, viewdeleted, editlink, retrievedfrom, version-poweredby-others, + retrievedfrom, thisisdeleted, viewsourcelink, lastmodifiedat, laggedslavemode, + protect-summary-cascade +* All BloomCache related code has been removed. This was largely experimental. +* $wgResourceModuleSkinStyles no longer supports per-module local or remote paths. They + can only be set for the entire skin. == Compatibility == @@ -417,7 +441,7 @@ Oracle and Microsoft SQL Server. The supported versions are: -* MySQL 5.0.2 or later +* MySQL 5.0.3 or later * PostgreSQL 8.3 or later * SQLite 3.3.7 or later * Oracle 9.0.1 or later diff --git a/StartProfiler.sample b/StartProfiler.sample index 6681b870cf..bdf21396e2 100644 --- a/StartProfiler.sample +++ b/StartProfiler.sample @@ -4,30 +4,35 @@ * To use a profiler, copy this file to StartProfiler.php and add: * $wgProfiler['class'] = 'ProfilerXhprof'; * - * For output, add: - * $wgProfiler['output'] = array( 'text' ); - * 'text' can be one (or more) of 'text' 'udp' 'db' or 'dump' - * 'db' requires creating the profiling table, see patch-profiling.sql + * For output, set the 'output' key to an array of class names, one for each + * output type you want the profiler to generate. For example: + * $wgProfiler['output'] = array( 'ProfilerOutputText' ); * - * The 'text' output will be added to the output page in a comment approriate - * to the output's mime type. For a text/html page, this display can be - * changed to a preformatted text block by setting the 'visible' configuration - * flag: + * The output classes available to you by default are ProfilerOutputDb, + * ProfilerOutputDump, ProfilerOutputStats, ProfilerOutputText, and + * ProfilerOutputUdp. + * + * ProfilerOutputStats outputs profiling data as StatsD metrics. It expects + * that you have set the $wgStatsdServer configuration variable to the host (or + * host:port) of your statsd server. + * + * ProfilerOutputText will output profiling data in the page body as a comment. + * You can make the profiling data in HTML render as part of the page content + * by setting the 'visible' configuration flag: * $wgProfiler['visible'] = true; * - * The 'db' output expects a database table that can be created by applying + * 'ProfilerOutputDb' expects a database table that can be created by applying * maintenance/archives/patch-profiling.sql to your database. * - * The 'dump' output expects a $wgProfiler['outputDir'] telling it where to + * 'ProfilerOutputDump' expects a $wgProfiler['outputDir'] telling it where to * write dump files. The files produced are compatible with the XHProf gui. - * * For a rudimentary sampling profiler: * $wgProfiler['class'] = 'ProfilerXhprof'; - * $wgProfiler['output'] = array( 'db' ); + * $wgProfiler['output'] = array( 'ProfilerOutputDb' ); * $wgProfiler['sampling'] = 50; // one every 50 requests * This will use ProfilerStub for non-sampled cases. * - * For performance, the profiler is always disabled for CLI scripts - * as they could be long running and the data would accumulate. Use - * the --profiler parameter of maintenance scripts to override this. + * For performance, the profiler is always disabled for CLI scripts as they + * could be long running and the data would accumulate. Use the '--profiler' + * parameter of maintenance scripts to override this. */ diff --git a/api.php b/api.php index 7788a36c2f..ea2f60aef2 100644 --- a/api.php +++ b/api.php @@ -30,6 +30,8 @@ * @file */ +use MediaWiki\Logger\LegacyLogger; + // So extensions (and other code) can check whether they're running in API mode define( 'MW_API', true ); @@ -59,7 +61,7 @@ if ( !$wgEnableAPI ) { // Set a dummy $wgTitle, because $wgTitle == null breaks various things // In a perfect world this wouldn't be necessary -$wgTitle = Title::makeTitle( NS_MAIN, 'API' ); +$wgTitle = Title::makeTitle( NS_SPECIAL, 'Badtitle/dummy title for API calls set in api.php' ); // RequestContext will read from $wgTitle, but it will also whine about it. // In a perfect world this wouldn't be necessary either. @@ -124,7 +126,7 @@ if ( $wgAPIRequestLog ) { } else { $items[] = "failed in ApiBeforeMain"; } - MWLoggerLegacyLogger::emit( implode( ',', $items ) . "\n", $wgAPIRequestLog ); + LegacyLogger::emit( implode( ',', $items ) . "\n", $wgAPIRequestLog ); wfDebug( "Logged API request to $wgAPIRequestLog\n" ); } diff --git a/autoload.php b/autoload.php index 2b7614dfd1..1e62ccca8a 100644 --- a/autoload.php +++ b/autoload.php @@ -1,6 +1,6 @@ __DIR__ . '/includes/Block.php', 'BlockListPager' => __DIR__ . '/includes/specials/SpecialBlockList.php', 'BlockLogFormatter' => __DIR__ . '/includes/logging/BlockLogFormatter.php', - 'BloomCache' => __DIR__ . '/includes/cache/bloom/BloomCache.php', - 'BloomCacheRedis' => __DIR__ . '/includes/cache/bloom/BloomCacheRedis.php', - 'BloomFilterTitleHasLogs' => __DIR__ . '/includes/cache/bloom/BloomFilters.php', 'BmpHandler' => __DIR__ . '/includes/media/BMP.php', - 'BufferingStatsdDataFactory' => __DIR__ . '/includes/libs/BufferingStatsdDataFactory.php', 'BrokenRedirectsPage' => __DIR__ . '/includes/specials/SpecialBrokenRedirects.php', + 'BufferingStatsdDataFactory' => __DIR__ . '/includes/libs/BufferingStatsdDataFactory.php', 'CLDRPluralRuleConverter' => __DIR__ . '/languages/utils/CLDRPluralRuleConverter.php', 'CLDRPluralRuleConverterExpression' => __DIR__ . '/languages/utils/CLDRPluralRuleConverterExpression.php', 'CLDRPluralRuleConverterFragment' => __DIR__ . '/languages/utils/CLDRPluralRuleConverterFragment.php', @@ -189,6 +186,7 @@ $wgAutoloadLocalClasses = array( 'CacheHelper' => __DIR__ . '/includes/cache/CacheHelper.php', 'CacheTime' => __DIR__ . '/includes/parser/CacheTime.php', 'CachedAction' => __DIR__ . '/includes/actions/CachedAction.php', + 'CachingSiteStore' => __DIR__ . '/includes/site/CachingSiteStore.php', 'CapsCleanup' => __DIR__ . '/maintenance/cleanupCaps.php', 'Category' => __DIR__ . '/includes/Category.php', 'CategoryFinder' => __DIR__ . '/includes/CategoryFinder.php', @@ -275,8 +273,8 @@ $wgAutoloadLocalClasses = array( 'DBFileJournal' => __DIR__ . '/includes/filebackend/filejournal/DBFileJournal.php', 'DBLockManager' => __DIR__ . '/includes/filebackend/lockmanager/DBLockManager.php', 'DBMasterPos' => __DIR__ . '/includes/db/DatabaseUtility.php', - 'DBObject' => __DIR__ . '/includes/db/DatabaseUtility.php', 'DBQueryError' => __DIR__ . '/includes/db/DatabaseError.php', + 'DBSiteStore' => __DIR__ . '/includes/site/DBSiteStore.php', 'DBUnexpectedError' => __DIR__ . '/includes/db/DatabaseError.php', 'DataUpdate' => __DIR__ . '/includes/deferred/DataUpdate.php', 'DatabaseBase' => __DIR__ . '/includes/db/Database.php', @@ -366,7 +364,6 @@ $wgAutoloadLocalClasses = array( 'EmailNotification' => __DIR__ . '/includes/mail/EmailNotification.php', 'EmaillingJob' => __DIR__ . '/includes/jobqueue/jobs/EmaillingJob.php', 'EmptyBagOStuff' => __DIR__ . '/includes/libs/objectcache/EmptyBagOStuff.php', - 'EmptyBloomCache' => __DIR__ . '/includes/cache/bloom/BloomCache.php', 'EncryptedPassword' => __DIR__ . '/includes/password/EncryptedPassword.php', 'EnhancedChangesList' => __DIR__ . '/includes/changes/EnhancedChangesList.php', 'EnotifNotifyJob' => __DIR__ . '/includes/jobqueue/jobs/EnotifNotifyJob.php', @@ -417,6 +414,7 @@ $wgAutoloadLocalClasses = array( 'FileBackendStoreShardDirIterator' => __DIR__ . '/includes/filebackend/FileBackendStore.php', 'FileBackendStoreShardFileIterator' => __DIR__ . '/includes/filebackend/FileBackendStore.php', 'FileBackendStoreShardListIterator' => __DIR__ . '/includes/filebackend/FileBackendStore.php', + 'FileBasedSiteLookup' => __DIR__ . '/includes/site/FileBasedSiteLookup.php', 'FileCacheBase' => __DIR__ . '/includes/cache/FileCacheBase.php', 'FileDeleteForm' => __DIR__ . '/includes/FileDeleteForm.php', 'FileDependency' => __DIR__ . '/includes/cache/CacheDependency.php', @@ -696,18 +694,17 @@ $wgAutoloadLocalClasses = array( 'MWFunction' => __DIR__ . '/includes/utils/MWFunction.php', 'MWHookException' => __DIR__ . '/includes/Hooks.php', 'MWHttpRequest' => __DIR__ . '/includes/HttpFunctions.php', - 'MWLogger' => __DIR__ . '/includes/debug/logger/Logger.php', - 'MWLoggerFactory' => __DIR__ . '/includes/debug/logger/Factory.php', - 'MWLoggerLegacyLogger' => __DIR__ . '/includes/debug/logger/legacy/Logger.php', - 'MWLoggerLegacySpi' => __DIR__ . '/includes/debug/logger/legacy/Spi.php', - 'MWLoggerMonologHandler' => __DIR__ . '/includes/debug/logger/monolog/Handler.php', - 'MWLoggerMonologLegacyFormatter' => __DIR__ . '/includes/debug/logger/monolog/LegacyFormatter.php', - 'MWLoggerMonologProcessor' => __DIR__ . '/includes/debug/logger/monolog/Processor.php', - 'MWLoggerMonologSamplingHandler' => __DIR__ . '/includes/debug/logger/monolog/SamplingHandler.php', - 'MWLoggerMonologSpi' => __DIR__ . '/includes/debug/logger/monolog/Spi.php', - 'MWLoggerMonologSyslogHandler' => __DIR__ . '/includes/debug/logger/monolog/SyslogHandler.php', - 'MWLoggerNullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php', - 'MWLoggerSpi' => __DIR__ . '/includes/debug/logger/Spi.php', + 'MWLogger' => __DIR__ . '/includes/debug/logger/Shims.php', + 'MWLoggerFactory' => __DIR__ . '/includes/debug/logger/Shims.php', + 'MWLoggerLegacyLogger' => __DIR__ . '/includes/debug/logger/Shims.php', + 'MWLoggerLegacySpi' => __DIR__ . '/includes/debug/logger/Shims.php', + 'MWLoggerMonologHandler' => __DIR__ . '/includes/debug/logger/monolog/Shims.php', + 'MWLoggerMonologLegacyFormatter' => __DIR__ . '/includes/debug/logger/monolog/Shims.php', + 'MWLoggerMonologProcessor' => __DIR__ . '/includes/debug/logger/monolog/Shims.php', + 'MWLoggerMonologSpi' => __DIR__ . '/includes/debug/logger/monolog/Shims.php', + 'MWLoggerMonologSyslogHandler' => __DIR__ . '/includes/debug/logger/monolog/Shims.php', + 'MWLoggerNullSpi' => __DIR__ . '/includes/debug/logger/Shims.php', + 'MWLoggerSpi' => __DIR__ . '/includes/debug/logger/Shims.php', 'MWMemcached' => __DIR__ . '/includes/objectcache/MemcachedClient.php', 'MWMessagePack' => __DIR__ . '/includes/libs/MWMessagePack.php', 'MWNamespace' => __DIR__ . '/includes/MWNamespace.php', @@ -740,6 +737,16 @@ $wgAutoloadLocalClasses = array( 'MediaWikiSite' => __DIR__ . '/includes/site/MediaWikiSite.php', 'MediaWikiTitleCodec' => __DIR__ . '/includes/title/MediaWikiTitleCodec.php', 'MediaWikiVersionFetcher' => __DIR__ . '/includes/MediaWikiVersionFetcher.php', + 'MediaWiki\\Logger\\LegacyLogger' => __DIR__ . '/includes/debug/logger/LegacyLogger.php', + 'MediaWiki\\Logger\\LegacySpi' => __DIR__ . '/includes/debug/logger/LegacySpi.php', + 'MediaWiki\\Logger\\LoggerFactory' => __DIR__ . '/includes/debug/logger/LoggerFactory.php', + 'MediaWiki\\Logger\\MonologSpi' => __DIR__ . '/includes/debug/logger/MonologSpi.php', + 'MediaWiki\\Logger\\Monolog\\LegacyFormatter' => __DIR__ . '/includes/debug/logger/monolog/LegacyFormatter.php', + 'MediaWiki\\Logger\\Monolog\\LegacyHandler' => __DIR__ . '/includes/debug/logger/monolog/LegacyHandler.php', + 'MediaWiki\\Logger\\Monolog\\SyslogHandler' => __DIR__ . '/includes/debug/logger/monolog/SyslogHandler.php', + 'MediaWiki\\Logger\\Monolog\\WikiProcessor' => __DIR__ . '/includes/debug/logger/monolog/WikiProcessor.php', + 'MediaWiki\\Logger\\NullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php', + 'MediaWiki\\Logger\\Spi' => __DIR__ . '/includes/debug/logger/Spi.php', 'MemCachedClientforWiki' => __DIR__ . '/includes/objectcache/MemcachedClient.php', 'MemcLockManager' => __DIR__ . '/includes/filebackend/lockmanager/MemcLockManager.php', 'MemcachedBagOStuff' => __DIR__ . '/includes/objectcache/MemcachedBagOStuff.php', @@ -909,6 +916,7 @@ $wgAutoloadLocalClasses = array( 'ProfilerOutput' => __DIR__ . '/includes/profiler/output/ProfilerOutput.php', 'ProfilerOutputDb' => __DIR__ . '/includes/profiler/output/ProfilerOutputDb.php', 'ProfilerOutputDump' => __DIR__ . '/includes/profiler/output/ProfilerOutputDump.php', + 'ProfilerOutputStats' => __DIR__ . '/includes/profiler/output/ProfilerOutputStats.php', 'ProfilerOutputText' => __DIR__ . '/includes/profiler/output/ProfilerOutputText.php', 'ProfilerOutputUdp' => __DIR__ . '/includes/profiler/output/ProfilerOutputUdp.php', 'ProfilerSectionOnly' => __DIR__ . '/includes/profiler/ProfilerSectionOnly.php', @@ -987,6 +995,7 @@ $wgAutoloadLocalClasses = array( 'ResourceLoaderModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderModule.php', 'ResourceLoaderSiteModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderSiteModule.php', 'ResourceLoaderSkinModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderSkinModule.php', + 'ResourceLoaderSpecialCharacterDataModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderSpecialCharacterDataModule.php', 'ResourceLoaderStartUpModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderStartUpModule.php', 'ResourceLoaderUserCSSPrefsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php', 'ResourceLoaderUserDefaultsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserDefaultsModule.php', @@ -1061,14 +1070,14 @@ $wgAutoloadLocalClasses = array( 'SiteExporter' => __DIR__ . '/includes/site/SiteExporter.php', 'SiteImporter' => __DIR__ . '/includes/site/SiteImporter.php', 'SiteList' => __DIR__ . '/includes/site/SiteList.php', - 'SiteListFileCache' => __DIR__ . '/includes/site/SiteListFileCache.php', - 'SiteListFileCacheBuilder' => __DIR__ . '/includes/site/SiteListFileCacheBuilder.php', + 'SiteLookup' => __DIR__ . '/includes/site/SiteLookup.php', 'SiteObject' => __DIR__ . '/includes/site/Site.php', 'SiteSQLStore' => __DIR__ . '/includes/site/SiteSQLStore.php', 'SiteStats' => __DIR__ . '/includes/SiteStats.php', 'SiteStatsInit' => __DIR__ . '/includes/SiteStats.php', 'SiteStatsUpdate' => __DIR__ . '/includes/deferred/SiteStatsUpdate.php', 'SiteStore' => __DIR__ . '/includes/site/SiteStore.php', + 'SitesCacheFileBuilder' => __DIR__ . '/includes/site/SitesCacheFileBuilder.php', 'Skin' => __DIR__ . '/includes/skins/Skin.php', 'SkinApi' => __DIR__ . '/includes/skins/SkinApi.php', 'SkinApiTemplate' => __DIR__ . '/includes/skins/SkinApiTemplate.php', @@ -1262,7 +1271,6 @@ $wgAutoloadLocalClasses = array( 'UploadStashFileException' => __DIR__ . '/includes/upload/UploadStash.php', 'UploadStashFileNotFoundException' => __DIR__ . '/includes/upload/UploadStash.php', 'UploadStashNoSuchKeyException' => __DIR__ . '/includes/upload/UploadStash.php', - 'UploadStashNotAvailableException' => __DIR__ . '/includes/upload/UploadStash.php', 'UploadStashNotLoggedInException' => __DIR__ . '/includes/upload/UploadStash.php', 'UploadStashWrongOwnerException' => __DIR__ . '/includes/upload/UploadStash.php', 'UploadStashZeroLengthFileException' => __DIR__ . '/includes/upload/UploadStash.php', diff --git a/composer.json b/composer.json index 8c0cfedb89..88ee9cf3e4 100644 --- a/composer.json +++ b/composer.json @@ -20,11 +20,12 @@ "ext-iconv": "*", "leafo/lessphp": "0.5.0", "liuggio/statsd-php-client": "1.0.12", - "oojs/oojs-ui": "0.9.1", + "oojs/oojs-ui": "0.9.7", "php": ">=5.3.3", "psr/log": "1.0.0", "wikimedia/cdb": "1.0.1", "wikimedia/composer-merge-plugin": "1.0.0", + "wikimedia/utfnormal": "1.0.2", "zordius/lightncandy": "0.18" }, "require-dev": { diff --git a/docs/extension.schema.json b/docs/extension.schema.json index dd35d0541c..d1b982c519 100644 --- a/docs/extension.schema.json +++ b/docs/extension.schema.json @@ -8,6 +8,10 @@ "description": "The extension's canonical name.", "required": true }, + "namemsg": { + "type": "string", + "description": "i18n message key of the extension's name." + }, "type": { "type": "string", "description": "The extension's type, as an index to $wgExtensionCredits.", @@ -417,6 +421,10 @@ } } }, + "ResourceModuleSkinStyles": { + "type": "object", + "description": "ResourceLoader modules for custom skin styles" + }, "ResourceLoaderSources": { "type": "object", "description": "ResourceLoader sources to register" diff --git a/docs/hooks.txt b/docs/hooks.txt index 20f5de8671..877b7ed709 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -1061,6 +1061,21 @@ etc. 'DatabaseOraclePostInit': Called after initialising an Oracle database &$db: the DatabaseOracle object +'DeletedContribsPager::reallyDoQuery': Called before really executing the query for Special:DeletedContributions +Similar to ContribsPager::reallyDoQuery +&$data: an array of results of all contribs queries +$pager: The DeletedContribsPager object hooked into +$offset: Index offset, inclusive +$limit: Exact query limit +$descending: Query direction, false for ascending, true for descending + +'DeletedContributionsLineEnding': Called before a DeletedContributions HTML line is finished. +Similar to ContributionsLineEnding +$page: SpecialPage object for DeletedContributions +&$ret: the HTML line +$row: the DB row for this line +&$classes: the classes to add to the surrounding
  • + 'NewDifferenceEngine': Called when a new DifferenceEngine object is made $title: the diff page title (nullable) &$oldId: the actual old Id to use in the diff @@ -1997,6 +2012,17 @@ return false to omit the line from RecentChanges and Watchlist special pages. can alter or append to the array of URLs for search & suggestion formats. &$urls: array of associative arrays with Url element attributes +'OpportunisticLinksUpdate': Called by WikiPage::triggerOpportunisticLinksUpdate +when a page view triggers a re-rendering of the page. This may happen +particularly if the parser cache is split by user language, and no cached +rendering of the page exists in the user's language. The hook is called +before checking whether page_links_updated indicates that the links are up +to date. Returning false will cause triggerOpportunisticLinksUpdate() to abort +without triggering any updates. +$page: the Page that was rendered. +$title: the Title of the rendered page. +$parserOutput: ParserOutput resulting from rendering the page. + 'OtherBlockLogLink': Get links to the block log from extensions which blocks users and/or IP addresses too. $otherBlockLink: An array with links to other block logs diff --git a/docs/logger.txt b/docs/logger.txt new file mode 100644 index 0000000000..89e620aff0 --- /dev/null +++ b/docs/logger.txt @@ -0,0 +1,71 @@ +MediaWiki\Logger\LoggerFactory implements a PSR-3 [0] compatible message +logging system. + +Named Psr\Log\LoggerInterface instances can be obtained from the +MediaWiki\Logger\LoggerFactory::getInstance() static method. +MediaWiki\Logger\LoggerFactory expects a class implementing the +MediaWiki\Logger\Spi interface to act as a factory for new +Psr\Log\LoggerInterface instances. + +The "Spi" in MediaWiki\Logger\Spi stands for "service provider interface". An +SPI is an API intended to be implemented or extended by a third party. This +software design pattern is intended to enable framework extension and +replaceable components. It is specifically used in the +MediaWiki\Logger\LoggerFactory service to allow alternate PSR-3 logging +implementations to be easily integrated with MediaWiki. + +The service provider interface allows the backend logging library to be +implemented in multiple ways. The $wgMWLoggerDefaultSpi global provides the +classname of the default MediaWiki\Logger\Spi implementation to be loaded at +runtime. This can either be the name of a class implementing the +MediaWiki\Logger\Spi with a zero argument constructor or a callable that will +return an MediaWiki\Logger\Spi instance. Alternately the +MediaWiki\Logger\LoggerFactory::registerProvider() static method can be called +to inject an MediaWiki\Logger\Spi instance into the LoggerFactory and bypass +the use of the default configuration variable. + +The MediaWiki\Logger\LegacySpi class implements a service provider to generate +MediaWiki\Logger\LegacyLogger instances. The MediaWiki\Logger\LegacyLogger +class implements the PSR-3 logger interface and provides output and +configuration equivalent to the historic logging output of wfDebug, +wfDebugLog, wfLogDBError and wfErrorLog. The MediaWiki\Logger\LegacySpi class +is the default service provider configured in DefaultSettings.php. It's usage +should be transparent for users who are not ready or do not wish to switch to +a alternate logging platform. + +The MediaWiki\Logger\MonologSpi class implements a service provider to +generate Psr\Log\LoggerInterface instances that use the Monolog [1] logging +library. See the PHP docs (or source) for MediaWiki\Logger\MonologSpi for +details on the configuration of this provider. The default configuration +installs a null handler that will silently discard all logging events. The +documentation provided by the class describes a more feature rich logging +configuration. + +== Classes == +; MediaWiki\Logger\LoggerFactory +: Factory for Psr\Log\LoggerInterface loggers +; MediaWiki\Logger\Spi +: Service provider interface for MediaWiki\Logger\LoggerFactory +; MediaWiki\Logger\NullSpi +: MediaWiki\Logger\Spi for creating instances that discard all log events +; MediaWiki\Logger\LegacySpi +: Service provider for creating MediaWiki\Logger\LegacyLogger instances +; MediaWiki\Logger\LegacyLogger +: PSR-3 logger that mimics the historical output and configuration of wfDebug, + wfErrorLog and other global logging functions. +; MediaWiki\Logger\MonologSpi +: MediaWiki\Logger\Spi for creating instances backed by the monolog logging library +; MediaWiki\Logger\Monolog\LegacyHandler +: Monolog handler that replicates the udp2log and file logging + functionality of wfErrorLog() +; MediaWiki\Logger\Monolog\WikiProcessor +: Monolog log processer that adds host: wfHostname() and wiki: wfWikiID() + to all records + +== Globals == +; $wgMWLoggerDefaultSpi +: Specification for creating the default service provider interface to use + with MediaWiki\Logger\LoggerFactory + +[0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md +[1]: https://github.com/Seldaek/monolog diff --git a/docs/mwlogger.txt b/docs/mwlogger.txt deleted file mode 100644 index ecc3626db0..0000000000 --- a/docs/mwlogger.txt +++ /dev/null @@ -1,71 +0,0 @@ -MWLoggerFactory implements a PSR-3 [0] compatible message logging system. - -Named Psr\Log\LoggerInterface instances can be obtained from the -MWLoggerFactory::getInstance() static method. MWLoggerFactory expects a class -implementing the MWLoggerSpi interface to act as a factory for new -Psr\Log\LoggerInterface instances. - -The "Spi" in MWLoggerSpi stands for "service provider interface". A SPI is -an API intended to be implemented or extended by a third party. This software -design pattern is intended to enable framework extension and replaceable -components. It is specifically used in the MWLoggerFactory service to allow -alternate PSR-3 logging implementations to be easily integrated with -MediaWiki. - -The MWLoggerFactory::getInstance() static method is the means by which most -code acquires a Psr\Log\LoggerInterface instance. This in turn delegates -creation of Psr\Log\LoggerInterface instances to a class implementing the -MWLoggerSpi service provider interface. - -The service provider interface allows the backend logging library to be -implemented in multiple ways. The $wgMWLoggerDefaultSpi global provides the -classname of the default MWLoggerSpi implementation to be loaded at runtime. -This can either be the name of a class implementing the MWLoggerSpi with -a zero argument constructor or a callable that will return an MWLoggerSpi -instance. Alternately the MWLoggerFactory::registerProvider method can be -called to inject an MWLoggerSpi instance into MWLoggerFactory and bypass the -use of this configuration variable. - -The MWLoggerLegacySpi class implements a service provider to generate -MWLoggerLegacyLogger instances. The MWLoggerLegacyLogger class implements the -PSR-3 logger interface and provides output and configuration equivalent to the -historic logging output of wfDebug, wfDebugLog, wfLogDBError and wfErrorLog. -The MWLoggerLegacySpi class is the default service provider configured in -DefaultSettings.php. It's usage should be transparent for users who are not -ready or do not wish to switch to a alternate logging platform. - -The MWLoggerMonologSpi class implements a service provider to generate -Psr\Log\LoggerInterface instances that use the Monolog [1] logging library. -See the PHP docs (or source) for MWLoggerMonologSpi for details on the -configuration of this provider. The default configuration installs a null -handler that will silently discard all logging events. The documentation -provided by the class describes a more feature rich logging configuration. - -== Classes == -; MWLoggerFactory -: Factory for Psr\Log\LoggerInterface loggers -; MWLoggerSpi -: Service provider interface for MWLoggerFactory -; MWLoggerNullSpi -: MWLoggerSpi for creating instances that discard all log events -; MWLoggerLegacySpi -: Service provider for creating MWLoggerLegacyLogger instances -; MWLoggerLegacyLogger -: PSR-3 logger that mimics the historical output and configuration of wfDebug, - wfErrorLog and other global logging functions. -; MWLoggerMonologSpi -: MWLoggerSpi for creating instances backed by the monolog logging library -; MwLoggerMonologHandler -: Monolog handler that replicates the udp2log and file logging - functionality of wfErrorLog() -; MwLoggerMonologProcessor -: Monolog log processer that adds host: wfHostname() and wiki: wfWikiID() - to all records - -== Globals == -; $wgMWLoggerDefaultSpi -: Specification for creating the default service provider interface to use - with MWLoggerFactory - -[0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md -[1]: https://github.com/Seldaek/monolog diff --git a/docs/sitescache.txt b/docs/sitescache.txt new file mode 100644 index 0000000000..13bf371d20 --- /dev/null +++ b/docs/sitescache.txt @@ -0,0 +1,42 @@ +MediaWiki's SiteStore can be cached and stored in a flat file, +in a json format. If the SiteStore is frequently accessed, the +file cache may provide a performance benefit over a database +store, even with memcached in front of it. + +Configuration: + +File-based caching can be enabled by setting $wgSitesCacheFile +to the file path of the cache file. + +The file can then be generated with the rebuildSitesCache.php +maintenance script. + +Format: + +In the sites cache file, sites are listed in a key-value +map, with the key being the site's global id (e.g. "enwiki") +and a key-value map as the value. The site list is wrapped +with in a "sites" key. + +Example: + +"sites": { + "aawiktionary": { + "globalid": "aawiktionary", + "type": "mediawiki", + "group": "wiktionary", + "source": "local", + "language": "aa", + "localids": [], + "config": [], + "data": { + "paths": { + "file_path": "http:\/\/aa.wiktionary.org\/w\/$1", + "page_path": "http:\/\/aa.wiktionary.org\/wiki\/$1" + } + }, + "forward": false, + "internalid": 2666, + "identifiers": [] + } +} diff --git a/includes/Block.php b/includes/Block.php index 4698f457d6..873a26d86f 100644 --- a/includes/Block.php +++ b/includes/Block.php @@ -442,19 +442,33 @@ class Block { $dbw = wfGetDB( DB_MASTER ); } - # Don't collide with expired blocks - Block::purgeExpired(); + # Periodic purge via commit hooks + if ( mt_rand( 0, 9 ) == 0 ) { + Block::purgeExpired(); + } $row = $this->getDatabaseArray(); $row['ipb_id'] = $dbw->nextSequenceValue( "ipblocks_ipb_id_seq" ); - $dbw->insert( - 'ipblocks', - $row, - __METHOD__, - array( 'IGNORE' ) - ); + $dbw->insert( 'ipblocks', $row, __METHOD__, array( 'IGNORE' ) ); $affected = $dbw->affectedRows(); + + # Don't collide with expired blocks. + # Do this after trying to insert to avoid pointless gap locks. + if ( !$affected ) { + $dbw->delete( 'ipblocks', + array( + 'ipb_address' => $row['ipb_address'], + 'ipb_user' => $row['ipb_user'], + 'ipb_expiry < ' . $dbw->addQuotes( $dbw->timestamp() ) + ), + __METHOD__ + ); + + $dbw->insert( 'ipblocks', $row, __METHOD__, array( 'IGNORE' ) ); + $affected = $dbw->affectedRows(); + } + $this->mId = $dbw->insertId(); if ( $affected ) { diff --git a/includes/CategoryViewer.php b/includes/CategoryViewer.php index 48436c5d67..66079c0179 100644 --- a/includes/CategoryViewer.php +++ b/includes/CategoryViewer.php @@ -603,7 +603,7 @@ class CategoryViewer extends ContextSource { * @return string HTML */ private function pagingLinks( $first, $last, $type = '' ) { - $prevLink = $this->msg( 'prevn' )->numParams( $this->limit )->escaped(); + $prevLink = $this->msg( 'prev-page' )->text(); if ( $first != '' ) { $prevQuery = $this->query; @@ -617,7 +617,7 @@ class CategoryViewer extends ContextSource { ); } - $nextLink = $this->msg( 'nextn' )->numParams( $this->limit )->escaped(); + $nextLink = $this->msg( 'next-page' )->text(); if ( $last != '' ) { $lastQuery = $this->query; diff --git a/includes/ChangeTags.php b/includes/ChangeTags.php index d597d6d473..52c665cf0b 100644 --- a/includes/ChangeTags.php +++ b/includes/ChangeTags.php @@ -41,17 +41,13 @@ class ChangeTags { public static function formatSummaryRow( $tags, $page ) { global $wgLang; - $tags = explode( ',', $tags ); - - // XXX(Ori Livneh, 2014-11-08): remove once bug 73181 is resolved. - $tags = array_diff( $tags, array( 'HHVM', '' ) ); - if ( !$tags ) { return array( '', array() ); } $classes = array(); + $tags = explode( ',', $tags ); $displayTags = array(); foreach ( $tags as $tag ) { $displayTags[] = Xml::tags( diff --git a/includes/Collation.php b/includes/Collation.php index dac3e938a8..481d8e7034 100644 --- a/includes/Collation.php +++ b/includes/Collation.php @@ -341,7 +341,7 @@ class IcuCollation extends Collation { // Check for CJK $firstChar = mb_substr( $string, 0, 1, 'UTF-8' ); - if ( ord( $firstChar ) > 0x7f && self::isCjk( utf8ToCodepoint( $firstChar ) ) ) { + if ( ord( $firstChar ) > 0x7f && self::isCjk( UtfNormal\Utils::utf8ToCodepoint( $firstChar ) ) ) { return $firstChar; } diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 8a4769d1c4..c8197f2893 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -52,6 +52,8 @@ if ( !defined( 'MEDIAWIKI' ) ) { die( 1 ); } +/** @endcond */ + /** * wgConf hold the site configuration. * Not used for much in a default install. @@ -2145,28 +2147,6 @@ $wgObjectCaches = array( 'hash' => array( 'class' => 'HashBagOStuff' ), ); -/** - * Map of bloom filter store names to configuration arrays. - * - * Example: - * $wgBloomFilterStores['main'] = array( - * 'cacheId' => 'main-v1', - * 'class' => 'BloomCacheRedis', - * 'redisServers' => array( '127.0.0.1:6379' ), - * 'redisConfig' => array( 'connectTimeout' => 2 ) - * ); - * - * A primary bloom filter must be created manually. - * Example in eval.php: - * - * BloomCache::get( 'main' )->init( 'shared', 1000000000, .001 ); - * - * The size should be as large as practical given wiki size and resources. - * - * @since 1.24 - */ -$wgBloomFilterStores = array(); - /** * The expiry time for the parser cache, in seconds. * The default is 86400 (one day). @@ -3358,8 +3338,6 @@ $wgResourceModules = array(); * * As with $wgResourceModules, paths default to being relative to the MediaWiki root. * You should always provide a localBasePath and remoteBasePath (or remoteExtPath/remoteSkinPath). - * Either for all skin styles at once (first example below) or for each module separately (second - * example). * * @par Example: * @code @@ -3369,19 +3347,6 @@ $wgResourceModules = array(); * 'remoteSkinPath' => 'Foo', * 'localBasePath' => __DIR__, * ); - * - * $wgResourceModuleSkinStyles['foo'] = array( - * 'bar' => array( - * 'bar.css', - * 'remoteSkinPath' => 'Foo', - * 'localBasePath' => __DIR__, - * ), - * 'quux' => array( - * 'quux.css', - * 'remoteSkinPath' => 'Foo', - * 'localBasePath' => __DIR__, - * ), - * ); * @endcode */ $wgResourceModuleSkinStyles = array(); @@ -3805,7 +3770,7 @@ $wgInterwikiFallbackSite = 'wiki'; */ /** - * Specify the file location for the SiteStore json cache file. + * Specify the file location for the Sites json cache file. */ $wgSitesCacheFile = false; @@ -4003,7 +3968,7 @@ $wgUrlProtocols = array( ); /** - * If true, removes (substitutes) templates in "~~~~" signatures. + * If true, removes (by substituting) templates in signatures. */ $wgCleanSignatures = true; @@ -4226,6 +4191,18 @@ $wgPasswordSalt = true; */ $wgMinimalPasswordLength = 1; +/** + * Specifies the maximal length of a user password (T64685). + * + * It is not recommended to make this greater than the default, as it can + * allow DoS attacks by users setting really long passwords. In addition, + * this should not be lowered too much, as it enforces weak passwords. + * + * @warning Unlike other password settings, user with passwords greater than + * the maximum will not be able to log in. + */ +$wgMaximalPasswordLength = 4096; + /** * Specifies if users should be sent to a password-reset form on login, if their * password doesn't meet the requirements of User::isValidPassword(). @@ -4863,7 +4840,6 @@ $wgAutopromote = array( * @endcode * Where event is either: * - 'onEdit' (when user edits) - * - 'onView' (when user views the wiki) * * Criteria has the same format as $wgAutopromote * @@ -4872,7 +4848,6 @@ $wgAutopromote = array( */ $wgAutopromoteOnce = array( 'onEdit' => array(), - 'onView' => array() ); /** @@ -5313,19 +5288,24 @@ $wgDebugLogGroups = array(); * * The value should be an array suitable for use with * ObjectFactory::getObjectFromSpec(). The created object is expected to - * implement the MWLoggerSpi interface. See ObjectFactory for additional + * implement the MediaWiki\Logger\Spi interface. See ObjectFactory for additional * details. * - * Alternately the MWLoggerFactory::registerProvider method can be called to - * inject an MWLoggerSpi instance into MWLoggerFactory and bypass the use of - * this configuration variable entirely. + * Alternately the MediaWiki\Logger\LoggerFactory::registerProvider method can + * be called to inject an MediaWiki\Logger\Spi instance into the LoggerFactory + * and bypass the use of this configuration variable entirely. + * + * @par To completely disable logging: + * @code + * $wgMWLoggerDefaultSpi = array( 'class' => '\\MediaWiki\\Logger\\NullSpi' ); + * @endcode * * @since 1.25 * @var array $wgMWLoggerDefaultSpi * @see MwLogger */ $wgMWLoggerDefaultSpi = array( - 'class' => 'MWLoggerLegacySpi', + 'class' => '\\MediaWiki\\Logger\\LegacySpi', ); /** @@ -5408,6 +5388,7 @@ $wgDeprecationReleaseLimit = false; /** * Only record profiling info for pages that took longer than this + * @deprecated since 1.25: set $wgProfiler['threshold'] instead. */ $wgProfileLimit = 0.0; @@ -6689,8 +6670,6 @@ $wgLogActions = array( 'protect/modify' => 'modifiedarticleprotection', 'protect/unprotect' => 'unprotectedarticle', 'protect/move_prot' => 'movedarticleprotection', - 'import/upload' => 'import-logentry-upload', - 'import/interwiki' => 'import-logentry-interwiki', ); /** @@ -6725,6 +6704,8 @@ $wgLogActionsHandlers = array( 'block/reblock' => 'BlockLogFormatter', 'suppress/block' => 'BlockLogFormatter', 'suppress/reblock' => 'BlockLogFormatter', + 'import/upload' => 'LogFormatter', + 'import/interwiki' => 'LogFormatter', ); /** diff --git a/includes/Defines.php b/includes/Defines.php index 8456c5dd6a..c9263da94a 100644 --- a/includes/Defines.php +++ b/includes/Defines.php @@ -208,7 +208,6 @@ require_once __DIR__ . '/libs/normal/UtfNormalDefines.php'; /**@{ * Hook support constants */ -define( 'MW_SUPPORTS_EDITFILTERMERGED', 1 ); define( 'MW_SUPPORTS_PARSERFIRSTCALLINIT', 1 ); define( 'MW_SUPPORTS_LOCALISATIONCACHE', 1 ); define( 'MW_SUPPORTS_CONTENTHANDLER', 1 ); @@ -245,11 +244,6 @@ define( 'SFH_NO_HASH', 1 ); define( 'SFH_OBJECT_ARGS', 2 ); /**@}*/ -/** - * Flags for Parser::replaceLinkHolders - */ -define( 'RLH_FOR_UPDATE', 1 ); - /**@{ * Autopromote conditions (must be here and not in Autopromote.php, so that * they're loaded for DefaultSettings.php before AutoLoader.php) diff --git a/includes/EditPage.php b/includes/EditPage.php index a8a17cf90b..e11342603b 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -377,9 +377,6 @@ class EditPage { /** @var bool */ protected $edit; - /** @var bool */ - public $live; - /** * @param Article $article */ @@ -478,11 +475,6 @@ class EditPage { $this->importFormData( $wgRequest ); $this->firsttime = false; - if ( $this->live ) { - $this->livePreview(); - return; - } - if ( wfReadOnly() && $this->save ) { // Force preview $this->save = false; @@ -801,8 +793,7 @@ class EditPage { wfDebug( "POST DATA: " . var_export( $_POST, true ) . "\n" ); $this->preview = true; } else { - /* Fallback for live preview */ - $this->preview = $request->getCheck( 'wpPreview' ) || $request->getCheck( 'wpLivePreview' ); + $this->preview = $request->getCheck( 'wpPreview' ); $this->diff = $request->getCheck( 'wpDiff' ); // Remember whether a save was requested, so we can indicate @@ -915,7 +906,6 @@ class EditPage { * allowed. */ - $this->live = $request->getCheck( 'live' ); $this->editintro = $request->getText( 'editintro', // Custom edit intro for new sections $this->section === 'new' ? 'MediaWiki:addsection-editintro' : '' ); @@ -2098,6 +2088,9 @@ class EditPage { $displayTitle = $contextTitle->getPrefixedText(); } $wgOut->setPageTitle( wfMessage( $msg, $displayTitle ) ); + # Transmit the name of the message to JavaScript for live preview + # Keep Resources.php/mediawiki.action.edit.preview in sync with the possible keys + $wgOut->addJsConfigVars( 'wgEditMessage', $msg ); } /** @@ -2555,7 +2548,19 @@ class EditPage { } // Add edit notices - $wgOut->addHTML( implode( "\n", $this->mTitle->getEditNotices( $this->oldid ) ) ); + $editNotices = $this->mTitle->getEditNotices( $this->oldid ); + if ( count( $editNotices ) ) { + $wgOut->addHTML( implode( "\n", $editNotices ) ); + } else { + $msg = wfMessage( 'editnotice-notext' ); + if ( !$msg->isDisabled() ) { + $wgOut->addHTML( + '
    ' + . $msg->parseAsBlock() + . '
    ' + ); + } + } if ( $this->isConflict ) { $wgOut->wrapWikiMsg( "
    \n$1\n
    ", 'explainconflict' ); @@ -2665,19 +2670,21 @@ class EditPage { array( 'userinvalidcssjstitle', $this->mTitle->getSkinFromCssJsSubpage() ) ); } - if ( $this->formtype !== 'preview' ) { - if ( $this->isCssSubpage && $wgAllowUserCss ) { - $wgOut->wrapWikiMsg( - "
    \n$1\n
    ", - array( 'usercssyoucanpreview' ) - ); - } + if ( $this->getTitle()->isSubpageOf( $wgUser->getUserPage() ) ) { + if ( $this->formtype !== 'preview' ) { + if ( $this->isCssSubpage && $wgAllowUserCss ) { + $wgOut->wrapWikiMsg( + "
    \n$1\n
    ", + array( 'usercssyoucanpreview' ) + ); + } - if ( $this->isJsSubpage && $wgAllowUserJs ) { - $wgOut->wrapWikiMsg( - "
    \n$1\n
    ", - array( 'userjsyoucanpreview' ) - ); + if ( $this->isJsSubpage && $wgAllowUserJs ) { + $wgOut->wrapWikiMsg( + "
    \n$1\n
    ", + array( 'userjsyoucanpreview' ) + ); + } } } } @@ -3809,36 +3816,6 @@ HTML return $buttons; } - /** - * Output preview text only. This can be sucked into the edit page - * via JavaScript, and saves the server time rendering the skin as - * well as theoretically being more robust on the client (doesn't - * disturb the edit box's undo history, won't eat your text on - * failure, etc). - * - * @todo This doesn't include category or interlanguage links. - * Would need to enhance it a bit, "maybe wrap them in XML - * or something..." that might also require more skin - * initialization, so check whether that's a problem. - */ - function livePreview() { - global $wgOut; - $wgOut->disable(); - header( 'Content-type: text/xml; charset=utf-8' ); - header( 'Cache-control: no-cache' ); - - $previewText = $this->getPreviewText(); - #$categories = $skin->getCategoryLinks(); - - $s = - '' . "\n" . - Xml::tags( 'livepreview', null, - Xml::element( 'preview', null, $previewText ) - #. Xml::element( 'category', null, $categories ) - ); - echo $s; - } - /** * Creates a basic error page which informs the user that * they have attempted to edit a nonexistent section. @@ -4009,7 +3986,7 @@ HTML // breaks one of the entities whilst editing. if ( ( substr( $invalue, $i, 1 ) == ";" ) && ( strlen( $hexstring ) <= 6 ) ) { $codepoint = hexdec( $hexstring ); - $result .= codepointToUtf8( $codepoint ); + $result .= UtfNormal\Utils::codepointToUtf8( $codepoint ); } else { $result .= "&#x" . $hexstring . substr( $invalue, $i, 1 ); } diff --git a/includes/FeedUtils.php b/includes/FeedUtils.php index 15fdbc59cc..a01d64208c 100644 --- a/includes/FeedUtils.php +++ b/includes/FeedUtils.php @@ -164,7 +164,7 @@ class FeedUtils { $diffText = "

    Can't load revision $newid

    "; } else { // Diff output fine, clean up any illegal UTF-8 - $diffText = UtfNormal::cleanUp( $diffText ); + $diffText = UtfNormal\Validator::cleanUp( $diffText ); $diffText = self::applyDiffStyle( $diffText ); } } else { diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 9ae6cb8570..7c4ebc27e2 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -26,6 +26,7 @@ if ( !defined( 'MEDIAWIKI' ) ) { use Liuggio\StatsdClient\StatsdClient; use Liuggio\StatsdClient\Sender\SocketSender; +use MediaWiki\Logger\LoggerFactory; // Hide compatibility functions from Doxygen /// @cond @@ -166,12 +167,8 @@ if ( !function_exists( 'hash_equals' ) ) { /** * Load an extension * - * This is the closest equivalent to: - * require_once "$IP/extensions/$name/$name.php"; - * as it will process and load the extension immediately. - * - * However, batch loading with wfLoadExtensions will - * be more performant. + * This queues an extension to be loaded through + * the ExtensionRegistry system. * * @param string $name Name of the extension to load * @param string|null $path Absolute path of where to find the extension.json file @@ -181,7 +178,7 @@ function wfLoadExtension( $name, $path = null ) { global $IP; $path = "$IP/extensions/$name/extension.json"; } - ExtensionRegistry::getInstance()->load( $path ); + ExtensionRegistry::getInstance()->queue( $path ); } /** @@ -202,8 +199,6 @@ function wfLoadExtensions( array $exts ) { foreach ( $exts as $ext ) { $registry->queue( "$IP/extensions/$ext/extension.json" ); } - - $registry->loadFromQueue(); } /** @@ -218,7 +213,7 @@ function wfLoadSkin( $name, $path = null ) { global $IP; $path = "$IP/skins/$name/skin.json"; } - ExtensionRegistry::getInstance()->load( $path ); + ExtensionRegistry::getInstance()->queue( $path ); } /** @@ -233,8 +228,6 @@ function wfLoadSkins( array $skins ) { foreach ( $skins as $skin ) { $registry->queue( "$IP/skins/$skin/skin.json" ); } - - $registry->loadFromQueue(); } /** @@ -1030,12 +1023,7 @@ function wfMatchesDomainList( $url, $domains ) { * @since 1.25 support for additional context data * * @param string $text - * @param string|bool $dest Destination of the message: - * - 'all': both to the log and HTML (debug toolbar or HTML comments) - * - 'log': only to the log and not in HTML - * For backward compatibility, it can also take a boolean: - * - true: same as 'all' - * - false: same as 'log' + * @param string|bool $dest Unused * @param array $context Additional logging context data */ function wfDebug( $text, $dest = 'all', array $context = array() ) { @@ -1046,13 +1034,6 @@ function wfDebug( $text, $dest = 'all', array $context = array() ) { return; } - // Turn $dest into a string if it's a boolean (for b/c) - if ( $dest === true ) { - $dest = 'all'; - } elseif ( $dest === false ) { - $dest = 'log'; - } - $text = trim( $text ); // Inline logic from deprecated wfDebugTimer() @@ -1067,21 +1048,11 @@ function wfDebug( $text, $dest = 'all', array $context = array() ) { ); } - if ( $dest === 'all' ) { - $prefix = ''; - if ( $wgDebugTimestamps ) { - // Prepend elapsed request time and real memory usage with two - // trailing spaces. - $prefix = "{$context['seconds_elapsed']} {$context['memory_used']} "; - } - MWDebug::debugMsg( "{$prefix}{$text}" ); - } - if ( $wgDebugLogPrefix !== '' ) { $context['prefix'] = $wgDebugLogPrefix; } - $logger = MWLoggerFactory::getInstance( 'wfDebug' ); + $logger = LoggerFactory::getInstance( 'wfDebug' ); $logger->debug( $text, $context ); } @@ -1181,11 +1152,7 @@ function wfDebugLog( $text = trim( $text ); - if ( $dest === 'all' ) { - MWDebug::debugMsg( "[{$logGroup}] {$text}\n" ); - } - - $logger = MWLoggerFactory::getInstance( $logGroup ); + $logger = LoggerFactory::getInstance( $logGroup ); $context['private'] = ( $dest === 'private' ); $logger->info( $text, $context ); } @@ -1199,7 +1166,7 @@ function wfDebugLog( * @param array $context Additional logging context data */ function wfLogDBError( $text, array $context = array() ) { - $logger = MWLoggerFactory::getInstance( 'wfLogDBError' ); + $logger = LoggerFactory::getInstance( 'wfLogDBError' ); $logger->error( trim( $text ), $context ); } @@ -1258,11 +1225,11 @@ function wfLogWarning( $msg, $callerOffset = 1, $level = E_USER_WARNING ) { * @param string $file Filename * @param array $context Additional logging context data * @throws MWException - * @deprecated since 1.25 Use MWLoggerLegacyLogger::emit or UDPTransport + * @deprecated since 1.25 Use MediaWiki\Logger\LegacyLogger::emit or UDPTransport */ function wfErrorLog( $text, $file, array $context = array() ) { wfDeprecated( __METHOD__, '1.25' ); - $logger = MWLoggerFactory::getInstance( 'wfErrorLog' ); + $logger = LoggerFactory::getInstance( 'wfErrorLog' ); $context['destination'] = $file; $logger->info( trim( $text ), $context ); } @@ -1271,10 +1238,15 @@ function wfErrorLog( $text, $file, array $context = array() ) { * @todo document */ function wfLogProfilingData() { - global $wgRequestTime, $wgDebugLogGroups, $wgDebugRawPage; - global $wgProfileLimit, $wgUser, $wgRequest; + global $wgDebugLogGroups, $wgDebugRawPage; $context = RequestContext::getMain(); + $request = $context->getRequest(); + + $profiler = Profiler::instance(); + $profiler->setContext( $context ); + $profiler->logData(); + $config = $context->getConfig(); if ( $config->has( 'StatsdServer' ) ) { $statsdServer = explode( ':', $config->get( 'StatsdServer' ) ); @@ -1285,22 +1257,11 @@ function wfLogProfilingData() { $statsdClient->send( $context->getStats()->getBuffer() ); } - $profiler = Profiler::instance(); - # Profiling must actually be enabled... if ( $profiler instanceof ProfilerStub ) { return; } - // Get total page request time and only show pages that longer than - // $wgProfileLimit time (default is 0) - $elapsed = microtime( true ) - $wgRequestTime; - if ( $elapsed <= $wgProfileLimit ) { - return; - } - - $profiler->logData(); - if ( isset( $wgDebugLogGroups['profileoutput'] ) && $wgDebugLogGroups['profileoutput'] === false ) { @@ -1311,7 +1272,7 @@ function wfLogProfilingData() { return; } - $ctx = array( 'elapsed' => $elapsed ); + $ctx = array( 'elapsed' => $request->getElapsedTime() ); if ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { $ctx['forwarded_for'] = $_SERVER['HTTP_X_FORWARDED_FOR']; } @@ -1330,23 +1291,20 @@ function wfLogProfilingData() { // Don't load $wgUser at this late stage just for statistics purposes // @todo FIXME: We can detect some anons even if it is not loaded. // See User::getId() - if ( $wgUser->isItemLoaded( 'id' ) && $wgUser->isAnon() ) { - $ctx['anon'] = true; - } else { - $ctx['anon'] = false; - } + $user = $context->getUser(); + $ctx['anon'] = $user->isItemLoaded( 'id' ) && $user->isAnon(); // Command line script uses a FauxRequest object which does not have // any knowledge about an URL and throw an exception instead. try { - $ctx['url'] = urldecode( $wgRequest->getRequestURL() ); + $ctx['url'] = urldecode( $request->getRequestURL() ); } catch ( Exception $ignored ) { // no-op } $ctx['output'] = $profiler->getOutput(); - $log = MWLoggerFactory::getInstance( 'profileoutput' ); + $log = LoggerFactory::getInstance( 'profileoutput' ); $log->info( "Elapsed: {elapsed}; URL: <{url}>\n{output}", $ctx ); } @@ -3106,7 +3064,8 @@ function wfMerge( $old, $mine, $yours, &$result ) { fclose( $yourtextFile ); # Check for a conflict - $cmd = wfEscapeShellArg( $wgDiff3, '-a', '--overlap-only', $mytextName, $oldtextName, $yourtextName ); + $cmd = wfEscapeShellArg( $wgDiff3, '-a', '--overlap-only', $mytextName, + $oldtextName, $yourtextName ); $handle = popen( $cmd, 'r' ); if ( fgets( $handle, 1024 ) ) { @@ -3117,7 +3076,8 @@ function wfMerge( $old, $mine, $yours, &$result ) { pclose( $handle ); # Merge differences - $cmd = wfEscapeShellArg( $wgDiff3, '-a', '-e', '--merge', $mytextName, $oldtextName, $yourtextName ); + $cmd = wfEscapeShellArg( $wgDiff3, '-a', '-e', '--merge', $mytextName, + $oldtextName, $yourtextName ); $handle = popen( $cmd, 'r' ); $result = ''; do { @@ -3141,7 +3101,9 @@ function wfMerge( $old, $mine, $yours, &$result ) { /** * Returns unified plain-text diff of two texts. - * Useful for machine processing of diffs. + * "Useful" for machine processing of diffs. + * + * @deprecated since 1.25, use DiffEngine/UnifiedDiffFormatter directly * * @param string $before The text before the changes. * @param string $after The text after the changes. @@ -3181,6 +3143,11 @@ function wfDiff( $before, $after, $params = '-u' ) { $cmd = "$wgDiff " . $params . ' ' . wfEscapeShellArg( $oldtextName, $newtextName ); $h = popen( $cmd, 'r' ); + if ( !$h ) { + unlink( $oldtextName ); + unlink( $newtextName ); + throw new Exception( __METHOD__ . '(): popen() failed' ); + } $diff = ''; diff --git a/includes/Html.php b/includes/Html.php index 879922516e..d312e0a6e9 100644 --- a/includes/Html.php +++ b/includes/Html.php @@ -104,7 +104,8 @@ class Html { /** * Modifies a set of attributes meant for button elements * and apply a set of default attributes when $wgUseMediaWikiUIEverywhere enabled. - * @param array $modifiers to add to the button + * @param array $attrs + * @param string[] $modifiers to add to the button * @see https://tools.wmflabs.org/styleguide/desktop/index.html for guidance on available modifiers * @return array $attrs A modified attribute array */ @@ -151,10 +152,6 @@ class Html { } else { $attrs['class'] = 'mw-ui-input'; } - - // Note that size can effect the desired width rendering of mw-ui-input elements - // so it is removed. Left intact when mediawiki ui not enabled. - unset( $attrs['size'] ); } return $attrs; } @@ -168,12 +165,12 @@ class Html { * @param array $attrs Associative array of attributes, e.g., array( * 'href' => 'http://www.mediawiki.org/' ). See expandAttributes() for * further documentation. - * @param array $modifiers to add to the button + * @param string[] $modifiers to add to the button * @see http://tools.wmflabs.org/styleguide/desktop/index.html for guidance on available modifiers * @return string Raw HTML */ public static function linkButton( $contents, $attrs, $modifiers = array() ) { - return Html::element( 'a', + return self::element( 'a', self::buttonAttributes( $attrs, $modifiers ), $contents ); @@ -188,14 +185,14 @@ class Html { * @param array $attrs Associative array of attributes, e.g., array( * 'href' => 'http://www.mediawiki.org/' ). See expandAttributes() for * further documentation. - * @param array $modifiers to add to the button + * @param string[] $modifiers to add to the button * @see http://tools.wmflabs.org/styleguide/desktop/index.html for guidance on available modifiers * @return string Raw HTML */ public static function submitButton( $contents, $attrs, $modifiers = array() ) { $attrs['type'] = 'submit'; $attrs['value'] = $contents; - return Html::element( 'input', self::buttonAttributes( $attrs, $modifiers ) ); + return self::element( 'input', self::buttonAttributes( $attrs, $modifiers ) ); } /** @@ -603,17 +600,20 @@ class Html { } else { // Apparently we need to entity-encode \n, \r, \t, although the // spec doesn't mention that. Since we're doing strtr() anyway, - // and we don't need <> escaped here, we may as well not call - // htmlspecialchars(). + // we may as well not call htmlspecialchars(). // @todo FIXME: Verify that we actually need to // escape \n\r\t here, and explain why, exactly. # // We could call Sanitizer::encodeAttribute() for this, but we // don't because we're stubborn and like our marginal savings on // byte size from not having to encode unnecessary quotes. + // The only difference between this transform and the one by + // Sanitizer::encodeAttribute() is '<' is only encoded here if + // $wgWellFormedXml is set, and ' is not encoded. $map = array( '&' => '&', '"' => '"', + '>' => '>', "\n" => ' ', "\r" => ' ', "\t" => ' ' @@ -708,7 +708,7 @@ class Html { * new HTML5 input types and attributes. * * @param string $name Name attribute - * @param array $value Value attribute + * @param string $value Value attribute * @param string $type Type attribute * @param array $attribs Associative array of miscellaneous extra * attributes, passed to Html::element() @@ -719,7 +719,7 @@ class Html { $attribs['value'] = $value; $attribs['name'] = $name; if ( in_array( $type, array( 'text', 'search', 'email', 'password', 'number' ) ) ) { - $attribs = Html::getTextInputAttributes( $attribs ); + $attribs = self::getTextInputAttributes( $attribs ); } return self::element( 'input', $attribs ); } @@ -730,7 +730,7 @@ class Html { * @param string $name Name attribute * @param bool $checked Whether the checkbox is checked or not * @param array $attribs Array of additional attributes - * @return string + * @return string Raw HTML */ public static function check( $name, $checked = false, array $attribs = array() ) { if ( isset( $attribs['value'] ) ) { @@ -753,7 +753,7 @@ class Html { * @param string $name Name attribute * @param bool $checked Whether the checkbox is checked or not * @param array $attribs Array of additional attributes - * @return string + * @return string Raw HTML */ public static function radio( $name, $checked = false, array $attribs = array() ) { if ( isset( $attribs['value'] ) ) { @@ -776,7 +776,7 @@ class Html { * @param string $label Contents of the label * @param string $id ID of the element being labeled * @param array $attribs Additional attributes - * @return string + * @return string Raw HTML */ public static function label( $label, $id, array $attribs = array() ) { $attribs += array( @@ -822,7 +822,7 @@ class Html { } else { $spacedValue = $value; } - return self::element( 'textarea', Html::getTextInputAttributes( $attribs ), $spacedValue ); + return self::element( 'textarea', self::getTextInputAttributes( $attribs ), $spacedValue ); } /** @@ -893,7 +893,7 @@ class Html { } elseif ( is_int( $nsId ) ) { $nsName = $wgContLang->convertNamespace( $nsId ); } - $optionsHtml[] = Html::element( + $optionsHtml[] = self::element( 'option', array( 'disabled' => in_array( $nsId, $params['disable'] ), 'value' => $nsId, @@ -912,7 +912,7 @@ class Html { $ret = ''; if ( isset( $params['label'] ) ) { - $ret .= Html::element( + $ret .= self::element( 'label', array( 'for' => isset( $selectAttribs['id'] ) ? $selectAttribs['id'] : null, ), $params['label'] @@ -920,11 +920,11 @@ class Html { } // Wrap options in a