diff --git a/setup/applications.php b/setup/applications.php index 78043dfed7..d6d952fe33 100644 --- a/setup/applications.php +++ b/setup/applications.php @@ -127,7 +127,7 @@ if(@get_var('submit',Array('POST'))) { $app_title = $setup_info[$appname]['title'] ? $setup_info[$appname]['title'] : $setup_info[$appname]['name']; $terror = array(); - $terror[] = $setup_info[$appname]; + $terror[$appname] = $setup_info[$appname]; if ($setup_info[$appname]['tables']) { @@ -162,7 +162,7 @@ if(@get_var('submit',Array('POST'))) { $app_title = $setup_info[$appname]['title'] ? $setup_info[$appname]['title'] : $setup_info[$appname]['name']; $terror = array(); - $terror[] = $setup_info[$appname]; + $terror[$appname] = $setup_info[$appname]; if ($setup_info[$appname]['tables']) { @@ -173,6 +173,8 @@ if(@get_var('submit',Array('POST'))) } else { + // check default_records for apps without tables, they might need some initial work too + $terror = $GLOBALS['egw_setup']->process->default_records($terror,$DEBUG); if ($GLOBALS['egw_setup']->app_registered($setup_info[$appname]['name'])) { $GLOBALS['egw_setup']->update_app($setup_info[$appname]['name']); @@ -199,7 +201,7 @@ if(@get_var('submit',Array('POST'))) { $app_title = $setup_info[$appname]['title'] ? $setup_info[$appname]['title'] : $setup_info[$appname]['name']; $terror = array(); - $terror[] = $setup_info[$appname]; + $terror[$appname] = $setup_info[$appname]; $GLOBALS['egw_setup']->process->upgrade($terror,$DEBUG); if ($setup_info[$appname]['tables']) diff --git a/setup/inc/class.setup_detection.inc.php b/setup/inc/class.setup_detection.inc.php index 515d6347c7..e141c04a1d 100755 --- a/setup/inc/class.setup_detection.inc.php +++ b/setup/inc/class.setup_detection.inc.php @@ -6,12 +6,21 @@ * @package setup * @author Dan Kuykendall * @author Miles Lott + * @author Ralf Becker * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @version $Id$ */ +/** + * Class detecting the current installation status of EGroupware + */ class setup_detection { + /** + * Get available application versions and data from filesystem + * + * @return array $setup_info + */ function get_versions() { $d = dir(EGW_SERVER_ROOT); @@ -34,7 +43,13 @@ class setup_detection return $setup_info; } - function get_db_versions($setup_info='') + /** + * Get versions of installed applications from database + * + * @param array $setup_info + * @return array $setup_info + */ + function get_db_versions($setup_info=null) { $tname = Array(); $GLOBALS['egw_setup']->db->Halt_On_Error = 'no'; @@ -97,16 +112,17 @@ class setup_detection return $setup_info; } - /* app status values: - U Upgrade required/available - R upgrade in pRogress - C upgrade Completed successfully - D Dependency failure - P Post-install dependency failure - F upgrade Failed - V Version mismatch at end of upgrade (Not used, proposed only) - M Missing files at start of upgrade (Not used, proposed only) - */ + /** + * Compare versions from filesystem and database and set status: + * U Upgrade required/available + * R upgrade in pRogress + * C upgrade Completed successfully + * D Dependency failure + * P Post-install dependency failure + * F upgrade Failed + * V Version mismatch at end of upgrade (Not used, proposed only) + * M Missing files at start of upgrade (Not used, proposed only) + */ function compare_versions($setup_info) { foreach($setup_info as $key => $value) @@ -208,10 +224,10 @@ class setup_detection return $setup_info; } - /* - Called during the mass upgrade routine (Stage 1) to check for apps - that wish to be excluded from this process. - */ + /** + * Called during the mass upgrade routine (Stage 1) to check for apps + * that wish to be excluded from this process. + */ function upgrade_exclude($setup_info) { foreach($setup_info as $key => $value) @@ -224,6 +240,11 @@ class setup_detection return $setup_info; } + /** + * Check if header exists and is up to date + * + * @return int 1=no header.inc.php, 2=no header admin pw, 3=no instances, 4=need upgrade, 10=ok + */ function check_header() { if(!file_exists('../header.inc.php')) @@ -254,6 +275,12 @@ class setup_detection return '10'; } + /** + * Check if database exists + * + * @param array $setup_info + * @return int 1=no database, 3=empty, 4=need upgrade, 10=complete + */ function check_db($setup_info='') { $setup_info = $setup_info ? $setup_info : $GLOBALS['setup_info']; diff --git a/setup/inc/class.setup_process.inc.php b/setup/inc/class.setup_process.inc.php index 0cf06832e2..5f0fb3b1ef 100755 --- a/setup/inc/class.setup_process.inc.php +++ b/setup/inc/class.setup_process.inc.php @@ -1,373 +1,358 @@ * - * Originally written for phpGroupWare. * - * (C) 2001-2004 Miles Lott * - * Upgrade process rewritten by to no * - * longer require tables_baseline files and delta-upgrades * - * -------------------------------------------- * - * 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 2 of the License, or (at your * - * option) any later version. * - \**************************************************************************/ - /* $Id$ */ +/** + * EGroupware setup - update / install an EGroupware instance + * + * @link http://www.egroupware.org + * @author Miles Lott + * @copyright 2001-2004 Miles Lott + * @author Ralf Becker + * Upgrade process rewritten by to no longer require tables_baseline files and delta-upgrades + * @package setup + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id$ + */ - /* app status values: - U Upgrade required/available - R upgrade in pRogress - C upgrade Completed successfully - D Dependency failure - F upgrade Failed - V Version mismatch at end of upgrade (Not used, proposed only) - M Missing files at start of upgrade (Not used, proposed only) - */ +/** + * Update / install an EGroupware instance + * + * app status values: + * U Upgrade required/available + * R upgrade in pRogress + * C upgrade Completed successfully + * D Dependency failure + * F upgrade Failed + * V Version mismatch at end of upgrade (Not used, proposed only) + * M Missing files at start of upgrade (Not used, proposed only) + */ +class setup_process +{ + var $tables; + var $updateincluded = array(); - class setup_process + /** + * Target version of a complete upgrade, set by pass() + * + * @var string + */ + var $api_version_target; + + /** + * instance of setup's translation class + * + * @var setup_translation + */ + var $translation; + + /** + * Constructor + */ + function __construct() { - var $oProc; - var $tables; - var $updateincluded = array(); - var $translation; + $this->translation = new setup_translation(); + } - function setup_process() + /** + * create schema_proc object + * + * @param none + */ + function init_process() + { + $GLOBALS['egw_setup']->oProc = new schema_proc(); + } + + /** + * the mother of all multipass upgrade parental loop functions + * + * @param array $setup_info array of application info from setup.inc.php files + * @param string $type='new' defaults to new(install), could also be 'upgrade' + * @param boolean $DEBUG=false print debugging info + * @param boolean $force_en=false install english language files + * @param string $system_charset=null charset to use + * @param array $preset_config=array() + */ + function pass(array $setup_info,$method='new',$DEBUG=False,$force_en=False,$preset_config=array()) + { + if(!$method) { - $this->translation =& CreateObject('setup.setup_translation'); + return False; } + // Place api first + $pass['phpgwapi'] = $setup_info['phpgwapi']; + $pass['admin'] = $setup_info['admin']; + $pass['preferences'] = $setup_info['preferences']; + $pass['etemplate'] = $setup_info['etemplate']; // helps to minimize passes, as many apps depend on it + @reset($setup_info); + $setup_info = $GLOBALS['egw_setup']->detection->get_versions($setup_info); + @reset($setup_info); - /** - * create schema_proc object - * - * @param none - */ - function init_process() + // setting api-target-version for general use + $this->api_version_target = $setup_info['phpgwapi']['version']; + + $i = 1; + $passed = array(); + $passing = array(); + $pass_string = implode (':', $pass); + $passing_string = implode (':', $passing); + $do_langs = false; + while($pass_string != $passing_string) { - $GLOBALS['egw_setup']->oProc =& CreateObject('phpgwapi.schema_proc'); - } - - /** - * the mother of all multipass upgrade parental loop functions - * - * @param array $setup_info array of application info from setup.inc.php files - * @param string $type='new' defaults to new(install), could also be 'upgrade' - * @param boolean $DEBUG=false print debugging info - * @param boolean $force_en=false install english language files - * @param string $system_charset=null charset to use - * @param array $preset_config=array() - */ - function pass($setup_info,$method='new',$DEBUG=False,$force_en=False,$preset_config=array()) - { - if(!$method) - { - return False; - } - // Place api first - $pass['phpgwapi'] = $setup_info['phpgwapi']; - $pass['admin'] = $setup_info['admin']; - $pass['preferences'] = $setup_info['preferences']; - @reset($setup_info); - $setup_info = $GLOBALS['egw_setup']->detection->get_versions($setup_info); - @reset($setup_info); - - $i = 1; - $passed = array(); $passing = array(); - $pass_string = implode (':', $pass); - $passing_string = implode (':', $passing); - $do_langs = false; - while($pass_string != $passing_string) + if($DEBUG) { echo '
process->pass(): #' . $i . ' for ' . $method . ' processing' . "\n"; } + /* Check current versions and dependencies */ + $setup_info = $GLOBALS['egw_setup']->detection->get_db_versions($setup_info); + $setup_info = $GLOBALS['egw_setup']->detection->compare_versions($setup_info); + //_debug_array($setup_info);exit; + $setup_info = $GLOBALS['egw_setup']->detection->check_depends($setup_info); + //if($i==2) { _debug_array($passed);exit; } + + /* stuff the rest of the apps, but only those with available upgrades */ + foreach($setup_info as $key => $value) { - $passing = array(); - if($DEBUG) { echo '
process->pass(): #' . $i . ' for ' . $method . ' processing' . "\n"; } - /* Check current versions and dependencies */ - $setup_info = $GLOBALS['egw_setup']->detection->get_db_versions($setup_info); - $setup_info = $GLOBALS['egw_setup']->detection->compare_versions($setup_info); - //_debug_array($setup_info);exit; - $setup_info = $GLOBALS['egw_setup']->detection->check_depends($setup_info); - //if($i==2) { _debug_array($passed);exit; } - - /* stuff the rest of the apps, but only those with available upgrades */ - while(list($key,$value) = @each($setup_info)) + if (isset($value['only_db']) && ( + is_array($value['only_db']) && !in_array($GLOBALS['egw_setup']->db->Type,$value['only_db']) || + !is_array($value['only_db']) && $GLOBALS['egw_setup']->db->Type != $value['only_db'])) { - if (isset($value['only_db']) && ( - is_array($value['only_db']) && !in_array($GLOBALS['egw_setup']->db->Type,$value['only_db']) || - !is_array($value['only_db']) && $GLOBALS['egw_setup']->db->Type != $value['only_db'])) - { - continue; // app does not support this db-type, dont try installing it - } - if(($value['name'] != 'phpgwapi') && ($value['status'] == 'U')) - { - if(($passed[$value['name']]['status'] != 'F') && ($passed[$value['name']]['status'] != 'C')) - { - $pass[$value['name']] = $setup_info[$value['name']]; - } - } - /* - Now if we are on the 2nd or more passes, add api in - if (!$pass['phpgwapi']) - { - $pass['phpgwapi'] = $setup_info['phpgwapi']; - } - */ + continue; // app does not support this db-type, dont try installing it } - - switch($method) + if($value['name'] != 'phpgwapi' && $value['status'] == 'U') { - case 'new': - /* Create tables and insert new records for each app in this list */ - $passing = $this->current($pass,$DEBUG); - $this->save_minimal_config($preset_config); - $passing = $this->default_records($passing,$DEBUG); - $do_langs = true; // just do it once at the end of all passes - break; - case 'upgrade': - /* Run upgrade scripts on each app in the list */ - $passing = $this->upgrade($pass,$DEBUG); - $do_langs = true; // just do it once at the end of all passes - //_debug_array($pass);exit; - break; - default: - /* What the heck are you doing? */ - return False; - break; - } - - $pass = array(); - @reset($passing); - while(list($key,$value) = @each($passing)) - { - if($value['status'] == 'C') - { - $passed[$value['name']] = $passing[$value['name']]; - if($DEBUG) { echo '
process->pass(): '.$passed[$value['name']]['name'] . ' install completed'."\n"; } - } - elseif($value['status'] == 'F') - { - $setup_info[$value['name']] = $passing[$value['name']]; - if($DEBUG) { echo '
process->pass(): '.$setup_info[$value['name']]['name'] . ' install failed'."\n"; } - } - elseif($value['status'] == 'D') + if($passed[$value['name']]['status'] != 'F' && $passed[$value['name']]['status'] != 'C') { $pass[$value['name']] = $setup_info[$value['name']]; - if($DEBUG) { echo '
process->pass(): '.$pass[$value['name']]['name'] . ' fails dependency check on this pass'."\n"; } - } - else - { - $tmp = $passing[$value['name']]['name']; - if($DEBUG) { echo '
process->pass(): '.$tmp . ' skipped on this pass'."\n"; } } } + } - $i++; - if($i == 20) /* Then oops it broke */ + switch($method) + { + case 'new': + /* Create tables and insert new records for each app in this list */ + $passing = $this->current($pass,$DEBUG); + $this->save_minimal_config($preset_config); + $passing = $this->default_records($passing,$DEBUG); + $do_langs = true; // just do it once at the end of all passes + break; + case 'upgrade': + /* Run upgrade scripts on each app in the list */ + $passing = $this->upgrade($pass,$DEBUG); + $do_langs = true; // just do it once at the end of all passes + //_debug_array($pass);exit; + break; + default: + /* What the heck are you doing? */ + return False; + break; + } + + $pass = array(); + foreach($passing as $key => $value) + { + if($value['status'] == 'C') { - echo '
Setup failure: excess looping in process->pass():'."\n"; - echo '
Pass:
'."\n"; - _debug_array($pass); - echo '
Passed:
'."\n"; - _debug_array($passed); - exit; + $passed[$value['name']] = $passing[$value['name']]; + if($DEBUG) { echo '
process->pass(): '.$passed[$value['name']]['name'] . ' install completed'."\n"; } } - $pass_string = implode (':', $pass); - $passing_string = implode (':', $passing); - } - if ($do_langs) // just do it once at the end of all passes - { - $langs = false; - if ($method == 'new') + elseif($value['status'] == 'F') { - $langs[] = ($own_lang = get_var('ConfigLang',Array('POST','COOKIE'))); - if ($own_lang != 'en') $langs[] = 'en'; + $setup_info[$value['name']] = $passing[$value['name']]; + if($DEBUG) { echo '
process->pass(): '.$setup_info[$value['name']]['name'] . ' install failed'."\n"; } } - $this->translation->drop_add_all_langs($langs); - } - /* now return the list */ - return $setup_info = array_merge($setup_info,$passed); - } - - /** - * saves a minimal default config, so you get a running install without entering and saveing Step #2 config - * - * @param array $preset_config=array() - */ - function save_minimal_config(array $preset_config=array()) - { - $is_windows = strtoupper(substr(PHP_OS,0,3)) == 'WIN'; - - $current_config['site_title'] = 'eGroupWare'; - $current_config['hostname'] = $_SERVER['HTTP_HOST'] ? $_SERVER['HTTP_HOST'] : 'localhost'; - - // guessing the eGW url - $parts = explode('/',$_SERVER['PHP_SELF']); - array_pop($parts); // remove config.php - array_pop($parts); // remove setup - $current_config['webserver_url'] = implode('/',$parts); - $egroupwareDirName = end($parts); - - if(!$is_windows) { - if(@is_dir('/tmp')) { - $current_config['temp_dir'] = '/tmp'; - } else { - $current_config['temp_dir'] = '/path/to/temp/dir'; - } - $current_config['files_dir'] = '/var/lib/'.$egroupwareDirName.'/'.$GLOBALS['egw_setup']->ConfigDomain.'/files'; - $current_config['backup_dir'] = '/var/lib/'.$egroupwareDirName.'/'.$GLOBALS['egw_setup']->ConfigDomain.'/backup'; - } else { - if(@is_dir('c:\\windows\\temp')) { - $current_config['temp_dir'] = 'c:\\windows\\temp'; - } else { - $current_config['temp_dir'] = 'c:\\path\\to\\temp\\dir'; - } - $current_config['files_dir'] = 'c:\\Program files\\'.$egroupwareDirName.'\\'.$GLOBALS['egw_setup']->ConfigDomain.'\\files'; - $current_config['backup_dir'] = 'c:\\Program files\\'.$egroupwareDirName.'\\'.$GLOBALS['egw_setup']->ConfigDomain.'\\backup'; - } - $datetime =& CreateObject('phpgwapi.egw_datetime'); - $current_config['tz_offset'] = $datetime->getbestguess(); - unset($datetime); - - // RalfBecker: php.net recommend this for security reasons, it should be our default too - $current_config['usecookies'] = 'True'; - - if ($GLOBALS['egw_setup']->system_charset) - { - $current_config['system_charset'] = $GLOBALS['egw_setup']->system_charset; - } - - $current_config['install_id'] = md5($_SERVER['HTTP_HOST'].microtime(true).$GLOBALS['egw_setup']->ConfigDomain); - - if ($preset_config) - { - $current_config = array_merge($current_config,$preset_config); - } - - foreach($current_config as $name => $value) - { - $GLOBALS['egw_setup']->db->insert($GLOBALS['egw_setup']->config_table,array( - 'config_value' => $value, - ),array( - 'config_app' => 'phpgwapi', - 'config_name' => $name, - ),__FILE__,__LINE__); - } - - // so the default_records use the current data - $GLOBALS['egw_setup']->setup_account_object($current_config); - } - - /** - * drop tables per application, check that they are in the db first - * - * @param $setup_info array of application info from setup.inc.php files, etc. - */ - function droptables($setup_info,$DEBUG=False) - { - if(!@$GLOBALS['egw_setup']->oProc) - { - $this->init_process(); - } - /* The following is built so below we won't try to drop a table that isn't there. */ - $tablenames = $GLOBALS['egw_setup']->db->table_names(); - if (!is_array($setup_info) || !is_array($tablenames)) - { - return $setup_info; // nothing to do - } - $tables = array(); - foreach($tablenames as $data) - { - $tables[] = $data['table_name']; - } - - if (!is_array($setup_info)) - { - return $setup_info; - } - foreach($setup_info as $app_name => $data) - { - if(is_array($data['tables'])) + elseif($value['status'] == 'D') { - foreach($data['tables'] as $table) - { - //echo $table; - if(in_array($table,$tables)) - { - if($DEBUG){ echo '
process->droptables(): Dropping :'. $app_name . ' table: ' . $table; } - $GLOBALS['egw_setup']->oProc->DropTable($table); - // Update the array values for return below - $setup_info[$app_name]['status'] = 'U'; - } - } - } - } - - /* Done, return current status */ - return $setup_info; - } - - /** - * process current table setup in each application/setup dir - * - * @param array $setup_info array of application info from setup.inc.php files, etc. - * @param boolean $DEBUG=false - */ - function current($setup_info,$DEBUG=False) - { - if(!@$GLOBALS['egw_setup']->oProc) - { - $this->init_process(); - } - @reset($setup_info); - while(list($key,$null) = @each($setup_info)) - { - $enabled = False; - $appname = $setup_info[$key]['name']; - $apptitle = $setup_info[$key]['title']; - - if($DEBUG) { echo '
process->current(): Incoming status: ' . $appname . ',status: '. $setup_info[$key]['status']; } - - $appdir = EGW_SERVER_ROOT . SEP . $appname . SEP . 'setup' . SEP; - - if($setup_info[$key]['tables'] && file_exists($appdir.'tables_current.inc.php')) - { - if($DEBUG) { echo '
process->current(): Including: ' . $appdir.'tables_current.inc.php'; } - include ($appdir.'tables_current.inc.php'); - $ret = $this->post_process($phpgw_baseline,$DEBUG); - if($ret) - { - if($GLOBALS['egw_setup']->app_registered($appname)) - { - $GLOBALS['egw_setup']->update_app($appname); - $GLOBALS['egw_setup']->update_hooks($appname); - } - else - { - $GLOBALS['egw_setup']->register_app($appname); - $GLOBALS['egw_setup']->register_hooks($appname); - } - // Update the array values for return below - $setup_info[$key]['status'] = 'C'; - } - else - { - /* script processing failed */ - if($DEBUG) { echo '
process->current(): Failed for ' . $appname . ',status: '. $setup_info[$key]['status']; } - $setup_info[$key]['status'] = 'F'; - } + $pass[$value['name']] = $setup_info[$value['name']]; + if($DEBUG) { echo '
process->pass(): '.$pass[$value['name']]['name'] . ' fails dependency check on this pass'."\n"; } } else { - if($DEBUG) { echo '
process->current(): No current tables for ' . $apptitle . "\n"; } - /* - Add the app, but disable it if it has tables defined. - A manual sql script install is needed, but we do add the hooks - */ - $enabled = 99; - if($setup_info[$key]['tables'][0] != '') + $tmp = $passing[$value['name']]['name']; + if($DEBUG) { echo '
process->pass(): '.$tmp . ' skipped on this pass'."\n"; } + } + } + + $i++; + if($i == 20) /* Then oops it broke */ + { + echo '
Setup failure: excess looping in process->pass():'."\n"; + echo '
Pass:
'."\n"; + _debug_array($pass); + echo '
Passed:
'."\n"; + _debug_array($passed); + exit; + } + $pass_string = implode (':', $pass); + $passing_string = implode (':', $passing); + } + if ($do_langs) // just do it once at the end of all passes + { + $langs = false; + if ($method == 'new') + { + $langs[] = ($own_lang = get_var('ConfigLang',Array('POST','COOKIE'))); + if ($own_lang != 'en') $langs[] = 'en'; + } + $this->translation->drop_add_all_langs($langs); + } + /* now return the list */ + return $setup_info = array_merge($setup_info,$passed); + } + + /** + * saves a minimal default config, so you get a running install without entering and saveing Step #2 config + * + * @param array $preset_config=array() + */ + function save_minimal_config(array $preset_config=array()) + { + $is_windows = strtoupper(substr(PHP_OS,0,3)) == 'WIN'; + + $current_config['site_title'] = 'eGroupWare'; + $current_config['hostname'] = $_SERVER['HTTP_HOST'] ? $_SERVER['HTTP_HOST'] : 'localhost'; + + // guessing the eGW url + $parts = explode('/',$_SERVER['PHP_SELF']); + array_pop($parts); // remove config.php + array_pop($parts); // remove setup + $current_config['webserver_url'] = implode('/',$parts); + $egroupwareDirName = end($parts); + + if(!$is_windows) { + if(@is_dir('/tmp')) + { + $current_config['temp_dir'] = '/tmp'; + } + else + { + $current_config['temp_dir'] = '/path/to/temp/dir'; + } + $current_config['files_dir'] = '/var/lib/'.$egroupwareDirName.'/'.$GLOBALS['egw_setup']->ConfigDomain.'/files'; + $current_config['backup_dir'] = '/var/lib/'.$egroupwareDirName.'/'.$GLOBALS['egw_setup']->ConfigDomain.'/backup'; + } + else + { + if(@is_dir('c:\\windows\\temp')) + { + $current_config['temp_dir'] = 'c:\\windows\\temp'; + } + else + { + $current_config['temp_dir'] = 'c:\\path\\to\\temp\\dir'; + } + $current_config['files_dir'] = 'c:\\Program files\\'.$egroupwareDirName.'\\'.$GLOBALS['egw_setup']->ConfigDomain.'\\files'; + $current_config['backup_dir'] = 'c:\\Program files\\'.$egroupwareDirName.'\\'.$GLOBALS['egw_setup']->ConfigDomain.'\\backup'; + } + $datetime =& CreateObject('phpgwapi.egw_datetime'); + $current_config['tz_offset'] = $datetime->getbestguess(); + unset($datetime); + + // RalfBecker: php.net recommend this for security reasons, it should be our default too + $current_config['usecookies'] = 'True'; + + if ($GLOBALS['egw_setup']->system_charset) + { + $current_config['system_charset'] = $GLOBALS['egw_setup']->system_charset; + } + + $current_config['install_id'] = md5($_SERVER['HTTP_HOST'].microtime(true).$GLOBALS['egw_setup']->ConfigDomain); + + if ($preset_config) + { + $current_config = array_merge($current_config,$preset_config); + } + + foreach($current_config as $name => $value) + { + $GLOBALS['egw_setup']->db->insert($GLOBALS['egw_setup']->config_table,array( + 'config_value' => $value, + ),array( + 'config_app' => 'phpgwapi', + 'config_name' => $name, + ),__FILE__,__LINE__); + } + + // so the default_records use the current data + $GLOBALS['egw_setup']->setup_account_object($current_config); + } + + /** + * drop tables per application, check that they are in the db first + * + * @param $setup_info array of application info from setup.inc.php files, etc. + */ + function droptables(array $setup_info,$DEBUG=False) + { + if(!@$GLOBALS['egw_setup']->oProc) + { + $this->init_process(); + } + /* The following is built so below we won't try to drop a table that isn't there. */ + $tablenames = $GLOBALS['egw_setup']->db->table_names(); + if (!is_array($setup_info) || !is_array($tablenames)) + { + return $setup_info; // nothing to do + } + $tables = array(); + foreach($tablenames as $data) + { + $tables[] = $data['table_name']; + } + + if (!is_array($setup_info)) + { + return $setup_info; + } + foreach($setup_info as $app_name => $data) + { + if(is_array($data['tables'])) + { + foreach($data['tables'] as $table) + { + //echo $table; + if(in_array($table,$tables)) { - $enabled = False; + if($DEBUG){ echo '
process->droptables(): Dropping :'. $app_name . ' table: ' . $table; } + $GLOBALS['egw_setup']->oProc->DropTable($table); + // Update the array values for return below + $setup_info[$app_name]['status'] = 'U'; } + } + } + } + + /* Done, return current status */ + return $setup_info; + } + + /** + * process current table setup in each application/setup dir + * + * @param array $setup_info array of application info from setup.inc.php files, etc. + * @param boolean $DEBUG=false output further diagnostics + * @return array $setup_info + */ + function current(array $setup_info,$DEBUG=False) + { + //echo __METHOD__; _debug_array($setup_info); + if(!isset($GLOBALS['egw_setup']->oProc)) + { + $this->init_process(); + } + foreach($setup_info as $appname => &$appdata) + { + $enabled = False; + $apptitle = $appdata['title']; + + if($DEBUG) { echo '
process->current(): Incoming status: ' . $appname . ',status: '. $appdata['status']; } + + $appdir = EGW_SERVER_ROOT . SEP . $appname . SEP . 'setup' . SEP; + + if($appdata['tables'] && file_exists($appdir.'tables_current.inc.php')) + { + if($DEBUG) { echo '
process->current(): Including: ' . $appdir.'tables_current.inc.php'; } + include ($appdir.'tables_current.inc.php'); + $ret = $this->post_process($phpgw_baseline,$DEBUG); + if($ret) + { if($GLOBALS['egw_setup']->app_registered($appname)) { $GLOBALS['egw_setup']->update_app($appname); @@ -375,306 +360,349 @@ } else { - $GLOBALS['egw_setup']->register_app($appname,$enabled); + $GLOBALS['egw_setup']->register_app($appname); $GLOBALS['egw_setup']->register_hooks($appname); } - $setup_info[$key]['status'] = 'C'; - } - if($DEBUG) { echo '
process->current(): Outgoing status: ' . $appname . ',status: '. $setup_info[$key]['status']; } - } - - /* Done, return current status */ - return ($setup_info); - } - - /** - * process default_records.inc.php in each application/setup dir - * - * @param $setup_info array of application info from setup.inc.php files, etc. - */ - function default_records($setup_info,$DEBUG=False) - { - if(!@$GLOBALS['egw_setup']->oProc) - { - $this->init_process(); - } - @reset($setup_info); - while(list($key,$null) = @each($setup_info)) - { - $appname = $setup_info[$key]['name']; - $appdir = EGW_SERVER_ROOT . SEP . $appname . SEP . 'setup' . SEP; - - if($setup_info[$key]['tables'] && file_exists($appdir.'default_records.inc.php')) - { - if($DEBUG) - { - echo '
process->default_records(): Including default records for ' . $appname . "\n"; - } - $GLOBALS['egw_setup']->oProc->m_odb->transaction_begin(); - $oProc = &$GLOBALS['egw_setup']->oProc; // to be compatible with old apps - include ($appdir.'default_records.inc.php'); - $GLOBALS['egw_setup']->oProc->m_odb->transaction_commit(); - } - /* $setup_info[$key]['status'] = 'C'; */ - } - - /* Done, return current status */ - return ($setup_info); - } - - /** - * process test_data.inc.php in each application/setup dir for developer tests - * - * This data should work with the baseline tables - * @param $setup_info array of application info from setup.inc.php files, etc. - */ - function test_data($setup_info,$DEBUG=False) - { - if(!@$GLOBALS['egw_setup']->oProc) - { - $this->init_process(); - } - @reset($setup_info); - while(list($key,$null) = @each($setup_info)) - { - $appname = $setup_info[$key]['name']; - $appdir = EGW_SERVER_ROOT . SEP . $appname . SEP . 'setup' . SEP; - - if(file_exists($appdir.'test_data.inc.php')) - { - if($DEBUG) - { - echo '
process->test_data(): Including baseline test data for ' . $appname . "\n"; - } - $GLOBALS['egw_setup']->oProc->m_odb->transaction_begin(); - include ($appdir.'test_data.inc.php'); - $GLOBALS['egw_setup']->oProc->m_odb->transaction_commit(); - } - } - - /* Done, return current status */ - return ($setup_info); - } - - /** - * process baseline table setup in each application/setup dir - * - * @param $appinfo array of application info from setup.inc.php files, etc. - */ - function baseline($setup_info,$DEBUG=False) - { - if(!@$GLOBALS['egw_setup']->oProc) - { - $this->init_process(); - } - - @reset($setup_info); - while(list($key,$null) = @each($setup_info)) - { - $appname = $setup_info[$key]['name']; - $appdir = EGW_SERVER_ROOT . SEP . $appname . SEP . 'setup' . SEP; - - if(file_exists($appdir.'tables_baseline.inc.php')) - { - if($DEBUG) - { - echo '
process->baseline(): Including baseline tables for ' . $appname . "\n"; - } - include ($appdir.'tables_baseline.inc.php'); - $GLOBALS['egw_setup']->oProc->GenerateScripts($phpgw_baseline, $DEBUG); - $this->post_process($phpgw_baseline,$DEBUG); - - /* Update the array values for return below */ - /* $setup_info[$key]['status'] = 'R'; */ + // Update the array values for return below + $appdata['status'] = 'C'; } else { - if($DEBUG) - { - echo '
process->baseline(): No baseline tables for ' . $appname . "\n"; - } - //$setup_info[$key]['status'] = 'C'; + /* script processing failed */ + if($DEBUG) { echo '
process->current(): Failed for ' . $appname . ',status: '. $appdata['status']; } + $appdata['status'] = 'F'; } } - - /* Done, return current status */ - return ($setup_info); + else + { + if($DEBUG) { echo '
process->current(): No current tables for ' . $apptitle . "\n"; } + /* + Add the app, but disable it if it has tables defined. + A manual sql script install is needed, but we do add the hooks + */ + $enabled = 99; + if($appdata['tables'][0] != '') + { + $enabled = False; + } + if($GLOBALS['egw_setup']->app_registered($appname)) + { + $GLOBALS['egw_setup']->update_app($appname); + $GLOBALS['egw_setup']->update_hooks($appname); + } + else + { + $GLOBALS['egw_setup']->register_app($appname,$enabled); + $GLOBALS['egw_setup']->register_hooks($appname); + } + $appdata['status'] = 'C'; + } + if($DEBUG) { echo '
process->current(): Outgoing status: ' . $appname . ',status: '. $appdata['status']; } } - /** - * process available upgrades in each application/setup dir - * - * @param $appinfo array of application info from setup.inc.php files, etc. - */ - function upgrade($setup_info,$DEBUG=False) + /* Done, return current status */ + return $setup_info; + } + + /** + * process default_records.inc.php in each application/setup dir + * + * @param array $setup_info array of application info from setup.inc.php files, etc. + * @param boolean $DEBUG=false output further diagnostics + * @return array $setup_info + */ + function default_records(array $setup_info,$DEBUG=False) + { + //echo __METHOD__; _debug_array($setup_info); + if(!@$GLOBALS['egw_setup']->oProc) { - if(!@$GLOBALS['egw_setup']->oProc) - { - $this->init_process(); - } - $GLOBALS['egw_setup']->oProc->m_odb->HaltOnError = 'yes'; + $this->init_process(); + } + foreach($setup_info as $appname => &$appdata) + { + $appdir = EGW_SERVER_ROOT . SEP . $appname . SEP . 'setup' . SEP; - foreach($setup_info as $key => $appdata) + if(file_exists($appdir.'default_records.inc.php')) { - $appname = $appdata['name']; - /* Don't try to upgrade an app that is not installed */ - if(!$GLOBALS['egw_setup']->app_registered($appname)) - { - if($DEBUG) - { - echo "

process->upgrade(): Application not installed: $appname

\n"; - } - unset($setup_info[$appname]); - continue; - } - - /* if upgrade required, or if we are running again after an upgrade or dependency failure */ if($DEBUG) { - echo '
'."process->upgrade(): Incoming : appname: $appname, version: $appdata[currentver], status: $appdata[status]\n"; + echo '
process->default_records(): Including default records for ' . $appname . "\n"; } - if($appdata['status'] == 'U' || $appdata['status'] == 'D' ||$appdata['status'] == 'V' || $appdata['status'] == '') // TODO this is not getting set for api upgrade, sometimes ??? - { - $currentver = $appdata['currentver']; - $targetver = $appdata['version']; // The version we need to match when done - $appdir = EGW_SERVER_ROOT . SEP . $appname . SEP . 'setup' . SEP; + $GLOBALS['egw_setup']->oProc->m_odb->transaction_begin(); + $oProc = &$GLOBALS['egw_setup']->oProc; // to be compatible with old apps + include ($appdir.'default_records.inc.php'); + $GLOBALS['egw_setup']->oProc->m_odb->transaction_commit(); + } + /* $appdata['status'] = 'C'; */ + } - if(file_exists($appdir . 'tables_update.inc.php')) + /* Done, return current status */ + return ($setup_info); + } + + /** + * process test_data.inc.php in each application/setup dir for developer tests + * + * This data should work with the baseline tables + * + * @param array $setup_info array of application info from setup.inc.php files, etc. + * @param boolean $DEBUG=false output further diagnostics + * @return array $setup_info + */ + function test_data(array $setup_info,$DEBUG=False) + { + if(!@$GLOBALS['egw_setup']->oProc) + { + $this->init_process(); + } + foreach($setup_info as $appname => &$appdata) + { + $appdir = EGW_SERVER_ROOT . SEP . $appname . SEP . 'setup' . SEP; + + if(file_exists($appdir.'test_data.inc.php')) + { + if($DEBUG) + { + echo '
process->test_data(): Including baseline test data for ' . $appname . "\n"; + } + $GLOBALS['egw_setup']->oProc->m_odb->transaction_begin(); + include ($appdir.'test_data.inc.php'); + $GLOBALS['egw_setup']->oProc->m_odb->transaction_commit(); + } + } + + /* Done, return current status */ + return ($setup_info); + } + + /** + * process baseline table setup in each application/setup dir + * + * @param array $setup_info array of application info from setup.inc.php files, etc. + * @param boolean $DEBUG=false output further diagnostics + * @return array $setup_info + */ + function baseline(array $setup_info,$DEBUG=False) + { + if(!@$GLOBALS['egw_setup']->oProc) + { + $this->init_process(); + } + foreach($setup_info as $appname => &$appdata) + { + $appdir = EGW_SERVER_ROOT . SEP . $appname . SEP . 'setup' . SEP; + + if(file_exists($appdir.'tables_baseline.inc.php')) + { + if($DEBUG) + { + echo '
process->baseline(): Including baseline tables for ' . $appname . "\n"; + } + include ($appdir.'tables_baseline.inc.php'); + $GLOBALS['egw_setup']->oProc->GenerateScripts($phpgw_baseline, $DEBUG); + $this->post_process($phpgw_baseline,$DEBUG); + + /* Update the array values for return below */ + /* $setup_info[$key]['status'] = 'R'; */ + } + else + { + if($DEBUG) + { + echo '
process->baseline(): No baseline tables for ' . $appname . "\n"; + } + //$setup_info[$key]['status'] = 'C'; + } + } + + /* Done, return current status */ + return ($setup_info); + } + + /** + * process available upgrades in each application/setup dir + * + * @param array $setup_info array of application info from setup.inc.php files, etc. + * @param boolean $DEBUG=false output further diagnostics + * @return array $setup_info + */ + function upgrade($setup_info,$DEBUG=False) + { + //echo __METHOD__; _debug_array($setup_info); + if(!@$GLOBALS['egw_setup']->oProc) + { + $this->init_process(); + } + $GLOBALS['egw_setup']->oProc->m_odb->HaltOnError = 'yes'; + + foreach($setup_info as $appname => &$appdata) + { + // check if app is NOT installed + if(!$GLOBALS['egw_setup']->app_registered($appname)) + { + // check if app wants to be automatically installed on update to version x or allways + if (isset($appdata['autoinstall']) && ($appdata['autoinstall'] === true || + $appdata['autoinstall'] === $this->api_version_target)) + { + $info = $this->current(array($appname => $appdata),$DEBUG); + $info = $this->default_records($info,$DEBUG); + $appdata = $info[$appname]; + continue; + } + /* Don't try to upgrade an app that is not installed */ + if($DEBUG) + { + echo "

process->upgrade(): Application not installed: $appname

\n"; + } + unset($setup_info[$appname]); + continue; + } + + /* if upgrade required, or if we are running again after an upgrade or dependency failure */ + if($DEBUG) + { + echo '
'."process->upgrade(): Incoming : appname: $appname, version: $appdata[currentver], status: $appdata[status]\n"; + } + if($appdata['status'] == 'U' || $appdata['status'] == 'D' ||$appdata['status'] == 'V' || $appdata['status'] == '') // TODO this is not getting set for api upgrade, sometimes ??? + { + $currentver = $appdata['currentver']; + $targetver = $appdata['version']; // The version we need to match when done + $appdir = EGW_SERVER_ROOT . SEP . $appname . SEP . 'setup' . SEP; + + if(file_exists($appdir . 'tables_update.inc.php')) + { + if (!@$this->updateincluded[$appname]) { - if (!@$this->updateincluded[$appname]) - { - include ($appdir . 'tables_update.inc.php'); - $this->updateincluded[$appname] = True; - } - while ($currentver && $currentver != $targetver && - function_exists($function = $appname . '_upgrade' . str_replace('.','_',$currentver))) - { - if($DEBUG) - { - echo "
process->upgrade(): $appname($currentver --> $targetver): running $function()\n"; - } - if (!($currentver = $function())) - { - if($DEBUG) - { - echo "failed!!!\n"; - } - $appstatus = 'F'; - } - else - { - if($DEBUG) - { - echo "--> $currentver\n"; - } - } - } - if ($currentver == $targetver) // upgrades succesful - { - if($DEBUG) - { - echo "
process->upgrade(): Upgrade of $appname to $targetver is completed.\n"; - } - $appstatus = 'C'; - } - elseif ($currentver) - { - if($DEBUG) - { - echo "
process->upgrade(): No table upgrade available for appname: $appname, version: $currentver\n"; - } - $setup_info[$key]['currentver'] = $targetver; - $appstatus = 'F'; - } + include ($appdir . 'tables_update.inc.php'); + $this->updateincluded[$appname] = True; } - else + while ($currentver && $currentver != $targetver && + function_exists($function = $appname . '_upgrade' . str_replace('.','_',$currentver))) { if($DEBUG) { - echo "
process->upgrade(): No table upgrade required/availible for $appname\n"; + echo "
process->upgrade(): $appname($currentver --> $targetver): running $function()\n"; } - $appstatus = 'C'; - } - if ($appstatus == 'C') // update successful completed - { - $setup_info[$key]['currentver'] = $targetver; - - if($GLOBALS['egw_setup']->app_registered($appname)) + if (!($currentver = $function())) { - $GLOBALS['egw_setup']->update_app($appname); - $GLOBALS['egw_setup']->update_hooks($appname); + if($DEBUG) + { + echo "failed!!!\n"; + } + $appstatus = 'F'; } else { - $GLOBALS['egw_setup']->register_app($appname); - $GLOBALS['egw_setup']->register_hooks($appname); + if($DEBUG) + { + echo "--> $currentver\n"; + } } } - + if ($currentver == $targetver) // upgrades succesful + { + if($DEBUG) + { + echo "
process->upgrade(): Upgrade of $appname to $targetver is completed.\n"; + } + $appstatus = 'C'; + } + elseif ($currentver) + { + if($DEBUG) + { + echo "
process->upgrade(): No table upgrade available for appname: $appname, version: $currentver\n"; + } + $appdate['currentver'] = $targetver; + $appstatus = 'F'; + } } else { if($DEBUG) { - echo "
process->upgrade(): No upgrade required for $appname\n"; + echo "
process->upgrade(): No table upgrade required/availible for $appname\n"; } $appstatus = 'C'; } - /* Done with this app, update status */ + if ($appstatus == 'C') // update successful completed + { + $appdata['currentver'] = $targetver; + + if($GLOBALS['egw_setup']->app_registered($appname)) + { + $GLOBALS['egw_setup']->update_app($appname); + $GLOBALS['egw_setup']->update_hooks($appname); + } + else + { + $GLOBALS['egw_setup']->register_app($appname); + $GLOBALS['egw_setup']->register_hooks($appname); + } + } + + } + else + { if($DEBUG) { - echo "
process->upgrade(): Outgoing : appname: $appname, status: $appstatus
\n"; + echo "
process->upgrade(): No upgrade required for $appname\n"; } - $setup_info[$key]['status'] = $appstatus; + $appstatus = 'C'; } - - /* Done, return current status */ - return ($setup_info); + /* Done with this app, update status */ + if($DEBUG) + { + echo "
process->upgrade(): Outgoing : appname: $appname, status: $appstatus
\n"; + } + $appdate['status'] = $appstatus; } - /** - * commit above processing to the db - * - */ - function post_process($tables,$DEBUG=False) - { - if(!$tables) - { - return False; - } - - return $GLOBALS['egw_setup']->oProc->ExecuteScripts($tables,$DEBUG); - } - - /** - * send this a table name, returns printable column spec and keys for the table from schema_proc - * - * @param $tablename table whose array you want to see - */ - function sql_to_array($tablename='') - { - if(!$tablename) - { - return False; - } - - if(!$GLOBALS['egw_setup']->oProc) - { - $this->init_process(); - } - - $GLOBALS['egw_setup']->oProc->m_oTranslator->_GetColumns($GLOBALS['egw_setup']->oProc, $tablename, $sColumns, $sColumnName); - - while(list($key,$tbldata) = each($GLOBALS['egw_setup']->oProc->m_oTranslator->sCol)) - { - $arr .= $tbldata; - } - $pk = $GLOBALS['egw_setup']->oProc->m_oTranslator->pk; - $fk = $GLOBALS['egw_setup']->oProc->m_oTranslator->fk; - $ix = $GLOBALS['egw_setup']->oProc->m_oTranslator->ix; - $uc = $GLOBALS['egw_setup']->oProc->m_oTranslator->uc; - - return array($arr,$pk,$fk,$ix,$uc); - } + /* Done, return current status */ + return $setup_info; } -?> + + /** + * commit above processing to the db + * + */ + function post_process($tables,$DEBUG=False) + { + if(!$tables) + { + return False; + } + return $GLOBALS['egw_setup']->oProc->ExecuteScripts($tables,$DEBUG); + } + + /** + * send this a table name, returns printable column spec and keys for the table from schema_proc + * + * @param $tablename table whose array you want to see + */ + function sql_to_array($tablename='') + { + if(!$tablename) + { + return False; + } + + if(!$GLOBALS['egw_setup']->oProc) + { + $this->init_process(); + } + + $GLOBALS['egw_setup']->oProc->m_oTranslator->_GetColumns($GLOBALS['egw_setup']->oProc, $tablename, $sColumns, $sColumnName); + + while(list($key,$tbldata) = each($GLOBALS['egw_setup']->oProc->m_oTranslator->sCol)) + { + $arr .= $tbldata; + } + $pk = $GLOBALS['egw_setup']->oProc->m_oTranslator->pk; + $fk = $GLOBALS['egw_setup']->oProc->m_oTranslator->fk; + $ix = $GLOBALS['egw_setup']->oProc->m_oTranslator->ix; + $uc = $GLOBALS['egw_setup']->oProc->m_oTranslator->uc; + + return array($arr,$pk,$fk,$ix,$uc); + } +}