Source for file PearWrapper.php

Documentation is available at PearWrapper.php

  1. <?php
  2. // vim: foldmethod=marker
  3. /**
  4.  *  PearWrapper.php
  5.  *
  6.  *  @author     ICHII Takashi <ichii386@schweetheart.jp>
  7.  *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
  8.  *  @package    Ethna
  9.  *  @version    $Id: 0d5ac26a60682608f56c627841bb2f745d99a3c1 $
  10.  */
  11.  
  12. require_once 'PEAR.php';
  13. require_once 'PEAR/Config.php';
  14. require_once 'PEAR/Command.php';
  15. require_once 'PEAR/PackageFile.php';
  16.  
  17. // {{{ Ethna_PearWrapper
  18. /**
  19.  *  wrapper class for PEAR_Command
  20.  *  This class should be instantiated in ethna handler.
  21.  *
  22.  *  @author     ICHII Takashi <ichii386@schweetheart.jp>
  23.  *  @access     public
  24.  *  @package    Ethna
  25.  */
  26. {
  27.     // {{{ properties
  28.     /**#@+
  29.      *  @access     private
  30.      */
  31.  
  32.     /** @protected    string  channel url of ethna repositry */
  33.     protected $channel;
  34.  
  35.     /** @protected    string  target, 'master' or 'local' */
  36.     protected $target;
  37.  
  38.     /** @protected    object  controller object collesponding to the target */
  39.     protected $target_ctl;
  40.  
  41.     /** @protected    object  PEAR_Config     PEAR_Config object */
  42.     protected $config;
  43.  
  44.     /** @protected    object  PEAR_Registry   PEAR_Registry object */
  45.     protected $registry;
  46.  
  47.     /** @protected    object  PEAR_Frontend   PEAR_Frontend(_CLI) object */
  48.     protected $ui;
  49.  
  50.     /** @protected    array   options for pearcmd */
  51.     protected $_pearopt;
  52.  
  53.     /**#@-*/
  54.     // }}}
  55.  
  56.     // {{{ constructor, initializer
  57.     /**
  58.      *  Ethna_PearWrapper constructor
  59.      *
  60.      *  @access public
  61.      */
  62.     public function __construct()
  63.     {
  64.         $this->channel = null;
  65.         $this->config = null;
  66.         $this->registry = null;
  67.         $this->ui = null;
  68.         $this->target = null;
  69.         $this->target_ctl = null;
  70.     }
  71.  
  72.     /**
  73.      *  setup PEAR_Config and so on.
  74.      *
  75.      *  @param  string      $target     whether 'master' or 'local'
  76.      *  @param  string|null$app_dir    local application directory.
  77.      *  @param  string|null$channel    channel for the package repository.
  78.      *  @return true|Ethna_Error
  79.      */
  80.     public function init($target$app_dir null$channel null)
  81.     {
  82.         $true true;
  83.         if ($target == 'master'{
  84.             $this->target = 'master';
  85.         else {
  86.             // default target is 'local'.
  87.             $this->target = 'local';
  88.         }
  89.  
  90.         // setup PEAR_Frontend
  91.         PEAR_Command::setFrontendType('CLI');
  92.         $this->ui = PEAR_Command::getFrontendObject();
  93.  
  94.         // set PEAR's error handling
  95.         // TODO: if PEAR/Command/Install.php is newer than 1.117, displayError goes well.
  96.         PEAR::setErrorHandling(PEAR_ERROR_CALLBACKarray($this->ui'displayFatalError'));
  97.  
  98.         // set channel
  99.         $master_setting Ethna_Handle::getMasterSetting('repositry');
  100.         if ($channel !== null{
  101.             $this->channel = $channel;
  102.         else if (isset($master_setting["channel_{$target}"])) {
  103.             $this->channel = $master_setting["channel_{$target}"];
  104.         else {
  105.             $this->channel = 'pear.ethna.jp';
  106.         }
  107.  
  108.         // set target controller
  109.         if ($target == 'master'{
  110.             $this->target_ctl = Ethna_Handle::getEthnaController();
  111.         else {
  112.             $this->target_ctl = Ethna_Handle::getAppController($app_dir);
  113.         }
  114.         if (Ethna::isError($this->target_ctl)) {
  115.             return $this->target_ctl;
  116.         }
  117.  
  118.         // setup PEAR_Config
  119.         if ($target == 'master'{
  120.             $ret $this->_setMasterConfig();
  121.         else {
  122.             $ret $this->_setLocalConfig();
  123.         }
  124.         if (Ethna::isError($ret)) {
  125.             return $ret;
  126.         }
  127.         $this->ui->setConfig($this->config);
  128.  
  129.         // setup PEAR_Registry
  130.         $this->registry = $this->config->getRegistry();
  131.  
  132.         return $true;
  133.     }
  134.  
  135.     /**
  136.      *  config for master.
  137.      *
  138.      *  @return true|Ethna_Error
  139.      *  @access private
  140.      */
  141.     private function _setMasterConfig()
  142.     {
  143.         $true true;
  144.  
  145.         // setup config
  146.         $this->config = PEAR_Config::singleton();
  147.  
  148.         // setup channel
  149.         $reg $this->config->getRegistry();
  150.         if ($reg->channelExists($this->channel== false{
  151.             $ret $this->doChannelDiscover();
  152.             if (Ethna::isError($ret)) {
  153.                 return $ret;
  154.             }
  155.         }
  156.  
  157.         return $true;
  158.     }
  159.  
  160.     /**
  161.      *  config for local.
  162.      *
  163.      *  @return true|Ethna_Error
  164.      *  @access protected
  165.      */
  166.     protected function _setLocalConfig()
  167.     {
  168.         $true true;
  169.  
  170.         // determine dirs
  171.         $base $this->target_ctl->getBaseDir();
  172.         $bin  $this->target_ctl->getDirectory('bin');
  173.         $tmp  $this->target_ctl->getDirectory('tmp');
  174.         $dirs array(
  175.                 'php_dir'       => "{$base}/skel",
  176.                 'bin_dir'       => "{$bin}",
  177.                 'cache_dir'     => "{$tmp}/.pear/cache",
  178.                 'download_dir'  => "{$tmp}/.pear/download",
  179.                 'temp_dir'      => "{$tmp}/.pear/temp",
  180.                 'doc_dir'       => "{$tmp}/.pear/doc",
  181.                 'ext_dir'       => "{$tmp}/.pear/ext",
  182.                 'data_dir'      => "{$tmp}/.pear/data",
  183.                 'test_dir'      => "{$tmp}/.pear/test",
  184.                 );
  185.  
  186.         // mkdir
  187.         foreach ($dirs as $key => $dir{
  188.             if (is_dir($dir== false{
  189.                 Ethna_Util::mkdir($dir0755);
  190.             }
  191.         }
  192.  
  193.         $pearrc "{$base}/skel/.pearrc";
  194.         $this->config = PEAR_Config::singleton($pearrc);
  195.  
  196.         // read local .pearrc if exists.
  197.         if (is_file($pearrc&& is_readable($pearrc)) {
  198.             $this->config->readConfigFile($pearrc);
  199.         }
  200.  
  201.         // set dirs to config
  202.         foreach ($dirs as $key => $dir{
  203.             $this->config->set($key$dir);
  204.         }
  205.  
  206.         // setup channel
  207.         $reg $this->config->getRegistry();
  208.         if ($reg->channelExists($this->channel== false{
  209.             $ret $this->doChannelDiscover();
  210.             if (Ethna::isError($ret)) {
  211.                 return $ret;
  212.             }
  213.         }
  214.         $this->config->set('default_channel'$this->channel);
  215.  
  216.         // write local .pearrc
  217.         $this->config->writeConfigFile();
  218.  
  219.         return $true;
  220.     }
  221.     // }}}
  222.  
  223.     // {{{ doClearCache
  224.     /**
  225.      *  do clear-cache
  226.      *
  227.      *  @return true|Ethna_Error
  228.      */
  229.     public function doClearCache()
  230.     {
  231.         $true true;
  232.         $r $this->_run('clear-cache'array()array());
  233.         if (PEAR::isError($r)) {
  234.             return $r;
  235.         }
  236.         return $true;
  237.     }
  238.     // }}}
  239.  
  240.     // {{{ doChannelDiscover
  241.     /**
  242.      *  do channel-discover
  243.      *
  244.      *  @return true|Ethna_Error
  245.      */
  246.     public function doChannelDiscover()
  247.     {
  248.         $true true;
  249.         $r $this->_run('channel-discover'array()array($this->channel));
  250.         if (PEAR::isError($r)) {
  251.             return $r;
  252.         }
  253.         return $true;
  254.     }
  255.     // }}}
  256.  
  257.     // {{{ isChannelExists
  258.     /**
  259.      *  whether channel discovered or not
  260.      *
  261.      *  @return bool 
  262.      */
  263.     public function isChannelExists()
  264.     {
  265.         return $this->registry->channelExists($this->channel);
  266.     }
  267.     // }}}
  268.  
  269.     // {{{ doChannelUpdate
  270.     /**
  271.      *  do channel-update
  272.      *
  273.      *  @return true|Ethna_Error
  274.      */
  275.     public function doChannelUpdate()
  276.     {
  277.         $true true;
  278.         if ($this->isChannelExists(== false{
  279.             $r $this->doChannelDiscover();
  280.             if (PEAR::isError($r)) {
  281.                 return $r;
  282.             }
  283.         }
  284.         $r $this->_run('channel-update'array()array($this->channel));
  285.         if (PEAR::isError($r)) {
  286.             return $r;
  287.         }
  288.         return $true;
  289.     }
  290.     // }}}
  291.  
  292.     // {{{ _doInstallOrUpgrade
  293.     /**
  294.      *  do install
  295.      *
  296.      *  @param  string  $command    'install' or 'upgrade'
  297.      *  @param  string  $package    package string
  298.      *  @return true|Ethna_Error
  299.      *  @access private
  300.      */
  301.     private function _doInstallOrUpgrade($command$package)
  302.     {
  303.         $true true;
  304.         $r $this->_run($commandarray()array($package));
  305.         if (PEAR::isError($r)) {
  306.             return $r;
  307.         }
  308.         return $true;
  309.     }
  310.     // }}}
  311.         
  312.     // {{{ doInstall
  313.     /**
  314.      *  do install
  315.      *
  316.      *  @param  string  $pkg_name   package name.
  317.      *  @param  string  $state      package state.
  318.      *  @return true|Ethna_Error
  319.      */
  320.     public function doInstall($pkg_name$state null)
  321.     {
  322.         $pkg "{$this->channel}/{$pkg_name}";
  323.         if ($state !== null) {
  324.             $pkg = "{$pkg}-{$state}";
  325.         }
  326.         $r = $this->_doInstallOrUpgrade('install'$pkg)
  327.         return $r;
  328.     }
  329.     // }}}
  330.     // {{{ doInstallFromTgz
  331.     /**
  332.      *  do install from local tgz file
  333.      *
  334.      *  @param  string  $pkg_file   package filename
  335.      *  @return true|Ethna_Error
  336.      */
  337.     public function doInstallFromTgz($pkg_file)
  338.     {
  339.         $r = $this->_doInstallOrUpgrade('install'$pkg_file)
  340.         return $r;
  341.     }
  342.     // }}}
  343.     // {{{ doUpgrade
  344.     /**
  345.      *  do upgrade
  346.      *
  347.      *  @param  string  $pkg_name   package name.
  348.      *  @param  string  $state      package state.
  349.      *  @return true|Ethna_Error
  350.      */
  351.     public function doUpgrade($pkg_name, $state = null)
  352.     {
  353.         $pkg = "{$this->channel}/{$pkg_name}";
  354.         if ($state !== null) {
  355.             $pkg = "{$pkg}-{$state}";
  356.         }
  357.         $r = $this->_doInstallOrUpgrade('upgrade'$pkg);
  358.         return $r;
  359.     }
  360.     // }}}
  361.     // {{{ doUpgradeFromTgz
  362.     /**
  363.      *  do upgrade from local tgz file
  364.      *
  365.      *  @param  string  $pkg_file   package filename
  366.      *  @return true|Ethna_Error
  367.      */
  368.     public function doUpgradeFromTgz($pkg_file)
  369.     {
  370.         $r = $this->_doInstallOrUpgrade('upgrade'$pkg_file)
  371.         return $r;
  372.     }
  373.     // }}}
  374.     // {{{ isInstalled
  375.     /**
  376.      *  check package installed
  377.      *
  378.      *  @param  string  $package package name
  379.      *  @return bool
  380.      */
  381.     public function isInstalled($package)
  382.     {
  383.         return $this->registry->packageExists($package$this->channel);
  384.     }
  385.     // }}}
  386.     // {{{ getVersion
  387.     /**
  388.      *  get package version
  389.      *
  390.      *  @param  string  $package package name
  391.      *  @return string  version string
  392.      */
  393.     public function getVersion($package)
  394.     {
  395.         $pobj = $this->registry->getPackage($package$this->channel);
  396.         return $pobj->getVersion();
  397.     }
  398.     // }}}
  399.     // {{{ getState
  400.     /**
  401.      *  get package version
  402.      *
  403.      *  @param  string  $package package name
  404.      *  @return string  version string
  405.      */
  406.     public function getState($package)
  407.     {
  408.         $pobj = $this->registry->getPackage($package$this->channel);
  409.         return $pobj->getState();
  410.     }
  411.     // }}}
  412.     // {{{ doUninstall
  413.     /**
  414.      *  do uninstall (packages installed with ethna command)
  415.      *
  416.      *  @return true|Ethna_Error
  417.      */
  418.     public function doUninstall($package)
  419.     {
  420.         $true = true;
  421.         if ($this->isInstalled($package== false{
  422.             return Ethna::raiseNotice("{$this->channel}/{$package} is not installed.");
  423.         }
  424.         $r = $this->_run('uninstall'array()array("{$this->channel}/{$package}"));
  425.         if (PEAR::isError($r)) {
  426.             return $r;
  427.         }
  428.         if ($this->isInstalled($package)) {
  429.             return Ethna::raiseNotice("uninstall failed: {$this->channel}/{$package}");
  430.         }
  431.         return $true;
  432.     }
  433.     // }}}
  434.     // {{{ getPackageNameFromTgz
  435.     /**
  436.      *  get package info from tar/tgz file.
  437.      *
  438.      *  @param  string  $filename   package file name.
  439.      *  @return string  package name
  440.      *  @access public
  441.      *  @static
  442.      */
  443.     public function getPackageNameFromTgz($filename)
  444.     {
  445.         $config = PEAR_Config::singleton();
  446.         $packagefile = new PEAR_PackageFile($config);
  447.         $info = $packagefile->fromTgzFile($filenamePEAR_VALIDATE_NORMAL);
  448.         if (PEAR::isError($info)) {
  449.             return $info;
  450.         }
  451.         $info_array = $info->toArray();
  452.         return $info_array['name'];
  453.     }
  454.     // }}}
  455.     // {{{ getCanonicalPackageName
  456.     /**
  457.      *  get canonical package name (case sensitive)
  458.      *
  459.      *  @param  string  $package    package name.
  460.      *  @return string  canonical name
  461.      *  @access public
  462.      */
  463.     public function getCanonicalPackageName($package)
  464.     {
  465.         if ($this->isInstalled($package== false{
  466.             return Ethna::raiseNotice("{$this->channel}/{$package} is not installed.");
  467.         }
  468.         $pobj = $this->registry->getPackage($package$this->channel);
  469.         $cname $pobj->getName();
  470.         return $cname;
  471.     }
  472.     // }}}
  473.     // {{{ getInstalledPackageList
  474.     /**
  475.      *  get installed package list
  476.      *
  477.      *  @return array   installed package list
  478.      *  @access public
  479.      */
  480.     public function getInstalledPackageList()
  481.     {
  482.         $ret = array();
  483.         foreach ($this->registry->listPackages($this->channelas $pkg{
  484.             $ret[] = $this->getCanonicalPackageName($pkg);
  485.         }
  486.         return $ret;
  487.     }
  488.     // }}}
  489.     // {{{ doInfo
  490.     /**
  491.      *  do info (packages installed with ethna command)
  492.      *
  493.      *  @param  string  $package    package name.
  494.      *  @return true|Ethna_Error
  495.      */
  496.     public function doInfo($package)
  497.     {
  498.         return $this->_run('info'array()array("{$this->channel}/{$package}"));
  499.     }
  500.     // }}}
  501.     // {{{ doRemoteInfo
  502.     /**
  503.      *  do info (packages installable with ethna command)
  504.      *
  505.      *  @param  string  $package    package name.
  506.      *  @return true|Ethna_Error
  507.      */
  508.     public function doRemoteInfo($package)
  509.     {
  510.         return $this->_run('remote-info'array()array("{$this->channel}/{$package}"));
  511.     }
  512.     // }}}
  513.     // {{{ doUpgradeAll
  514.     /**
  515.      *  do upgrade-all
  516.      *
  517.      *  @return true|Ethna_Error
  518.      */
  519.     public function doUpgradeAll()
  520.     {
  521.         return $this->_run('upgrade-all'array('channel' => "{$this->channel}"), array());
  522.     }
  523.     // }}}
  524.     // {{{ doList
  525.     /**
  526.      *  do list (packages installed with ethna command)
  527.      *
  528.      *  @return true|Ethna_Error
  529.      */
  530.     public function doList()
  531.     {
  532.         return $this->_run('list'array('channel' => $this->channel)array());
  533.     }
  534.     // }}}
  535.     // {{{ doRemoteList
  536.     /**
  537.      *  do remote-list (packages installable with ethna command)
  538.      *
  539.      *  @return true|Ethna_Error
  540.      */
  541.     public function doRemoteList()
  542.     {
  543.         return $this->_run('remote-list'array('channel' => $this->channel)array());
  544.     }
  545.     // }}}
  546.     // {{{ subroutines.
  547.     /**
  548.      *  run PEAR_Command.
  549.      *
  550.      *  @param  string  $command    command name
  551.      *  @param  array   $options    options
  552.      *  @param  array   $params     parameters
  553.      *  @return true|Ethna_Error
  554.      *  @access private 
  555.      *  @see PEAR_Command_Common::run, etc.
  556.      */
  557.     protected function _run($command, $options, $params)
  558.     {
  559.         if ($this->config === null{
  560.             return Ethna::raiseError('configuration not initialized.');
  561.         }
  562.  
  563.         $true = true;
  564.  
  565.         $cmd = PEAR_Command::factory($command, $this->config);
  566.         if (PEAR::isError($cmd)) {
  567.             return $cmd;
  568.         }
  569.  
  570.         // pear command options
  571.         if (is_array($this->_pearopt&& count($this->_pearopt0{
  572.             $pearopts = $this->_getPearOpt($cmd$command$this->_pearopt);
  573.             $options array_merge($pearopts$options);
  574.         }
  575.  
  576.         $ret = $cmd->run($command$options$params);
  577.         if (PEAR::isError($ret)) {
  578.             return $ret;
  579.         }
  580.  
  581.         return $true;
  582.     }
  583.  
  584.     /**
  585.      *  provide yes-or-no dialog.
  586.      *
  587.      *  @return bool
  588.      *  @access public
  589.      */
  590.     public function confirmDialog($message, $default = 'yes')
  591.     {
  592.         $ret = $this->ui->userConfirm($message);
  593.         return $ret;
  594.     }
  595.  
  596.     /**
  597.      *  provide table layout
  598.      *
  599.      *  @param  array   $headline   headline
  600.      *  @param  array   $rows       rows which have the same size as headline's.
  601.      *  @access public
  602.      */
  603.     public function displayTable($caption, $headline, $rows)
  604.     {
  605.         // spacing
  606.         foreach (array_keys($headline) as $k) {
  607.             $headline[$k] = sprintf('% -8s', $headline[$k]);
  608.         }
  609.  
  610.         $data = array('caption'  => $caption,
  611.                       'border'   => true,
  612.                       'headline' => $headline,
  613.                       'data'     => $rows);
  614.         $this->ui->outputData($data);
  615.     }
  616.  
  617.     /**
  618.      *  (experimental)
  619.      *  @access public
  620.      */
  621.     public function setPearOpt($pearopt)
  622.     {
  623.         $this->_pearopt = $pearopt;
  624.     }
  625.  
  626.     /**
  627.      *  (experimental)
  628.      *  @return array
  629.      */
  630.     private function _getPearOpt($cmd_obj, $cmd_str, $opt_array)
  631.     {
  632.         $short_args = $long_args = null;
  633.         PEAR_Command::getGetOptArgs($cmd_str, $short_args, $long_args);
  634.         $opt = new Ethna_Getopt();
  635.         $opt_arg = $opt->getopt($opt_array$short_args$long_args);
  636.         if (Ethna::isError($opt_arg)) return array();
  637.         $opts array();
  638.         foreach ($opt_arg[0as $tmp{
  639.             list($opt, $val) = $tmp;
  640.             if ($val === null) $val = true;
  641.             if (strlen($opt) == 1) {
  642.                 $cmd_opts = $cmd_obj->getOptions($cmd_str);
  643.                 foreach ($cmd_opts as $o => $d{
  644.                     if (isset($d['shortopt']) && $d['shortopt'] == $opt) {
  645.                         $opts[$o] = $val;
  646.                     }
  647.                 }
  648.             } else {
  649.                 if (substr($opt, 0, 2) == '--') $opts[substr($opt, 2)] = $val;
  650.             }
  651.         }
  652.         return $opts;
  653.     }
  654.                 
  655.  
  656.     // }}}
  657. }

Documentation generated on Fri, 11 Nov 2011 03:58:53 +0900 by phpDocumentor 1.4.3