MaintenanceRunner: load script file early if possible
If possible, load the script file before running Setup.php. This way, script files can control the setup process by defining constants. This is needed by scome scripts, namely: - instal.php, to override config loading by defining MW_CONFIG_CALLBACK - generateConfigSchema.php, for setting MW_USE_CONFIG_SCHEMA_CLASS - mergeMessageFileList.php, for setting MW_NO_EXTENSION_MESSAGES - shell.php, for setting MW_NO_SESSION Note that this will not work for scripts defined in extensions. In order to allow script files to be loaded based on class name, AutoLoader.php is included before Setup.php is run. This is a modified version of I638f99c3cc6f8ab8216bd65ada959a6a11ff454b. Co-authored-by: PleaseStand <pleasestand@live.com> Change-Id: I2bf3b91c0a7162413cd1392252cb4f29a0d3d594
This commit is contained in:
parent
ae6d4e6fa3
commit
63e07eed60
8 changed files with 106 additions and 23 deletions
|
|
@ -269,6 +269,7 @@ $wgAutoloadLocalClasses = [
|
|||
'CollapsibleFieldsetLayout' => __DIR__ . '/includes/htmlform/CollapsibleFieldsetLayout.php',
|
||||
'Collation' => __DIR__ . '/includes/collation/Collation.php',
|
||||
'CollationCkb' => __DIR__ . '/includes/collation/CollationCkb.php',
|
||||
'CommandLineInstaller' => __DIR__ . '/maintenance/install.php',
|
||||
'CommentStore' => __DIR__ . '/includes/CommentStore/CommentStore.php',
|
||||
'CommentStoreComment' => __DIR__ . '/includes/CommentStore/CommentStoreComment.php',
|
||||
'CompareLanguageConverterOutput' => __DIR__ . '/maintenance/compareLanguageConverterOutput.php',
|
||||
|
|
|
|||
|
|
@ -76,3 +76,22 @@ function wfDetectInstallPath(): string {
|
|||
|
||||
return MW_INSTALL_PATH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the operating system is Windows
|
||||
*
|
||||
* @return bool True if it's Windows, false otherwise.
|
||||
*/
|
||||
function wfIsWindows() {
|
||||
return PHP_OS_FAMILY === 'Windows';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are running from the commandline
|
||||
*
|
||||
* @since 1.31
|
||||
* @return bool
|
||||
*/
|
||||
function wfIsCLI() {
|
||||
return PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1411,25 +1411,6 @@ function wfTimestampNow() {
|
|||
return MWTimestamp::now( TS_MW );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the operating system is Windows
|
||||
*
|
||||
* @return bool True if it's Windows, false otherwise.
|
||||
*/
|
||||
function wfIsWindows() {
|
||||
return PHP_OS_FAMILY === 'Windows';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are running from the commandline
|
||||
*
|
||||
* @since 1.31
|
||||
* @return bool
|
||||
*/
|
||||
function wfIsCLI() {
|
||||
return PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg';
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to get the system directory for temporary files. First
|
||||
* $wgTmpDirectory is checked, and then the TMPDIR, TMP, and TEMP
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ if ( !$maintClass || !class_exists( $maintClass ) ) {
|
|||
define( 'MEDIAWIKI', true );
|
||||
|
||||
$IP = wfDetectInstallPath();
|
||||
require_once "$IP/includes/AutoLoader.php";
|
||||
|
||||
$runner = new MaintenanceRunner();
|
||||
$runner->initForClass( $maintClass, $GLOBALS['argv'] );
|
||||
|
|
|
|||
|
|
@ -317,6 +317,50 @@ class MaintenanceRunner {
|
|||
return $scriptClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preload the script file, so any defines in file level code are executed.
|
||||
* This way, scripts can control what Setup.php does.
|
||||
*
|
||||
* @internal
|
||||
* @param string $script
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function preloadScriptFile( string $script ): string {
|
||||
[ $extName, $scriptName ] = $this->splitScript( $script );
|
||||
|
||||
if ( $extName !== null ) {
|
||||
// Preloading is not supported. findScriptClass() will try to find the script later.
|
||||
return $script;
|
||||
}
|
||||
|
||||
$scriptFile = $this->expandScriptFile( $scriptName, null );
|
||||
|
||||
$scriptClass = null;
|
||||
if ( file_exists( $scriptFile ) ) {
|
||||
$scriptClass = $this->loadScriptFile( $scriptFile );
|
||||
}
|
||||
|
||||
if ( !$scriptClass ) {
|
||||
$scriptClass = $this->expandScriptClass( $scriptName, null );
|
||||
}
|
||||
|
||||
// NOTE: class_exists will trigger auto-loading, so file-level code in the script file will run.
|
||||
if ( class_exists( $scriptClass ) ) {
|
||||
// Return the script class name we found, so we don't try to load the file again!
|
||||
return $scriptClass;
|
||||
}
|
||||
|
||||
// Preloading failed. Let findScriptClass() try to find the script later.
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param string $script
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function findScriptClass( string $script ): string {
|
||||
[ $extName, $scriptName ] = $this->splitScript( $script );
|
||||
|
||||
|
|
@ -488,6 +532,12 @@ class MaintenanceRunner {
|
|||
$_SERVER['SERVER_NAME'] = $this->parameters->getOption( 'server' );
|
||||
}
|
||||
|
||||
// Try to load the script file before running Setup.php if possible.
|
||||
// This allows the script file to define constants that change the behavior
|
||||
// of Setup.php.
|
||||
// Note that this will only work reliably for core scripts.
|
||||
$this->script = $this->preloadScriptFile( $this->script );
|
||||
|
||||
if ( !is_readable( $settingsFile ) ) {
|
||||
// NOTE: Some maintenance scripts can (and need to) run without LocalSettings.
|
||||
// But we only know that once we have instantiated the Maintenance object.
|
||||
|
|
|
|||
|
|
@ -21,13 +21,12 @@
|
|||
* @ingroup Maintenance
|
||||
*/
|
||||
|
||||
// NO_AUTOLOAD -- file-scope define() used to modify behaviour
|
||||
|
||||
use MediaWiki\Settings\SettingsBuilder;
|
||||
use Wikimedia\AtEase\AtEase;
|
||||
|
||||
require_once __DIR__ . '/Maintenance.php';
|
||||
|
||||
define( 'MW_CONFIG_CALLBACK', 'Installer::overrideConfig' );
|
||||
define( 'MEDIAWIKI_INSTALL', true );
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ if ( !MaintenanceRunner::shouldExecute() ) {
|
|||
// Define the MediaWiki entrypoint
|
||||
define( 'MEDIAWIKI', true );
|
||||
|
||||
// This environment variable is ensured present by Maintenance.php.
|
||||
$IP = getenv( 'MW_INSTALL_PATH' );
|
||||
$IP = wfDetectInstallPath();
|
||||
require_once "$IP/includes/AutoLoader.php";
|
||||
|
||||
// phpcs:disable: MediaWiki.NamingConventions.ValidGlobalName.allowedPrefix
|
||||
$runner = new MaintenanceRunner();
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ class MaintenanceRunnerTest extends TestCase {
|
|||
return parent::findScriptClass( $script );
|
||||
}
|
||||
|
||||
public function preloadScriptFile( string $script ): string {
|
||||
return parent::preloadScriptFile( $script );
|
||||
}
|
||||
|
||||
protected function fatalError( $msg, $exitCode = 1 ) {
|
||||
$this->error( $msg );
|
||||
throw new UnexpectedValueException( $msg );
|
||||
|
|
@ -108,4 +112,32 @@ class MaintenanceRunnerTest extends TestCase {
|
|||
$this->assertSame( $expected, $class );
|
||||
}
|
||||
|
||||
public function providePreloadScriptFile() {
|
||||
// NOTE: We must use a different class for each test case,
|
||||
// otherwise we may trigger a "cannot re-declare class" error.
|
||||
|
||||
yield 'plain name'
|
||||
=> [ 'findOrphanedFiles', FindOrphanedFiles::class ];
|
||||
|
||||
yield 'name with suffix'
|
||||
=> [ 'getText.php', GetTextMaint::class ];
|
||||
|
||||
yield 'class name'
|
||||
=> [ 'FindOrphanedFiles', FindOrphanedFiles::class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providePreloadScriptFile
|
||||
*/
|
||||
public function testPreloadScriptFile( $script, $expected ) {
|
||||
$runner = $this->newRunner();
|
||||
|
||||
$class = $runner->preloadScriptFile( $script );
|
||||
|
||||
if ( str_starts_with( $class, '\\' ) ) {
|
||||
$class = substr( $class, 1 );
|
||||
}
|
||||
$this->assertSame( $expected, $class );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue