module should express a dependency on it.
* Removed configuration option $wgCopyrightIcon (deprecated since 1.18). Use
$wgFooterIcons['copyright']['copyright'] instead.
-* ApiMain::getShowVersions() was removed (deprecated in 1.21).
-* ApiMain::addModule() was removed (deprecated in 1.21).
-* ApiMain::addFormat() was removed (deprecated in 1.21).
-* ApiMain::getFormats() was removed (deprecated in 1.21).
-* ApiPageSet::finishPageSetGeneration() was removed (deprecated in 1.21).
=== New features in 1.27 ===
* $wgDataCenterUpdateStickTTL was also added. This decides how long a user
* ApiQuery::setGeneratorContinue() was removed (deprecated since 1.24).
* ApiMain::getModules() was removed (deprecated since 1.21).
* ApiBase::getVersion() was removed (deprecated since 1.21).
-* Language::getLangObj() was removed (deprecated since 1.24).
-* Language::getLanguageName() was removed (deprecated since 1.20).
-* Language::getLanguageNames() was removed (deprecated since 1.20).
-* Language::getTranslatedLanguageNames() was removed (deprecated since 1.20).
-* Language::specialPage() was removed (deprecated since 1.24).
-* MediaWikiTestCase::assertException() was removed (deprecated since 1.22).
-* OutputPage::getHeadItems() was removed (deprecated since 1.24).
-* OutputPage::getScript() was removed (deprecated since 1.24).
-* OutputPage::out() was removed (deprecated since 1.22).
-* OutputPage::setAllowedModules() was removed (deprecated since 1.24).
-* UserrightsPage::makeGroupNameListForLog() was removed (deprecated since 1.21).
-* MediaWikiSite::newFromGlobalId() was removed (deprecated since 1.21).
+* ApiMain::getShowVersions() was removed (deprecated in 1.21).
+* ApiMain::addModule() was removed (deprecated in 1.21).
+* ApiMain::addFormat() was removed (deprecated in 1.21).
+* ApiMain::getFormats() was removed (deprecated in 1.21).
+* ApiPageSet::finishPageSetGeneration() was removed (deprecated in 1.21).
=== Languages updated in 1.27 ===
way. Run `composer install` to install it and other dev dependencies to run unit tests.
* wl_id field added to the watchlist table.
* Revision::getRawText() was removed (deprecated since 1.21).
+* WikiPage::replaceSection() was removed (deprecated since 1.21).
+* Article::replaceSection() was removed (deprecated since 1.21).
+* Language::getLangObj() was removed (deprecated since 1.24).
+* Language::getLanguageName() was removed (deprecated since 1.20).
+* Language::getLanguageNames() was removed (deprecated since 1.20).
+* Language::getTranslatedLanguageNames() was removed (deprecated since 1.20).
+* Language::specialPage() was removed (deprecated since 1.24).
+* MediaWikiTestCase::assertException() was removed (deprecated since 1.22).
+* OutputPage::getHeadItems() was removed (deprecated since 1.24).
+* OutputPage::getScript() was removed (deprecated since 1.24).
+* OutputPage::out() was removed (deprecated since 1.22).
+* OutputPage::setAllowedModules() was removed (deprecated since 1.24).
+* UserrightsPage::makeGroupNameListForLog() was removed (deprecated since 1.21).
+* MediaWikiSite::newFromGlobalId() was removed (deprecated since 1.21).
+* Title::newFromRedirect() was removed (deprecated since 1.21).
+* Skin::commonPrintStylesheet() was removed (deprecated since 1.22).
+* Skin::getCommonStylePath() was removed (deprecated since 1.24).
+* Skin::newFromKey() was removed (deprecated since 1.24).
+* Skin::getUsableSkins() was removed (deprecated since 1.23).
+* LoadBalancer::pickRandom() was removed (deprecated in 1.21).
== Compatibility ==
* Get the content of the wanted revision, without section extraction.
*
* The result of this function can be used to compare user's input with
- * section replaced in its context (using WikiPage::replaceSection())
+ * section replaced in its context (using WikiPage::replaceSectionAtRev())
* to the original text of the edit.
*
* This differs from Article::getContent() that when a missing revision is
} elseif ( $this->section != '' ) {
# Try to get a section anchor from the section source, redirect
# to edited section if header found.
- # XXX: Might be better to integrate this into Article::replaceSection
+ # XXX: Might be better to integrate this into Article::replaceSectionAtRev
# for duplicate heading checking and maybe parsing.
$hasmatch = preg_match( "/^ *([=]{1,6})(.*?)(\\1) *\\n/i", $this->textbox1, $matches );
# We can't deal with anchors, includes, html etc in the header for now,
);
}
-if ( isset( $wgFooterIcons['copyright'] )
- && isset( $wgFooterIcons['copyright']['copyright'] )
+if ( isset( $wgFooterIcons['copyright']['copyright'] )
&& $wgFooterIcons['copyright']['copyright'] === []
) {
if ( $wgRightsIcon || $wgRightsText ) {
'src' => $wgRightsIcon,
'alt' => $wgRightsText,
];
- } else {
- unset( $wgFooterIcons['copyright']['copyright'] );
}
}
return $title;
}
- /**
- * Extract a redirect destination from a string and return the
- * Title, or null if the text doesn't contain a valid redirect
- * This will only return the very next target, useful for
- * the redirect table and other checks that don't need full recursion
- *
- * @param string $text Text with possible redirect
- * @return Title The corresponding Title
- * @deprecated since 1.21, use Content::getRedirectTarget instead.
- */
- public static function newFromRedirect( $text ) {
- ContentHandler::deprecated( __METHOD__, '1.21' );
-
- $content = ContentHandler::makeContent( $text, null, CONTENT_MODEL_WIKITEXT );
- return $content->getRedirectTarget();
- }
-
/**
* Extract a redirect destination from a string and return the
* Title, or null if the text doesn't contain a valid redirect
protected $lastKnownSlavePos;
/** @var string Method to detect slave lag */
protected $lagDetectionMethod;
+ /** @var array Method to detect slave lag */
+ protected $lagDetectionOptions = [];
/** @var string|null */
private $serverVersion = null;
* pt-heartbeat assumes the table is at heartbeat.heartbeat
* and uses UTC timestamps in the heartbeat.ts column.
* (https://www.percona.com/doc/percona-toolkit/2.2/pt-heartbeat.html)
+ * - lagDetectionOptions : if using pt-heartbeat, this can be set to an array map to change
+ * the default behavior. Normally, the heartbeat row with the server
+ * ID of this server's master will be used. Set the "conds" field to
+ * override the query conditions, e.g. ['shard' => 's1'].
* @param array $params
*/
function __construct( array $params ) {
$this->lagDetectionMethod = isset( $params['lagDetectionMethod'] )
? $params['lagDetectionMethod']
: 'Seconds_Behind_Master';
+ $this->lagDetectionOptions = isset( $params['lagDetectionOptions'] )
+ ? $params['lagDetectionOptions']
+ : [];
}
/**
* @return bool|float
*/
protected function getLagFromPtHeartbeat() {
- $masterInfo = $this->getMasterServerInfo();
- if ( !$masterInfo ) {
- wfLogDBError(
- "Unable to query master of {db_server} for server ID",
- $this->getLogContext( [
- 'method' => __METHOD__
- ] )
- );
+ $options = $this->lagDetectionOptions;
+
+ if ( isset( $options['conds'] ) ) {
+ // Best method for multi-DC setups: use logical channel names
+ $data = $this->getHeartbeatData( $options['conds'] );
+ } else {
+ // Standard method: use master server ID (works with stock pt-heartbeat)
+ $masterInfo = $this->getMasterServerInfo();
+ if ( !$masterInfo ) {
+ wfLogDBError(
+ "Unable to query master of {db_server} for server ID",
+ $this->getLogContext( [
+ 'method' => __METHOD__
+ ] )
+ );
+
+ return false; // could not get master server ID
+ }
- return false; // could not get master server ID
+ $conds = [ 'server_id' => intval( $masterInfo['serverId'] ) ];
+ $data = $this->getHeartbeatData( $conds );
}
- list( $time, $nowUnix ) = $this->getHeartbeatData( $masterInfo['serverId'] );
+ list( $time, $nowUnix ) = $data;
if ( $time !== null ) {
// @time is in ISO format like "2015-09-25T16:48:10.000510"
$dateTime = new DateTime( $time, new DateTimeZone( 'UTC' ) );
}
/**
- * @param string $masterId Server ID
- * @return array (heartbeat `ts` column value or null, UNIX timestamp)
+ * @param array $conds WHERE clause conditions to find a row
+ * @return array (heartbeat `ts` column value or null, UNIX timestamp) for the newest beat
* @see https://www.percona.com/doc/percona-toolkit/2.1/pt-heartbeat.html
*/
- protected function getHeartbeatData( $masterId ) {
- // Get the status row for this master; use the oldest for sanity in case the master
- // has entries listed under different server IDs (which should really not happen).
- // Note: this would use "MAX(TIMESTAMPDIFF(MICROSECOND,ts,UTC_TIMESTAMP(6)))" but the
+ protected function getHeartbeatData( array $conds ) {
+ $whereSQL = $this->makeList( $conds, LIST_AND );
+ // Use ORDER BY for channel based queries since that field might not be UNIQUE.
+ // Note: this would use "TIMESTAMPDIFF(MICROSECOND,ts,UTC_TIMESTAMP(6))" but the
// percision field is not supported in MySQL <= 5.5.
$res = $this->query(
- "SELECT ts FROM heartbeat.heartbeat WHERE server_id=" . intval( $masterId )
+ "SELECT ts FROM heartbeat.heartbeat WHERE $whereSQL ORDER BY ts DESC LIMIT 1"
);
$row = $res ? $res->fetchObject() : false;
return wfSetVar( $this->mParentInfo, $x );
}
- /**
- * Given an array of non-normalised probabilities, this function will select
- * an element and return the appropriate key
- *
- * @deprecated since 1.21, use ArrayUtils::pickRandom()
- *
- * @param array $weights
- * @return bool|int|string
- */
- public function pickRandom( array $weights ) {
- return ArrayUtils::pickRandom( $weights );
- }
-
/**
* @param array $loads
* @param bool|string $wiki Wiki to get non-lagged for
$title,
htmlspecialchars( $title->getFullText() ),
[],
- // Automatically append redirect=no to each link, since most of them are
- // redirect pages themselves.
+ // Make sure wiki page redirects are not followed
$title->isRedirect() ? [ 'redirect' => 'no' ] : [],
( $forceKnown ? [ 'known', 'noclasses' ] : [] )
) . '</li>';
return $this->mPage->protectDescriptionLog( $limit, $expiry );
}
- /**
- * Call to WikiPage function for backwards compatibility.
- * @see WikiPage::replaceSection
- */
- public function replaceSection( $sectionId, $text, $sectionTitle = '',
- $edittime = null
- ) {
- ContentHandler::deprecated( __METHOD__, '1.21' );
- return $this->mPage->replaceSection( $sectionId, $text, $sectionTitle,
- $edittime
- );
- }
-
/**
* Call to WikiPage function for backwards compatibility.
* @see WikiPage::replaceSectionAtRev
return false;
}
- /**
- * @param string|number|null|bool $sectionId Section identifier as a number or string
- * (e.g. 0, 1 or 'T-1'), null/false or an empty string for the whole page
- * or 'new' for a new section.
- * @param string $text New text of the section.
- * @param string $sectionTitle New section's subject, only if $section is "new".
- * @param string $edittime Revision timestamp or null to use the current revision.
- *
- * @throws MWException
- * @return string|null New complete article text, or null if error.
- *
- * @deprecated since 1.21, use replaceSectionAtRev() instead
- */
- public function replaceSection( $sectionId, $text, $sectionTitle = '',
- $edittime = null
- ) {
- ContentHandler::deprecated( __METHOD__, '1.21' );
-
- // NOTE: keep condition in sync with condition in replaceSectionContent!
- if ( strval( $sectionId ) === '' ) {
- // Whole-page edit; let the whole text through
- return $text;
- }
-
- if ( !$this->supportsSections() ) {
- throw new MWException( "sections not supported for content model " .
- $this->getContentHandler()->getModelID() );
- }
-
- // could even make section title, but that's not required.
- $sectionContent = ContentHandler::makeContent( $text, $this->getTitle() );
-
- $newContent = $this->replaceSectionContent( $sectionId, $sectionContent, $sectionTitle,
- $edittime );
-
- return ContentHandler::getContentText( $newContent );
- }
-
/**
* Returns true if this page's content model supports sections.
*
}
global $wgContLang;
+ $conf = $this->getConfig();
- $mainPage = Title::newMainPage();
+ // We can't use Title::newMainPage() if 'mainpage' is in
+ // $wgForceUIMsgAsContentMsg because that will try to use the session
+ // user's language and we have no session user. This does the
+ // equivalent but falling back to our ResourceLoaderContext language
+ // instead.
+ $mainPage = Title::newFromText( $context->msg( 'mainpage' )->inContentLanguage()->text() );
+ if ( !$mainPage ) {
+ $mainPage = Title::newFromText( 'Main Page' );
+ }
/**
* Namespace related preparation
}
}
- $conf = $this->getConfig();
// Build list of variables
$vars = [
'wgLoadScript' => wfScript( 'load' ),
return $allowedSkins;
}
- /**
- * @deprecated since 1.23, use getAllowedSkins
- * @return string[]
- */
- public static function getUsableSkins() {
- wfDeprecated( __METHOD__, '1.23' );
- return self::getAllowedSkins();
- }
-
/**
* Normalize a skin preference value to a form that can be loaded.
*
}
}
- /**
- * Factory method for loading a skin of a given type
- * @param string $key 'monobook', 'vector', etc.
- * @return Skin
- * @deprecated since 1.24; Use SkinFactory instead
- */
- static function &newFromKey( $key ) {
- wfDeprecated( __METHOD__, '1.24' );
-
- $key = Skin::normalizeKey( $key );
- $factory = SkinFactory::getDefaultInstance();
-
- // normalizeKey() guarantees that a skin with this key will exist.
- $skin = $factory->makeSkin( $key );
- return $skin;
- }
-
/**
* @return string Skin name
*/
$targetUser->canReceiveEmail();
}
- /**
- * This function previously returned a fully resolved style path URL to images or styles stored in
- * the legacy skins/common/ directory.
- *
- * That directory has been removed in 1.24 and the function always returns an empty string.
- *
- * @deprecated since 1.24
- * @param string $name The name or path of a skin resource file
- * @return string Empty string
- */
- function getCommonStylePath( $name ) {
- wfDeprecated( __METHOD__, '1.24' );
- return '';
- }
-
/**
* Return a fully resolved style path url to images or styles stored in the current skins's folder.
* This method returns a url resolved using the configured skin style path
return $bar;
}
- /**
- * This function previously controlled whether the 'mediawiki.legacy.wikiprintable' module
- * should be loaded by OutputPage. That module no longer exists and the return value of this
- * method is ignored.
- *
- * If your skin doesn't provide its own print styles, the 'mediawiki.legacy.commonPrint' module
- * can be used instead (SkinTemplate-based skins do it automatically).
- *
- * @deprecated since 1.22
- * @return bool
- */
- public function commonPrintStylesheet() {
- wfDeprecated( __METHOD__, '1.22' );
- return false;
- }
-
/**
* Gets new talk page messages for the current user and returns an
* appropriate alert message (or an empty string if there are no messages)
$db->expects( $this->any() )
->method( 'getHeartbeatData' )
- ->with( 172 )
+ ->with( [ 'server_id' => 172 ] )
->will( $this->returnValue( [ $ptTimeISO, $now ] ) );
$db->setLBInfo( 'clusterMasterHost', 'db1052' );
];
}
- /**
- * @dataProvider dataReplaceSection
- * @covers WikiPage::replaceSection
- */
- public function testReplaceSection( $title, $model, $text, $section, $with,
- $sectionTitle, $expected
- ) {
- $this->hideDeprecated( "WikiPage::replaceSection" );
-
- $page = $this->createPage( $title, $text, $model );
- $text = $page->replaceSection( $section, $with, $sectionTitle );
- $text = trim( $text );
-
- $this->assertEquals( $expected, $text );
- }
-
/**
* @dataProvider dataReplaceSection
* @covers WikiPage::replaceSectionContent
}
/**
+ * Flaky test (T131549).
+ *
+ * @group Broken
* @dataProvider provider_testTimestampedUID
* @covers UIDGenerator::newTimestampedUID128
* @covers UIDGenerator::newTimestampedUID88