3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
5 // +----------------------------------------------------------------------+
6 // | Akelos Framework - http://www.akelos.org |
7 // +----------------------------------------------------------------------+
8 // | Copyright (c) 2002-2006, Akelos Media, S.L. & Bermi Ferrer Martinez |
9 // | Released under the GNU Lesser General Public License, see LICENSE.txt|
10 // +----------------------------------------------------------------------+
13 * @package AkelosFramework
14 * @subpackage Installer
15 * @author Bermi Ferrer <bermi a.t akelos c.om>
16 * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org
17 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
22 var $options = array();
23 var $errors = array();
25 function AkelosInstaller($options)
27 $default_options = array(
28 'source' => $this->_absolutePath(dirname(__FILE__
).DIRECTORY_SEPARATOR
.'..'),
32 'public_html' => false,
33 'dependencies' => false
35 $this->options
= array_merge($default_options, $options);
37 $this->options
['directory'] = $this->_absolutePath(@$this->options
['directory']);
39 if(empty($this->options
['directory'])){
40 trigger_error('You must supply a valid destination path', E_USER_ERROR
);
43 $this->source_tree
= Ak
::dir($this->options
['source'],array('dirs'=>true,'recurse'=>true));
45 if(empty($this->options
['dependencies'])){
46 $this->framework_dirs
= array('lib', 'vendor', 'test');
48 foreach ($this->framework_dirs
as $framework_dir){
49 foreach ($this->source_tree
as $k => $v){
50 if(isset($v[$framework_dir])){
51 unset($this->source_tree
[$k]) ;
57 $this->destination_tree
= Ak
::dir($this->options
['directory'],array('dirs'=>true,'recurse'=>true));
62 if(empty($this->destination_tree
) ||
!empty($this->options
['force'])){
63 if(!is_dir($this->options
['directory'])){
64 if(!$this->_makeDir($this->options
['directory'])){
65 $this->addError("Can't create directory: " . $this->options
['directory']);
70 $this->_copyFrameworkFiles($this->source_tree
, $this->options
['source']);
72 if(empty($this->options
['dependencies'])){
73 $this->_setupApplicationTestingEnvironment();
74 $this->_linkDependencies();
77 $this->runEvironmentSpecificTasks();
79 $this->_linkPublicHtmlFolder();
82 $this->addError('Installation directory is not empty. Add --force if you want to override existing files');
89 function _setupApplicationTestingEnvironment()
91 $source_test_dir = $this->options
['source'].DS
.'test';
92 $test_dir = $this->options
['directory'].DS
.'test';
94 $this->_makeDir($test_dir);
95 $this->_copyFile($source_test_dir.DS
.'app.php');
97 $this->_makeDir($test_dir.DS
.'fixtures');
98 $this->_makeDir($test_dir.DS
.'fixtures'.DS
.'app');
100 $this->_copyFile($source_test_dir.DS
.'fixtures'.DS
.'app'.DS
.'application_controller.php');
101 $this->_copyFile($source_test_dir.DS
.'fixtures'.DS
.'app'.DS
.'shared_model.php');
103 $this->_makeDir($test_dir.DS
.'fixtures'.DS
.'config');
104 $this->_copyFile($source_test_dir.DS
.'fixtures'.DS
.'config'.DS
.'config.php');
106 $this->_makeDir($test_dir.DS
.'fixtures'.DS
.'data');
107 $this->_makeDir($test_dir.DS
.'fixtures'.DS
.'public');
108 $this->_copyFile($source_test_dir.DS
.'fixtures'.DS
.'public'.DS
.'.htaccess');
109 $this->_copyFile($source_test_dir.DS
.'fixtures'.DS
.'public'.DS
.'index.php');
113 function _linkPublicHtmlFolder()
115 if(!empty($this->options
['public_html'])){
116 if(function_exists('symlink')){
117 $this->options
['public_html'] = $this->_absolutePath($this->options
['public_html']);
118 $link_info = @linkinfo
($this->options
['public_html']);
119 if(!is_numeric($link_info) ||
$link_info < 0){
120 $this->yield("\n Adding symbolic link ".$this->options
['public_html'].' to the public web server.');
121 if(@symlink
($this->options
['directory'].DS
.'public',$this->options
['public_html'])){
126 $this->yield("\n Could not create a symbolic link of ".$this->options
['directory'].DS
.'public'.' at '.$this->options
['public_html']);
129 $this->_addRootLevelDispatcher();
130 $this->_addHtaccessDirectoryProtection();
135 function _linkDependencies()
137 $this->yield("\n Linking the application with the framework at ".$this->options
['source'])."\n";
139 'config'.DS
.'DEFAULT-config.php',
140 'app'.DS
.'controllers'.DS
.'framework_setup_controller.php') as $file){
141 if(file_exists($this->options
['directory'].DS
.$file)){
142 $file_contents = str_replace("// defined('AK_FRAMEWORK_DIR') ? null : define('AK_FRAMEWORK_DIR', '/path/to/the/framework');",
143 "defined('AK_FRAMEWORK_DIR') ? null : define('AK_FRAMEWORK_DIR', '".addcslashes($this->options
['source'],'\\')."');",
144 file_get_contents($this->options
['directory'].DS
.$file));
145 file_put_contents($this->options
['directory'].DS
.$file, $file_contents);
150 function _addRootLevelDispatcher()
152 $this->_copyFile($this->options
['source'].DS
.'index.php');
153 $this->_copyFile($this->options
['source'].DS
.'.htaccess');
156 function _addHtaccessDirectoryProtection()
158 foreach($this->source_tree
as $k=>$node){
159 if (is_array($node)){
160 $folder = array_shift(array_keys($node));
161 $path = $this->options
['directory'].DS
.$folder;
162 if(is_dir($path) && !file_exists($path.DS
.'.htaccess') && $folder != 'public'){
163 file_put_contents($path.DS
.'.htaccess', "order allow,deny\ndeny from all");
169 function _copyFrameworkFiles($directory_structure, $base_path = '.')
171 foreach ($directory_structure as $k=>$node){
173 $path = $base_path.DS
.$node;
175 $this->_makeDir($path);
176 }elseif(is_file($path)){
177 $this->_copyFile($path);
178 }elseif(is_array($node)){
179 foreach ($node as $dir=>$items){
180 $path = $base_path.DS
.$dir;
182 $this->_makeDir($path);
183 $this->_copyFrameworkFiles($items, $path);
191 function _makeDir($path)
193 $dir = $this->_getDestinationPath($path);
195 if($this->_canUsePath($dir)){
197 $this->yield(" Creating directory: ".$dir);
205 function _copyFile($path)
207 $destination_file = $this->_getDestinationPath($path);
209 if($this->_canUsePath($destination_file)){
210 if(!file_exists($destination_file)){
211 $this->yield(" Creating file: ".$destination_file);
212 copy($path, $destination_file);
213 }elseif(md5_file($path) != md5_file($destination_file)){
214 $this->yield(" Modifying file: ".$destination_file);
215 copy($path, $destination_file);
218 $source_file_mode = fileperms($path);
219 $target_file_mode = fileperms($destination_file);
220 if($source_file_mode != $target_file_mode){
221 $this->yield(" Setting $destination_file permissions to: ".(sprintf("%o",$source_file_mode)));
222 chmod($destination_file,$source_file_mode);
228 * Computes the destination path
230 * Gicing /path/to/the_framework/lib/Ak.php will rerturn /my/project/path/lib/Ak.php
233 function _getDestinationPath($path)
235 return str_replace($this->options
['source'], $this->options
['directory'], $path);
239 * Returns false if operating on the path is not allowed
241 function _canUsePath($path)
243 if(is_file($path) ||
is_dir($path)){
244 return !empty($this->options
['skip']) ?
false : !empty($this->options
['force']);
250 function _absolutePath($path)
253 if (!preg_match((AK_OS
== 'WINDOWS' ?
"/^\w+:/" : "/^\//"), $path )) {
254 $current_dir = AK_OS
== 'WINDOWS' ?
str_replace("\\", DS
, realpath('.').DS
) : realpath('.').DS
;
255 $_path = $current_dir . $_path;
258 if(AK_OS
== 'WINDOWS'){
259 list($start, $_path) = explode(':', $_path, 2);
262 $real_parts = array();
263 $parts = explode(DS
, $_path);
264 for ($i = 0; $i < count($parts); $i++
) {
265 if (strlen($parts[$i]) == 0 ||
$parts[$i] == "."){
268 if ($parts[$i] == '..'){
269 if(count($real_parts) > 0){
270 array_pop($real_parts);
273 array_push($real_parts, $parts[$i]);
276 return $start.DS
.implode(DS
,$real_parts );
279 function yield($message)
281 if(empty($this->options
['quiet'])){
286 function addError($error)
288 $this->errors
[$error] = '';
293 return array_keys($this->errors
);
298 return !empty($this->errors
);
302 function runEvironmentSpecificTasks()
304 if($evironment = $this->guessEnvironment()){
305 $method_name = 'run'.$evironment.'Tasks';
306 if(method_exists($this, $method_name)){
307 $this->$method_name();
312 // Environment specific tasks
314 function guessEnvironment()
316 if(AK_OS
== 'WINDOWS'){
317 if(file_exists('C:/xampp/apache/conf/httpd.conf')){
318 return 'DefaultXamppOnWindows';
324 function runDefaultXamppOnWindowsTasks()
326 // XAMPP has mod_rewrite disabled by default so we will try to enable it.
327 $http_conf = file_get_contents('C:/xampp/apache/conf/httpd.conf');
328 if(strstr($http_conf, '#LoadModule rewrite_module')){
329 $this->yield('Enabling mod_rewrite');
330 file_put_contents('C:/xampp/apache/conf/httpd.conf.akelos', $http_conf);
331 file_put_contents('C:/xampp/apache/conf/httpd.conf',
333 '#LoadModule rewrite_module',
334 'LoadModule rewrite_module',
338 $this->yield('Restarting Apache');
340 exec('C:\xampp\apache\bin\pv -f -k apache.exe -q');
341 exec('rm C:\xampp\apache\logs\httpd.pid');
343 // Start Apache in the background
344 $shell = new COM('WScript.Shell');
345 $shell->Run('C:\xampp\apache\bin\apache.exe', 0, false);
348 $my_cnf = @file_get_contents
('C:/xampp/mysql/bin/my.cnf');
349 // InnoDB engine is not enabled by default on XAMPP we need it enabled in order to use transactions
350 if(strstr($my_cnf, '#innodb_')){
351 $this->yield('Enabling InnoDB MySQL engine.');
352 file_put_contents('C:/xampp/mysql/bin/my.cnf.akelos', $my_cnf);
353 file_put_contents('C:/xampp/mysql/bin/my.cnf',
355 array('skip-innodb', '#innodb_', '#set-variable = innodb'),
356 array('#skip-innodb', 'innodb_', 'set-variable = innodb')
359 $this->yield('Restarting MySQL server.');
360 $shell = new COM('WScript.Shell');
361 $shell->Run('C:\xampp\mysql\bin\mysqladmin --user=pma --password= shutdown', 0, false);
362 $shell = new COM('WScript.Shell');
363 $shell->Run('C:\xampp\mysql\bin\mysqld --defaults-file=C:\xampp\mysql\bin\my.cnf --standalone --console', 0, false);
369 define('DS', DIRECTORY_SEPARATOR
);
370 define('AK_OS', (strtoupper(substr(PHP_OS
, 0, 3)) === 'WIN' ?
'WINDOWS' : 'UNIX'));
371 define('AK_PHP5', version_compare(PHP_VERSION
, '5', '>=') == 1 ?
true : false);
373 define('AK_BASE_DIR', str_replace(DS
.'script'.DS
.'setup','',__FILE__
));
374 @ini_set
("include_path",(AK_BASE_DIR
.DS
.'vendor'.DS
.'pear'.PATH_SEPARATOR
.ini_get("include_path")));
377 if(!empty($_SERVER['argv'][1]) && $_SERVER['argv'][1][0] != '-'){
378 $_SERVER['argv'][0] = '-d';
382 require_once (dirname(__FILE__
).DS
.'..'.DS
.'lib'.DS
.'Ak.php');
383 require_once (dirname(__FILE__
).DS
.'..'.DS
.'vendor'.DS
.'pear'.DS
.'PHP'.DS
.'Compat'.DS
.'Function'.DS
.'file_put_contents.php');
384 require_once (dirname(__FILE__
).DS
.'..'.DS
.'vendor'.DS
.'pear'.DS
.'Console'.DS
.'Getargs.php');
389 'directory' => array(
393 'desc' => 'Destination directory for installing the application.'),
401 'default' => 'false',
402 'desc' => 'Overwrite files that already exist.'),
409 'default' => 'false',
410 'desc' => 'Skip files that already exist.'),
417 'default' => 'false',
418 'desc' => 'Suppress normal output.'),
421 'public_html' => array(
425 'desc' => 'Location where the application will be accesed by the webserver.'),
429 'dependencies' => array(
434 'desc' => 'Includes a copy of the framework into the application directory.'),
441 'desc' => 'Show this help message.'),
449 $args =& Console_Getargs
::factory($config);
451 if (PEAR
::isError($args)) {
452 if ($args->getCode() === CONSOLE_GETARGS_ERROR_USER
) {
453 echo Console_Getargs
::getHelp($config, null, $args->getMessage())."\n";
454 } else if ($args->getCode() === CONSOLE_GETARGS_HELP
) {
455 echo @Console_Getargs
::getHelp($config)."\n";
460 $options = $args->getValues();
463 echo Console_Getargs
::getHelp($config)."\n";
467 $Installer = new AkelosInstaller($options);
469 $Installer->install();
471 if($args->getValue('quiet') == ''){
472 if($Installer->hasErrors()){
473 echo "\nThere where some errors during the installation process:\n";
474 echo "\n * ".join("\n * ",$Installer->getErrors());
475 }elseif(empty($Installer->options
['force'])){
476 echo "\n Please point your browser to ".
477 (empty($Installer->options
['public_html']) ?
$Installer->options
['directory'] : $Installer->options
['public_html']).
478 " in order to complete the installation process";