diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2014-12-27 15:41:37 +0100 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2014-12-31 11:43:28 +0100 |
commit | c1f9b1f7b1b77776192048005dcc66dcf3df2bfb (patch) | |
tree | 2b38796e738dd74cb42ecd9bfd151803108386bc /includes/specials/SpecialVersion.php | |
parent | b88ab0086858470dd1f644e64cb4e4f62bb2be9b (diff) |
Update to MediaWiki 1.24.1
Diffstat (limited to 'includes/specials/SpecialVersion.php')
-rw-r--r-- | includes/specials/SpecialVersion.php | 738 |
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] = "<{$tags[$i]}>"; - } - $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 = '<' . htmlspecialchars( $value ) . '>'; + } ); + $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 = '–'; + $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'; } - } |