From 2dbed8d5cd1bae41f18d9c3cb0e5e34864aa924d Mon Sep 17 00:00:00 2001 From: "Mark A. Hershberger" Date: Sun, 27 Jun 2010 21:48:51 +0000 Subject: [PATCH] * consolidate some installer functionals into the Installer class * add beginning of CliInstallerOutput class * make it possible to override LocalSettings from a maint script * make basic cli installation possible (only tested mysql so far) --- config/new-index.php | 25 +------ includes/AutoLoader.php | 1 + includes/installer/CliInstaller.php | 77 ++++++++++++++++----- includes/installer/CliInstallerOutput.php | 83 +++++++++++++++++++++++ includes/installer/Installer.php | 30 +++++++- maintenance/Maintenance.php | 12 ++-- maintenance/doMaintenance.php | 11 ++- maintenance/install.php | 36 ++++++---- 8 files changed, 210 insertions(+), 65 deletions(-) create mode 100644 includes/installer/CliInstallerOutput.php diff --git a/config/new-index.php b/config/new-index.php index de0a8143a2..2291dc20ba 100644 --- a/config/new-index.php +++ b/config/new-index.php @@ -1,35 +1,12 @@ disableBackend(); -LBFactory::disableBackend(); - -// Load the installer's i18n file -$wgExtensionMessagesFiles['MediawikiInstaller'] = './includes/installer/Installer.i18n.php'; - $installer = new WebInstaller( $wgRequest ); -$wgParser->setHook( 'doclink', array( $installer, 'docLink' ) ); if ( !$installer->startSession() ) { $installer->finish(); diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index b4ae511b80..6571c9e8dd 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -414,6 +414,7 @@ $wgAutoloadLocalClasses = array( # includes/installer 'CliInstaller' => 'includes/installer/CliInstaller.php', + 'CliInstallerOutput' => 'includes/installer/CliInstallerOutput.php', 'Installer' => 'includes/installer/Installer.php', 'InstallerDBType' => 'includes/installer/InstallerDBType.php', 'LBFactory_InstallerFake' => 'includes/installer/Installer.php', diff --git a/includes/installer/CliInstaller.php b/includes/installer/CliInstaller.php index 307762ee98..2e1ecd1e6a 100644 --- a/includes/installer/CliInstaller.php +++ b/includes/installer/CliInstaller.php @@ -1,24 +1,41 @@ 'wgDBtype', + 'dbserver' => 'wgDBserver', + 'dbname' => 'wgDBname', + 'dbuser' => 'wgDBuser', + 'dbpass' => 'wgDBpassword', + 'dbprefix' => 'wgDBprefix', + 'dbtableoptions' => 'wgDBTableOptions', + 'dbmysql5' => 'wgDBmysql5', + 'dbserver' => 'wgDBserver', + 'dbport' => 'wgDBport', + 'dbname' => 'wgDBname', + 'dbuser' => 'wgDBuser', + 'dbpass' => 'wgDBpassword', + 'dbschema' => 'wgDBmwschema', + 'dbts2schema' => 'wgDBts2schema', + 'dbpath' => 'wgSQLiteDataDir', + ); + + /** Constructor */ function __construct( $siteName, $admin = null, $option = array()) { parent::__construct(); + foreach ( $this->optionMap as $opt => $global ) { + if ( isset( $option[$opt] ) ) { + $GLOBALS[$global] = $option[$opt]; + $this->setVar( $global, $option[$opt] ); + } + } + if ( isset( $option['lang'] ) ) { global $wgLang, $wgContLang, $wgLanguageCode; $this->setVar( '_UserLang', $option['lang'] ); @@ -31,22 +48,48 @@ class CliInstaller extends Installer { if ( $admin ) { $this->setVar( '_AdminName', $admin ); } else { - $this->setVar( '_AdminName', wfMsgForContent( 'config-admin-default-username' ) ); + $this->setVar( '_AdminName', + wfMsgForContent( 'config-admin-default-username' ) ); } + + if ( !isset( $option['installdbuser'] ) ) { + $this->setVar( '_InstallUser', + $this->getVar( 'wgDBuser' ) ); + $this->setVar( '_InstallPassword', + $this->getVar( 'wgDBpassword' ) ); + } + + if ( isset( $option['pass'] ) ) { + $this->setVar( '_AdminPassword', $option['pass'] ); + } + + $this->output = new CliInstallerOutput( $this ); } /** * Main entry point. */ function execute( ) { - var_dump($this->getVar('_AdminName')); + foreach( $this->getInstallSteps() as $step ) { + $this->showMessage("Installing $step... "); + $func = 'install' . ucfirst( $step ); + $status = $this->{$func}(); + $ok = $status->isGood(); + if ( !$ok ) { + $this->showStatusError( $status ); + exit; + } + $this->showMessage("done\n"); + } } function showMessage( $msg /*, ... */ ) { - echo "Message: $msg\n"; + $this->output->addHTML($msg); + $this->output->output(); } function showStatusError( $status ) { - echo "Error: $status\n"; + $this->output->addHTML($status->getWikiText()."\n"); + $this->output->flush(); } } diff --git a/includes/installer/CliInstallerOutput.php b/includes/installer/CliInstallerOutput.php new file mode 100644 index 0000000000..55c239cdc2 --- /dev/null +++ b/includes/installer/CliInstallerOutput.php @@ -0,0 +1,83 @@ +parent = $parent; + } + + function addHTML( $html ) { + $this->contents .= $html; + } + + function addWikiText( $text ) { + $this->addHTML( $this->parent->parse( $text ) ); + } + + function addHTMLNoFlush( $html ) { + $this->contents .= $html; + } + + function addWarning( $msg ) { + $this->warnings .= "

$msg

\n"; + } + + function addWarningMsg( $msg /*, ... */ ) { + $params = func_get_args(); + array_shift( $params ); + $this->addWarning( wfMsg( $msg, $params ) ); + } + + function redirect( $url ) { + if ( $this->headerDone ) { + throw new MWException( __METHOD__ . ' called after sending headers' ); + } + $this->redirectTarget = $url; + } + + function output() { + $this->flush(); + $this->outputFooter(); + } + + function useShortHeader( $use = true ) { + } + + function flush() { + echo $this->contents; + flush(); + $this->contents = ''; + } + + function getDir() { + global $wgLang; + if( !is_object( $wgLang ) || !$wgLang->isRtl() ) + return 'ltr'; + else + return 'rtl'; + } + + function getLanguageCode() { + global $wgLang; + if( !is_object( $wgLang ) ) + return 'en'; + else + return $wgLang->getCode(); + } + + function outputWarnings() { + $this->addHTML( $this->warnings ); + $this->warnings = ''; + } + + function outputFooter() {} + +} diff --git a/includes/installer/Installer.php b/includes/installer/Installer.php index 3cc8a3f1b0..38ecde17ce 100644 --- a/includes/installer/Installer.php +++ b/includes/installer/Installer.php @@ -215,6 +215,16 @@ abstract class Installer { * Constructor, always call this from child classes */ function __construct() { + // Disable the i18n cache and LoadBalancer + Language::getLocalisationCache()->disableBackend(); + LBFactory::disableBackend(); + + // Load the installer's i18n file + global $wgExtensionMessagesFiles; + $wgExtensionMessagesFiles['MediawikiInstaller'] = + './includes/installer/Installer.i18n.php'; + + $this->settings = $this->internalDefaults; foreach ( $this->defaultVarNames as $var ) { $this->settings[$var] = $GLOBALS[$var]; @@ -909,7 +919,7 @@ abstract class Installer { } } - /* + /** * On POSIX systems return the primary group of the webserver we're running under. * On other systems just returns null. * @@ -934,4 +944,22 @@ abstract class Installer { return $group; } + + /** + * Override the necessary bits of the config to run an installation + */ + public static function overrideConfig() { + define( 'MW_NO_SESSION', 1 ); + + // Don't access the database + $GLOBALS['wgUseDatabaseMessages'] = false; + // Debug-friendly + $GLOBALS['wgShowExceptionDetails'] = true; + // Don't break forms + $GLOBALS['wgExternalLinkTarget'] = '_blank'; + + // Extended debugging. Maybe disable before release? + $GLOBALS['wgShowSQLErrors'] = true; + $GLOBALS['wgShowDBErrorBacktrace'] = true; + } } diff --git a/maintenance/Maintenance.php b/maintenance/Maintenance.php index 31d737ca5a..75dd663daf 100644 --- a/maintenance/Maintenance.php +++ b/maintenance/Maintenance.php @@ -217,7 +217,8 @@ abstract class Maintenance { * Throw some output to the user. Scripts can call this with no fears, * as we handle all --quiet stuff here * @param $out String: the text to show to the user - * @param $channel Mixed: unique identifier for the channel. See function outputChanneled. + * @param $channel Mixed: unique identifier for the channel. See + * function outputChanneled. */ protected function output( $out, $channel = null ) { if ( $this->mQuiet ) { @@ -256,13 +257,14 @@ abstract class Maintenance { private $atLineStart = true; private $lastChannel = null; - + /** * Message outputter with channeled message support. Messages on the * same channel are concatenated, but any intervening messages in another * channel start a new line. * @param $msg String: the message without trailing newline - * @param $channel Channel identifier or null for no channel. Channel comparison uses ===. + * @param $channel Channel identifier or null for no + * channel. Channel comparison uses ===. */ public function outputChanneled( $msg, $channel = null ) { $handle = fopen( 'php://stdout', 'w' ); @@ -556,7 +558,7 @@ abstract class Maintenance { $die = true; } } - + if ( $die ) { $this->maybeHelp( true ); } @@ -588,7 +590,7 @@ abstract class Maintenance { $screenWidth = 80; // TODO: Caculate this! $tab = " "; $descWidth = $screenWidth - ( 2 * strlen( $tab ) ); - + ksort( $this->mParams ); if ( $this->hasOption( 'help' ) || $force ) { $this->mQuiet = false; diff --git a/maintenance/doMaintenance.php b/maintenance/doMaintenance.php index a1cd4576c0..1fc50b1fda 100644 --- a/maintenance/doMaintenance.php +++ b/maintenance/doMaintenance.php @@ -61,9 +61,13 @@ if ( file_exists( "$IP/StartProfiler.php" ) ) { require_once( "$IP/includes/AutoLoader.php" ); require_once( "$IP/includes/Defines.php" ); -// Load settings, using wikimedia-mode if needed -// Fixme: replace this hack with general farm-friendly code -if ( file_exists( "$IP/wmf-config/wikimedia-mode" ) ) { +if ( defined( 'MW_CONFIG_CALLBACK' ) ) { + # Use a callback function to configure MediaWiki + require_once( "$IP/includes/DefaultSettings.php" ); + call_user_func( MW_CONFIG_CALLBACK ); +} elseif ( file_exists( "$IP/wmf-config/wikimedia-mode" ) ) { + // Load settings, using wikimedia-mode if needed + // Fixme: replace this hack with general farm-friendly code # TODO FIXME! Wikimedia-specific stuff needs to go away to an ext # Maybe a hook? global $cluster; @@ -76,6 +80,7 @@ if ( file_exists( "$IP/wmf-config/wikimedia-mode" ) ) { } else { require_once( $maintenance->loadSettings() ); } + if ( $maintenance->getDbType() === Maintenance::DB_ADMIN && is_readable( "$IP/AdminSettings.php" ) ) { diff --git a/maintenance/install.php b/maintenance/install.php index d68ae27659..70bc30c9f6 100644 --- a/maintenance/install.php +++ b/maintenance/install.php @@ -20,34 +20,40 @@ * @see wfWaitForSlaves() */ -define( 'MW_NO_DB', 1 ); -define( 'MW_NO_SESSION', 1 ); -define( 'MW_CONFIG_CALLBACK', 'wfInstallerConfig' ); +define( 'MW_CONFIG_CALLBACK', 'Installer::overrideConfig' ); -$IP = dirname( dirname( __FILE__ ) ); - -require_once( "$IP/maintenance/Maintenance.php" ); +require_once( dirname( dirname( __FILE__ ) )."/maintenance/Maintenance.php" ); class CommandLineInstaller extends Maintenance { public function __construct() { + parent::__construct(); + $this->addArg( 'name', 'The name of the wiki', true); + $this->addArg( 'admin', 'The username of the wiki administrator (WikiSysop)', false); $this->addOption( 'pass', 'The password for the wiki administrator. You will be prompted for this if it isn\'t provided', false, true); - /* $this->addOption( 'email', 'The email for the wiki administrator', false, true); */ + $this->addOption( 'email', 'The email for the wiki administrator', false, true); + $this->addOption( 'lang', 'The language to use (en)', false, true ); /* $this->addOption( 'cont-lang', 'The content language (en)', false, true ); */ - $this->addOption( 'db-type', 'The type of database (mysql)', false, true ); - /* $this->addOption( 'db-host', 'The database host (localhost)', false, true ); */ - /* $this->addOption( 'db-port', 'The database port (3306 for mysql, 5432 for pg)', false, true ); */ - $this->addOption( 'db-name', 'The database name (my_wiki)', false, true ); - $this->addOption( 'db-path', 'The path for the SQLite DB (/var/data)', false, true ); - /* $this->addOption( 'db-schema', 'The schema for the MediaWiki DB in pg (mediawiki)', false, true ); */ - /* $this->addOption( 'db-tsearch2-schema', 'The schema for the tsearch2 DB in pg (public)', false, true ); */ + + $this->addOption( 'dbtype', 'The type of database (mysql)', false, true ); + /* $this->addOption( 'dbhost', 'The database host (localhost)', false, true ); */ + /* $this->addOption( 'dbport', 'The database port (3306 for mysql, 5432 for pg)', false, true ); */ + $this->addOption( 'dbname', 'The database name (my_wiki)', false, true ); + $this->addOption( 'dbpath', 'The path for the SQLite DB (/var/data)', false, true ); + $this->addOption( 'installdbuser', 'The user to use for installing (root)', false, true ); + $this->addOption( 'installdbpass', 'The pasword for the DB user to install as.', false, true ); + /* $this->addOption( 'dbschema', 'The schema for the MediaWiki DB in pg (mediawiki)', false, true ); */ + /* $this->addOption( 'dbtsearch2schema', 'The schema for the tsearch2 DB in pg (public)', false, true ); */ /* $this->addOption( 'namespace', 'The project namespace (same as the name)', false, true ); */ } public function execute() { - $installer = new CliInstaller( $this->mArgs[0], $this->mArgs[1], $this->mOptions ); + $adminName = isset( $this->mArgs[1] ) ? $this->mArgs[1] : null; + + $installer = + new CliInstaller( $this->mArgs[0], $adminName, $this->mOptions ); $installer->execute(); } -- 2.20.1