Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
76.67% covered (warning)
76.67%
23 / 30
50.00% covered (danger)
50.00%
3 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ExternalTextDiffer
76.67% covered (warning)
76.67%
23 / 30
50.00% covered (danger)
50.00%
3 / 6
10.03
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFormats
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFormatContext
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doRenderBatch
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 doRender
80.00% covered (warning)
80.00%
20 / 25
0.00% covered (danger)
0.00%
0 / 1
4.13
1<?php
2
3namespace MediaWiki\Diff\TextDiffer;
4
5use MediaWiki\Shell\Shell;
6use RuntimeException;
7
8/**
9 * @since 1.41
10 */
11class ExternalTextDiffer extends BaseTextDiffer {
12    /** @var string */
13    private $externalPath;
14
15    /**
16     * @param string $externalPath The path to the executable file which provides the diff
17     */
18    public function __construct( $externalPath ) {
19        $this->externalPath = $externalPath;
20    }
21
22    public function getName(): string {
23        return 'external';
24    }
25
26    public function getFormats(): array {
27        return [ 'external' ];
28    }
29
30    public function getFormatContext( string $format ) {
31        return self::CONTEXT_ROW;
32    }
33
34    protected function doRenderBatch( string $oldText, string $newText, array $formats ): array {
35        return [ 'external' => $this->doRender( $oldText, $newText ) ];
36    }
37
38    /**
39     * @param string $oldText
40     * @param string $newText
41     * @return string
42     */
43    private function doRender( $oldText, $newText ) {
44        $tmpDir = wfTempDir();
45        $tempName1 = tempnam( $tmpDir, 'diff_' );
46        $tempName2 = tempnam( $tmpDir, 'diff_' );
47
48        $tempFile1 = fopen( $tempName1, "w" );
49        if ( !$tempFile1 ) {
50            throw new RuntimeException( "Could not create temporary file $tempName1 for external diffing" );
51        }
52        $tempFile2 = fopen( $tempName2, "w" );
53        if ( !$tempFile2 ) {
54            throw new RuntimeException( "Could not create temporary file $tempName2 for external diffing" );
55        }
56        fwrite( $tempFile1, $oldText );
57        fwrite( $tempFile2, $newText );
58        fclose( $tempFile1 );
59        fclose( $tempFile2 );
60        $cmd = [ $this->externalPath, $tempName1, $tempName2 ];
61        $result = Shell::command( $cmd )
62            ->execute();
63        $exitCode = $result->getExitCode();
64        if ( $exitCode !== 0 ) {
65            throw new RuntimeException( "External diff command returned code {$exitCode}. Stderr: "
66                . wfEscapeWikiText( $result->getStderr() )
67            );
68        }
69        $diffText = $result->getStdout();
70        unlink( $tempName1 );
71        unlink( $tempName2 );
72
73        return $diffText;
74    }
75}