Merge "API: allow disabling TOC in action=parse"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 18 Dec 2013 14:52:19 +0000 (14:52 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 18 Dec 2013 14:52:19 +0000 (14:52 +0000)
12 files changed:
includes/ImagePage.php
includes/filerepo/LocalRepo.php
includes/job/JobQueueFederated.php
includes/media/SVG.php
includes/specials/SpecialBlockList.php
includes/specials/SpecialExpandTemplates.php
languages/messages/MessagesEn.php
languages/messages/MessagesQqq.php
maintenance/language/messages.inc
maintenance/runJobs.php
resources/mediawiki.special/mediawiki.special.css
tests/phpunit/includes/filebackend/FileBackendTest.php

index c73d72c..997a948 100644 (file)
@@ -316,7 +316,12 @@ class ImagePage extends Article {
 
                        $renderLang = $request->getVal( 'lang' );
                        if ( !is_null( $renderLang ) ) {
-                               $params['lang'] = $renderLang;
+                               $handler = $this->displayImg->getHandler();
+                               if ( $handler && $handler->validateParam( 'lang', $renderLang ) ) {
+                                       $params['lang'] = $renderLang;
+                               } else {
+                                       $renderLang = null;
+                               }
                        }
 
                        $width_orig = $this->displayImg->getWidth( $page );
@@ -1002,7 +1007,7 @@ EOT
                if ( !$haveDefaultLang ) {
                        // Its hard to know if the content is really in the default language, or
                        // if its just unmarked content that could be in any language.
-                       $opts = Xml::option( wfMessage( 'img-lang-default' )->text(), '', $defaultLang === $curLang ) . $opts;
+                       $opts = Xml::option( wfMessage( 'img-lang-default' )->text(), $defaultLang, $defaultLang === $curLang ) . $opts;
                }
                if ( !$haveCurrentLang && $defaultLang !== $curLang ) {
                        $name = Language::fetchLanguageName( $curLang, $this->getContext()->getLanguage()->getCode() );
index 2df28bc..c5346aa 100644 (file)
@@ -275,15 +275,26 @@ class LocalRepo extends FileRepo {
                $applyMatchingFiles = function( ResultWrapper $res, &$searchSet, &$finalFiles )
                        use ( $repo, $fileMatchesSearch, $flags )
                {
+                       global $wgContLang;
+                       $info = $repo->getInfo();
                        foreach ( $res as $row ) {
                                $file = $repo->newFileFromRow( $row );
-                               $dbKey = $file->getTitle()->getDBkey();
-                               // There must have been a search for this exact DB Key
-                               if ( $fileMatchesSearch( $file, $searchSet[$dbKey] ) ) {
-                                       $finalFiles[$dbKey] = ( $flags & FileRepo::NAME_AND_TIME_ONLY )
-                                               ? array( 'title' => $dbKey, 'timestamp' => $file->getTimestamp() )
-                                               : $file;
-                                       unset( $searchSet[$dbKey] );
+                               // There must have been a search for this DB key, but this has to handle the
+                               // cases were title capitalization is different on the client and repo wikis.
+                               $dbKeysLook = array( str_replace( ' ', '_', $file->getName() ) );
+                               if ( !empty( $info['initialCapital'] ) ) {
+                                       // Search keys for "hi.png" and "Hi.png" should use the "Hi.png file"
+                                       $dbKeysLook[] = $wgContLang->lcfirst( $file->getName() );
+                               }
+                               foreach ( $dbKeysLook as $dbKey ) {
+                                       if ( isset( $searchSet[$dbKey])
+                                               && $fileMatchesSearch( $file, $searchSet[$dbKey] )
+                                       ) {
+                                               $finalFiles[$dbKey] = ( $flags & FileRepo::NAME_AND_TIME_ONLY )
+                                                       ? array( 'title' => $dbKey, 'timestamp' => $file->getTimestamp() )
+                                                       : $file;
+                                               unset( $searchSet[$dbKey] );
+                                       }
                                }
                        }
                };
index 589bed6..f4caac6 100644 (file)
@@ -150,21 +150,20 @@ class JobQueueFederated extends JobQueue {
                        return false;
                }
 
+               $empty = true;
+               $failed = 0;
                foreach ( $this->partitionQueues as $queue ) {
                        try {
-                               if ( !$queue->doIsEmpty() ) {
-                                       $this->cache->add( $key, 'false', self::CACHE_TTL_LONG );
-
-                                       return false;
-                               }
+                               $empty = $empty && $queue->doIsEmpty();
                        } catch ( JobQueueError $e ) {
+                               ++$failed;
                                MWExceptionHandler::logException( $e );
                        }
                }
+               $this->throwErrorIfAllPartitionsDown( $failed );
 
-               $this->cache->add( $key, 'true', self::CACHE_TTL_LONG );
-
-               return true;
+               $this->cache->add( $key, $empty ? 'true' : 'false', self::CACHE_TTL_LONG );
+               return !$empty;
        }
 
        protected function doGetSize() {
@@ -196,14 +195,16 @@ class JobQueueFederated extends JobQueue {
                        return $count;
                }
 
-               $count = 0;
+               $failed = 0;
                foreach ( $this->partitionQueues as $queue ) {
                        try {
                                $count += $queue->$method();
                        } catch ( JobQueueError $e ) {
+                               ++$failed;
                                MWExceptionHandler::logException( $e );
                        }
                }
+               $this->throwErrorIfAllPartitionsDown( $failed );
 
                $this->cache->set( $key, $count, self::CACHE_TTL_SHORT );
 
@@ -275,7 +276,7 @@ class JobQueueFederated extends JobQueue {
                        } else {
                                $partitionRing = $partitionRing->newWithoutLocation( $partition ); // blacklist
                                if ( !$partitionRing ) {
-                                       throw new JobQueueError( "Could not insert job(s), all partitions are down." );
+                                       throw new JobQueueError( "Could not insert job(s), no partitions available." );
                                }
                                $jobsLeft = array_merge( $jobsLeft, $jobBatch ); // not inserted
                        }
@@ -297,7 +298,7 @@ class JobQueueFederated extends JobQueue {
                        } else {
                                $partitionRing = $partitionRing->newWithoutLocation( $partition ); // blacklist
                                if ( !$partitionRing ) {
-                                       throw new JobQueueError( "Could not insert job(s), all partitions are down." );
+                                       throw new JobQueueError( "Could not insert job(s), no partitions available." );
                                }
                                $jobsLeft = array_merge( $jobsLeft, $jobBatch ); // not inserted
                        }
@@ -316,6 +317,7 @@ class JobQueueFederated extends JobQueue {
 
                $partitionsTry = $this->partitionMap; // (partition => weight)
 
+               $failed = 0;
                while ( count( $partitionsTry ) ) {
                        $partition = ArrayUtils::pickRandom( $partitionsTry );
                        if ( $partition === false ) {
@@ -327,8 +329,9 @@ class JobQueueFederated extends JobQueue {
                        try {
                                $job = $queue->pop();
                        } catch ( JobQueueError $e ) {
-                               $job = false;
+                               ++$failed;
                                MWExceptionHandler::logException( $e );
+                               $job = false;
                        }
                        if ( $job ) {
                                $job->metadata['QueuePartition'] = $partition;
@@ -338,6 +341,7 @@ class JobQueueFederated extends JobQueue {
                                unset( $partitionsTry[$partition] ); // blacklist partition
                        }
                }
+               $this->throwErrorIfAllPartitionsDown( $failed );
 
                $this->cache->set( $key, 'true', JobQueueDB::CACHE_TTL_LONG );
 
@@ -381,25 +385,32 @@ class JobQueueFederated extends JobQueue {
        }
 
        protected function doDelete() {
+               $failed = 0;
                /** @var JobQueue $queue */
                foreach ( $this->partitionQueues as $queue ) {
                        try {
                                $queue->doDelete();
                        } catch ( JobQueueError $e ) {
+                               ++$failed;
                                MWExceptionHandler::logException( $e );
                        }
                }
+               $this->throwErrorIfAllPartitionsDown( $failed );
+               return true;
        }
 
        protected function doWaitForBackups() {
+               $failed = 0;
                /** @var JobQueue $queue */
                foreach ( $this->partitionQueues as $queue ) {
                        try {
                                $queue->waitForBackups();
                        } catch ( JobQueueError $e ) {
+                               ++$failed;
                                MWExceptionHandler::logException( $e );
                        }
                }
+               $this->throwErrorIfAllPartitionsDown( $failed );
        }
 
        protected function doGetPeriodicTasks() {
@@ -463,6 +474,7 @@ class JobQueueFederated extends JobQueue {
        protected function doGetSiblingQueuesWithJobs( array $types ) {
                $result = array();
 
+               $failed = 0;
                /** @var JobQueue $queue */
                foreach ( $this->partitionQueues as $queue ) {
                        try {
@@ -476,16 +488,18 @@ class JobQueueFederated extends JobQueue {
                                        break; // short-circuit
                                }
                        } catch ( JobQueueError $e ) {
+                               ++$failed;
                                MWExceptionHandler::logException( $e );
                        }
                }
+               $this->throwErrorIfAllPartitionsDown( $failed );
 
                return array_values( $result );
        }
 
        protected function doGetSiblingQueueSizes( array $types ) {
                $result = array();
-
+               $failed = 0;
                /** @var JobQueue $queue */
                foreach ( $this->partitionQueues as $queue ) {
                        try {
@@ -498,13 +512,28 @@ class JobQueueFederated extends JobQueue {
                                        return null; // not supported on all partitions; bail
                                }
                        } catch ( JobQueueError $e ) {
+                               ++$failed;
                                MWExceptionHandler::logException( $e );
                        }
                }
+               $this->throwErrorIfAllPartitionsDown( $failed );
 
                return $result;
        }
 
+       /**
+        * Throw an error if no partitions available
+        *
+        * @param int $down The number of up partitions down
+        * @return void
+        * @throws JobQueueError
+        */
+       protected function throwErrorIfAllPartitionsDown( $down ) {
+               if ( $down >= count( $this->partitionQueues ) ) {
+                       throw new JobQueueError( 'No queue partitions available.' );
+               }
+       }
+
        public function setTestingPrefix( $key ) {
                /** @var JobQueue $queue */
                foreach ( $this->partitionQueues as $queue ) {
index ecc4ef8..ce7fcbb 100644 (file)
@@ -432,7 +432,7 @@ class SvgHandler extends ImageHandler {
                        return ( $value > 0 );
                } elseif ( $name == 'lang' ) {
                        // Validate $code
-                       if ( !Language::isValidBuiltinCode( $value ) ) {
+                       if ( $value === '' || !Language::isValidBuiltinCode( $value ) ) {
                                wfDebug( "Invalid user language code\n" );
 
                                return false;
index f1992c0..4e4db11 100644 (file)
@@ -230,7 +230,7 @@ class BlockListPager extends TablePager {
        function getFieldNames() {
                static $headers = null;
 
-               if ( $headers == array() ) {
+               if ( $headers === null ) {
                        $headers = array(
                                'ipb_timestamp' => 'blocklist-timestamp',
                                'ipb_target' => 'blocklist-target',
@@ -455,8 +455,6 @@ class BlockListPager extends TablePager {
 
 /**
  * Items per page dropdown. Essentially a crap workaround for bug 32603.
- *
- * @todo Do not release 1.19 with this.
  */
 class HTMLBlockedUsersItemSelect extends HTMLSelectField {
        /**
index a78133c..24476fe 100644 (file)
@@ -32,6 +32,9 @@ class SpecialExpandTemplates extends SpecialPage {
        /** @var boolean whether or not to show the XML parse tree */
        protected $generateXML;
 
+       /** @var boolean whether or not to show the raw HTML code */
+       protected $generateRawHtml;
+
        /** @var boolean whether or not to remove comments in the expanded wikitext */
        protected $removeComments;
 
@@ -62,6 +65,7 @@ class SpecialExpandTemplates extends SpecialPage {
                }
                $input = $request->getText( 'wpInput' );
                $this->generateXML = $request->getBool( 'wpGenerateXml' );
+               $this->generateRawHtml = $request->getBool( 'wpGenerateRawHtml' );
 
                if ( strlen( $input ) ) {
                        $this->removeComments = $request->getBool( 'wpRemoveComments', false );
@@ -113,7 +117,15 @@ class SpecialExpandTemplates extends SpecialPage {
                        }
 
                        $out->addHTML( $tmp );
-                       $this->showHtmlPreview( $title, $output, $out );
+
+                       $rawhtml = $this->generateHtml( $title, $output );
+
+                       if ( $this->generateRawHtml && strlen( $rawhtml ) > 0 ) {
+                               $out->addHTML( $this->makeOutput( $rawhtml, 'expand_templates_html_output' ) );
+                       }
+
+                       $this->showHtmlPreview( $title, $rawhtml, $out );
+
                }
 
        }
@@ -171,6 +183,12 @@ class SpecialExpandTemplates extends SpecialPage {
                        'generate_xml',
                        $this->generateXML
                ) . '</p>';
+               $form .= '<p>' . Xml::checkLabel(
+                       $this->msg( 'expand_templates_generate_rawhtml' )->text(),
+                       'wpGenerateRawHtml',
+                       'generate_rawhtml',
+                       $this->generateRawHtml
+               ) . '</p>';
                $form .= '<p>' . Xml::submitButton(
                        $this->msg( 'expand_templates_ok' )->text(),
                        array( 'accesskey' => 's' )
@@ -202,28 +220,38 @@ class SpecialExpandTemplates extends SpecialPage {
        }
 
        /**
-        * Render the supplied wiki text and append to the page as a preview
+        * Renders the supplied wikitext as html
         *
         * @param Title $title
         * @param string $text
-        * @param OutputPage $out
+        * @return string
         */
-       private function showHtmlPreview( Title $title, $text, OutputPage $out ) {
+       private function generateHtml( Title $title, $text ) {
                global $wgParser;
 
                $popts = ParserOptions::newFromContext( $this->getContext() );
                $popts->setTargetLanguage( $title->getPageLanguage() );
                $pout = $wgParser->parse( $text, $title, $popts );
-               $lang = $title->getPageViewLanguage();
 
+               return $pout->getText();
+       }
+
+       /**
+        * Wraps the provided html code in a div and outputs it to the page
+        *
+        * @param Title $title
+        * @param string $html
+        * @param OutputPage $out
+        */
+       private function showHtmlPreview( Title $title, $html, OutputPage $out ) {
+               $lang = $title->getPageViewLanguage();
                $out->addHTML( "<h2>" . $this->msg( 'expand_templates_preview' )->escaped() . "</h2>\n" );
                $out->addHTML( Html::openElement( 'div', array(
                        'class' => 'mw-content-' . $lang->getDir(),
                        'dir' => $lang->getDir(),
                        'lang' => $lang->getHtmlCode(),
                ) ) );
-
-               $out->addHTML( $pout->getText() );
+               $out->addHTML( $html );
                $out->addHTML( Html::closeElement( 'div' ) );
        }
 }
index ed69f7e..225aa07 100644 (file)
@@ -5110,19 +5110,21 @@ Otherwise, you can use the easy form below. Your comment will be added to the pa
 'limitreport-expensivefunctioncount-value' => '$1/$2', # only translate this message to other languages if you have to change it
 
 # ExpandTemplates
-'expandtemplates'                  => 'Expand templates',
-'expand_templates_intro'           => 'This special page takes text and expands all templates in it recursively.
+'expandtemplates'                   => 'Expand templates',
+'expand_templates_intro'            => 'This special page takes text and expands all templates in it recursively.
 It also expands supported parser functions like
 <code><nowiki>{{</nowiki>#language:…}}</code> and variables like
 <code><nowiki>{{</nowiki>CURRENTDAY}}</code>.
 In fact, it expands pretty much everything in double-braces.',
-'expand_templates_title'           => 'Context title, for {{FULLPAGENAME}}, etc.:',
-'expand_templates_input'           => 'Input text:',
-'expand_templates_output'          => 'Result',
-'expand_templates_xml_output'      => 'XML output',
-'expand_templates_ok'              => 'OK',
-'expand_templates_remove_comments' => 'Remove comments',
-'expand_templates_remove_nowiki'   => 'Suppress <nowiki> tags in result',
-'expand_templates_generate_xml'    => 'Show XML parse tree',
-'expand_templates_preview'         => 'Preview',
+'expand_templates_title'            => 'Context title, for {{FULLPAGENAME}}, etc.:',
+'expand_templates_input'            => 'Input text:',
+'expand_templates_output'           => 'Result',
+'expand_templates_xml_output'       => 'XML output',
+'expand_templates_html_output'      => 'Raw HTML output',
+'expand_templates_ok'               => 'OK',
+'expand_templates_remove_comments'  => 'Remove comments',
+'expand_templates_remove_nowiki'    => 'Suppress <nowiki> tags in result',
+'expand_templates_generate_xml'     => 'Show XML parse tree',
+'expand_templates_generate_rawhtml' => 'Show raw HTML',
+'expand_templates_preview'          => 'Preview',
 );
index e3e574a..fb260b5 100644 (file)
@@ -10532,6 +10532,7 @@ For more information, see [[mw:Extension:ExpandTemplates]]',
 'expand_templates_input' => '{{Identical|Input text}}',
 'expand_templates_output' => '{{Identical|Result}}',
 'expand_templates_xml_output' => 'Used as HTML <code><nowiki><h2></nowiki></code> heading.',
+'expand_templates_html_output' => 'Used as HTML <code><nowiki><h2></nowiki></code> heading.',
 'expand_templates_ok' => '{{Identical|OK}}',
 'expand_templates_remove_comments' => 'Check box to tell [[mw:Extension:ExpandTemplates]] to not show comments in the expanded template.',
 'expand_templates_remove_nowiki' => "Option on [[Special:Expandtemplates]]
@@ -10553,6 +10554,7 @@ Ticked:
 test
 </pre>",
 'expand_templates_generate_xml' => 'Used as checkbox label.',
+'expand_templates_generate_rawhtml' => 'Used as checkbox label.',
 'expand_templates_preview' => '{{Identical|Preview}}',
 
 );
index aeb9453..4ca74f7 100644 (file)
@@ -3948,10 +3948,12 @@ $wgMessageStructure = array(
                'expand_templates_input',
                'expand_templates_output',
                'expand_templates_xml_output',
+               'expand_templates_html_output',
                'expand_templates_ok',
                'expand_templates_remove_comments',
                'expand_templates_remove_nowiki',
                'expand_templates_generate_xml',
+               'expand_templates_generate_rawhtml',
                'expand_templates_preview',
        ),
 );
index 429edf4..8a4a5ab 100644 (file)
@@ -2,10 +2,6 @@
 /**
  * Run pending jobs.
  *
- * Options:
- *  --maxjobs <num> (default 10000)
- *  --type <job_cmd>
- *
  * 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
index 3cd9739..7b1d416 100644 (file)
@@ -38,7 +38,7 @@ tr.mw-block-hideuser {
 
 /**** Special:BlockList ****/
 table.mw-blocklist span.mw-usertoollinks,
-span.mw-blocklist-actions{
+span.mw-blocklist-actions {
        white-space: nowrap;
        font-size: 90%;
 }
index 072cb7c..13c906f 100644 (file)
@@ -1114,6 +1114,57 @@ class FileBackendTest extends MediaWikiTestCase {
                return $cases;
        }
 
+       /**
+        * @dataProvider provider_testGetFileStat
+        * @covers FileBackend::streamFile
+        */
+       public function testStreamFile( $path, $content, $alreadyExists ) {
+               $this->backend = $this->singleBackend;
+               $this->tearDownFiles();
+               $this->doTestStreamFile( $path, $content, $alreadyExists );
+               $this->tearDownFiles();
+       }
+
+       private function doTestStreamFile( $path, $content ) {
+               $backendName = $this->backendClass();
+
+               // Test doStreamFile() directly to avoid header madness
+               $class = new ReflectionClass( $this->backend );
+               $method = $class->getMethod( 'doStreamFile' );
+               $method->setAccessible( true );
+
+               if ( $content !== null ) {
+                       $this->prepare( array( 'dir' => dirname( $path ) ) );
+                       $status = $this->create( array( 'dst' => $path, 'content' => $content ) );
+                       $this->assertGoodStatus( $status,
+                               "Creation of file at $path succeeded ($backendName)." );
+
+                       ob_start();
+                       $method->invokeArgs( $this->backend, array( array( 'src' => $path ) ) );
+                       $data = ob_get_contents();
+                       ob_end_clean();
+
+                       $this->assertEquals( $content, $data, "Correct content streamed from '$path'" );
+               } else { // 404 case
+                       ob_start();
+                       $method->invokeArgs( $this->backend, array( array( 'src' => $path ) ) );
+                       $data = ob_get_contents();
+                       ob_end_clean();
+
+                       $this->assertEquals( '', $data, "Correct content streamed from '$path' ($backendName)" );
+               }
+       }
+
+       public static function provider_testStreamFile() {
+               $cases = array();
+
+               $base = self::baseStorePath();
+               $cases[] = array( "$base/unittest-cont1/e/b/z/some_file.txt", "some file contents" );
+               $cases[] = array( "$base/unittest-cont1/e/b/some-other_file.txt", null );
+
+               return $cases;
+       }
+
        /**
         * @dataProvider provider_testGetFileContents
         * @covers FileBackend::getFileContents