> Ignoring, -f[orce] passed'); } else { exit(1); } } // }}} // {{{ ardl(string proxy, string url, string targetdir) function ardl($proxy, $url, $targetdir, $permissions= -1) { static $pw= 10; if ($proxy) { println('---> ', $url, ' via ', $proxy); $u= parse_url($proxy); $request= sprintf( "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", $url.'.ar', $u['host'] ); } else { println('---> ', $url); $u= parse_url($url); $request= sprintf( "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", $u['path'].'.ar', $u['host'] ); } $fd= fsockopen($u['host'], isset($u['port']) ? $u['port'] : 80, $errno, $errstr); if (!$fd) { println('*** Failed (#', $errno, ': ', $errstr, ' ***'); return FALSE; } // Send HTTP request fputs($fd, $request); // Read HTTP response $status= fgets($fd, 1024); sscanf($status, "HTTP/1.%*d %d %[^\r]", $code, $message); if (200 != $code) { println('*** Failed (HTTP ', $code, ': ', $message, ' ***'); return FALSE; } do { if (FALSE === ($header= fgets($fd, 1024))) return FALSE; if ('' === ($header= rtrim($header))) break; } while ($header); while ($line= fgets($fd, 0xFF)) { if (2 != sscanf($line, '--%d:%[^:]--', $length, $filename)) continue; printf( '---> %s (%.2f kB) [%s]%s', $filename, $length / 1024, str_repeat('.', $pw), str_repeat("\x08", $pw+ 1) ); $target= $targetdir.DIRECTORY_SEPARATOR.$filename; $ft= fopen($target, 'wb'); if (!$ft) { println('*** I/O Error w/ ', $filename, ' ***'); return FALSE; } $s= 0; $c= 0; while ($s < $length) { $s+= fwrite($ft, fread($fd, min(0x1000, $length- $s))); // Update progress $d= ceil(($s / $length) * $pw); if ($d == $c) continue; echo str_repeat('#', $d- $c); flush(); $c= $d; } fclose($ft); // Change permissions if requested if (-1 != $permissions) { chmod($target, fileperms($target) | $permissions); } println(); } fclose($fd); return TRUE; } // }}} // {{{ which(string command [, bool ext]) function which($command, $ext= FALSE) { if ('/' === $command{0} || ':' === $command{1}) { $search= array(''); } else { $search= array(); foreach (explode(PATH_SEPARATOR, getenv('PATH')) as $path) { $search[]= rtrim($path, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } } $extensions= array(''); $ext && $extensions+= explode(PATH_SEPARATOR, getenv('PATHEXT')); foreach ($search as $path) { foreach ($extensions as $ext) { if (file_exists($q= $path.$command.$ext)) return realpath($q); } } return NULL; } // }}} // {{{ inpath(string dir) function inpath($dir) { $realpath= realpath($dir); foreach (explode(PATH_SEPARATOR, getenv('PATH')) as $path) { if (realpath($path) == $realpath) return TRUE; } return FALSE; } // }}} // {{{ inpath(string dir) function usage() { println('*** Usage: setup -d [-b ] [-p ] [-e ] [-f]'); println('- d : Path to where XP runners should be installed'); println('- b : Path to PHP binary (default: `which php5 || php)`'); println('- p : HTTP proxy to use (default: none), e.g. http://proxy.example.com:3128/'); println('- e : Runner environment to use (default: auto-detect)'); println('- f : Force continuation even if prerequisite checks fail'); return 1; } // }}} // {{{ main error_reporting(E_ALL); $bin= $runtime= $runners= $proxy= NULL; $warnings= array(); $uname= php_uname(); $force= FALSE; println('===> Setup for ', VERSION, ' @ ', $uname); // Parse command line arguments for ($i= 0; $i < $argc; $i++) { switch ($argv[$i]) { case '-d': $bin= $argv[++$i]; break; case '-b': $runtime= $argv[++$i]; break; case '-e': $runners= $argv[++$i]; break; case '-p': $proxy= $argv[++$i]; break; case '-f': $force= TRUE; break; case '-?': case '--help': usage() && exit(1); } } if (!$bin) usage() && exit(1); // Runner path: Check whether "bin" exists and is in PATH if (!is_dir($bin)) { $warnings[]= 'Bindir '.$bin.' does not exist, created it for you'; } if (!inpath($bin)) { $warnings[]= 'Bindir '.$bin.' is not in PATH, you might want to consider adding it!'; } // Check for PHP runtime if ($runtime) { if (!($resolved= which($runtime, TRUE))) { println('*** Could not find specified runtime ', $runtime, ' ***'); exit(1); } $runtime= $resolved; } else { if (!($runtime= which('php5', TRUE))) { if (!($runtime= which('php', TRUE))) { println('*** PHP command not in path (', getenv('PATH'), ') ***'); exit(1); } } } // Detect environment println('===> Environment'); switch (TRUE) { case NULL !== $runners: break; case TRUE == preg_match('/^([A-Z]+)BSD/i', $uname): $runners= 'bsd'; break; case TRUE == preg_match('/^Windows/i', $uname): println('---> Windows'); // Verify .NET version $d= dir(getenv('SYSTEMROOT').'/Microsoft.NET/Framework'); $versions= array(); while ($entry= $d->read()) { if (sscanf($entry, 'v%d.%d.%s', $major, $minor, $patch) > 1) { $versions[]= substr($entry, 1); } } $d->close(); if (!version_compare(max($versions), '2.0', 'gt')) { println('*** .NET Framework 2.0 or greater required, found [', implode(', ', $versions), ']'); exit(1); } $runners= 'windows'; break; default: println('---> Un*x'); $runners= 'unix'; break; } println('---> Using ', $runners, ' runners'); // Download dependencies ardl($proxy, BASE_URL.VERSION.'/depend', TARGET_DIR) || exit(1); $depend= parse_ini_file(TARGET_DIR.'depend.ini', TRUE); // Found it, execute $extensions= array(); $proc= proc_open('"'.$runtime.'"', array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w')), $pipes); if (!$proc) { println('*** PHP executable ', $runtime, ' could not be forked ***'); exit(1); } // Gather information fwrite($pipes[0], ' array_flip(array_map("strtolower", get_loaded_extensions())), "ini" => ini_get_all() )); ?>'); fclose($pipes[0]); // Scan until we find a NUL character. This is the beginning of our output while (fgetc($pipes[1]) != "\0"); fscanf($pipes[1], '%s %s', $version, $sapi); // Read the rest for ($out= ''; !feof($pipes[1]); ) $out.= fread($pipes[1], 0x1000); for ($err= ''; !feof($pipes[2]); ) $err.= fread($pipes[2], 0x1000); fclose($pipes[1]); fclose($pipes[2]); $exitcode= proc_close($proc); $config= unserialize($out); // Verify it worked if (0 != $exitcode || '' != $err || !is_array($config)) { println('*** PHP executable ', $runtime, ' exited with unexpected exit code ', $exitcode, ' (', $err, ') ***'); exit(1); } println('---> System PHP ', $version, ' SAPI ', $sapi, ' @ ', $runtime); // Verify version foreach ($depend['php'] as $op => $compare) { if (!version_compare($version, $compare, $op)) { println('*** PHP Version ', $op, ' ', $compare, ' required ***'); halt($force); } } // Check extensions foreach ($depend['ext.required'] as $ext => $usage) { if (!isset($config['ext'][$ext])) { println('*** PHP Extension ', $ext, ' required for ', $usage, ' ***'); halt($force); } } foreach ($depend['ext.conflict'] as $ext => $usage) { if (isset($config['ext'][$ext])) { println('*** PHP Extension ', $ext, ' conflicts (', $usage, ') ***'); halt($force); } } foreach ($depend['ext.optional'] as $ext => $usage) { if (!isset($config['ext'][$ext])) { $warnings[]= 'PHP Extension '.$ext.' not found, needed for '.$usage.' (ignoring)'; } } // Check configuration foreach ($depend['ini'] as $setting => $match) { $value= @$config['ext'][$setting]['local_value']; if (!preg_match($match, $value)) { println('*** PHP .ini setting ', $setting, ' needs to match ', $match, ' (but is '.$value.') ***'); exit(1); } } unlink(TARGET_DIR.'depend.ini'); println('===> Dependencies OK'); // Create directories $target= TARGET_DIR.DIRECTORY_SEPARATOR.VERSION.DIRECTORY_SEPARATOR; println('---> Target: ', $target); foreach (array($target, $target.'tools', $target.'lib', $bin) as $dir) { if (is_dir($dir)) continue; if (mkdir($dir)) continue; println('*** Failed to create directory ', $dir, ' ***'); exit(1); } // Download : // * base (lang.base.php) // * tools (tools/class.php, tools/xar.php, ...) // * META-INF (boot.pth, ChangeLog) // * Libraries (xp-rt, xp-tools, net.xp_framework XAR) println('===> Base'); ardl($proxy, BASE_URL.VERSION.'/base', $target) || exit(2); println('===> Tools'); ardl($proxy, BASE_URL.VERSION.'/tools', $target) || exit(2); println('===> META-INF'); ardl($proxy, BASE_URL.VERSION.'/meta-inf', $target) || exit(2); println('===> Libraries'); ardl($proxy, BASE_URL.VERSION.'/lib', $target) || exit(2); // Download runners ardl($proxy, BASE_URL.'bin/'.$runners, $bin, 0700) || exit(3); // Create xp.ini. Always use forward slashes! $config= $bin.DIRECTORY_SEPARATOR.'xp.ini'; println('===> Settings (', $config, ')'); if (file_exists($config)) { $warnings[]= 'xp.ini already existed in '.$bin.', wrote config to xp-'.VERSION.'.ini instead'; $config= $bin.DIRECTORY_SEPARATOR.'xp-'.VERSION.'.ini'; } $fp= fopen($config, 'wb'); fwrite($fp, 'use='.str_replace(DIRECTORY_SEPARATOR, '/', realpath($target)).PHP_EOL); fwrite($fp, '[runtime]'.PHP_EOL); fwrite($fp, 'default='.str_replace(DIRECTORY_SEPARATOR, '/', $runtime).PHP_EOL); fwrite($fp, PHP_EOL); fclose($fp); // Print warnings if (!empty($warnings)) { println('===> Warnings:'); foreach ($warnings as $warning) { println('!!! ', $warning); } } // Check to see if it works. println('===> Configuration:'); // Found it, execute unset($pipes); putenv('XP_RT='.$runtime); putenv('USE_XP='.realpath($target)); $xp= realpath($bin).DIRECTORY_SEPARATOR.'xp'; $proc= proc_open('"'.$xp.'" -v', array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w')), $pipes); if (!$proc) { println('*** XP runners ', $xp, ' could not be forked ***'); exit(1); } fclose($pipes[0]); // Read the rest for ($out= ''; !feof($pipes[1]); ) echo fread($pipes[1], 0x1000); for ($err= ''; !feof($pipes[2]); ) echo fread($pipes[2], 0x1000); fclose($pipes[1]); fclose($pipes[2]); // xp.tools.Version exits w/ exitcode 1 $exitcode= proc_close($proc); if (1 != $exitcode) { println('*** XP runner ', $xp, ' exited with unexpected exitcode ', $exitcode); exit(4); } println('===> Done'); // }}} ?>