Index: trunk/extensions/Score/Score.i18n.php |
— | — | @@ -27,35 +27,50 @@ |
28 | 28 | |
29 | 29 | /* English */ |
30 | 30 | $messages['en'] = array( |
| 31 | + 'score-abc2lynotexecutable' => 'ABC to LilyPond converter could not be executed.', |
| 32 | + 'score-abcconversionerr' => 'Unable to convert ABC file to LilyPond format: |
| 33 | +$1', |
| 34 | + 'score-noabcinput' => 'ABC source file could not be created', |
31 | 35 | 'score-chdirerr' => 'Unable to change directory', |
32 | 36 | 'score-cleanerr' => 'Unable to clean out old files before re-rendering', |
33 | 37 | 'score-compilererr' => 'Unable to compile LilyPond input file: |
34 | 38 | $1', |
35 | 39 | 'score-desc' => 'Adds a tag for rendering musical scores with LilyPond', |
36 | 40 | 'score-getcwderr' => 'Unable to obtain current working directory', |
| 41 | + 'score-invalidlang' => 'Invalid score language specified. Currently recognised languages are lang="lilypond" (the default) and lang="ABC".', |
37 | 42 | 'score-nooutput' => 'Failed to create LilyPond image directory', |
38 | 43 | 'score-nofactory' => 'Failed to create LilyPond factory directory', |
39 | 44 | 'score-noinput' => 'Failed to create LilyPond input file', |
| 45 | + 'score-notexecutable' => 'Could not execute LilyPond. Make sure <code>$wgLilyPond</code> is set correctly.', |
40 | 46 | 'score-page' => 'Page $1', |
| 47 | + 'score-pregreplaceerr' => 'PCRE regular expression replacement failed', |
| 48 | + 'score-readerr' => 'Unable to read file', |
41 | 49 | 'score-renameerr' => 'Error moving score files to upload directory', |
42 | 50 | 'score-trimerr' => 'Image could not be trimmed. Set $wgScoreTrim=false if this problem persists.', |
43 | | - 'score-notexecutable' => 'Could not execute LilyPond. Make sure <code>$wgLilyPond</code> is set correctly.', |
| 51 | + 'score-versionerr' => 'Unable to obtain LilyPond version.', |
44 | 52 | ); |
45 | 53 | |
46 | 54 | /** Message documentation (Message documentation) */ |
47 | 55 | $messages['qqq'] = array( |
| 56 | + 'score-abc2lynotexecutable' => 'Displayed if the ABC to LilyPond converter could not be executed.', |
| 57 | + 'score-abcconversionerr' => 'Displayed if the ABC to LilyPond conversion failed. $1 is the error (generally big block of text in a pre tag)', |
| 58 | + 'score-noabcinput' => 'Displayed if an ABC source file could not be created for lang="ABC".', |
48 | 59 | 'score-chdirerr' => 'Displayed if the extension cannot change its working directory.', |
49 | 60 | 'score-cleanerr' => 'Displayed if an old file cleanup operation fails.', |
50 | 61 | 'score-compilererr' => 'Displayed if the LilyPond code could not be compiled. $1 is the error (generally big block of text in a pre tag)', |
51 | 62 | 'score-desc' => '{{desc}}', |
52 | 63 | 'score-getcwderr' => 'Displayed if the extension cannot obtain the CWD.', |
| 64 | + 'score-invalidlang' => 'Displayed if the lang="…" attribute contains an unrecognised score language.', |
53 | 65 | 'score-nooutput' => 'Displayed if the LilyPond image/midi dir cannot be created.', |
54 | 66 | 'score-nofactory' => 'Displayed if the LilyPond/ImageMagick working directory cannot be created.', |
55 | 67 | 'score-noinput' => 'Displayed if the LilyPond input file cannot be created.', |
| 68 | + 'score-notexecutable' => 'Displayed if LilyPond binary can\'t be executed.', |
56 | 69 | 'score-page' => 'The word "Page" as used in pagination. $1 is the page number', |
| 70 | + 'score-pregreplaceerr' => 'Displayed if a PCRE regular expression replacement failed.', |
| 71 | + 'score-readerr' => 'Displayed if the extension could not read a file', |
57 | 72 | 'score-renameerr' => 'Displayed if moving the resultant files from the working environment to the upload directory fails.', |
58 | 73 | 'score-trimerr' => 'Displayed if the extension failed to trim an output image.', |
59 | | - 'score-notexecutable' => "Displayed if LilyPond binary can't be executed.", |
| 74 | + 'score-versionerr' => 'Displayed if the extension failed to obtain the version string of LilyPond.', |
60 | 75 | ); |
61 | 76 | |
62 | 77 | /** German (Deutsch) |
Index: trunk/extensions/Score/Score.php |
— | — | @@ -47,6 +47,8 @@ |
48 | 48 | $wgScoreTrim = null; |
49 | 49 | /* Path of lilypond executable */ |
50 | 50 | $wgLilyPond = '/usr/bin/lilypond'; |
| 51 | +/* Path to converter from ABC */ |
| 52 | +$wgAbc2Ly = '/usr/bin/abc2ly'; |
51 | 53 | |
52 | 54 | /* |
53 | 55 | * Extension credits |
Index: trunk/extensions/Score/README |
— | — | @@ -26,6 +26,8 @@ |
27 | 27 | |
28 | 28 | require_once("$IP/extensions/Score/Score.php"); |
29 | 29 | $wgLilyPond = '/path/to/your/lilypond/executable'; /* required */ |
| 30 | + $wgAbc2Ly = '/path/to/your/abc2ly/executable'; /* if you want ABC to |
| 31 | + LilyPond conversion */ |
30 | 32 | $wgScoreTrim = true; /* Set to false if you don't want score trimming */ |
31 | 33 | |
32 | 34 | to your LocalSettings.php file. If you get unexpected out-of-memory errors, |
— | — | @@ -58,3 +60,22 @@ |
59 | 61 | You may also combine the "raw" and "midi" attributes, but remember that in |
60 | 62 | this case, you need to provide the necessary \midi block yourself. |
61 | 63 | |
| 64 | +The extension also supports the ABC music notation through LilyPond's abc2ly |
| 65 | +converter (see the documentation for $wgAbc2Ly above). Use |
| 66 | + |
| 67 | +<score lang="ABC">…</score> |
| 68 | + |
| 69 | +to write music in ABC, for example |
| 70 | + |
| 71 | +<score lang="ABC" midi="1"> |
| 72 | +X:1 |
| 73 | +M:C |
| 74 | +L:1/4 |
| 75 | +K:C |
| 76 | +C, D, E, F,|G, A, B, C|D E F G|A B c d|e f g a|b c' d' e'|f' g' a' b'|] |
| 77 | +</score> |
| 78 | + |
| 79 | +As you can see, you may combine the lang attribute with the midi attribute. |
| 80 | +The raw attribute will be ignored if lang is specified to be anything else than |
| 81 | +"lilypond". |
| 82 | + |
Index: trunk/extensions/Score/Score.body.php |
— | — | @@ -27,8 +27,8 @@ |
28 | 28 | die( "This file cannot be run standalone.\n" ); |
29 | 29 | } |
30 | 30 | |
31 | | -/* |
32 | | - * Score ecxceptions |
| 31 | +/** |
| 32 | + * Score exception |
33 | 33 | */ |
34 | 34 | class ScoreException extends Exception { |
35 | 35 | /** |
— | — | @@ -37,47 +37,192 @@ |
38 | 38 | public function __construct( $message, $code = 0, Exception $previous = null ) { |
39 | 39 | parent::__construct( $message, $code, $previous ); |
40 | 40 | } |
| 41 | + |
| 42 | + /** |
| 43 | + * Auto-renders exception as HTML error message in the wiki's content |
| 44 | + * language. |
| 45 | + * |
| 46 | + * @return error message HTML. |
| 47 | + */ |
| 48 | + public function __toString() { |
| 49 | + return Html::rawElement( |
| 50 | + 'span', |
| 51 | + array( 'class' => 'error' ), |
| 52 | + wfMessage( $this->getMessage() )->inContentLanguage()->parse() |
| 53 | + ); |
| 54 | + } |
41 | 55 | } |
42 | 56 | |
43 | | -/* |
| 57 | +/** |
| 58 | + * Score call exception. |
| 59 | + * This is a type of exception thrown when a call to some binary used by the |
| 60 | + * Score extension fails. |
| 61 | + */ |
| 62 | +class ScoreCallException extends ScoreException { |
| 63 | + /** |
| 64 | + * Error message returned from the call. |
| 65 | + */ |
| 66 | + private $callErrMsg; |
| 67 | + |
| 68 | + /** |
| 69 | + * Constructs a new ScoreCallException. |
| 70 | + * |
| 71 | + * @param $message Message key to be used. It should accept one |
| 72 | + * parameter, the error message returned from the binary. |
| 73 | + * @param $callErrMsg Raw error message returned by the binary. |
| 74 | + */ |
| 75 | + public function __construct( $message, $callErrMsg, $code = 0, Exception $previous = null ) { |
| 76 | + $this->callErrMsg = $callErrMsg; |
| 77 | + parent::__construct( $message, $code, $previous ); |
| 78 | + } |
| 79 | + |
| 80 | + /** |
| 81 | + * Auto-renders exception as HTML error message in the wiki's content |
| 82 | + * language. |
| 83 | + * |
| 84 | + * @return error message HTML. |
| 85 | + */ |
| 86 | + public function __toString() { |
| 87 | + return wfMessage( $this->getMessage() ) |
| 88 | + ->inContentLanguage() |
| 89 | + ->rawParams( Html::rawElement( 'pre', array(), strip_tags( $this->callErrMsg ) ) ) |
| 90 | + ->parse(); |
| 91 | + } |
| 92 | +} |
| 93 | + |
| 94 | +/** |
44 | 95 | * Score class |
45 | 96 | */ |
46 | 97 | class Score { |
47 | 98 | /** |
| 99 | + * LilyPond version string. |
| 100 | + * It defaults to null and is set the first time it is required. |
| 101 | + */ |
| 102 | + private static $lilypondVersion = null; |
| 103 | + |
| 104 | + /** |
| 105 | + * Determines the version of LilyPond in use and writes the version |
| 106 | + * string to self::$lilypondVersion. |
| 107 | + * |
| 108 | + * @throws ScoreException if LilyPond could not be executed properly. |
| 109 | + */ |
| 110 | + private static function getLilypondVersion() { |
| 111 | + global $wgLilyPond; |
| 112 | + |
| 113 | + if ( !is_executable( $wgLilyPond ) ) { |
| 114 | + throw new ScoreException( 'score-notexecutable' ); |
| 115 | + } |
| 116 | + |
| 117 | + $cmd = wfEscapeShellArg( $wgLilyPond ) . ' --version'; |
| 118 | + $stdout = wfShellExec( $cmd, $rc ); |
| 119 | + if ( $rc != 0 ) { |
| 120 | + throw new ScoreException( 'score-versionerr' ); |
| 121 | + } |
| 122 | + |
| 123 | + $n = sscanf( $stdout, 'GNU LilyPond %s', self::$lilypondVersion ); |
| 124 | + if ( $n != 1 ) { |
| 125 | + self::$lilypondVersion = null; |
| 126 | + throw new ScoreException( 'score-versionerr' ); |
| 127 | + } |
| 128 | + } |
| 129 | + |
| 130 | + /** |
48 | 131 | * Renders the lilypond code in a <score>…</score> tag. |
49 | 132 | * |
50 | | - * @param $lilypondCode |
| 133 | + * @param $code |
51 | 134 | * @param $args |
52 | 135 | * @param $parser |
53 | 136 | * @param $frame |
54 | 137 | * |
55 | 138 | * @return Image link HTML, and possibly anchor to MIDI file. |
56 | 139 | */ |
57 | | - public static function render( $lilypondCode, array $args, Parser $parser, PPFrame $frame ) { |
| 140 | + public static function render( $code, array $args, Parser $parser, PPFrame $frame ) { |
| 141 | + global $wgTmpDirectory; |
58 | 142 | |
59 | | - if ( array_key_exists( 'midi', $args ) ) { |
60 | | - $renderMidi = $args['midi']; |
61 | | - } else { |
62 | | - $renderMidi = false; |
| 143 | + try { |
| 144 | + /* create working environment */ |
| 145 | + $factoryPrefix = 'MWLP.'; |
| 146 | + $fuzz = md5( mt_rand() ); |
| 147 | + $factoryDirectory = $wgTmpDirectory . "/$factoryPrefix$fuzz"; |
| 148 | + $rc = wfMkdirParents( $factoryDirectory, 0700, __METHOD__ ); |
| 149 | + if ( !$rc ) { |
| 150 | + throw new ScoreException( 'score-nofactory' ); |
| 151 | + } |
| 152 | + } catch ( ScoreException $e ) { |
| 153 | + return $e; |
63 | 154 | } |
64 | | - if ( array_key_exists( 'raw', $args ) && $args['raw'] ) { |
65 | | - return self::runRaw( $lilypondCode, $renderMidi ); |
66 | | - } else { |
67 | | - return self::run( $lilypondCode, $renderMidi ); |
| 155 | + |
| 156 | + try { |
| 157 | + /* Midi rendering? */ |
| 158 | + if ( array_key_exists( 'midi', $args ) ) { |
| 159 | + $renderMidi = $args['midi']; |
| 160 | + } else { |
| 161 | + $renderMidi = false; |
| 162 | + } |
| 163 | + |
| 164 | + /* Score language selection */ |
| 165 | + if ( array_key_exists( 'lang', $args ) ) { |
| 166 | + $lang = $args['lang']; |
| 167 | + } else { |
| 168 | + $lang = 'lilypond'; |
| 169 | + } |
| 170 | + |
| 171 | + /* Create lilypond input file */ |
| 172 | + $lilypondFile = $factoryDirectory . '/file.ly'; |
| 173 | + switch ( $lang ) { |
| 174 | + case 'lilypond': |
| 175 | + if ( !array_key_exists( 'raw', $args ) || !$args['raw'] ) { |
| 176 | + $lilypondCode = self::embedLilypondCode( $code, $renderMidi ); |
| 177 | + $altText = $code; |
| 178 | + } else { |
| 179 | + $lilypondCode = $code; |
| 180 | + $altText = false; |
| 181 | + } |
| 182 | + $rc = file_put_contents( $lilypondFile, $lilypondCode ); |
| 183 | + if ( $rc === false ) { |
| 184 | + throw new ScoreException( 'score-noinput' ); |
| 185 | + } |
| 186 | + break; |
| 187 | + case 'ABC': |
| 188 | + $altText = false; |
| 189 | + self::runAbc2Ly( $code, $factoryDirectory ); |
| 190 | + break; |
| 191 | + default: |
| 192 | + throw new ScoreException( 'score-invalidlang' ); |
| 193 | + } |
| 194 | + |
| 195 | + $html = self::runLilypond( $factoryDirectory, $renderMidi, $altText ); |
| 196 | + } catch ( ScoreException $e ) { |
| 197 | + self::eraseFactory( $factoryDirectory ); |
| 198 | + return $e; |
68 | 199 | } |
| 200 | + |
| 201 | + /* tear down working environment */ |
| 202 | + if ( !self::eraseFactory( $factoryDirectory ) ) { |
| 203 | + self::debug( "Unable to delete temporary working directory.\n" ); |
| 204 | + } |
| 205 | + |
| 206 | + return $html; |
69 | 207 | } |
70 | 208 | |
71 | 209 | /** |
72 | | - * Runs lilypond with the code embedded in a score block. |
| 210 | + * Embeds simple LilyPond code in a score block. |
73 | 211 | * |
74 | 212 | * @param $lilypondCode |
75 | 213 | * @param $renderMidi |
76 | 214 | * |
77 | | - * @return Image link HTML, and possibly anchor to MIDI file. |
| 215 | + * @return Raw lilypond code. |
| 216 | + * |
| 217 | + * @throws ScoreException if determining the LilyPond version fails. |
78 | 218 | */ |
79 | | - private static function run( $lilypondCode, $renderMidi ) { |
| 219 | + private static function embedLilypondCode( $lilypondCode, $renderMidi ) { |
| 220 | + /* Get LilyPond version if we don't know it yet */ |
| 221 | + if ( self::$lilypondVersion === null ) { |
| 222 | + self::getLilypondVersion(); |
| 223 | + } |
| 224 | + |
80 | 225 | /* Raw code. Note: the "strange" ##f, ##t, etc., are actually part of the lilypond code! |
81 | | - * The raw code was taken directly from the original LilyPond extension */ |
| 226 | + * The raw code is based on the raw code from the original LilyPond extension */ |
82 | 227 | $raw = "\\header {\n" |
83 | 228 | . "\ttagline = ##f\n" |
84 | 229 | . "}\n" |
— | — | @@ -86,42 +231,100 @@ |
87 | 232 | . "\traggedbottom = ##t\n" |
88 | 233 | . "\tindent = 0\mm\n" |
89 | 234 | . "}\n" |
90 | | - . "\\version \"2.12.3\"\n" |
| 235 | + . '\version "' . self::$lilypondVersion . "\"\n" |
91 | 236 | . "\\score {\n" |
92 | 237 | . $lilypondCode |
93 | 238 | . "\t\\layout { }\n" |
94 | 239 | . ( $renderMidi ? "\t\\midi { }\n" : "" ) |
95 | 240 | . "}\n"; |
96 | | - return self::runRaw( $raw, $renderMidi, $lilypondCode ); |
| 241 | + return $raw; |
97 | 242 | } |
98 | 243 | |
99 | 244 | /** |
| 245 | + * Runs abc2ly, creating the LilyPond input file. |
| 246 | + * |
| 247 | + * $code ABC code. |
| 248 | + * $factoryDirectory Working environment. The LilyPond input file is |
| 249 | + * created as "file.ly" in this directory. |
| 250 | + * |
| 251 | + * @throws ScoreException if the conversion fails. |
| 252 | + */ |
| 253 | + private function runAbc2Ly( $code, $factoryDirectory ) { |
| 254 | + global $wgAbc2Ly; |
| 255 | + |
| 256 | + $abcFile = $factoryDirectory . '/file.abc'; |
| 257 | + $lyFile = $factoryDirectory . '/file.ly'; |
| 258 | + |
| 259 | + /* Create ABC input file */ |
| 260 | + $rc = file_put_contents( $abcFile, ltrim( $code ) ); // abc2ly is picky about whitespace at the start of the file |
| 261 | + if ( $rc === false ) { |
| 262 | + throw new ScoreException( 'score-noabcinput' ); |
| 263 | + } |
| 264 | + |
| 265 | + /* Convert to LilyPond file */ |
| 266 | + if ( !is_executable( $wgAbc2Ly ) ) { |
| 267 | + throw new ScoreException( 'score-abc2lynotexecutable' ); |
| 268 | + } |
| 269 | + |
| 270 | + $cmd = wfEscapeShellArg( $wgAbc2Ly ) |
| 271 | + . ' -s' |
| 272 | + . ' --output=' . wfEscapeShellArg( $lyFile ) |
| 273 | + . ' ' . wfEscapeShellArg( $abcFile ) |
| 274 | + . ' 2>&1'; // FIXME: this last bit is not portable |
| 275 | + $output = wfShellExec( $cmd, $rc ); |
| 276 | + if ( $rc != 0 ) { |
| 277 | + throw new ScoreCallException( 'score-abcconversionerr', $output ); |
| 278 | + } |
| 279 | + if ( !file_exists( $lyFile ) ) { |
| 280 | + /* Occasionally, abc2ly will return exit code 0 but not create an output file */ |
| 281 | + throw new ScoreCallException( 'score-abcconversionerr', $output ); |
| 282 | + } |
| 283 | + |
| 284 | + /* The output file has a tagline which should be removed in a wiki context */ |
| 285 | + $lyData = file_get_contents( $lyFile ); |
| 286 | + if ( $lyData === false ) { |
| 287 | + throw new ScoreException( 'score-readerr' ); |
| 288 | + } |
| 289 | + $lyData = preg_replace( '/^(\s*tagline\s*=).*/m', '$1 ##f', $lyData ); |
| 290 | + if ( $lyData === null ) { |
| 291 | + throw new ScoreException( 'score-pregreplaceerr' ); |
| 292 | + } |
| 293 | + $rc = file_put_contents( $lyFile, $lyData ); |
| 294 | + if ( $rc === false ) { |
| 295 | + throw new ScoreException( 'score-noinput' ); |
| 296 | + } |
| 297 | + } |
| 298 | + |
| 299 | + /** |
100 | 300 | * Runs lilypond. |
101 | 301 | * |
102 | | - * @param $lilypondCode |
| 302 | + * @param $factoryDirectory Directory of the working environment. |
| 303 | + * The LilyPond input file "file.ly" is expected to be in |
| 304 | + * this directory. |
103 | 305 | * @param $renderMidi |
104 | 306 | * @param $altText Alternate text for the score image. |
105 | 307 | * If set to false, the alt text will contain pagination instead. |
106 | 308 | * |
107 | 309 | * @return Image link HTML, and possibly anchor to MIDI file. |
108 | 310 | */ |
109 | | - private static function runRaw( $lilypondCode, $renderMidi, $altText = false ) { |
110 | | - global $wgTmpDirectory, $wgUploadDirectory, $wgUploadPath, $wgLilyPond, $wgScoreTrim; |
| 311 | + private static function runLilypond( $factoryDirectory, $renderMidi, $altText = false ) { |
| 312 | + global $wgUploadDirectory, $wgUploadPath, $wgLilyPond, $wgScoreTrim; |
111 | 313 | |
112 | 314 | wfProfileIn( __METHOD__ ); |
113 | 315 | |
114 | 316 | /* Various paths and filenames */ |
115 | | - $factoryPrefix = 'MWLP.'; |
116 | | - $fuzz = md5( mt_rand() ); |
117 | | - $factoryDirectory = $wgTmpDirectory . "/$factoryPrefix$fuzz"; |
118 | | - $lilypondFile = $factoryDirectory . "/file.ly"; |
119 | | - $factoryMidi = $factoryDirectory . "/file.midi"; |
120 | | - $factoryImage = $factoryDirectory . "/file.png"; |
121 | | - $factoryImageTrimmed = $factoryDirectory . "/file-trimmed.png"; |
122 | | - $factoryMultiFormat = $factoryDirectory . "/file-%d.png"; // for multi-page scores |
123 | | - $factoryMultiTrimmedFormat = $factoryDirectory . "/file-%d-trimmed.png"; |
124 | | - $lilypondDir = "lilypond"; |
125 | | - $rel = $lilypondDir . "/" . md5( $lilypondCode ); // FIXME: Too many files in one directory? |
| 317 | + $lilypondFile = $factoryDirectory . '/file.ly'; |
| 318 | + $factoryMidi = $factoryDirectory . '/file.midi'; |
| 319 | + $factoryImage = $factoryDirectory . '/file.png'; |
| 320 | + $factoryImageTrimmed = $factoryDirectory . '/file-trimmed.png'; |
| 321 | + $factoryMultiFormat = $factoryDirectory . '/file-%d.png'; // for multi-page scores |
| 322 | + $factoryMultiTrimmedFormat = $factoryDirectory . '/file-%d-trimmed.png'; |
| 323 | + $lilypondDir = 'lilypond'; |
| 324 | + $md5 = md5_file( $lilypondFile ); |
| 325 | + if ( $md5 === false ) { |
| 326 | + throw new ScoreException( 'score-noinput' ); |
| 327 | + } |
| 328 | + $rel = $lilypondDir . '/' . $md5; // FIXME: Too many files in one directory? |
126 | 329 | $filePrefix = "$wgUploadDirectory/$rel"; |
127 | 330 | $pathPrefix = "$wgUploadPath/$rel"; |
128 | 331 | $midi = "$filePrefix.midi"; |
— | — | @@ -171,17 +374,6 @@ |
172 | 375 | } |
173 | 376 | } |
174 | 377 | |
175 | | - /* create working environment */ |
176 | | - $rc = wfMkdirParents( $factoryDirectory, 0700, __METHOD__ ); |
177 | | - if ( !$rc ) { |
178 | | - throw new ScoreException( 'score-nofactory' ); |
179 | | - } |
180 | | - |
181 | | - $rc = file_put_contents( $lilypondFile, $lilypondCode ); |
182 | | - if ( $rc === false ) { |
183 | | - throw new ScoreException( 'score-noinput' ); |
184 | | - } |
185 | | - |
186 | 378 | /* generate lilypond output files in working environment */ |
187 | 379 | $oldcwd = getcwd(); |
188 | 380 | if ( $oldcwd === false ) { |
— | — | @@ -204,29 +396,16 @@ |
205 | 397 | throw new ScoreException( 'score-chdir' ); |
206 | 398 | } |
207 | 399 | if ( $rc2 != 0 ) { |
208 | | - self::eraseFactory( $factoryDirectory ); |
209 | | - wfProfileOut( __METHOD__ ); |
210 | | - $msg = wfMessage( 'score-compilererr' ) |
211 | | - ->inContentLanguage() |
212 | | - ->rawParams( |
213 | | - ' ' . Html::rawElement( 'pre', array(), strip_tags( $output ) ) . "\n" |
214 | | - ); |
215 | | - return $msg; |
| 400 | + throw new ScoreCallException( 'score-compilererr', $output ); |
216 | 401 | } |
217 | 402 | |
218 | 403 | /* trim output images if wanted */ |
219 | 404 | if ( $wgScoreTrim ) { |
220 | 405 | if ( file_exists( $factoryImage ) ) { |
221 | 406 | $rc = self::trimImage( $factoryImage, $factoryImageTrimmed ); |
222 | | - if ( !$rc ) { |
223 | | - throw new ScoreException( 'score-trimerr' ); |
224 | | - } |
225 | 407 | } |
226 | 408 | for ( $i = 1; file_exists( $f = sprintf( $factoryMultiFormat, $i ) ); ++$i ) { |
227 | 409 | $rc = self::trimImage( $f, sprintf( $factoryMultiTrimmedFormat, $i ) ); |
228 | | - if ( !$rc ) { |
229 | | - throw new ScoreException( 'score-trimerr' ); |
230 | | - } |
231 | 410 | } |
232 | 411 | } else { |
233 | 412 | $factoryImageTrimmed = $factoryImage; |
— | — | @@ -248,20 +427,10 @@ |
249 | 428 | throw new ScoreException( 'score-renameerr' ); |
250 | 429 | } |
251 | 430 | |
252 | | - /* tear down working environment */ |
253 | | - if ( !self::eraseFactory( $factoryDirectory ) ) { |
254 | | - self::debug( "Unable to delete temporary working directory.\n" ); |
255 | | - } |
256 | 431 | } catch ( ScoreException $e ) { |
257 | | - self::eraseFactory( $factoryDirectory ); |
258 | 432 | wfProfileOut( __METHOD__ ); |
259 | | - return Html::rawElement( |
260 | | - 'span', |
261 | | - array( 'class' => 'error' ), |
262 | | - wfMessage( $e->getMessage() )->inContentLanguage()->parse() |
263 | | - ); |
| 433 | + throw $e; |
264 | 434 | } |
265 | | - wfProfileOut( __METHOD__ ); |
266 | 435 | } |
267 | 436 | |
268 | 437 | /* return output link(s) */ |
— | — | @@ -309,7 +478,7 @@ |
310 | 479 | * @param $source |
311 | 480 | * @param $dest |
312 | 481 | * |
313 | | - * @return true on success, false on error. |
| 482 | + * @throws ScoreException on error. |
314 | 483 | */ |
315 | 484 | private static function trimImage( $source, $dest ) { |
316 | 485 | global $wgImageMagickConvertCommand; |
— | — | @@ -319,11 +488,9 @@ |
320 | 489 | . wfEscapeShellArg( $source ) . ' ' |
321 | 490 | . wfEscapeShellArg( $dest ); |
322 | 491 | wfShellExec( $cmd, $rc ); |
323 | | - if ( $rc == 0 ) { |
324 | | - return true; |
| 492 | + if ( $rc != 0 ) { |
| 493 | + throw new ScoreException( 'score-trimerr' ); |
325 | 494 | } |
326 | | - |
327 | | - return false; |
328 | 495 | } |
329 | 496 | |
330 | 497 | /** |