'CategoryPage' => __DIR__ . '/includes/page/CategoryPage.php',
'CategoryPager' => __DIR__ . '/includes/specials/SpecialCategories.php',
'CategoryViewer' => __DIR__ . '/includes/CategoryViewer.php',
- 'CdbException' => __DIR__ . '/includes/libs/cdb/CdbException.php',
- 'CdbFunctions' => __DIR__ . '/includes/libs/cdb/CdbFunctions.php',
- 'CdbReader' => __DIR__ . '/includes/libs/cdb/CdbReader.php',
- 'CdbReaderDBA' => __DIR__ . '/includes/libs/cdb/CdbReaderDBA.php',
- 'CdbReaderPHP' => __DIR__ . '/includes/libs/cdb/CdbReaderPHP.php',
- 'CdbWriter' => __DIR__ . '/includes/libs/cdb/CdbWriter.php',
- 'CdbWriterDBA' => __DIR__ . '/includes/libs/cdb/CdbWriterDBA.php',
- 'CdbWriterPHP' => __DIR__ . '/includes/libs/cdb/CdbWriterPHP.php',
+ 'CdbException' => __DIR__ . '/includes/CdbCompat.php',
+ 'CdbReader' => __DIR__ . '/includes/CdbCompat.php',
+ 'CdbWriter' => __DIR__ . '/includes/CdbCompat.php',
'CgzCopyTransaction' => __DIR__ . '/maintenance/storage/recompressTracked.php',
'ChangePassword' => __DIR__ . '/maintenance/changePassword.php',
'ChangeTags' => __DIR__ . '/includes/ChangeTags.php',
'lessc_formatter_lessjs' => __DIR__ . '/includes/libs/lessc.inc.php',
'lessc_parser' => __DIR__ . '/includes/libs/lessc.inc.php',
'profile_point' => __DIR__ . '/profileinfo.php',
-);
\ No newline at end of file
+);
"require": {
"php": ">=5.3.3",
"psr/log": "1.0.0",
- "cssjanus/cssjanus": "1.1.0"
+ "cssjanus/cssjanus": "1.1.0",
+ "cdb/cdb": "1.0.0"
},
"require-dev": {
"phpunit/phpunit": "*"
--- /dev/null
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/***
+ * This file contains a set of backwards-compatability class names
+ * after the cdb functions were moved out into a separate library
+ * and put under a proper namespace
+ *
+ * @since 1.25
+ */
+
+/**
+ * @deprecated since 1.25
+ */
+abstract class CdbReader extends \Cdb\Reader {}
+
+/**
+ * @deprecated since 1.25
+ */
+abstract class CdbWriter extends \Cdb\Writer {}
+
+/**
+ * @deprecated since 1.25
+ */
+class CdbException extends \Cdb\Exception {}
/**
* Site admin email address.
*
- * Defaults to "wikiadmin@{$wgServerName}".
+ * Defaults to "wikiadmin@$wgServerName".
*/
$wgEmergencyContact = false;
*
* The address we should use as sender when a user is requesting his password.
*
- * Defaults to "apache@{$wgServerName}".
+ * Defaults to "apache@$wgServerName".
*/
$wgPasswordSender = false;
* $wgDebugRawPage - if false, 'action=raw' hits will not result in debug output.
* $wgDebugComments - if on, some debug items may appear in comments in the HTML output.
*
+ * @since 1.25 support for additional context data
+ *
* @param string $text
* @param string|bool $dest Destination of the message:
* - 'all': both to the log and HTML (debug toolbar or HTML comments)
* For backward compatibility, it can also take a boolean:
* - true: same as 'all'
* - false: same as 'log'
+ * @param array $context Additional logging context data
*/
-function wfDebug( $text, $dest = 'all' ) {
+function wfDebug( $text, $dest = 'all', array $context = array() ) {
global $wgDebugRawPage, $wgDebugLogPrefix;
+ global $wgDebugTimestamps, $wgRequestTime;
if ( !$wgDebugRawPage && wfIsDebugRawPage() ) {
return;
$dest = 'log';
}
- $timer = wfDebugTimer();
- if ( $timer !== '' ) {
- // Prepend elapsed request time and real memory usage to each line
- $text = preg_replace( '/[^\n]/', $timer . '\0', $text, 1 );
+ $text = trim( $text );
+
+ // Inline logic from deprecated wfDebugTimer()
+ if ( $wgDebugTimestamps ) {
+ $context['seconds_elapsed'] = sprintf(
+ '%6.4f',
+ microtime( true ) - $wgRequestTime
+ );
+ $context['memory_used'] = sprintf(
+ '%5.1fM',
+ ( memory_get_usage( true ) / ( 1024 * 1024 ) )
+ );
}
if ( $dest === 'all' ) {
- MWDebug::debugMsg( $text );
+ $prefix = '';
+ if ( $wgDebugTimestamps ) {
+ // Prepend elapsed request time and real memory usage with two
+ // trailing spaces.
+ $prefix = "{$context['seconds_elapsed']} {$context['memory_used']} ";
+ }
+ MWDebug::debugMsg( "{$prefix}{$text}" );
}
- $ctx = array();
if ( $wgDebugLogPrefix !== '' ) {
- $ctx['prefix'] = $wgDebugLogPrefix;
+ $context['prefix'] = $wgDebugLogPrefix;
}
$logger = MWLogger::getInstance( 'wfDebug' );
- $logger->debug( rtrim( $text, "\n" ), $ctx );
+ $logger->debug( $text, $context );
}
/**
/**
* Get microsecond timestamps for debug logs
*
+ * @deprecated since 1.25
* @return string
*/
function wfDebugTimer() {
global $wgDebugTimestamps, $wgRequestTime;
+ wfDeprecated( __METHOD__, '1.25' );
+
if ( !$wgDebugTimestamps ) {
return '';
}
* a sampling factor.
*
* @since 1.23 support for sampling log messages via $wgDebugLogGroups.
+ * @since 1.25 support for additional context data
*
* @param string $logGroup
* @param string $text
* For backward compatibility, it can also take a boolean:
* - true: same as 'all'
* - false: same as 'private'
+ * @param array $context Additional logging context data
*/
-function wfDebugLog( $logGroup, $text, $dest = 'all' ) {
+function wfDebugLog(
+ $logGroup, $text, $dest = 'all', array $context = array()
+) {
// Turn $dest into a string if it's a boolean (for b/c)
if ( $dest === true ) {
$dest = 'all';
}
$logger = MWLogger::getInstance( $logGroup );
- $logger->debug( $text, array(
- 'private' => ( $dest === 'private' ),
- ) );
+ $context['private'] = ( $dest === 'private' );
+ $logger->debug( $text, $context );
}
/**
* Log for database errors
*
+ * @since 1.25 support for additional context data
+ *
* @param string $text Database error message.
+ * @param array $context Additional logging context data
*/
-function wfLogDBError( $text ) {
+function wfLogDBError( $text, array $context = array() ) {
$logger = MWLogger::getInstance( 'wfLogDBError' );
- $logger->error( trim( $text ) );
+ $logger->error( trim( $text ), $context );
}
/**
*
* Can also log to TCP or UDP with the syntax udp://host:port/prefix. This will
* send lines to the specified port, prefixed by the specified prefix and a space.
+ * @since 1.25 support for additional context data
*
* @param string $text
* @param string $file Filename
+ * @param array $context Additional logging context data
* @throws MWException
*/
-function wfErrorLog( $text, $file ) {
+function wfErrorLog( $text, $file, array $context = array() ) {
$logger = MWLogger::getInstance( 'wfErrorLog' );
- $logger->info( trim( $text ), array(
- 'destination' => $file,
- ) );
+ $context['destination'] = $file;
+ $logger->info( trim( $text ), $context );
}
/**
'wgMonthNames' => $lang->getMonthNamesArray(),
'wgMonthNamesShort' => $lang->getMonthAbbreviationsArray(),
'wgRelevantPageName' => $relevantTitle->getPrefixedDBkey(),
+ 'wgRelevantArticleId' => $relevantTitle->getArticleId(),
);
if ( $user->isLoggedIn() ) {
}
$t = new Title();
- $t->mDbkeyform = Title::makeName( $ns, $title, $fragment, $interwiki );
+ $t->mDbkeyform = Title::makeName( $ns, $title, $fragment, $interwiki, true );
if ( $t->secureAndSplit() ) {
return $t;
} else {
* @param string $title The DB key form the title
* @param string $fragment The link fragment (after the "#")
* @param string $interwiki The interwiki prefix
+ * @param boolean $canoncialNamespace If true, use the canonical name for
+ * $ns instead of the localized version.
* @return string The prefixed form of the title
*/
- public static function makeName( $ns, $title, $fragment = '', $interwiki = '' ) {
+ public static function makeName( $ns, $title, $fragment = '', $interwiki = '',
+ $canoncialNamespace = false
+ ) {
global $wgContLang;
- $namespace = $wgContLang->getNsText( $ns );
+ if ( $canoncialNamespace ) {
+ $namespace = MWNamespace::getCanonicalName( $ns );
+ } else {
+ $namespace = $wgContLang->getNsText( $ns );
+ }
$name = $namespace == '' ? $title : "$namespace:$title";
if ( strval( $interwiki ) != '' ) {
$name = "$interwiki:$name";
* @return int|null The corresponding user's ID, or null if user is nonexistent
*/
public static function idFromName( $name ) {
- // We don't want to call Title::makeTitleSafe yet, since that call path
- // ends up needing the user language, which ends up trying to load the
- // user object, which ends up back here (bug 54193).
- $nt = Title::makeTitle( NS_USER, $name );
+ $nt = Title::makeTitleSafe( NS_USER, $name );
+ if ( is_null( $nt ) ) {
+ // Illegal name
+ return null;
+ }
+
if ( isset( self::$idCacheByName[$name] ) ) {
return self::$idCacheByName[$name];
}
# Check that there is no previous output or previously set up buffers, because
# that would cause us to potentially mix gzip and non-gzip output, creating a
# big mess.
-if ( !defined( 'MW_NO_OUTPUT_BUFFER' ) && ob_get_level() == 0 ) {
+if ( ob_get_level() == 0 ) {
require_once "$IP/includes/OutputHandler.php";
ob_start( 'wfOutputHandler' );
}
* @file
*/
+use Cdb\Exception as CdbException;
+use Cdb\Reader as CdbReader;
+use Cdb\Writer as CdbWriter;
/**
* Class for caching the contents of localisation files, Messages*.php
* and *.i18n.php.
$this->mPHPError = $errstr;
}
+ /**
+ * Create a log context to pass to wfLogDBError or other logging functions.
+ *
+ * @param array $extras Additional data to add to context
+ * @return array
+ */
+ protected function getLogContext( array $extras = array() ) {
+ return array_merge(
+ array(
+ 'db_server' => $this->mServer,
+ 'db_name' => $this->mDBname,
+ 'db_user' => $this->mUser,
+ ),
+ $extras
+ );
+ }
+
/**
* Closes a database connection.
* if it is open : commits any open transactions
}
# Log the query time and feed it into the DB trx profiler
- $queryStartTime = microtime( true );
- $queryProfile = new ScopedCallback( function() use ( $queryStartTime, $queryProf ) {
- $elapsed = microtime( true ) - $queryStartTime;
- $trxProfiler = Profiler::instance()->getTransactionProfiler();
- $trxProfiler->recordFunctionCompletion( $queryProf, $elapsed );
- } );
+ if ( $queryProf != '' ) {
+ $queryStartTime = microtime( true );
+ $queryProfile = new ScopedCallback( function() use ( $queryStartTime, $queryProf ) {
+ $elapsed = microtime( true ) - $queryStartTime;
+ $trxProfiler = Profiler::instance()->getTransactionProfiler();
+ $trxProfiler->recordFunctionCompletion( $queryProf, $elapsed );
+ } );
+ }
# Do the query and handle errors
$ret = $this->doQuery( $commentedSql );
$elapsed = round( microtime( true ) - $wgRequestTime, 3 );
if ( $elapsed < 300 ) {
# Not a database error to lose a transaction after a minute or two
- wfLogDBError( "Connection lost and reconnected after {$elapsed}s, query: $sqlx" );
+ wfLogDBError(
+ "Connection lost and reconnected after {$elapsed}s, query: $sqlx",
+ $this->getLogContext( array(
+ 'method' => __METHOD__,
+ 'query' => $sqlx,
+ ) )
+ );
}
if ( $hadTrx ) {
# Leave $ret as false and let an error be reported.
$this->ignoreErrors( $ignore );
} else {
$sql1line = mb_substr( str_replace( "\n", "\\n", $sql ), 0, 5 * 1024 );
- wfLogDBError( "$fname\t{$this->mServer}\t$errno\t$error\t$sql1line" );
+ wfLogDBError(
+ "{fname}\t{db_server}\t{errno}\t{error}\t{sql1line}",
+ $this->getLogContext( array(
+ 'method' => __METHOD__,
+ 'errno' => $errno,
+ 'error' => $error,
+ 'sql1line' => $sql1line,
+ 'fname' => $fname,
+ ) )
+ );
wfDebug( "SQL ERROR: " . $error . "\n" );
throw new DBQueryError( $this, $error, $errno, $sql, $fname );
}
$msg = "$fname: Transaction already in progress (from {$this->mTrxFname}), " .
" performing implicit commit!";
wfWarn( $msg );
- wfLogDBError( $msg );
+ wfLogDBError( $msg,
+ $this->getLogContext( array(
+ 'method' => __METHOD__,
+ 'fname' => $fname,
+ ) )
+ );
} else {
// if the transaction was automatic and has done write operations,
// log it if $wgDebugDBTransactions is enabled.
if ( !$error ) {
$error = $this->lastError();
}
- wfLogDBError( "Error connecting to {$this->mServer}: $error" );
+ wfLogDBError(
+ "Error connecting to {db_server}: {error}",
+ $this->getLogContext( array(
+ 'method' => __METHOD__,
+ 'error' => $error,
+ ) )
+ );
wfDebug( "DB connection error\n" .
"Server: $server, User: $user, Password: " .
substr( $password, 0, 3 ) . "..., error: " . $error . "\n" );
$success = $this->selectDB( $dbName );
wfRestoreWarnings();
if ( !$success ) {
- wfLogDBError( "Error selecting database $dbName on server {$this->mServer}" );
+ wfLogDBError(
+ "Error selecting database {db_name} on server {db_server}",
+ $this->getLogContext( array(
+ 'method' => __METHOD__,
+ ) )
+ );
wfDebug( "Error selecting database $dbName on server {$this->mServer} " .
"from client host " . wfHostname() . "\n" );
// Use doQuery() to avoid opening implicit transactions (DBO_TRX)
$success = $this->doQuery( "SET sql_mode = $mode", __METHOD__ );
if ( !$success ) {
- wfLogDBError( "Error setting sql_mode to $mode on server {$this->mServer}" );
+ wfLogDBError(
+ "Error setting sql_mode to $mode on server {db_server}",
+ $this->getLogContext( array(
+ 'method' => __METHOD__,
+ ) )
+ );
wfProfileOut( __METHOD__ );
$this->reportConnectionError( "Error setting sql_mode to $mode" );
}
*/
private function reportConnectionError() {
$conn = $this->mErrorConnection; // The connection which caused the error
+ $context = array(
+ 'method' => __METHOD__,
+ 'last_error' => $this->mLastError,
+ );
if ( !is_object( $conn ) ) {
// No last connection, probably due to all servers being too busy
- wfLogDBError( "LB failure with no last connection. Connection error: {$this->mLastError}" );
+ wfLogDBError(
+ "LB failure with no last connection. Connection error: {last_error}",
+ $context
+ );
// If all servers were busy, mLastError will contain something sensible
throw new DBConnectionError( null, $this->mLastError );
} else {
- $server = $conn->getProperty( 'mServer' );
- wfLogDBError( "Connection error: {$this->mLastError} ({$server})" );
- $conn->reportConnectionError( "{$this->mLastError} ({$server})" ); // throws DBConnectionError
+ $context['db_server'] = $conn->getProperty( 'mServer' );
+ wfLogDBError(
+ "Connection error: {last_error} ({db_server})",
+ $context
+ );
+ $conn->reportConnectionError( "{$this->mLastError} ({$context['db_server']})" ); // throws DBConnectionError
}
return false; /* not reached */
// Default formatting is wfDebugLog's historic style
$text = self::formatAsWfDebugLog( $channel, $message, $context );
}
- return $text;
+
+ return self::interpolate( $text, $context );
}
*/
protected static function formatAsWfDebug( $channel, $message, $context ) {
$text = preg_replace( '![\x00-\x08\x0b\x0c\x0e-\x1f]!', ' ', $message );
+ if ( isset( $context['seconds_elapsed'] ) ) {
+ // Prepend elapsed request time and real memory usage with two
+ // trailing spaces.
+ $text = "{$context['seconds_elapsed']} {$context['memory_used']} {$text}";
+ }
if ( isset( $context['prefix'] ) ) {
$text = "{$context['prefix']}{$text}";
}
}
+ /**
+ * Interpolate placeholders in logging message.
+ *
+ * @param string $message
+ * @param array $context
+ */
+ public static function interpolate( $message, array $context ) {
+ if ( strpos( $message, '{' ) !== false ) {
+ $replace = array();
+ foreach ( $context as $key => $val ) {
+ $replace['{' . $key . '}'] = $val;
+ }
+ $message = strtr( $message, $replace );
+ }
+ return $message;
+ }
+
+
/**
* Select the appropriate log output destination for the given log event.
*
strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE' ) !== false
) {
// JS appears to be the only method that works consistently with IE7+
- $this->addHtml( "\n<script>jQuery( function () { document.location = " .
+ $this->addHtml( "\n<script>jQuery( function () { location.href = " .
Xml::encodeJsVar( $lsUrl ) . "; } );</script>\n" );
} else {
$this->parent->request->response()->header( "Refresh: 0;url=$lsUrl" );
*
* @file
*/
+use \Cdb\Exception as CdbException;
+use \Cdb\Reader as CdbReader;
/**
* The interwiki class
+++ /dev/null
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * Exception for Cdb errors.
- * This explicitly doesn't subclass MWException to encourage reuse.
- */
-class CdbException extends Exception {
-}
+++ /dev/null
-<?php
-/**
- * This is a port of D.J. Bernstein's CDB to PHP. It's based on the copy that
- * appears in PHP 5.3. Changes are:
- * * Error returns replaced with exceptions
- * * Exception thrown if sizes or offsets are between 2GB and 4GB
- * * Some variables renamed
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * Common functions for readers and writers
- */
-class CdbFunctions {
- /**
- * Take a modulo of a signed integer as if it were an unsigned integer.
- * $b must be less than 0x40000000 and greater than 0
- *
- * @param int $a
- * @param int $b
- *
- * @return int
- */
- public static function unsignedMod( $a, $b ) {
- if ( $a & 0x80000000 ) {
- $m = ( $a & 0x7fffffff ) % $b + 2 * ( 0x40000000 % $b );
-
- return $m % $b;
- } else {
- return $a % $b;
- }
- }
-
- /**
- * Shift a signed integer right as if it were unsigned
- * @param int $a
- * @param int $b
- * @return int
- */
- public static function unsignedShiftRight( $a, $b ) {
- if ( $b == 0 ) {
- return $a;
- }
- if ( $a & 0x80000000 ) {
- return ( ( $a & 0x7fffffff ) >> $b ) | ( 0x40000000 >> ( $b - 1 ) );
- } else {
- return $a >> $b;
- }
- }
-
- /**
- * The CDB hash function.
- *
- * @param string $s
- *
- * @return int
- */
- public static function hash( $s ) {
- $h = 5381;
- $len = strlen( $s );
- for ( $i = 0; $i < $len; $i++ ) {
- $h5 = ( $h << 5 ) & 0xffffffff;
- // Do a 32-bit sum
- // Inlined here for speed
- $sum = ( $h & 0x3fffffff ) + ( $h5 & 0x3fffffff );
- $h =
- (
- ( $sum & 0x40000000 ? 1 : 0 )
- + ( $h & 0x80000000 ? 2 : 0 )
- + ( $h & 0x40000000 ? 1 : 0 )
- + ( $h5 & 0x80000000 ? 2 : 0 )
- + ( $h5 & 0x40000000 ? 1 : 0 )
- ) << 30
- | ( $sum & 0x3fffffff );
- $h ^= ord( $s[$i] );
- $h &= 0xffffffff;
- }
-
- return $h;
- }
-}
+++ /dev/null
-<?php
-/**
- * Native CDB file reader and writer.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * Read from a CDB file.
- * Native and pure PHP implementations are provided.
- * http://cr.yp.to/cdb.html
- */
-abstract class CdbReader {
- /**
- * The file handle
- */
- protected $handle;
-
- /**
- * Open a file and return a subclass instance
- *
- * @param string $fileName
- *
- * @return CdbReader
- */
- public static function open( $fileName ) {
- return self::haveExtension() ?
- new CdbReaderDBA( $fileName ) :
- new CdbReaderPHP( $fileName );
- }
-
- /**
- * Returns true if the native extension is available
- *
- * @return bool
- */
- public static function haveExtension() {
- if ( !function_exists( 'dba_handlers' ) ) {
- return false;
- }
- $handlers = dba_handlers();
- if ( !in_array( 'cdb', $handlers ) || !in_array( 'cdb_make', $handlers ) ) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Create the object and open the file
- *
- * @param string $fileName
- */
- abstract public function __construct( $fileName );
-
- /**
- * Close the file. Optional, you can just let the variable go out of scope.
- */
- abstract public function close();
-
- /**
- * Get a value with a given key. Only string values are supported.
- *
- * @param string $key
- */
- abstract public function get( $key );
-}
+++ /dev/null
-<?php
-/**
- * DBA-based CDB reader/writer
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * Reader class which uses the DBA extension
- */
-class CdbReaderDBA extends CdbReader {
- public function __construct( $fileName ) {
- $this->handle = dba_open( $fileName, 'r-', 'cdb' );
- if ( !$this->handle ) {
- throw new CdbException( 'Unable to open CDB file "' . $fileName . '"' );
- }
- }
-
- public function close() {
- if ( isset( $this->handle ) ) {
- dba_close( $this->handle );
- }
- unset( $this->handle );
- }
-
- public function get( $key ) {
- return dba_fetch( $key, $this->handle );
- }
-}
+++ /dev/null
-<?php
-/**
- * This is a port of D.J. Bernstein's CDB to PHP. It's based on the copy that
- * appears in PHP 5.3. Changes are:
- * * Error returns replaced with exceptions
- * * Exception thrown if sizes or offsets are between 2GB and 4GB
- * * Some variables renamed
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * CDB reader class
- */
-class CdbReaderPHP extends CdbReader {
- /** The filename */
- protected $fileName;
-
- /* number of hash slots searched under this key */
- protected $loop;
-
- /* initialized if loop is nonzero */
- protected $khash;
-
- /* initialized if loop is nonzero */
- protected $kpos;
-
- /* initialized if loop is nonzero */
- protected $hpos;
-
- /* initialized if loop is nonzero */
- protected $hslots;
-
- /* initialized if findNext() returns true */
- protected $dpos;
-
- /* initialized if cdb_findnext() returns 1 */
- protected $dlen;
-
- /**
- * @param string $fileName
- * @throws CdbException
- */
- public function __construct( $fileName ) {
- $this->fileName = $fileName;
- $this->handle = fopen( $fileName, 'rb' );
- if ( !$this->handle ) {
- throw new CdbException( 'Unable to open CDB file "' . $this->fileName . '".' );
- }
- $this->findStart();
- }
-
- public function close() {
- if ( isset( $this->handle ) ) {
- fclose( $this->handle );
- }
- unset( $this->handle );
- }
-
- /**
- * @param mixed $key
- * @return bool|string
- */
- public function get( $key ) {
- // strval is required
- if ( $this->find( strval( $key ) ) ) {
- return $this->read( $this->dlen, $this->dpos );
- } else {
- return false;
- }
- }
-
- /**
- * @param string $key
- * @param int $pos
- * @return bool
- */
- protected function match( $key, $pos ) {
- $buf = $this->read( strlen( $key ), $pos );
-
- return $buf === $key;
- }
-
- protected function findStart() {
- $this->loop = 0;
- }
-
- /**
- * @throws CdbException
- * @param int $length
- * @param int $pos
- * @return string
- */
- protected function read( $length, $pos ) {
- if ( fseek( $this->handle, $pos ) == -1 ) {
- // This can easily happen if the internal pointers are incorrect
- throw new CdbException(
- 'Seek failed, file "' . $this->fileName . '" may be corrupted.' );
- }
-
- if ( $length == 0 ) {
- return '';
- }
-
- $buf = fread( $this->handle, $length );
- if ( $buf === false || strlen( $buf ) !== $length ) {
- throw new CdbException(
- 'Read from CDB file failed, file "' . $this->fileName . '" may be corrupted.' );
- }
-
- return $buf;
- }
-
- /**
- * Unpack an unsigned integer and throw an exception if it needs more than 31 bits
- * @param string $s
- * @throws CdbException
- * @return mixed
- */
- protected function unpack31( $s ) {
- $data = unpack( 'V', $s );
- if ( $data[1] > 0x7fffffff ) {
- throw new CdbException(
- 'Error in CDB file "' . $this->fileName . '", integer too big.' );
- }
-
- return $data[1];
- }
-
- /**
- * Unpack a 32-bit signed integer
- * @param string $s
- * @return int
- */
- protected function unpackSigned( $s ) {
- $data = unpack( 'va/vb', $s );
-
- return $data['a'] | ( $data['b'] << 16 );
- }
-
- /**
- * @param string $key
- * @return bool
- */
- protected function findNext( $key ) {
- if ( !$this->loop ) {
- $u = CdbFunctions::hash( $key );
- $buf = $this->read( 8, ( $u << 3 ) & 2047 );
- $this->hslots = $this->unpack31( substr( $buf, 4 ) );
- if ( !$this->hslots ) {
- return false;
- }
- $this->hpos = $this->unpack31( substr( $buf, 0, 4 ) );
- $this->khash = $u;
- $u = CdbFunctions::unsignedShiftRight( $u, 8 );
- $u = CdbFunctions::unsignedMod( $u, $this->hslots );
- $u <<= 3;
- $this->kpos = $this->hpos + $u;
- }
-
- while ( $this->loop < $this->hslots ) {
- $buf = $this->read( 8, $this->kpos );
- $pos = $this->unpack31( substr( $buf, 4 ) );
- if ( !$pos ) {
- return false;
- }
- $this->loop += 1;
- $this->kpos += 8;
- if ( $this->kpos == $this->hpos + ( $this->hslots << 3 ) ) {
- $this->kpos = $this->hpos;
- }
- $u = $this->unpackSigned( substr( $buf, 0, 4 ) );
- if ( $u === $this->khash ) {
- $buf = $this->read( 8, $pos );
- $keyLen = $this->unpack31( substr( $buf, 0, 4 ) );
- if ( $keyLen == strlen( $key ) && $this->match( $key, $pos + 8 ) ) {
- // Found
- $this->dlen = $this->unpack31( substr( $buf, 4 ) );
- $this->dpos = $pos + 8 + $keyLen;
-
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * @param mixed $key
- * @return bool
- */
- protected function find( $key ) {
- $this->findStart();
-
- return $this->findNext( $key );
- }
-}
-
+++ /dev/null
-<?php
-/**
- * Native CDB file reader and writer.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * Write to a CDB file.
- * Native and pure PHP implementations are provided.
- * http://cr.yp.to/cdb.html
- */
-abstract class CdbWriter {
- /**
- * The file handle
- */
- protected $handle;
-
- /**
- * File we'll be writing to when we're done
- * @var string
- */
- protected $realFileName;
-
- /**
- * File we write to temporarily until we're done
- * @var string
- */
- protected $tmpFileName;
-
- /**
- * Open a writer and return a subclass instance.
- * The user must have write access to the directory, for temporary file creation.
- *
- * @param string $fileName
- *
- * @return CdbWriterDBA|CdbWriterPHP
- */
- public static function open( $fileName ) {
- return CdbReader::haveExtension() ?
- new CdbWriterDBA( $fileName ) :
- new CdbWriterPHP( $fileName );
- }
-
- /**
- * Create the object and open the file
- *
- * @param string $fileName
- */
- abstract public function __construct( $fileName );
-
- /**
- * Set a key to a given value. The value will be converted to string.
- * @param string $key
- * @param string $value
- */
- abstract public function set( $key, $value );
-
- /**
- * Close the writer object. You should call this function before the object
- * goes out of scope, to write out the final hashtables.
- */
- abstract public function close();
-
- /**
- * If the object goes out of scope, close it for sanity
- */
- public function __destruct() {
- if ( isset( $this->handle ) ) {
- $this->close();
- }
- }
-
- /**
- * Are we running on Windows?
- * @return bool
- */
- protected function isWindows() {
- return substr( php_uname(), 0, 7 ) == 'Windows';
- }
-}
+++ /dev/null
-<?php
-/**
- * DBA-based CDB reader/writer
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * Writer class which uses the DBA extension
- */
-class CdbWriterDBA extends CdbWriter {
- public function __construct( $fileName ) {
- $this->realFileName = $fileName;
- $this->tmpFileName = $fileName . '.tmp.' . mt_rand( 0, 0x7fffffff );
- $this->handle = dba_open( $this->tmpFileName, 'n', 'cdb_make' );
- if ( !$this->handle ) {
- throw new CdbException( 'Unable to open CDB file for write "' . $fileName . '"' );
- }
- }
-
- public function set( $key, $value ) {
- return dba_insert( $key, $value, $this->handle );
- }
-
- public function close() {
- if ( isset( $this->handle ) ) {
- dba_close( $this->handle );
- }
- if ( $this->isWindows() ) {
- unlink( $this->realFileName );
- }
- if ( !rename( $this->tmpFileName, $this->realFileName ) ) {
- throw new CdbException( 'Unable to move the new CDB file into place.' );
- }
- unset( $this->handle );
- }
-}
+++ /dev/null
-<?php
-/**
- * This is a port of D.J. Bernstein's CDB to PHP. It's based on the copy that
- * appears in PHP 5.3. Changes are:
- * * Error returns replaced with exceptions
- * * Exception thrown if sizes or offsets are between 2GB and 4GB
- * * Some variables renamed
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * CDB writer class
- */
-class CdbWriterPHP extends CdbWriter {
- protected $hplist;
-
- protected $numentries;
-
- protected $pos;
-
- /**
- * @param string $fileName
- */
- public function __construct( $fileName ) {
- $this->realFileName = $fileName;
- $this->tmpFileName = $fileName . '.tmp.' . mt_rand( 0, 0x7fffffff );
- $this->handle = fopen( $this->tmpFileName, 'wb' );
- if ( !$this->handle ) {
- $this->throwException(
- 'Unable to open CDB file "' . $this->tmpFileName . '" for write.' );
- }
- $this->hplist = array();
- $this->numentries = 0;
- $this->pos = 2048; // leaving space for the pointer array, 256 * 8
- if ( fseek( $this->handle, $this->pos ) == -1 ) {
- $this->throwException( 'fseek failed in file "' . $this->tmpFileName . '".' );
- }
- }
-
- /**
- * @param string $key
- * @param string $value
- */
- public function set( $key, $value ) {
- if ( strval( $key ) === '' ) {
- // DBA cross-check hack
- return;
- }
- $this->addbegin( strlen( $key ), strlen( $value ) );
- $this->write( $key );
- $this->write( $value );
- $this->addend( strlen( $key ), strlen( $value ), CdbFunctions::hash( $key ) );
- }
-
- /**
- * @throws CdbException
- */
- public function close() {
- $this->finish();
- if ( isset( $this->handle ) ) {
- fclose( $this->handle );
- }
- if ( $this->isWindows() && file_exists( $this->realFileName ) ) {
- unlink( $this->realFileName );
- }
- if ( !rename( $this->tmpFileName, $this->realFileName ) ) {
- $this->throwException( 'Unable to move the new CDB file into place.' );
- }
- unset( $this->handle );
- }
-
- /**
- * @throws CdbException
- * @param string $buf
- */
- protected function write( $buf ) {
- $len = fwrite( $this->handle, $buf );
- if ( $len !== strlen( $buf ) ) {
- $this->throwException( 'Error writing to CDB file "' . $this->tmpFileName . '".' );
- }
- }
-
- /**
- * @throws CdbException
- * @param int $len
- */
- protected function posplus( $len ) {
- $newpos = $this->pos + $len;
- if ( $newpos > 0x7fffffff ) {
- $this->throwException(
- 'A value in the CDB file "' . $this->tmpFileName . '" is too large.' );
- }
- $this->pos = $newpos;
- }
-
- /**
- * @param int $keylen
- * @param int $datalen
- * @param int $h
- */
- protected function addend( $keylen, $datalen, $h ) {
- $this->hplist[] = array(
- 'h' => $h,
- 'p' => $this->pos
- );
-
- $this->numentries++;
- $this->posplus( 8 );
- $this->posplus( $keylen );
- $this->posplus( $datalen );
- }
-
- /**
- * @throws CdbException
- * @param int $keylen
- * @param int $datalen
- */
- protected function addbegin( $keylen, $datalen ) {
- if ( $keylen > 0x7fffffff ) {
- $this->throwException( 'Key length too long in file "' . $this->tmpFileName . '".' );
- }
- if ( $datalen > 0x7fffffff ) {
- $this->throwException( 'Data length too long in file "' . $this->tmpFileName . '".' );
- }
- $buf = pack( 'VV', $keylen, $datalen );
- $this->write( $buf );
- }
-
- /**
- * @throws CdbException
- */
- protected function finish() {
- // Hack for DBA cross-check
- $this->hplist = array_reverse( $this->hplist );
-
- // Calculate the number of items that will be in each hashtable
- $counts = array_fill( 0, 256, 0 );
- foreach ( $this->hplist as $item ) {
- ++$counts[255 & $item['h']];
- }
-
- // Fill in $starts with the *end* indexes
- $starts = array();
- $pos = 0;
- for ( $i = 0; $i < 256; ++$i ) {
- $pos += $counts[$i];
- $starts[$i] = $pos;
- }
-
- // Excessively clever and indulgent code to simultaneously fill $packedTables
- // with the packed hashtables, and adjust the elements of $starts
- // to actually point to the starts instead of the ends.
- $packedTables = array_fill( 0, $this->numentries, false );
- foreach ( $this->hplist as $item ) {
- $packedTables[--$starts[255 & $item['h']]] = $item;
- }
-
- $final = '';
- for ( $i = 0; $i < 256; ++$i ) {
- $count = $counts[$i];
-
- // The size of the hashtable will be double the item count.
- // The rest of the slots will be empty.
- $len = $count + $count;
- $final .= pack( 'VV', $this->pos, $len );
-
- $hashtable = array();
- for ( $u = 0; $u < $len; ++$u ) {
- $hashtable[$u] = array( 'h' => 0, 'p' => 0 );
- }
-
- // Fill the hashtable, using the next empty slot if the hashed slot
- // is taken.
- for ( $u = 0; $u < $count; ++$u ) {
- $hp = $packedTables[$starts[$i] + $u];
- $where = CdbFunctions::unsignedMod(
- CdbFunctions::unsignedShiftRight( $hp['h'], 8 ), $len );
- while ( $hashtable[$where]['p'] ) {
- if ( ++$where == $len ) {
- $where = 0;
- }
- }
- $hashtable[$where] = $hp;
- }
-
- // Write the hashtable
- for ( $u = 0; $u < $len; ++$u ) {
- $buf = pack( 'vvV',
- $hashtable[$u]['h'] & 0xffff,
- CdbFunctions::unsignedShiftRight( $hashtable[$u]['h'], 16 ),
- $hashtable[$u]['p'] );
- $this->write( $buf );
- $this->posplus( 8 );
- }
- }
-
- // Write the pointer array at the start of the file
- rewind( $this->handle );
- if ( ftell( $this->handle ) != 0 ) {
- $this->throwException( 'Error rewinding to start of file "' . $this->tmpFileName . '".' );
- }
- $this->write( $final );
- }
-
- /**
- * Clean up the temp file and throw an exception
- *
- * @param string $msg
- * @throws CdbException
- */
- protected function throwException( $msg ) {
- if ( $this->handle ) {
- fclose( $this->handle );
- unlink( $this->tmpFileName );
- }
- throw new CdbException( $msg );
- }
-}
$env['MAGICK_TMPDIR'] = $wgImageMagickTempDir;
}
- $rotation = $this->getRotation( $image );
+ $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
$cmd = call_user_func_array( 'wfEscapeShellArg', array_merge(
}
}
- $rotation = $this->getRotation( $image );
+ $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image );
list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
$im->setImageBackgroundColor( new ImagickPixel( 'white' ) );
$src_image = call_user_func( $loader, $params['srcPath'] );
- $rotation = function_exists( 'imagerotate' ) ? $this->getRotation( $image ) : 0;
+ $rotation = function_exists( 'imagerotate' ) && !isset( $params['disableRotation'] ) ? $this->getRotation( $image ) : 0;
list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation );
$dst_image = imagecreatetruecolor( $width, $height );
# Transform functions and binaries need a FS source file
$thumbnailSource = $this->getThumbnailSource( $image, $params );
+ // If the source isn't the original, disable EXIF rotation because it's already been applied
+ if ( $scalerParams['srcWidth'] != $thumbnailSource['width']
+ || $scalerParams['srcHeight'] != $thumbnailSource['height'] ) {
+ $scalerParams['disableRotation'] = true;
+ }
+
$scalerParams['srcPath'] = $thumbnailSource['path'];
$scalerParams['srcWidth'] = $thumbnailSource['width'];
$scalerParams['srcHeight'] = $thumbnailSource['height'];
uasort( $dataByFunc, function( $a, $b ) {
return $a['real'] < $b['real']; // descending order
} );
- $profileReport = "Top template expansion time report (%,ms,calls,template)\n";
+ $profileReport = "Transclusion expansion time report (%,ms,calls,template)\n";
foreach ( array_slice( $dataByFunc, 0, 10 ) as $item ) {
- $profileReport .= sprintf( "%6.2f%% %3.6f %6d - %s\n",
+ $profileReport .= sprintf( "%6.2f%% %8.3f %6d - %s\n",
$item['%real'], $item['real'], $item['calls'],
htmlspecialchars($item['name'] ) );
}
$this->parserOptions = $parserOptions;
$this->content = $content;
$this->cacheKey = ParserCache::singleton()->getKey( $page, $parserOptions );
- parent::__construct( 'ArticleView', $this->cacheKey . ':revid:' . $revid );
+ $keyPrefix = $this->cacheKey ?: wfMemcKey( 'articleview', 'missingcachekey' );
+ parent::__construct( 'ArticleView', $keyPrefix . ':revid:' . $revid );
}
/**
* @param string $functionname
*/
public function profileIn( $functionname ) {
- global $wgDebugFunctionEntry;
- if ( $wgDebugFunctionEntry ) {
- $this->debug( "Entering {$functionname}" );
- }
}
/**
* @param string $functionname
*/
public function profileOut( $functionname ) {
- global $wgDebugFunctionEntry;
- if ( $wgDebugFunctionEntry ) {
- $this->debug( "Exiting {$functionname}" );
- }
}
/**
/**
* Custom PHP profiler for parser/DB type section names that xhprof/xdebug can't handle
*
- * @TODO: refactor implementation by moving Profiler code to here when non-automatic
- * profiler support is dropped.
- *
* @since 1.25
*/
class SectionProfiler {
- /** @var ProfilerStandard */
- protected $profiler;
+ /** @var array List of resolved profile calls with start/end data */
+ protected $stack = array();
+ /** @var array Queue of open profile calls with start data */
+ protected $workStack = array();
+
+ /** @var array Map of (function name => aggregate data array) */
+ protected $collated = array();
+ /** @var bool */
+ protected $collateDone = false;
+ /** @var bool Whether to collect the full stack trace or just aggregates */
+ protected $collateOnly = true;
- public function __construct() {
- // This does *not* care about PHP request start time
- $this->profiler = new ProfilerStandard( array( 'initTotal' => false ) );
+ /** @var array Cache of a standard broken collation entry */
+ protected $errorEntry;
+
+ /**
+ * @param array $params
+ */
+ public function __construct( array $params = array() ) {
+ $this->errorEntry = $this->getErrorEntry();
+ $this->collateOnly = empty( $params['trace'] );
}
/**
* @return ScopedCallback
*/
public function scopedProfileIn( $section ) {
- $profiler = $this->profiler;
- $sc = new ScopedCallback( function() use ( $profiler, $section ) {
- $profiler->profileOut( $section );
- } );
- $profiler->profileIn( $section );
+ $this->profileInInternal( $section );
- return $sc;
+ $that = $this;
+ return new ScopedCallback( function() use ( $that, $section ) {
+ $that->profileOutInternal( $section );
+ } );
}
/**
* - %memory : percent memory used
*/
public function getFunctionStats() {
- $data = $this->profiler->getFunctionStats();
+ $this->collateData();
- $cpuTotal = 0;
- $memoryTotal = 0;
- $elapsedTotal = 0;
- foreach ( $data as $item ) {
- $memoryTotal += $item['memory'];
- $elapsedTotal += $item['real'];
- $cpuTotal += $item['cpu'];
+ $totalCpu = 0.0;
+ $totalReal = 0.0;
+ $totalMem = 0;
+ foreach ( $this->collated as $fname => $data ) {
+ $totalCpu += $data['cpu'];
+ $totalReal += $data['real'];
+ $totalMem += $data['memory'];
}
- foreach ( $data as &$item ) {
- $item['%cpu'] = $item['cpu'] ? $item['cpu'] / $cpuTotal * 100 : 0;
- $item['%real'] = $elapsedTotal ? $item['real'] / $elapsedTotal * 100 : 0;
- $item['%memory'] = $item['memory'] ? $item['memory'] / $memoryTotal * 100 : 0;
+ $profile = array();
+ foreach ( $this->collated as $fname => $data ) {
+ $profile[] = array(
+ 'name' => $fname,
+ 'calls' => $data['count'],
+ 'real' => $data['real'] * 1000,
+ '%real' => $totalReal ? 100 * $data['real'] / $totalReal : 0,
+ 'cpu' => $data['cpu'] * 1000,
+ '%cpu' => $totalCpu ? 100 * $data['cpu'] / $totalCpu : 0,
+ 'memory' => $data['memory'],
+ '%memory' => $totalMem ? 100 * $data['memory'] / $totalMem : 0,
+ );
}
- unset( $item );
- $data[] = array(
+ $profile[] = array(
'name' => '-total',
'calls' => 1,
- 'real' => $elapsedTotal,
+ 'real' => 1000 * $totalReal,
'%real' => 100,
- 'memory' => $memoryTotal,
+ 'cpu' => 1000 * $totalCpu,
+ '%cpu' => 100,
+ 'memory' => $totalMem,
'%memory' => 100,
);
- return $data;
+ return $profile;
+ }
+
+ /**
+ * @return array Initial collation entry
+ */
+ protected function getZeroEntry() {
+ return array(
+ 'cpu' => 0.0,
+ 'real' => 0.0,
+ 'memory' => 0,
+ 'count' => 0
+ );
+ }
+
+ /**
+ * @return array Initial collation entry for errors
+ */
+ protected function getErrorEntry() {
+ $entry = $this->getZeroEntry();
+ $entry['count'] = 1;
+ return $entry;
+ }
+
+ /**
+ * Update the collation entry for a given method name
+ *
+ * @param string $name
+ * @param float $elapsedCpu
+ * @param float $elapsedReal
+ * @param int $memChange
+ */
+ protected function updateEntry( $name, $elapsedCpu, $elapsedReal, $memChange ) {
+ $entry =& $this->collated[$name];
+ if ( !is_array( $entry ) ) {
+ $entry = $this->getZeroEntry();
+ $this->collated[$name] =& $entry;
+ }
+ $entry['cpu'] += $elapsedCpu;
+ $entry['real'] += $elapsedReal;
+ $entry['memory'] += $memChange > 0 ? $memChange : 0;
+ $entry['count']++;
+ }
+
+ /**
+ * This method should not be called outside SectionProfiler
+ *
+ * @param string $functionname
+ */
+ public function profileInInternal( $functionname ) {
+ $this->workStack[] = array(
+ $functionname,
+ count( $this->workStack ),
+ $this->getTime( 'time' ),
+ $this->getTime( 'cpu' ),
+ memory_get_usage()
+ );
+ }
+
+ /**
+ * This method should not be called outside SectionProfiler
+ *
+ * @param string $functionname
+ */
+ public function profileOutInternal( $functionname ) {
+ $item = array_pop( $this->workStack );
+ if ( $item === null ) {
+ $this->debugGroup( 'profileerror', "Profiling error: $functionname" );
+ return;
+ }
+ list( $ofname, /* $ocount */, $ortime, $octime, $omem ) = $item;
+
+ if ( $functionname === 'close' ) {
+ $message = "Profile section ended by close(): {$ofname}";
+ $this->debugGroup( 'profileerror', $message );
+ if ( $this->collateOnly ) {
+ $this->collated[$message] = $this->errorEntry;
+ } else {
+ $this->stack[] = array( $message, 0, 0.0, 0.0, 0, 0.0, 0.0, 0 );
+ }
+ $functionname = $ofname;
+ } elseif ( $ofname !== $functionname ) {
+ $message = "Profiling error: in({$ofname}), out($functionname)";
+ $this->debugGroup( 'profileerror', $message );
+ if ( $this->collateOnly ) {
+ $this->collated[$message] = $this->errorEntry;
+ } else {
+ $this->stack[] = array( $message, 0, 0.0, 0.0, 0, 0.0, 0.0, 0 );
+ }
+ }
+ $realTime = $this->getTime( 'wall' );
+ $cpuTime = $this->getTime( 'cpu' );
+ if ( $this->collateOnly ) {
+ $elapsedcpu = $cpuTime - $octime;
+ $elapsedreal = $realTime - $ortime;
+ $memchange = memory_get_usage() - $omem;
+ $this->updateEntry( $functionname, $elapsedcpu, $elapsedreal, $memchange );
+ } else {
+ $this->stack[] = array_merge( $item,
+ array( $realTime, $cpuTime, memory_get_usage() ) );
+ }
+ }
+
+ /**
+ * Returns a tree of function calls with their real times
+ * @return string
+ */
+ public function getCallTreeReport() {
+ if ( $this->collateOnly ) {
+ throw new Exception( "Tree is only available for trace profiling." );
+ }
+ return implode( '', array_map(
+ array( $this, 'getCallTreeLine' ), $this->remapCallTree( $this->stack )
+ ) );
+ }
+
+ /**
+ * Recursive function the format the current profiling array into a tree
+ *
+ * @param array $stack Profiling array
+ * @return array
+ */
+ protected function remapCallTree( array $stack ) {
+ if ( count( $stack ) < 2 ) {
+ return $stack;
+ }
+ $outputs = array();
+ for ( $max = count( $stack ) - 1; $max > 0; ) {
+ /* Find all items under this entry */
+ $level = $stack[$max][1];
+ $working = array();
+ for ( $i = $max -1; $i >= 0; $i-- ) {
+ if ( $stack[$i][1] > $level ) {
+ $working[] = $stack[$i];
+ } else {
+ break;
+ }
+ }
+ $working = $this->remapCallTree( array_reverse( $working ) );
+ $output = array();
+ foreach ( $working as $item ) {
+ array_push( $output, $item );
+ }
+ array_unshift( $output, $stack[$max] );
+ $max = $i;
+
+ array_unshift( $outputs, $output );
+ }
+ $final = array();
+ foreach ( $outputs as $output ) {
+ foreach ( $output as $item ) {
+ $final[] = $item;
+ }
+ }
+ return $final;
+ }
+
+ /**
+ * Callback to get a formatted line for the call tree
+ * @param array $entry
+ * @return string
+ */
+ protected function getCallTreeLine( $entry ) {
+ // $entry has (name, level, stime, scpu, smem, etime, ecpu, emem)
+ list( $fname, $level, $startreal, , , $endreal ) = $entry;
+ $delta = $endreal - $startreal;
+ $space = str_repeat( ' ', $level );
+ # The ugly double sprintf is to work around a PHP bug,
+ # which has been fixed in recent releases.
+ return sprintf( "%10s %s %s\n",
+ trim( sprintf( "%7.3f", $delta * 1000.0 ) ), $space, $fname );
+ }
+
+ /**
+ * Populate collated data
+ */
+ protected function collateData() {
+ if ( $this->collateDone ) {
+ return;
+ }
+ $this->collateDone = true;
+ // Close opened profiling sections
+ while ( count( $this->workStack ) ) {
+ $this->profileOutInternal( 'close' );
+ }
+
+ if ( $this->collateOnly ) {
+ return; // already collated as methods exited
+ }
+
+ $this->collated = array();
+
+ # Estimate profiling overhead
+ $profileCount = count( $this->stack );
+ $this->calculateOverhead( $profileCount );
+
+ # First, subtract the overhead!
+ $overheadTotal = $overheadMemory = $overheadInternal = array();
+ foreach ( $this->stack as $entry ) {
+ // $entry is (name,pos,rtime0,cputime0,mem0,rtime1,cputime1,mem1)
+ $fname = $entry[0];
+ $elapsed = $entry[5] - $entry[2];
+ $memchange = $entry[7] - $entry[4];
+
+ if ( $fname === '-overhead-total' ) {
+ $overheadTotal[] = $elapsed;
+ $overheadMemory[] = max( 0, $memchange );
+ } elseif ( $fname === '-overhead-internal' ) {
+ $overheadInternal[] = $elapsed;
+ }
+ }
+ $overheadTotal = $overheadTotal ?
+ array_sum( $overheadTotal ) / count( $overheadInternal ) : 0;
+ $overheadMemory = $overheadMemory ?
+ array_sum( $overheadMemory ) / count( $overheadInternal ) : 0;
+ $overheadInternal = $overheadInternal ?
+ array_sum( $overheadInternal ) / count( $overheadInternal ) : 0;
+
+ # Collate
+ foreach ( $this->stack as $index => $entry ) {
+ // $entry is (name,pos,rtime0,cputime0,mem0,rtime1,cputime1,mem1)
+ $fname = $entry[0];
+ $elapsedCpu = $entry[6] - $entry[3];
+ $elapsedReal = $entry[5] - $entry[2];
+ $memchange = $entry[7] - $entry[4];
+ $subcalls = $this->calltreeCount( $this->stack, $index );
+
+ if ( substr( $fname, 0, 9 ) !== '-overhead' ) {
+ # Adjust for profiling overhead (except special values with elapsed=0
+ if ( $elapsed ) {
+ $elapsed -= $overheadInternal;
+ $elapsed -= ( $subcalls * $overheadTotal );
+ $memchange -= ( $subcalls * $overheadMemory );
+ }
+ }
+
+ $this->updateEntry( $fname, $elapsedCpu, $elapsedReal, $memchange );
+ }
+
+ $this->collated['-overhead-total']['count'] = $profileCount;
+ arsort( $this->collated, SORT_NUMERIC );
+ }
+
+ /**
+ * Dummy calls to calculate profiling overhead
+ *
+ * @param int $profileCount
+ */
+ protected function calculateOverhead( $profileCount ) {
+ $this->profileInInternal( '-overhead-total' );
+ for ( $i = 0; $i < $profileCount; $i++ ) {
+ $this->profileInInternal( '-overhead-internal' );
+ $this->profileOutInternal( '-overhead-internal' );
+ }
+ $this->profileOutInternal( '-overhead-total' );
+ }
+
+ /**
+ * Counts the number of profiled function calls sitting under
+ * the given point in the call graph. Not the most efficient algo.
+ *
+ * @param array $stack
+ * @param int $start
+ * @return int
+ */
+ protected function calltreeCount( $stack, $start ) {
+ $level = $stack[$start][1];
+ $count = 0;
+ for ( $i = $start -1; $i >= 0 && $stack[$i][1] > $level; $i-- ) {
+ $count ++;
+ }
+ return $count;
+ }
+
+ /**
+ * Get the initial time of the request, based either on $wgRequestTime or
+ * $wgRUstart. Will return null if not able to find data.
+ *
+ * @param string|bool $metric Metric to use, with the following possibilities:
+ * - user: User CPU time (without system calls)
+ * - cpu: Total CPU time (user and system calls)
+ * - wall (or any other string): elapsed time
+ * - false (default): will fall back to default metric
+ * @return float|null
+ */
+ protected function getTime( $metric = 'wall' ) {
+ if ( $metric === 'cpu' || $metric === 'user' ) {
+ $ru = wfGetRusage();
+ if ( !$ru ) {
+ return 0;
+ }
+ $time = $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6;
+ if ( $metric === 'cpu' ) {
+ # This is the time of system calls, added to the user time
+ # it gives the total CPU time
+ $time += $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6;
+ }
+ return $time;
+ } else {
+ return microtime( true );
+ }
+ }
+
+ /**
+ * Add an entry in the debug log file
+ *
+ * @param string $s String to output
+ */
+ protected function debug( $s ) {
+ if ( function_exists( 'wfDebug' ) ) {
+ wfDebug( $s );
+ }
+ }
+
+ /**
+ * Add an entry in the debug log group
+ *
+ * @param string $group Group to send the message to
+ * @param string $s String to output
+ */
+ protected function debugGroup( $group, $s ) {
+ if ( function_exists( 'wfDebugLog' ) ) {
+ wfDebugLog( $group, $s );
+ }
}
}
// sort for stable output
ksort( $content );
+ // extensions using this generator are appending to the existing
+ // autoload.
+ if ( $this->variableName === 'wgAutoloadClasses' ) {
+ $op = '+=';
+ } else {
+ $op = '=';
+ }
+
$output = implode( "\n\t", $content );
file_put_contents(
$this->basepath . '/autoload.php',
global \${$this->variableName};
-\${$this->variableName} = array(
+\${$this->variableName} {$op} array(
{$output}
);
-# Doxyfile 1.7.6.1
+# Doxyfile 1.8.6
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for MediaWiki.
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
-ALIASES = "type{1}=<b> \1 </b>:" \
- "types{2}=<b> \1 </b> or <b> \2 </b>:" \
- "types{3}=<b> \1 </b>, <b> \2 </b>, or <b> \3 </b>:" \
- "arrayof{2}=<b> Array </b> of \2" \
- "null=\type{Null}" \
- "boolean=\type{Boolean}" \
- "bool=\type{Boolean}" \
- "integer=\type{Integer}" \
- "int=\type{Integer}" \
- "string=\type{String}" \
- "str=\type{String}" \
- "mixed=\type{Mixed}" \
- "access=\par Access:\n" \
- "private=\access private" \
- "protected=\access protected" \
- "public=\access public" \
- "copyright=\note" \
- "license=\note" \
- "codeCoverageIgnore="
+ALIASES = "type{1}=<b> \1 </b>:" \
+ "types{2}=<b> \1 </b> or <b> \2 </b>:" \
+ "types{3}=<b> \1 </b>, <b> \2 </b>, or <b> \3 </b>:" \
+ "arrayof{2}=<b> Array </b> of \2" \
+ "null=\type{Null}" \
+ "boolean=\type{Boolean}" \
+ "bool=\type{Boolean}" \
+ "integer=\type{Integer}" \
+ "int=\type{Integer}" \
+ "string=\type{String}" \
+ "str=\type{String}" \
+ "mixed=\type{Mixed}" \
+ "access=\par Access:\n" \
+ "private=\access private" \
+ "protected=\access protected" \
+ "public=\access public" \
+ "copyright=\note" \
+ "license=\note" \
+ "codeCoverageIgnore="
TCL_SUBST =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
EXTENSION_MAPPING =
+MARKDOWN_SUPPORT = YES
+AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
-SYMBOL_CACHE_SIZE = 0
LOOKUP_CACHE_SIZE = 2
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
+EXTRACT_PACKAGE = NO
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
+SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
-SHOW_DIRECTORIES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = NO
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
+# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
-# configuration options related to the input files
+# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = {{INPUT}}
INPUT_ENCODING = UTF-8
RECURSIVE = YES
EXCLUDE = {{EXCLUDE}}
EXCLUDE_SYMLINKS = YES
-EXCLUDE_PATTERNS = LocalSettings.php AdminSettings.php StartProfiler.php .svn */.git/* {{EXCLUDE_PATTERNS}}
+EXCLUDE_PATTERNS = LocalSettings.php \
+ AdminSettings.php \
+ StartProfiler.php \
+ .svn \
+ */.git/* \
+ {{EXCLUDE_PATTERNS}}
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
+USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
-# configuration options related to source browsing
+# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
REFERENCES_LINK_SOURCE = YES
+SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
+# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
-# configuration options related to the HTML output
+# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
+HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = YES
-HTML_ALIGN_MEMBERS = YES
HTML_DYNAMIC_SECTIONS = NO
+HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
-ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = YES
-USE_INLINE_TREES = YES
+ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
+MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
MATHJAX_EXTENSIONS =
+MATHJAX_CODEFILE =
SEARCHENGINE = YES
SERVER_BASED_SEARCH = YES
+EXTERNAL_SEARCH = NO
+SEARCHENGINE_URL =
+SEARCHDATA_FILE = searchdata.xml
+EXTERNAL_SEARCH_ID =
+EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
+# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
+LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
#---------------------------------------------------------------------------
-# configuration options related to the RTF output
+# Configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
-# configuration options related to the man page output
+# Configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = {{GENERATE_MAN}}
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
-# configuration options related to the XML output
+# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+GENERATE_DOCBOOK = NO
+DOCBOOK_OUTPUT = docbook
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
+# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
-# Configuration::additions related to external references
+# Configuration options related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE = {{OUTPUT_DIRECTORY}}/html/tagfile.xml
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
+EXTERNAL_PAGES = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
MSCGEN_PATH =
+DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = {{HAVE_DOT}}
DOT_NUM_THREADS = 0
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
+UML_LIMIT_NUM_FIELDS = 10
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
+DIAFILE_DIRS =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = YES
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
-
* @todo document
* @ingroup Maintenance
*/
+use \Cdb\Exception as CdbException;
+use \Cdb\Reader as CdbReader;
/** */
require_once __DIR__ . '/commandLine.inc';
// it works only comparing to window.self or window.window (http://stackoverflow.com/q/4850978/319266)
if ( window.top !== window.self ) {
// Un-trap us from framesets
- window.top.location = window.location;
+ window.top.location.href = location.href;
}
}
// Bind onchange event handler and append to form
$html.append(
$( select ).change( function () {
- window.location = QUnit.url( { useskin: $( this ).val() } );
+ location.href = QUnit.url( { useskin: $( this ).val() } );
} )
);
// therefore save and restore scrollTop to prevent jumping.
scrollTop = $( window ).scrollTop();
if ( mode !== 'noHash' ) {
- window.location.hash = '#mw-prefsection-' + name;
+ location.hash = '#mw-prefsection-' + name;
}
$( window ).scrollTop( scrollTop );
// If we've reloaded the page or followed an open-in-new-window,
// make the selected tab visible.
- hash = window.location.hash;
+ hash = location.hash;
if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
}
( document.documentMode === undefined || document.documentMode >= 8 )
) {
$( window ).on( 'hashchange', function () {
- var hash = window.location.hash;
+ var hash = location.hash;
if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
} else if ( hash === '' ) {
* @param {Object|string} [uri] URI string, or an Object with appropriate properties (especially
* another URI object to clone). Object must have non-blank `protocol`, `host`, and `path`
* properties. If omitted (or set to `undefined`, `null` or empty string), then an object
- * will be created for the default `uri` of this constructor (`document.location` for
- * mw.Uri, other values for other instances -- see mw.UriRelative for details).
+ * will be created for the default `uri` of this constructor (`location.href` for mw.Uri,
+ * other values for other instances -- see mw.UriRelative for details).
* @param {Object|boolean} [options] Object with options, or (backwards compatibility) a boolean
* for strictMode
* @param {boolean} [options.strictMode=false] Trigger strict mode parsing of the url.
return Uri;
};
- // If we are running in a browser, inject the current document location (for relative URLs).
- if ( document && document.location && document.location.href ) {
- mw.Uri = mw.UriRelative( document.location.href );
- }
+ // Default to the current browsing location (for relative URLs).
+ mw.Uri = mw.UriRelative( location.href );
}( mediaWiki, jQuery ) );
* Returns null if not found.
*
* @param {string} param The parameter name.
- * @param {string} [url=document.location.href] URL to search through, defaulting to the current document's URL.
+ * @param {string} [url=location.href] URL to search through, defaulting to the current browsing location.
* @return {Mixed} Parameter value or null.
*/
getParamValue: function ( param, url ) {
if ( url === undefined ) {
- url = document.location.href;
+ url = location.href;
}
// Get last match, stop at hash
var re = new RegExp( '^[^#]*[&?]' + $.escapeRE( param ) + '=([^&#]*)' ),
--- /dev/null
+<?php
+/**
+ * @section LICENSE
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+class MWLoggerLegacyLoggerTest extends MediaWikiTestCase {
+
+ /**
+ * @covers MWLoggerLegacyLogger::interpolate
+ * @dataProvider provideInterpolate
+ */
+ public function testInterpolate( $message, $context, $expect ) {
+ $this->assertEquals(
+ $expect, MWLoggerLegacyLogger::interpolate( $message, $context ) );
+ }
+
+ public function provideInterpolate() {
+ return array(
+ array(
+ 'no-op',
+ array(),
+ 'no-op',
+ ),
+ array(
+ 'Hello {world}!',
+ array(
+ 'world' => 'World',
+ ),
+ 'Hello World!',
+ ),
+ array(
+ '{greeting} {user}',
+ array(
+ 'greeting' => 'Goodnight',
+ 'user' => 'Moon',
+ ),
+ 'Goodnight Moon',
+ ),
+ array(
+ 'Oops {key_not_set}',
+ array(),
+ 'Oops {key_not_set}',
+ ),
+ array(
+ '{ not interpolated }',
+ array(
+ 'not interpolated' => 'This should NOT show up in the message',
+ ),
+ '{ not interpolated }',
+ ),
+ );
+ }
+
+}
+++ /dev/null
-<?php
-
-/**
- * Test the CDB reader/writer
- * @covers CdbWriterPHP
- * @covers CdbWriterDBA
- */
-class CdbTest extends MediaWikiTestCase {
-
- protected function setUp() {
- parent::setUp();
- if ( !CdbReader::haveExtension() ) {
- $this->markTestSkipped( 'Native CDB support is not available' );
- }
- }
-
- /**
- * @group medium
- */
- public function testCdb() {
- $dir = wfTempDir();
- if ( !is_writable( $dir ) ) {
- $this->markTestSkipped( "Temp dir isn't writable" );
- }
-
- $phpcdbfile = $this->getNewTempFile();
- $dbacdbfile = $this->getNewTempFile();
-
- $w1 = new CdbWriterPHP( $phpcdbfile );
- $w2 = new CdbWriterDBA( $dbacdbfile );
-
- $data = array();
- for ( $i = 0; $i < 1000; $i++ ) {
- $key = $this->randomString();
- $value = $this->randomString();
- $w1->set( $key, $value );
- $w2->set( $key, $value );
-
- if ( !isset( $data[$key] ) ) {
- $data[$key] = $value;
- }
- }
-
- $w1->close();
- $w2->close();
-
- $this->assertEquals(
- md5_file( $phpcdbfile ),
- md5_file( $dbacdbfile ),
- 'same hash'
- );
-
- $r1 = new CdbReaderPHP( $phpcdbfile );
- $r2 = new CdbReaderDBA( $dbacdbfile );
-
- foreach ( $data as $key => $value ) {
- if ( $key === '' ) {
- // Known bug
- continue;
- }
- $v1 = $r1->get( $key );
- $v2 = $r2->get( $key );
-
- $v1 = $v1 === false ? '(not found)' : $v1;
- $v2 = $v2 === false ? '(not found)' : $v2;
-
- # cdbAssert( 'Mismatch', $key, $v1, $v2 );
- $this->cdbAssert( "PHP error", $key, $v1, $value );
- $this->cdbAssert( "DBA error", $key, $v2, $value );
- }
- }
-
- private function randomString() {
- $len = mt_rand( 0, 10 );
- $s = '';
- for ( $j = 0; $j < $len; $j++ ) {
- $s .= chr( mt_rand( 0, 255 ) );
- }
-
- return $s;
- }
-
- private function cdbAssert( $msg, $key, $v1, $v2 ) {
- $this->assertEquals(
- $v2,
- $v1,
- $msg . ', k=' . bin2hex( $key )
- );
- }
-}