From: Michael M Slusarz Date: Sat, 28 Aug 2010 23:40:25 +0000 (-0600) Subject: Use PEAR libraries to parse package.xml files. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=3bb949869f9b553936f31d04deec4e6eb226f3fc;p=horde.git Use PEAR libraries to parse package.xml files. --- diff --git a/framework/bin/install_dev b/framework/bin/install_dev index 555b3371a..728122be0 100755 --- a/framework/bin/install_dev +++ b/framework/bin/install_dev @@ -84,7 +84,7 @@ chmod($web_dir . '/static', $static_mode); print "\nLINKING framework\n"; mkdir($web_dir . '/libs'); -system(dirname(__FILE__) . '/install_framework --src ' . $horde_git . '/framework --dest ' . $web_dir . '/libs'); +system(dirname(__FILE__) . '/install_framework --src ' . escapeshellarg($horde_git) . '/framework --dest ' . escapeshellarg($web_dir . '/libs') . ' --horde ' . escapeshellarg($web_dir)); print "\nLINKING applications to web directory " . $web_dir . "\n"; foreach ($apps as $app) { diff --git a/framework/bin/install_framework b/framework/bin/install_framework index 770b20666..2f689c189 100755 --- a/framework/bin/install_framework +++ b/framework/bin/install_framework @@ -2,13 +2,7 @@ * Copyright 2003-2010 The Horde Project (http://www.horde.org/) @@ -16,15 +10,16 @@ * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @category Horde - * @package tools * @author Wolfram Kriesing * @author Jan Schneider + * @author Michael Slusarz + * @category Horde + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @package framework */ -// Default values for srcDir and destDir are empty. -$srcDir = null; -$destDir = null; +$destDir = $hordeDir = $srcDir = null; +$debug = $dryrun = false; // Default to copying if this is run on Windows. $copy = strncasecmp(PHP_OS, 'WIN', 3) ? false : true; @@ -32,20 +27,37 @@ $copy = strncasecmp(PHP_OS, 'WIN', 3) ? false : true; // All packages by default. $pkg = null; -for ($i = 1; $i < count($argv); $i++) { +for ($i = 1; $i < count($argv); ++$i) { switch ($argv[$i]) { case '--copy': $copy = true; break; + case '--debug': + $debug = true; + break; + + case '--dryrun': + $dryrun = true; + break; + case '--help': print_usage(); + case '--horde': + if (isset($argv[$i + 1])) { + if (is_dir($argv[$i + 1])) { + $hordeDir = $argv[++$i]; + } else { + exit($argv[$i + 1] . " is not a directory"); + } + } + break; + case '--src': if (isset($argv[$i + 1])) { if (is_dir($argv[$i + 1])) { - $srcDir = $argv[$i + 1]; - $i++; + $srcDir = $argv[++$i]; } else { exit($argv[$i + 1] . " is not a directory"); } @@ -55,8 +67,7 @@ for ($i = 1; $i < count($argv); $i++) { case '--dest': if (isset($argv[$i + 1])) { if (is_dir($argv[$i + 1])) { - $destDir = $argv[$i + 1]; - $i++; + $destDir = $argv[++$i]; } else { exit($argv[$i + 1] . " is not a directory"); } @@ -64,12 +75,11 @@ for ($i = 1; $i < count($argv); $i++) { break; case '--pkg': - $pkg = $argv[$i + 1]; + $pkg = $argv[++$i]; if (!is_dir($pkg) || !file_exists($pkg . '/package.xml')) { exit("$pkg is not a valid package directory.\n"); } - $pkg = preg_replace('|/+$|', '', $pkg); - $i++; + $pkg = preg_replace('|/+$|', '', $pkg) . '/package.xml'; break; default: @@ -77,33 +87,45 @@ for ($i = 1; $i < count($argv); $i++) { } } +if (is_null($hordeDir)) { + print_usage('Missing the horde installation directory.'); +} + // Try to auto-detect the source and dest dirs. $cwd = getcwd(); -if ($srcDir === null) { - if (is_dir($cwd . '/framework')) { - $srcDir = $cwd . DIRECTORY_SEPARATOR . 'framework'; - } else { - $srcDir = dirname(__FILE__) . '/..'; - } +if (is_null($srcDir) && is_null($pkg)) { + $srcDir = is_dir($cwd . '/framework') + ? $cwd . DIRECTORY_SEPARATOR . 'framework' + : dirname(__FILE__) . '/..'; } -if ($destDir === null && is_dir($cwd . '/lib')) { +if (is_null($destDir) && is_dir($cwd . '/lib')) { $destDir = $cwd . DIRECTORY_SEPARATOR . 'lib'; } -if ($srcDir === null || $destDir === null) { +if ((is_null($srcDir) && is_null($pkg)) || is_null($destDir)) { print_usage('Failed to auto-detect source and destination directories,'); } +// Make $hordeDir an absolute path. +if (($hordeDir[0] != '/') && + !preg_match('/[A-Za-z]:/', $hordeDir) && + ($cwd = getcwd())) { + $hordeDir = $cwd . '/' . $hordeDir; +} +$hordeDir = rtrim($hordeDir, '/'); + // Make $srcDir an absolute path. -if (($srcDir[0] != '/' && !preg_match('/[A-Za-z]:/', $srcDir)) && - $cwd = getcwd()) { +if (($srcDir[0] != '/') && + !preg_match('/[A-Za-z]:/', $srcDir) && + ($cwd = getcwd())) { $srcDir = $cwd . '/' . $srcDir; } $srcDir = rtrim($srcDir, '/'); // Make $destDir an absolute path. -if (($destDir[0] != '/' && !preg_match('/[A-Za-z]:/', $destDir)) && - $cwd = getcwd()) { +if (($destDir[0] != '/') && + !preg_match('/[A-Za-z]:/', $destDir) && + ($cwd = getcwd())) { $destDir = $cwd . '/' . $destDir; } $destDir = rtrim($destDir, '/'); @@ -114,14 +136,11 @@ if (strpos(ini_get('include_path'), $destDir) === false) { } // Do CLI checks and environment setup first. -if (!@include_once dirname(__FILE__) . '/../Cli/lib/Horde/Cli.php') { - if (!@include_once 'Horde/Cli.php') { - if (!@include_once $srcDir . '/Cli/lib/Horde/Cli.php') { - if (!@include_once $cwd . '/../Cli/lib/Horde/Cli.php') { - print_usage('Horde_Cli library is not in the include_path or in the src directory.'); - } - } - } +if ((!@include_once dirname(__FILE__) . '/../Cli/lib/Horde/Cli.php') && + (!@include_once 'Horde/Cli.php') && + (!@include_once $srcDir . '/Cli/lib/Horde/Cli.php') && + (!@include_once $cwd . '/../Cli/lib/Horde/Cli.php')) { + print_usage('Horde_Cli library is not in the include_path or in the src directory.'); } // Make sure no one runs this from the web. @@ -131,408 +150,107 @@ if (!Horde_Cli::runningFromCLI()) { // Load the CLI environment - make sure there's no time limit, init // some variables, etc. -$GLOBALS['cli'] = Horde_Cli::init(); +$cli = Horde_Cli::init(); -if (!class_exists('SimpleXMLElement', false)) { - include_once 'Tree/Tree.php'; - if (!class_exists('Tree')) { - print_usage('You need the PEAR "Tree" package installed'); - } -} +$cli->message('Source directory: ' . $srcDir); +$cli->message('Framework destination directory: ' . $destDir); +$cli->message('Horde directory: ' . $hordeDir); +$cli->message('Create symbolic links: ' . ($copy ? 'NO' : 'Yes')); -// Tree throws some irrelevant reference; silence them. -error_reporting(E_ALL & ~E_NOTICE); +// Create the local PEAR config. +if (!(@include_once 'PEAR/Config.php') || + !(@include_once 'PEAR/PackageFile.php')) { + print_usage('PEAR libraries are not in the PHP include_path.'); +} +error_reporting(E_ALL & ~E_DEPRECATED); +$pear_config = PEAR_Config::singleton(); +$pear_pkg = new PEAR_PackageFile($pear_config); -$linker = new Linker($copy); if ($pkg) { - $linker->process($pkg, $destDir); -} elseif ($handle = opendir($srcDir)) { - while ($file = readdir($handle)) { - if ($file != '.' && - $file != '..' && - $file != 'CVS' && - is_dir($srcDir . '/' . $file)) { - $linker->process($srcDir . '/' . $file, $destDir); + $pkgs = array($pkg); +} else { + $di = new DirectoryIterator($srcDir); + $pkgs = array(); + foreach ($di as $val) { + $pathname = $val->getPathname(); + if ($val->isDir() && + !$di->isDot() && + file_exists($pathname . '/package.xml')) { + $pkgs[basename($val)] = $pathname; } } - closedir($handle); - } - -echo "\n"; - -/** - */ -class Linker { - - var $_srcDir; - - /** - * The base directory for the complete package. - * - * @string - */ - var $_baseDir; - - /** - * The base installation directories of the current directory or file - * relative to $_baseDir. The current base directory is always at array - * position 0. - * - * @array - */ - var $_baseInstallDir = array(''); - - var $_fileroles = array('php'); - - var $_role; - - var $_copy; - - var $_tree; + asort($pkgs); +} - var $_contents; +$cli->writeLn(); +$cli->message('Package(s) to install: ' . ($pkg ? $pkg : 'ALL (' . count($pkgs) . ' packages)')); - function Linker($copy = false) - { - $this->_copy = $copy; +foreach ($pkgs as $key => $val) { + if ($debug) { + $cli->writeLn(); } + $cli->message('Installing package ' . $key); - function process($srcDir, $destDir) - { - $this->_srcDir = $srcDir; - $packageFile = $this->_srcDir . '/package.xml'; - $cli = $GLOBALS['cli']; - - if (!is_file($packageFile)) { - $cli->message('No package.xml in ' . $this->_srcDir, 'cli.warning'); - return false; - } + $pkg_ob = $pear_pkg->fromPackageFile($val . '/package.xml', PEAR_VALIDATE_NORMAL); - $this->_tree = $this->getXmlTree($packageFile); + foreach ($pkg_ob->getInstallationFilelist() as $file) { + $orig = realpath($val . '/' . $file['attribs']['name']); - // Read package name. - $packageName = trim($this->_tree->getElementContent('/package/name', 'cdata')); - $cli->writeln("Processing package $packageName."); - - // First, look for '/package/phprelease/filelist', which - // overrides '/package/contents'. - if (($filelist = $this->_tree->getElementByPath('/package/phprelease/filelist'))) { - // Do this better, make the tree class work case insensitive. - $this->_baseDir = preg_replace('|/+|', '/', $destDir); - if (!is_dir($this->_baseDir)) { - require_once 'System.php'; - System::mkdir('-p ' . $this->_baseDir); + switch ($file['attribs']['role']) { + case 'horde': + if (isset($file['attribs']['install-as'])) { + $dest = $hordeDir . '/' . $file['attribs']['install-as']; + } else { + $cli->message('Could not determine install directory (role "horde") for ' . $hordeDir, 'cli.error'); + continue; } + break; - $this->_handleFilelistTag($filelist); - - // Look for contents in '/package/contents'. - } elseif (($this->_contents = $this->_tree->getElementByPath('/package/contents'))) { - // Do this better, make the tree class work case insensitive. - $this->_baseDir = preg_replace('|/+|', '/', $destDir); - if (!is_dir($this->_baseDir)) { - require_once 'System.php'; - System::mkdir('-p ' . $this->_baseDir); + case 'php': + if (isset($file['attribs']['install-as'])) { + $dest = $destDir . '/' . $file['attribs']['install-as']; + } elseif (isset($file['attribs']['baseinstalldir'])) { + $dest = $destDir . $file['attribs']['baseinstalldir'] . '/' . $file['attribs']['name']; + } else { + $dest = $destDir . '/' . $file['attribs']['name']; } + break; - $this->_handleContentsTag($this->_contents); - - // Didn't find either. - } else { - $cli->message('No filelist or contents tags found inside: ' . $packageFile, 'cli.warning'); + default: + $dest = null; } - unset($this->_tree); - unset($this->_contents); - } - - function _handleFilelistTag($element, $curDir = '') - { - if (isset($element['children'])) { - foreach ($element['children'] as $child) { - switch ($child['name']) { - case 'install': - // - $this->_handleInstallTag($child, $curDir); - break; - - default: - $GLOBALS['cli']->message('No handler for tag: ' . $child['name'], 'cli-warning'); - break; - } + if (!is_null($dest)) { + if (!$dryrun && file_exists($dest)) { + @unlink($dest); + } elseif (!$dryrun && !file_exists(dirname($dest))) { + @mkdir(dirname($dest), 0777, true); } - } - } - function _handleContentsTag($element, $curDir = '') - { - if (isset($element['children'])) { - foreach ($element['children'] as $child) { - switch ($child['name']) { - case 'file': - $this->_handleFileTag($child, $curDir); - break; - - case 'dir': - $this->_handleDirTag($child, $curDir); - break; - - default: - $GLOBALS['cli']->message('No handler for tag: ' . $child['name'], 'cli-warning'); - break; + if ($copy) { + if ($debug) { + print 'COPY: ' . $orig . ' -> ' . $dest . "\n"; } - } - } - } - - function _handleDirTag($element, $curDir) - { - if ($element['attributes']['name'] != '/') { - if (substr($curDir, -1) != DIRECTORY_SEPARATOR) { - $curDir .= DIRECTORY_SEPARATOR; - } - $curDir .= $element['attributes']['name']; - } - - if (!empty($element['attributes']['baseinstalldir'])) { - array_unshift($this->_baseInstallDir, $element['attributes']['baseinstalldir']); - } - $this->_handleContentsTag($element, $curDir); - if (!empty($element['attributes']['baseinstalldir'])) { - array_shift($this->_baseInstallDir); - } - } - - function _handleFileTag($element, $curDir) - { - if (!empty($element['attributes']['role'])) { - $this->_role = $element['attributes']['role']; - } - - if (!in_array($this->_role, $this->_fileroles)) { - return; - } - - if (!empty($element['attributes']['name'])) { - $filename = $element['attributes']['name']; - } else { - $filename = $element['cdata']; - } - $filename = trim($filename); - - if (!empty($element['attributes']['baseinstalldir'])) { - $dir = $element['attributes']['baseinstalldir']; - } else { - $dir = $this->_baseInstallDir[0]; - } - if (substr($dir, -1) == '/') { - $dir = substr($dir, 0, -1); - } - $dir .= $curDir; - if (substr($dir, -1) == '/') { - $dir = substr($dir, 0, -1); - } - - if (!is_dir($this->_baseDir . $dir)) { - require_once 'System.php'; - System::mkdir('-p ' . $this->_baseDir . $dir); - } - - if ($this->_copy) { - $cmd = "cp {$this->_srcDir}$curDir/$filename {$this->_baseDir}$dir/$filename"; - } else { - $parent = $this->_findCommonParent($this->_srcDir . $curDir, - $this->_baseDir . $dir); - $dirs = substr_count(substr($this->_baseDir . $dir, - strlen($parent)), - '/'); - $src = str_repeat('../', $dirs) . - substr($this->_srcDir . $curDir, strlen($parent) + 1); - $cmd = "ln -sf $src/$filename {$this->_baseDir}$dir/$filename"; - } - - exec($cmd); - } - - function _handleInstallTag($element, $curDir) - { - if (empty($element['attributes']['name'])) { - // Warning? - return; - } - $src = trim($element['attributes']['name']); - $srcDir = dirname($src); - - if (empty($element['attributes']['as'])) { - // Warning? - return; - } - $as = trim($element['attributes']['as']); - $asDir = dirname($as); - - $role = $this->_findRole($src); - if (!in_array($role, $this->_fileroles)) { - return; - } - - if (!is_dir($this->_baseDir . '/' . $asDir)) { - require_once 'System.php'; - System::mkdir('-p ' . $this->_baseDir . '/' . $asDir); - } - - if ($this->_copy) { - $cmd = "cp {$this->_srcDir}$curDir/$src {$this->_baseDir}/$as"; - } else { - $parent = $this->_findCommonParent($this->_srcDir . $curDir, - $this->_baseDir . $asDir); - $dirs = substr_count(substr($this->_baseDir . $srcDir, strlen($parent)), - '/'); - $src = str_repeat('../', $dirs) . substr($this->_srcDir . $curDir, strlen($parent) + 1) . '/' . $src; - $cmd = "ln -sf $src {$this->_baseDir}/$as"; - } - - exec($cmd); - } - - function _findRole($filename) - { - if (!$this->_contents) { - $this->_contents = $this->_tree->getElementByPath('/package/contents'); - if (!$this->_contents) { - return false; - } - } - - if (!isset($this->_contents['children'])) { - return false; - } - - $pieces = explode('/', $filename); - if (!count($pieces)) { - return false; - } - - $element = $this->_contents; - while (true) { - $continue = false; - foreach ($element['children'] as $child) { - if (!in_array($child['name'], array('file', 'dir'))) { - continue; + if (!$dryrun && !copy($orig, $dest)) { + $cli->message('Could not link ' . $orig . '.', 'cli.error'); } - - if ($child['attributes']['name'] == '/') { - $continue = true; - break; + } else { + if ($debug) { + print 'SYMLINK: ' . $orig . ' -> ' . $dest . "\n"; } - - if ($child['attributes']['name'] == $pieces[0]) { - if (count($pieces) == 1) { - if (isset($child['attributes']['role'])) { - return $child['attributes']['role']; - } else { - return false; - } - } - - array_shift($pieces); - if (!count($pieces)) { - return false; - } - - $continue = true; - break; + if (!$dryrun && !symlink($orig, $dest)) { + $cli->message('Could not link ' . $orig . '.', 'cli.error'); } } - - if (!$continue) { - return false; - } - - if (!isset($child['children'])) { - return false; - } - $element = $child; } - - return false; - } - - function _findCommonParent($a, $b) - { - for ($common = '', $lastpos = 0, $pos = strpos($a, '/', 1); - $pos !== false && strpos($b, substr($a, 0, $pos)) === 0; - $pos = strpos($a, '/', $pos + 1)) { - $common .= substr($a, $lastpos, $pos - $lastpos); - $lastpos = $pos; - } - return $common; - } - - function getXmlTree($packageFile) - { - if (class_exists('SimpleXMLElement', false)) { - return new Linker_Xml_Tree($packageFile); - } else { - $tree = Tree::setupMemory('XML', $packageFile); - $tree->setup(); - return $tree; - } - } - -} - -class Linker_Xml_Tree -{ - var $_sxml; - - function __construct($packageFile) - { - $this->_sxml = simplexml_load_file($packageFile); - } - - function getElementContent($path, $field) - { - $elt = $this->getElementByPath($path); - return $elt[$field]; - } - - function getElementByPath($path) - { - $path = str_replace('/package', '', $path); - - $node = $this->_sxml; - $path = preg_split('|/|', $path, -1, PREG_SPLIT_NO_EMPTY); - while ($path) { - $ptr = array_shift($path); - if (!$node->$ptr) return null; - $node = $node->$ptr; - } - - return $this->_asArray($node); } - - function _asArray($sxml) - { - $element = array(); - $element['name'] = $sxml->getName(); - $element['cdata'] = (string)$sxml; - $element['attributes'] = array(); - foreach ($sxml->attributes() as $k => $v) { - $element['attributes'][$k] = (string)$v; - } - $element['children'] = array(); - foreach ($sxml->children() as $node) { - $element['children'][] = $this->_asArray($node); - } - - return $element; - } - } +/** + * Usage message. + */ function print_usage($message = '') { - if (!empty($message)) { echo "install_framework: $message\n\n"; } @@ -540,12 +258,17 @@ function print_usage($message = '') echo <<