* consolidate some installer functionals into the Installer class
authorMark A. Hershberger <mah@users.mediawiki.org>
Sun, 27 Jun 2010 21:48:51 +0000 (21:48 +0000)
committerMark A. Hershberger <mah@users.mediawiki.org>
Sun, 27 Jun 2010 21:48:51 +0000 (21:48 +0000)
* 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
includes/AutoLoader.php
includes/installer/CliInstaller.php
includes/installer/CliInstallerOutput.php [new file with mode: 0644]
includes/installer/Installer.php
maintenance/Maintenance.php
maintenance/doMaintenance.php
maintenance/install.php

index de0a814..2291dc2 100644 (file)
@@ -1,35 +1,12 @@
 <?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();
index b4ae511..6571c9e 100644 (file)
@@ -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',
index 307762e..2e1ecd1 100644 (file)
@@ -1,24 +1,41 @@
 <?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'] );
@@ -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 (file)
index 0000000..55c239c
--- /dev/null
@@ -0,0 +1,83 @@
+<?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() {}
+
+}
index 3cc8a3f..38ecde1 100644 (file)
@@ -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;
+       }
 }
index 31d737c..75dd663 100644 (file)
@@ -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;
index a1cd457..1fc50b1 100644 (file)
@@ -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" ) )
 {
index d68ae27..70bc30c 100644 (file)
  * @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();
        }