Merge "Import the PSR logger classes in Message"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 5 Jul 2019 06:59:10 +0000 (06:59 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 5 Jul 2019 06:59:10 +0000 (06:59 +0000)
21 files changed:
includes/OutputPage.php
includes/ProtectionForm.php
includes/ReadOnlyMode.php
includes/Revision/RevisionStore.php
includes/Revision/SlotRecord.php
includes/SiteStatsInit.php
includes/actions/HistoryAction.php
includes/db/MWLBFactory.php
includes/libs/objectcache/MultiWriteBagOStuff.php
includes/libs/objectcache/RedisBagOStuff.php
includes/libs/rdbms/database/DBConnRef.php
includes/resourceloader/ResourceLoaderStartUpModule.php
includes/site/DBSiteStore.php
includes/specials/forms/PreferencesFormOOUI.php
includes/watcheditem/WatchedItemQueryService.php
languages/i18n/en.json
maintenance/populateRevisionSha1.php
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.TagItemWidget.less
resources/src/startup/mediawiki.js
tests/phpunit/includes/OutputPageTest.php
tests/phpunit/includes/Revision/SlotRecordTest.php

index 28e0a31..58b025a 100644 (file)
@@ -3712,43 +3712,54 @@ class OutputPage extends ContextSource {
         */
        protected function buildExemptModules() {
                $chunks = [];
-               // Things that go after the ResourceLoaderDynamicStyles marker
-               $append = [];
 
-               // We want site, private and user styles to override dynamically added styles from
-               // general modules, but we want dynamically added styles to override statically added
-               // style modules. So the order has to be:
-               // - page style modules (formatted by ResourceLoaderClientHtml::getHeadHtml())
-               // - dynamically loaded styles (added by mw.loader before ResourceLoaderDynamicStyles)
-               // - ResourceLoaderDynamicStyles marker
-               // - site/private/user styles
+               // Requirements:
+               // - Within modules provided by the software (core, skin, extensions),
+               //   styles from skin stylesheets should be overridden by styles
+               //   from modules dynamically loaded with JavaScript.
+               // - Styles from site-specific, private, and user modules should override
+               //   both of the above.
+               //
+               // The effective order for stylesheets must thus be:
+               // 1. Page style modules, formatted server-side by ResourceLoaderClientHtml.
+               // 2. Dynamically-loaded styles, inserted client-side by mw.loader.
+               // 3. Styles that are site-specific, private or from the user, formatted
+               //    server-side by this function.
+               //
+               // The 'ResourceLoaderDynamicStyles' marker helps JavaScript know where
+               // point #2 is.
 
                // Add legacy styles added through addStyle()/addInlineStyle() here
                $chunks[] = implode( '', $this->buildCssLinksArray() ) . $this->mInlineStyles;
 
-               $chunks[] = Html::element(
-                       'meta',
-                       [ 'name' => 'ResourceLoaderDynamicStyles', 'content' => '' ]
-               );
-
+               // Things that go after the ResourceLoaderDynamicStyles marker
+               $append = [];
                $separateReq = [ 'site.styles', 'user.styles' ];
                foreach ( $this->rlExemptStyleModules as $group => $moduleNames ) {
-                       // Combinable modules
-                       $chunks[] = $this->makeResourceLoaderLink(
-                               array_diff( $moduleNames, $separateReq ),
-                               ResourceLoaderModule::TYPE_STYLES
-                       );
-
-                       foreach ( array_intersect( $moduleNames, $separateReq ) as $name ) {
-                               // These require their own dedicated request in order to support "@import"
-                               // syntax, which is incompatible with concatenation. (T147667, T37562)
-                               $chunks[] = $this->makeResourceLoaderLink( $name,
+                       if ( $moduleNames ) {
+                               $append[] = $this->makeResourceLoaderLink(
+                                       array_diff( $moduleNames, $separateReq ),
                                        ResourceLoaderModule::TYPE_STYLES
                                );
+
+                               foreach ( array_intersect( $moduleNames, $separateReq ) as $name ) {
+                                       // These require their own dedicated request in order to support "@import"
+                                       // syntax, which is incompatible with concatenation. (T147667, T37562)
+                                       $append[] = $this->makeResourceLoaderLink( $name,
+                                               ResourceLoaderModule::TYPE_STYLES
+                                       );
+                               }
                        }
                }
+               if ( $append ) {
+                       $chunks[] = Html::element(
+                               'meta',
+                               [ 'name' => 'ResourceLoaderDynamicStyles', 'content' => '' ]
+                       );
+                       $chunks = array_merge( $chunks, $append );
+               }
 
-               return self::combineWrappedStrings( array_merge( $chunks, $append ) );
+               return self::combineWrappedStrings( $chunks );
        }
 
        /**
index 2f10598..4bead34 100644 (file)
@@ -200,7 +200,7 @@ class ProtectionForm {
        /**
         * Show the input form with optional error message
         *
-        * @param string|null $err Error message or null if there's no error
+        * @param string|string[]|null $err Error message or null if there's no error
         */
        function show( $err = null ) {
                $out = $this->mContext->getOutput();
index 1a09290..d0da10e 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-use Wikimedia\Rdbms\LoadBalancer;
+use Wikimedia\Rdbms\ILoadBalancer;
 
 /**
  * A service class for fetching the wiki's current read-only mode.
@@ -12,10 +12,10 @@ class ReadOnlyMode {
        /** @var ConfiguredReadOnlyMode */
        private $configuredReadOnly;
 
-       /** @var LoadBalancer */
+       /** @var ILoadBalancer */
        private $loadBalancer;
 
-       public function __construct( ConfiguredReadOnlyMode $cro, LoadBalancer $loadBalancer ) {
+       public function __construct( ConfiguredReadOnlyMode $cro, ILoadBalancer $loadBalancer ) {
                $this->configuredReadOnly = $cro;
                $this->loadBalancer = $loadBalancer;
        }
index f269afe..ec1c08c 100644 (file)
@@ -63,7 +63,7 @@ use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\DBConnRef;
 use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\ILoadBalancer;
-use Wikimedia\Rdbms\ResultWrapper;
+use Wikimedia\Rdbms\IResultWrapper;
 
 /**
  * Service for looking up page revisions.
@@ -1638,7 +1638,7 @@ class RevisionStore
         * Factory method for SlotRecords based on known slot rows.
         *
         * @param int $revId The revision to load slots for.
-        * @param object[]|ResultWrapper $slotRows
+        * @param object[]|IResultWrapper $slotRows
         * @param int $queryFlags
         * @param Title $title
         *
index 064f7a4..7465f79 100644 (file)
@@ -539,6 +539,11 @@ class SlotRecord {
                try {
                        $sha1 = $this->getStringField( 'content_sha1' );
                } catch ( IncompleteRevisionException $ex ) {
+                       $sha1 = null;
+               }
+
+               // Compute if missing. Missing could mean null or empty.
+               if ( $sha1 === null || $sha1 === '' ) {
                        $format = $this->hasField( 'format_name' )
                                ? $this->getStringField( 'format_name' )
                                : null;
index e97db2d..932e1c3 100644 (file)
@@ -191,7 +191,7 @@ class SiteStatsInit {
 
        /**
         * @param int $index
-        * @param string[] $groups
+        * @param string[]|string $groups
         * @return IDatabase
         */
        private static function getDB( $index, $groups = [] ) {
index b1d5a50..4df2f56 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\ResultWrapper;
+use Wikimedia\Rdbms\IResultWrapper;
 use Wikimedia\Rdbms\FakeResultWrapper;
 
 /**
@@ -313,7 +313,7 @@ class HistoryAction extends FormlessAction {
         * @param int $limit The limit number of revisions to get
         * @param int $offset
         * @param int $direction Either self::DIR_PREV or self::DIR_NEXT
-        * @return ResultWrapper
+        * @return IResultWrapper
         */
        function fetchRevisions( $limit, $offset, $direction ) {
                // Fail if article doesn't exist.
index 27695cc..3d404d3 100644 (file)
@@ -70,6 +70,7 @@ abstract class MWLBFactory {
         * @param BagOStuff $mainStash
         * @param WANObjectCache $wanCache
         * @return array
+        * @internal For use with service wiring
         */
        public static function applyDefaultConfig(
                array $lbConf,
@@ -152,8 +153,11 @@ abstract class MWLBFactory {
                        $serversCheck = [ $lbConf['serverTemplate'] ] ?? [];
                }
 
-               self::assertValidServerConfigs( $serversCheck, $options->get( 'DBname' ),
-                       $options->get( 'DBprefix' ) );
+               self::assertValidServerConfigs(
+                       $serversCheck,
+                       $options->get( 'DBname' ),
+                       $options->get( 'DBprefix' )
+               );
 
                $lbConf = self::injectObjectCaches( $lbConf, $srvCace, $mainStash, $wanCache );
 
@@ -164,7 +168,7 @@ abstract class MWLBFactory {
         * @return array
         */
        private static function getDbTypesWithSchemas() {
-               return [ 'postgres', 'msssql' ];
+               return [ 'postgres', 'mssql' ];
        }
 
        /**
@@ -328,6 +332,7 @@ abstract class MWLBFactory {
         *
         * @param array $config (e.g. $wgLBFactoryConf)
         * @return string Class name
+        * @internal For use with service wiring
         */
        public static function getLBFactoryClass( array $config ) {
                // For configuration backward compatibility after removing
@@ -365,13 +370,9 @@ abstract class MWLBFactory {
        /**
         * @param LBFactory $lbFactory
         * @param string $dbType 'mysql', 'sqlite', etc.
+        * @internal For use with service wiring
         */
        public static function setSchemaAliases( LBFactory $lbFactory, $dbType ) {
-               if ( $dbType instanceof Config ) {
-                       // Before 1.34 this took a whole Config just to get $dbType
-                       wfDeprecated( __METHOD__ . ' with Config argument', '1.34' );
-                       $dbType = $dbType->get( 'DBtype' );
-               }
                if ( $dbType === 'mysql' ) {
                        /**
                         * When SQLite indexes were introduced in r45764, it was noted that
@@ -398,6 +399,7 @@ abstract class MWLBFactory {
        /**
         * Log a database deprecation warning
         * @param string $msg Deprecation message
+        * @internal For use with service wiring
         */
        public static function logDeprecation( $msg ) {
                global $wgDevelopmentWarnings;
index 0503382..e832734 100644 (file)
@@ -299,7 +299,7 @@ class MultiWriteBagOStuff extends BagOStuff {
         * @param int[] $indexes List of backing cache indexes
         * @param bool $asyncWrites
         * @param string $method Method name of backing caches
-        * @param array[] $args Arguments to the method of backing caches
+        * @param array $args Arguments to the method of backing caches
         * @return bool
         */
        protected function doWrite( $indexes, $asyncWrites, $method, array $args ) {
index 0ba9c3f..743b9eb 100644 (file)
@@ -427,7 +427,7 @@ class RedisBagOStuff extends BagOStuff {
         * not. The safest response for us is to explicitly destroy the connection
         * object and let it be reopened during the next request.
         * @param RedisConnRef $conn
-        * @param Exception $e
+        * @param RedisException $e
         */
        protected function handleException( RedisConnRef $conn, $e ) {
                $this->setLastError( BagOStuff::ERR_UNEXPECTED );
index c8e31df..d80a718 100644 (file)
@@ -28,7 +28,7 @@ class DBConnRef implements IDatabase {
 
        /**
         * @param ILoadBalancer $lb Connection manager for $conn
-        * @param Database|array $conn Database or (server index, query groups, domain, flags)
+        * @param IDatabase|array $conn Database or (server index, query groups, domain, flags)
         * @param int $role The type of connection asked for; one of DB_MASTER/DB_REPLICA
         * @internal This method should not be called outside of LoadBalancer
         */
index f0de411..7880f6f 100644 (file)
@@ -105,7 +105,6 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                        'wgCaseSensitiveNamespaces' => $caseSensitiveNamespaces,
                        'wgLegalTitleChars' => Title::convertByteClassToUnicodeClass( Title::legalChars() ),
                        'wgIllegalFileChars' => Title::convertByteClassToUnicodeClass( $illegalFileChars ),
-                       'wgResourceLoaderStorageVersion' => $conf->get( 'ResourceLoaderStorageVersion' ),
                        'wgResourceLoaderStorageEnabled' => $conf->get( 'ResourceLoaderStorageEnabled' ),
                        'wgForeignUploadTargets' => $conf->get( 'ForeignUploadTargets' ),
                        'wgEnableUploads' => $conf->get( 'EnableUploads' ),
@@ -367,6 +366,30 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                return $baseModules;
        }
 
+       /**
+        * Get the localStorage key for the entire module store. The key references
+        * $wgDBname to prevent clashes between wikis under the same web domain.
+        *
+        * @return string localStorage item key for JavaScript
+        */
+       private function getStoreKey() {
+               return 'MediaWikiModuleStore:' . $this->getConfig()->get( 'DBname' );
+       }
+
+       /**
+        * Get the key on which the JavaScript module cache (mw.loader.store) will vary.
+        *
+        * @param ResourceLoaderContext $context
+        * @return string String of concatenated vary conditions
+        */
+       private function getStoreVary( ResourceLoaderContext $context ) {
+               return implode( ':', [
+                       $context->getSkin(),
+                       $this->getConfig()->get( 'ResourceLoaderStorageVersion' ),
+                       $context->getLanguage(),
+               ] );
+       }
+
        /**
         * @param ResourceLoaderContext $context
         * @return string JavaScript code
@@ -399,6 +422,8 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule {
                        '$VARS.maxQueryLength' => ResourceLoader::encodeJsonForScript(
                                $conf->get( 'ResourceLoaderMaxQueryLength' )
                        ),
+                       '$VARS.storeKey' => ResourceLoader::encodeJsonForScript( $this->getStoreKey() ),
+                       '$VARS.storeVary' => ResourceLoader::encodeJsonForScript( $this->getStoreVary( $context ) ),
                ];
                $profilerStubs = [
                        '$CODE.profileExecuteStart();' => 'mw.loader.profiler.onExecuteStart( module );',
index b2403ce..bb6a6b3 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-use Wikimedia\Rdbms\LoadBalancer;
+use Wikimedia\Rdbms\ILoadBalancer;
 
 /**
  * Represents the site configuration of a wiki.
@@ -38,7 +38,7 @@ class DBSiteStore implements SiteStore {
        protected $sites = null;
 
        /**
-        * @var LoadBalancer
+        * @var ILoadBalancer
         */
        private $dbLoadBalancer;
 
@@ -48,9 +48,9 @@ class DBSiteStore implements SiteStore {
         * @todo inject some kind of connection manager that is aware of the target wiki,
         * instead of injecting a LoadBalancer.
         *
-        * @param LoadBalancer $dbLoadBalancer
+        * @param ILoadBalancer $dbLoadBalancer
         */
-       public function __construct( LoadBalancer $dbLoadBalancer ) {
+       public function __construct( ILoadBalancer $dbLoadBalancer ) {
                $this->dbLoadBalancer = $dbLoadBalancer;
        }
 
index 9b86812..5dae156 100644 (file)
@@ -146,9 +146,8 @@ class PreferencesFormOOUI extends OOUIHTMLForm {
                                ) .
                                $this->getFooterText( $key );
 
-                       $tabPanels[] = new OOUI\TabPanelLayout( [
+                       $tabPanels[] = new OOUI\TabPanelLayout( 'mw-prefsection-' . $key, [
                                'classes' => [ 'mw-htmlform-autoinfuse-lazy' ],
-                               'name' => 'mw-prefsection-' . $key,
                                'label' => $label,
                                'content' => new OOUI\FieldsetLayout( [
                                        'classes' => [ 'mw-prefs-section-fieldset' ],
index b134bfe..f6ad623 100644 (file)
@@ -4,7 +4,7 @@ use MediaWiki\Linker\LinkTarget;
 use MediaWiki\User\UserIdentity;
 use Wikimedia\Assert\Assert;
 use Wikimedia\Rdbms\IDatabase;
-use Wikimedia\Rdbms\LoadBalancer;
+use Wikimedia\Rdbms\ILoadBalancer;
 
 /**
  * Class performing complex database queries related to WatchedItems.
@@ -53,7 +53,7 @@ class WatchedItemQueryService {
        const SORT_DESC = 'DESC';
 
        /**
-        * @var LoadBalancer
+        * @var ILoadBalancer
         */
        private $loadBalancer;
 
@@ -70,7 +70,7 @@ class WatchedItemQueryService {
        private $watchedItemStore;
 
        public function __construct(
-               LoadBalancer $loadBalancer,
+               ILoadBalancer $loadBalancer,
                CommentStore $commentStore,
                ActorMigration $actorMigration,
                WatchedItemStoreInterface $watchedItemStore
index e33e9bd..0da5c5f 100644 (file)
        "edit-error-short": "Error: $1",
        "edit-error-long": "Errors:\n\n$1",
        "specialmute": "Mute",
-       "specialmute-success": "Your mute preferences have been successfully updated. See all muted users in [[Special:Preferences]].",
+       "specialmute-success": "Your mute preferences have been updated. See all muted users in [[Special:Preferences|your preferences]].",
        "specialmute-submit": "Confirm",
        "specialmute-label-mute-email": "Mute emails from this user",
        "specialmute-header": "Please select your mute preferences for {{BIDI:[[User:$1]]}}.",
index 9662044..f91a5b6 100644 (file)
@@ -24,6 +24,8 @@
 
 require_once __DIR__ . '/Maintenance.php';
 
+use MediaWiki\MediaWikiServices;
+
 /**
  * Maintenance script that fills the rev_sha1 and ar_sha1 columns of revision
  * and archive tables for revisions created before MW 1.19.
@@ -50,17 +52,22 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
                        $this->fatalError( "archive table does not exist" );
                } elseif ( !$db->fieldExists( 'revision', 'rev_sha1', __METHOD__ ) ) {
                        $this->output( "rev_sha1 column does not exist\n\n", true );
-
                        return false;
                }
 
+               $revStore = MediaWikiServices::getInstance()->getRevisionStore();
+
                $this->output( "Populating rev_sha1 column\n" );
-               $rc = $this->doSha1Updates( 'revision', 'rev_id', Revision::getQueryInfo(), 'rev' );
+               $rc = $this->doSha1Updates( $revStore, 'revision', 'rev_id',
+                       $revStore->getQueryInfo(), 'rev'
+               );
 
                $this->output( "Populating ar_sha1 column\n" );
-               $ac = $this->doSha1Updates( 'archive', 'ar_rev_id', Revision::getArchiveQueryInfo(), 'ar' );
+               $ac = $this->doSha1Updates( $revStore, 'archive', 'ar_rev_id',
+                       $revStore->getArchiveQueryInfo(), 'ar'
+               );
                $this->output( "Populating ar_sha1 column legacy rows\n" );
-               $ac += $this->doSha1LegacyUpdates();
+               $ac += $this->doSha1LegacyUpdates( $revStore );
 
                $this->output( "rev_sha1 and ar_sha1 population complete "
                        . "[$rc revision rows, $ac archive rows].\n" );
@@ -69,13 +76,14 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
        }
 
        /**
+        * @param MediaWiki\Revision\RevisionStore $revStore
         * @param string $table
         * @param string $idCol
         * @param array $queryInfo
         * @param string $prefix
         * @return int Rows changed
         */
-       protected function doSha1Updates( $table, $idCol, $queryInfo, $prefix ) {
+       protected function doSha1Updates( $revStore, $table, $idCol, $queryInfo, $prefix ) {
                $db = $this->getDB( DB_MASTER );
                $batchSize = $this->getBatchSize();
                $start = $db->selectField( $table, "MIN($idCol)", '', __METHOD__ );
@@ -93,6 +101,7 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
                $blockEnd = $start + $batchSize - 1;
                while ( $blockEnd <= $end ) {
                        $this->output( "...doing $idCol from $blockStart to $blockEnd\n" );
+
                        $cond = "$idCol BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd .
                                " AND $idCol IS NOT NULL AND {$prefix}_sha1 = ''";
                        $res = $db->select(
@@ -101,7 +110,7 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
 
                        $this->beginTransaction( $db, __METHOD__ );
                        foreach ( $res as $row ) {
-                               if ( $this->upgradeRow( $row, $table, $idCol, $prefix ) ) {
+                               if ( $this->upgradeRow( $revStore, $row, $table, $idCol, $prefix ) ) {
                                        $count++;
                                }
                        }
@@ -115,19 +124,21 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
        }
 
        /**
+        * @param MediaWiki\Revision\RevisionStore $revStore
+        * @param string $emptySha1
         * @return int
         */
-       protected function doSha1LegacyUpdates() {
+       protected function doSha1LegacyUpdates( $revStore ) {
                $count = 0;
                $db = $this->getDB( DB_MASTER );
-               $arQuery = Revision::getArchiveQueryInfo();
+               $arQuery = $revStore->getArchiveQueryInfo();
                $res = $db->select( $arQuery['tables'], $arQuery['fields'],
                        [ 'ar_rev_id IS NULL', 'ar_sha1' => '' ], __METHOD__, [], $arQuery['joins'] );
 
                $updateSize = 0;
                $this->beginTransaction( $db, __METHOD__ );
                foreach ( $res as $row ) {
-                       if ( $this->upgradeLegacyArchiveRow( $row ) ) {
+                       if ( $this->upgradeLegacyArchiveRow( $revStore, $row ) ) {
                                ++$count;
                        }
                        if ( ++$updateSize >= 100 ) {
@@ -143,75 +154,67 @@ class PopulateRevisionSha1 extends LoggedUpdateMaintenance {
        }
 
        /**
+        * @param MediaWiki\Revision\RevisionStore $revStore
         * @param stdClass $row
         * @param string $table
         * @param string $idCol
         * @param string $prefix
         * @return bool
         */
-       protected function upgradeRow( $row, $table, $idCol, $prefix ) {
+       protected function upgradeRow( $revStore, $row, $table, $idCol, $prefix ) {
                $db = $this->getDB( DB_MASTER );
+
+               // Create a revision and use it to get the sha1 from the content table, if possible.
                try {
                        $rev = ( $table === 'archive' )
-                               ? Revision::newFromArchiveRow( $row )
-                               : new Revision( $row );
-                       $text = $rev->getSerializedData();
+                               ? $revStore->newRevisionFromArchiveRow( $row )
+                               : $revStore->newRevisionFromRow( $row );
+                       $sha1 = $rev->getSha1();
                } catch ( Exception $e ) {
                        $this->output( "Data of revision with {$idCol}={$row->$idCol} unavailable!\n" );
-
-                       return false; // T24624?
+                       return false; // T24624? T22757?
                }
-               if ( !is_string( $text ) ) {
-                       # This should not happen, but sometimes does (T22757)
-                       $this->output( "Data of revision with {$idCol}={$row->$idCol} unavailable!\n" );
 
-                       return false;
-               } else {
-                       $db->update( $table,
-                               [ "{$prefix}_sha1" => Revision::base36Sha1( $text ) ],
-                               [ $idCol => $row->$idCol ],
-                               __METHOD__
-                       );
+               $db->update( $table,
+                       [ "{$prefix}_sha1" => $sha1 ],
+                       [ $idCol => $row->$idCol ],
+                       __METHOD__
+               );
 
-                       return true;
-               }
+               return true;
        }
 
        /**
+        * @param MediaWiki\Revision\RevisionStore $revStore
         * @param stdClass $row
         * @return bool
         */
-       protected function upgradeLegacyArchiveRow( $row ) {
+       protected function upgradeLegacyArchiveRow( $revStore, $row ) {
                $db = $this->getDB( DB_MASTER );
+
+               // Create a revision and use it to get the sha1 from the content table, if possible.
                try {
-                       $rev = Revision::newFromArchiveRow( $row );
+                       $rev = $revStore->newRevisionFromArchiveRow( $row );
+                       $sha1 = $rev->getSha1();
                } catch ( Exception $e ) {
                        $this->output( "Text of revision with timestamp {$row->ar_timestamp} unavailable!\n" );
-
-                       return false; // T24624?
+                       return false; // T24624? T22757?
                }
-               $text = $rev->getSerializedData();
-               if ( !is_string( $text ) ) {
-                       # This should not happen, but sometimes does (T22757)
-                       $this->output( "Data of revision with timestamp {$row->ar_timestamp} unavailable!\n" );
 
-                       return false;
-               } else {
-                       # Archive table as no PK, but (NS,title,time) should be near unique.
-                       # Any duplicates on those should also have duplicated text anyway.
-                       $db->update( 'archive',
-                               [ 'ar_sha1' => Revision::base36Sha1( $text ) ],
-                               [
-                                       'ar_namespace' => $row->ar_namespace,
-                                       'ar_title' => $row->ar_title,
-                                       'ar_timestamp' => $row->ar_timestamp,
-                                       'ar_len' => $row->ar_len // extra sanity
-                               ],
-                               __METHOD__
-                       );
+               # Archive table has no PK, but (NS,title,time) should be near unique.
+               # Any duplicates on those should also have duplicated text anyway.
+               $db->update( 'archive',
+                       [ 'ar_sha1' => $sha1 ],
+                       [
+                               'ar_namespace' => $row->ar_namespace,
+                               'ar_title' => $row->ar_title,
+                               'ar_timestamp' => $row->ar_timestamp,
+                               'ar_len' => $row->ar_len // extra sanity
+                       ],
+                       __METHOD__
+               );
 
-                       return true;
-               }
+               return true;
        }
 }
 
index 31a5f54..4f645b9 100644 (file)
@@ -42,7 +42,7 @@
                color: @colorGray5;
        }
 
-       &.oo-ui-labelElement .oo-ui-labelElement-label {
+       &.oo-ui-labelElement:not( .oo-ui-tagItemWidget-fixed ) .oo-ui-labelElement-label {
                cursor: pointer;
        }
 
index d339704..dbb32e5 100644 (file)
                                         * @return {string} localStorage item key
                                         */
                                        getStoreKey: function () {
-                                               return 'MediaWikiModuleStore:' + mw.config.get( 'wgDBname' );
+                                               return $VARS.storeKey;
                                        },
 
                                        /**
                                         * @return {string} String of concatenated vary conditions.
                                         */
                                        getVary: function () {
-                                               return mw.config.get( 'skin' ) + ':' +
-                                                       mw.config.get( 'wgResourceLoaderStorageVersion' ) + ':' +
-                                                       mw.config.get( 'wgUserLanguage' );
+                                               return $VARS.storeVary;
                                        },
 
                                        /**
index 243a90d..448eec8 100644 (file)
@@ -2674,11 +2674,11 @@ class OutputPageTest extends MediaWikiTestCase {
                return [
                        'empty' => [
                                'exemptStyleModules' => [],
-                               '<meta name="ResourceLoaderDynamicStyles" content=""/>',
+                               '',
                        ],
                        'empty sets' => [
                                'exemptStyleModules' => [ 'site' => [], 'noscript' => [], 'private' => [], 'user' => [] ],
-                               '<meta name="ResourceLoaderDynamicStyles" content=""/>',
+                               '',
                        ],
                        'default logged-out' => [
                                'exemptStyleModules' => [ 'site' => [ 'site.styles' ] ],
index 1b6ff2a..6495967 100644 (file)
@@ -77,7 +77,7 @@ class SlotRecordTest extends MediaWikiTestCase {
                $this->assertFalse( $record->isInherited() );
                $this->assertSame( 'A', $record->getContent()->getText() );
                $this->assertSame( 1, $record->getSize() );
-               $this->assertNotNull( $record->getSha1() );
+               $this->assertNotEmpty( $record->getSha1() );
                $this->assertSame( CONTENT_MODEL_WIKITEXT, $record->getModel() );
                $this->assertSame( 2, $record->getRevision() );
                $this->assertSame( 2, $record->getRevision() );
@@ -96,7 +96,7 @@ class SlotRecordTest extends MediaWikiTestCase {
                $this->assertFalse( $record->hasOrigin() );
                $this->assertSame( 'A', $record->getContent()->getText() );
                $this->assertSame( 1, $record->getSize() );
-               $this->assertNotNull( $record->getSha1() );
+               $this->assertNotEmpty( $record->getSha1() );
                $this->assertSame( CONTENT_MODEL_WIKITEXT, $record->getModel() );
                $this->assertSame( 'myRole', $record->getRole() );
        }
@@ -177,6 +177,14 @@ class SlotRecordTest extends MediaWikiTestCase {
                $this->assertSame( $hash, $record->getSha1() );
        }
 
+       public function testHashComputed() {
+               $row = $this->makeRow();
+               $row->content_sha1 = '';
+
+               $rec = new SlotRecord( $row, new WikitextContent( 'A' ) );
+               $this->assertNotEmpty( $rec->getSha1() );
+       }
+
        public function testNewWithSuppressedContent() {
                $input = new SlotRecord( $this->makeRow(), new WikitextContent( 'A' ) );
                $output = SlotRecord::newWithSuppressedContent( $input );