Merge "Maintenance script to check LESS files for validity"
authorBrion VIBBER <brion@wikimedia.org>
Mon, 30 Sep 2013 17:54:41 +0000 (17:54 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 30 Sep 2013 17:54:41 +0000 (17:54 +0000)
21 files changed:
RELEASE-NOTES-1.22
includes/AutoLoader.php
includes/GlobalFunctions.php
includes/WikiPage.php
includes/api/ApiQuery.php
includes/api/ApiQueryFileRepoInfo.php [new file with mode: 0644]
includes/filebackend/FileBackendStore.php
includes/filebackend/SwiftFileBackend.php
includes/filerepo/FileRepo.php
includes/filerepo/ForeignAPIRepo.php
includes/media/Bitmap.php
includes/media/ImageHandler.php
includes/media/Jpeg.php
includes/media/MediaHandler.php
includes/media/SVG.php
includes/parser/ParserCache.php
includes/specials/SpecialUserlogin.php
includes/upload/UploadBase.php
resources/jquery/jquery.textSelection.js
tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js
thumb.php

index c9bff69..8b94b81 100644 (file)
@@ -232,6 +232,8 @@ production.
    for more details regarding custom functions.
 ** $wgResourceLoaderLESSImportPaths is an array of file system paths. Files
    referenced in LESS '@import' statements are looked up here first.
+* Added meta=filerepoinfo API module for getting information about foreign
+  image repositories, and related ForeignAPIRepo methods getInfo and getApiUrl.
 
 === Bug fixes in 1.22 ===
 * Disable Special:PasswordReset when $wgEnableEmail is false. Previously one
index 7eec763..8d571ad 100644 (file)
@@ -414,6 +414,7 @@ $wgAutoloadLocalClasses = array(
        'ApiQueryQueryPage' => 'includes/api/ApiQueryQueryPage.php',
        'ApiQueryRandom' => 'includes/api/ApiQueryRandom.php',
        'ApiQueryRecentChanges' => 'includes/api/ApiQueryRecentChanges.php',
+       'ApiQueryFileRepoInfo' => 'includes/api/ApiQueryFileRepoInfo.php',
        'ApiQueryRevisions' => 'includes/api/ApiQueryRevisions.php',
        'ApiQuerySearch' => 'includes/api/ApiQuerySearch.php',
        'ApiQuerySiteinfo' => 'includes/api/ApiQuerySiteinfo.php',
index ca0ac68..ba60fd8 100644 (file)
@@ -2782,9 +2782,11 @@ function wfShellExecDisabled() {
  *                 added to the executed command environment.
  * @param array $limits optional array with limits(filesize, memory, time, walltime)
  *                 this overwrites the global wgShellMax* limits.
- * @return string collected stdout as a string (trailing newlines stripped)
+ * @param array $options Array of options. Only one is "duplicateStderr" => true, which
+ *                 Which duplicates stderr to stdout, including errors from limit.sh
+ * @return string collected stdout as a string
  */
-function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array() ) {
+function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array(), $options = array() ) {
        global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime,
                $wgMaxShellWallClockTime, $wgShellCgroup;
 
@@ -2796,6 +2798,8 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array
                        'Unable to run external programs, passthru() is disabled.';
        }
 
+       $includeStderr = isset( $options['duplicateStderr'] ) && $options['duplicateStderr'];
+
        wfInitShellLocale();
 
        $envcmd = '';
@@ -2818,6 +2822,10 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array
        $cmd = $envcmd . $cmd;
 
        if ( php_uname( 's' ) == 'Linux' ) {
+               $stderrDuplication = '';
+               if ( $includeStderr ) {
+                       $stderrDuplication = 'exec 2>&1; ';
+               }
                $time = intval ( isset( $limits['time'] ) ? $limits['time'] : $wgMaxShellTime );
                if ( isset( $limits['walltime'] ) ) {
                        $wallTime = intval( $limits['walltime'] );
@@ -2833,17 +2841,25 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array
                        $cmd = '/bin/bash ' . escapeshellarg( "$IP/includes/limit.sh" ) . ' ' .
                                escapeshellarg( $cmd ) . ' ' .
                                escapeshellarg(
+                                       $stderrDuplication .
                                        "MW_CPU_LIMIT=$time; " .
                                        'MW_CGROUP=' . escapeshellarg( $wgShellCgroup ) . '; ' .
                                        "MW_MEM_LIMIT=$mem; " .
                                        "MW_FILE_SIZE_LIMIT=$filesize; " .
                                        "MW_WALL_CLOCK_LIMIT=$wallTime"
                                );
+               } else {
+                       $cmd .= ' 2>&1';
                }
+       } elseif ( $includeStderr ) {
+               $cmd .= ' 2>&1';
        }
        wfDebug( "wfShellExec: $cmd\n" );
 
-       $retval = 1; // error by default?
+       // Default to an unusual value that shouldn't happen naturally,
+       // so in the unlikely event of a weird php bug, it would be
+       // more obvious what happened.
+       $retval = 200;
        ob_start();
        passthru( $cmd, $retval );
        $output = ob_get_contents();
@@ -2855,6 +2871,24 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array
        return $output;
 }
 
+/**
+ * Execute a shell command, returning both stdout and stderr. Convenience
+ * function, as all the arguments to wfShellExec can become unwieldy.
+ *
+ * @note This also includes errors from limit.sh, e.g. if $wgMaxShellFileSize is exceeded.
+ * @param string $cmd Command line, properly escaped for shell.
+ * @param &$retval null|Mixed optional, will receive the program's exit code.
+ *                 (non-zero is usually failure)
+ * @param array $environ optional environment variables which should be
+ *                 added to the executed command environment.
+ * @param array $limits optional array with limits(filesize, memory, time, walltime)
+ *                 this overwrites the global wgShellMax* limits.
+ * @return string collected stdout and stderr as a string
+ */
+function wfShellExecWithStderr( $cmd, &$retval = null, $environ = array(), $limits = array() ) {
+       return wfShellExec( $cmd, $retval, $environ, $limits, array( 'duplicateStderr' => true ) );
+}
+
 /**
  * Workaround for http://bugs.php.net/bug.php?id=45132
  * escapeshellarg() destroys non-ASCII characters if LANG is not a UTF-8 locale
index 2265aca..048dd68 100644 (file)
@@ -3518,6 +3518,9 @@ class PoolWorkArticleView extends PoolCounterWork {
                        return false;
                }
 
+               // Reduce effects of race conditions for slow parses (bug 46014)
+               $cacheTime = wfTimestampNow();
+
                $time = - microtime( true );
                $this->parserOutput = $content->getParserOutput( $this->page->getTitle(), $this->revid, $this->parserOptions );
                $time += microtime( true );
@@ -3529,7 +3532,8 @@ class PoolWorkArticleView extends PoolCounterWork {
                }
 
                if ( $this->cacheable && $this->parserOutput->isCacheable() ) {
-                       ParserCache::singleton()->save( $this->parserOutput, $this->page, $this->parserOptions );
+                       ParserCache::singleton()->save(
+                               $this->parserOutput, $this->page, $this->parserOptions, $cacheTime );
                }
 
                // Make sure file cache is not used on uncacheable content.
index aafd582..ce59118 100644 (file)
@@ -102,6 +102,7 @@ class ApiQuery extends ApiBase {
                'allmessages' => 'ApiQueryAllMessages',
                'siteinfo' => 'ApiQuerySiteinfo',
                'userinfo' => 'ApiQueryUserInfo',
+               'filerepoinfo' => 'ApiQueryFileRepoInfo',
        );
 
        /**
diff --git a/includes/api/ApiQueryFileRepoInfo.php b/includes/api/ApiQueryFileRepoInfo.php
new file mode 100644 (file)
index 0000000..3a35353
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Copyright © 2013 Mark Holmquist <mtraceur@member.fsf.org>
+ *
+ * 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
+ * @since 1.22
+ */
+
+/**
+ * A query action to return meta information about the foreign file repos
+ * configured on the wiki.
+ *
+ * @ingroup API
+ */
+class ApiQueryFileRepoInfo extends ApiQueryBase {
+
+       public function __construct( $query, $moduleName ) {
+               parent::__construct( $query, $moduleName, 'fri' );
+       }
+
+       protected function getInitialisedRepoGroup() {
+               $repoGroup = RepoGroup::singleton();
+
+               if ( !$repoGroup->reposInitialised ) {
+                       $repoGroup->initialiseRepos();
+               }
+
+               return $repoGroup;
+       }
+
+       public function execute() {
+               $params = $this->extractRequestParams();
+               $props = array_flip( $params['prop'] );
+
+               $repos = array();
+
+               $repoGroup = $this->getInitialisedRepoGroup();
+
+               $repoGroup->forEachForeignRepo( function ( $repo ) use ( &$repos, $props ) {
+                       $repos[] = array_intersect_key( $repo->getInfo(), $props );
+               } );
+
+               $repos[] = array_intersect_key( $repoGroup->localRepo->getInfo(), $props );
+
+               $result = $this->getResult();
+               $result->setIndexedTagName( $repos, 'repo' );
+               $result->addValue( array( 'query' ), 'repos', $repos );
+       }
+
+       public function getCacheMode( $params ) {
+               return 'public';
+       }
+
+       public function getAllowedParams() {
+               $props = $this->getProps();
+
+               return array(
+                       'prop' => array(
+                               ApiBase::PARAM_DFLT => join( '|', $props ),
+                               ApiBase::PARAM_ISMULTI => true,
+                               ApiBase::PARAM_TYPE => $props,
+                       ),
+               );
+       }
+
+       public function getProps() {
+               $props = array();
+               $repoGroup = $this->getInitialisedRepoGroup();
+
+               $repoGroup->forEachForeignRepo( function ( $repo ) use ( &$props ) {
+                       $props = array_merge( $props, array_keys( $repo->getInfo() ) );
+               } );
+
+               return array_values( array_unique( array_merge( $props, array_keys( $repoGroup->localRepo->getInfo() ) ) ) );
+       }
+
+       public function getParamDescription() {
+               $p = $this->getModulePrefix();
+               return array(
+                       'prop' => array(
+                               'Which repository properties to get (there may be more available on some wikis):',
+                               ' apiurl      - URL to the repository API - helpful for getting image info from the host.',
+                               ' name        - The key of the repository - used in e.g. $wgForeignFileRepos and imageinfo return values.',
+                               ' displayname - The human-readable name of the repository wiki.',
+                               ' rooturl     - Root URL for image paths.',
+                               ' local       - Whether that repository is the local one or not.',
+                       ),
+               );
+       }
+
+       public function getDescription() {
+               return 'Return meta information about image repositories configured on the wiki.';
+       }
+
+       public function getExamples() {
+               return array(
+                       'api.php?action=query&meta=filerepoinfo&friprop=apiurl|name|displayname',
+               );
+       }
+}
index e976a7a..8ff383b 100644 (file)
 abstract class FileBackendStore extends FileBackend {
        /** @var BagOStuff */
        protected $memCache;
-       /** @var ProcessCacheLRU */
-       protected $cheapCache; // Map of paths to small (RAM/disk) cache items
-       /** @var ProcessCacheLRU */
-       protected $expensiveCache; // Map of paths to large (RAM/disk) cache items
+       /** @var ProcessCacheLRU Map of paths to small (RAM/disk) cache items */
+       protected $cheapCache;
+       /** @var ProcessCacheLRU Map of paths to large (RAM/disk) cache items */
+       protected $expensiveCache;
 
-       /** @var Array Map of container names to sharding settings */
-       protected $shardViaHashLevels = array(); // (container name => config array)
+       /** @var Array Map of container names to sharding config */
+       protected $shardViaHashLevels = array();
+
+       /** @var callback Method to get the MIME type of files */
+       protected $mimeCallback;
 
        protected $maxFileSize = 4294967296; // integer bytes (4GiB)
 
@@ -54,11 +57,21 @@ abstract class FileBackendStore extends FileBackend {
 
        /**
         * @see FileBackend::__construct()
+        * Additional $config params include:
+        *   - mimeCallback : Callback that takes (storage path, content, file system path) and
+        *                    returns the MIME type of the file or 'unknown/unknown'. The file
+        *                    system path parameter should be used if the content one is null.
         *
         * @param array $config
         */
        public function __construct( array $config ) {
                parent::__construct( $config );
+               $this->mimeCallback = isset( $config['mimeCallback'] )
+                       ? $config['mimeCallback']
+                       : function( $storagePath, $content, $fsPath ) {
+                               // @TODO: handle the case of extension-less files using the contents
+                               return StreamFile::contentTypeFromPath( $storagePath ) ?: 'unknown/unknown';
+                       };
                $this->memCache = new EmptyBagOStuff(); // disabled by default
                $this->cheapCache = new ProcessCacheLRU( self::CACHE_CHEAP_SIZE );
                $this->expensiveCache = new ProcessCacheLRU( self::CACHE_EXPENSIVE_SIZE );
@@ -1583,6 +1596,18 @@ abstract class FileBackendStore extends FileBackend {
                }
                return $opts;
        }
+
+       /**
+        * Get the content type to use in HEAD/GET requests for a file
+        *
+        * @param string $storagePath
+        * @param string|null $content File data
+        * @param string|null $fsPath File system path
+        * @return MIME type
+        */
+       protected function getContentType( $storagePath, $content, $fsPath ) {
+               return call_user_func_array( $this->mimeCallback, func_get_args() );
+       }
 }
 
 /**
index f3aa145..a620f88 100644 (file)
@@ -252,10 +252,7 @@ class SwiftFileBackend extends FileBackendStore {
                        // The MD5 here will be checked within Swift against its own MD5.
                        $obj->set_etag( md5( $params['content'] ) );
                        // Use the same content type as StreamFile for security
-                       $obj->content_type = StreamFile::contentTypeFromPath( $params['dst'] );
-                       if ( !strlen( $obj->content_type ) ) { // special case
-                               $obj->content_type = 'unknown/unknown';
-                       }
+                       $obj->content_type = $this->getContentType( $params['dst'], $params['content'], null );
                        // Set any other custom headers if requested
                        if ( isset( $params['headers'] ) ) {
                                $obj->headers += $this->sanitizeHdrs( $params['headers'] );
@@ -329,10 +326,7 @@ class SwiftFileBackend extends FileBackendStore {
                        // The MD5 here will be checked within Swift against its own MD5.
                        $obj->set_etag( md5_file( $params['src'] ) );
                        // Use the same content type as StreamFile for security
-                       $obj->content_type = StreamFile::contentTypeFromPath( $params['dst'] );
-                       if ( !strlen( $obj->content_type ) ) { // special case
-                               $obj->content_type = 'unknown/unknown';
-                       }
+                       $obj->content_type = $this->getContentType( $params['dst'], null, $params['src'] );
                        // Set any other custom headers if requested
                        if ( isset( $params['headers'] ) ) {
                                $obj->headers += $this->sanitizeHdrs( $params['headers'] );
index bc1ad91..1195d5f 100644 (file)
@@ -1716,6 +1716,22 @@ class FileRepo {
         * @throws MWException
         */
        protected function assertWritableRepo() {}
+
+
+       /**
+        * Return information about the repository.
+        *
+        * @return array
+        * @since 1.22
+        */
+       public function getInfo() {
+               return array(
+                       'name' => $this->getName(),
+                       'displayname' => $this->getDisplayName(),
+                       'rootUrl' => $this->getRootUrl(),
+                       'local' => $this->isLocal(),
+               );
+       }
 }
 
 /**
index 128412c..02d83bb 100644 (file)
@@ -80,6 +80,14 @@ class ForeignAPIRepo extends FileRepo {
                }
        }
 
+       /**
+        * @return string
+        * @since 1.22
+        */
+       function getApiUrl() {
+               return $this->mApiBase;
+       }
+
        /**
         * Per docs in FileRepo, this needs to return false if we don't support versioned
         * files. Well, we don't.
@@ -416,6 +424,18 @@ class ForeignAPIRepo extends FileRepo {
                return Http::userAgent() . " ForeignAPIRepo/" . self::VERSION;
        }
 
+       /**
+        * Get information about the repo - overrides/extends the parent
+        * class's information.
+        * @return array
+        * @since 1.22
+        */
+       function getInfo() {
+               $info = parent::getInfo();
+               $info['apiurl'] = $this->getApiUrl();
+               return $info;
+       }
+
        /**
         * Like a Http:get request, but with custom User-Agent.
         * @see Http:get
index 9f7a09c..e2444a1 100644 (file)
@@ -99,17 +99,6 @@ class BitmapHandler extends ImageHandler {
                return array( $width, $height );
        }
 
-       /**
-        * Function that returns the number of pixels to be thumbnailed.
-        * Intended for animated GIFs to multiply by the number of frames.
-        *
-        * @param File $image
-        * @return int
-        */
-       function getImageArea( $image ) {
-               return $image->getWidth() * $image->getHeight();
-       }
-
        /**
         * @param $image File
         * @param  $dstPath
@@ -357,12 +346,12 @@ class BitmapHandler extends ImageHandler {
                        " -depth 8 $sharpen " .
                        " -rotate -$rotation " .
                        " {$animation_post} " .
-                       wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) ) . " 2>&1";
+                       wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) );
 
                wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
                wfProfileIn( 'convert' );
                $retval = 0;
-               $err = wfShellExec( $cmd, $retval, $env );
+               $err = wfShellExecWithStderr( $cmd, $retval, $env );
                wfProfileOut( 'convert' );
 
                if ( $retval !== 0 ) {
@@ -472,7 +461,7 @@ class BitmapHandler extends ImageHandler {
                wfDebug( __METHOD__ . ": Running custom convert command $cmd\n" );
                wfProfileIn( 'convert' );
                $retval = 0;
-               $err = wfShellExec( $cmd, $retval );
+               $err = wfShellExecWithStderr( $cmd, $retval );
                wfProfileOut( 'convert' );
 
                if ( $retval !== 0 ) {
@@ -712,24 +701,6 @@ class BitmapHandler extends ImageHandler {
                imagejpeg( $dst_image, $thumbPath, 95 );
        }
 
-       /**
-        * On supporting image formats, try to read out the low-level orientation
-        * of the file and return the angle that the file needs to be rotated to
-        * be viewed.
-        *
-        * This information is only useful when manipulating the original file;
-        * the width and height we normally work with is logical, and will match
-        * any produced output views.
-        *
-        * The base BitmapHandler doesn't understand any metadata formats, so this
-        * is left up to child classes to implement.
-        *
-        * @param $file File
-        * @return int 0, 90, 180 or 270
-        */
-       public function getRotation( $file ) {
-               return 0;
-       }
 
        /**
         * Returns whether the current scaler supports rotation (im and gd do)
@@ -774,11 +745,11 @@ class BitmapHandler extends ImageHandler {
                                $cmd = wfEscapeShellArg( $wgImageMagickConvertCommand ) . " " .
                                        wfEscapeShellArg( $this->escapeMagickInput( $params['srcPath'], $scene ) ) .
                                        " -rotate -$rotation " .
-                                       wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) ) . " 2>&1";
+                                       wfEscapeShellArg( $this->escapeMagickOutput( $params['dstPath'] ) );
                                wfDebug( __METHOD__ . ": running ImageMagick: $cmd\n" );
                                wfProfileIn( 'convert' );
                                $retval = 0;
-                               $err = wfShellExec( $cmd, $retval, $env );
+                               $err = wfShellExecWithStderr( $cmd, $retval, $env );
                                wfProfileOut( 'convert' );
                                if ( $retval !== 0 ) {
                                        $this->logErrorForExternalProcess( $retval, $err, $cmd );
index 8e46f2f..e079003 100644 (file)
@@ -200,6 +200,19 @@ abstract class ImageHandler extends MediaHandler {
                wfRestoreWarnings();
                return $gis;
        }
+       /**
+        * Function that returns the number of pixels to be thumbnailed.
+        * Intended for animated GIFs to multiply by the number of frames.
+        *
+        * If the file doesn't support a notion of "area" return 0.
+        *
+        * @param File $image
+        * @return int
+        */
+       function getImageArea( $image ) {
+               return $image->getWidth() * $image->getHeight();
+       }
+
 
        /**
         * @param $file File
index 1feb378..fa76366 100644 (file)
@@ -75,11 +75,11 @@ class JpegHandler extends ExifBitmapHandler {
                        $cmd = wfEscapeShellArg( $wgJpegTran ) .
                                " -rotate " . wfEscapeShellArg( $rotation ) .
                                " -outfile " . wfEscapeShellArg( $params['dstPath'] ) .
-                               " " . wfEscapeShellArg( $params['srcPath'] ) . " 2>&1";
+                               " " . wfEscapeShellArg( $params['srcPath'] );
                        wfDebug( __METHOD__ . ": running jpgtran: $cmd\n" );
                        wfProfileIn( 'jpegtran' );
                        $retval = 0;
-                       $err = wfShellExec( $cmd, $retval, $env );
+                       $err = wfShellExecWithStderr( $cmd, $retval, $env );
                        wfProfileOut( 'jpegtran' );
                        if ( $retval !== 0 ) {
                                $this->logErrorForExternalProcess( $retval, $err, $cmd );
index 2e8d41d..8ec2e9a 100644 (file)
@@ -643,4 +643,23 @@ abstract class MediaHandler {
        public static function canRotate() {
                return false;
        }
+
+       /**
+        * On supporting image formats, try to read out the low-level orientation
+        * of the file and return the angle that the file needs to be rotated to
+        * be viewed.
+        *
+        * This information is only useful when manipulating the original file;
+        * the width and height we normally work with is logical, and will match
+        * any produced output views.
+        *
+        * For files we don't know, we return 0.
+        *
+        * @param $file File
+        * @return int 0, 90, 180 or 270
+        */
+       public function getRotation( $file ) {
+               return 0;
+       }
+
 }
index 4c055a5..72a9696 100644 (file)
@@ -177,7 +177,7 @@ class SvgHandler extends ImageHandler {
                                                wfEscapeShellArg( $srcPath ),
                                                wfEscapeShellArg( $dstPath ) ),
                                        $wgSVGConverters[$wgSVGConverter]
-                               ) . " 2>&1";
+                               );
 
                                $env = array();
                                if ( $lang !== false ) {
@@ -186,7 +186,7 @@ class SvgHandler extends ImageHandler {
 
                                wfProfileIn( 'rsvg' );
                                wfDebug( __METHOD__ . ": $cmd\n" );
-                               $err = wfShellExec( $cmd, $retval, $env );
+                               $err = wfShellExecWithStderr( $cmd, $retval, $env );
                                wfProfileOut( 'rsvg' );
                        }
                }
index 7c5eeb4..7053f13 100644 (file)
@@ -223,19 +223,19 @@ class ParserCache {
         * @param $parserOutput ParserOutput
         * @param $article Article
         * @param $popts ParserOptions
+        * @param $cacheTime Time when the cache was generated
         */
-       public function save( $parserOutput, $article, $popts ) {
+       public function save( $parserOutput, $article, $popts, $cacheTime = null ) {
                $expire = $parserOutput->getCacheExpiry();
-
                if ( $expire > 0 ) {
-                       $now = wfTimestampNow();
+                       $cacheTime = $cacheTime ?: wfTimestampNow();
 
                        $optionsKey = new CacheTime;
                        $optionsKey->mUsedOptions = $parserOutput->getUsedOptions();
                        $optionsKey->updateCacheExpiry( $expire );
 
-                       $optionsKey->setCacheTime( $now );
-                       $parserOutput->setCacheTime( $now );
+                       $optionsKey->setCacheTime( $cacheTime );
+                       $parserOutput->setCacheTime( $cacheTime );
 
                        $optionsKey->setContainsOldMagic( $parserOutput->containsOldMagic() );
 
@@ -245,8 +245,8 @@ class ParserCache {
                        // Save the timestamp so that we don't have to load the revision row on view
                        $parserOutput->setTimestamp( $article->getTimestamp() );
 
-                       $parserOutput->mText .= "\n<!-- Saved in parser cache with key $parserOutputKey and timestamp $now -->\n";
-                       wfDebug( "Saved in parser cache with key $parserOutputKey and timestamp $now\n" );
+                       $parserOutput->mText .= "\n<!-- Saved in parser cache with key $parserOutputKey and timestamp $cacheTime\n -->\n";
+                       wfDebug( "Saved in parser cache with key $parserOutputKey and timestamp $cacheTime\n" );
 
                        // Save the parser output
                        $this->mMemc->set( $parserOutputKey, $parserOutput, $expire );
index 48bef9d..a68efc4 100644 (file)
@@ -168,10 +168,7 @@ class LoginForm extends SpecialPage {
 
                // If logging in and not on HTTPS, either redirect to it or offer a link.
                global $wgSecureLogin;
-               if (
-                       $this->mType !== 'signup' &&
-                       WebRequest::detectProtocol() !== 'https'
-               ) {
+               if ( WebRequest::detectProtocol() !== 'https' ) {
                        $title = $this->getFullTitle();
                        $query = array(
                                'returnto' => $this->mReturnTo,
index 4b8a562..2260241 100644 (file)
@@ -1324,7 +1324,7 @@ abstract class UploadBase {
                # NOTE: there's a 50 line workaround to make stderr redirection work on windows, too.
                #      that does not seem to be worth the pain.
                #      Ask me (Duesentrieb) about it if it's ever needed.
-               $output = wfShellExec( "$command 2>&1", $exitCode );
+               $output = wfShellExecWithStderr( $command, $exitCode );
 
                # map exit code to AV_xxx constants.
                $mappedCode = $exitCode;
index c44816b..2b5a440 100644 (file)
                                                postFinished = false;
                                                periRange = document.selection.createRange().duplicate();
 
-                                               preRange = rangeForElementIE( e ),
+                                               preRange = rangeForElementIE( e );
                                                // Move the end where we need it
                                                preRange.setEndPoint( 'EndToStart', periRange );
 
index f2676d7..08adb93 100644 (file)
@@ -95,8 +95,8 @@
                        '</div>' +
                        '<ul><li></li></ul>' +
                        '</div>';
-               $( tocHtml ).appendTo( '#qunit-fixture' ),
-                       $toggleLink = $( '#togglelink' );
+               $( tocHtml ).appendTo( '#qunit-fixture' );
+               $toggleLink = $( '#togglelink' );
 
                assert.strictEqual( $toggleLink.length, 1, 'Toggle link is appended to the page.' );
 
index 2cda344..d2976f2 100644 (file)
--- a/thumb.php
+++ b/thumb.php
@@ -387,6 +387,7 @@ function wfThumbError( $status, $msg ) {
                header( 'HTTP/1.1 500 Internal server error' );
        }
        if ( $wgShowHostnames ) {
+               header( 'X-MW-Thumbnail-Renderer: ' . wfHostname() );
                $url = htmlspecialchars( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '' );
                $hostname = htmlspecialchars( wfHostname() );
                $debug = "<!-- $url -->\n<!-- $hostname -->\n";