<?php
-define( 'MW_NO_DB', 1 );
-define( 'MW_NO_SESSION', 1 );
-define( 'MW_CONFIG_CALLBACK', 'wfInstallerConfig' );
-
-function wfInstallerConfig() {
- // 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;
-}
+define( 'MW_CONFIG_CALLBACK', 'Installer::overrideConfig' );
chdir( ".." );
require( './includes/WebStart.php' );
require_once( './maintenance/updaters.inc' ); // sigh...
-// Disable the i18n cache and LoadBalancer
-Language::getLocalisationCache()->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();
# 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',
<?php
-function wfInstallerConfig() {
- // 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;
-}
-
class CliInstaller extends Installer {
+ /* The maintenance class in effect */
+ private $maint;
+
+ private $optionMap = array(
+ 'dbtype' => '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'] );
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();
}
}
--- /dev/null
+<?php
+
+/**
+ * Output class modelled on OutputPage.
+ *
+ * I've opted to use a distinct class rather than derive from OutputPage here in
+ * the interests of separation of concerns: if we used a subclass, there would be
+ * quite a lot of things you could do in OutputPage that would break the installer,
+ * that wouldn't be immediately obvious.
+ */
+class CliInstallerOutput {
+
+ function __construct( $parent ) {
+ $this->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 .= "<p>$msg</p>\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() {}
+
+}
* 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];
}
}
- /*
+ /**
* On POSIX systems return the primary group of the webserver we're running under.
* On other systems just returns null.
*
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;
+ }
}
* 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 ) {
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' );
$die = true;
}
}
-
+
if ( $die ) {
$this->maybeHelp( true );
}
$screenWidth = 80; // TODO: Caculate this!
$tab = " ";
$descWidth = $screenWidth - ( 2 * strlen( $tab ) );
-
+
ksort( $this->mParams );
if ( $this->hasOption( 'help' ) || $force ) {
$this->mQuiet = false;
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;
} else {
require_once( $maintenance->loadSettings() );
}
+
if ( $maintenance->getDbType() === Maintenance::DB_ADMIN &&
is_readable( "$IP/AdminSettings.php" ) )
{
* @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();
}