Merge "Pygmentize: Treat Shellbox network loss like non-zero exit code"

This commit is contained in:
jenkins-bot 2023-06-06 23:55:12 +00:00 committed by Gerrit Code Review
commit 81f673bc6d
2 changed files with 99 additions and 10 deletions

View file

@ -22,6 +22,7 @@ namespace MediaWiki\SyntaxHighlight;
use MediaWiki\MediaWikiServices;
use Shellbox\Command\BoxedCommand;
use Shellbox\ShellboxError;
/**
* Wrapper around the `pygmentize` command
@ -291,22 +292,33 @@ class Pygmentize {
foreach ( $options as $k => $v ) {
$optionPairs[] = "{$k}={$v}";
}
$result = self::boxedCommand()
->params(
self::getPath(),
'-l', $lexer,
'-f', 'html',
'-O', implode( ',', $optionPairs ),
'file'
)
->inputFileFromString( 'file', $code )
->execute();
self::recordShellout( 'highlight' );
try {
$result = self::boxedCommand()
->params(
self::getPath(),
'-l', $lexer,
'-f', 'html',
'-O', implode( ',', $optionPairs ),
'file'
)
->inputFileFromString( 'file', $code )
->execute();
} catch ( ShellboxError $exception ) {
// If we have trouble sending or receiving over the network to
// Shellbox, we technically don't know if the command succeed or failed,
// but, treat the highlight() command as recoverable by wrapping this in
// PygmentsException. This permits the Parser tag to fallback to
// plainCodeWrap(), thus avoiding a fatal on pageviews (T292663).
throw new PygmentsException( 'ShellboxError', 0, $exception );
}
$output = $result->getStdout();
if ( $result->getExitCode() != 0 ) {
throw new PygmentsException( $output );
}
return $output;
}

View file

@ -0,0 +1,77 @@
<?php
use MediaWiki\Shell\CommandFactory;
use MediaWiki\SyntaxHighlight\SyntaxHighlight;
use Shellbox\Command\BoxedCommand;
use Shellbox\Command\BoxedResult;
use Shellbox\ShellboxError;
/**
* @covers MediaWiki\SyntaxHighlight\SyntaxHighlight
* @covers MediaWiki\SyntaxHighlight\Pygmentize
*/
class PygmentizeTest extends MediaWikiIntegrationTestCase {
protected function setUp(): void {
parent::setUp();
$this->setMwGlobals( [
// Run with the default useBundled=true
'wgPygmentizePath' => false,
// Silence wfWarn for the expected Shellbox error
'wgDevelopmentWarnings' => false,
] );
}
private function stubShellbox( ?BoxedResult $result, ?Exception $e ) {
$factory = $this->createStub( CommandFactory::class );
$command = new class ( $result, $e ) extends BoxedCommand {
private $result;
private $e;
public function __construct( $result, $e ) {
$this->result = $result;
$this->e = $e;
}
public function execute(): BoxedResult {
if ( $this->e ) {
throw $this->e;
}
return $this->result;
}
};
$factory->method( 'createBoxed' )->willReturn( $command );
$this->setService( 'ShellCommandFactory', $factory );
}
public static function provideHighlight() {
yield 'basic' => [
( new BoxedResult )
->stdout( '<div class="mw-highlight><code>x</code></div>' )
->exitCode( 0 ),
null,
'<div class="mw-highlight mw-highlight-lang-json mw-content-ltr" dir="ltr"><code>x</code></div>'
];
yield 'pre-fallback for non-zero exit' => [
( new BoxedResult )
->stdout( 'Boo' )
->exitCode( 42 ),
null,
'<div class="mw-highlight mw-highlight-lang-json mw-content-ltr" dir="ltr"><pre>"example"</pre></div>'
];
yield 'pre-fallback for network error (T292663)' => [
null,
new ShellboxError( 'Wazaaaa', 0 ),
'<div class="mw-highlight mw-highlight-lang-json mw-content-ltr" dir="ltr"><pre>"example"</pre></div>'
];
}
/**
* @dataProvider provideHighlight
*/
public function testHighlightBasic( ?BoxedResult $result, ?Exception $e, string $expect ) {
$this->stubShellbox( $result, $e );
$status = SyntaxHighlight::highlight( '"example"', 'json' );
$this->assertSame( $expect, $status->getValue() );
}
}