Drop symfony/process dependency, use Shell\Command instead

We originally started using symfony/process because kzykhys/pygments
depended upon it. But that library was unmaintained and became broken,
so we stopped using it, and just used symfony/process directly.

At the time, the main reason in favor of symfony/process was that it
could pass stdin to pygments, while Shell\Command couldn't - but it can
now (T182463)! On top of that, there are downsides, like not respecting
the default MediaWiki shell limits, being incompatible with core's
firejail support, and requiring an external composer dependency.

Note that because Shell::command() will enforce MediaWiki's normal
limits, it's possible that some large pages may no longer render with
syntax highlighting if they pass those limits.

Bug: T182467
Bug: T181771
Change-Id: Ie1cb72b7eb17d943f79ecae4d94a2110546ef039
This commit is contained in:
Kunal Mehta 2017-12-08 12:57:08 -08:00
parent 578bb79921
commit 15b894bdbc
6 changed files with 31 additions and 53 deletions

5
README
View file

@ -14,10 +14,7 @@ with earlier versions of MediaWiki, visit:
== Installation == == Installation ==
First, you will need to ensure that this extension's Composer-managed Add this line to your LocalSettings.php:
dependencies are available. In the extension directory, run 'composer update'.
Next, Add this line to your LocalSettings.php:
wfLoadExtension( 'SyntaxHighlight_GeSHi' ); wfLoadExtension( 'SyntaxHighlight_GeSHi' );

View file

@ -17,7 +17,6 @@
*/ */
use MediaWiki\Shell\Shell; use MediaWiki\Shell\Shell;
use Symfony\Component\Process\ProcessBuilder;
class SyntaxHighlight { class SyntaxHighlight {
@ -288,32 +287,23 @@ class SyntaxHighlight {
foreach ( $options as $k => $v ) { foreach ( $options as $k => $v ) {
$optionPairs[] = "{$k}={$v}"; $optionPairs[] = "{$k}={$v}";
} }
$builder = new ProcessBuilder(); $result = Shell::command(
$builder->setPrefix( self::getPygmentizePath() ); self::getPygmentizePath(),
$process = $builder '-l', $lexer,
->add( '-l' )->add( $lexer ) '-f', 'html',
->add( '-f' )->add( 'html' ) '-O', implode( ',', $optionPairs )
->add( '-O' )->add( implode( ',', $optionPairs ) ) )
->getProcess(); ->input( $code )
->execute();
$process->setInput( $code ); if ( $result->getExitCode() != 0 ) {
/* Workaround for T151523 (buggy $process->getOutput()).
If/when this issue is fixed in HHVM or Symfony,
replace this with "$process->run(); $output = $process->getOutput();"
*/
$output = '';
$process->run( function ( $type, $capturedOutput ) use ( &$output ) {
$output .= $capturedOutput;
} );
if ( !$process->isSuccessful() ) {
$status->warning( 'syntaxhighlight-error-pygments-invocation-failure' ); $status->warning( 'syntaxhighlight-error-pygments-invocation-failure' );
wfWarn( 'Failed to invoke Pygments: ' . $process->getErrorOutput() ); wfWarn( 'Failed to invoke Pygments: ' . $result->getStderr() );
$status->value = self::highlight( $code, null, $args )->getValue(); $status->value = self::highlight( $code, null, $args )->getValue();
return $status; return $status;
} }
$output = $result->getStdout();
$cache->set( $cacheKey, $output ); $cache->set( $cacheKey, $output );
} }

View file

@ -1,9 +1,6 @@
{ {
"name": "mediawiki/syntax-highlight", "name": "mediawiki/syntax-highlight",
"description": "Syntax highlighting extension for MediaWiki", "description": "Syntax highlighting extension for MediaWiki",
"require": {
"symfony/process": "~3.3"
},
"require-dev": { "require-dev": {
"jakub-onderka/php-parallel-lint": "0.9.2", "jakub-onderka/php-parallel-lint": "0.9.2",
"mediawiki/mediawiki-codesniffer": "15.0.0", "mediawiki/mediawiki-codesniffer": "15.0.0",

View file

@ -14,7 +14,7 @@
"license-name": "GPL-2.0+", "license-name": "GPL-2.0+",
"type": "parserhook", "type": "parserhook",
"requires": { "requires": {
"MediaWiki": ">= 1.27" "MediaWiki": ">= 1.31"
}, },
"MessagesDirs": { "MessagesDirs": {
"SyntaxHighlight_GeSHi": [ "SyntaxHighlight_GeSHi": [
@ -77,6 +77,5 @@
"ParserTestFiles": [ "ParserTestFiles": [
"tests/parserTests.txt" "tests/parserTests.txt"
], ],
"load_composer_autoloader": true,
"manifest_version": 1 "manifest_version": 1
} }

View file

@ -22,7 +22,7 @@
* @ingroup Maintenance * @ingroup Maintenance
*/ */
use Symfony\Component\Process\ProcessBuilder; use MediaWiki\Shell\Shell;
$IP = getenv( 'MW_INSTALL_PATH' ) ?: __DIR__ . '/../../..'; $IP = getenv( 'MW_INSTALL_PATH' ) ?: __DIR__ . '/../../..';
@ -39,22 +39,18 @@ class UpdateCSS extends Maintenance {
$target = __DIR__ . '/../modules/pygments.generated.css'; $target = __DIR__ . '/../modules/pygments.generated.css';
$css = "/* Stylesheet generated by updateCSS.php */\n"; $css = "/* Stylesheet generated by updateCSS.php */\n";
$builder = new ProcessBuilder(); $result = Shell::command(
$builder->setPrefix( SyntaxHighlight::getPygmentizePath() ); SyntaxHighlight::getPygmentizePath(),
'-f', 'html',
'-S', 'default',
'-a', '.' . SyntaxHighlight::HIGHLIGHT_CSS_CLASS
)->execute();
$process = $builder if ( $result->getExitCode() != 0 ) {
->add( '-f' )->add( 'html' ) throw new \RuntimeException( $result->getStderr() );
->add( '-S' )->add( 'default' )
->add( '-a' )->add( '.' . SyntaxHighlight::HIGHLIGHT_CSS_CLASS )
->getProcess();
$process->run();
if ( !$process->isSuccessful() ) {
throw new \RuntimeException( $process->getErrorOutput() );
} }
$css .= $process->getOutput(); $css .= $result->getStdout();
if ( file_put_contents( $target, $css ) === false ) { if ( file_put_contents( $target, $css ) === false ) {
$this->output( "Failed to write to {$target}\n" ); $this->output( "Failed to write to {$target}\n" );

View file

@ -22,7 +22,7 @@
* @ingroup Maintenance * @ingroup Maintenance
*/ */
use Symfony\Component\Process\ProcessBuilder; use MediaWiki\Shell\Shell;
$IP = getenv( 'MW_INSTALL_PATH' ) ?: __DIR__ . '/../../..'; $IP = getenv( 'MW_INSTALL_PATH' ) ?: __DIR__ . '/../../..';
@ -43,17 +43,16 @@ class UpdateLexerList extends Maintenance {
$lexers = []; $lexers = [];
$builder = new ProcessBuilder(); $result = Shell::command(
$builder->setPrefix( SyntaxHighlight::getPygmentizePath() ); SyntaxHighlight::getPygmentizePath(),
'-L', 'lexer'
)->execute();
$process = $builder->add( '-L' )->add( 'lexer' )->getProcess(); if ( $result->getExitCode() != 0 ) {
$process->run(); throw new \RuntimeException( $result->getStderr() );
if ( !$process->isSuccessful() ) {
throw new \RuntimeException( $process->getErrorOutput() );
} }
$output = $process->getOutput(); $output = $result->getStdout();
foreach ( explode( "\n", $output ) as $line ) { foreach ( explode( "\n", $output ) as $line ) {
if ( substr( $line, 0, 1 ) === '*' ) { if ( substr( $line, 0, 1 ) === '*' ) {
$newLexers = explode( ', ', trim( $line, "* :\n" ) ); $newLexers = explode( ', ', trim( $line, "* :\n" ) );