summaryrefslogtreecommitdiff
path: root/includes/specials/SpecialVersion.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/specials/SpecialVersion.php')
-rw-r--r--includes/specials/SpecialVersion.php738
1 files changed, 565 insertions, 173 deletions
diff --git a/includes/specials/SpecialVersion.php b/includes/specials/SpecialVersion.php
index 5ba785f5..cb3fc118 100644
--- a/includes/specials/SpecialVersion.php
+++ b/includes/specials/SpecialVersion.php
@@ -29,9 +29,13 @@
* @ingroup SpecialPage
*/
class SpecialVersion extends SpecialPage {
-
protected $firstExtOpened = false;
+ /**
+ * Stores the current rev id/SHA hash of MediaWiki core
+ */
+ protected $coreId = '';
+
protected static $extensionTypes = false;
protected static $viewvcUrls = array(
@@ -46,43 +50,95 @@ class SpecialVersion extends SpecialPage {
/**
* main()
+ * @param string|null $par
*/
public function execute( $par ) {
- global $wgSpecialVersionShowHooks, $IP;
+ global $IP, $wgExtensionCredits;
$this->setHeaders();
$this->outputHeader();
$out = $this->getOutput();
$out->allowClickjacking();
- if ( $par !== 'Credits' ) {
- $text =
- $this->getMediaWikiCredits() .
- $this->softwareInformation() .
- $this->getEntryPointInfo() .
- $this->getExtensionCredits();
- if ( $wgSpecialVersionShowHooks ) {
- $text .= $this->getWgHooks();
+ // Explode the sub page information into useful bits
+ $parts = explode( '/', (string)$par );
+ $extNode = null;
+ if ( isset( $parts[1] ) ) {
+ $extName = str_replace( '_', ' ', $parts[1] );
+ // Find it!
+ foreach ( $wgExtensionCredits as $group => $extensions ) {
+ foreach ( $extensions as $ext ) {
+ if ( isset( $ext['name'] ) && ( $ext['name'] === $extName ) ) {
+ $extNode = &$ext;
+ break 2;
+ }
+ }
}
-
- $out->addWikiText( $text );
- $out->addHTML( $this->IPInfo() );
-
- if ( $this->getRequest()->getVal( 'easteregg' ) ) {
- // TODO: put something interesting here
+ if ( !$extNode ) {
+ $out->setStatusCode( 404 );
}
} else {
- // Credits sub page
-
- // Header
- $out->addHTML( wfMessage( 'version-credits-summary' )->parseAsBlock() );
+ $extName = 'MediaWiki';
+ }
- $wikiText = file_get_contents( $IP . '/CREDITS' );
+ // Now figure out what to do
+ switch ( strtolower( $parts[0] ) ) {
+ case 'credits':
+ $wikiText = '{{int:version-credits-not-found}}';
+ if ( $extName === 'MediaWiki' ) {
+ $wikiText = file_get_contents( $IP . '/CREDITS' );
+ } elseif ( ( $extNode !== null ) && isset( $extNode['path'] ) ) {
+ $file = $this->getExtAuthorsFileName( dirname( $extNode['path'] ) );
+ if ( $file ) {
+ $wikiText = file_get_contents( $file );
+ if ( substr( $file, -4 ) === '.txt' ) {
+ $wikiText = Html::element( 'pre', array(), $wikiText );
+ }
+ }
+ }
- // Take everything from the first section onwards, to remove the (not localized) header
- $wikiText = substr( $wikiText, strpos( $wikiText, '==' ) );
+ $out->setPageTitle( $this->msg( 'version-credits-title', $extName ) );
+ $out->addWikiText( $wikiText );
+ break;
+
+ case 'license':
+ $wikiText = '{{int:version-license-not-found}}';
+ if ( $extName === 'MediaWiki' ) {
+ $wikiText = file_get_contents( $IP . '/COPYING' );
+ } elseif ( ( $extNode !== null ) && isset( $extNode['path'] ) ) {
+ $file = $this->getExtLicenseFileName( dirname( $extNode['path'] ) );
+ if ( $file ) {
+ $wikiText = file_get_contents( $file );
+ if ( !isset( $extNode['license-name'] ) ) {
+ // If the developer did not explicitly set license-name they probably
+ // are unaware that we're now sucking this file in and thus it's probably
+ // not wikitext friendly.
+ $wikiText = "<pre>$wikiText</pre>";
+ }
+ }
+ }
- $out->addWikiText( $wikiText );
+ $out->setPageTitle( $this->msg( 'version-license-title', $extName ) );
+ $out->addWikiText( $wikiText );
+ break;
+
+ default:
+ $out->addModules( 'mediawiki.special.version' );
+ $out->addWikiText(
+ $this->getMediaWikiCredits() .
+ $this->softwareInformation() .
+ $this->getEntryPointInfo()
+ );
+ $out->addHtml(
+ $this->getSkinCredits() .
+ $this->getExtensionCredits() .
+ $this->getParserTags() .
+ $this->getParserFunctionHooks()
+ );
+ $out->addWikiText( $this->getWgHooks() );
+ $out->addHTML( $this->IPInfo() );
+
+ break;
}
}
@@ -92,7 +148,11 @@ class SpecialVersion extends SpecialPage {
* @return string
*/
private static function getMediaWikiCredits() {
- $ret = Xml::element( 'h2', array( 'id' => 'mw-version-license' ), wfMessage( 'version-license' )->text() );
+ $ret = Xml::element(
+ 'h2',
+ array( 'id' => 'mw-version-license' ),
+ wfMessage( 'version-license' )->text()
+ );
// This text is always left-to-right.
$ret .= '<div class="plainlinks">';
@@ -107,18 +167,21 @@ class SpecialVersion extends SpecialPage {
/**
* Get the "MediaWiki is copyright 2001-20xx by lots of cool guys" text
*
- * @return String
+ * @return string
*/
public static function getCopyrightAndAuthorList() {
global $wgLang;
if ( defined( 'MEDIAWIKI_INSTALL' ) ) {
- $othersLink = '[//www.mediawiki.org/wiki/Special:Version/Credits ' . wfMessage( 'version-poweredby-others' )->text() . ']';
+ $othersLink = '[//www.mediawiki.org/wiki/Special:Version/Credits ' .
+ wfMessage( 'version-poweredby-others' )->text() . ']';
} else {
- $othersLink = '[[Special:Version/Credits|' . wfMessage( 'version-poweredby-others' )->text() . ']]';
+ $othersLink = '[[Special:Version/Credits|' .
+ wfMessage( 'version-poweredby-others' )->text() . ']]';
}
- $translatorsLink = '[//translatewiki.net/wiki/Translating:MediaWiki/Credits ' . wfMessage( 'version-poweredby-translators' )->text() . ']';
+ $translatorsLink = '[//translatewiki.net/wiki/Translating:MediaWiki/Credits ' .
+ wfMessage( 'version-poweredby-translators' )->text() . ']';
$authorList = array(
'Magnus Manske', 'Brion Vibber', 'Lee Daniel Crocker',
@@ -141,7 +204,7 @@ class SpecialVersion extends SpecialPage {
*
* @return string
*/
- static function softwareInformation() {
+ public static function softwareInformation() {
$dbr = wfGetDB( DB_SLAVE );
// Put the software in an array of form 'name' => 'version'. All messages should
@@ -149,13 +212,21 @@ class SpecialVersion extends SpecialPage {
// wikimarkup can be used.
$software = array();
$software['[https://www.mediawiki.org/ MediaWiki]'] = self::getVersionLinked();
- $software['[http://www.php.net/ PHP]'] = phpversion() . " (" . PHP_SAPI . ")";
+ if ( wfIsHHVM() ) {
+ $software['[http://hhvm.com/ HHVM]'] = HHVM_VERSION . " (" . PHP_SAPI . ")";
+ } else {
+ $software['[https://php.net/ PHP]'] = PHP_VERSION . " (" . PHP_SAPI . ")";
+ }
$software[$dbr->getSoftwareLink()] = $dbr->getServerInfo();
// Allow a hook to add/remove items.
wfRunHooks( 'SoftwareInfo', array( &$software ) );
- $out = Xml::element( 'h2', array( 'id' => 'mw-version-software' ), wfMessage( 'version-software' )->text() ) .
+ $out = Xml::element(
+ 'h2',
+ array( 'id' => 'mw-version-software' ),
+ wfMessage( 'version-software' )->text()
+ ) .
Xml::openElement( 'table', array( 'class' => 'wikitable plainlinks', 'id' => 'sv-software' ) ) .
"<tr>
<th>" . wfMessage( 'version-software-product' )->text() . "</th>
@@ -175,7 +246,7 @@ class SpecialVersion extends SpecialPage {
/**
* Return a string of the MediaWiki version with SVN revision if available.
*
- * @param $flags String
+ * @param string $flags
* @return mixed
*/
public static function getVersion( $flags = '' ) {
@@ -205,6 +276,7 @@ class SpecialVersion extends SpecialPage {
}
wfProfileOut( __METHOD__ );
+
return $version;
}
@@ -233,11 +305,12 @@ class SpecialVersion extends SpecialPage {
}
wfProfileOut( __METHOD__ );
+
return $v;
}
/**
- * @return string wgVersion + a link to subversion revision of svn BASE
+ * @return string Global wgVersion + a link to subversion revision of svn BASE
*/
private static function getVersionLinkedSvn() {
global $IP;
@@ -273,12 +346,14 @@ class SpecialVersion extends SpecialPage {
preg_match( "/^(\d+\.\d+)/", $wgVersion, $versionParts );
$versionUrl = "https://www.mediawiki.org/wiki/MediaWiki_{$versionParts[1]}";
}
+
return "[$versionUrl $wgVersion]";
}
/**
* @since 1.22 Returns the HEAD date in addition to the sha1 and link
- * @return bool|string wgVersion + HEAD sha1 stripped to the first 7 chars with link and date, or false on failure
+ * @return bool|string Global wgVersion + HEAD sha1 stripped to the first 7 chars
+ * with link and date, or false on failure
*/
private static function getVersionLinkedGit() {
global $IP, $wgLang;
@@ -298,7 +373,7 @@ class SpecialVersion extends SpecialPage {
$gitHeadCommitDate = $gitInfo->getHeadCommitDate();
if ( $gitHeadCommitDate ) {
- $shortSHA1 .= "<br/>" . $wgLang->timeanddate( $gitHeadCommitDate, true );
+ $shortSHA1 .= Html::element( 'br' ) . $wgLang->timeanddate( $gitHeadCommitDate, true );
}
return self::getwgVersionLinked() . " $shortSHA1";
@@ -308,9 +383,7 @@ class SpecialVersion extends SpecialPage {
* Returns an array with the base extension types.
* Type is stored as array key, the message as array value.
*
- * TODO: ideally this would return all extension types, including
- * those added by SpecialVersionExtensionTypes. This is not possible
- * since this hook is passing along $this though.
+ * TODO: ideally this would return all extension types.
*
* @since 1.17
*
@@ -340,35 +413,39 @@ class SpecialVersion extends SpecialPage {
*
* @since 1.17
*
- * @param $type String
+ * @param string $type
*
* @return string
*/
public static function getExtensionTypeName( $type ) {
$types = self::getExtensionTypes();
+
return isset( $types[$type] ) ? $types[$type] : $types['other'];
}
/**
- * Generate wikitext showing extensions name, URL, author and description.
+ * Generate wikitext showing the name, URL, author and description of each extension.
*
- * @return String: Wikitext
+ * @return string Wikitext
*/
- function getExtensionCredits() {
- global $wgExtensionCredits, $wgExtensionFunctions, $wgParser;
+ public function getExtensionCredits() {
+ global $wgExtensionCredits;
- if ( !count( $wgExtensionCredits ) && !count( $wgExtensionFunctions ) ) {
+ if (
+ count( $wgExtensionCredits ) === 0 ||
+ // Skins are displayed separately, see getSkinCredits()
+ ( count( $wgExtensionCredits ) === 1 && isset( $wgExtensionCredits['skin'] ) )
+ ) {
return '';
}
$extensionTypes = self::getExtensionTypes();
- /**
- * @deprecated as of 1.17, use hook ExtensionTypes instead.
- */
- wfRunHooks( 'SpecialVersionExtensionTypes', array( &$this, &$extensionTypes ) );
-
- $out = Xml::element( 'h2', array( 'id' => 'mw-version-ext' ), $this->msg( 'version-extensions' )->text() ) .
+ $out = Xml::element(
+ 'h2',
+ array( 'id' => 'mw-version-ext' ),
+ $this->msg( 'version-extensions' )->text()
+ ) .
Xml::openElement( 'table', array( 'class' => 'wikitable plainlinks', 'id' => 'sv-ext' ) );
// Make sure the 'other' type is set to an array.
@@ -383,9 +460,11 @@ class SpecialVersion extends SpecialPage {
}
}
+ $this->firstExtOpened = false;
// Loop through the extension categories to display their extensions in the list.
foreach ( $extensionTypes as $type => $message ) {
- if ( $type != 'other' ) {
+ // Skins have a separate section
+ if ( $type !== 'other' && $type !== 'skin' ) {
$out .= $this->getExtensionCategory( $type, $message );
}
}
@@ -393,24 +472,89 @@ class SpecialVersion extends SpecialPage {
// We want the 'other' type to be last in the list.
$out .= $this->getExtensionCategory( 'other', $extensionTypes['other'] );
+ $out .= Xml::closeElement( 'table' );
+
+ return $out;
+ }
+
+ /**
+ * Generate wikitext showing the name, URL, author and description of each skin.
+ *
+ * @return string Wikitext
+ */
+ public function getSkinCredits() {
+ global $wgExtensionCredits;
+ if ( !isset( $wgExtensionCredits['skin'] ) || count( $wgExtensionCredits['skin'] ) === 0 ) {
+ return '';
+ }
+
+ $out = Xml::element(
+ 'h2',
+ array( 'id' => 'mw-version-skin' ),
+ $this->msg( 'version-skins' )->text()
+ ) .
+ Xml::openElement( 'table', array( 'class' => 'wikitable plainlinks', 'id' => 'sv-skin' ) );
+
+ $this->firstExtOpened = false;
+ $out .= $this->getExtensionCategory( 'skin', null );
+
+ $out .= Xml::closeElement( 'table' );
+
+ return $out;
+ }
+
+ /**
+ * Obtains a list of installed parser tags and the associated H2 header
+ *
+ * @return string HTML output
+ */
+ protected function getParserTags() {
+ global $wgParser;
+
$tags = $wgParser->getTags();
- $cnt = count( $tags );
- if ( $cnt ) {
- for ( $i = 0; $i < $cnt; ++$i ) {
- $tags[$i] = "&lt;{$tags[$i]}&gt;";
- }
- $out .= $this->openExtType( $this->msg( 'version-parser-extensiontags' )->text(), 'parser-tags' );
- $out .= '<tr><td colspan="4">' . $this->listToText( $tags ) . "</td></tr>\n";
+ if ( count( $tags ) ) {
+ $out = Html::rawElement(
+ 'h2',
+ array( 'class' => 'mw-headline' ),
+ Linker::makeExternalLink(
+ '//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Tag_extensions',
+ $this->msg( 'version-parser-extensiontags' )->parse(),
+ false /* msg()->parse() already escapes */
+ )
+ );
+
+ array_walk( $tags, function ( &$value ) {
+ $value = '&lt;' . htmlspecialchars( $value ) . '&gt;';
+ } );
+ $out .= $this->listToText( $tags );
+ } else {
+ $out = '';
}
+ return $out;
+ }
+
+ /**
+ * Obtains a list of installed parser function hooks and the associated H2 header
+ *
+ * @return string HTML output
+ */
+ protected function getParserFunctionHooks() {
+ global $wgParser;
+
$fhooks = $wgParser->getFunctionHooks();
if ( count( $fhooks ) ) {
- $out .= $this->openExtType( $this->msg( 'version-parser-function-hooks' )->text(), 'parser-function-hooks' );
- $out .= '<tr><td colspan="4">' . $this->listToText( $fhooks ) . "</td></tr>\n";
- }
+ $out = Html::rawElement( 'h2', array( 'class' => 'mw-headline' ), Linker::makeExternalLink(
+ '//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Parser_functions',
+ $this->msg( 'version-parser-function-hooks' )->parse(),
+ false /* msg()->parse() already escapes */
+ ) );
- $out .= Xml::closeElement( 'table' );
+ $out .= $this->listToText( $fhooks );
+ } else {
+ $out = '';
+ }
return $out;
}
@@ -420,8 +564,8 @@ class SpecialVersion extends SpecialPage {
*
* @since 1.17
*
- * @param $type String
- * @param $message String
+ * @param string $type
+ * @param string $message
*
* @return string
*/
@@ -445,11 +589,11 @@ class SpecialVersion extends SpecialPage {
/**
* Callback to sort extensions by type.
- * @param $a array
- * @param $b array
+ * @param array $a
+ * @param array $b
* @return int
*/
- function compare( $a, $b ) {
+ public function compare( $a, $b ) {
if ( $a['name'] === $b['name'] ) {
return 0;
} else {
@@ -460,63 +604,160 @@ class SpecialVersion extends SpecialPage {
}
/**
- * Creates and formats the credits for a single extension and returns this.
+ * Creates and formats a version line for a single extension.
*
- * @param $extension Array
+ * Information for five columns will be created. Parameters required in the
+ * $extension array for part rendering are indicated in ()
+ * - The name of (name), and URL link to (url), the extension
+ * - Official version number (version) and if available version control system
+ * revision (path), link, and date
+ * - If available the short name of the license (license-name) and a linke
+ * to ((LICENSE)|(COPYING))(\.txt)? if it exists.
+ * - Description of extension (descriptionmsg or description)
+ * - List of authors (author) and link to a ((AUTHORS)|(CREDITS))(\.txt)? file if it exists
*
- * @return string
+ * @param array $extension
+ *
+ * @return string Raw HTML
*/
- function getCreditsForExtension( array $extension ) {
- global $wgLang;
+ public function getCreditsForExtension( array $extension ) {
+ $out = $this->getOutput();
- $name = isset( $extension['name'] ) ? $extension['name'] : '[no name]';
+ // We must obtain the information for all the bits and pieces!
+ // ... such as extension names and links
+ if ( isset( $extension['namemsg'] ) ) {
+ // Localized name of extension
+ $extensionName = $this->msg( $extension['namemsg'] )->text();
+ } elseif ( isset( $extension['name'] ) ) {
+ // Non localized version
+ $extensionName = $extension['name'];
+ } else {
+ $extensionName = $this->msg( 'version-no-ext-name' )->text();
+ }
- $vcsText = false;
+ if ( isset( $extension['url'] ) ) {
+ $extensionNameLink = Linker::makeExternalLink(
+ $extension['url'],
+ $extensionName,
+ true,
+ '',
+ array( 'class' => 'mw-version-ext-name' )
+ );
+ } else {
+ $extensionNameLink = $extensionName;
+ }
+
+ // ... and the version information
+ // If the extension path is set we will check that directory for GIT and SVN
+ // metadata in an attempt to extract date and vcs commit metadata.
+ $canonicalVersion = '&ndash;';
+ $extensionPath = null;
+ $vcsVersion = null;
+ $vcsLink = null;
+ $vcsDate = null;
+
+ if ( isset( $extension['version'] ) ) {
+ $canonicalVersion = $out->parseInline( $extension['version'] );
+ }
if ( isset( $extension['path'] ) ) {
- $gitInfo = new GitInfo( dirname( $extension['path'] ) );
- $gitHeadSHA1 = $gitInfo->getHeadSHA1();
- if ( $gitHeadSHA1 !== false ) {
- $vcsText = '(' . substr( $gitHeadSHA1, 0, 7 ) . ')';
- $gitViewerUrl = $gitInfo->getHeadViewUrl();
- if ( $gitViewerUrl !== false ) {
- $vcsText = "[$gitViewerUrl $vcsText]";
+ global $IP;
+ $extensionPath = dirname( $extension['path'] );
+ if ( $this->coreId == '' ) {
+ wfDebug( 'Looking up core head id' );
+ $coreHeadSHA1 = self::getGitHeadSha1( $IP );
+ if ( $coreHeadSHA1 ) {
+ $this->coreId = $coreHeadSHA1;
+ } else {
+ $svnInfo = self::getSvnInfo( $IP );
+ if ( $svnInfo !== false ) {
+ $this->coreId = $svnInfo['checkout-rev'];
+ }
}
- $gitHeadCommitDate = $gitInfo->getHeadCommitDate();
- if ( $gitHeadCommitDate ) {
- $vcsText .= "<br/>" . $wgLang->timeanddate( $gitHeadCommitDate, true );
+ }
+ $cache = wfGetCache( CACHE_ANYTHING );
+ $memcKey = wfMemcKey( 'specialversion-ext-version-text', $extension['path'], $this->coreId );
+ list( $vcsVersion, $vcsLink, $vcsDate ) = $cache->get( $memcKey );
+
+ if ( !$vcsVersion ) {
+ wfDebug( "Getting VCS info for extension $extensionName" );
+ $gitInfo = new GitInfo( $extensionPath );
+ $vcsVersion = $gitInfo->getHeadSHA1();
+ if ( $vcsVersion !== false ) {
+ $vcsVersion = substr( $vcsVersion, 0, 7 );
+ $vcsLink = $gitInfo->getHeadViewUrl();
+ $vcsDate = $gitInfo->getHeadCommitDate();
+ } else {
+ $svnInfo = self::getSvnInfo( $extensionPath );
+ if ( $svnInfo !== false ) {
+ $vcsVersion = $this->msg( 'version-svn-revision', $svnInfo['checkout-rev'] )->text();
+ $vcsLink = isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : '';
+ }
}
+ $cache->set( $memcKey, array( $vcsVersion, $vcsLink, $vcsDate ), 60 * 60 * 24 );
} else {
- $svnInfo = self::getSvnInfo( dirname( $extension['path'] ) );
- # Make subversion text/link.
- if ( $svnInfo !== false ) {
- $directoryRev = isset( $svnInfo['directory-rev'] ) ? $svnInfo['directory-rev'] : null;
- $vcsText = $this->msg( 'version-svn-revision', $directoryRev, $svnInfo['checkout-rev'] )->text();
- $vcsText = isset( $svnInfo['viewvc-url'] ) ? '[' . $svnInfo['viewvc-url'] . " $vcsText]" : $vcsText;
- }
+ wfDebug( "Pulled VCS info for extension $extensionName from cache" );
}
}
- # Make main link (or just the name if there is no URL).
- if ( isset( $extension['url'] ) ) {
- $mainLink = "[{$extension['url']} $name]";
- } else {
- $mainLink = $name;
- }
+ $versionString = Html::rawElement(
+ 'span',
+ array( 'class' => 'mw-version-ext-version' ),
+ $canonicalVersion
+ );
- if ( isset( $extension['version'] ) ) {
- $versionText = '<span class="mw-version-ext-version">' .
- $this->msg( 'version-version', $extension['version'] )->text() .
- '</span>';
- } else {
- $versionText = '';
+ if ( $vcsVersion ) {
+ if ( $vcsLink ) {
+ $vcsVerString = Linker::makeExternalLink(
+ $vcsLink,
+ $this->msg( 'version-version', $vcsVersion ),
+ true,
+ '',
+ array( 'class' => 'mw-version-ext-vcs-version' )
+ );
+ } else {
+ $vcsVerString = Html::element( 'span',
+ array( 'class' => 'mw-version-ext-vcs-version' ),
+ "({$vcsVersion})"
+ );
+ }
+ $versionString .= " {$vcsVerString}";
+
+ if ( $vcsDate ) {
+ $vcsTimeString = Html::element( 'span',
+ array( 'class' => 'mw-version-ext-vcs-timestamp' ),
+ $this->getLanguage()->timeanddate( $vcsDate, true )
+ );
+ $versionString .= " {$vcsTimeString}";
+ }
+ $versionString = Html::rawElement( 'span',
+ array( 'class' => 'mw-version-ext-meta-version' ),
+ $versionString
+ );
}
- # Make description text.
- $description = isset( $extension['description'] ) ? $extension['description'] : '';
+ // ... and license information; if a license file exists we
+ // will link to it
+ $licenseLink = '';
+ if ( isset( $extension['license-name'] ) ) {
+ $licenseLink = Linker::link(
+ $this->getPageTitle( 'License/' . $extensionName ),
+ $out->parseInline( $extension['license-name'] ),
+ array( 'class' => 'mw-version-ext-license' )
+ );
+ } elseif ( $this->getExtLicenseFileName( $extensionPath ) ) {
+ $licenseLink = Linker::link(
+ $this->getPageTitle( 'License/' . $extensionName ),
+ $this->msg( 'version-ext-license' ),
+ array( 'class' => 'mw-version-ext-license' )
+ );
+ }
+ // ... and generate the description; which can be a parameterized l10n message
+ // in the form array( <msgname>, <parameter>, <parameter>... ) or just a straight
+ // up string
if ( isset( $extension['descriptionmsg'] ) ) {
- # Look for a localized description.
+ // Localized description of extension
$descriptionMsg = $extension['descriptionmsg'];
if ( is_array( $descriptionMsg ) ) {
@@ -527,65 +768,80 @@ class SpecialVersion extends SpecialPage {
} else {
$description = $this->msg( $descriptionMsg )->text();
}
- }
-
- if ( $vcsText !== false ) {
- $extNameVer = "<tr>
- <td><em>$mainLink $versionText</em></td>
- <td><em>$vcsText</em></td>";
+ } elseif ( isset( $extension['description'] ) ) {
+ // Non localized version
+ $description = $extension['description'];
} else {
- $extNameVer = "<tr>
- <td colspan=\"2\"><em>$mainLink $versionText</em></td>";
+ $description = '';
}
+ $description = $out->parseInline( $description );
- $author = isset( $extension['author'] ) ? $extension['author'] : array();
- $extDescAuthor = "<td>$description</td>
- <td>" . $this->listAuthors( $author, false ) . "</td>
- </tr>\n";
+ // ... now get the authors for this extension
+ $authors = isset( $extension['author'] ) ? $extension['author'] : array();
+ $authors = $this->listAuthors( $authors, $extensionName, $extensionPath );
- return $extNameVer . $extDescAuthor;
+ // Finally! Create the table
+ $html = Html::openElement( 'tr', array(
+ 'class' => 'mw-version-ext',
+ 'id' => "mw-version-ext-{$extensionName}"
+ )
+ );
+
+ $html .= Html::rawElement( 'td', array(), $extensionNameLink );
+ $html .= Html::rawElement( 'td', array(), $versionString );
+ $html .= Html::rawElement( 'td', array(), $licenseLink );
+ $html .= Html::rawElement( 'td', array( 'class' => 'mw-version-ext-description' ), $description );
+ $html .= Html::rawElement( 'td', array( 'class' => 'mw-version-ext-authors' ), $authors );
+
+ $html .= Html::closeElement( 'td' );
+
+ return $html;
}
/**
* Generate wikitext showing hooks in $wgHooks.
*
- * @return String: wikitext
+ * @return string Wikitext
*/
private function getWgHooks() {
- global $wgHooks;
+ global $wgSpecialVersionShowHooks, $wgHooks;
- if ( count( $wgHooks ) ) {
+ if ( $wgSpecialVersionShowHooks && count( $wgHooks ) ) {
$myWgHooks = $wgHooks;
ksort( $myWgHooks );
- $ret = Xml::element( 'h2', array( 'id' => 'mw-version-hooks' ), $this->msg( 'version-hooks' )->text() ) .
- Xml::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-hooks' ) ) .
- "<tr>
- <th>" . $this->msg( 'version-hook-name' )->text() . "</th>
- <th>" . $this->msg( 'version-hook-subscribedby' )->text() . "</th>
- </tr>\n";
+ $ret = array();
+ $ret[] = '== {{int:version-hooks}} ==';
+ $ret[] = Html::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-hooks' ) );
+ $ret[] = Html::openElement( 'tr' );
+ $ret[] = Html::element( 'th', array(), $this->msg( 'version-hook-name' )->text() );
+ $ret[] = Html::element( 'th', array(), $this->msg( 'version-hook-subscribedby' )->text() );
+ $ret[] = Html::closeElement( 'tr' );
foreach ( $myWgHooks as $hook => $hooks ) {
- $ret .= "<tr>
- <td>$hook</td>
- <td>" . $this->listToText( $hooks ) . "</td>
- </tr>\n";
+ $ret[] = Html::openElement( 'tr' );
+ $ret[] = Html::element( 'td', array(), $hook );
+ $ret[] = Html::element( 'td', array(), $this->listToText( $hooks ) );
+ $ret[] = Html::closeElement( 'tr' );
}
- $ret .= Xml::closeElement( 'table' );
- return $ret;
+ $ret[] = Html::closeElement( 'table' );
+
+ return implode( "\n", $ret );
} else {
return '';
}
}
- private function openExtType( $text, $name = null ) {
- $opt = array( 'colspan' => 4 );
+ private function openExtType( $text = null, $name = null ) {
$out = '';
+ $opt = array( 'colspan' => 5 );
if ( $this->firstExtOpened ) {
// Insert a spacing line
- $out .= '<tr class="sv-space">' . Html::element( 'td', $opt ) . "</tr>\n";
+ $out .= Html::rawElement( 'tr', array( 'class' => 'sv-space' ),
+ Html::element( 'td', $opt )
+ );
}
$this->firstExtOpened = true;
@@ -593,7 +849,27 @@ class SpecialVersion extends SpecialPage {
$opt['id'] = "sv-$name";
}
- $out .= "<tr>" . Xml::element( 'th', $opt, $text ) . "</tr>\n";
+ if ( $text !== null ) {
+ $out .= Html::rawElement( 'tr', array(),
+ Html::element( 'th', $opt, $text )
+ );
+ }
+
+ $firstHeadingMsg = ( $name === 'credits-skin' )
+ ? 'version-skin-colheader-name'
+ : 'version-ext-colheader-name';
+ $out .= Html::openElement( 'tr' );
+ $out .= Html::element( 'th', array( 'class' => 'mw-version-ext-col-label' ),
+ $this->msg( $firstHeadingMsg )->text() );
+ $out .= Html::element( 'th', array( 'class' => 'mw-version-ext-col-label' ),
+ $this->msg( 'version-ext-colheader-version' )->text() );
+ $out .= Html::element( 'th', array( 'class' => 'mw-version-ext-col-label' ),
+ $this->msg( 'version-ext-colheader-license' )->text() );
+ $out .= Html::element( 'th', array( 'class' => 'mw-version-ext-col-label' ),
+ $this->msg( 'version-ext-colheader-description' )->text() );
+ $out .= Html::element( 'th', array( 'class' => 'mw-version-ext-col-label' ),
+ $this->msg( 'version-ext-colheader-credits' )->text() );
+ $out .= Html::closeElement( 'tr' );
return $out;
}
@@ -601,64 +877,156 @@ class SpecialVersion extends SpecialPage {
/**
* Get information about client's IP address.
*
- * @return String: HTML fragment
+ * @return string HTML fragment
*/
private function IPInfo() {
$ip = str_replace( '--', ' - ', htmlspecialchars( $this->getRequest()->getIP() ) );
+
return "<!-- visited from $ip -->\n<span style='display:none'>visited from $ip</span>";
}
/**
* Return a formatted unsorted list of authors
*
- * @param $authors mixed: string or array of strings
- * @return String: HTML fragment
+ * 'And Others'
+ * If an item in the $authors array is '...' it is assumed to indicate an
+ * 'and others' string which will then be linked to an ((AUTHORS)|(CREDITS))(\.txt)?
+ * file if it exists in $dir.
+ *
+ * Similarly an entry ending with ' ...]' is assumed to be a link to an
+ * 'and others' page.
+ *
+ * If no '...' string variant is found, but an authors file is found an
+ * 'and others' will be added to the end of the credits.
+ *
+ * @param string|array $authors
+ * @param string $extName Name of the extension for link creation
+ * @param string $extDir Path to the extension root directory
+ *
+ * @return string HTML fragment
*/
- function listAuthors( $authors ) {
+ public function listAuthors( $authors, $extName, $extDir ) {
+ $hasOthers = false;
+
$list = array();
foreach ( (array)$authors as $item ) {
if ( $item == '...' ) {
- $list[] = $this->msg( 'version-poweredby-others' )->text();
+ $hasOthers = true;
+
+ if ( $this->getExtAuthorsFileName( $extDir ) ) {
+ $text = Linker::link(
+ $this->getPageTitle( "Credits/$extName" ),
+ $this->msg( 'version-poweredby-others' )->text()
+ );
+ } else {
+ $text = $this->msg( 'version-poweredby-others' )->text();
+ }
+ $list[] = $text;
} elseif ( substr( $item, -5 ) == ' ...]' ) {
- $list[] = substr( $item, 0, -4 ) . $this->msg( 'version-poweredby-others' )->text() . "]";
+ $hasOthers = true;
+ $list[] = $this->getOutput()->parseInline(
+ substr( $item, 0, -4 ) . $this->msg( 'version-poweredby-others' )->text() . "]"
+ );
} else {
- $list[] = $item;
+ $list[] = $this->getOutput()->parseInline( $item );
}
}
+
+ if ( !$hasOthers && $this->getExtAuthorsFileName( $extDir ) ) {
+ $list[] = $text = Linker::link(
+ $this->getPageTitle( "Credits/$extName" ),
+ $this->msg( 'version-poweredby-others' )->text()
+ );
+ }
+
return $this->listToText( $list, false );
}
/**
- * Convert an array of items into a list for display.
+ * Obtains the full path of an extensions authors or credits file if
+ * one exists.
+ *
+ * @param string $extDir Path to the extensions root directory
+ *
+ * @since 1.23
*
- * @param array $list of elements to display
- * @param $sort Boolean: whether to sort the items in $list
+ * @return bool|string False if no such file exists, otherwise returns
+ * a path to it.
+ */
+ public static function getExtAuthorsFileName( $extDir ) {
+ if ( !$extDir ) {
+ return false;
+ }
+
+ foreach ( scandir( $extDir ) as $file ) {
+ $fullPath = $extDir . DIRECTORY_SEPARATOR . $file;
+ if ( preg_match( '/^((AUTHORS)|(CREDITS))(\.txt)?$/', $file ) &&
+ is_readable( $fullPath ) &&
+ is_file( $fullPath )
+ ) {
+ return $fullPath;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Obtains the full path of an extensions copying or license file if
+ * one exists.
+ *
+ * @param string $extDir Path to the extensions root directory
*
- * @return String
+ * @since 1.23
+ *
+ * @return bool|string False if no such file exists, otherwise returns
+ * a path to it.
*/
- function listToText( $list, $sort = true ) {
- $cnt = count( $list );
+ public static function getExtLicenseFileName( $extDir ) {
+ if ( !$extDir ) {
+ return false;
+ }
- if ( $cnt == 1 ) {
- // Enforce always returning a string
- return (string)self::arrayToString( $list[0] );
- } elseif ( $cnt == 0 ) {
- return '';
- } else {
- if ( $sort ) {
- sort( $list );
+ foreach ( scandir( $extDir ) as $file ) {
+ $fullPath = $extDir . DIRECTORY_SEPARATOR . $file;
+ if ( preg_match( '/^((COPYING)|(LICENSE))(\.txt)?$/', $file ) &&
+ is_readable( $fullPath ) &&
+ is_file( $fullPath )
+ ) {
+ return $fullPath;
}
- return $this->getLanguage()->listToText( array_map( array( __CLASS__, 'arrayToString' ), $list ) );
}
+
+ return false;
+ }
+
+ /**
+ * Convert an array of items into a list for display.
+ *
+ * @param array $list List of elements to display
+ * @param bool $sort Whether to sort the items in $list
+ *
+ * @return string
+ */
+ public function listToText( $list, $sort = true ) {
+ if ( !count( $list ) ) {
+ return '';
+ }
+ if ( $sort ) {
+ sort( $list );
+ }
+
+ return $this->getLanguage()
+ ->listToText( array_map( array( __CLASS__, 'arrayToString' ), $list ) );
}
/**
* Convert an array or object to a string for display.
*
- * @param $list Mixed: will convert an array to string if given and return
- * the paramater unaltered otherwise
+ * @param mixed $list Will convert an array to string if given and return
+ * the paramater unaltered otherwise
*
- * @return Mixed
+ * @return mixed
*/
public static function arrayToString( $list ) {
if ( is_array( $list ) && count( $list ) == 1 ) {
@@ -666,6 +1034,7 @@ class SpecialVersion extends SpecialPage {
}
if ( is_object( $list ) ) {
$class = wfMessage( 'parentheses' )->params( get_class( $list ) )->escaped();
+
return $class;
} elseif ( !is_array( $list ) ) {
return $list;
@@ -675,6 +1044,7 @@ class SpecialVersion extends SpecialPage {
} else {
$class = $list[0];
}
+
return wfMessage( 'parentheses' )->params( "$class, {$list[1]}" )->escaped();
}
}
@@ -692,7 +1062,7 @@ class SpecialVersion extends SpecialPage {
* url The subversion URL of the directory
* repo-url The base URL of the repository
* viewvc-url A ViewVC URL pointing to the checked-out revision
- * @param $dir string
+ * @param string $dir
* @return array|bool
*/
public static function getSvnInfo( $dir ) {
@@ -765,9 +1135,9 @@ class SpecialVersion extends SpecialPage {
/**
* Retrieve the revision number of a Subversion working directory.
*
- * @param string $dir directory of the svn checkout
+ * @param string $dir Directory of the svn checkout
*
- * @return Integer: revision number as int
+ * @return int Revision number
*/
public static function getSvnRevision( $dir ) {
$info = self::getSvnInfo( $dir );
@@ -782,15 +1152,25 @@ class SpecialVersion extends SpecialPage {
}
/**
- * @param string $dir directory of the git checkout
- * @return bool|String sha1 of commit HEAD points to
+ * @param string $dir Directory of the git checkout
+ * @return bool|string Sha1 of commit HEAD points to
*/
public static function getGitHeadSha1( $dir ) {
$repo = new GitInfo( $dir );
+
return $repo->getHeadSHA1();
}
/**
+ * @param string $dir Directory of the git checkout
+ * @return bool|string Branch currently checked out
+ */
+ public static function getGitCurrentBranch( $dir ) {
+ $repo = new GitInfo( $dir );
+ return $repo->getCurrentBranch();
+ }
+
+ /**
* Get the list of entry points and their URLs
* @return string Wikitext
*/
@@ -810,7 +1190,11 @@ class SpecialVersion extends SpecialPage {
'dir' => $language->getDir(),
'lang' => $language->getCode()
);
- $out = Html::element( 'h2', array( 'id' => 'mw-version-entrypoints' ), $this->msg( 'version-entrypoints' )->text() ) .
+ $out = Html::element(
+ 'h2',
+ array( 'id' => 'mw-version-entrypoints' ),
+ $this->msg( 'version-entrypoints' )->text()
+ ) .
Html::openElement( 'table',
array(
'class' => 'wikitable plainlinks',
@@ -820,8 +1204,16 @@ class SpecialVersion extends SpecialPage {
)
) .
Html::openElement( 'tr' ) .
- Html::element( 'th', $thAttribures, $this->msg( 'version-entrypoints-header-entrypoint' )->text() ) .
- Html::element( 'th', $thAttribures, $this->msg( 'version-entrypoints-header-url' )->text() ) .
+ Html::element(
+ 'th',
+ $thAttribures,
+ $this->msg( 'version-entrypoints-header-entrypoint' )->text()
+ ) .
+ Html::element(
+ 'th',
+ $thAttribures,
+ $this->msg( 'version-entrypoints-header-url' )->text()
+ ) .
Html::closeElement( 'tr' );
foreach ( $entryPoints as $message => $value ) {
@@ -835,11 +1227,11 @@ class SpecialVersion extends SpecialPage {
}
$out .= Html::closeElement( 'table' );
+
return $out;
}
protected function getGroupName() {
return 'wiki';
}
-
}