[ Index ]

PHP Cross Reference of Akelos Framework

title

Body

[close]

/AkPlugin/ -> AkPluginManager.php (source)

   1  <?php
   2  
   3  /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
   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  // +----------------------------------------------------------------------+
  11  
  12  
  13  /**
  14   * Plugin manager
  15   * 
  16   * @package Plugins
  17   * @subpackage Manager
  18   * @author Bermi Ferrer <bermi a.t akelos c.om> 2007
  19   * @copyright Copyright (c) 2002-2007, Akelos Media, S.L. http://www.akelos.org
  20   * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
  21   */
  22  
  23  @set_time_limit(0);
  24  @ini_set('memory_limit', -1);
  25  
  26  require_once (AK_LIB_DIR.DS.'AkPlugin.php');
  27  
  28  defined('AK_PLUGINS_MAIN_REPOSITORY') ? null : define('AK_PLUGINS_MAIN_REPOSITORY', 'http://svn.akelos.org/plugins');
  29  defined('AK_PLUGINS_REPOSITORY_DISCOVERY_PAGE') ? null : define('AK_PLUGINS_REPOSITORY_DISCOVERY_PAGE', 'http://wiki.akelos.org/plugins');
  30  
  31  /**
  32   * Plugin manager
  33   * 
  34   * @package Plugins
  35   * @subpackage Manager
  36   * @author Bermi Ferrer <bermi a.t akelos c.om> 2007
  37   * @copyright Copyright (c) 2002-2007, Akelos Media, S.L. http://www.akelos.org
  38   * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html>
  39   */
  40  class AkPluginManager extends AkObject
  41  {
  42  
  43      /**
  44       * Main repository, must be an Apache mod_svn interface to subversion. Defaults to AK_PLUGINS_MAIN_REPOSITORY.
  45       * @var    string
  46       * @access public
  47       */
  48      var $main_repository = AK_PLUGINS_MAIN_REPOSITORY;
  49  
  50      /**
  51       * Repository discovery page.
  52       * 
  53       * A wiki page containing links to repositories. Links on that wiki page 
  54       * must link to an http:// protocol (no SSL yet) and end in plugins.
  55       * Defaults to  AK_PLUGINS_REPOSITORY_DISCOVERY_PAGE
  56       * @var    string
  57       * @access public
  58       */
  59      var $respository_discovery_page = AK_PLUGINS_REPOSITORY_DISCOVERY_PAGE;
  60  
  61  
  62  
  63      /**
  64       * Gets a list of available repositories.
  65       * 
  66       * @param  boolean $force_reload Forces reloading, useful for testing and when running as an application server.
  67       * @return array   List of repository URLs
  68       * @access public 
  69       */
  70      function getAvailableRepositories($force_reload = false)
  71      {
  72          if(!empty($this->tmp_repositories)){
  73              return $this->tmp_repositories;
  74          }
  75  
  76          if($force_reload || empty($this->repositories)){
  77              $this->repositories = array($this->main_repository);
  78              if(file_exists($this->_getRepositoriesConfigPath())){
  79                  $repository_candidates = array_diff(array_map('trim', explode("\n",Ak::file_get_contents($this->_getRepositoriesConfigPath()))), array(''));
  80                  if(!empty($repository_candidates)){
  81                      foreach ($repository_candidates as $repository_candidate){
  82                          if(strlen($repository_candidate) > 0 && $repository_candidate[0] != '#' && strstr($repository_candidate,'plugins')){
  83                              $this->repositories[] = $repository_candidate;
  84                          }
  85                      }
  86                  }
  87              }
  88          }
  89          return $this->repositories;
  90      }
  91  
  92  
  93  
  94      /**
  95       * Ads a repository to the know repositories list.
  96       * 
  97       * @param  string $repository_path  An Apache mod_svn interface to subversion.
  98       * @return void  
  99       * @access public
 100       */
 101      function addRepository($repository_path)
 102      {
 103          if(!in_array(trim($repository_path), $this->getAvailableRepositories(true))){
 104              Ak::file_add_contents($this->_getRepositoriesConfigPath(), $repository_path."\n");
 105          }
 106      }
 107  
 108  
 109  
 110      /**
 111       * Removes a repository to the know repositories list.
 112       * 
 113       * @param  string $repository_path  An Apache mod_svn interface to subversion.
 114       * @return boolean Returns false if the repository was not available
 115       * @access public 
 116       */
 117      function removeRepository($repository_path)
 118      {
 119          if(file_exists($this->_getRepositoriesConfigPath())){
 120              $repositories = Ak::file_get_contents($this->_getRepositoriesConfigPath());
 121              if(!strstr($repositories, $repository_path)){
 122                  return false;
 123              }
 124              $repositories = str_replace(array($repository_path, "\r", "\n\n"), array('', "\n", "\n"), $repositories);
 125              Ak::file_put_contents($this->_getRepositoriesConfigPath(), $repositories);
 126          }
 127      }
 128  
 129  
 130  
 131      /**
 132       * Gets a list of available plugins.
 133       * 
 134       * Goes through each trusted plugin server and retrieves the name of the 
 135       * folders (plugins) on the repository path.
 136       * 
 137       * @param  boolean $force_update If it is not set to true, it will only check remote sources once per hour
 138       * @return array   Returns an array containing "plugin_name" => "repository URL"
 139       * @access public 
 140       */
 141      function getPlugins($force_update = false)
 142      {
 143          if($force_update || !is_file($this->_getRepositoriesCahePath()) || filemtime($this->_getRepositoriesCahePath()) > 3600){
 144              if(!$this->_updateRemotePluginsList()){
 145                  return array();
 146              }
 147          }
 148  
 149          return array_map('trim', Ak::convert('yaml', 'array', Ak::file_get_contents($this->_getRepositoriesCahePath())));
 150      }
 151  
 152  
 153  
 154      /**
 155       * Retrieves a list of installed plugins
 156       * 
 157       * @return array  Returns an array with the plugins available at AK_PLUGINS_DIR
 158       * @access public
 159       */
 160      function getInstalledPlugins()
 161      {
 162          $Loader = new AkPluginLoader();
 163          return $Loader->getAvailablePlugins();
 164      }
 165  
 166  
 167  
 168      /**
 169       * Installs a plugin
 170       * 
 171       * Install a plugin from a remote resource.
 172       * 
 173       * Plugins can have an Akelos installer at located at "plugin_name/installer/plugin_name_installer.php"
 174       * If the installer is available, it will run the "PluginNameInstaller::install()" method, which will trigger
 175       * all the up_* methods for the installer.
 176       * 
 177       * @param  string  $plugin_name Plugin name
 178       * @param  unknown $repository   An Apache mod_svn interface to subversion. If not provided it will use a trusted repository.
 179       * @param  array $options  
 180       * - externals: Use svn:externals to grab the plugin. Enables plugin updates and plugin versioning.
 181       * - checkout:  Use svn checkout to grab the plugin. Enables updating but does not add a svn:externals entry.
 182       * - revision:  Checks out the given revision from subversion. Ignored if subversion is not used.
 183       * - force:     Overwrite existing files.
 184       * @return mixed Returns false if the plugin can't be found.
 185       * @access public 
 186       */
 187      function installPlugin($plugin_name, $repository = null, $options = array())
 188      {
 189          $default_options = array(
 190          'externals' => false,
 191          'checkout' => false,
 192          'force' => false,
 193          'revision' => null,
 194          );
 195  
 196          $options = array_merge($default_options, $options);
 197  
 198          $plugin_name = Ak::sanitize_include($plugin_name, 'high');
 199  
 200          $install_method = $this->guessBestInstallMethod($options);
 201  
 202          if($install_method != 'local directory'){
 203              $repository = $this->getRepositoryForPlugin($plugin_name, $repository);
 204          }
 205          if(!$options['force'] && is_dir(AK_PLUGINS_DIR.DS.$plugin_name)){
 206              trigger_error(Ak::t('Destination directory is not empty. Use force option to overwrite exiting files.'), E_USER_NOTICE);
 207          }else{
 208              $method = '_installUsing'.AkInflector::camelize($install_method);
 209              $this->$method($plugin_name, rtrim($repository, '/'), $options['revision'], $options['force']);
 210              $this->_runInstaller($plugin_name, 'install', $options);
 211          }
 212      }
 213      
 214      function guessBestInstallMethod($options = array())
 215      {
 216          if(defined('AK_BEST_PLUGIN_INSTALL_METHOD') && in_array(AK_BEST_PLUGIN_INSTALL_METHOD,
 217          array('local directory', 'checkout', 'export', 'http'))){
 218              return AK_BEST_PLUGIN_INSTALL_METHOD;
 219          }
 220          if(!empty($options['parameters']) && is_dir($options['parameters'])){
 221              return 'local directory';
 222          }elseif($this->canUseSvn()){
 223              if(!empty($options['externals']) && $this->_shouldUseSvnExternals()){
 224                  return 'externals';
 225              }elseif(!empty($options['checkout']) && $this->_shouldUseSvnCheckout()){
 226                  return 'checkout';
 227              }
 228              return 'export';
 229          }else{
 230              return 'http';
 231          }
 232      }
 233  
 234      function canUseSvn()
 235      {
 236          return strstr(`svn --version`, 'CollabNet');
 237      }
 238  
 239  
 240      /**
 241       * Updates a plugin if there are changes.
 242       * 
 243       * Uses subversion update if available. If http update is used, it will 
 244       * download the whole plugin unless there is a CHANGELOG file, in which case
 245       * it will only perform the update if there are changes.
 246       * 
 247       * @param  string  $plugin_name Plugin name
 248       * @param  string $repository   An Apache mod_svn interface to subversion. If not provided it will use a trusted repository.
 249       * @return null
 250       * @access public 
 251       */
 252      function updatePlugin($plugin_name, $repository = null)
 253      {
 254          $options = array(
 255          'externals' => false,
 256          'checkout' => false
 257          );
 258  
 259          $plugin_name = Ak::sanitize_include($plugin_name, 'high');
 260  
 261          $method = '_updateUsing'.AkInflector::camelize($this->guessBestInstallMethod($options));
 262          $this->$method($plugin_name, rtrim($this->getRepositoryForPlugin($plugin_name, $repository), '/'));
 263  
 264          $this->_runInstaller($plugin_name, 'install');
 265      }
 266  
 267  
 268      /**
 269       * Uninstalls an existing plugin
 270       * 
 271       * Plugins can have an Akelos installer at located at "plugin_name/installer/plugin_name_installer.php"
 272       * If the installer is available, it will run the "PluginNameInstaller::uninstall()" method, which will trigger
 273       * all the down_* methods for the installer.
 274       * 
 275       * @param  string  $plugin_name Plugin name
 276       * @return void  
 277       * @access public
 278       */
 279      function uninstallPlugin($plugin_name)
 280      {
 281          $plugin_name = Ak::sanitize_include($plugin_name, 'high');
 282          $this->_runInstaller($plugin_name, 'uninstall');
 283          if(is_dir(AK_PLUGINS_DIR.DS.$plugin_name)){
 284              Ak::directory_delete(AK_PLUGINS_DIR.DS.$plugin_name);
 285          }
 286          if($this->_shouldUseSvnExternals()){
 287              $this->_uninstallExternals($plugin_name);
 288          }
 289      }
 290  
 291  
 292      /**
 293       * Gets a list of repositories available at the web page defined by AK_PLUGINS_REPOSITORY_DISCOVERY_PAGE (http://wiki.akelos.org/plugins by default)
 294       * 
 295       * @return array An array of non trusted repositories available at http://wiki.akelos.org/plugins
 296       * @access public 
 297       */
 298      function getDiscoveredRepositories()
 299      {
 300          return array_diff($this->_getRepositoriesFromRemotePage(), $this->getAvailableRepositories(true));
 301      }
 302  
 303  
 304      /**
 305       * Returns the repository for a given $plugin_name
 306       * 
 307       * @param  string  $plugin_name     The name of the plugin
 308       * @param  string  $repository  If a repository name is provided it will check for the plugin name existance.
 309       * @return mixed Repository URL or false if plugin can't be found   
 310       * @access public
 311       */
 312      function getRepositoryForPlugin($plugin_name, $repository = null)
 313      {
 314          if(empty($repository)){
 315              $available_plugins = $this->getPlugins();
 316          }else{
 317              $available_plugins = array();
 318              $this->_addAvailablePlugins_($repository, &$available_plugins);
 319          }
 320  
 321          if(empty($available_plugins[$plugin_name])){
 322              trigger_error(Ak::t('Could not find %plugin_name plugin', array('%plugin_name' => $plugin_name)), E_USER_NOTICE);
 323              return false;
 324          }elseif (empty($repository)){
 325              $repository = $available_plugins[$plugin_name];
 326          }
 327          return $repository;
 328      }
 329  
 330      /**
 331       * Runs the plugin installer/uninstaller if available
 332       * 
 333       * Plugins can have an Akelos installer at located at "plugin_name/installer/plugin_name_installer.php"
 334       * If the installer is available, it will run the "PluginNameInstaller::install/uninstall()" method, which will trigger
 335       * all the up/down_* methods for the installer.
 336       * 
 337       * @param  string  $plugin_name     The name of the plugin
 338       * @param  string  $install_or_uninstall What to do, options are install or uninstall
 339       * @return void   
 340       * @access private
 341       */
 342      function _runInstaller($plugin_name, $install_or_uninstall = 'install', $options = array())
 343      {
 344          $plugin_dir = AK_PLUGINS_DIR.DS.$plugin_name;
 345          if(file_exists($plugin_dir.DS.'installer'.DS.$plugin_name.'_installer.php')){
 346              require_once (AK_LIB_DIR.DS.'AkInstaller.php');
 347              require_once (AK_LIB_DIR.DS.'AkPluginInstaller.php');
 348              require_once($plugin_dir.DS.'installer'.DS.$plugin_name.'_installer.php');
 349              $class_name = AkInflector::camelize($plugin_name.'_installer');
 350              if(class_exists($class_name)){
 351                  $Installer =& new $class_name(null,$plugin_name);
 352                  $Installer->options = $options;
 353                  $Installer->db->debug = false;
 354                  $Installer->warn_if_same_version = false;
 355                  $Installer->$install_or_uninstall();
 356              }
 357          }
 358      }
 359  
 360  
 361      /**
 362       * Retrieves the URL's from the AK_PLUGINS_REPOSITORY_DISCOVERY_PAGE (http://wiki.akelos.org/plugins by default)
 363       * 
 364       * Plugins in that page must follow this convention:
 365       * 
 366       *  * Only http:// protocol. No https:// or svn:// support yet
 367       *  * The URL must en in plugins to be fetched automatically
 368       * 
 369       * @return array   An array of existing repository URLs
 370       * @access private
 371       */
 372      function _getRepositoriesFromRemotePage()
 373      {
 374  
 375          $repositories = array();
 376          if(preg_match_all('/href="(http:\/\/(?!wiki\.akelos\.org)[^"]*plugins)/', Ak::url_get_contents($this->respository_discovery_page), $matches)){
 377              $repositories = array_unique($matches[1]);
 378          }
 379          return $repositories;
 380      }
 381  
 382      /**
 383       * Copy recursively a remote svn dir into a local path.
 384       * 
 385       * Downloads recursively the contents of remote directories from a mod_svn Apache subversion interface to a local destination.
 386       * 
 387       * File or directory permissions are not copied, so you will need to use installers to fix it if required.
 388       * 
 389       * @param  string  $source      An Apache mod_svn interface to subversion URL.
 390       * @param  string  $destination Destination directory
 391       * @return void   
 392       * @access private
 393       */
 394      function _copyRemoteDir($source, $destination)
 395      {
 396          $dir_name = trim(substr($source, strrpos(rtrim($source, '/'), '/')),'/');
 397          Ak::make_dir($destination.DS.$dir_name);
 398  
 399          list($directories, $files) = $this->_parseRemoteAndGetDirectoriesAndFiles($source);
 400  
 401          foreach ($files as $file){
 402              $this->_copyRemoteFile($source.$file, $destination.DS.$dir_name.DS.$file);
 403          }
 404  
 405          foreach ($directories as $directory){
 406              $this->_copyRemoteDir($source.$directory.'/', $destination.DS.$dir_name);
 407          }
 408      }
 409  
 410  
 411  
 412      /**
 413       * Copies a remote file into a local destination
 414       * 
 415       * @param  string $source      Source URL
 416       * @param  string  $destination Destination directory
 417       * @return void   
 418       * @access private
 419       */
 420      function _copyRemoteFile($source, $destination)
 421      {
 422          Ak::file_put_contents($destination, Ak::url_get_contents($source));
 423      }
 424  
 425  
 426  
 427      /**
 428       * Performs an update of available cached plugins.
 429       * 
 430       * @return boolean   
 431       * @access private
 432       */
 433      function _updateRemotePluginsList()
 434      {
 435          $new_plugins = array();
 436          foreach ($this->getAvailableRepositories() as $repository){
 437              $this->_addAvailablePlugins_($repository, $new_plugins);
 438          }
 439          if(empty($new_plugins)){
 440              trigger_error(Ak::t('Could not fetch remote plugins from one of these repositories: %repositories', array('%repositories' => "\n".join("\n", $this->getAvailableRepositories()))), E_USER_NOTICE);
 441              return false;
 442          }
 443          return Ak::file_put_contents($this->_getRepositoriesCahePath(), Ak::convert('array', 'yaml', $new_plugins));
 444      }
 445  
 446  
 447  
 448      /**
 449       * Modifies $plugins_list adding the plugins available at $repository
 450       * 
 451       * @param  string $repository    Repository URL
 452       * @param  array   $plugins_list Plugins list in the format 'plugin_name' => 'repository'
 453       * @return void   
 454       * @access private
 455       */
 456      function _addAvailablePlugins_($repository, &$plugins_list)
 457      {
 458          list($directories) = $this->_parseRemoteAndGetDirectoriesAndFiles($repository);
 459          foreach ($directories as $plugin){
 460              if(empty($plugins_list[$plugin])){
 461                  $plugins_list[$plugin] = $repository;
 462              }
 463          }
 464      }
 465  
 466  
 467  
 468      /**
 469       * Parses a remote Apache svn web page and returns a list of available files and directories
 470       * 
 471       * @param  string $remote_path Repository URL
 472       * @return array   an array like array($directories, $files). Use list($directories, $files) = $this->_parseRemoteAndGetDirectoriesAndFiles($remote_path) for getting the results of this method
 473       * @access private
 474       */
 475      function _parseRemoteAndGetDirectoriesAndFiles($remote_path)
 476      {
 477          $directories = $files = array();
 478          $remote_contents = Ak::url_get_contents(rtrim($remote_path, '/').'/');
 479  
 480          if(preg_match_all('/href="([A-Za-z\-_0-9]+)\/"/', $remote_contents, $matches)){
 481              foreach ($matches[1] as $directory){
 482                  $directories[] = trim($directory);
 483              }
 484          }
 485          if(preg_match_all('/href="(\.?[A-Za-z\-_0-9\.]+)"/', $remote_contents, $matches)){
 486              foreach ($matches[1] as $file){
 487                  $files[] = trim($file);
 488              }
 489          }
 490          return array($directories, $files);
 491      }
 492  
 493  
 494  
 495      /**
 496       * Trusted repositories location
 497       * 
 498       * By default trusted repositories are located at config/plugin_repositories.txt
 499       * 
 500       * @return string  Trusted repositories  path
 501       * @access private
 502       */
 503      function _getRepositoriesConfigPath()
 504      {
 505          if(empty($this->tmp_repositories)){
 506              return AK_CONFIG_DIR.DS.'plugin_repositories.txt';
 507          }else{
 508              return AK_TMP_DIR.DS.'plugin_repositories.'.md5(serialize($this->tmp_repositories));
 509          }
 510      }
 511  
 512  
 513  
 514      /**
 515       * Cached informations about available plugins
 516       * 
 517       * @return string  Plugin information cache path. By default AK_TMP_DIR.DS.'plugin_repositories.yaml'
 518       * @access private
 519       */
 520      function _getRepositoriesCahePath()
 521      {
 522          return AK_TMP_DIR.DS.'plugin_repositories.yaml';
 523      }
 524  
 525  
 526  
 527      function _shouldUseSvnExternals()
 528      {
 529          return is_dir(AK_PLUGINS_DIR.DS.'.svn');
 530      }
 531  
 532      function _shouldUseSvnCheckout()
 533      {
 534          return is_dir(AK_PLUGINS_DIR.DS.'.svn');
 535      }
 536  
 537      function _installUsingCheckout($name, $uri, $rev = null, $force = false)
 538      {
 539          $rev = empty($rev) ? '' : " -r $rev ";
 540          $force = $force ? ' --force ' : '';
 541          $plugin_dir = AK_PLUGINS_DIR.DS.$name;
 542          `svn co $force $rev $uri/$name $plugin_dir`;
 543      }
 544  
 545      function _updateUsingCheckout($name)
 546      {
 547          $plugin_dir = AK_PLUGINS_DIR.DS.$name;
 548          `svn update $plugin_dir`;
 549      }
 550  
 551      function _installUsingLocalDirectory($name, $path, $rev = null)
 552      {
 553          $source = $path.DS.$name;
 554          $plugin_dir = AK_PLUGINS_DIR;
 555          $command = AK_OS == 'UNIX' ? 'cp -rf ' : 'xcopy /h /r /k /x /y /S /E ';
 556          `$command $source $plugin_dir`;
 557      }
 558  
 559      function _updateUsingLocalDirectory($name)
 560      {
 561          trigger_error(Ak::t('Updating from local targets it\'s not supported yet. Please use install --force instead.'));
 562      }
 563  
 564      function _installUsingExport($name, $uri, $rev = null, $force = false)
 565      {
 566          $rev = empty($rev) ? '' : " -r $rev ";
 567          $force = $force ? ' --force ' : '';
 568          $plugin_dir = AK_PLUGINS_DIR.DS.$name;
 569          `svn export $force $rev $uri/$name $plugin_dir`;
 570      }
 571  
 572      function _updateUsingExport($name, $uri)
 573      {
 574          $plugin_dir = AK_PLUGINS_DIR.DS.$name;
 575          `svn export --force $uri/$name $plugin_dir`;
 576      }
 577  
 578      function _installUsingExternals($name, $uri, $rev = null, $force = false)
 579      {
 580          $extras = empty($rev) ? '' : " -r $rev ";
 581          $extras .= ($force ? ' --force ' : '');
 582          $externals = $this->_getExternals();
 583          $externals[$name] = $uri;
 584          $this->_setExternals($externals, $extras);
 585          $this->_installUsingCheckout($name, $uri, $rev, $force);
 586      }
 587  
 588      function _updateUsingExternals($name)
 589      {
 590          $this->_updateUsingCheckout($name);
 591      }
 592  
 593      function _updateUsingHttp($name, $uri)
 594      {
 595          if(is_file(AK_PLUGINS_DIR.DS.$name.DS.'CHANGELOG') &&
 596          md5(Ak::url_get_contents(rtrim($uri, '/').'/'.$name.'/CHANGELOG')) == md5_file(AK_PLUGINS_DIR.DS.$name.DS.'CHANGELOG')){
 597              return false;
 598          }
 599          $this->_copyRemoteDir(rtrim($uri, '/').'/'.$name.'/', AK_PLUGINS_DIR);
 600      }
 601  
 602  
 603      function _setExternals($items, $extras = '')
 604      {
 605          $externals = array();
 606          foreach ($items as $name => $uri){
 607              $externals[] = "$name ".rtrim($uri, '/');
 608          }
 609          $tmp_file = AK_TMP_DIR.DS.Ak::uuid();
 610          $plugins_dir = AK_PLUGINS_DIR;
 611          Ak::file_put_contents($tmp_file, join("\n", $externals));
 612          `svn propset $extras -q svn:externals -F "$tmp_file" "$plugins_dir"`;
 613          Ak::file_delete($tmp_file);
 614      }
 615  
 616      function _uninstallExternals($name)
 617      {
 618          $externals = $this->_getExternals();
 619          unset($externals[$name]);
 620          $this->_setExternals($externals);
 621      }
 622  
 623      function _getExternals()
 624      {
 625          if($this->_shouldUseSvnExternals()){
 626              $plugins_dir = AK_PLUGINS_DIR;
 627              $svn_externals = array_diff(array_map('trim',(array)explode("\n", `svn propget svn:externals "$plugins_dir"`)), array(''));
 628              $externals = array();
 629              foreach ($svn_externals as $svn_external){
 630                  list($name, $uri) = explode(' ', trim($svn_external));
 631                  $externals[$name] = $uri;
 632              }
 633              return $externals;
 634          }else{
 635              return array();
 636          }
 637      }
 638  
 639      function _installUsingHttp($name, $uri)
 640      {
 641          $this->_copyRemoteDir(rtrim($uri, '/').'/'.$name.'/', AK_PLUGINS_DIR);
 642      }
 643  
 644  }
 645  
 646  ?>


Generated: Mon Oct 27 12:43:49 2008 Cross-referenced by PHPXref 0.6