Commit deb7d5f3 authored by Francois Marier's avatar Francois Marier Committed by Gerrit Code Review
Browse files

Merge changes I7eaff22f,I9f13de74

* changes:
  Add CLI Installer and Upgrade (Bug #844604)
  Add CLI Library (Bug #844607)
parents aa407d63 22e450eb
<?php
/**
* Mahara: Electronic portfolio, weblog, resume builder and social networking
* Copyright (C) 2011 Andrew Nicols <andrew.nicols@luns.net.uk>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package mahara
* @subpackage core
* @author Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
*/
define('INTERNAL', 1);
define('ADMIN', 1);
define('INSTALLER', 1);
define('CLI', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
require(get_config('libroot') . 'cli.php');
require(get_config('libroot') . 'upgrade.php');
require(get_config('docroot') . 'local/install.php');
$cli = get_cli();
$options = array();
$options['adminpassword'] = new stdClass();
$options['adminpassword']->examplevalue = 'Password1!';
$options['adminpassword']->shortoptions = array('p');
$options['adminpassword']->description = get_string('cliadminpassword', 'admin');
$options['adminpassword']->required = true;
$options['adminemail'] = new stdClass();
$options['adminemail']->examplevalue = 'user@example.org';
$options['adminemail']->shortoptions = array('e');
$options['adminemail']->description = get_string('cliadminemail', 'admin');
$options['adminemail']->required = true;
$settings = new stdClass();
$settings->options = $options;
$settings->info = get_string('cliinstallerdescription', 'admin');
$cli->setup($settings);
// Check whether we need to do anything
if (table_exists(new XMLDBTable('config'))) {
cli::cli_exit(get_string('maharainstalled', 'admin'), false);
}
// Check initial password and e-mail address before we install
try {
$adminpassword = $cli->get_cli_param('adminpassword');
$adminemail = $cli->get_cli_param('adminemail');
}
catch (ParameterException $e) {
cli::cli_exit($e->getMessage(), true);
}
// Determine what we will install
$upgrades = check_upgrades();
$upgrades['firstcoredata'] = true;
$upgrades['localpreinst'] = true;
$upgrades['lastcoredata'] = true;
$upgrades['localpostinst'] = true;
// Actually perform the installation
log_info(get_string('cliinstallingmahara', 'admin'));
upgrade_mahara($upgrades);
// Set initial password and e-mail address
$userobj = new User();
$userobj = $userobj->find_by_username('admin');
$userobj->email = $adminemail;
$userobj->commit();
// Password changes should be performed by the authfactory
$authobj = AuthFactory::create($userobj->authinstance);
$authobj->change_password($userobj, $adminpassword, true);
<?php
/**
* Mahara: Electronic portfolio, weblog, resume builder and social networking
* Copyright (C) 2011 Andrew Nicols <andrew.nicols@luns.net.uk>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package mahara
* @subpackage core
* @author Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
*/
define('INTERNAL', 1);
define('ADMIN', 1);
define('INSTALLER', 1);
define('CLI', 1);
require(dirname(dirname(dirname(__FILE__))) . '/init.php');
require(get_config('libroot') . 'cli.php');
require(get_config('libroot') . 'upgrade.php');
require(get_config('docroot') . 'local/install.php');
$cli = get_cli();
$options = array();
$settings = new stdClass();
$settings->options = $options;
$settings->info = get_string('cliupgraderdescription', 'admin');
$cli->setup($settings);
// Check whether Mahara is installed yet
if (!table_exists(new XMLDBTable('config'))) {
cli::cli_exit(get_string('maharanotinstalled', 'admin'), false);
}
// Check whether we need to do anything
$upgrades = check_upgrades();
if (!$upgrades) {
cli::cli_exit(get_string('noupgrades', 'admin'), false);
}
// Check for issues which would pose problems during upgrade
ensure_upgrade_sanity();
// Actually perform the upgrade
log_info(get_string('cliupgradingmahara', 'admin'));
upgrade_mahara($upgrades);
......@@ -308,7 +308,9 @@ if (!get_config('installed')) {
$scriptfilename = str_replace('\\', '/', $_SERVER['SCRIPT_FILENAME']);
if (false === strpos($scriptfilename, 'admin/index.php')
&& false === strpos($scriptfilename, 'admin/upgrade.php')
&& false === strpos($scriptfilename, 'admin/upgrade.json.php')) {
&& false === strpos($scriptfilename, 'admin/upgrade.json.php')
&& false === strpos($scriptfilename, 'admin/cli/install.php')
&& false === strpos($scriptfilename, 'admin/cli/upgrade.php')) {
redirect('/admin/');
}
}
......
......@@ -40,6 +40,7 @@ $string['coredata'] = 'core data';
$string['coredatasuccess'] = 'Successfully installed core data';
$string['fromversion'] = 'From version';
$string['information'] = 'Information';
$string['installingplugin'] = 'Installing %s';
$string['installsuccess'] = 'Successfully installed version ';
$string['toversion'] = 'To version';
$string['localdatasuccess'] = 'Successfully installed local customisations';
......@@ -53,6 +54,7 @@ $string['thefollowingupgradesareready'] = 'The following upgrades are ready:';
$string['registerthismaharasite'] = 'Register this Mahara site';
$string['upgradeloading'] = 'Loading...';
$string['upgrades'] = 'Upgrades';
$string['upgradingplugin'] = 'Upgrading %s';
$string['upgradesuccess'] = 'Successfully upgraded';
$string['upgradesuccesstoversion'] = 'Successfully upgraded to version ';
$string['upgradefailure'] = 'Failed to upgrade!';
......@@ -63,6 +65,14 @@ $string['Plugin'] = 'Plugin';
$string['jsrequiredforupgrade'] = 'You must enable javascript to perform an install or upgrade.';
$string['dbnotutf8warning'] = 'You are not using a UTF-8 database. Mahara stores all data as UTF-8 internally. You may still attempt this upgrade but it is recommended that you convert your database to UTF-8.';
$string['dbcollationmismatch'] = 'A column of your database is using a collation that is not the same as the database default. Please ensure all columns use the same collation as the database.';
$string['maharainstalled'] = 'Mahara is already installed';
$string['cliadminpassword'] = 'The password for the admin user';
$string['cliadminemail'] = 'The e-mail address for the admin user';
$string['cliinstallerdescription'] = 'Install the Mahara and create required data directories';
$string['cliinstallingmahara'] = 'Installing Mahara';
$string['cliupgraderdescription'] = 'Upgrade the mahara database and data to the version of mahara installed';
$string['cliupgradingmahara'] = 'Upgrading Mahara';
$string['maharanotinstalled'] = 'Mahara is not currently installed. Please install mahara before trying to upgrade';
// Admin navigation menu
$string['adminhome'] = 'Admin home';
......
<?php
/**
* Mahara: Electronic portfolio, weblog, resume builder and social networking
* Copyright (C) 2011 Andrew Nicols <andrew.nicols@luns.net.uk>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package mahara
* @subpackage lib
* @author Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
*/
/**
* Command Line Interface Class for mahara
*
* Two methods of use are currently supported:
* * basic; and
* * extended.
*
* In basic use, the CLI can be used to retrieve parameters passed on the
* command line. For example, when called as:
*
* php htdocs/admin/cli/example.php --argument=value --argument2 -x -q=n pony
*
* the library could be used to determine the argument options as follows:
*
* <?php
*
* define('CLI', true);
* define('INTERNAL', true);
* include(dirname(dirname(__FILE__)) . '/init.php');
*
* $cli = get_cli();
* $cli->set_cli_shortoptions(array('x' => 'argumentx', 'q' => 'question'));
* $argument = $cli->get_cli_param('argument');
* $argument = $cli->get_cli_param('argument2');
* $argument = $cli->get_cli_param('argumentx');
* $argument = $cli->get_cli_param('question');
* $argument = $cli->get_cli_unmatched();
*
*
* In the extended version, a greater degree of setup is required, but a
* number of other benefits are available as a result, including:
* * help and usage generation;
* * built-in verbosity support; and
* * built-in argument validation.
*
* The following sample code demonstrates how to use the extended version:
* <?php
*
* define('CLI', true);
* define('INTERNAL', true);
* include(dirname(dirname(__FILE__)) . '/init.php');
*
* $cli = get_cli();
*
* $options = array();
* $options['argument'] = new stdClass();
* $options['argument']->exampleValue = 'value';
* $options['argument']->description = 'This is an example description for argument';
*
* $options['argument2'] = new stdClass();
* $options['argument2']->description = 'This is an example description for argument2 - it takes no value';
*
* $options['argumentx'] = new stdClass();
* $options['argumentx']->description = 'This is an example description for argumentx - it takes no value and has an alias';
* $options['argumentx']->shortoptions = array('x');
*
* $options['question'] = new stdClass();
* $options['question']->exampleValue = 'value';
* $options['question']->description = 'This is an example description for question - it typicaly takes an argument and has an alias of q';
* $options['question']->shortoptions = array('q');
*
* $settings = new stdClass();
* $settings->options = $options;
* $settings->allowunmatched = true;
* $settings->info = 'Some information about what this script does';
*
* $cli->setup($settings);
*/
class cli {
/**
* Store the short option mapping information
*/
private $shortoptions = array();
/**
* Store default option values in a readily available format
*/
private $defaultvalues = array();
/**
* Store the arguments given on the CLI
*/
private $arguments = null;
/**
* Store any unmatched entries not recognised as valid arguments
*/
private $unmatched = null;
/**
* By default, allow unmatched text in the data stream to allow for
* simple use. This will be turned off by anyone calling setup()
*/
private $allowunmatched = true;
/**
* Store the settings passed in
*/
private $settings = null;
/**
* Set up the CLI interface correctly
*
* @param object settings The settings to work with
* @return void
*/
public function setup($settings) {
// Handle various options
$this->allowunmatched = (isset($settings->allowunmatched)) ? $settings->allowunmatched : false;
// Add verbosity and help options
$help = new stdClass();
$help->shortoptions = array('h');
$help->description = 'Display this help and usage information';
$settings->options['help'] = $help;
$verbose = new stdClass();
$verbose->shortoptions = array('v');
$verbose->description = 'Increase verbosity of the CLI script to show more information';
$settings->options['verbose'] = $verbose;
// Process longoption configuraiton
foreach ($settings->options as $name => $optionsettings) {
// Store the default value
$this->defaultvalues[$name] = (isset($optionsettings->defaultvalue)) ? $optionsettings->defaultvalue : false;
// By default this value isn't required
$optionsettings->required = (isset($optionsettings->required)) ? $optionsettings->required : false;
// Set the default description
if (!isset($optionsettings->description)) {
$optionsettings->description = '';
}
// Check all short options
if (isset($optionsettings->shortoptions)) {
foreach ($optionsettings->shortoptions AS $k => $shortoption) {
$this->shortoptions[$shortoption] = $name;
}
}
else {
$optionsettings->shortoptions = array();
}
}
// Store all settings for any access required later
$this->settings = $settings;
// Validate the options given
$this->validate_options();
// Process default arguments
$this->process_default_arguments();
}
/**
* Process the default arguments supplied if this script was called by
* using the extended method.
*
* If the verbose option is called, verbosity is increased to screen
* for all targets - dbg, info, warn, and environ.
* If the help option is called, then the help and usage information is
* printed using {@see cli_print_help}.
* @return void
*/
private function process_default_arguments() {
global $CFG;
// Check for verbosity
$verbose = $this->get_cli_param('verbose');
if ($verbose) {
$CFG->log_dbg_targets = LOG_TARGET_SCREEN | LOG_TARGET_ERRORLOG;
$CFG->log_info_targets = LOG_TARGET_SCREEN | LOG_TARGET_ERRORLOG;
$CFG->log_warn_targets = LOG_TARGET_SCREEN | LOG_TARGET_ERRORLOG;
$CFG->log_environ_targets = LOG_TARGET_SCREEN | LOG_TARGET_ERRORLOG;
}
// Check for usage/help request
$help = $this->get_cli_param('help');
if ($help) {
$this->cli_print_help();
}
}
/**
* Set the Short Option to Long Option mapping for basic usage
*
* @param array $shortoptions An associative array mapping the short
* option to the long option name
* @return void
*/
public function set_cli_shortoptions($shortoption) {
$this->shortoptions = $shortoption;
}
/**
* Compile the list of CLI arguments
*
* The following options are valid:
*
* --foo=bar
* -foo=bar
* --example-flag-without-content
* -example-flag-without-content
*
* It is not possible to have any whitespace between the = and any values
*
* Any other values are ignored and no warnings are issued
*
* @return array of specified variables
*/
public function _get_cli_params() {
global $argv;
if ($this->arguments && $this->unmatched) {
return array($this->arguments, $this->unmatched);
}
// We want to manipulate the arguments. Doing so on $argv would be
// pretty rude
$options = $argv;
// Remove the script name
unset ($options[0]);
// Trim off anything after a -- with no arguments
if (($key = array_search('--', $options)) !== false) {
$options = array_slice($options, 0, $key);
}
$this->arguments = array();
$this->unmatched = array();
foreach ($options as $argument) {
// Attempt to match arguments
preg_match('/^(-(-)?)([^=]*)(=(.*))?$/', $argument, $matches);
if (count($matches) && !empty($matches[3])) {
$argname = $matches[3];
if ($matches[1] == '-' && isset($this->shortoptions[$argname])) {
$argname = $this->shortoptions[$argname];
}
$argdata = isset($matches[5]) ? $matches[5] : true;
$this->arguments[$argname] = $argdata;
}
else {
// The argument didn't match a known setting so store it in
// case this was expected
$this->unmatched[] = $argument;
}
}
return array($this->arguments, $this->unmatched);
}
/**
* Retrieve the specified CLI argument
*
* @param string $name The name of the argument to retrieve
* @param mixed $default The default value for the parameter
* @return mixed the value of that parameter, or true if the value has no
* paramter but is set
*/
public function _get_cli_param($name) {
list($cliparams) = $this->_get_cli_params();
if (isset($cliparams[$name])) {
$value = $cliparams[$name];
}
else if (isset($this->defaultvalues[$name])) {
return array($this->defaultvalues[$name], true);
}
else if (func_num_args() == 2) {
$php_work_around = func_get_arg(1);
return array($php_work_around, true);
}
else {
throw new ParameterException("Missing parameter '$name' and no default supplied");
}
return array($value, false);
}
/**
* Retrieve the value of the command line argument for the specified
* setting.
*
* @param string $name The name of the argument to retrieve
* @param mixed $default The default value to use if the argument was not
* specified
* @return mixed
*/
public function get_cli_param($name) {
$args = func_get_args();
list ($value) = call_user_func_array(array($this, '_get_cli_param'), $args);
return $value;
}
/**
* Retrieve all data supplied on the command line which was not
* specified as an argument
*
* @return array All arguments specified, split on whitespace
*/
public function get_cli_unmatched() {
list($cliparams, $unmatched) = $this->_get_cli_params();
return $unmatched;
}
/**
* Validate all arguments supplied on the command line
*
* @return void
*/
function validate_options() {
$this->_get_cli_params();
// Check for unmatched data when allowunmatched is not set
if (count($this->unmatched) && !$this->allowunmatched) {
$this->cli_print_help(true);
}
// Check for invalid arguments
foreach ($this->arguments as $argument => $value) {
if (!isset($this->settings->options[$argument])) {
log_info('An invalid argument was specified: ' . $argument);
$this->cli_print_help(true);
}
}
// Check for missing arguments
foreach ($this->settings->options as $argument => $settings) {
if ($settings->required && !isset($this->arguments[$argument])) {
if (isset($settings->required_callback)) {
call_user_func($settings->required_callback);
$this->cli_print();
$this->cli_print_help(true);
}
else {
$this->cli_print('Missing option ' . $argument);
$this->cli_print();
$this->cli_print_help(true);
}
}
}
}
/**
* Exit the program with a message and set the exit status appropriately
*
* @param string $message The message to output
* @param mixed $error false if exiting normally; true or the expected
* error code if exiting abnormally. If true is used, then an exit code of
* 127 is used
* @return void
*/
public function cli_exit($message = null, $error = false) {
if ($message) {
print($message . "\n");
}
if ($error === false) {
$exitcode = 0;
}
else if ($error === true || !is_int($error)) {
$exitcode = 127;
}
exit($exitcode);
}
/**
* Print out a message formatted for the command line
*
* @param string $message The message to output
* @return void
*/
public function cli_print($message = '') {
print($message . "\n");
}
/**
* Print the help and usage information for this CLI script
*
* If a description is supplied for an argument, then this is
* word-wrapped to standard terminal lengths. All available options are
* also displayed.
*
* @param integer $exitcode The exit code to use, or true to indicate
* an error - {@see cli_exit}
*/
public function cli_print_help($exitcode = 0) {
// Display usage information
printf ("Usage: %s ", basename(__FILE__));
$options = array();
foreach ($this->settings->options as $option => $settings) {
$optiondisplay = '--' . $option;
if (isset($settings->examplevalue)) {
$optiondisplay .= '=' . $settings->examplevalue;
}
if (!$settings->required) {
$optiondisplay = '[' . $optiondisplay . ']';
}
$options[] = $optiondisplay;