Added file backend support via $wgMathFileBackend.

* Also removed old legacy migration code.

Change-Id: I43cfd7f0da49690a2d0b4eb2daab9b8a110137b7
This commit is contained in:
Aaron 2012-08-20 15:11:16 -07:00
parent 29a0a80e8f
commit ae9e0d989b
2 changed files with 79 additions and 78 deletions

View File

@ -38,11 +38,33 @@ class MathRenderer {
var $mathml = ''; var $mathml = '';
var $conservativeness = 0; var $conservativeness = 0;
function __construct( $tex, $params = array() ) { public function __construct( $tex, $params = array() ) {
$this->tex = $tex; $this->tex = $tex;
$this->params = $params; $this->params = $params;
} }
/**
* @return FileBackend
*/
protected function getBackend() {
global $wgMathFileBackend, $wgMathDirectory;
if ( $wgMathFileBackend ) {
return FileBackendGroup::singleton()->get( $wgMathFileBackend );
} else {
static $backend = null;
if ( !$backend ) {
$backend = new FSFileBackend( array(
'name' => 'math-backend',
'lockManager' => 'nullLockManager',
'containerPaths' => array( 'math-render' => $wgMathDirectory ),
'fileMode' => 777
) );
}
return $backend;
}
}
function setOutputMode( $mode ) { function setOutputMode( $mode ) {
$validModes = array( MW_MATH_PNG, MW_MATH_SOURCE, MW_MATH_MATHJAX ); $validModes = array( MW_MATH_PNG, MW_MATH_SOURCE, MW_MATH_MATHJAX );
if ( in_array( $mode, $validModes ) ) { if ( in_array( $mode, $validModes ) ) {
@ -54,8 +76,7 @@ class MathRenderer {
} }
function render() { function render() {
global $wgTmpDirectory; global $wgTexvc, $wgTexvcBackgroundColor, $wgUseSquid;
global $wgTexvc, $wgMathCheckFiles, $wgTexvcBackgroundColor;
if( $this->mode == MW_MATH_SOURCE || $this->mode == MW_MATH_MATHJAX ) { if( $this->mode == MW_MATH_SOURCE || $this->mode == MW_MATH_MATHJAX ) {
# No need to render or parse anything more! # No need to render or parse anything more!
@ -75,27 +96,17 @@ class MathRenderer {
return; # bug 8372 return; # bug 8372
} }
if( !$this->_recall() ) { $tmpDir = wfTempDir();
if( $wgMathCheckFiles ) { if( !$this->_recall() ) { // cache miss
# Ensure that the temp and output directories are available before continuing...
if( !file_exists( $wgTmpDirectory ) ) {
if( !wfMkdirParents( $wgTmpDirectory, null, __METHOD__ ) ) {
return $this->_error( 'math_bad_tmpdir' );
}
} elseif( !is_dir( $wgTmpDirectory ) || !is_writable( $wgTmpDirectory ) ) {
return $this->_error( 'math_bad_tmpdir' );
}
}
if( !is_executable( $wgTexvc ) ) { if( !is_executable( $wgTexvc ) ) {
return $this->_error( 'math_notexvc' ); return $this->_error( 'math_notexvc' );
} }
$cmd = $wgTexvc . ' ' . $cmd = $wgTexvc . ' ' .
wfEscapeSingleQuotes( $wgTmpDirectory ) . ' '. wfEscapeSingleQuotes( $tmpDir ) . ' '.
wfEscapeSingleQuotes( $wgTmpDirectory ) . ' '. wfEscapeSingleQuotes( $tmpDir ) . ' '.
wfEscapeSingleQuotes( $this->tex ) . ' '. wfEscapeSingleQuotes( $this->tex ) . ' '.
wfEscapeSingleQuotes( 'UTF-8' ) . ' '. wfEscapeSingleQuotes( 'UTF-8' ) . ' '.
wfEscapeSingleQuotes( $wgTexvcBackgroundColor ); wfEscapeSingleQuotes( $wgTexvcBackgroundColor );
if ( wfIsWindows() ) { if ( wfIsWindows() ) {
# Invoke it within cygwin sh, because texvc expects sh features in its default shell # Invoke it within cygwin sh, because texvc expects sh features in its default shell
@ -107,9 +118,16 @@ class MathRenderer {
wfDebug( "TeX output:\n $contents\n---\n" ); wfDebug( "TeX output:\n $contents\n---\n" );
if ( strlen( $contents ) == 0 ) { if ( strlen( $contents ) == 0 ) {
return $this->_error( 'math_unknown_error' ); if ( !file_exists( $tmpDir ) || !is_writable( $tmpDir ) ) {
return $this->_error( 'math_bad_tmpdir' );
} else {
return $this->_error( 'math_unknown_error' );
}
} }
$tempFsFile = new TempFSFile( "$tmpDir/{$this->hash}.png" );
$tempFsFile->autocollect(); // destroy file when $tempFsFile leaves scope
$retval = substr( $contents, 0, 1 ); $retval = substr( $contents, 0, 1 );
$errmsg = ''; $errmsg = '';
if ( ( $retval == 'C' ) || ( $retval == 'M' ) || ( $retval == 'L' ) ) { if ( ( $retval == 'C' ) || ( $retval == 'M' ) || ( $retval == 'L' ) ) {
@ -169,33 +187,26 @@ class MathRenderer {
if ( $errmsg ) { if ( $errmsg ) {
return $errmsg; return $errmsg;
} } elseif ( !preg_match( "/^[a-f0-9]{32}$/", $this->hash ) ) {
if ( !preg_match( "/^[a-f0-9]{32}$/", $this->hash ) ) {
return $this->_error( 'math_unknown_error' ); return $this->_error( 'math_unknown_error' );
} } elseif( !file_exists( "$tmpDir/{$this->hash}.png" ) ) {
return $this->_error( 'math_image_error' );
if( !file_exists( "$wgTmpDirectory/{$this->hash}.png" ) ) { } elseif( filesize( "$tmpDir/{$this->hash}.png" ) == 0 ) {
return $this->_error( 'math_image_error' ); return $this->_error( 'math_image_error' );
} }
if( filesize( "$wgTmpDirectory/{$this->hash}.png" ) == 0 ) { $hashpath = $this->_getHashPath(); // final storage directory
return $this->_error( 'math_image_error' );
}
$hashpath = $this->_getHashPath(); $backend = $this->getBackend();
if( !file_exists( $hashpath ) ) { # Create any containers/directories as needed...
wfSuppressWarnings(); if ( !$backend->prepare( array( 'dir' => $hashpath ) )->isOK() ) {
$ret = wfMkdirParents( $hashpath, 0755, __METHOD__ ); return $this->_error( 'math_output_error' );
wfRestoreWarnings();
if( !$ret ) {
return $this->_error( 'math_bad_output' );
}
} elseif( !is_dir( $hashpath ) || !is_writable( $hashpath ) ) {
return $this->_error( 'math_bad_output' );
} }
// Store the file at the final storage path...
if( !rename( "$wgTmpDirectory/{$this->hash}.png", "$hashpath/{$this->hash}.png" ) ) { if ( !$backend->quickStore( array(
'src' => "$tmpDir/{$this->hash}.png", 'dst' => "$hashpath/{$this->hash}.png"
) )->isOK()
) {
return $this->_error( 'math_output_error' ); return $this->_error( 'math_output_error' );
} }
@ -221,7 +232,6 @@ class MathRenderer {
} }
// If we're replacing an older version of the image, make sure it's current. // If we're replacing an older version of the image, make sure it's current.
global $wgUseSquid;
if ( $wgUseSquid ) { if ( $wgUseSquid ) {
$urls = array( $this->_mathImageUrl() ); $urls = array( $this->_mathImageUrl() );
$u = new SquidUpdate( $urls ); $u = new SquidUpdate( $urls );
@ -240,7 +250,7 @@ class MathRenderer {
} }
function _recall() { function _recall() {
global $wgMathDirectory, $wgMathCheckFiles; global $wgMathCheckFiles;
$this->md5 = md5( $this->tex ); $this->md5 = md5( $this->tex );
$dbr = wfGetDB( DB_SLAVE ); $dbr = wfGetDB( DB_SLAVE );
@ -257,7 +267,7 @@ class MathRenderer {
); );
if( $rpage !== false ) { if( $rpage !== false ) {
# Tailing 0x20s can get dropped by the database, add it back on if necessary: # Trailing 0x20s can get dropped by the database, add it back on if necessary:
$xhash = unpack( 'H32md5', $dbr->decodeBlob( $rpage->math_outputhash ) . " " ); $xhash = unpack( 'H32md5', $dbr->decodeBlob( $rpage->math_outputhash ) . " " );
$this->hash = $xhash['md5']; $this->hash = $xhash['md5'];
@ -265,46 +275,22 @@ class MathRenderer {
$this->html = $rpage->math_html; $this->html = $rpage->math_html;
$this->mathml = $rpage->math_mathml; $this->mathml = $rpage->math_mathml;
$filename = $this->_getHashPath() . "/{$this->hash}.png";
if( !$wgMathCheckFiles ) { if( !$wgMathCheckFiles ) {
// Short-circuit the file existence & migration checks // Short-circuit the file existence & migration checks
return true; return true;
} }
if( file_exists( $filename ) ) { $filename = $this->_getHashPath() . "/{$this->hash}.png"; // final storage path
if( filesize( $filename ) == 0 ) {
$backend = $this->getBackend();
if( $backend->fileExists( array( 'src' => $filename ) ) ) {
if( $backend->getFileSize( array( 'src' => $filename ) ) == 0 ) {
// Some horrible error corrupted stuff :( // Some horrible error corrupted stuff :(
wfSuppressWarnings(); $backend->quickDelete( array( 'src' => $filename ) );
unlink( $filename );
wfRestoreWarnings();
} else { } else {
return true; return true; // cache hit
} }
} }
if( file_exists( $wgMathDirectory . "/{$this->hash}.png" ) ) {
$hashpath = $this->_getHashPath();
if( !file_exists( $hashpath ) ) {
wfSuppressWarnings();
$ret = wfMkdirParents( $hashpath, 0755, __METHOD__ );
wfRestoreWarnings();
if( !$ret ) {
return false;
}
} elseif( !is_dir( $hashpath ) || !is_writable( $hashpath ) ) {
return false;
}
if ( function_exists( 'link' ) ) {
return link( $wgMathDirectory . "/{$this->hash}.png",
$hashpath . "/{$this->hash}.png" );
} else {
return rename( $wgMathDirectory . "/{$this->hash}.png",
$hashpath . "/{$this->hash}.png" );
}
}
} }
# Missing from the database and/or the render cache # Missing from the database and/or the render cache
@ -368,13 +354,19 @@ class MathRenderer {
return "$wgMathPath/$dir/{$this->hash}.png"; return "$wgMathPath/$dir/{$this->hash}.png";
} }
/**
* @return string Storage directory
*/
function _getHashPath() { function _getHashPath() {
global $wgMathDirectory; $path = $this->getBackend()->getRootStoragePath() .
$path = $wgMathDirectory . '/' . $this->_getHashSubPath(); '/math-render/' . $this->_getHashSubPath();
wfDebug( "TeX: getHashPath, hash is: $this->hash, path is: $path\n" ); wfDebug( "TeX: getHashPath, hash is: $this->hash, path is: $path\n" );
return $path; return $path;
} }
/**
* @return string Relative directory
*/
function _getHashSubPath() { function _getHashSubPath() {
return substr( $this->hash, 0, 1) return substr( $this->hash, 0, 1)
. '/' . substr( $this->hash, 1, 1 ) . '/' . substr( $this->hash, 1, 1 )

View File

@ -73,6 +73,15 @@ $wgMathCheckFiles = true;
*/ */
$wgMathPath = false; $wgMathPath = false;
/**
* The name of a file backend ($wgFileBackends) to use for storing math renderings.
* Defaults to FSFileBackend using $wgMathDirectory as a base path.
*
* See http://www.mediawiki.org/wiki/Manual:Enable_TeX for details about how to
* set up mathematical formula display.
*/
$wgMathFileBackend = false;
/** /**
* The filesystem path of the math directory. * The filesystem path of the math directory.
* Defaults to "{$wgUploadDirectory}/math". * Defaults to "{$wgUploadDirectory}/math".